From ccdd3a4cee90a419b666a571664c8d4aeb44590b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 9 Nov 2011 12:08:40 +0100 Subject: [PATCH 001/534] Added configure option for the IKEv1 implementation in charon. --- configure.in | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) mode change 100644 => 100755 configure.in diff --git a/configure.in b/configure.in old mode 100644 new mode 100755 index 66daeb6b8..893914251 --- a/configure.in +++ b/configure.in @@ -158,7 +158,8 @@ ARG_ENABL_SET([manager], [enable web management console (proof of concept ARG_ENABL_SET([mediation], [enable IKEv2 Mediation Extension.]) ARG_ENABL_SET([integrity-test], [enable integrity testing of libstrongswan and plugins.]) ARG_DISBL_SET([load-warning], [disable the charon/pluto plugin load option warning in starter.]) -ARG_DISBL_SET([pluto], [disable the IKEv1 keying daemon pluto.]) +ARG_ENABL_SET([pluto], [enable the IKEv1 keying daemon pluto.]) +ARG_DISBL_SET([ikev1], [disable IKEv1 protocol support in charon.]) ARG_DISBL_SET([xauth], [disable xauth plugin.]) ARG_DISBL_SET([threads], [disable the use of threads in pluto. Charon always uses threads.]) ARG_DISBL_SET([adns], [disable the use of adns in pluto (disables opportunistic encryption).]) @@ -1009,6 +1010,7 @@ AM_CONDITIONAL(USE_ME, test x$mediation = xtrue) AM_CONDITIONAL(USE_INTEGRITY_TEST, test x$integrity_test = xtrue) AM_CONDITIONAL(USE_LOAD_WARNING, test x$load_warning = xtrue) AM_CONDITIONAL(USE_PLUTO, test x$pluto = xtrue) +AM_CONDITIONAL(USE_IKEV1, test x$ikev1 = xtrue) AM_CONDITIONAL(USE_THREADS, test x$threads = xtrue) AM_CONDITIONAL(USE_ADNS, test x$adns = xtrue) AM_CONDITIONAL(USE_CHARON, test x$charon = xtrue) @@ -1043,7 +1045,9 @@ fi if test x$monolithic = xtrue; then AC_DEFINE(MONOLITHIC) fi - +if test x$ikev1 = xtrue; then + AC_DEFINE(USE_IKEV1) +fi dnl ============================== dnl build Makefiles From 526b5afb4510163372f7981e57d69fad3ea53906 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 15 Nov 2011 13:53:56 +0100 Subject: [PATCH 002/534] Extended IKE header for IKEv1 support --- src/libcharon/encoding/message.c | 9 +- src/libcharon/encoding/payloads/ike_header.c | 173 +++++++++++++++---- src/libcharon/encoding/payloads/ike_header.h | 114 ++++++++++-- src/libcharon/network/receiver.c | 2 +- 4 files changed, 238 insertions(+), 60 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 2b5399294..fa724e4b1 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1120,9 +1120,8 @@ METHOD(message_t, generate, status_t, DBG2(DBG_ENC, "not encrypting payloads"); } - ike_header = ike_header_create(); - ike_header->set_maj_version(ike_header, this->major_version); - ike_header->set_min_version(ike_header, this->minor_version); + ike_header = ike_header_create_version(this->major_version, + this->minor_version); ike_header->set_exchange_type(ike_header, this->exchange_type); ike_header->set_message_id(ike_header, this->message_id); ike_header->set_response_flag(ike_header, !this->is_request); @@ -1567,8 +1566,8 @@ message_t *message_create_from_packet(packet_t *packet) .get_packet_data = _get_packet_data, .destroy = _destroy, }, - .major_version = IKE_MAJOR_VERSION, - .minor_version = IKE_MINOR_VERSION, + .major_version = IKEV2_MAJOR_VERSION, + .minor_version = IKEV2_MINOR_VERSION, .exchange_type = EXCHANGE_TYPE_UNDEFINED, .is_request = TRUE, .first_payload = NO_PAYLOAD, diff --git a/src/libcharon/encoding/payloads/ike_header.c b/src/libcharon/encoding/payloads/ike_header.c index 24d22f3a1..556e42258 100644 --- a/src/libcharon/encoding/payloads/ike_header.c +++ b/src/libcharon/encoding/payloads/ike_header.c @@ -81,12 +81,27 @@ struct private_ike_header_t { * TRUE, if this is a response, FALSE if its a Request. */ bool response; + + /** + * TRUE, if the packet is encrypted (IKEv1). + */ + bool encryption; + + /** + * TRUE, if the commit flag is set (IKEv1). + */ + bool commit; + + /** + * TRUE, if the auth only flag is set (IKEv1). + */ + bool authonly; } flags; /** * Reserved bits of IKE header */ - bool reserved[5]; + bool reserved[2]; /** * Associated Message-ID. @@ -99,9 +114,14 @@ struct private_ike_header_t { u_int32_t length; }; -ENUM_BEGIN(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, EXCHANGE_TYPE_UNDEFINED, - "EXCHANGE_TYPE_UNDEFINED"); -ENUM_NEXT(exchange_type_names, IKE_SA_INIT, IKE_SESSION_RESUME, EXCHANGE_TYPE_UNDEFINED, +ENUM_BEGIN(exchange_type_names, ID_PROT, INFORMATIONAL_V1, + "ID_PROT", + "AUTH_ONLY", + "AGGRESSIVE", + "INFORMATIONAL_V1"); +ENUM_NEXT(exchange_type_names, QUICK_MODE, IKE_SESSION_RESUME, INFORMATIONAL_V1, + "QUICK_MODE", + "NEW_GROUP_MODE", "IKE_SA_INIT", "IKE_AUTH", "CREATE_CHILD_SA", @@ -110,13 +130,18 @@ ENUM_NEXT(exchange_type_names, IKE_SA_INIT, IKE_SESSION_RESUME, EXCHANGE_TYPE_UN #ifdef ME ENUM_NEXT(exchange_type_names, ME_CONNECT, ME_CONNECT, IKE_SESSION_RESUME, "ME_CONNECT"); -ENUM_END(exchange_type_names, ME_CONNECT); +ENUM_NEXT(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, + EXCHANGE_TYPE_UNDEFINED, ME_CONNECT, + "EXCHANGE_TYPE_UNDEFINED"); #else -ENUM_END(exchange_type_names, IKE_SESSION_RESUME); +ENUM_NEXT(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, + EXCHANGE_TYPE_UNDEFINED, IKE_SESSION_RESUME, + "EXCHANGE_TYPE_UNDEFINED"); #endif /* ME */ +ENUM_END(exchange_type_names, EXCHANGE_TYPE_UNDEFINED); /** - * Encoding rules to parse or generate a IKEv2-Header. + * Encoding rules to parse or generate a IKE-Header. * * The defined offsets are the positions in a object of type * ike_header_t. @@ -137,21 +162,19 @@ encoding_rule_t ike_header_encodings[] = { /* 2 Bit reserved bits */ { RESERVED_BIT, offsetof(private_ike_header_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_ike_header_t, reserved[1]) }, - /* 3 Bit flags, stored in the fields response, version and initiator */ + /* 6 flags */ { FLAG, offsetof(private_ike_header_t, flags.response) }, { FLAG, offsetof(private_ike_header_t, flags.version) }, { FLAG, offsetof(private_ike_header_t, flags.initiator) }, - /* 3 Bit reserved bits */ - { RESERVED_BIT, offsetof(private_ike_header_t, reserved[2]) }, - { RESERVED_BIT, offsetof(private_ike_header_t, reserved[3]) }, - { RESERVED_BIT, offsetof(private_ike_header_t, reserved[4]) }, + { FLAG, offsetof(private_ike_header_t, flags.authonly) }, + { FLAG, offsetof(private_ike_header_t, flags.commit) }, + { FLAG, offsetof(private_ike_header_t, flags.encryption)}, /* 4 Byte message id, stored in the field message_id */ { U_INT_32, offsetof(private_ike_header_t, message_id) }, /* 4 Byte length fied, stored in the field length */ { HEADER_LENGTH,offsetof(private_ike_header_t, length) }, }; - /* 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -172,26 +195,51 @@ encoding_rule_t ike_header_encodings[] = { METHOD(payload_t, verify, status_t, private_ike_header_t *this) { - if ((this->exchange_type < IKE_SA_INIT) || - ((this->exchange_type > INFORMATIONAL) -#ifdef ME - && (this->exchange_type != ME_CONNECT) -#endif /* ME */ - )) + switch (this->exchange_type) { - /* unsupported exchange type */ - return FAILED; + case ID_PROT: + case AGGRESSIVE: + if (this->message_id != 0) + { + return FAILED; + } + /* fall */ + case AUTH_ONLY: + case INFORMATIONAL_V1: + case QUICK_MODE: + case NEW_GROUP_MODE: + if (this->maj_version != IKEV1_MAJOR_VERSION) + { + return FAILED; + } + break; + case IKE_SA_INIT: + case IKE_AUTH: + case CREATE_CHILD_SA: + case INFORMATIONAL: + case IKE_SESSION_RESUME: +#ifdef ME + case ME_CONNECT: +#endif /* ME */ + if (this->maj_version != IKEV2_MAJOR_VERSION) + { + return FAILED; + } + break; + default: + /* unsupported exchange type */ + return FAILED; } - if (this->initiator_spi == 0 -#ifdef ME - /* we allow zero spi for INFORMATIONAL exchanges, - * to allow connectivity checks */ - && this->exchange_type != INFORMATIONAL -#endif /* ME */ - ) + if (this->initiator_spi == 0) { - /* initiator spi not set */ - return FAILED; +#ifdef ME + if (this->exchange_type != INFORMATIONAL) + /* we allow zero spi for INFORMATIONAL exchanges, + * to allow connectivity checks */ +#endif /* ME */ + { + return FAILED; + } } return SUCCESS; } @@ -311,6 +359,43 @@ METHOD(ike_header_t, set_initiator_flag, void, this->flags.initiator = initiator; } +METHOD(ike_header_t, get_encryption_flag, bool, + private_ike_header_t *this) +{ + return this->flags.encryption; +} + +METHOD(ike_header_t, set_encryption_flag, void, + private_ike_header_t *this, bool encryption) +{ + this->flags.encryption = encryption; +} + + +METHOD(ike_header_t, get_commit_flag, bool, + private_ike_header_t *this) +{ + return this->flags.commit; +} + +METHOD(ike_header_t, set_commit_flag, void, + private_ike_header_t *this, bool commit) +{ + this->flags.commit = commit; +} + +METHOD(ike_header_t, get_authonly_flag, bool, + private_ike_header_t *this) +{ + return this->flags.authonly; +} + +METHOD(ike_header_t, set_authonly_flag, void, + private_ike_header_t *this, bool authonly) +{ + this->flags.authonly = authonly; +} + METHOD(ike_header_t, get_exchange_type, u_int8_t, private_ike_header_t *this) { @@ -373,21 +458,35 @@ ike_header_t *ike_header_create() .set_version_flag = _set_version_flag, .get_initiator_flag = _get_initiator_flag, .set_initiator_flag = _set_initiator_flag, + .get_encryption_flag = _get_encryption_flag, + .set_encryption_flag = _set_encryption_flag, + .get_commit_flag = _get_commit_flag, + .set_commit_flag = _set_commit_flag, + .get_authonly_flag = _get_authonly_flag, + .set_authonly_flag = _set_authonly_flag, .get_exchange_type = _get_exchange_type, .set_exchange_type = _set_exchange_type, .get_message_id = _get_message_id, .set_message_id = _set_message_id, .destroy = _destroy, }, - .maj_version = IKE_MAJOR_VERSION, - .min_version = IKE_MINOR_VERSION, - .exchange_type = EXCHANGE_TYPE_UNDEFINED, - .flags = { - .initiator = TRUE, - .version = HIGHER_VERSION_SUPPORTED_FLAG, - }, .length = IKE_HEADER_LENGTH, + .exchange_type = EXCHANGE_TYPE_UNDEFINED, ); return &this->public; } + +/* + * Described in header. + */ +ike_header_t *ike_header_create_version(int major, int minor) +{ + ike_header_t *this = ike_header_create(); + + this->set_maj_version(this, major); + this->set_min_version(this, minor); + this->set_initiator_flag(this, TRUE); + + return this; +} diff --git a/src/libcharon/encoding/payloads/ike_header.h b/src/libcharon/encoding/payloads/ike_header.h index 5579a4961..aa456de9d 100644 --- a/src/libcharon/encoding/payloads/ike_header.h +++ b/src/libcharon/encoding/payloads/ike_header.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Tobias Brunner - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -30,19 +30,24 @@ typedef struct ike_header_t ike_header_t; #include /** - * Major Version of IKEv2. + * Major Version of IKEv1 we implement. */ -#define IKE_MAJOR_VERSION 2 +#define IKEV1_MAJOR_VERSION 1 /** - * Minor Version of IKEv2. + * Minor Version of IKEv2 we implement. */ -#define IKE_MINOR_VERSION 0 +#define IKEV1_MINOR_VERSION 0 /** - * Flag in IKEv2-Header. Always 0. + * Major Version of IKEv2 we implement. */ -#define HIGHER_VERSION_SUPPORTED_FLAG 0 +#define IKEV2_MAJOR_VERSION 2 + +/** + * Minor Version of IKEv2 we implement. + */ +#define IKEV2_MINOR_VERSION 0 /** * Length of IKE Header in Bytes. @@ -57,9 +62,34 @@ typedef struct ike_header_t ike_header_t; enum exchange_type_t{ /** - * EXCHANGE_TYPE_UNDEFINED. In private space, since not a official message type. + * Identity Protection (Main mode). */ - EXCHANGE_TYPE_UNDEFINED = 255, + ID_PROT = 2, + + /** + * Authentication Only. + */ + AUTH_ONLY = 3, + + /** + * Aggresive (Aggressive mode) + */ + AGGRESSIVE = 4, + + /** + * Informational in IKEv1 + */ + INFORMATIONAL_V1 = 5, + + /** + * Quick Mode + */ + QUICK_MODE = 32, + + /** + * New Group Mode + */ + NEW_GROUP_MODE = 33, /** * IKE_SA_INIT. @@ -77,7 +107,7 @@ enum exchange_type_t{ CREATE_CHILD_SA = 36, /** - * INFORMATIONAL. + * INFORMATIONAL in IKEv2. */ INFORMATIONAL = 37, @@ -91,6 +121,11 @@ enum exchange_type_t{ */ ME_CONNECT = 240 #endif /* ME */ + + /** + * Undefined exchange type, in private space. + */ + EXCHANGE_TYPE_UNDEFINED = 255, }; /** @@ -99,14 +134,10 @@ enum exchange_type_t{ extern enum_name_t *exchange_type_names; /** - * An object of this type represents an IKEv2 header and is used to - * generate and parse IKEv2 headers. - * - * The header format of an IKEv2-Message is compatible to the - * ISAKMP-Header format to allow implementations supporting - * both versions of the IKE-protocol. + * An object of this type represents an IKE header of either IKEv1 or IKEv2. */ struct ike_header_t { + /** * The payload_t interface. */ @@ -210,6 +241,48 @@ struct ike_header_t { */ void (*set_initiator_flag) (ike_header_t *this, bool initiator); + /** + * Get the encryption flag. + * + * @return encryption flag + */ + bool (*get_encryption_flag) (ike_header_t *this); + + /** + * Set the encryption flag. + * + * @param encryption encryption flag + */ + void (*set_encryption_flag) (ike_header_t *this, bool encryption); + + /** + * Get the commit flag. + * + * @return commit flag + */ + bool (*get_commit_flag) (ike_header_t *this); + + /** + * Set the commit flag. + * + * @param commit commit flag + */ + void (*set_commit_flag) (ike_header_t *this, bool commit); + + /** + * Get the authentication only flag. + * + * @return authonly flag + */ + bool (*get_authonly_flag) (ike_header_t *this); + + /** + * Set the authentication only flag. + * + * @param authonly authonly flag + */ + void (*set_authonly_flag) (ike_header_t *this, bool authonly); + /** * Get the exchange type. * @@ -245,10 +318,17 @@ struct ike_header_t { }; /** - * Create an ike_header_t object + * Create an empty ike_header_t object. * * @return ike_header_t object */ ike_header_t *ike_header_create(void); +/** + * Create an ike_header_t object for a specific major/minor version + * + * @return ike_header_t object + */ +ike_header_t *ike_header_create_version(int major, int minor); + #endif /** IKE_HEADER_H_ @}*/ diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index 2887595fc..ec30fca61 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -371,7 +371,7 @@ static job_requeue_t receive_packets(private_receiver_t *this) } /* check IKE major version */ - if (message->get_major_version(message) != IKE_MAJOR_VERSION) + if (message->get_major_version(message) != IKEV2_MAJOR_VERSION) { DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, " "sending INVALID_MAJOR_VERSION", message->get_major_version(message), From 867701bc6ddce3a5c4024a22b4715936bfcbb13e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 15 Nov 2011 14:03:24 +0100 Subject: [PATCH 003/534] Accept and process IKEv1 messages in receiver --- src/libcharon/network/receiver.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index ec30fca61..3e75d9b04 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -162,6 +162,7 @@ static void send_notify(message_t *request, notify_type_t type, chunk_t data) response->destroy(response); } } + /* TODO-IKEv1: send IKEv1 specific notifies */ } /** @@ -371,16 +372,26 @@ static job_requeue_t receive_packets(private_receiver_t *this) } /* check IKE major version */ - if (message->get_major_version(message) != IKEV2_MAJOR_VERSION) + switch (message->get_major_version(message)) { - DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, " - "sending INVALID_MAJOR_VERSION", message->get_major_version(message), - message->get_minor_version(message), packet->get_source(packet)); - send_notify(message, INVALID_MAJOR_VERSION, chunk_empty); - message->destroy(message); - return JOB_REQUEUE_DIRECT; + case IKEV2_MAJOR_VERSION: + break; +#ifdef USE_IKEV1 + case IKEV1_MAJOR_VERSION: + break; +#endif /* USE_IKEV1 */ + default: + DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, " + "sending INVALID_MAJOR_VERSION", + message->get_major_version(message), + message->get_minor_version(message), + packet->get_source(packet)); + send_notify(message, INVALID_MAJOR_VERSION, chunk_empty); + message->destroy(message); + return JOB_REQUEUE_DIRECT; } + /* TODO-IKEv1: drop too agressive mainmodes */ if (message->get_request(message) && message->get_exchange_type(message) == IKE_SA_INIT) { From e33b41e7b04440e93096786f304ce9b4a88c7cba Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 15 Nov 2011 14:47:20 +0100 Subject: [PATCH 004/534] Added IKEv1 payload identifiers --- src/libcharon/encoding/payloads/payload.c | 32 ++++++++++- src/libcharon/encoding/payloads/payload.h | 69 ++++++++++++++++++++++- 2 files changed, 97 insertions(+), 4 deletions(-) diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index d1e677db7..93b3641f1 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -39,7 +39,21 @@ ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD, "NO_PAYLOAD"); -ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, NO_PAYLOAD, +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, VENDOR_ID_V1, NO_PAYLOAD, + "SECURITY_ASSOCIATION_V1", + "PROPOSAL_V1", + "TRANSFORM_V1", + "KEY_EXCHANGE_V1", + "ID_V1", + "CERTIFICATE_V1", + "CERTIFICATE_REQUEST_V1", + "HASH_V1", + "SIGNATURE_V1", + "NONCE_V1", + "NOTIFICATION_V1", + "DELETE_V1", + "VENDOR_ID_V1"); +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, VENDOR_ID_V1, "SECURITY_ASSOCIATION", "KEY_EXCHANGE", "ID_INITIATOR", @@ -80,7 +94,21 @@ ENUM_END(payload_type_names, CONFIGURATION_ATTRIBUTE); /* short forms of payload names */ ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD, "--"); -ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, NO_PAYLOAD, +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION_V1, VENDOR_ID_V1, NO_PAYLOAD, + "SA", + "PROP", + "TRANS", + "KE", + "ID", + "CERT", + "CERTREQ", + "HASH", + "SIG", + "No", + "NO", + "D", + "V"); +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, VENDOR_ID_V1, "SA", "KE", "IDi", diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index ad3023fe6..021383a1d 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -31,18 +31,83 @@ typedef struct payload_t payload_t; /** - * Payload-Types of a IKEv2-Message. + * Payload-Types of an IKE message. * * Header and substructures are also defined as * payload types with values from PRIVATE USE space. */ -enum payload_type_t{ +enum payload_type_t { /** * End of payload list in next_payload */ NO_PAYLOAD = 0, + /** + * The security association (SA) payload containing proposals. + */ + SECURITY_ASSOCIATION_V1 = 1, + + /** + * The proposal payload, containing transforms. + */ + PROPOSAL_V1 = 2, + + /** + * The transform payload. + */ + TRANSFORM_V1 = 3, + + /** + * The key exchange (KE) payload containing diffie-hellman values. + */ + KEY_EXCHANGE_V1 = 4, + + /** + * ID payload. + */ + ID_V1 = 5, + + /** + * Certificate payload with certificates (CERT). + */ + CERTIFICATE_V1 = 6, + + /** + * Certificate request payload. + */ + CERTIFICATE_REQUEST_V1 = 7, + + /** + * Hash payload. + */ + HASH_V1 = 8, + + /** + * Signature payload + */ + SIGNATURE_V1 = 9, + + /** + * Nonce payload. + */ + NONCE_V1 = 10, + + /** + * Notification payload. + */ + NOTIFICATION_V1 = 11, + + /** + * Delete payload. + */ + DELETE_V1 = 12, + + /** + * Vendor id payload. + */ + VENDOR_ID_V1 = 13, + /** * The security association (SA) payload containing proposals. */ From 2fc986182f4d0953db83787990572c64b4c98b42 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 15 Nov 2011 15:30:39 +0100 Subject: [PATCH 005/534] Handle IKEv1 messages in managers checkout_by_message --- src/libcharon/sa/ike_sa_manager.c | 39 ++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 731ae6007..6d6fb4b80 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -970,6 +970,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, entry_t *entry; ike_sa_t *ike_sa = NULL; ike_sa_id_t *id; + bool is_init = FALSE; id = message->get_ike_sa_id(message); id = id->clone(id); @@ -977,11 +978,29 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, DBG2(DBG_MGR, "checkout IKE_SA by message"); - if (message->get_request(message) && - message->get_exchange_type(message) == IKE_SA_INIT && - this->hasher) + if (id->get_responder_spi(id) == 0) { - /* IKE_SA_INIT request. Check for an IKE_SA with such a message hash. */ + if (message->get_major_version(message) == IKEV2_MAJOR_VERSION) + { + if (message->get_exchange_type(message) == IKE_SA_INIT && + message->get_request(message)) + { + is_init = TRUE; + } + } + else + { + if (message->get_exchange_type(message) == ID_PROT || + message->get_exchange_type(message) == AGGRESSIVE) + { + is_init = TRUE; + } + } + } + + if (is_init && this->hasher) + { + /* First request. Check for an IKE_SA with such a message hash. */ chunk_t data, hash; data = message->get_packet_data(message); @@ -990,7 +1009,8 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (get_entry_by_hash(this, id, hash, &entry, &segment) == SUCCESS) { - if (entry->message_id == 0) + if (message->get_exchange_type(message) == IKE_SA_INIT && + entry->message_id == 0) { unlock_single_segment(this, segment); chunk_free(&hash); @@ -1011,8 +1031,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (ike_sa == NULL) { - if (id->get_responder_spi(id) == 0 && - message->get_exchange_type(message) == IKE_SA_INIT) + if (is_init) { /* no IKE_SA found, create a new one */ id->set_responder_spi(id, get_spi(this)); @@ -1048,7 +1067,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (get_entry_by_id(this, id, &entry, &segment) == SUCCESS) { - /* only check out if we are not processing this request */ + /* only check out in IKEv2 if we are not already processing it */ if (message->get_request(message) && message->get_message_id(message) == entry->message_id) { @@ -1057,7 +1076,9 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, } else if (wait_for_entry(this, entry, segment)) { - ike_sa_id_t *ike_id = entry->ike_sa->get_id(entry->ike_sa); + ike_sa_id_t *ike_id; + + ike_id = entry->ike_sa->get_id(entry->ike_sa); entry->checked_out = TRUE; entry->message_id = message->get_message_id(message); if (ike_id->get_responder_spi(ike_id) == 0) From ecf854a00b03129f40621207400a372125327cf9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 15 Nov 2011 14:58:23 +0000 Subject: [PATCH 006/534] Added IKEv1 payload identifiers to "known" payload list --- src/libcharon/encoding/payloads/payload.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 93b3641f1..47fe20cca 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -211,8 +211,15 @@ payload_t *payload_create(payload_type_t type) */ bool payload_is_known(payload_type_t type) { - if (type == HEADER || - (type >= SECURITY_ASSOCIATION && type <= EXTENSIBLE_AUTHENTICATION)) + if (type == HEADER) + { + return TRUE; + } + if (type >= SECURITY_ASSOCIATION && type <= EXTENSIBLE_AUTHENTICATION) + { + return TRUE; + } + if (type >= SECURITY_ASSOCIATION_V1 && type <= VENDOR_ID_V1) { return TRUE; } From 837298c5909362ab7ca165f1efca214616579501 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 15 Nov 2011 14:58:47 +0000 Subject: [PATCH 007/534] Use vendor id payload for IKEv1 payloads, too --- src/libcharon/encoding/payloads/payload.c | 3 ++- .../encoding/payloads/vendor_id_payload.c | 15 +++++++++++---- .../encoding/payloads/vendor_id_payload.h | 11 +++++++---- src/libcharon/sa/tasks/ike_vendor.c | 3 ++- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 47fe20cca..78451c5b4 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -192,7 +192,8 @@ payload_t *payload_create(payload_type_t type) case DELETE: return (payload_t*)delete_payload_create(0); case VENDOR_ID: - return (payload_t*)vendor_id_payload_create(); + case VENDOR_ID_V1: + return (payload_t*)vendor_id_payload_create(type); case CONFIGURATION: return (payload_t*)cp_payload_create(); case CONFIGURATION_ATTRIBUTE: diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.c b/src/libcharon/encoding/payloads/vendor_id_payload.c index e9e80e989..3dab3941e 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.c +++ b/src/libcharon/encoding/payloads/vendor_id_payload.c @@ -55,6 +55,11 @@ struct private_vendor_id_payload_t { * The contained data. */ chunk_t data; + + /** + * Either a IKEv1 or a IKEv2 vendor ID payload + */ + payload_type_t type; }; /** @@ -111,7 +116,7 @@ METHOD(payload_t, get_encoding_rules, void, METHOD(payload_t, get_type, payload_type_t, private_vendor_id_payload_t *this) { - return VENDOR_ID; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -148,7 +153,8 @@ METHOD2(payload_t, vendor_id_payload_t, destroy, void, /* * Described in header */ -vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) +vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type, + chunk_t data) { private_vendor_id_payload_t *this; @@ -169,6 +175,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) .next_payload = NO_PAYLOAD, .payload_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH + data.len, .data = data, + .type = type, ); return &this->public; } @@ -176,7 +183,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) /* * Described in header */ -vendor_id_payload_t *vendor_id_payload_create() +vendor_id_payload_t *vendor_id_payload_create(payload_type_t type) { - return vendor_id_payload_create_data(chunk_empty); + return vendor_id_payload_create_data(type, chunk_empty); } diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.h b/src/libcharon/encoding/payloads/vendor_id_payload.h index 4e4e7d8eb..4943af436 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.h +++ b/src/libcharon/encoding/payloads/vendor_id_payload.h @@ -33,7 +33,7 @@ typedef struct vendor_id_payload_t vendor_id_payload_t; #define VENDOR_ID_PAYLOAD_HEADER_LENGTH 4 /** - * Class representing an IKEv2 VENDOR ID payload. + * Class representing an IKEv1/IKEv2 VENDOR ID payload. * * The VENDOR ID payload format is described in RFC section 3.12. */ @@ -58,18 +58,21 @@ struct vendor_id_payload_t { }; /** - * Creates an empty Vendor ID payload. + * Creates an empty Vendor ID payload for IKEv1 or IKEv2. * + * @@param type VENDOR_ID or VENDOR_ID_V1 * @return vendor ID payload */ -vendor_id_payload_t *vendor_id_payload_create(); +vendor_id_payload_t *vendor_id_payload_create(payload_type_t type); /** * Creates a vendor ID payload using a chunk of data * + * @param type VENDOR_ID or VENDOR_ID_V1 * @param data data to use in vendor ID payload, gets owned by payload * @return vendor ID payload */ -vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data); +vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type, + chunk_t data); #endif /** VENDOR_ID_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_vendor.c b/src/libcharon/sa/tasks/ike_vendor.c index 1c14ee06b..b3a7dddfa 100644 --- a/src/libcharon/sa/tasks/ike_vendor.c +++ b/src/libcharon/sa/tasks/ike_vendor.c @@ -57,7 +57,8 @@ METHOD(task_t, build, status_t, { vendor_id_payload_t *vid; - vid = vendor_id_payload_create_data(chunk_clone(strongswan_vid)); + vid = vendor_id_payload_create_data(VENDOR_ID, + chunk_clone(strongswan_vid)); message->add_payload(message, &vid->payload_interface); } From fdb8421f3683918c3218838df742a7673e0f542d Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 15 Nov 2011 14:27:19 +0100 Subject: [PATCH 008/534] Typo fixed. --- src/libcharon/encoding/payloads/ike_header.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/ike_header.h b/src/libcharon/encoding/payloads/ike_header.h index aa456de9d..2ee247873 100644 --- a/src/libcharon/encoding/payloads/ike_header.h +++ b/src/libcharon/encoding/payloads/ike_header.h @@ -35,7 +35,7 @@ typedef struct ike_header_t ike_header_t; #define IKEV1_MAJOR_VERSION 1 /** - * Minor Version of IKEv2 we implement. + * Minor Version of IKEv1 we implement. */ #define IKEV1_MINOR_VERSION 0 From 6ba70ba8dd2ffcd28fc1aeaf106f8561ef947634 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 15 Nov 2011 16:13:50 +0100 Subject: [PATCH 009/534] Message rules for IKEv1 ID_PROT exchange added. These rules are quite broad and cover main mode with at least PSK and signature based authentication. --- src/libcharon/encoding/message.c | 77 ++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index fa724e4b1..eab3427a1 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -414,6 +414,72 @@ static payload_order_t me_connect_r_order[] = { }; #endif /* ME */ +#ifdef USE_IKEV1 +/** + * Message rule for ID_PROT from initiator. + */ +static payload_rule_t id_prot_i_rules[] = { +/* payload type min max encr suff */ + {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, TRUE, FALSE}, + {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, + {SIGNATURE_V1, 0, 1, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, +}; + +/** + * payload order for ID_PROT from initiator. + */ +static payload_order_t id_prot_i_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {NOTIFICATION_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for ID_PROT from responder. + */ +static payload_rule_t id_prot_r_rules[] = { +/* payload type min max encr suff */ + {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, TRUE, FALSE}, + {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, + {SIGNATURE_V1, 0, 1, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, +}; + +/** + * payload order for ID_PROT from responder. + */ +static payload_order_t id_prot_r_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {NOTIFICATION_V1, 0}, + {VENDOR_ID_V1, 0}, +}; +#endif /* USE_IKEV1 */ + /** * Message rules, defines allowed payloads. */ @@ -460,6 +526,17 @@ static message_rule_t message_rules[] = { countof(me_connect_r_order), me_connect_r_order, }, #endif /* ME */ +#ifdef USE_IKEV1 + {ID_PROT, TRUE, FALSE, + countof(id_prot_i_rules), id_prot_i_rules, + countof(id_prot_i_order), id_prot_i_order, + }, + {ID_PROT, FALSE, FALSE, + countof(id_prot_r_rules), id_prot_r_rules, + countof(id_prot_r_order), id_prot_r_order, + }, + /* TODO-IKEv1: define rules for other exchanges */ +#endif /* USE_IKEV1 */ }; From 130c9a54c2c9c5586d685bf98b3bf004f7465d8f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 15 Nov 2011 18:21:28 +0100 Subject: [PATCH 010/534] Message rules for IKEv1 AGGRESSIVE exchange added. These are basically the same as for ID_PROT but no payloads are expected to be encrypted (at least if using PSK or signatures for authentication). --- src/libcharon/encoding/message.c | 72 ++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index eab3427a1..5386d4984 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -478,6 +478,70 @@ static payload_order_t id_prot_r_order[] = { {NOTIFICATION_V1, 0}, {VENDOR_ID_V1, 0}, }; + +/** + * Message rule for AGGRESSIVE from initiator. + */ +static payload_rule_t aggressive_i_rules[] = { +/* payload type min max encr suff */ + {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, FALSE, FALSE}, + {CERTIFICATE_V1, 0, 1, FALSE, FALSE}, + {SIGNATURE_V1, 0, 1, FALSE, FALSE}, + {HASH_V1, 0, 1, FALSE, FALSE}, +}; + +/** + * payload order for AGGRESSIVE from initiator. + */ +static payload_order_t aggressive_i_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {NOTIFICATION_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for AGGRESSIVE from responder. + */ +static payload_rule_t aggressive_r_rules[] = { +/* payload type min max encr suff */ + {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, FALSE, FALSE}, + {CERTIFICATE_V1, 0, 1, FALSE, FALSE}, + {SIGNATURE_V1, 0, 1, FALSE, FALSE}, + {HASH_V1, 0, 1, FALSE, FALSE}, +}; + +/** + * payload order for AGGRESSIVE from responder. + */ +static payload_order_t aggressive_r_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {NOTIFICATION_V1, 0}, + {VENDOR_ID_V1, 0}, +}; #endif /* USE_IKEV1 */ /** @@ -535,6 +599,14 @@ static message_rule_t message_rules[] = { countof(id_prot_r_rules), id_prot_r_rules, countof(id_prot_r_order), id_prot_r_order, }, + {AGGRESSIVE, TRUE, FALSE, + countof(aggressive_i_rules), aggressive_i_rules, + countof(aggressive_i_order), aggressive_i_order, + }, + {AGGRESSIVE, FALSE, FALSE, + countof(aggressive_r_rules), aggressive_r_rules, + countof(aggressive_r_order), aggressive_r_order, + }, /* TODO-IKEv1: define rules for other exchanges */ #endif /* USE_IKEV1 */ }; From 8f3aea2f774c5647c6cb7e4da664c6323f5cc669 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 15 Nov 2011 18:23:15 +0100 Subject: [PATCH 011/534] Message rules for IKEv1 INFORMATIONAL exchange added. Since INFORMATIONAL "exchanges" are actually unidirectionally sent message we don't have any responder rules. --- src/libcharon/encoding/message.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 5386d4984..823a97f0f 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -542,6 +542,26 @@ static payload_order_t aggressive_r_order[] = { {NOTIFICATION_V1, 0}, {VENDOR_ID_V1, 0}, }; + +/** + * Message rule for INFORMATIONAL_V1 from initiator. + */ +static payload_rule_t informational_i_rules_v1[] = { +/* payload type min max encr suff */ + {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL_V1 from initiator. + */ +static payload_order_t informational_i_order_v1[] = { +/* payload type notify type */ + {NOTIFICATION_V1, 0}, + {DELETE_V1, 0}, + {VENDOR_ID_V1, 0}, +}; #endif /* USE_IKEV1 */ /** @@ -607,6 +627,10 @@ static message_rule_t message_rules[] = { countof(aggressive_r_rules), aggressive_r_rules, countof(aggressive_r_order), aggressive_r_order, }, + {INFORMATIONAL_V1, TRUE, TRUE, + countof(informational_i_rules_v1), informational_i_rules_v1, + countof(informational_i_order_v1), informational_i_order_v1, + }, /* TODO-IKEv1: define rules for other exchanges */ #endif /* USE_IKEV1 */ }; From b0b9d185931e7f88f0f7c89e9ef4e6034ac38dd3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 09:29:38 +0100 Subject: [PATCH 012/534] Extend sa_payload for IKEv1 support --- src/conftest/hooks/custom_proposal.c | 3 +- src/conftest/hooks/pretend_auth.c | 3 +- src/conftest/hooks/set_proposal_number.c | 2 +- src/libcharon/encoding/parser.c | 12 ++ src/libcharon/encoding/payloads/encodings.h | 5 + src/libcharon/encoding/payloads/payload.c | 3 +- src/libcharon/encoding/payloads/payload.h | 12 ++ src/libcharon/encoding/payloads/sa_payload.c | 125 +++++++++++++++---- src/libcharon/encoding/payloads/sa_payload.h | 20 ++- src/libcharon/sa/tasks/child_create.c | 6 +- src/libcharon/sa/tasks/ike_init.c | 6 +- 11 files changed, 160 insertions(+), 37 deletions(-) diff --git a/src/conftest/hooks/custom_proposal.c b/src/conftest/hooks/custom_proposal.c index e4acd841f..9522335b1 100644 --- a/src/conftest/hooks/custom_proposal.c +++ b/src/conftest/hooks/custom_proposal.c @@ -145,7 +145,8 @@ METHOD(listener_t, message, bool, proposal->get_protocol(proposal), proposal->get_spi(proposal)); DBG1(DBG_CFG, "injecting custom proposal: %#P", new_props); - new = sa_payload_create_from_proposal_list(new_props); + new = sa_payload_create_from_proposal_list( + SECURITY_ASSOCIATION, new_props); message->add_payload(message, (payload_t*)new); new_props->destroy_offset(new_props, offsetof(proposal_t, destroy)); } diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c index 4b7168cac..dd6ab9959 100644 --- a/src/conftest/hooks/pretend_auth.c +++ b/src/conftest/hooks/pretend_auth.c @@ -294,7 +294,8 @@ static void process_auth_response(private_pretend_auth_t *this, if (this->proposal) { message->add_payload(message, (payload_t*) - sa_payload_create_from_proposal(this->proposal)); + sa_payload_create_from_proposal(SECURITY_ASSOCIATION, + this->proposal)); } if (this->tsi) { diff --git a/src/conftest/hooks/set_proposal_number.c b/src/conftest/hooks/set_proposal_number.c index a59d96b6d..32b0155cb 100644 --- a/src/conftest/hooks/set_proposal_number.c +++ b/src/conftest/hooks/set_proposal_number.c @@ -121,7 +121,7 @@ METHOD(listener_t, message, bool, } enumerator->destroy(enumerator); } - sa = sa_payload_create_from_proposal_list(updated); + sa = sa_payload_create_from_proposal_list(SECURITY_ASSOCIATION, updated); list->destroy_offset(list, offsetof(proposal_t, destroy)); updated->destroy_offset(updated, offsetof(proposal_t, destroy)); message->add_payload(message, (payload_t*)sa); diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 6309a5c3f..09b52168f 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -496,6 +496,18 @@ METHOD(parser_t, parse_payload, status_t, } break; } + case PROPOSALS_V1: + { + if (payload_length < SA_PAYLOAD_V1_HEADER_LENGTH || + !parse_list(this, rule_number, output + rule->offset, + PROPOSAL_SUBSTRUCTURE_V1, + payload_length - SA_PAYLOAD_V1_HEADER_LENGTH)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } case TRANSFORMS: { if (payload_length < diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index 52af4a984..80df979cc 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -219,6 +219,11 @@ enum encoding_type_t { */ PROPOSALS, + /** + * Same as PROPOSALS, but for IKEv1 in a SECURITY_ASSOCIATION_V1 + */ + PROPOSALS_V1, + /** * Representating one or more transform substructures. * diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 78451c5b4..14617b4e3 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -156,7 +156,8 @@ payload_t *payload_create(payload_type_t type) case HEADER: return (payload_t*)ike_header_create(); case SECURITY_ASSOCIATION: - return (payload_t*)sa_payload_create(); + case SECURITY_ASSOCIATION_V1: + return (payload_t*)sa_payload_create(type); case PROPOSAL_SUBSTRUCTURE: return (payload_t*)proposal_substructure_create(); case TRANSFORM_SUBSTRUCTURE: diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index 021383a1d..ff1ae73a3 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -29,6 +29,10 @@ typedef struct payload_t payload_t; #include #include +/** + * Domain of interpretation used by IPsec/IKEv1 + */ +#define IKEV1_DOI_IPSEC 1 /** * Payload-Types of an IKE message. @@ -243,6 +247,14 @@ enum payload_type_t { * used internally to handle a transform attribute like a payload. */ CONFIGURATION_ATTRIBUTE = 261, + + /** + * PROPOSAL_SUBSTRUCTURE has a value of PRIVATE USE space. + * + * This payload type is not sent over wire and just + * used internally to handle a proposal substructure like a payload. + */ + PROPOSAL_SUBSTRUCTURE_V1 = 262, }; /** diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 89464ac3d..af3012623 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -22,6 +22,8 @@ #include #include +/* IKEv1 situation */ +#define SIT_IDENTITY_ONLY 1 typedef struct private_sa_payload_t private_sa_payload_t; @@ -48,7 +50,7 @@ struct private_sa_payload_t { /** * Reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. @@ -58,21 +60,75 @@ struct private_sa_payload_t { /** * Proposals in this payload are stored in a linked_list_t. */ - linked_list_t * proposals; + linked_list_t *proposals; + + /** + * Type of this payload, V1 or V2 + */ + payload_type_t type; + + /** + * IKEv1 DOI + */ + u_int32_t doi; + + /** + * IKEv1 situation + */ + u_int32_t situation; }; /** - * Encoding rules to parse or generate a IKEv2-SA Payload - * - * The defined offsets are the positions in a object of type - * private_sa_payload_t. + * Encoding rules for IKEv1 SA payload */ -encoding_rule_t sa_payload_encodings[] = { +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, + /* 8 reserved bits */ + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[7]) }, + /* Length of the whole SA payload*/ + { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, + /* DOI*/ + { U_INT_32, offsetof(private_sa_payload_t, doi) }, + /* Situation*/ + { U_INT_32, offsetof(private_sa_payload_t, situation) }, + /* Proposals are stored in a proposal substructure, + offset points to a linked_list_t pointer */ + { PROPOSALS_V1, offsetof(private_sa_payload_t, proposals) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Situation ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Encoding rules for IKEv2 SA payload + */ +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, /* the critical bit */ { FLAG, offsetof(private_sa_payload_t, critical) }, - /* 7 Bit reserved bits, nowhere stored */ + /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, @@ -144,14 +200,22 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, void, private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count) { - *rules = sa_payload_encodings; - *rule_count = countof(sa_payload_encodings); + if (this->type == SECURITY_ASSOCIATION_V1) + { + *rules = encodings_v1; + *rule_count = countof(encodings_v1); + } + else + { + *rules = encodings_v2; + *rule_count = countof(encodings_v2); + } } METHOD(payload_t, get_type, payload_type_t, private_sa_payload_t *this) { - return SECURITY_ASSOCIATION; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -175,6 +239,11 @@ static void compute_length(private_sa_payload_t *this) payload_t *current; size_t length = SA_PAYLOAD_HEADER_LENGTH; + if (this->type == SECURITY_ASSOCIATION_V1) + { + length = SA_PAYLOAD_V1_HEADER_LENGTH; + } + enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, (void **)¤t)) { @@ -270,14 +339,14 @@ METHOD2(payload_t, sa_payload_t, destroy, void, private_sa_payload_t *this) { this->proposals->destroy_offset(this->proposals, - offsetof(proposal_substructure_t, destroy)); + offsetof(payload_t, destroy)); free(this); } /* * Described in header. */ -sa_payload_t *sa_payload_create() +sa_payload_t *sa_payload_create(payload_type_t type) { private_sa_payload_t *this; @@ -298,41 +367,49 @@ sa_payload_t *sa_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = SA_PAYLOAD_HEADER_LENGTH, .proposals = linked_list_create(), + .type = type, + /* for IKEv1 only */ + .doi = IKEV1_DOI_IPSEC, + .situation = SIT_IDENTITY_ONLY, ); + + compute_length(this); + return &this->public; } /* * Described in header. */ -sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals) +sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type, + linked_list_t *proposals) { - private_sa_payload_t *this; + sa_payload_t *this; enumerator_t *enumerator; proposal_t *proposal; - this = (private_sa_payload_t*)sa_payload_create(); + this = sa_payload_create(type); enumerator = proposals->create_enumerator(proposals); while (enumerator->enumerate(enumerator, &proposal)) { - add_proposal(this, proposal); + this->add_proposal(this, proposal); } enumerator->destroy(enumerator); - return &this->public; + return this; } /* * Described in header. */ -sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal) +sa_payload_t *sa_payload_create_from_proposal(payload_type_t type, + proposal_t *proposal) { - private_sa_payload_t *this; + sa_payload_t *this; - this = (private_sa_payload_t*)sa_payload_create(); - add_proposal(this, proposal); + this = sa_payload_create(type); + this->add_proposal(this, proposal); - return &this->public; + return this; } diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h index cc8c481c8..11fc774e5 100644 --- a/src/libcharon/encoding/payloads/sa_payload.h +++ b/src/libcharon/encoding/payloads/sa_payload.h @@ -30,12 +30,17 @@ typedef struct sa_payload_t sa_payload_t; #include /** - * SA_PAYLOAD length in bytes without any proposal substructure. + * SECURITY_ASSOCIATION length in bytes without any proposal substructure. */ #define SA_PAYLOAD_HEADER_LENGTH 4 /** - * Class representing an IKEv2-SA Payload. + * SECURITY_ASSOCIATION_V1 length in bytes without any proposal substructure. + */ +#define SA_PAYLOAD_V1_HEADER_LENGTH 12 + +/** + * Class representing an IKEv1 or IKEv2 SA Payload. * * The SA Payload format is described in RFC section 3.3. */ @@ -76,17 +81,20 @@ struct sa_payload_t { /** * Creates an empty sa_payload_t object * + * @param type SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1 * @return created sa_payload_t object */ -sa_payload_t *sa_payload_create(void); +sa_payload_t *sa_payload_create(payload_type_t type); /** * Creates a sa_payload_t object from a list of proposals. * + * @param type SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1 * @param proposals list of proposals to build the payload from * @return sa_payload_t object */ -sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals); +sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type, + linked_list_t *proposals); /** * Creates a sa_payload_t object from a single proposal. @@ -94,9 +102,11 @@ sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals); * This is only for convenience. Use sa_payload_create_from_proposal_list * if you want to add more than one proposal. * + * @param type SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1 * @param proposal proposal from which the payload should be built. * @return sa_payload_t object */ -sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal); +sa_payload_t *sa_payload_create_from_proposal(payload_type_t type, + proposal_t *proposal); #endif /** SA_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index 67c29d31f..fdc5b520e 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -526,11 +526,13 @@ static void build_payloads(private_child_create_t *this, message_t *message) /* add SA payload */ if (this->initiator) { - sa_payload = sa_payload_create_from_proposal_list(this->proposals); + sa_payload = sa_payload_create_from_proposal_list(SECURITY_ASSOCIATION, + this->proposals); } else { - sa_payload = sa_payload_create_from_proposal(this->proposal); + sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION, + this->proposal); } message->add_payload(message, (payload_t*)sa_payload); diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/tasks/ike_init.c index b8e66c7e6..911e0c2aa 100644 --- a/src/libcharon/sa/tasks/ike_init.c +++ b/src/libcharon/sa/tasks/ike_init.c @@ -132,7 +132,8 @@ static void build_payloads(private_ike_init_t *this, message_t *message) enumerator->destroy(enumerator); } - sa_payload = sa_payload_create_from_proposal_list(proposal_list); + sa_payload = sa_payload_create_from_proposal_list(SECURITY_ASSOCIATION, + proposal_list); proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); } else @@ -142,7 +143,8 @@ static void build_payloads(private_ike_init_t *this, message_t *message) /* include SPI of new IKE_SA when we are rekeying */ this->proposal->set_spi(this->proposal, id->get_responder_spi(id)); } - sa_payload = sa_payload_create_from_proposal(this->proposal); + sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION, + this->proposal); } message->add_payload(message, (payload_t*)sa_payload); From 3f6d1b13a7d53bf465c65687e18425d14a143af8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 12:40:09 +0000 Subject: [PATCH 013/534] Added additional IKEv1 payload and encoding identifiers --- src/libcharon/encoding/parser.c | 25 +++++++++ src/libcharon/encoding/payloads/encodings.c | 3 ++ src/libcharon/encoding/payloads/encodings.h | 10 ++++ src/libcharon/encoding/payloads/payload.c | 29 ++++++++--- src/libcharon/encoding/payloads/payload.h | 56 +++++++++------------ 5 files changed, 83 insertions(+), 40 deletions(-) diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 09b52168f..c2c60f06a 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -521,6 +521,19 @@ METHOD(parser_t, parse_payload, status_t, } break; } + case TRANSFORMS_V1: + { + if (payload_length < + spi_size + PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH || + !parse_list(this, rule_number, output + rule->offset, + TRANSFORM_SUBSTRUCTURE_V1, payload_length - spi_size - + PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } case TRANSFORM_ATTRIBUTES: { if (payload_length < TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH || @@ -533,6 +546,18 @@ METHOD(parser_t, parse_payload, status_t, } break; } + case TRANSFORM_ATTRIBUTES_V1: + { + if (payload_length < TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH || + !parse_list(this, rule_number, output + rule->offset, + TRANSFORM_ATTRIBUTE_V1, + payload_length - TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } case CONFIGURATION_ATTRIBUTES: { if (payload_length < CP_PAYLOAD_HEADER_LENGTH || diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index 85caeda82..d181d9303 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -32,8 +32,11 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "KEY_EXCHANGE_DATA", "NOTIFICATION_DATA", "PROPOSALS", + "PROPOSALS_V1", "TRANSFORMS", + "TRANSFORMS_V1", "TRANSFORM_ATTRIBUTES", + "TRANSFORM_ATTRIBUTES_V1", "CONFIGURATION_ATTRIBUTES", "CONFIGURATION_ATTRIBUTE_VALUE", "ATTRIBUTE_FORMAT", diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index 80df979cc..8c9fb866c 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -237,6 +237,11 @@ enum encoding_type_t { */ TRANSFORMS, + /** + * Same as TRANSFORMS, but for IKEv1 in a PROPOSAL_SUBSTRUCTURE_V1. + */ + TRANSFORMS_V1, + /** * Representating one or more Attributes of a transform substructure. * @@ -250,6 +255,11 @@ enum encoding_type_t { */ TRANSFORM_ATTRIBUTES, + /** + * Same as TRANSFORM_ATTRIBUTES, but for IKEv1 in TRANSFORMS_V1. + */ + TRANSFORM_ATTRIBUTES_V1, + /** * Representating one or more Attributes of a configuration payload. * diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 14617b4e3..2021e847e 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -76,16 +76,22 @@ ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, "HEADER", "PROPOSAL_SUBSTRUCTURE", + "PROPOSAL_SUBSTRUCTURE_V1", "TRANSFORM_SUBSTRUCTURE", + "TRANSFORM_SUBSTRUCTURE_V1", "TRANSFORM_ATTRIBUTE", + "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", "CONFIGURATION_ATTRIBUTE"); #else ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, EXTENSIBLE_AUTHENTICATION, "HEADER", "PROPOSAL_SUBSTRUCTURE", + "PROPOSAL_SUBSTRUCTURE_V1", "TRANSFORM_SUBSTRUCTURE", + "TRANSFORM_SUBSTRUCTURE_V1", "TRANSFORM_ATTRIBUTE", + "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", "CONFIGURATION_ATTRIBUTE"); #endif /* ME */ @@ -131,18 +137,24 @@ ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, "HDR", "PROP", + "PROP", + "TRANS", "TRANS", "TRANSATTR", + "TRANSATTR", "TSSUB", - "CPATTR"); + "CATTR"); #else ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, EXTENSIBLE_AUTHENTICATION, "HDR", "PROP", + "PROP", + "TRANS", "TRANS", "TRANSATTR", + "TRANSATTR", "TSSUB", - "CPATTR"); + "CATTR"); #endif /* ME */ ENUM_END(payload_type_short_names, CONFIGURATION_ATTRIBUTE); @@ -159,21 +171,22 @@ payload_t *payload_create(payload_type_t type) case SECURITY_ASSOCIATION_V1: return (payload_t*)sa_payload_create(type); case PROPOSAL_SUBSTRUCTURE: - return (payload_t*)proposal_substructure_create(); + case PROPOSAL_SUBSTRUCTURE_V1: + return (payload_t*)proposal_substructure_create(type); case TRANSFORM_SUBSTRUCTURE: - return (payload_t*)transform_substructure_create(); + case TRANSFORM_SUBSTRUCTURE_V1: + return (payload_t*)transform_substructure_create(type); case TRANSFORM_ATTRIBUTE: - return (payload_t*)transform_attribute_create(); + case TRANSFORM_ATTRIBUTE_V1: + return (payload_t*)transform_attribute_create(type); case NONCE: return (payload_t*)nonce_payload_create(); case ID_INITIATOR: - return (payload_t*)id_payload_create(ID_INITIATOR); case ID_RESPONDER: - return (payload_t*)id_payload_create(ID_RESPONDER); #ifdef ME case ID_PEER: - return (payload_t*)id_payload_create(ID_PEER); #endif /* ME */ + return (payload_t*)id_payload_create(type); case AUTHENTICATION: return (payload_t*)auth_payload_create(); case CERTIFICATE: diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index ff1ae73a3..5e0b7dd38 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -203,58 +203,50 @@ enum payload_type_t { /** * Header has a value of PRIVATE USE space. * - * This payload type is not sent over wire and just - * used internally to handle IKEv2-Header like a payload. + * This type and all the following are never sent over wire and are + * used internally only. */ HEADER = 256, /** - * PROPOSAL_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a proposal substructure like a payload. + * PROPOSAL_SUBSTRUCTURE, IKEv2 proposals in a SA payload. */ - PROPOSAL_SUBSTRUCTURE = 257, + PROPOSAL_SUBSTRUCTURE, /** - * TRANSFORM_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform substructure like a payload. + * PROPOSAL_SUBSTRUCTURE_V1, IKEv1 proposals in a SA payload. */ - TRANSFORM_SUBSTRUCTURE = 258, + PROPOSAL_SUBSTRUCTURE_V1, /** - * TRANSFORM_ATTRIBUTE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform attribute like a payload. + * TRANSFORM_SUBSTRUCTURE, IKEv2 transforms in a proposal substructure. */ - TRANSFORM_ATTRIBUTE = 259, + TRANSFORM_SUBSTRUCTURE, /** - * TRAFFIC_SELECTOR_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform selector like a payload. + * TRANSFORM_SUBSTRUCTURE_V1, IKEv1 transforms in a proposal substructure. */ - TRAFFIC_SELECTOR_SUBSTRUCTURE = 260, + TRANSFORM_SUBSTRUCTURE_V1, /** - * CONFIGURATION_ATTRIBUTE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform attribute like a payload. + * TRANSFORM_ATTRIBUTE, IKEv2 attribute in a transform. */ - CONFIGURATION_ATTRIBUTE = 261, + TRANSFORM_ATTRIBUTE, /** - * PROPOSAL_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a proposal substructure like a payload. + * TRANSFORM_ATTRIBUTE_V1, IKEv1 attribute in a transform. */ - PROPOSAL_SUBSTRUCTURE_V1 = 262, + TRANSFORM_ATTRIBUTE_V1, + + /** + * TRAFFIC_SELECTOR_SUBSTRUCTURE, traffic selector in a TS payload. + */ + TRAFFIC_SELECTOR_SUBSTRUCTURE, + + /** + * CONFIGURATION_ATTRIBUTE, attribute in a configuration payload. + */ + CONFIGURATION_ATTRIBUTE, }; /** From 1bf2971ff2d63f1f1c4d59d1091b8a1b11b0ef62 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 13:46:54 +0100 Subject: [PATCH 014/534] Implemented limited payload parsing for IKEv1 SA payloads --- .../encoding/payloads/proposal_substructure.c | 354 ++++++++++++++++-- .../encoding/payloads/proposal_substructure.h | 12 +- src/libcharon/encoding/payloads/sa_payload.c | 19 +- .../encoding/payloads/transform_attribute.c | 89 +++-- .../encoding/payloads/transform_attribute.h | 61 ++- .../payloads/transform_substructure.c | 163 ++++---- .../payloads/transform_substructure.h | 35 +- 7 files changed, 557 insertions(+), 176 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 4753d574d..efa748bd0 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -25,7 +25,7 @@ #include /** - * IKEv1 Value for a proposal payload. + * IKEv2 Value for a proposal payload. */ #define PROPOSAL_TYPE_VALUE 2 @@ -84,16 +84,43 @@ struct private_proposal_substructure_t { /** * Transforms are stored in a linked_list_t. */ - linked_list_t * transforms; + linked_list_t *transforms; + + /** + * Type of this payload, PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a Proposal substructure. - * - * The defined offsets are the positions in a object of type - * private_proposal_substructure_t. + * Encoding rules for a IKEv1 Proposal substructure. */ -encoding_rule_t proposal_substructure_encodings[] = { +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, + /* 1 Reserved Byte */ + { RESERVED_BYTE, offsetof(private_proposal_substructure_t, reserved) }, + /* Length of the whole proposal substructure payload*/ + { PAYLOAD_LENGTH, offsetof(private_proposal_substructure_t, proposal_length) }, + /* proposal number is a number of 8 bit */ + { U_INT_8, offsetof(private_proposal_substructure_t, proposal_number) }, + /* protocol ID is a number of 8 bit */ + { U_INT_8, offsetof(private_proposal_substructure_t, protocol_id) }, + /* SPI Size has its own type */ + { SPI_SIZE, offsetof(private_proposal_substructure_t, spi_size) }, + /* Number of transforms is a number of 8 bit */ + { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) }, + /* SPI is a chunk of variable size*/ + { SPI, offsetof(private_proposal_substructure_t, spi) }, + /* Transforms are stored in a transform substructure, + offset points to a linked_list_t pointer */ + { TRANSFORMS_V1, offsetof(private_proposal_substructure_t, transforms) } +}; + +/** + * Encoding rules for a IKEv2 Proposal substructure. + */ +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, /* 1 Reserved Byte */ @@ -131,6 +158,76 @@ encoding_rule_t proposal_substructure_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encryption. + */ +typedef enum { + IKEV1_ENCR_DES_CBC = 1, + IKEV1_ENCR_IDEA_CBC = 2, + IKEV1_ENCR_BLOWFISH_CBC = 3, + IKEV1_ENCR_RC5_R16_B64_CBC = 4, + IKEV1_ENCR_3DES_CBC = 5, + IKEV1_ENCR_CAST_CBC = 6, + IKEV1_ENCR_AES_CBC = 7, + IKEV1_ENCR_CAMELLIA_CBC = 8, + IKEV1_ENCR_LAST = 9, +} ikev1_encryption_t; + +/** + * IKEv1 hash. + */ +typedef enum { + IKEV1_HASH_MD5 = 1, + IKEV1_HASH_SHA1 = 2, + IKEV1_HASH_TIGER = 3, + IKEV1_HASH_SHA2_256 = 4, + IKEV1_HASH_SHA2_384 = 5, + IKEV1_HASH_SHA2_512 = 6, +} ikev1_hash_t; + +/** + * IKEv1 Transform ID IKE. + */ +typedef enum { + IKEV1_TRANSID_KEY_IKE = 1, +} ikev1_ike_transid_t; + +/** + * IKEv1 Transform ID ESP. + */ +typedef enum { + IKEV1_TRANSID_ESP_DES_IV64 = 1, + IKEV1_TRANSID_ESP_DES = 2, + IKEV1_TRANSID_ESP_3DES = 3, + IKEV1_TRANSID_ESP_RC5 = 4, + IKEV1_TRANSID_ESP_IDEA = 5, + IKEV1_TRANSID_ESP_CAST = 6, + IKEV1_TRANSID_ESP_BLOWFISH = 7, + IKEV1_TRANSID_ESP_3IDEA = 8, + IKEV1_TRANSID_ESP_DES_IV32 = 9, + IKEV1_TRANSID_ESP_RC4 = 10, + IKEV1_TRANSID_ESP_NULL = 11, + IKEV1_TRANSID_ESP_AES_CBC = 12, +} ikev1_esp_transid_t; + +/** + * IKEv1 ESP Encapsulation mode. + */ +typedef enum { + IKEV1_ENCAP_TUNNEL = 1, + IKEV1_ENCAP_TRANSPORT = 2, + IKEV1_ENCAP_UDP_TUNNEL = 3, + IKEV1_ENCAP_UDP_TRANSPORT = 4, +} ikev1_esp_encap_t; + +/** + * IKEv1 Life duration types. + */ +typedef enum { + IKEV1_LIFE_TYPE_SECONDS = 1, + IKEV1_LIFE_TYPE_KILOBYTES = 2, +} ikev1_life_type_t; + METHOD(payload_t, verify, status_t, private_proposal_substructure_t *this) { @@ -192,14 +289,22 @@ METHOD(payload_t, get_encoding_rules, void, private_proposal_substructure_t *this, encoding_rule_t **rules, size_t *rule_count) { - *rules = proposal_substructure_encodings; - *rule_count = countof(proposal_substructure_encodings); + if (this->type == PROPOSAL_SUBSTRUCTURE) + { + *rules = encodings_v2; + *rule_count = countof(encodings_v2); + } + else + { + *rules = encodings_v1; + *rule_count = countof(encodings_v1); + } } METHOD(payload_t, get_type, payload_type_t, private_proposal_substructure_t *this) { - return PROPOSAL_SUBSTRUCTURE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -301,43 +406,206 @@ METHOD(proposal_substructure_t, get_spi, chunk_t, return this->spi; } +/** + * Add a transform to a proposal for IKEv2 + */ +static void add_to_proposal_v2(proposal_t *proposal, + transform_substructure_t *transform) +{ + transform_attribute_t *tattr; + enumerator_t *enumerator; + u_int16_t key_length = 0; + + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &tattr)) + { + if (tattr->get_attribute_type(tattr) == TATTR_IKEV2_KEY_LENGTH) + { + key_length = tattr->get_value(tattr); + break; + } + } + enumerator->destroy(enumerator); + + proposal->add_algorithm(proposal, + transform->get_transform_type_or_number(transform), + transform->get_transform_id(transform), key_length); +} + +/** + * Get IKEv2 algorithm from IKEv1 identifier + */ +static u_int16_t get_alg_from_ikev1(transform_type_t type, u_int16_t value) +{ + typedef struct { + u_int16_t ikev1; + u_int16_t ikev2; + } algo_map_t; + + static algo_map_t encr[] = { + { IKEV1_ENCR_DES_CBC, ENCR_DES }, + { IKEV1_ENCR_IDEA_CBC, ENCR_IDEA }, + { IKEV1_ENCR_BLOWFISH_CBC, ENCR_BLOWFISH }, + { IKEV1_ENCR_3DES_CBC, ENCR_3DES }, + { IKEV1_ENCR_CAST_CBC, ENCR_CAST }, + { IKEV1_ENCR_AES_CBC, ENCR_AES_CBC }, + { IKEV1_ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CBC }, + }; + static algo_map_t integ[] = { + { IKEV1_HASH_MD5, AUTH_HMAC_MD5_96 }, + { IKEV1_HASH_SHA1, AUTH_HMAC_SHA1_96 }, + { IKEV1_HASH_SHA2_256, AUTH_HMAC_SHA2_256_128 }, + { IKEV1_HASH_SHA2_384, AUTH_HMAC_SHA2_384_192 }, + { IKEV1_HASH_SHA2_512, AUTH_HMAC_SHA2_512_256 }, + }; + static algo_map_t prf[] = { + { IKEV1_HASH_MD5, PRF_HMAC_MD5 }, + { IKEV1_HASH_SHA1, PRF_HMAC_SHA1 }, + { IKEV1_HASH_SHA2_256, PRF_HMAC_SHA2_256 }, + { IKEV1_HASH_SHA2_384, PRF_HMAC_SHA2_384 }, + { IKEV1_HASH_SHA2_512, PRF_HMAC_SHA2_512 }, + }; + int i, count; + u_int16_t def; + algo_map_t *map; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = encr; + count = countof(encr); + def = ENCR_UNDEFINED; + break; + case INTEGRITY_ALGORITHM: + map = integ; + count = countof(integ); + def = AUTH_UNDEFINED; + break; + case PSEUDO_RANDOM_FUNCTION: + map = prf; + count = countof(prf); + def = PRF_UNDEFINED; + break; + default: + return 0; + } + + for (i = 0; i < count; i++) + { + if (map[i].ikev1 == value) + { + return map[i].ikev2; + } + } + return def; +} + +/** + * Add an IKE transform to a proposal for IKEv1 + */ +static void add_to_proposal_v1_ike(proposal_t *proposal, + transform_substructure_t *transform) +{ + transform_attribute_type_t type; + transform_attribute_t *tattr; + enumerator_t *enumerator; + u_int16_t value, key_length = 0; + u_int16_t encr = ENCR_UNDEFINED; + + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &tattr)) + { + type = tattr->get_attribute_type(tattr); + value = tattr->get_value(tattr); + switch (type) + { + case TATTR_PH1_ENCRYPTION_ALGORITHM: + encr = get_alg_from_ikev1(ENCRYPTION_ALGORITHM, value); + break; + case TATTR_PH1_KEY_LENGTH: + key_length = value; + break; + case TATTR_PH1_HASH_ALGORITHM: + proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, + get_alg_from_ikev1(INTEGRITY_ALGORITHM, value), 0); + proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, + get_alg_from_ikev1(PSEUDO_RANDOM_FUNCTION, value), 0); + break; + case TATTR_PH1_GROUP: + proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + value, 0); + break; + default: + /* TODO-IKEv1: lifetimes, authentication and other attributes */ + break; + } + } + enumerator->destroy(enumerator); + + if (encr != ENCR_UNDEFINED) + { + proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, key_length); + } +} + +/** + * Add an ESP transform to a proposal for IKEv1 + */ +static void add_to_proposal_v1_esp(proposal_t *proposal, + transform_substructure_t *transform) +{ + /* TODO-IKEv1: create ESP proposals */ +} + METHOD(proposal_substructure_t, get_proposal, proposal_t*, private_proposal_substructure_t *this) { - enumerator_t *enumerator; transform_substructure_t *transform; + enumerator_t *enumerator; proposal_t *proposal; - u_int64_t spi; proposal = proposal_create(this->protocol_id, this->proposal_number); enumerator = this->transforms->create_enumerator(this->transforms); while (enumerator->enumerate(enumerator, &transform)) { - transform_type_t transform_type; - u_int16_t transform_id; - u_int16_t key_length = 0; - - transform_type = transform->get_transform_type(transform); - transform_id = transform->get_transform_id(transform); - transform->get_key_length(transform, &key_length); - - proposal->add_algorithm(proposal, transform_type, transform_id, key_length); + if (this->type == PROPOSAL_SUBSTRUCTURE) + { + add_to_proposal_v2(proposal, transform); + } + else + { + switch (this->protocol_id) + { + case PROTO_IKE: + add_to_proposal_v1_ike(proposal, transform); + break; + case PROTO_ESP: + add_to_proposal_v1_esp(proposal, transform); + break; + default: + break; + } + /* TODO-IKEv1: We currently accept the first set of transforms + * in a substructure only. We need to return multiple proposals, + * but this messes up proposal numbering, as we don't support + * transform numbering. */ + break; + } } enumerator->destroy(enumerator); switch (this->spi.len) { case 4: - spi = *((u_int32_t*)this->spi.ptr); + proposal->set_spi(proposal, *((u_int32_t*)this->spi.ptr)); break; case 8: - spi = *((u_int64_t*)this->spi.ptr); + proposal->set_spi(proposal, *((u_int64_t*)this->spi.ptr)); break; default: - spi = 0; + break; } - proposal->set_spi(proposal, spi); return proposal; } @@ -352,7 +620,7 @@ METHOD2(payload_t, proposal_substructure_t, destroy, void, private_proposal_substructure_t *this) { this->transforms->destroy_offset(this->transforms, - offsetof(transform_substructure_t, destroy)); + offsetof(payload_t, destroy)); chunk_free(&this->spi); free(this); } @@ -360,7 +628,7 @@ METHOD2(payload_t, proposal_substructure_t, destroy, void, /* * Described in header. */ -proposal_substructure_t *proposal_substructure_create() +proposal_substructure_t *proposal_substructure_create(payload_type_t type) { private_proposal_substructure_t *this; @@ -389,6 +657,7 @@ proposal_substructure_t *proposal_substructure_create() .next_payload = NO_PAYLOAD, .proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH, .transforms = linked_list_create(), + .type = type, ); return &this->public; @@ -398,21 +667,28 @@ proposal_substructure_t *proposal_substructure_create() * Described in header. */ proposal_substructure_t *proposal_substructure_create_from_proposal( - proposal_t *proposal) + payload_type_t type, proposal_t *proposal) { transform_substructure_t *transform; private_proposal_substructure_t *this; u_int16_t alg, key_size; enumerator_t *enumerator; + payload_type_t subtype = TRANSFORM_SUBSTRUCTURE; - this = (private_proposal_substructure_t*)proposal_substructure_create(); + if (type == PROPOSAL_SUBSTRUCTURE_V1) + { + /* TODO-IKEv1: IKEv1 specific proposal encoding */ + subtype = TRANSFORM_SUBSTRUCTURE_V1; + } + + this = (private_proposal_substructure_t*)proposal_substructure_create(type); /* encryption algorithm is only available in ESP */ enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(ENCRYPTION_ALGORITHM, - alg, key_size); + transform = transform_substructure_create_type(subtype, + ENCRYPTION_ALGORITHM, alg, key_size); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -421,8 +697,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(INTEGRITY_ALGORITHM, - alg, key_size); + transform = transform_substructure_create_type(subtype, + INTEGRITY_ALGORITHM, alg, key_size); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -431,8 +707,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, PSEUDO_RANDOM_FUNCTION); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(PSEUDO_RANDOM_FUNCTION, - alg, key_size); + transform = transform_substructure_create_type(subtype, + PSEUDO_RANDOM_FUNCTION, alg, key_size); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -441,8 +717,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); while (enumerator->enumerate(enumerator, &alg, NULL)) { - transform = transform_substructure_create_type(DIFFIE_HELLMAN_GROUP, - alg, 0); + transform = transform_substructure_create_type(subtype, + DIFFIE_HELLMAN_GROUP, alg, 0); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -451,8 +727,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, EXTENDED_SEQUENCE_NUMBERS); while (enumerator->enumerate(enumerator, &alg, NULL)) { - transform = transform_substructure_create_type(EXTENDED_SEQUENCE_NUMBERS, - alg, 0); + transform = transform_substructure_create_type(subtype, + EXTENDED_SEQUENCE_NUMBERS, alg, 0); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index d0ba1fd2a..86ccd5b8b 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -37,9 +37,7 @@ typedef struct proposal_substructure_t proposal_substructure_t; #define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8 /** - * Class representing an IKEv2-PROPOSAL SUBSTRUCTURE. - * - * The PROPOSAL SUBSTRUCTURE format is described in RFC section 3.3.1. + * Class representing an IKEv1/IKEv2 proposal substructure. */ struct proposal_substructure_t { @@ -126,17 +124,19 @@ struct proposal_substructure_t { /** * Creates an empty proposal_substructure_t object * - * @return proposal_substructure_t object + * @param type PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 + * @return proposal_substructure_t object */ -proposal_substructure_t *proposal_substructure_create(void); +proposal_substructure_t *proposal_substructure_create(payload_type_t type); /** * Creates a proposal_substructure_t from a proposal_t. * + * @param type PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 * @param proposal proposal to build a substruct out of it * @return proposal_substructure_t object */ proposal_substructure_t *proposal_substructure_create_from_proposal( - proposal_t *proposal); + payload_type_t type, proposal_t *proposal); #endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index af3012623..061226310 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -158,11 +158,16 @@ static encoding_rule_t encodings_v2[] = { METHOD(payload_t, verify, status_t, private_sa_payload_t *this) { - int expected_number = 1, current_number; + int expected_number = 0, current_number; status_t status = SUCCESS; enumerator_t *enumerator; proposal_substructure_t *substruct; + if (this->type == SECURITY_ASSOCIATION) + { + expected_number = 1; + } + /* check proposal numbering */ enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, (void**)&substruct)) @@ -264,10 +269,15 @@ METHOD(sa_payload_t, add_proposal, void, private_sa_payload_t *this, proposal_t *proposal) { proposal_substructure_t *substruct, *last; + payload_type_t subtype = PROPOSAL_SUBSTRUCTURE; u_int count; count = this->proposals->get_count(this->proposals); - substruct = proposal_substructure_create_from_proposal(proposal); + if (this->type == SECURITY_ASSOCIATION_V1) + { + subtype = PROPOSAL_SUBSTRUCTURE_V1; + } + substruct = proposal_substructure_create_from_proposal(subtype, proposal); if (count > 0) { this->proposals->get_last(this->proposals, (void**)&last); @@ -297,6 +307,11 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*, linked_list_t *list; proposal_t *proposal; + if (this->type == SECURITY_ASSOCIATION_V1) + { /* IKEv1 proposals start with 0 */ + struct_number = ignore_struct_number = -1; + } + list = linked_list_create(); /* we do not support proposals split up to two proposal substructures, as * AH+ESP bundles are not supported in RFC4301 anymore. diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 7d21258b1..e928dcddb 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -23,6 +23,44 @@ #include #include +ENUM(tattr_ph1_names, TATTR_PH1_ENCRYPTION_ALGORITHM, TATTR_PH1_GROUP_ORDER, + "ENCRYPTION_ALGORITHM", + "HASH_ALGORITHM", + "AUTH_METHOD", + "GROUP", + "GROUP_TYPE", + "GROUP_PRIME", + "GROUP_GENONE", + "GROUP_GENTWO", + "GROUP_CURVE_A", + "GROUP_CURVE_B", + "LIFE_TYPE", + "LIFE_DURATION", + "PRF", + "KEY_LENGTH", + "FIELD_SIZE", + "GROUP_ORDER", +); + +ENUM(tattr_ph2_names, TATTR_PH2_SA_LIFE_TYPE, TATTR_PH2_EXT_SEQ_NUMBER, + "SA_LIFE_TYPE", + "SA_LIFE_DURATION", + "GROUP", + "ENCAP_MODE", + "AUTH_ALGORITHM", + "KEY_LENGTH", + "KEY_ROUNDS", + "COMP_DICT_SIZE", + "COMP_PRIV_ALGORITHM", + "ECN_TUNNEL", + "EXT_SEQ_NUMBER", +); + +ENUM(tattr_ikev2_names, TATTR_IKEV2_KEY_LENGTH, TATTR_IKEV2_KEY_LENGTH, + "KEY_LENGTH", +); + + typedef struct private_transform_attribute_t private_transform_attribute_t; /** @@ -57,22 +95,17 @@ struct private_transform_attribute_t { * Attribute value as chunk if attribute_format is 0 (FALSE). */ chunk_t attribute_value; + + /** + * Payload type, TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 + */ + payload_type_t type; }; - -ENUM_BEGIN(transform_attribute_type_name, ATTRIBUTE_UNDEFINED, ATTRIBUTE_UNDEFINED, - "ATTRIBUTE_UNDEFINED"); -ENUM_NEXT(transform_attribute_type_name, KEY_LENGTH, KEY_LENGTH, ATTRIBUTE_UNDEFINED, - "KEY_LENGTH"); -ENUM_END(transform_attribute_type_name, KEY_LENGTH); - /** - * Encoding rules to parse or generate a Transform attribute. - * - * The defined offsets are the positions in a object of type - * private_transform_attribute_t. + * Encoding rules for IKEv1/IKEv2 transform attributes */ -encoding_rule_t transform_attribute_encodings[] = { +static encoding_rule_t encodings[] = { /* Flag defining the format of this payload */ { ATTRIBUTE_FORMAT, offsetof(private_transform_attribute_t, attribute_format) }, /* type of the attribute as 15 bit unsigned integer */ @@ -105,14 +138,14 @@ METHOD(payload_t, get_encoding_rules, void, private_transform_attribute_t *this, encoding_rule_t **rules, size_t *rule_count) { - *rules = transform_attribute_encodings; - *rule_count = countof(transform_attribute_encodings); + *rules = encodings; + *rule_count = countof(encodings); } METHOD(payload_t, get_type, payload_type_t, private_transform_attribute_t *this) { - return TRANSFORM_ATTRIBUTE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -192,19 +225,19 @@ METHOD(transform_attribute_t, get_attribute_type, u_int16_t, METHOD(transform_attribute_t, clone_, transform_attribute_t*, private_transform_attribute_t *this) { - private_transform_attribute_t *new_clone; + private_transform_attribute_t *new; - new_clone = (private_transform_attribute_t *)transform_attribute_create(); + new = (private_transform_attribute_t*)transform_attribute_create(this->type); - new_clone->attribute_format = this->attribute_format; - new_clone->attribute_type = this->attribute_type; - new_clone->attribute_length_or_value = this->attribute_length_or_value; + new->attribute_format = this->attribute_format; + new->attribute_type = this->attribute_type; + new->attribute_length_or_value = this->attribute_length_or_value; - if (!new_clone->attribute_format) + if (!new->attribute_format) { - new_clone->attribute_value = chunk_clone(this->attribute_value); + new->attribute_value = chunk_clone(this->attribute_value); } - return &new_clone->public; + return &new->public; } METHOD2(payload_t, transform_attribute_t, destroy, void, @@ -217,7 +250,7 @@ METHOD2(payload_t, transform_attribute_t, destroy, void, /* * Described in header. */ -transform_attribute_t *transform_attribute_create() +transform_attribute_t *transform_attribute_create(payload_type_t type) { private_transform_attribute_t *this; @@ -242,6 +275,7 @@ transform_attribute_t *transform_attribute_create() .destroy = _destroy, }, .attribute_format = TRUE, + .type = type, ); return &this->public; } @@ -251,8 +285,11 @@ transform_attribute_t *transform_attribute_create() */ transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length) { - transform_attribute_t *attribute = transform_attribute_create(); - attribute->set_attribute_type(attribute, KEY_LENGTH); + transform_attribute_t *attribute; + + attribute = transform_attribute_create(TRANSFORM_ATTRIBUTE); + attribute->set_attribute_type(attribute, TATTR_IKEV2_KEY_LENGTH); attribute->set_value(attribute, key_length); + return attribute; } diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h index a5fe0154b..21bde46b8 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.h +++ b/src/libcharon/encoding/payloads/transform_attribute.h @@ -28,26 +28,66 @@ typedef struct transform_attribute_t transform_attribute_t; #include #include - /** - * Type of the attribute, as in IKEv2 RFC 3.3.5. + * Type of the attribute. */ enum transform_attribute_type_t { - ATTRIBUTE_UNDEFINED = 16384, - KEY_LENGTH = 14 + /** IKEv1 Phase 1 attributes */ + TATTR_PH1_ENCRYPTION_ALGORITHM = 1, + TATTR_PH1_HASH_ALGORITHM = 2, + TATTR_PH1_AUTH_METHOD = 3, + TATTR_PH1_GROUP = 4, + TATTR_PH1_GROUP_TYPE = 5, + TATTR_PH1_GROUP_PRIME = 6, + TATTR_PH1_GROUP_GENONE = 7, + TATTR_PH1_GROUP_GENTWO = 8, + TATTR_PH1_GROUP_CURVE_A = 9, + TATTR_PH1_GROUP_CURVE_B = 10, + TATTR_PH1_LIFE_TYPE = 11, + TATTR_PH1_LIFE_DURATION = 12, + TATTR_PH1_PRF = 13, + TATTR_PH1_KEY_LENGTH = 14, + TATTR_PH1_FIELD_SIZE = 15, + TATTR_PH1_GROUP_ORDER = 16, + /** IKEv1 Phase 2 attributes */ + TATTR_PH2_SA_LIFE_TYPE = 1, + TATTR_PH2_SA_LIFE_DURATION = 2, + TATTR_PH2_GROUP = 3, + TATTR_PH2_ENCAP_MODE = 4, + TATTR_PH2_AUTH_ALGORITHM = 5, + TATTR_PH2_KEY_LENGTH = 6, + TATTR_PH2_KEY_ROUNDS = 7, + TATTR_PH2_COMP_DICT_SIZE = 8, + TATTR_PH2_COMP_PRIV_ALGORITHM = 9, + TATTR_PH2_ECN_TUNNEL = 10, + TATTR_PH2_EXT_SEQ_NUMBER = 11, + /* IKEv2 key length attribute */ + TATTR_IKEV2_KEY_LENGTH = 14, + /* undefined, private use attribute */ + TATTR_UNDEFINED = 16384, }; /** - * enum name for transform_attribute_type_t. + * Enum names for IKEv1 Phase 1 transform_attribute_type_t. */ -extern enum_name_t *transform_attribute_type_names; +extern enum_name_t *tattr_ph1_names; /** - * Class representing an IKEv2- TRANSFORM Attribute. - * - * The TRANSFORM ATTRIBUTE format is described in RFC section 3.3.5. + * Enum names for IKEv1 Phase 2 transform_attribute_type_t. + */ +extern enum_name_t *tattr_ph2_names; + +/** + * Enum names for IKEv2 transform_attribute_type_t. + */ +extern enum_name_t *tattr_ikev2_names; + + +/** + * Class representing an IKEv1/IKEv2 TRANSFORM Attribute. */ struct transform_attribute_t { + /** * The payload_t interface. */ @@ -117,9 +157,10 @@ struct transform_attribute_t { /** * Creates an empty transform_attribute_t object. * + * @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 * @return transform_attribute_t object */ -transform_attribute_t *transform_attribute_create(void); +transform_attribute_t *transform_attribute_create(payload_type_t type); /** * Creates an transform_attribute_t of type KEY_LENGTH. diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c index 3f04b3539..141898a5b 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.c +++ b/src/libcharon/encoding/payloads/transform_substructure.c @@ -41,10 +41,11 @@ struct private_transform_substructure_t { * Next payload type. */ u_int8_t next_payload; + /** - * Reserved bytes + * Reserved byte */ - u_int8_t reserved[2]; + u_int8_t reserved[3]; /** * Length of this payload. @@ -52,43 +53,70 @@ struct private_transform_substructure_t { u_int16_t transform_length; /** - * Type of the transform. + * Type or number, Type of the transform in IKEv2, number in IKEv2. */ - u_int8_t transform_type; + u_int8_t transform_ton; /** - * Transform ID. + * Transform ID, as encoded in IKEv1. */ - u_int16_t transform_id; + u_int8_t transform_id_v1; + + /** + * Transform ID, as encoded in IKEv2. + */ + u_int16_t transform_id_v2; /** * Transforms Attributes are stored in a linked_list_t. */ linked_list_t *attributes; + + /** + * Payload type, TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a Transform substructure. - * - * The defined offsets are the positions in a object of type - * private_transform_substructure_t. + * Encoding rules for TRANSFORM_SUBSTRUCTURE */ -encoding_rule_t transform_substructure_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, + { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, /* 1 Reserved Byte */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, /* Length of the whole transform substructure*/ - { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, - /* transform type is a number of 8 bit */ - { U_INT_8, offsetof(private_transform_substructure_t, transform_type) }, + { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, + /* transform type */ + { U_INT_8, offsetof(private_transform_substructure_t, transform_ton) }, + /* transform identifier, as used by IKEv1 */ + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, + /* transform identifier, as used by IKEv2 */ + { U_INT_16, offsetof(private_transform_substructure_t, transform_id_v2) }, + /* Attributes in a transform attribute list */ + { TRANSFORM_ATTRIBUTES, offsetof(private_transform_substructure_t, attributes) } +}; + +/** + * Encoding rules for TRANSFORM_SUBSTRUCTURE_V1 + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, /* 1 Reserved Byte */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, - /* transform ID is a number of 8 bit */ - { U_INT_16, offsetof(private_transform_substructure_t, transform_id) }, - /* Attributes are stored in a transform attribute, - offset points to a linked_list_t pointer */ - { TRANSFORM_ATTRIBUTES, offsetof(private_transform_substructure_t, attributes) } + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, + /* Length of the whole transform substructure*/ + { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, + /* transform number */ + { U_INT_8, offsetof(private_transform_substructure_t, transform_ton)}, + /* transform identifier, as used by IKEv1 */ + { U_INT_8, offsetof(private_transform_substructure_t, transform_id_v1) }, + /* transform identifier, as used by IKEv2 */ + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[2]) }, + /* Attributes in a transform attribute list */ + { TRANSFORM_ATTRIBUTES_V1, offsetof(private_transform_substructure_t, attributes) } }; /* @@ -97,7 +125,7 @@ encoding_rule_t transform_substructure_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! 0 (last) or 3 ! RESERVED ! Transform Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - !Transform Type ! RESERVED ! Transform ID ! + ! Tfrm Typ or # ! Tfrm ID IKEv1 ! Transform ID IKEv2 ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! ~ Transform Attributes ~ @@ -118,23 +146,6 @@ METHOD(payload_t, verify, status_t, return FAILED; } - switch (this->transform_type) - { - case ENCRYPTION_ALGORITHM: - case PSEUDO_RANDOM_FUNCTION: - case INTEGRITY_ALGORITHM: - case DIFFIE_HELLMAN_GROUP: - case EXTENDED_SEQUENCE_NUMBERS: - /* we don't check transform ID, we want to reply - * cleanly with NO_PROPOSAL_CHOSEN or so if we don't support it */ - break; - default: - { - DBG1(DBG_ENC, "invalid transform type: %d", this->transform_type); - return FAILED; - } - } - enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attribute)) { @@ -155,14 +166,22 @@ METHOD(payload_t, get_encoding_rules, void, private_transform_substructure_t *this, encoding_rule_t **rules, size_t *rule_count) { - *rules = transform_substructure_encodings; - *rule_count = countof(transform_substructure_encodings); + if (this->type == TRANSFORM_ATTRIBUTE) + { + *rules = encodings_v2; + *rule_count = countof(encodings_v2); + } + else + { + *rules = encodings_v1; + *rule_count = countof(encodings_v1); + } } METHOD(payload_t, get_type, payload_type_t, private_transform_substructure_t *this) { - return TRANSFORM_SUBSTRUCTURE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -174,7 +193,7 @@ METHOD(payload_t, get_next_type, payload_type_t, /** * recompute the length of the payload. */ -static void compute_length (private_transform_substructure_t *this) +static void compute_length(private_transform_substructure_t *this) { enumerator_t *enumerator; payload_t *attribute; @@ -205,50 +224,40 @@ METHOD(payload_t, set_next_type, void, { } -METHOD(transform_substructure_t, get_transform_type, u_int8_t, +METHOD(transform_substructure_t, get_transform_type_or_number, u_int8_t, private_transform_substructure_t *this) { - return this->transform_type; + return this->transform_ton; } METHOD(transform_substructure_t, get_transform_id, u_int16_t, private_transform_substructure_t *this) { - return this->transform_id; + if (this->type == TRANSFORM_SUBSTRUCTURE) + { + return this->transform_id_v2; + } + return this->transform_id_v1; } -METHOD(transform_substructure_t, get_key_length, status_t, - private_transform_substructure_t *this, u_int16_t *key_length) +METHOD(transform_substructure_t, create_attribute_enumerator, enumerator_t*, + private_transform_substructure_t *this) { - enumerator_t *enumerator; - transform_attribute_t *attribute; - - enumerator = this->attributes->create_enumerator(this->attributes); - while (enumerator->enumerate(enumerator, &attribute)) - { - if (attribute->get_attribute_type(attribute) == KEY_LENGTH) - { - *key_length = attribute->get_value(attribute); - enumerator->destroy(enumerator); - return SUCCESS; - } - } - enumerator->destroy(enumerator); - return FAILED; + return this->attributes->create_enumerator(this->attributes); } METHOD2(payload_t, transform_substructure_t, destroy, void, private_transform_substructure_t *this) { this->attributes->destroy_offset(this->attributes, - offsetof(transform_attribute_t, destroy)); + offsetof(payload_t, destroy)); free(this); } /* * Described in header. */ -transform_substructure_t *transform_substructure_create() +transform_substructure_t *transform_substructure_create(payload_type_t type) { private_transform_substructure_t *this; @@ -264,14 +273,15 @@ transform_substructure_t *transform_substructure_create() .destroy = _destroy, }, .set_is_last_transform = _set_is_last_transform, - .get_transform_type = _get_transform_type, + .get_transform_type_or_number = _get_transform_type_or_number, .get_transform_id = _get_transform_id, - .get_key_length = _get_key_length, + .create_attribute_enumerator = _create_attribute_enumerator, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, .transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH, .attributes = linked_list_create(), + .type = type, ); return &this->public; } @@ -279,15 +289,22 @@ transform_substructure_t *transform_substructure_create() /* * Described in header */ -transform_substructure_t *transform_substructure_create_type( - transform_type_t type, u_int16_t id, u_int16_t key_length) +transform_substructure_t *transform_substructure_create_type(payload_type_t type, + u_int8_t type_or_number, u_int16_t id, u_int16_t key_length) { private_transform_substructure_t *this; - this = (private_transform_substructure_t*)transform_substructure_create(); + this = (private_transform_substructure_t*)transform_substructure_create(type); - this->transform_type = type; - this->transform_id = id; + this->transform_ton = type_or_number; + if (type == TRANSFORM_SUBSTRUCTURE) + { + this->transform_id_v2 = id; + } + else + { + this->transform_id_v1 = id; + } if (key_length) { this->attributes->insert_last(this->attributes, diff --git a/src/libcharon/encoding/payloads/transform_substructure.h b/src/libcharon/encoding/payloads/transform_substructure.h index 102dbb3d3..e6a7f8e4d 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.h +++ b/src/libcharon/encoding/payloads/transform_substructure.h @@ -45,9 +45,7 @@ typedef struct transform_substructure_t transform_substructure_t; #define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8 /** - * Class representing an IKEv2- TRANSFORM SUBSTRUCTURE. - * - * The TRANSFORM SUBSTRUCTURE format is described in RFC section 3.3.2. + * Class representing an IKEv1/IKEv2 transform substructure. */ struct transform_substructure_t { @@ -75,11 +73,11 @@ struct transform_substructure_t { void (*set_is_last_transform) (transform_substructure_t *this, bool is_last); /** - * get transform type of the current transform. + * Get transform type (IKEv2) or the transform number (IKEv1). * * @return Transform type of current transform substructure. */ - u_int8_t (*get_transform_type) (transform_substructure_t *this); + u_int8_t (*get_transform_type_or_number) (transform_substructure_t *this); /** * Get transform id of the current transform. @@ -89,16 +87,11 @@ struct transform_substructure_t { u_int16_t (*get_transform_id) (transform_substructure_t *this); /** - * Get transform id of the current transform. + * Create an enumerator over transform attributes. * - * @param key_length The key length is written to this location - * @return - * - SUCCESS if a key length attribute is contained - * - FAILED if no key length attribute is part of this - * transform or key length uses more then 16 bit! + * @return enumerator over transform_attribute_t* */ - status_t (*get_key_length) (transform_substructure_t *this, - u_int16_t *key_length); + enumerator_t* (*create_attribute_enumerator)(transform_substructure_t *this); /** * Destroys an transform_substructure_t object. @@ -109,19 +102,21 @@ struct transform_substructure_t { /** * Creates an empty transform_substructure_t object. * + * @param type TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 * @return created transform_substructure_t object */ -transform_substructure_t *transform_substructure_create(void); +transform_substructure_t *transform_substructure_create(payload_type_t type); /** * Creates an empty transform_substructure_t object. * - * @param type type of transform to create - * @param id transform id specifc for the transform type - * @param key_length key length for key length attribute, 0 to omit - * @return transform_substructure_t object + * @param type TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 + * @param type_or_number Type (IKEv2) or number (IKEv1) of transform + * @param id transform id specifc for the transform type + * @param key_length key length for key length attribute, 0 to omit + * @return transform_substructure_t object */ -transform_substructure_t *transform_substructure_create_type( - transform_type_t type, u_int16_t id, u_int16_t key_length); +transform_substructure_t *transform_substructure_create_type(payload_type_t type, + u_int8_t type_or_number, u_int16_t id, u_int16_t key_length); #endif /** TRANSFORM_SUBSTRUCTURE_H_ @}*/ From 8a2d079d785e069891dcae41e7b1aae51f50c9ae Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Nov 2011 10:31:53 +0100 Subject: [PATCH 015/534] Certificate request payloads can be sent in pretty much any IKEv1 message. --- src/libcharon/encoding/message.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 823a97f0f..58b7df505 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2006-2011 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2010 revosec AG * Copyright (C) 2006 Daniel Roethlisberger @@ -35,25 +35,30 @@ #include /** - * Max number of notify payloads per IKEv2 Message + * Max number of notify payloads per IKEv2 message */ #define MAX_NOTIFY_PAYLOADS 20 /** - * Max number of delete payloads per IKEv2 Message + * Max number of delete payloads per IKEv2 message */ #define MAX_DELETE_PAYLOADS 20 /** - * Max number of certificate payloads per IKEv2 Message + * Max number of certificate payloads per IKEv2 message */ #define MAX_CERT_PAYLOADS 8 /** - * Max number of Vendor ID payloads per IKEv2 Message + * Max number of vendor ID payloads per IKEv2 message */ #define MAX_VID_PAYLOADS 20 +/** + * Max number of certificate request payloads per IKEv1 message + */ +#define MAX_CERTREQ_PAYLOADS 5 + /** * A payload rule defines the rules for a payload * in a specific message rule. It defines if and how @@ -425,6 +430,7 @@ static payload_rule_t id_prot_i_rules[] = { {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, {NONCE_V1, 0, 1, FALSE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, TRUE, FALSE}, {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, {SIGNATURE_V1, 0, 1, TRUE, FALSE}, @@ -443,6 +449,7 @@ static payload_order_t id_prot_i_order[] = { {CERTIFICATE_V1, 0}, {SIGNATURE_V1, 0}, {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, {NOTIFICATION_V1, 0}, {VENDOR_ID_V1, 0}, }; @@ -457,6 +464,7 @@ static payload_rule_t id_prot_r_rules[] = { {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, {NONCE_V1, 0, 1, FALSE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, TRUE, FALSE}, {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, {SIGNATURE_V1, 0, 1, TRUE, FALSE}, @@ -475,6 +483,7 @@ static payload_order_t id_prot_r_order[] = { {CERTIFICATE_V1, 0}, {SIGNATURE_V1, 0}, {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, {NOTIFICATION_V1, 0}, {VENDOR_ID_V1, 0}, }; @@ -489,6 +498,7 @@ static payload_rule_t aggressive_i_rules[] = { {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, {NONCE_V1, 0, 1, FALSE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, FALSE, FALSE}, {CERTIFICATE_V1, 0, 1, FALSE, FALSE}, {SIGNATURE_V1, 0, 1, FALSE, FALSE}, @@ -507,6 +517,7 @@ static payload_order_t aggressive_i_order[] = { {CERTIFICATE_V1, 0}, {SIGNATURE_V1, 0}, {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, {NOTIFICATION_V1, 0}, {VENDOR_ID_V1, 0}, }; @@ -521,6 +532,7 @@ static payload_rule_t aggressive_r_rules[] = { {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, {NONCE_V1, 0, 1, FALSE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, FALSE, FALSE}, {CERTIFICATE_V1, 0, 1, FALSE, FALSE}, {SIGNATURE_V1, 0, 1, FALSE, FALSE}, @@ -539,6 +551,7 @@ static payload_order_t aggressive_r_order[] = { {CERTIFICATE_V1, 0}, {SIGNATURE_V1, 0}, {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, {NOTIFICATION_V1, 0}, {VENDOR_ID_V1, 0}, }; From 4ed52db2bbe4d884e5e0ed507b0d9c19f7b4343e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Nov 2011 12:06:55 +0100 Subject: [PATCH 016/534] Allow creation of message_t objects for IKEv1 packets. --- src/conftest/hooks/force_cookie.c | 2 +- src/conftest/hooks/unencrypted_notify.c | 2 +- src/libcharon/encoding/message.c | 52 +++++++++++++++---------- src/libcharon/encoding/message.h | 45 ++++++++++----------- src/libcharon/network/receiver.c | 2 +- src/libcharon/sa/connect_manager.c | 2 +- src/libcharon/sa/ike_sa.c | 2 +- src/libcharon/sa/task_manager.c | 4 +- 8 files changed, 62 insertions(+), 49 deletions(-) diff --git a/src/conftest/hooks/force_cookie.c b/src/conftest/hooks/force_cookie.c index e34f82851..e2ccb66a8 100644 --- a/src/conftest/hooks/force_cookie.c +++ b/src/conftest/hooks/force_cookie.c @@ -68,7 +68,7 @@ METHOD(listener_t, message, bool, chunk_t data = chunk_from_thing("COOKIE test data"); DBG1(DBG_CFG, "sending COOKIE: %#B", &data); - response = message_create(); + response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); dst = message->get_source(message); src = message->get_destination(message); response->set_source(response, src->clone(src)); diff --git a/src/conftest/hooks/unencrypted_notify.c b/src/conftest/hooks/unencrypted_notify.c index 80bdc64b7..507f30cae 100644 --- a/src/conftest/hooks/unencrypted_notify.c +++ b/src/conftest/hooks/unencrypted_notify.c @@ -95,7 +95,7 @@ METHOD(listener_t, ike_updown, bool, DBG1(DBG_CFG, "injecting unencrypted INFORMATIONAL message"); - message = message_create(); + message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); message->set_message_id(message, this->id); message->set_ike_sa_id(message, ike_sa->get_id(ike_sa)); message->set_exchange_type(message, INFORMATIONAL); diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 58b7df505..71ff4b068 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -686,6 +686,11 @@ struct private_message_t { */ bool is_request; + /** + * The message is encrypted (IKEv1) + */ + bool is_encrypted; + /** * Higher version supported? */ @@ -694,7 +699,7 @@ struct private_message_t { /** * Reserved bits in IKE header */ - bool reserved[5]; + bool reserved[2]; /** * Sorting of message disabled? @@ -1422,13 +1427,15 @@ METHOD(message_t, parse_header, status_t, } DESTROY_IF(this->ike_sa_id); - this->ike_sa_id = ike_sa_id_create(ike_header->get_initiator_spi(ike_header), + this->ike_sa_id = ike_sa_id_create( + ike_header->get_initiator_spi(ike_header), ike_header->get_responder_spi(ike_header), ike_header->get_initiator_flag(ike_header)); this->exchange_type = ike_header->get_exchange_type(ike_header); this->message_id = ike_header->get_message_id(ike_header); this->is_request = !ike_header->get_response_flag(ike_header); + this->is_encrypted = ike_header->get_encryption_flag(ike_header); this->major_version = ike_header->get_maj_version(ike_header); this->minor_version = ike_header->get_min_version(ike_header); this->first_payload = ike_header->payload_interface.get_next_type( @@ -1442,19 +1449,12 @@ METHOD(message_t, parse_header, status_t, this->reserved[i] = *reserved; } } - DBG2(DBG_ENC, "parsed a %N %s", exchange_type_names, this->exchange_type, - this->is_request ? "request" : "response"); - ike_header->destroy(ike_header); - this->rule = get_message_rule(this); - if (!this->rule) - { - DBG1(DBG_ENC, "no message rules specified for a %N %s", - exchange_type_names, this->exchange_type, - this->is_request ? "request" : "response"); - } - return status; + DBG2(DBG_ENC, "parsed a %N %s header", exchange_type_names, + this->exchange_type, this->major_version == IKEV1_MAJOR_VERSION ? + "message" : (this->is_request ? "request" : "response")); + return SUCCESS; } /** @@ -1640,6 +1640,15 @@ METHOD(message_t, parse_body, status_t, DBG2(DBG_ENC, "parsing body of message, first payload is %N", payload_type_names, type); + this->rule = get_message_rule(this); + if (!this->rule) + { + DBG1(DBG_ENC, "no message rules specified for a %N %s", + exchange_type_names, this->exchange_type, + this->is_request ? "request" : "response"); + return PARSE_ERROR; + } + while (type != NO_PAYLOAD) { DBG2(DBG_ENC, "starting parsing a %N payload", @@ -1707,7 +1716,7 @@ METHOD(message_t, destroy, void, } /* - * Described in Header-File + * Described in header. */ message_t *message_create_from_packet(packet_t *packet) { @@ -1752,8 +1761,6 @@ message_t *message_create_from_packet(packet_t *packet) .get_packet_data = _get_packet_data, .destroy = _destroy, }, - .major_version = IKEV2_MAJOR_VERSION, - .minor_version = IKEV2_MINOR_VERSION, .exchange_type = EXCHANGE_TYPE_UNDEFINED, .is_request = TRUE, .first_payload = NO_PAYLOAD, @@ -1762,14 +1769,19 @@ message_t *message_create_from_packet(packet_t *packet) .parser = parser_create(packet->get_data(packet)), ); - return (&this->public); + return &this->public; } /* - * Described in Header. + * Described in header. */ -message_t *message_create() +message_t *message_create(int major, int minor) { - return message_create_from_packet(packet_create()); + message_t *this = message_create_from_packet(packet_create()); + + this->set_major_version(this, major); + this->set_minor_version(this, minor); + + return this; } diff --git a/src/libcharon/encoding/message.h b/src/libcharon/encoding/message.h index 0e78ea436..20f3c16d7 100644 --- a/src/libcharon/encoding/message.h +++ b/src/libcharon/encoding/message.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2006-2011 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -182,7 +182,7 @@ struct message_t { * all payloads to encrypt are added to the encryption payload, which is * always the last one. * - * @param payload payload to append + * @param payload payload to append */ void (*add_payload) (message_t *this, payload_t *payload); @@ -208,14 +208,14 @@ struct message_t { /** * Parses header of message. * - * Begins parisng of a message created via message_create_from_packet(). + * Begins parsing of a message created via message_create_from_packet(). * The parsing context is stored, so a subsequent call to parse_body() * will continue the parsing process. * * @return - * - SUCCESS if header could be parsed + * - SUCCESS if header could be parsed * - PARSE_ERROR if corrupted/invalid data found - * - FAILED if consistence check of header failed + * - FAILED if consistency check of header failed */ status_t (*parse_header) (message_t *this); @@ -230,11 +230,11 @@ struct message_t { * * @param aead aead transform to verify/decrypt message * @return - * - SUCCESS if parsing successful + * - SUCCESS if parsing successful * - PARSE_ERROR if message parsing failed - * - VERIFY_ERROR if message verification failed (bad syntax) - * - FAILED if integrity check failed - * - INVALID_STATE if aead not supplied, but needed + * - VERIFY_ERROR if message verification failed (bad syntax) + * - FAILED if integrity check failed + * - INVALID_STATE if aead not supplied, but needed */ status_t (*parse_body) (message_t *this, aead_t *aead); @@ -250,10 +250,10 @@ struct message_t { * @param aead aead transform to encrypt/sign message * @param packet copy of generated packet * @return - * - SUCCESS if packet could be generated - * - INVALID_STATE if exchange type is currently not set - * - NOT_FOUND if no rules found for message generation - * - INVALID_STATE if aead not supplied but needed. + * - SUCCESS if packet could be generated + * - INVALID_STATE if exchange type is currently not set + * - NOT_FOUND if no rules found for message generation + * - INVALID_STATE if aead not supplied but needed. */ status_t (*generate) (message_t *this, aead_t *aead, packet_t **packet); @@ -278,7 +278,7 @@ struct message_t { * Sets the source host informations. * * @warning host_t object is not getting cloned and gets destroyed by - * message_t.destroy or next call of message_t.set_source. + * message_t.destroy or next call of message_t.set_source. * * @param host host_t object representing source host */ @@ -298,7 +298,7 @@ struct message_t { * Sets the destination host informations. * * @warning host_t object is not getting cloned and gets destroyed by - * message_t.destroy or next call of message_t.set_destination. + * message_t.destroy or next call of message_t.set_destination. * * @param host host_t object representing destination host */ @@ -357,26 +357,27 @@ struct message_t { }; /** - * Creates an message_t object from a incoming UDP Packet. + * Creates a message_t object from an incoming UDP packet. * * The given packet gets owned by the message. The message is uninitialized, * call parse_header() to populate header fields. * * @param packet packet_t object which is assigned to message - * @return message_t object + * @return message_t object */ -message_t * message_create_from_packet(packet_t *packet); - +message_t *message_create_from_packet(packet_t *packet); /** - * Creates an empty message_t object. + * Creates an empty message_t object for a specific major/minor version. * * - exchange_type is set to NOT_SET * - original_initiator is set to TRUE * - is_request is set to TRUE * - * @return message_t object + * @param major major IKE version of this message + * @param minor minor IKE version of this message + * @return message_t object */ -message_t * message_create(void); +message_t *message_create(int major, int minor); #endif /** MESSAGE_H_ @}*/ diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index 3e75d9b04..2f024900e 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -144,7 +144,7 @@ static void send_notify(message_t *request, notify_type_t type, chunk_t data) packet_t *packet; ike_sa_id_t *ike_sa_id; - response = message_create(); + response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); dst = request->get_source(request); src = request->get_destination(request); response->set_source(response, src->clone(src)); diff --git a/src/libcharon/sa/connect_manager.c b/src/libcharon/sa/connect_manager.c index 7b6ca430f..31947aa7b 100644 --- a/src/libcharon/sa/connect_manager.c +++ b/src/libcharon/sa/connect_manager.c @@ -1028,7 +1028,7 @@ static void queue_retransmission(private_connect_manager_t *this, check_list_t * static void send_check(private_connect_manager_t *this, check_list_t *checklist, check_t *check, endpoint_pair_t *pair, bool request) { - message_t *message = message_create(); + message_t *message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); message->set_message_id(message, check->mid); message->set_exchange_type(message, INFORMATIONAL); message->set_request(message, request); diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 75868ab2c..29ce3ce81 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -926,7 +926,7 @@ static void send_notify_response(private_ike_sa_t *this, message_t *request, message_t *response; packet_t *packet; - response = message_create(); + response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); response->set_exchange_type(response, request->get_exchange_type(request)); response->set_request(response, FALSE); response->set_message_id(response, request->get_message_id(request)); diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c index 473bf34f1..8a4e81ac2 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager.c @@ -425,7 +425,7 @@ METHOD(task_manager_t, initiate, status_t, me = this->ike_sa->get_my_host(this->ike_sa); other = this->ike_sa->get_other_host(this->ike_sa); - message = message_create(); + message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); message->set_message_id(message, this->initiating.mid); message->set_source(message, me->clone(me)); message->set_destination(message, other->clone(other)); @@ -607,7 +607,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) me = request->get_destination(request); other = request->get_source(request); - message = message_create(); + message = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); message->set_exchange_type(message, request->get_exchange_type(request)); /* send response along the path the request came in */ message->set_source(message, me->clone(me)); From 7f56cf1a650254d0aee249b4fc87cbea78ae6073 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Nov 2011 14:23:50 +0100 Subject: [PATCH 017/534] Message parsing slightly refactored, allows parsing of unencrypted IKEv1 messages. --- src/libcharon/encoding/message.c | 92 ++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 40 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 71ff4b068..1dad23bc2 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1482,6 +1482,53 @@ static bool is_connectivity_check(private_message_t *this, payload_t *payload) return FALSE; } +/** + * Parses and verifies the unencrypted payloads contained in the message + */ +static status_t parse_payloads(private_message_t *this) +{ + payload_type_t type = this->first_payload; + + while (type != NO_PAYLOAD) + { + DBG2(DBG_ENC, "starting parsing a %N payload", + payload_type_names, type); + + status = this->parser->parse_payload(this->parser, type, &payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "payload type %N could not be parsed", + payload_type_names, type); + return PARSE_ERROR; + } + + DBG2(DBG_ENC, "verifying payload of type %N", payload_type_names, type); + status = payload->verify(payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "%N payload verification failed", + payload_type_names, type); + payload->destroy(payload); + return VERIFY_ERROR; + } + + DBG2(DBG_ENC, "%N payload verified. Adding to payload list", + payload_type_names, type); + this->payloads->insert_last(this->payloads, payload); + + /* an encryption payload is the last one, so STOP here. decryption is + * done later */ + if (type == ENCRYPTED) + { + DBG2(DBG_ENC, "%N payload found. Stop parsing", + payload_type_names, type); + break; + } + type = payload->get_next_type(payload); + } + return SUCCESS; +} + /** * Decrypt payload from the encryption payload */ @@ -1632,13 +1679,10 @@ METHOD(message_t, parse_body, status_t, { status_t status = SUCCESS; payload_t *payload; - payload_type_t type; char str[BUF_LEN]; - type = this->first_payload; - DBG2(DBG_ENC, "parsing body of message, first payload is %N", - payload_type_names, type); + payload_type_names, this->first_payload); this->rule = get_message_rule(this); if (!this->rule) @@ -1649,42 +1693,10 @@ METHOD(message_t, parse_body, status_t, return PARSE_ERROR; } - while (type != NO_PAYLOAD) - { - DBG2(DBG_ENC, "starting parsing a %N payload", - payload_type_names, type); - - status = this->parser->parse_payload(this->parser, type, &payload); - if (status != SUCCESS) - { - DBG1(DBG_ENC, "payload type %N could not be parsed", - payload_type_names, type); - return this->exchange_type == IKE_SA_INIT ? PARSE_ERROR : FAILED; - } - - DBG2(DBG_ENC, "verifying payload of type %N", payload_type_names, type); - status = payload->verify(payload); - if (status != SUCCESS) - { - DBG1(DBG_ENC, "%N payload verification failed", - payload_type_names, type); - payload->destroy(payload); - return this->exchange_type == IKE_SA_INIT ? VERIFY_ERROR : FAILED; - } - - DBG2(DBG_ENC, "%N payload verified. Adding to payload list", - payload_type_names, type); - this->payloads->insert_last(this->payloads, payload); - - /* an encryption payload is the last one, so STOP here. decryption is - * done later */ - if (type == ENCRYPTED) - { - DBG2(DBG_ENC, "%N payload found. Stop parsing", - payload_type_names, type); - break; - } - type = payload->get_next_type(payload); + status = parse_payloads(this); + if (status != SUCCESS) + { /* error is already logged */ + return status; } status = decrypt_payloads(this, aead); From 354ac9579f92d69a54b70b2010c7a5d35893eebc Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Nov 2011 15:05:08 +0100 Subject: [PATCH 018/534] Compile error fixed. --- src/libcharon/encoding/message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 1dad23bc2..91d7f3df9 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1488,6 +1488,8 @@ static bool is_connectivity_check(private_message_t *this, payload_t *payload) static status_t parse_payloads(private_message_t *this) { payload_type_t type = this->first_payload; + payload_t *payload; + status_t status; while (type != NO_PAYLOAD) { @@ -1678,7 +1680,6 @@ METHOD(message_t, parse_body, status_t, private_message_t *this, aead_t *aead) { status_t status = SUCCESS; - payload_t *payload; char str[BUF_LEN]; DBG2(DBG_ENC, "parsing body of message, first payload is %N", From 3238faf8e6a91f554a76a376bacbc333c3530925 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Nov 2011 16:19:13 +0100 Subject: [PATCH 019/534] Fix init message arrival check. --- src/libcharon/sa/ike_sa_manager.c | 35 +++++++++++++------------------ 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 6d6fb4b80..6b2d17386 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1031,34 +1031,27 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (ike_sa == NULL) { - if (is_init) - { - /* no IKE_SA found, create a new one */ - id->set_responder_spi(id, get_spi(this)); - entry = entry_create(); - entry->ike_sa = ike_sa_create(id); - entry->ike_sa_id = id->clone(id); + /* no IKE_SA found, create a new one */ + id->set_responder_spi(id, get_spi(this)); + entry = entry_create(); + entry->ike_sa = ike_sa_create(id); + entry->ike_sa_id = id->clone(id); - segment = put_entry(this, entry); - entry->checked_out = TRUE; - unlock_single_segment(this, segment); + segment = put_entry(this, entry); + entry->checked_out = TRUE; + unlock_single_segment(this, segment); - entry->message_id = message->get_message_id(message); - entry->init_hash = hash; - ike_sa = entry->ike_sa; + entry->message_id = message->get_message_id(message); + entry->init_hash = hash; + ike_sa = entry->ike_sa; - DBG2(DBG_MGR, "created IKE_SA %s[%u]", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); - } - else - { - chunk_free(&hash); - DBG1(DBG_MGR, "ignoring message, no such IKE_SA"); - } + DBG2(DBG_MGR, "created IKE_SA %s[%u]", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); } else { chunk_free(&hash); + DBG1(DBG_MGR, "ignoring message, no such IKE_SA"); } id->destroy(id); charon->bus->set_sa(charon->bus, ike_sa); From f7a8fcedc0305dfca7d82adba03c88401240d039 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 16 Nov 2011 17:28:06 +0100 Subject: [PATCH 020/534] Use enum to define IKE version on peer_cfg_t. Replaced all those magic numbers. --- src/conftest/config.c | 2 +- src/libcharon/config/peer_cfg.c | 23 +++++++------ src/libcharon/config/peer_cfg.h | 32 ++++++++++++++----- .../plugins/android/android_service.c | 2 +- src/libcharon/plugins/ha/ha_tunnel.c | 2 +- .../plugins/load_tester/load_tester_config.c | 2 +- src/libcharon/plugins/maemo/maemo_service.c | 3 +- src/libcharon/plugins/medcli/medcli_config.c | 6 ++-- src/libcharon/plugins/medsrv/medsrv_config.c | 2 +- src/libcharon/plugins/nm/nm_service.c | 2 +- src/libcharon/plugins/smp/smp.c | 2 +- src/libcharon/plugins/sql/sql_config.c | 2 +- src/libcharon/plugins/stroke/stroke_config.c | 2 +- src/libcharon/plugins/stroke/stroke_control.c | 16 +++++----- src/libcharon/plugins/stroke/stroke_list.c | 2 +- src/libcharon/plugins/uci/uci_config.c | 2 +- .../processing/jobs/start_action_job.c | 2 +- 17 files changed, 63 insertions(+), 41 deletions(-) diff --git a/src/conftest/config.c b/src/conftest/config.c index 952141211..51d491de5 100644 --- a/src/conftest/config.c +++ b/src/conftest/config.c @@ -251,7 +251,7 @@ static peer_cfg_t *load_peer_config(private_config_t *this, uintptr_t strength; ike_cfg = load_ike_config(this, settings, config); - peer_cfg = peer_cfg_create(config, 2, ike_cfg, CERT_ALWAYS_SEND, + peer_cfg = peer_cfg_create(config, IKEV2, ike_cfg, CERT_ALWAYS_SEND, UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, 0, NULL, NULL, FALSE, NULL, NULL); diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index c623cbc9b..73b5f5f9f 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -25,6 +25,11 @@ #include #include +ENUM(ike_version_names, IKEV1, IKEV2, + "IKEv1", + "IKEv2", +); + ENUM(cert_policy_names, CERT_ALWAYS_SEND, CERT_NEVER_SEND, "CERT_ALWAYS_SEND", "CERT_SEND_IF_ASKED", @@ -62,7 +67,7 @@ struct private_peer_cfg_t { /** * IKE version to use for initiation */ - u_int ike_version; + ike_version_t ike_version; /** * IKE config associated to this peer config @@ -169,7 +174,7 @@ METHOD(peer_cfg_t, get_name, char*, return this->name; } -METHOD(peer_cfg_t, get_ike_version, u_int, +METHOD(peer_cfg_t, get_ike_version, ike_version_t, private_peer_cfg_t *this) { return this->ike_version; @@ -563,13 +568,13 @@ METHOD(peer_cfg_t, destroy, void, /* * Described in header-file */ -peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, - cert_policy_t cert_policy, unique_policy_t unique, - u_int32_t keyingtries, u_int32_t rekey_time, - u_int32_t reauth_time, u_int32_t jitter_time, - u_int32_t over_time, bool mobike, u_int32_t dpd, - host_t *virtual_ip, char *pool, - bool mediation, peer_cfg_t *mediated_by, +peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, + ike_cfg_t *ike_cfg, cert_policy_t cert_policy, + unique_policy_t unique, u_int32_t keyingtries, + u_int32_t rekey_time, u_int32_t reauth_time, + u_int32_t jitter_time, u_int32_t over_time, + bool mobike, u_int32_t dpd, host_t *virtual_ip, + char *pool, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id) { private_peer_cfg_t *this; diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index f644fb547..6096f6413 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -23,6 +23,7 @@ #ifndef PEER_CFG_H_ #define PEER_CFG_H_ +typedef enum ike_version_t ike_version_t; typedef enum cert_policy_t cert_policy_t; typedef enum unique_policy_t unique_policy_t; typedef struct peer_cfg_t peer_cfg_t; @@ -38,6 +39,21 @@ typedef struct peer_cfg_t peer_cfg_t; #include #include +/** + * IKE version. + */ +enum ike_version_t { + /** IKE version 1 */ + IKEV1 = 1, + /** IKE version 2 */ + IKEV2 = 2, +}; + +/** + * enum strings fro ike_version_t + */ +extern enum_name_t *ike_version_names; + /** * Certificate sending policy. This is also used for certificate * requests when using this definition for the other peer. If @@ -130,7 +146,7 @@ struct peer_cfg_t { * * @return IKE major version */ - u_int (*get_ike_version)(peer_cfg_t *this); + ike_version_t (*get_ike_version)(peer_cfg_t *this); /** * Get the IKE config to use for initiaton. @@ -347,13 +363,13 @@ struct peer_cfg_t { * @param peer_id ID that identifies our peer at the mediation server * @return peer_cfg_t object */ -peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, - cert_policy_t cert_policy, unique_policy_t unique, - u_int32_t keyingtries, u_int32_t rekey_time, - u_int32_t reauth_time, u_int32_t jitter_time, - u_int32_t over_time, bool mobike, u_int32_t dpd, - host_t *virtual_ip, char *pool, - bool mediation, peer_cfg_t *mediated_by, +peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, + ike_cfg_t *ike_cfg, cert_policy_t cert_policy, + unique_policy_t unique, u_int32_t keyingtries, + u_int32_t rekey_time, u_int32_t reauth_time, + u_int32_t jitter_time, u_int32_t over_time, + bool mobike, u_int32_t dpd, host_t *virtual_ip, + char *pool, bool mediation, peer_cfg_t *mediated_by, identification_t *peer_id); #endif /** PEER_CFG_H_ @}*/ diff --git a/src/libcharon/plugins/android/android_service.c b/src/libcharon/plugins/android/android_service.c index 487567f2a..96603ab29 100644 --- a/src/libcharon/plugins/android/android_service.c +++ b/src/libcharon/plugins/android/android_service.c @@ -273,7 +273,7 @@ static job_requeue_t initiate(private_android_service_t *this) hostname, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); - peer_cfg = peer_cfg_create("android", 2, ike_cfg, CERT_SEND_IF_ASKED, + peer_cfg = peer_cfg_create("android", IKEV2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index 299053ec1..1f87c3d86 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -206,7 +206,7 @@ static void setup_tunnel(private_ha_tunnel_t *this, ike_cfg = ike_cfg_create(FALSE, FALSE, local, IKEV2_UDP_PORT, remote, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); - peer_cfg = peer_cfg_create("ha", 2, ike_cfg, CERT_NEVER_SEND, + peer_cfg = peer_cfg_create("ha", IKEV2, ike_cfg, CERT_NEVER_SEND, UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, 30, NULL, NULL, FALSE, NULL, NULL); diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c index 6bc6f91e4..301c9cc63 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -249,7 +249,7 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) "0.0.0.0", IKEV2_UDP_PORT, this->remote, IKEV2_UDP_PORT); } ike_cfg->add_proposal(ike_cfg, this->proposal->clone(this->proposal)); - peer_cfg = peer_cfg_create("load-test", 2, ike_cfg, + peer_cfg = peer_cfg_create("load-test", IKEV2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, 1, /* keytries */ this->ike_rekey, 0, /* rekey, reauth */ 0, this->ike_rekey, /* jitter, overtime */ diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index 6675e1d21..58361a408 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -327,7 +327,8 @@ static gboolean initiate_connection(private_maemo_service_t *this, hostname, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); - peer_cfg = peer_cfg_create(this->current, 2, ike_cfg, CERT_SEND_IF_ASKED, + peer_cfg = peer_cfg_create(this->current, IKEV2, ike_cfg, + CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index ee3e95422..f768eeb4e 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -122,7 +122,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, "0.0.0.0", IKEV2_UDP_PORT, address, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); med_cfg = peer_cfg_create( - "mediation", 2, ike_cfg, + "mediation", IKEV2, ike_cfg, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ @@ -159,7 +159,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, return NULL; } peer_cfg = peer_cfg_create( - name, 2, this->ike->get_ref(this->ike), + name, IKEV2, this->ike->get_ref(this->ike), CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ @@ -234,7 +234,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, return FALSE; } this->current = peer_cfg_create( - name, 2, this->ike->get_ref(this->ike), + name, IKEV2, this->ike->get_ref(this->ike), CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ diff --git a/src/libcharon/plugins/medsrv/medsrv_config.c b/src/libcharon/plugins/medsrv/medsrv_config.c index 6cacb34f6..fc3963a3d 100644 --- a/src/libcharon/plugins/medsrv/medsrv_config.c +++ b/src/libcharon/plugins/medsrv/medsrv_config.c @@ -88,7 +88,7 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, if (e->enumerate(e, &name)) { peer_cfg = peer_cfg_create( - name, 2, this->ike->get_ref(this->ike), + name, IKEV2, this->ike->get_ref(this->ike), CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ diff --git a/src/libcharon/plugins/nm/nm_service.c b/src/libcharon/plugins/nm/nm_service.c index a6783fcc3..8135476fd 100644 --- a/src/libcharon/plugins/nm/nm_service.c +++ b/src/libcharon/plugins/nm/nm_service.c @@ -499,7 +499,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, ike_cfg = ike_cfg_create(TRUE, encap, "0.0.0.0", IKEV2_UDP_PORT, (char*)address, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); - peer_cfg = peer_cfg_create(priv->name, 2, ike_cfg, + peer_cfg = peer_cfg_create(priv->name, IKEV2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c index 68935aaab..2743b7224 100644 --- a/src/libcharon/plugins/smp/smp.c +++ b/src/libcharon/plugins/smp/smp.c @@ -302,7 +302,7 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write ike_cfg_t *ike_cfg; linked_list_t *list; - if (peer_cfg->get_ike_version(peer_cfg) != 2) + if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) { /* only IKEv2 connections yet */ continue; } diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index dc016012c..ef181f66c 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -368,7 +368,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, if (ike) { peer_cfg = peer_cfg_create( - name, 2, ike, cert_policy, uniqueid, + name, IKEV2, ike, cert_policy, uniqueid, keyingtries, rekeytime, reauthtime, jitter, overtime, mobike, dpd_delay, vip, pool, mediation, mediated_cfg, peer_id); diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index f09c74155..4a49704ef 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -670,7 +670,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, * the pool name as the connection name, which the attribute provider * uses to serve pool addresses. */ peer_cfg = peer_cfg_create(msg->add_conn.name, - msg->add_conn.ikev2 ? 2 : 1, ike_cfg, + msg->add_conn.ikev2 ? IKEV2 : IKEV1, ike_cfg, msg->add_conn.me.sendcert, unique, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, msg->add_conn.mobike, msg->add_conn.dpd.delay, diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index f0d8f3b74..5897862c3 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -126,10 +126,10 @@ METHOD(stroke_control_t, initiate, void, msg->initiate.name); if (peer_cfg) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) + if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) { - DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config", - peer_cfg->get_ike_version(peer_cfg)); + DBG1(DBG_CFG, "ignoring initiation request for %N config", + ike_version_names, peer_cfg->get_ike_version(peer_cfg)); peer_cfg->destroy(peer_cfg); return; } @@ -161,7 +161,7 @@ METHOD(stroke_control_t, initiate, void, NULL, NULL, NULL, NULL); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) + if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) { continue; } @@ -568,10 +568,10 @@ METHOD(stroke_control_t, route, void, msg->route.name); if (peer_cfg) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) + if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) { - DBG1(DBG_CFG, "ignoring initiation request for IKEv%d config", - peer_cfg->get_ike_version(peer_cfg)); + DBG1(DBG_CFG, "ignoring initiation request for %N config", + ike_version_names, peer_cfg->get_ike_version(peer_cfg)); peer_cfg->destroy(peer_cfg); return; } @@ -603,7 +603,7 @@ METHOD(stroke_control_t, route, void, NULL, NULL, NULL, NULL); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) + if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) { continue; } diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index af061155f..4145a7962 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -489,7 +489,7 @@ METHOD(stroke_list_t, status, void, charon->backends, NULL, NULL, NULL, NULL); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != 2 || + if (peer_cfg->get_ike_version(peer_cfg) != IKEV2 || (name && !streq(name, peer_cfg->get_name(peer_cfg)))) { continue; diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c index 2f5e59b89..4e48b933a 100644 --- a/src/libcharon/plugins/uci/uci_config.c +++ b/src/libcharon/plugins/uci/uci_config.c @@ -172,7 +172,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, local_addr, IKEV2_UDP_PORT, remote_addr, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, create_proposal(ike_proposal, PROTO_IKE)); this->peer_cfg = peer_cfg_create( - name, 2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, + name, IKEV2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, 1, create_rekey(ike_rekey), 0, /* keytries, rekey, reauth */ 1800, 900, /* jitter, overtime */ TRUE, 60, /* mobike, dpddelay */ diff --git a/src/libcharon/processing/jobs/start_action_job.c b/src/libcharon/processing/jobs/start_action_job.c index b65181ef8..0019a1145 100644 --- a/src/libcharon/processing/jobs/start_action_job.c +++ b/src/libcharon/processing/jobs/start_action_job.c @@ -49,7 +49,7 @@ METHOD(job_t, execute, void, NULL, NULL, NULL, NULL); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != 2) + if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) { continue; } From 4ac22be0ec9d3f8aa0ef40dacf97c032fcd18e14 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 13:45:19 +0000 Subject: [PATCH 021/534] Fix unaligned aliasing warning in raw socket --- src/libcharon/plugins/socket_raw/socket_raw_socket.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libcharon/plugins/socket_raw/socket_raw_socket.c b/src/libcharon/plugins/socket_raw/socket_raw_socket.c index f371ed502..ae37d8f2b 100644 --- a/src/libcharon/plugins/socket_raw/socket_raw_socket.c +++ b/src/libcharon/plugins/socket_raw/socket_raw_socket.c @@ -442,23 +442,22 @@ static int open_send_socket(private_socket_raw_socket_t *this, int skt; memset(&addr, 0, sizeof(addr)); + addr.ss_family = family; /* precalculate constants depending on address family */ switch (family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)&addr; - sin->sin_family = AF_INET; - sin->sin_addr.s_addr = INADDR_ANY; - sin->sin_port = htons(port); + htoun32(&sin->sin_addr.s_addr, INADDR_ANY); + htoun16(&sin->sin_port, port); break; } case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&addr; - sin6->sin6_family = AF_INET6; memcpy(&sin6->sin6_addr, &in6addr_any, sizeof(in6addr_any)); - sin6->sin6_port = htons(port); + htoun16(&sin6->sin6_port, port); break; } default: From e69f7dcddfd41b412fe71fdee0cad467589d534d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 13:53:54 +0000 Subject: [PATCH 022/534] Use task manager as generic interface, renamed implementation to _v2. --- src/libcharon/Makefile.am | 2 +- src/libcharon/sa/ike_sa.c | 4 +- src/libcharon/sa/task_manager.h | 7 --- .../sa/{task_manager.c => task_manager_v2.c} | 29 ++++++------ src/libcharon/sa/task_manager_v2.h | 46 +++++++++++++++++++ 5 files changed, 64 insertions(+), 24 deletions(-) rename src/libcharon/sa/{task_manager.c => task_manager_v2.c} (98%) create mode 100644 src/libcharon/sa/task_manager_v2.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index b50ea2507..5cb17facf 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -66,7 +66,7 @@ sa/child_sa.c sa/child_sa.h \ sa/ike_sa.c sa/ike_sa.h \ sa/ike_sa_id.c sa/ike_sa_id.h \ sa/ike_sa_manager.c sa/ike_sa_manager.h \ -sa/task_manager.c sa/task_manager.h \ +sa/task_manager.h sa/task_manager_v2.c sa/task_manager_v2.h \ sa/keymat.c sa/keymat.h \ sa/shunt_manager.c sa/shunt_manager.h \ sa/trap_manager.c sa/trap_manager.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 29ce3ce81..03d834538 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -2209,7 +2209,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .keepalive_interval = lib->settings->get_time(lib->settings, "charon.keep_alive", KEEPALIVE_INTERVAL), ); - this->task_manager = task_manager_create(&this->public); + this->task_manager = &(task_manager_v2_create(&this->public)->task_manager); this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); return &this->public; diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 5bc6c80c4..b6cf5404c 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -194,11 +194,4 @@ struct task_manager_t { void (*destroy) (task_manager_t *this); }; -/** - * Create an instance of the task manager. - * - * @param ike_sa IKE_SA to manage. - */ -task_manager_t *task_manager_create(ike_sa_t *ike_sa); - #endif /** TASK_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager_v2.c similarity index 98% rename from src/libcharon/sa/task_manager.c rename to src/libcharon/sa/task_manager_v2.c index 8a4e81ac2..158c04b5b 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager_v2.c @@ -14,7 +14,7 @@ * for more details. */ -#include "task_manager.h" +#include "task_manager_v2.h" #include @@ -69,7 +69,7 @@ struct private_task_manager_t { /** * public functions */ - task_manager_t public; + task_manager_v2_t public; /** * associated IKE_SA we are serving @@ -1106,22 +1106,24 @@ METHOD(task_manager_t, destroy, void, /* * see header file */ -task_manager_t *task_manager_create(ike_sa_t *ike_sa) +task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) { private_task_manager_t *this; INIT(this, .public = { - .process_message = _process_message, - .queue_task = _queue_task, - .initiate = _initiate, - .retransmit = _retransmit, - .incr_mid = _incr_mid, - .reset = _reset, - .adopt_tasks = _adopt_tasks, - .busy = _busy, - .create_task_enumerator = _create_task_enumerator, - .destroy = _destroy, + .task_manager = { + .process_message = _process_message, + .queue_task = _queue_task, + .initiate = _initiate, + .retransmit = _retransmit, + .incr_mid = _incr_mid, + .reset = _reset, + .adopt_tasks = _adopt_tasks, + .busy = _busy, + .create_task_enumerator = _create_task_enumerator, + .destroy = _destroy, + }, }, .ike_sa = ike_sa, .initiating.type = EXCHANGE_TYPE_UNDEFINED, @@ -1138,4 +1140,3 @@ task_manager_t *task_manager_create(ike_sa_t *ike_sa) return &this->public; } - diff --git a/src/libcharon/sa/task_manager_v2.h b/src/libcharon/sa/task_manager_v2.h new file mode 100644 index 000000000..3e55c983b --- /dev/null +++ b/src/libcharon/sa/task_manager_v2.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup task_manager_v2 task_manager_v2 + * @{ @ingroup sa + */ + +#ifndef TASK_MANAGER_V2_H_ +#define TASK_MANAGER_V2_H_ + +typedef struct task_manager_v2_t task_manager_v2_t; + +#include + +/** + * Task manager, IKEv2 variant. + */ +struct task_manager_v2_t { + + /** + * Implements task_manager_t. + */ + task_manager_t task_manager; +}; + +/** + * Create an instance of the task manager. + * + * @param ike_sa IKE_SA to manage. + */ +task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa); + +#endif /** TASK_MANAGER_V2_H_ @}*/ From 4a09d9ee7f82468f35a95fb8d06001489b17eace Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 15:27:04 +0100 Subject: [PATCH 023/534] Added a stub for a IKEv1 task manager --- src/libcharon/Makefile.am | 2 +- src/libcharon/sa/task_manager_v1.c | 470 +++++++++++++++++++++++++++++ src/libcharon/sa/task_manager_v1.h | 46 +++ 3 files changed, 517 insertions(+), 1 deletion(-) create mode 100644 src/libcharon/sa/task_manager_v1.c create mode 100644 src/libcharon/sa/task_manager_v1.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 5cb17facf..0f525509d 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -67,7 +67,7 @@ sa/ike_sa.c sa/ike_sa.h \ sa/ike_sa_id.c sa/ike_sa_id.h \ sa/ike_sa_manager.c sa/ike_sa_manager.h \ sa/task_manager.h sa/task_manager_v2.c sa/task_manager_v2.h \ -sa/keymat.c sa/keymat.h \ +sa/task_manager_v1.c sa/task_manager_v1.h sa/keymat.c sa/keymat.h \ sa/shunt_manager.c sa/shunt_manager.h \ sa/trap_manager.c sa/trap_manager.h \ sa/tasks/child_create.c sa/tasks/child_create.h \ diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c new file mode 100644 index 000000000..ca2b8ae8a --- /dev/null +++ b/src/libcharon/sa/task_manager_v1.c @@ -0,0 +1,470 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2007-2010 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 . + * + * 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 "task_manager_v1.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ME +#include +#endif + +typedef struct exchange_t exchange_t; + +/** + * An exchange in the air, used do detect and handle retransmission + */ +struct exchange_t { + + /** + * Message ID used for this transaction + */ + u_int32_t mid; + + /** + * generated packet for retransmission + */ + packet_t *packet; +}; + +typedef struct private_task_manager_t private_task_manager_t; + +/** + * private data of the task manager + */ +struct private_task_manager_t { + + /** + * public functions + */ + task_manager_v1_t public; + + /** + * associated IKE_SA we are serving + */ + ike_sa_t *ike_sa; + + /** + * Exchange we are currently handling as responder + */ + struct { + /** + * Message ID of the exchange + */ + u_int32_t mid; + + /** + * packet for retransmission + */ + packet_t *packet; + + } responding; + + /** + * Exchange we are currently handling as initiator + */ + struct { + /** + * Message ID of the exchange + */ + u_int32_t mid; + + /** + * how many times we have retransmitted so far + */ + u_int retransmitted; + + /** + * packet for retransmission + */ + packet_t *packet; + + /** + * type of the initated exchange + */ + exchange_type_t type; + + } initiating; + + /** + * List of queued tasks not yet in action + */ + linked_list_t *queued_tasks; + + /** + * List of active tasks, initiated by ourselve + */ + linked_list_t *active_tasks; + + /** + * List of tasks initiated by peer + */ + linked_list_t *passive_tasks; + + /** + * the task manager has been reset + */ + bool reset; + + /** + * Number of times we retransmit messages before giving up + */ + u_int retransmit_tries; + + /** + * Retransmission timeout + */ + double retransmit_timeout; + + /** + * Base to calculate retransmission timeout + */ + double retransmit_base; +}; + +/** + * flush all tasks in the task manager + */ +static void flush(private_task_manager_t *this) +{ + this->queued_tasks->destroy_offset(this->queued_tasks, + offsetof(task_t, destroy)); + this->queued_tasks = linked_list_create(); + this->passive_tasks->destroy_offset(this->passive_tasks, + offsetof(task_t, destroy)); + this->passive_tasks = linked_list_create(); + this->active_tasks->destroy_offset(this->active_tasks, + offsetof(task_t, destroy)); + this->active_tasks = linked_list_create(); +} + +METHOD(task_manager_t, retransmit, status_t, + private_task_manager_t *this, u_int32_t message_id) +{ + return FAILED; +} + +METHOD(task_manager_t, initiate, status_t, + private_task_manager_t *this) +{ + return FAILED; +} + +/** + * handle exchange collisions + */ +static bool handle_collisions(private_task_manager_t *this, task_t *task) +{ + return FALSE; +} + +/** + * build a response depending on the "passive" task list + */ +static status_t build_response(private_task_manager_t *this, message_t *request) +{ + enumerator_t *enumerator; + task_t *task; + message_t *message; + host_t *me, *other; + bool delete = FALSE; + status_t status; + + me = request->get_destination(request); + other = request->get_source(request); + + message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); + message->set_exchange_type(message, request->get_exchange_type(request)); + /* send response along the path the request came in */ + message->set_source(message, me->clone(me)); + message->set_destination(message, other->clone(other)); + message->set_message_id(message, this->responding.mid); + message->set_request(message, FALSE); + + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->build(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + if (!handle_collisions(this, task)) + { + task->destroy(task); + } + break; + case NEED_MORE: + /* processed, but task needs another exchange */ + if (handle_collisions(this, task)) + { + this->passive_tasks->remove_at(this->passive_tasks, + enumerator); + } + break; + case FAILED: + default: + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + /* FALL */ + case DESTROY_ME: + /* destroy IKE_SA, but SEND response first */ + delete = TRUE; + break; + } + if (delete) + { + break; + } + } + enumerator->destroy(enumerator); + + /* message complete, send it */ + DESTROY_IF(this->responding.packet); + this->responding.packet = NULL; + status = this->ike_sa->generate_message(this->ike_sa, message, + &this->responding.packet); + message->destroy(message); + if (status != SUCCESS) + { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; + } + + charon->sender->send(charon->sender, + this->responding.packet->clone(this->responding.packet)); + if (delete) + { + return DESTROY_ME; + } + return SUCCESS; +} + +/** + * handle an incoming request message + */ +static status_t process_request(private_task_manager_t *this, + message_t *message) +{ + enumerator_t *enumerator; + task_t *task = NULL; + + if (this->passive_tasks->get_count(this->passive_tasks) == 0) + { /* create tasks depending on request type, if not already some queued */ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + /* TODO-IKEv1: handle mainmode */ + break; + case AGGRESSIVE: + /* TODO-IKEv1: agressive mode */ + return FAILED; + case QUICK_MODE: + /* TODO-IKEv1: quick mode */ + return FAILED; + case INFORMATIONAL_V1: + /* TODO-IKEv1: informational */ + return FAILED; + default: + return FAILED; + } + } + /* let the tasks process the message */ + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->process(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + task->destroy(task); + break; + case NEED_MORE: + /* processed, but task needs at least another call to build() */ + break; + case FAILED: + default: + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + /* FALL */ + case DESTROY_ME: + /* critical failure, destroy IKE_SA */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + enumerator->destroy(enumerator); + task->destroy(task); + return DESTROY_ME; + } + } + enumerator->destroy(enumerator); + + return build_response(this, message); +} + +METHOD(task_manager_t, process_message, status_t, + private_task_manager_t *this, message_t *msg) +{ + /* TODO-IKEv1: detect request/response */ + if (TRUE) + { + /* TODO-IKEv1: detect mainmode retransmission */ + charon->bus->message(charon->bus, msg, TRUE); + if (process_request(this, msg) != SUCCESS) + { + flush(this); + return DESTROY_ME; + } + } + else + { + /* TODO-IKEv1: handle response */ + return DESTROY_ME; + } + return SUCCESS; +} + +METHOD(task_manager_t, queue_task, void, + private_task_manager_t *this, task_t *task) +{ + DBG2(DBG_IKE, "queueing %N task", task_type_names, task->get_type(task)); + this->queued_tasks->insert_last(this->queued_tasks, task); +} + +METHOD(task_manager_t, adopt_tasks, void, + private_task_manager_t *this, task_manager_t *other_public) +{ + private_task_manager_t *other = (private_task_manager_t*)other_public; + task_t *task; + + /* move queued tasks from other to this */ + while (other->queued_tasks->remove_last(other->queued_tasks, + (void**)&task) == SUCCESS) + { + DBG2(DBG_IKE, "migrating %N task", task_type_names, task->get_type(task)); + task->migrate(task, this->ike_sa); + this->queued_tasks->insert_first(this->queued_tasks, task); + } +} + +METHOD(task_manager_t, busy, bool, + private_task_manager_t *this) +{ + return (this->active_tasks->get_count(this->active_tasks) > 0); +} + +METHOD(task_manager_t, incr_mid, void, + private_task_manager_t *this, bool initiate) +{ + if (initiate) + { + this->initiating.mid++; + } + else + { + this->responding.mid++; + } +} + +METHOD(task_manager_t, reset, void, + private_task_manager_t *this, u_int32_t initiate, u_int32_t respond) +{ + +} + +METHOD(task_manager_t, create_task_enumerator, enumerator_t*, + private_task_manager_t *this, task_queue_t queue) +{ + switch (queue) + { + case TASK_QUEUE_ACTIVE: + return this->active_tasks->create_enumerator(this->active_tasks); + case TASK_QUEUE_PASSIVE: + return this->passive_tasks->create_enumerator(this->passive_tasks); + case TASK_QUEUE_QUEUED: + return this->queued_tasks->create_enumerator(this->queued_tasks); + default: + return enumerator_create_empty(); + } +} + +METHOD(task_manager_t, destroy, void, + private_task_manager_t *this) +{ + flush(this); + + this->active_tasks->destroy(this->active_tasks); + this->queued_tasks->destroy(this->queued_tasks); + this->passive_tasks->destroy(this->passive_tasks); + + DESTROY_IF(this->responding.packet); + DESTROY_IF(this->initiating.packet); + free(this); +} + +/* + * see header file + */ +task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) +{ + private_task_manager_t *this; + + INIT(this, + .public = { + .task_manager = { + .process_message = _process_message, + .queue_task = _queue_task, + .initiate = _initiate, + .retransmit = _retransmit, + .incr_mid = _incr_mid, + .reset = _reset, + .adopt_tasks = _adopt_tasks, + .busy = _busy, + .create_task_enumerator = _create_task_enumerator, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiating.type = EXCHANGE_TYPE_UNDEFINED, + .queued_tasks = linked_list_create(), + .active_tasks = linked_list_create(), + .passive_tasks = linked_list_create(), + .retransmit_tries = lib->settings->get_int(lib->settings, + "charon.retransmit_tries", RETRANSMIT_TRIES), + .retransmit_timeout = lib->settings->get_double(lib->settings, + "charon.retransmit_timeout", RETRANSMIT_TIMEOUT), + .retransmit_base = lib->settings->get_double(lib->settings, + "charon.retransmit_base", RETRANSMIT_BASE), + ); + + return &this->public; +} diff --git a/src/libcharon/sa/task_manager_v1.h b/src/libcharon/sa/task_manager_v1.h new file mode 100644 index 000000000..99cd35e32 --- /dev/null +++ b/src/libcharon/sa/task_manager_v1.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup task_manager_v1 task_manager_v1 + * @{ @ingroup sa + */ + +#ifndef TASK_MANAGER_V1_H_ +#define TASK_MANAGER_V1_H_ + +typedef struct task_manager_v1_t task_manager_v1_t; + +#include + +/** + * Task manager, IKEv1 variant. + */ +struct task_manager_v1_t { + + /** + * Implements task_manager_t. + */ + task_manager_t task_manager; +}; + +/** + * Create an instance of the task manager. + * + * @param ike_sa IKE_SA to manage. + */ +task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa); + +#endif /** TASK_MANAGER_V1_H_ @}*/ From c73c832c5a2ced0eb3e731bb95012b5fce2f96e5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 14:44:06 +0000 Subject: [PATCH 024/534] Added an IKEv1 main mode task stub --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/task_manager_v1.c | 27 +----- src/libcharon/sa/tasks/main_mode.c | 136 +++++++++++++++++++++++++++++ src/libcharon/sa/tasks/main_mode.h | 49 +++++++++++ src/libcharon/sa/tasks/task.h | 2 + 5 files changed, 191 insertions(+), 24 deletions(-) create mode 100644 src/libcharon/sa/tasks/main_mode.c create mode 100644 src/libcharon/sa/tasks/main_mode.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 0f525509d..a3b72253d 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -86,6 +86,7 @@ sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ +sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/task.c sa/tasks/task.h daemon.lo : $(top_builddir)/config.status diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index ca2b8ae8a..7eb81fc44 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -16,30 +16,8 @@ #include "task_manager_v1.h" -#include - #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef ME -#include -#endif +#include typedef struct exchange_t exchange_t; @@ -285,7 +263,8 @@ static status_t process_request(private_task_manager_t *this, switch (message->get_exchange_type(message)) { case ID_PROT: - /* TODO-IKEv1: handle mainmode */ + task = (task_t *)main_mode_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); break; case AGGRESSIVE: /* TODO-IKEv1: agressive mode */ diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c new file mode 100644 index 000000000..d208896e4 --- /dev/null +++ b/src/libcharon/sa/tasks/main_mode.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "main_mode.h" + +#include + +#include +#include +#include +#include +#include + + +typedef struct private_main_mode_t private_main_mode_t; + +/** + * Private members of a main_mode_t task. + */ +struct private_main_mode_t { + + /** + * Public methods and task_t interface. + */ + main_mode_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * IKE config to establish + */ + ike_cfg_t *config; +}; + +METHOD(task_t, build_i, status_t, + private_main_mode_t *this, message_t *message) +{ + /* TODO-IKEv1: initiate mainmode */ + return FAILED; +} + +METHOD(task_t, process_r, status_t, + private_main_mode_t *this, message_t *message) +{ + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); + DBG0(DBG_IKE, "%H is initiating a Main Mode", message->get_source(message)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + /* TODO-IKEv1: process mainmode request */ + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_main_mode_t *this, message_t *message) +{ + /* TODO-IKEv1: build mainmode response */ + return FAILED; +} + +METHOD(task_t, process_i, status_t, + private_main_mode_t *this, message_t *message) +{ + /* TODO-IKEv1: process main mode as initiator */ + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_main_mode_t *this) +{ + return MAIN_MODE; +} + +METHOD(task_t, migrate, void, + private_main_mode_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_main_mode_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator) +{ + private_main_mode_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/tasks/main_mode.h b/src/libcharon/sa/tasks/main_mode.h new file mode 100644 index 000000000..d62501180 --- /dev/null +++ b/src/libcharon/sa/tasks/main_mode.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup main_mode main_mode + * @{ @ingroup tasks + */ + +#ifndef MAIN_MODE_H_ +#define MAIN_MODE_H_ + +typedef struct main_mode_t main_mode_t; + +#include +#include +#include + +/** + * IKEv1 main mode, establishes a mainmode including authentication. + */ +struct main_mode_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new main_mode task. + * + * @param initiator TRUE if task initiated locally + * @return task to handle by the task_manager + */ +main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** MAIN_MODE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index d57085954..6ceb2690f 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -69,6 +69,8 @@ enum task_type_t { CHILD_DELETE, /** rekey an CHILD_SA */ CHILD_REKEY, + /** IKEv1 main mode */ + MAIN_MODE, }; /** From da8cadbd93e93f746daba2698156a9744861537c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 15:09:02 +0000 Subject: [PATCH 025/534] Set default IKE header initiator flag in IKEv2 only --- src/libcharon/encoding/payloads/ike_header.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/ike_header.c b/src/libcharon/encoding/payloads/ike_header.c index 556e42258..8f379442b 100644 --- a/src/libcharon/encoding/payloads/ike_header.c +++ b/src/libcharon/encoding/payloads/ike_header.c @@ -486,7 +486,10 @@ ike_header_t *ike_header_create_version(int major, int minor) this->set_maj_version(this, major); this->set_min_version(this, minor); - this->set_initiator_flag(this, TRUE); - + if (major == IKEV2_MAJOR_VERSION) + { + this->set_initiator_flag(this, TRUE); + } return this; } + From bce8d3be1182f249659f2c01ac7feca58de533f4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 18:23:00 +0100 Subject: [PATCH 026/534] Don't set IKEv2 only header flags when using IKEv1 --- src/libcharon/encoding/message.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 91d7f3df9..6640b7696 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1315,10 +1315,13 @@ METHOD(message_t, generate, status_t, this->minor_version); ike_header->set_exchange_type(ike_header, this->exchange_type); ike_header->set_message_id(ike_header, this->message_id); - ike_header->set_response_flag(ike_header, !this->is_request); - ike_header->set_version_flag(ike_header, this->version_flag); - ike_header->set_initiator_flag(ike_header, + if (this->major_version == IKEV2_MAJOR_VERSION) + { + ike_header->set_response_flag(ike_header, !this->is_request); + ike_header->set_version_flag(ike_header, this->version_flag); + ike_header->set_initiator_flag(ike_header, this->ike_sa_id->is_initiator(this->ike_sa_id)); + } ike_header->set_initiator_spi(ike_header, this->ike_sa_id->get_initiator_spi(this->ike_sa_id)); ike_header->set_responder_spi(ike_header, From 2bcd51b3893b50acaad80ed2cc9c86e2e01f2f62 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 18:23:37 +0100 Subject: [PATCH 027/534] Added SA payload IKEv1 encoding types to generator --- src/libcharon/encoding/generator.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index ce3844361..329b1c15f 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -465,8 +465,11 @@ METHOD(generator_t, generate_payload, void, generate_from_chunk(this, rules[i].offset); break; case PROPOSALS: + case PROPOSALS_V1: case TRANSFORMS: + case TRANSFORMS_V1: case TRANSFORM_ATTRIBUTES: + case TRANSFORM_ATTRIBUTES_V1: case CONFIGURATION_ATTRIBUTES: case TRAFFIC_SELECTORS: { From 3a470f303542dfb127eb8b17553da06a92892ebb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 18:24:14 +0100 Subject: [PATCH 028/534] Added limiting encoding of IKEv1 SA payloads --- .../encoding/payloads/proposal_substructure.c | 274 +++++++++++++----- src/libcharon/encoding/payloads/sa_payload.c | 2 +- .../encoding/payloads/transform_attribute.c | 9 +- .../encoding/payloads/transform_attribute.h | 9 +- .../payloads/transform_substructure.c | 16 +- .../payloads/transform_substructure.h | 3 +- 6 files changed, 231 insertions(+), 82 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index efa748bd0..2a033b6a8 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -432,64 +432,78 @@ static void add_to_proposal_v2(proposal_t *proposal, transform->get_transform_id(transform), key_length); } +/** + * Map IKEv1 to IKEv2 algorithms + */ +typedef struct { + u_int16_t ikev1; + u_int16_t ikev2; +} algo_map_t; + +/** + * Encryption algorithm mapping + */ +static algo_map_t map_encr[] = { + { IKEV1_ENCR_DES_CBC, ENCR_DES }, + { IKEV1_ENCR_IDEA_CBC, ENCR_IDEA }, + { IKEV1_ENCR_BLOWFISH_CBC, ENCR_BLOWFISH }, + { IKEV1_ENCR_3DES_CBC, ENCR_3DES }, + { IKEV1_ENCR_CAST_CBC, ENCR_CAST }, + { IKEV1_ENCR_AES_CBC, ENCR_AES_CBC }, + { IKEV1_ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CBC }, +}; + +/** + * Integrity algorithm mapping + */ +static algo_map_t map_integ[] = { + { IKEV1_HASH_MD5, AUTH_HMAC_MD5_96 }, + { IKEV1_HASH_SHA1, AUTH_HMAC_SHA1_96 }, + { IKEV1_HASH_SHA2_256, AUTH_HMAC_SHA2_256_128 }, + { IKEV1_HASH_SHA2_384, AUTH_HMAC_SHA2_384_192 }, + { IKEV1_HASH_SHA2_512, AUTH_HMAC_SHA2_512_256 }, +}; + +/** + * PRF algorithm mapping + */ +static algo_map_t map_prf[] = { + { IKEV1_HASH_MD5, PRF_HMAC_MD5 }, + { IKEV1_HASH_SHA1, PRF_HMAC_SHA1 }, + { IKEV1_HASH_SHA2_256, PRF_HMAC_SHA2_256 }, + { IKEV1_HASH_SHA2_384, PRF_HMAC_SHA2_384 }, + { IKEV1_HASH_SHA2_512, PRF_HMAC_SHA2_512 }, +}; + /** * Get IKEv2 algorithm from IKEv1 identifier */ static u_int16_t get_alg_from_ikev1(transform_type_t type, u_int16_t value) { - typedef struct { - u_int16_t ikev1; - u_int16_t ikev2; - } algo_map_t; - - static algo_map_t encr[] = { - { IKEV1_ENCR_DES_CBC, ENCR_DES }, - { IKEV1_ENCR_IDEA_CBC, ENCR_IDEA }, - { IKEV1_ENCR_BLOWFISH_CBC, ENCR_BLOWFISH }, - { IKEV1_ENCR_3DES_CBC, ENCR_3DES }, - { IKEV1_ENCR_CAST_CBC, ENCR_CAST }, - { IKEV1_ENCR_AES_CBC, ENCR_AES_CBC }, - { IKEV1_ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CBC }, - }; - static algo_map_t integ[] = { - { IKEV1_HASH_MD5, AUTH_HMAC_MD5_96 }, - { IKEV1_HASH_SHA1, AUTH_HMAC_SHA1_96 }, - { IKEV1_HASH_SHA2_256, AUTH_HMAC_SHA2_256_128 }, - { IKEV1_HASH_SHA2_384, AUTH_HMAC_SHA2_384_192 }, - { IKEV1_HASH_SHA2_512, AUTH_HMAC_SHA2_512_256 }, - }; - static algo_map_t prf[] = { - { IKEV1_HASH_MD5, PRF_HMAC_MD5 }, - { IKEV1_HASH_SHA1, PRF_HMAC_SHA1 }, - { IKEV1_HASH_SHA2_256, PRF_HMAC_SHA2_256 }, - { IKEV1_HASH_SHA2_384, PRF_HMAC_SHA2_384 }, - { IKEV1_HASH_SHA2_512, PRF_HMAC_SHA2_512 }, - }; - int i, count; - u_int16_t def; algo_map_t *map; + u_int16_t def; + int i, count; switch (type) { case ENCRYPTION_ALGORITHM: - map = encr; - count = countof(encr); + map = map_encr; + count = countof(map_encr); def = ENCR_UNDEFINED; break; case INTEGRITY_ALGORITHM: - map = integ; - count = countof(integ); + map = map_integ; + count = countof(map_integ); def = AUTH_UNDEFINED; break; case PSEUDO_RANDOM_FUNCTION: - map = prf; - count = countof(prf); + map = map_prf; + count = countof(map_prf); def = PRF_UNDEFINED; break; default: return 0; } - for (i = 0; i < count; i++) { if (map[i].ikev1 == value) @@ -500,6 +514,41 @@ static u_int16_t get_alg_from_ikev1(transform_type_t type, u_int16_t value) return def; } +/** + * Get IKEv1 algorithm from IKEv2 identifier + */ +static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value) +{ + algo_map_t *map; + int i, count; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = map_encr; + count = countof(map_encr); + break; + case INTEGRITY_ALGORITHM: + map = map_integ; + count = countof(map_integ); + break; + case PSEUDO_RANDOM_FUNCTION: + map = map_prf; + count = countof(map_prf); + break; + default: + return 0; + } + for (i = 0; i < count; i++) + { + if (map[i].ikev2 == value) + { + return map[i].ikev1; + } + } + return 0; +} + /** * Add an IKE transform to a proposal for IKEv1 */ @@ -606,7 +655,6 @@ METHOD(proposal_substructure_t, get_proposal, proposal_t*, default: break; } - return proposal; } @@ -663,32 +711,97 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type) return &this->public; } -/* - * Described in header. +/** + * Add an IKEv1 IKE proposal to the substructure */ -proposal_substructure_t *proposal_substructure_create_from_proposal( - payload_type_t type, proposal_t *proposal) +static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, + proposal_t *proposal) { transform_substructure_t *transform; - private_proposal_substructure_t *this; u_int16_t alg, key_size; enumerator_t *enumerator; - payload_type_t subtype = TRANSFORM_SUBSTRUCTURE; - if (type == PROPOSAL_SUBSTRUCTURE_V1) + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, + 0, IKEV1_TRANSID_KEY_IKE); + + enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); + while (enumerator->enumerate(enumerator, &alg, &key_size)) { - /* TODO-IKEv1: IKEv1 specific proposal encoding */ - subtype = TRANSFORM_SUBSTRUCTURE_V1; + alg = get_ikev1_from_alg(ENCRYPTION_ALGORITHM, alg); + if (alg) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_ENCRYPTION_ALGORITHM, alg)); + if (key_size) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_KEY_LENGTH, key_size)); + } + } } + enumerator->destroy(enumerator); - this = (private_proposal_substructure_t*)proposal_substructure_create(type); + /* encode the integrity algorithm as hash and assume use the same PRF */ + enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); + while (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg); + if (alg) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_HASH_ALGORITHM, alg)); + } + } + enumerator->destroy(enumerator); + + enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); + while (enumerator->enumerate(enumerator, &alg, &key_size)) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_GROUP, alg)); + } + enumerator->destroy(enumerator); + + /* TODO-IKEv1: Add lifetime, auth and other attributes */ + + add_transform_substructure(this, transform); +} + +/** + * Add an IKEv1 ESP proposal to the substructure + */ +static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, + proposal_t *proposal) +{ + /* TODO-IKEv1: add ESP proposal to transform substr */ +} + +/** + * Add an IKEv2 proposal to the substructure + */ +static void set_from_proposal_v2(private_proposal_substructure_t *this, + proposal_t *proposal) +{ + transform_substructure_t *transform; + u_int16_t alg, key_size; + enumerator_t *enumerator; /* encryption algorithm is only available in ESP */ enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(subtype, - ENCRYPTION_ALGORITHM, alg, key_size); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + ENCRYPTION_ALGORITHM, alg); + if (key_size) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE, + TATTR_IKEV2_KEY_LENGTH, key_size)); + } add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -697,8 +810,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(subtype, - INTEGRITY_ALGORITHM, alg, key_size); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + INTEGRITY_ALGORITHM, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -707,8 +820,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, PSEUDO_RANDOM_FUNCTION); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(subtype, - PSEUDO_RANDOM_FUNCTION, alg, key_size); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + PSEUDO_RANDOM_FUNCTION, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -717,8 +830,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); while (enumerator->enumerate(enumerator, &alg, NULL)) { - transform = transform_substructure_create_type(subtype, - DIFFIE_HELLMAN_GROUP, alg, 0); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + DIFFIE_HELLMAN_GROUP, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -727,27 +840,58 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, EXTENDED_SEQUENCE_NUMBERS); while (enumerator->enumerate(enumerator, &alg, NULL)) { - transform = transform_substructure_create_type(subtype, - EXTENDED_SEQUENCE_NUMBERS, alg, 0); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + EXTENDED_SEQUENCE_NUMBERS, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); +} +/* + * Described in header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposal( + payload_type_t type, proposal_t *proposal) +{ + private_proposal_substructure_t *this; + u_int64_t spi64; + u_int32_t spi32; + + this = (private_proposal_substructure_t*)proposal_substructure_create(type); + + if (type == PROPOSAL_SUBSTRUCTURE) + { + set_from_proposal_v2(this, proposal); + } + else + { + switch (proposal->get_protocol(proposal)) + { + case PROTO_IKE: + set_from_proposal_v1_ike(this, proposal); + break; + case PROTO_ESP: + set_from_proposal_v1_esp(this, proposal); + break; + default: + break; + } + } /* add SPI, if necessary */ switch (proposal->get_protocol(proposal)) { case PROTO_AH: case PROTO_ESP: - this->spi_size = this->spi.len = 4; - this->spi.ptr = malloc(this->spi_size); - *((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal); + spi32 = proposal->get_spi(proposal); + this->spi = chunk_clone(chunk_from_thing(spi32)); + this->spi_size = this->spi.len; break; case PROTO_IKE: - if (proposal->get_spi(proposal)) + spi64 = proposal->get_spi(proposal); + if (spi64) { /* IKE only uses SPIS when rekeying, but on initial setup */ - this->spi_size = this->spi.len = 8; - this->spi.ptr = malloc(this->spi_size); - *((u_int64_t*)this->spi.ptr) = proposal->get_spi(proposal); + this->spi = chunk_clone(chunk_from_thing(spi64)); + this->spi_size = this->spi.len; } break; default: diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 061226310..8f9dda411 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -272,12 +272,12 @@ METHOD(sa_payload_t, add_proposal, void, payload_type_t subtype = PROPOSAL_SUBSTRUCTURE; u_int count; - count = this->proposals->get_count(this->proposals); if (this->type == SECURITY_ASSOCIATION_V1) { subtype = PROPOSAL_SUBSTRUCTURE_V1; } substruct = proposal_substructure_create_from_proposal(subtype, proposal); + count = this->proposals->get_count(this->proposals); if (count > 0) { this->proposals->get_last(this->proposals, (void**)&last); diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index e928dcddb..97bde8bce 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -283,13 +283,14 @@ transform_attribute_t *transform_attribute_create(payload_type_t type) /* * Described in header. */ -transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length) +transform_attribute_t *transform_attribute_create_value(payload_type_t type, + transform_attribute_type_t kind, u_int16_t value) { transform_attribute_t *attribute; - attribute = transform_attribute_create(TRANSFORM_ATTRIBUTE); - attribute->set_attribute_type(attribute, TATTR_IKEV2_KEY_LENGTH); - attribute->set_value(attribute, key_length); + attribute = transform_attribute_create(type); + attribute->set_attribute_type(attribute, kind); + attribute->set_value(attribute, value); return attribute; } diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h index 21bde46b8..eedb3be21 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.h +++ b/src/libcharon/encoding/payloads/transform_attribute.h @@ -163,11 +163,14 @@ struct transform_attribute_t { transform_attribute_t *transform_attribute_create(payload_type_t type); /** - * Creates an transform_attribute_t of type KEY_LENGTH. + * Creates a two byte value attribute for a given attribute kind. * - * @param key_length key length in bytes + * @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 + * @param kind attribute kind + * @param value fixed two byte value * @return transform_attribute_t object */ -transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length); +transform_attribute_t *transform_attribute_create_value(payload_type_t type, + transform_attribute_type_t kind, u_int16_t value); #endif /** TRANSFORM_ATTRIBUTE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c index 141898a5b..54463cbc3 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.c +++ b/src/libcharon/encoding/payloads/transform_substructure.c @@ -213,6 +213,13 @@ METHOD(payload_t, get_length, size_t, return this->transform_length; } +METHOD(transform_substructure_t, add_transform_attribute, void, + private_transform_substructure_t *this, transform_attribute_t *attribute) +{ + this->attributes->insert_last(this->attributes, attribute); + compute_length(this); +} + METHOD(transform_substructure_t, set_is_last_transform, void, private_transform_substructure_t *this, bool is_last) { @@ -272,6 +279,7 @@ transform_substructure_t *transform_substructure_create(payload_type_t type) .get_type = _get_type, .destroy = _destroy, }, + .add_transform_attribute = _add_transform_attribute, .set_is_last_transform = _set_is_last_transform, .get_transform_type_or_number = _get_transform_type_or_number, .get_transform_id = _get_transform_id, @@ -290,7 +298,7 @@ transform_substructure_t *transform_substructure_create(payload_type_t type) * Described in header */ transform_substructure_t *transform_substructure_create_type(payload_type_t type, - u_int8_t type_or_number, u_int16_t id, u_int16_t key_length) + u_int8_t type_or_number, u_int16_t id) { private_transform_substructure_t *this; @@ -305,12 +313,6 @@ transform_substructure_t *transform_substructure_create_type(payload_type_t type { this->transform_id_v1 = id; } - if (key_length) - { - this->attributes->insert_last(this->attributes, - (void*)transform_attribute_create_key_length(key_length)); - compute_length(this); - } return &this->public; } diff --git a/src/libcharon/encoding/payloads/transform_substructure.h b/src/libcharon/encoding/payloads/transform_substructure.h index e6a7f8e4d..7b1071275 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.h +++ b/src/libcharon/encoding/payloads/transform_substructure.h @@ -113,10 +113,9 @@ transform_substructure_t *transform_substructure_create(payload_type_t type); * @param type TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 * @param type_or_number Type (IKEv2) or number (IKEv1) of transform * @param id transform id specifc for the transform type - * @param key_length key length for key length attribute, 0 to omit * @return transform_substructure_t object */ transform_substructure_t *transform_substructure_create_type(payload_type_t type, - u_int8_t type_or_number, u_int16_t id, u_int16_t key_length); + u_int8_t type_or_number, u_int16_t id); #endif /** TRANSFORM_SUBSTRUCTURE_H_ @}*/ From 2e897fe30acfdde96209317e38419cda0e83b8cc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 16 Nov 2011 18:24:47 +0100 Subject: [PATCH 029/534] Handle first exchange in IKEv1 main mode as responder --- src/libcharon/sa/tasks/main_mode.c | 37 ++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index d208896e4..e8bd62554 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -23,7 +23,6 @@ #include #include - typedef struct private_main_mode_t private_main_mode_t; /** @@ -50,6 +49,11 @@ struct private_main_mode_t { * IKE config to establish */ ike_cfg_t *config; + + /** + * selected IKE proposal + */ + proposal_t *proposal; }; METHOD(task_t, build_i, status_t, @@ -66,15 +70,39 @@ METHOD(task_t, process_r, status_t, DBG0(DBG_IKE, "%H is initiating a Main Mode", message->get_source(message)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); - /* TODO-IKEv1: process mainmode request */ + if (!this->proposal) + { + linked_list_t *list; + sa_payload_t *sa_payload; + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return FAILED; + } + list = sa_payload->get_proposals(sa_payload); + this->proposal = this->config->select_proposal(this->config, list, FALSE); + + if (!this->proposal) + { + DBG1(DBG_IKE, "no proposal found"); + return FAILED; + } + } return NEED_MORE; } METHOD(task_t, build_r, status_t, private_main_mode_t *this, message_t *message) { - /* TODO-IKEv1: build mainmode response */ - return FAILED; + sa_payload_t *sa_payload; + + sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1, + this->proposal); + message->add_payload(message, &sa_payload->payload_interface); + return NEED_MORE; } METHOD(task_t, process_i, status_t, @@ -99,6 +127,7 @@ METHOD(task_t, migrate, void, METHOD(task_t, destroy, void, private_main_mode_t *this) { + DESTROY_IF(this->proposal); free(this); } From 717333da98b45590035fc4461538882428191e40 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 10:45:41 +0100 Subject: [PATCH 030/534] Add fixed PSK authentication method to IKEv1 proposal for now --- .../encoding/payloads/proposal_substructure.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 2a033b6a8..40caef858 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -228,6 +228,17 @@ typedef enum { IKEV1_LIFE_TYPE_KILOBYTES = 2, } ikev1_life_type_t; +/** + * IKEv1 authenticaiton methods + */ +typedef enum { + IKEV1_AUTH_PSK = 1, + IKEV1_AUTH_DSS_SIG = 2, + IKEV1_AUTH_RSA_SIG = 3, + IKEV1_AUTH_RSA_ENC = 4, + IKEV1_AUTH_RSA_ENC_REV = 5, +} ikev1_auth_method_t; + METHOD(payload_t, verify, status_t, private_proposal_substructure_t *this) { @@ -766,7 +777,10 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, } enumerator->destroy(enumerator); - /* TODO-IKEv1: Add lifetime, auth and other attributes */ + /* TODO-IKEv1: Add lifetime, non-fixed auth-method and other attributes */ + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_PSK)); add_transform_substructure(this, transform); } From bcfb0f409663d9afc0c1019dd826155d70320aef Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 10:53:35 +0100 Subject: [PATCH 031/534] Extended nonce payload for IKEv1 support --- src/libcharon/encoding/payloads/nonce_payload.c | 10 ++++++++-- src/libcharon/encoding/payloads/nonce_payload.h | 9 ++++----- src/libcharon/encoding/payloads/payload.c | 3 ++- src/libcharon/sa/tasks/child_create.c | 2 +- src/libcharon/sa/tasks/ike_init.c | 2 +- 5 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/libcharon/encoding/payloads/nonce_payload.c b/src/libcharon/encoding/payloads/nonce_payload.c index 78000b8c6..684bddce4 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.c +++ b/src/libcharon/encoding/payloads/nonce_payload.c @@ -57,6 +57,11 @@ struct private_nonce_payload_t { * The contained nonce value. */ chunk_t nonce; + + /** + * Payload type, NONCE or NONCE_V1 + */ + payload_type_t type; }; /** @@ -115,7 +120,7 @@ METHOD(payload_t, get_encoding_rules, void, METHOD(payload_t, get_type, payload_type_t, private_nonce_payload_t *this) { - return NONCE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -159,7 +164,7 @@ METHOD2(payload_t, nonce_payload_t, destroy, void, /* * Described in header */ -nonce_payload_t *nonce_payload_create() +nonce_payload_t *nonce_payload_create(payload_type_t type) { private_nonce_payload_t *this; @@ -180,6 +185,7 @@ nonce_payload_t *nonce_payload_create() }, .next_payload = NO_PAYLOAD, .payload_length = NONCE_PAYLOAD_HEADER_LENGTH, + .type = type, ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/nonce_payload.h b/src/libcharon/encoding/payloads/nonce_payload.h index e9212202e..3be2e2e13 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.h +++ b/src/libcharon/encoding/payloads/nonce_payload.h @@ -38,9 +38,7 @@ typedef struct nonce_payload_t nonce_payload_t; #define NONCE_PAYLOAD_HEADER_LENGTH 4 /** - * Object representing an IKEv2 Nonce payload. - * - * The Nonce payload format is described in RFC section 3.3. + * Object representing an IKEv1/IKEv2 Nonce payload. */ struct nonce_payload_t { /** @@ -71,8 +69,9 @@ struct nonce_payload_t { /** * Creates an empty nonce_payload_t object * - * @return nonce_payload_t object + * @param type NONCE or NONCE_V1 + * @return nonce_payload_t object */ -nonce_payload_t *nonce_payload_create(void); +nonce_payload_t *nonce_payload_create(payload_type_t type); #endif /** NONCE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 2021e847e..56563acef 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -180,7 +180,8 @@ payload_t *payload_create(payload_type_t type) case TRANSFORM_ATTRIBUTE_V1: return (payload_t*)transform_attribute_create(type); case NONCE: - return (payload_t*)nonce_payload_create(); + case NONCE_V1: + return (payload_t*)nonce_payload_create(type); case ID_INITIATOR: case ID_RESPONDER: #ifdef ME diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index fdc5b520e..587e37aea 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -539,7 +539,7 @@ static void build_payloads(private_child_create_t *this, message_t *message) /* add nonce payload if not in IKE_AUTH */ if (message->get_exchange_type(message) == CREATE_CHILD_SA) { - nonce_payload = nonce_payload_create(); + nonce_payload = nonce_payload_create(NONCE); nonce_payload->set_nonce(nonce_payload, this->my_nonce); message->add_payload(message, (payload_t*)nonce_payload); } diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/tasks/ike_init.c index 911e0c2aa..e6f4237ce 100644 --- a/src/libcharon/sa/tasks/ike_init.c +++ b/src/libcharon/sa/tasks/ike_init.c @@ -148,7 +148,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message) } message->add_payload(message, (payload_t*)sa_payload); - nonce_payload = nonce_payload_create(); + nonce_payload = nonce_payload_create(NONCE); nonce_payload->set_nonce(nonce_payload, this->my_nonce); ke_payload = ke_payload_create_from_diffie_hellman(this->dh); From 683d83ed3ef6c920a59f6d23d0f44c66fc6ded42 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 11:16:02 +0100 Subject: [PATCH 032/534] Extended KE payload for IKEv1 support --- src/libcharon/encoding/generator.c | 1 + src/libcharon/encoding/parser.c | 11 ++++ src/libcharon/encoding/payloads/encodings.c | 1 + src/libcharon/encoding/payloads/encodings.h | 5 ++ src/libcharon/encoding/payloads/ke_payload.c | 66 ++++++++++++++++---- src/libcharon/encoding/payloads/ke_payload.h | 34 +++++----- src/libcharon/encoding/payloads/payload.c | 3 +- src/libcharon/sa/tasks/child_create.c | 3 +- src/libcharon/sa/tasks/ike_init.c | 2 +- 9 files changed, 96 insertions(+), 30 deletions(-) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 329b1c15f..662ebf977 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -450,6 +450,7 @@ METHOD(generator_t, generate_payload, void, case ADDRESS: case SPI: case KEY_EXCHANGE_DATA: + case KEY_EXCHANGE_DATA_V1: case NOTIFICATION_DATA: case NONCE_DATA: case ID_DATA: diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index c2c60f06a..86ab212b8 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -729,6 +729,17 @@ METHOD(parser_t, parse_payload, status_t, } break; } + case KEY_EXCHANGE_DATA_V1: + { + if (payload_length < KE_PAYLOAD_V1_HEADER_LENGTH || + !parse_chunk(this, rule_number, output + rule->offset, + payload_length - KE_PAYLOAD_V1_HEADER_LENGTH)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } case NOTIFICATION_DATA: { if (payload_length < NOTIFY_PAYLOAD_HEADER_LENGTH + spi_size || diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index d181d9303..582847048 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -30,6 +30,7 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "SPI_SIZE", "SPI", "KEY_EXCHANGE_DATA", + "KEY_EXCHANGE_DATA_V1", "NOTIFICATION_DATA", "PROPOSALS", "PROPOSALS_V1", diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index 8c9fb866c..0e9a44e92 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -196,6 +196,11 @@ enum encoding_type_t { */ KEY_EXCHANGE_DATA, + /** + * Same as KEY_EXCHANGE_DATA, but for KEY_EXCHANGE_V1 + */ + KEY_EXCHANGE_DATA_V1, + /** * Representating a Notification field. * diff --git a/src/libcharon/encoding/payloads/ke_payload.c b/src/libcharon/encoding/payloads/ke_payload.c index 999d73192..53edaf4f4 100644 --- a/src/libcharon/encoding/payloads/ke_payload.c +++ b/src/libcharon/encoding/payloads/ke_payload.c @@ -67,15 +67,17 @@ struct private_ke_payload_t { * Key Exchange Data of this KE payload. */ chunk_t key_exchange_data; + + /** + * Payload type, KEY_EXCHANGE or KEY_EXCHANGE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a IKEv2-KE Payload. - * - * The defined offsets are the positions in a object of type - * private_ke_payload_t. + * Encoding rules for IKEv2 key exchange payload. */ -encoding_rule_t ke_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_ke_payload_t, next_payload) }, /* the critical bit */ @@ -96,7 +98,7 @@ encoding_rule_t ke_payload_encodings[] = { { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[0])}, { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[1])}, /* Key Exchange Data is from variable size */ - { KEY_EXCHANGE_DATA, offsetof(private_ke_payload_t, key_exchange_data)} + { KEY_EXCHANGE_DATA, offsetof(private_ke_payload_t, key_exchange_data)}, }; /* @@ -113,6 +115,30 @@ encoding_rule_t ke_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_ke_payload_t, next_payload) }, + /* Reserved Byte */ + { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[0])}, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_ke_payload_t, payload_length) }, + /* Key Exchange Data is from variable size */ + { KEY_EXCHANGE_DATA_V1, offsetof(private_ke_payload_t, key_exchange_data)}, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Key Exchange Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + METHOD(payload_t, verify, status_t, private_ke_payload_t *this) { @@ -122,14 +148,22 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, void, private_ke_payload_t *this, encoding_rule_t **rules, size_t *rule_count) { - *rules = ke_payload_encodings; - *rule_count = countof(ke_payload_encodings); + if (this->type == KEY_EXCHANGE) + { + *rules = encodings_v2; + *rule_count = countof(encodings_v2); + } + else + { + *rules = encodings_v1; + *rule_count = countof(encodings_v1); + } } METHOD(payload_t, get_type, payload_type_t, private_ke_payload_t *this) { - return KEY_EXCHANGE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -172,7 +206,7 @@ METHOD2(payload_t, ke_payload_t, destroy, void, /* * Described in header */ -ke_payload_t *ke_payload_create() +ke_payload_t *ke_payload_create(payload_type_t type) { private_ke_payload_t *this; @@ -194,20 +228,26 @@ ke_payload_t *ke_payload_create() .next_payload = NO_PAYLOAD, .payload_length = KE_PAYLOAD_HEADER_LENGTH, .dh_group_number = MODP_NONE, + .type = type, ); + if (type == KEY_EXCHANGE_V1) + { + this->payload_length = KE_PAYLOAD_V1_HEADER_LENGTH; + } return &this->public; } /* * Described in header */ -ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *dh) +ke_payload_t *ke_payload_create_from_diffie_hellman(payload_type_t type, + diffie_hellman_t *dh) { - private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create(); + private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create(type); dh->get_my_public_value(dh, &this->key_exchange_data); this->dh_group_number = dh->get_dh_group(dh); - this->payload_length = this->key_exchange_data.len + KE_PAYLOAD_HEADER_LENGTH; + this->payload_length += this->key_exchange_data.len; return &this->public; } diff --git a/src/libcharon/encoding/payloads/ke_payload.h b/src/libcharon/encoding/payloads/ke_payload.h index 65cc11883..c448ceff6 100644 --- a/src/libcharon/encoding/payloads/ke_payload.h +++ b/src/libcharon/encoding/payloads/ke_payload.h @@ -31,16 +31,20 @@ typedef struct ke_payload_t ke_payload_t; #include /** - * KE payload length in bytes without any key exchange data. + * KE payload length in bytes without any key exchange data (IKEv2). */ #define KE_PAYLOAD_HEADER_LENGTH 8 /** - * Class representing an IKEv2-KE Payload. - * - * The KE Payload format is described in RFC section 3.4. + * KE payload length in bytes without any key exchange data (IKEv1). + */ +#define KE_PAYLOAD_V1_HEADER_LENGTH 4 + +/** + * Class representing an IKEv1 or IKEv2 key exchange payload. */ struct ke_payload_t { + /** * The payload_t interface. */ @@ -54,32 +58,34 @@ struct ke_payload_t { chunk_t (*get_key_exchange_data) (ke_payload_t *this); /** - * Gets the Diffie-Hellman Group Number of this KE payload. + * Gets the Diffie-Hellman Group Number of this KE payload (IKEv2 only). * * @return DH Group Number of this payload */ diffie_hellman_group_t (*get_dh_group_number) (ke_payload_t *this); /** - * Destroys an ke_payload_t object. + * Destroys a ke_payload_t object. */ void (*destroy) (ke_payload_t *this); }; /** - * Creates an empty ke_payload_t object + * Creates an empty ke_payload_t object. * - * @return ke_payload_t object + * @param type KEY_EXCHANGE or KEY_EXCHANGE_V1 + * @return ke_payload_t object */ -ke_payload_t *ke_payload_create(void); +ke_payload_t *ke_payload_create(payload_type_t type); /** - * Creates a ke_payload_t from a diffie_hellman_t + * Creates a ke_payload_t from a diffie_hellman_t. * - * @param diffie_hellman diffie hellman object containing group and key - * @return ke_payload_t object + * @param type KEY_EXCHANGE or KEY_EXCHANGE_V1 + * @param dh diffie hellman object containing group and key + * @return ke_payload_t object */ -ke_payload_t *ke_payload_create_from_diffie_hellman( - diffie_hellman_t *diffie_hellman); +ke_payload_t *ke_payload_create_from_diffie_hellman(payload_type_t type, + diffie_hellman_t *dh); #endif /** KE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 56563acef..3e7c390e0 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -201,7 +201,8 @@ payload_t *payload_create(payload_type_t type) case TRAFFIC_SELECTOR_RESPONDER: return (payload_t*)ts_payload_create(FALSE); case KEY_EXCHANGE: - return (payload_t*)ke_payload_create(); + case KEY_EXCHANGE_V1: + return (payload_t*)ke_payload_create(type); case NOTIFY: return (payload_t*)notify_payload_create(); case DELETE: diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index 587e37aea..46382a2a0 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -547,7 +547,8 @@ static void build_payloads(private_child_create_t *this, message_t *message) /* diffie hellman exchange, if PFS enabled */ if (this->dh) { - ke_payload = ke_payload_create_from_diffie_hellman(this->dh); + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE, + this->dh); message->add_payload(message, (payload_t*)ke_payload); } diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/tasks/ike_init.c index e6f4237ce..aa514bffc 100644 --- a/src/libcharon/sa/tasks/ike_init.c +++ b/src/libcharon/sa/tasks/ike_init.c @@ -150,7 +150,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message) nonce_payload = nonce_payload_create(NONCE); nonce_payload->set_nonce(nonce_payload, this->my_nonce); - ke_payload = ke_payload_create_from_diffie_hellman(this->dh); + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE, this->dh); if (this->old_sa) { /* payload order differs if we are rekeying */ From e9b55b832546d05f464bdddbe779ed21cd17b624 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 11:27:55 +0100 Subject: [PATCH 033/534] Simplify signature of get_encoding_rules(), make all rules static --- src/conftest/hooks/set_length.c | 5 ++--- src/libcharon/encoding/generator.c | 5 ++--- src/libcharon/encoding/parser.c | 5 ++--- src/libcharon/encoding/payloads/auth_payload.c | 10 +++++----- src/libcharon/encoding/payloads/cert_payload.c | 10 +++++----- src/libcharon/encoding/payloads/certreq_payload.c | 10 +++++----- .../encoding/payloads/configuration_attribute.c | 11 +++++------ src/libcharon/encoding/payloads/cp_payload.c | 10 +++++----- src/libcharon/encoding/payloads/delete_payload.c | 10 +++++----- src/libcharon/encoding/payloads/eap_payload.c | 10 +++++----- .../encoding/payloads/encryption_payload.c | 11 +++++------ src/libcharon/encoding/payloads/id_payload.c | 10 +++++----- src/libcharon/encoding/payloads/ike_header.c | 10 +++++----- src/libcharon/encoding/payloads/ke_payload.c | 13 +++++-------- src/libcharon/encoding/payloads/nonce_payload.c | 10 +++++----- src/libcharon/encoding/payloads/notify_payload.c | 10 +++++----- src/libcharon/encoding/payloads/payload.c | 5 ++--- src/libcharon/encoding/payloads/payload.h | 6 +++--- .../encoding/payloads/proposal_substructure.c | 14 +++++--------- src/libcharon/encoding/payloads/sa_payload.c | 13 +++++-------- .../payloads/traffic_selector_substructure.c | 11 +++++------ .../encoding/payloads/transform_attribute.c | 7 +++---- .../encoding/payloads/transform_substructure.c | 14 +++++--------- src/libcharon/encoding/payloads/ts_payload.c | 10 +++++----- src/libcharon/encoding/payloads/unknown_payload.c | 10 +++++----- .../encoding/payloads/vendor_id_payload.c | 11 +++++------ 26 files changed, 114 insertions(+), 137 deletions(-) diff --git a/src/conftest/hooks/set_length.c b/src/conftest/hooks/set_length.c index 0379dcb7c..eb72e72d9 100644 --- a/src/conftest/hooks/set_length.c +++ b/src/conftest/hooks/set_length.c @@ -76,11 +76,10 @@ METHOD(listener_t, message, bool, if (type == payload->get_type(payload)) { encoding_rule_t *rules; - size_t count; u_int16_t *len; - int i; + int i, count; - payload->get_encoding_rules(payload, &rules, &count); + count = payload->get_encoding_rules(payload, &rules); for (i = 0; i < count; i++) { if (rules[i].type == PAYLOAD_LENGTH) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 662ebf977..5f1a5e8a4 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -404,8 +404,7 @@ METHOD(generator_t, get_chunk, chunk_t, METHOD(generator_t, generate_payload, void, private_generator_t *this,payload_t *payload) { - int i, offset_start; - size_t rule_count; + int i, offset_start, rule_count; encoding_rule_t *rules; payload_type_t payload_type; @@ -418,7 +417,7 @@ METHOD(generator_t, generate_payload, void, payload_type_names, payload_type); /* each payload has its own encoding rules */ - payload->get_encoding_rules(payload, &rules, &rule_count); + rule_count = payload->get_encoding_rules(payload, &rules); for (i = 0; i < rule_count;i++) { diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 86ab212b8..4736873a7 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -363,11 +363,10 @@ METHOD(parser_t, parse_payload, status_t, { payload_t *pld; void *output; - size_t rule_count; int payload_length = 0, spi_size = 0, attribute_length = 0; u_int16_t ts_type = 0; bool attribute_format = FALSE; - int rule_number; + int rule_number, rule_count; encoding_rule_t *rule; /* create instance of the payload to parse */ @@ -383,7 +382,7 @@ METHOD(parser_t, parse_payload, status_t, output = pld; /* parse the payload with its own rulse */ - pld->get_encoding_rules(pld, &this->rules, &rule_count); + rule_count = pld->get_encoding_rules(pld, &this->rules); for (rule_number = 0; rule_number < rule_count; rule_number++) { rule = &(this->rules[rule_number]); diff --git a/src/libcharon/encoding/payloads/auth_payload.c b/src/libcharon/encoding/payloads/auth_payload.c index cb44a997c..3825244e2 100644 --- a/src/libcharon/encoding/payloads/auth_payload.c +++ b/src/libcharon/encoding/payloads/auth_payload.c @@ -74,7 +74,7 @@ struct private_auth_payload_t { * The defined offsets are the positions in a object of type * private_auth_payload_t. */ -encoding_rule_t auth_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_auth_payload_t, next_payload) }, /* the critical bit */ @@ -119,11 +119,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_auth_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_auth_payload_t *this, encoding_rule_t **rules) { - *rules = auth_payload_encodings; - *rule_count = countof(auth_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c index c42cec680..8f6deb89c 100644 --- a/src/libcharon/encoding/payloads/cert_payload.c +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -95,7 +95,7 @@ struct private_cert_payload_t { * private_cert_payload_t. * */ -encoding_rule_t cert_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_cert_payload_t, next_payload) }, /* the critical bit */ @@ -166,11 +166,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_cert_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_cert_payload_t *this, encoding_rule_t **rules) { - *rules = cert_payload_encodings; - *rule_count = countof(cert_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c index 8e0836f0e..ec46e9277 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.c +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -72,7 +72,7 @@ struct private_certreq_payload_t { * The defined offsets are the positions in a object of type * private_certreq_payload_t. */ -encoding_rule_t certreq_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_certreq_payload_t, next_payload) }, /* the critical bit */ @@ -122,11 +122,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_certreq_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_certreq_payload_t *this, encoding_rule_t **rules) { - *rules = certreq_payload_encodings; - *rule_count = countof(certreq_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index e608497bd..a657ef13a 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -62,7 +62,7 @@ struct private_configuration_attribute_t { * The defined offsets are the positions in a object of type * private_configuration_attribute_t. */ -encoding_rule_t configuration_attribute_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 reserved bit */ { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved)}, /* type of the attribute as 15 bit unsigned integer */ @@ -154,12 +154,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_configuration_attribute_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_configuration_attribute_t *this, encoding_rule_t **rules) { - *rules = configuration_attribute_encodings; - *rule_count = countof(configuration_attribute_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c index 82e9e51b7..4e782dd88 100644 --- a/src/libcharon/encoding/payloads/cp_payload.c +++ b/src/libcharon/encoding/payloads/cp_payload.c @@ -83,7 +83,7 @@ struct private_cp_payload_t { * The defined offsets are the positions in a object of type * private_cp_payload_t. */ -encoding_rule_t cp_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, /* the critical bit */ @@ -142,11 +142,11 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_cp_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_cp_payload_t *this, encoding_rule_t **rules) { - *rules = cp_payload_encodings; - *rule_count = countof(cp_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index e6ee07d39..b396135be 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -79,7 +79,7 @@ struct private_delete_payload_t { * The defined offsets are the positions in a object of type * private_delete_payload_t. */ -encoding_rule_t delete_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, /* the critical bit */ @@ -145,11 +145,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_delete_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_delete_payload_t *this, encoding_rule_t **rules) { - *rules = delete_payload_encodings; - *rule_count = countof(delete_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_payload_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index cacaef222..581547499 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -65,7 +65,7 @@ struct private_eap_payload_t { * private_eap_payload_t. * */ -static encoding_rule_t eap_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_eap_payload_t, next_payload) }, /* the critical bit */ @@ -143,11 +143,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_eap_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_eap_payload_t *this, encoding_rule_t **rules) { - *rules = eap_payload_encodings; - *rule_count = sizeof(eap_payload_encodings) / sizeof(encoding_rule_t); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_payload_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c index e7b8063b7..b0b863b36 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.c +++ b/src/libcharon/encoding/payloads/encryption_payload.c @@ -79,7 +79,7 @@ struct private_encryption_payload_t { * The defined offsets are the positions in a object of type * private_encryption_payload_t. */ -encoding_rule_t encryption_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_encryption_payload_t, next_payload) }, /* Critical and 7 reserved bits, all stored for reconstruction */ @@ -115,12 +115,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_encryption_payload_t *this, encoding_rule_t **rules, - size_t *count) +METHOD(payload_t, get_encoding_rules, int, + private_encryption_payload_t *this, encoding_rule_t **rules) { - *rules = encryption_payload_encodings; - *count = countof(encryption_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index 3befadfe2..1d42f1595 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -83,7 +83,7 @@ struct private_id_payload_t { * The defined offsets are the positions in a object of type * private_id_payload_t. */ -encoding_rule_t id_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_id_payload_t, next_payload) }, /* the critical bit */ @@ -134,11 +134,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_id_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_id_payload_t *this, encoding_rule_t **rules) { - *rules = id_payload_encodings; - *rule_count = countof(id_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/ike_header.c b/src/libcharon/encoding/payloads/ike_header.c index 8f379442b..97c6d8c26 100644 --- a/src/libcharon/encoding/payloads/ike_header.c +++ b/src/libcharon/encoding/payloads/ike_header.c @@ -146,7 +146,7 @@ ENUM_END(exchange_type_names, EXCHANGE_TYPE_UNDEFINED); * The defined offsets are the positions in a object of type * ike_header_t. */ -encoding_rule_t ike_header_encodings[] = { +static encoding_rule_t encodings[] = { /* 8 Byte SPI, stored in the field initiator_spi */ { IKE_SPI, offsetof(private_ike_header_t, initiator_spi) }, /* 8 Byte SPI, stored in the field responder_spi */ @@ -244,11 +244,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_ike_header_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_ike_header_t *this, encoding_rule_t **rules) { - *rules = ike_header_encodings; - *rule_count = sizeof(ike_header_encodings) / sizeof(encoding_rule_t); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/ke_payload.c b/src/libcharon/encoding/payloads/ke_payload.c index 53edaf4f4..183e722a2 100644 --- a/src/libcharon/encoding/payloads/ke_payload.c +++ b/src/libcharon/encoding/payloads/ke_payload.c @@ -145,19 +145,16 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_ke_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_ke_payload_t *this, encoding_rule_t **rules) { if (this->type == KEY_EXCHANGE) { *rules = encodings_v2; - *rule_count = countof(encodings_v2); - } - else - { - *rules = encodings_v1; - *rule_count = countof(encodings_v1); + return countof(encodings_v2); } + *rules = encodings_v1; + return countof(encodings_v1); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/nonce_payload.c b/src/libcharon/encoding/payloads/nonce_payload.c index 684bddce4..86222c13a 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.c +++ b/src/libcharon/encoding/payloads/nonce_payload.c @@ -70,7 +70,7 @@ struct private_nonce_payload_t { * The defined offsets are the positions in a object of type * private_nonce_payload_t. */ -encoding_rule_t nonce_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_nonce_payload_t, next_payload) }, /* the critical bit */ @@ -110,11 +110,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_nonce_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_nonce_payload_t *this, encoding_rule_t **rules) { - *rules = nonce_payload_encodings; - *rule_count = countof(nonce_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index 5a47438ca..d8f45b9b4 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -263,7 +263,7 @@ struct private_notify_payload_t { * The defined offsets are the positions in a object of type * private_notify_payload_t. */ -encoding_rule_t notify_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, /* the critical bit */ @@ -423,11 +423,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_notify_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_notify_payload_t *this, encoding_rule_t **rules) { - *rules = notify_payload_encodings; - *rule_count = countof(notify_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 3e7c390e0..3882e00bf 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -255,10 +255,9 @@ bool payload_is_known(payload_type_t type) void* payload_get_field(payload_t *payload, encoding_type_t type, u_int skip) { encoding_rule_t *rule; - size_t count; - int i; + int i, count; - payload->get_encoding_rules(payload, &rule, &count); + count = payload->get_encoding_rules(payload, &rule); for (i = 0; i < count; i++) { if (rule[i].type == type && skip-- == 0) diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index 5e0b7dd38..963c5f090 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -271,10 +271,10 @@ struct payload_t { /** * Get encoding rules for this payload. * - * @param rules location to store pointer of first rule - * @param rule_count location to store number of rules + * @param rules location to store pointer to rules + * @return number of rules */ - void (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules, size_t *rule_count); + int (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules); /** * Get type of payload. diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 40caef858..3b663da86 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -296,20 +296,16 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_proposal_substructure_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_proposal_substructure_t *this, encoding_rule_t **rules) { if (this->type == PROPOSAL_SUBSTRUCTURE) { *rules = encodings_v2; - *rule_count = countof(encodings_v2); - } - else - { - *rules = encodings_v1; - *rule_count = countof(encodings_v1); + return countof(encodings_v2); } + *rules = encodings_v1; + return countof(encodings_v1); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 8f9dda411..32251e28b 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -202,19 +202,16 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_sa_payload_t *this, encoding_rule_t **rules) { if (this->type == SECURITY_ASSOCIATION_V1) { *rules = encodings_v1; - *rule_count = countof(encodings_v1); - } - else - { - *rules = encodings_v2; - *rule_count = countof(encodings_v2); + return countof(encodings_v1); } + *rules = encodings_v2; + return countof(encodings_v2); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.c b/src/libcharon/encoding/payloads/traffic_selector_substructure.c index df36e4383..c213441ab 100644 --- a/src/libcharon/encoding/payloads/traffic_selector_substructure.c +++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.c @@ -74,7 +74,7 @@ struct private_traffic_selector_substructure_t { * The defined offsets are the positions in a object of type * private_traffic_selector_substructure_t. */ -encoding_rule_t traffic_selector_substructure_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next ts type*/ { TS_TYPE, offsetof(private_traffic_selector_substructure_t, ts_type) }, /* 1 Byte IP protocol id*/ @@ -148,12 +148,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_traffic_selector_substructure_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_traffic_selector_substructure_t *this, encoding_rule_t **rules) { - *rules = traffic_selector_substructure_encodings; - *rule_count = countof(traffic_selector_substructure_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 97bde8bce..fa344019b 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -134,12 +134,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_transform_attribute_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_transform_attribute_t *this, encoding_rule_t **rules) { *rules = encodings; - *rule_count = countof(encodings); + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c index 54463cbc3..da022ca75 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.c +++ b/src/libcharon/encoding/payloads/transform_substructure.c @@ -162,20 +162,16 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_transform_substructure_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_transform_substructure_t *this, encoding_rule_t **rules) { if (this->type == TRANSFORM_ATTRIBUTE) { *rules = encodings_v2; - *rule_count = countof(encodings_v2); - } - else - { - *rules = encodings_v1; - *rule_count = countof(encodings_v1); + return countof(encodings_v2); } + *rules = encodings_v1; + return countof(encodings_v1); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/ts_payload.c b/src/libcharon/encoding/payloads/ts_payload.c index 28f760e40..8f4508a9c 100644 --- a/src/libcharon/encoding/payloads/ts_payload.c +++ b/src/libcharon/encoding/payloads/ts_payload.c @@ -81,7 +81,7 @@ struct private_ts_payload_t { * The defined offsets are the positions in a object of type * private_ts_payload_t. */ -encoding_rule_t ts_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_ts_payload_t, next_payload) }, /* the critical bit */ @@ -145,11 +145,11 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_ts_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_ts_payload_t *this, encoding_rule_t **rules) { - *rules = ts_payload_encodings; - *rule_count = countof(ts_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/unknown_payload.c b/src/libcharon/encoding/payloads/unknown_payload.c index 27af338b3..9f5c6ef98 100644 --- a/src/libcharon/encoding/payloads/unknown_payload.c +++ b/src/libcharon/encoding/payloads/unknown_payload.c @@ -68,7 +68,7 @@ struct private_unknown_payload_t { * private_unknown_payload_t. * */ -encoding_rule_t unknown_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_unknown_payload_t, next_payload) }, /* the critical bit */ @@ -109,11 +109,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_unknown_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_unknown_payload_t *this, encoding_rule_t **rules) { - *rules = unknown_payload_encodings; - *rule_count = sizeof(unknown_payload_encodings) / sizeof(encoding_rule_t); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_payload_type, payload_type_t, diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.c b/src/libcharon/encoding/payloads/vendor_id_payload.c index 3dab3941e..45669879b 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.c +++ b/src/libcharon/encoding/payloads/vendor_id_payload.c @@ -68,7 +68,7 @@ struct private_vendor_id_payload_t { * The defined offsets are the positions in a object of type * private_vendor_id_payload_t. */ -encoding_rule_t vendor_id_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_vendor_id_payload_t, next_payload) }, /* the critical bit */ @@ -105,12 +105,11 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_vendor_id_payload_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_vendor_id_payload_t *this, encoding_rule_t **rules) { - *rules = vendor_id_payload_encodings; - *rule_count = countof(vendor_id_payload_encodings); + *rules = encodings; + return countof(encodings); } METHOD(payload_t, get_type, payload_type_t, From 38fb67fbf18489f40845b072e4ed50b1f6cf0c9c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 11:27:46 +0000 Subject: [PATCH 034/534] Add a payload.get_header_length() method, remove header length definitions --- src/conftest/hooks/ike_auth_fill.c | 5 +- src/libcharon/encoding/parser.c | 287 ++++-------------- .../encoding/payloads/auth_payload.c | 11 +- .../encoding/payloads/auth_payload.h | 5 - .../encoding/payloads/cert_payload.c | 15 +- .../encoding/payloads/cert_payload.h | 5 - .../encoding/payloads/certreq_payload.c | 9 +- .../encoding/payloads/certreq_payload.h | 5 - .../payloads/configuration_attribute.c | 9 +- .../payloads/configuration_attribute.h | 5 - src/libcharon/encoding/payloads/cp_payload.c | 11 +- src/libcharon/encoding/payloads/cp_payload.h | 5 - .../encoding/payloads/delete_payload.c | 9 +- .../encoding/payloads/delete_payload.h | 5 - src/libcharon/encoding/payloads/eap_payload.c | 9 +- src/libcharon/encoding/payloads/eap_payload.h | 5 - .../encoding/payloads/encryption_payload.c | 11 +- .../encoding/payloads/encryption_payload.h | 5 - src/libcharon/encoding/payloads/id_payload.c | 9 +- src/libcharon/encoding/payloads/id_payload.h | 5 - src/libcharon/encoding/payloads/ike_header.c | 7 + src/libcharon/encoding/payloads/ke_payload.c | 17 +- src/libcharon/encoding/payloads/ke_payload.h | 10 - .../encoding/payloads/nonce_payload.c | 11 +- .../encoding/payloads/nonce_payload.h | 5 - .../encoding/payloads/notify_payload.c | 23 +- .../encoding/payloads/notify_payload.h | 5 - src/libcharon/encoding/payloads/payload.h | 7 + .../encoding/payloads/proposal_substructure.c | 11 +- .../encoding/payloads/proposal_substructure.h | 6 - src/libcharon/encoding/payloads/sa_payload.c | 21 +- src/libcharon/encoding/payloads/sa_payload.h | 10 - .../payloads/traffic_selector_substructure.c | 11 +- .../payloads/traffic_selector_substructure.h | 5 - .../encoding/payloads/transform_attribute.c | 7 + .../payloads/transform_substructure.c | 11 +- .../payloads/transform_substructure.h | 5 - src/libcharon/encoding/payloads/ts_payload.c | 11 +- src/libcharon/encoding/payloads/ts_payload.h | 5 - .../encoding/payloads/unknown_payload.c | 15 +- .../encoding/payloads/unknown_payload.h | 5 - .../encoding/payloads/vendor_id_payload.c | 9 +- .../encoding/payloads/vendor_id_payload.h | 5 - src/libcharon/network/receiver.c | 2 + 44 files changed, 257 insertions(+), 397 deletions(-) diff --git a/src/conftest/hooks/ike_auth_fill.c b/src/conftest/hooks/ike_auth_fill.c index 2843d60c1..052a4be08 100644 --- a/src/conftest/hooks/ike_auth_fill.c +++ b/src/conftest/hooks/ike_auth_fill.c @@ -51,7 +51,10 @@ struct private_ike_auth_fill_t { /** size of non ESP-Marker */ #define NON_ESP_MARKER_LEN 4 - +/** length of fixed encryption payload header */ +#define ENCRYPTION_PAYLOAD_HEADER_LENGTH 4 +/** length of fixed cert payload header */ +#define CERT_PAYLOAD_HEADER_LENGTH 5 /** * Calculate packet size on wire (without ethernet/IP header) */ diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 4736873a7..719c94254 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -358,12 +358,40 @@ static bool parse_chunk(private_parser_t *this, int rule_number, return TRUE; } +/** + * Map a encoding type to a encoded payload + */ +static payload_type_t map_wrapped_payload(encoding_type_t type) +{ + switch (type) + { + case PROPOSALS: + return PROPOSAL_SUBSTRUCTURE; + case PROPOSALS_V1: + return PROPOSAL_SUBSTRUCTURE_V1; + case TRANSFORMS: + return TRANSFORM_SUBSTRUCTURE; + case TRANSFORMS_V1: + return TRANSFORM_SUBSTRUCTURE_V1; + case TRANSFORM_ATTRIBUTES: + return TRANSFORM_ATTRIBUTE; + case TRANSFORM_ATTRIBUTES_V1: + return TRANSFORM_ATTRIBUTE_V1; + case CONFIGURATION_ATTRIBUTES: + return CONFIGURATION_ATTRIBUTE; + case TRAFFIC_SELECTORS: + return TRAFFIC_SELECTOR_SUBSTRUCTURE; + default: + return NO_PAYLOAD; + } +} + METHOD(parser_t, parse_payload, status_t, private_parser_t *this, payload_type_t payload_type, payload_t **payload) { payload_t *pld; void *output; - int payload_length = 0, spi_size = 0, attribute_length = 0; + int payload_length = 0, spi_size = 0, attribute_length = 0, header_length; u_int16_t ts_type = 0; bool attribute_format = FALSE; int rule_number, rule_count; @@ -381,6 +409,7 @@ METHOD(parser_t, parse_payload, status_t, /* base pointer for output, avoids casting in every rule */ output = pld; + header_length = pld->get_header_length(pld); /* parse the payload with its own rulse */ rule_count = pld->get_encoding_rules(pld, &this->rules); for (rule_number = 0; rule_number < rule_count; rule_number++) @@ -456,7 +485,8 @@ METHOD(parser_t, parse_payload, status_t, } /* parsed u_int16 should be aligned */ payload_length = *(u_int16_t*)(output + rule->offset); - if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH) + /* all payloads must have at least 4 bytes header */ + if (payload_length < 4) { pld->destroy(pld); return PARSE_ERROR; @@ -483,86 +513,44 @@ METHOD(parser_t, parse_payload, status_t, } break; } + /* lists */ case PROPOSALS: - { - if (payload_length < SA_PAYLOAD_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - PROPOSAL_SUBSTRUCTURE, - payload_length - SA_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } case PROPOSALS_V1: - { - if (payload_length < SA_PAYLOAD_V1_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - PROPOSAL_SUBSTRUCTURE_V1, - payload_length - SA_PAYLOAD_V1_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } case TRANSFORMS: - { - if (payload_length < - spi_size + PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRANSFORM_SUBSTRUCTURE, payload_length - spi_size - - PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } case TRANSFORMS_V1: - { - if (payload_length < - spi_size + PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRANSFORM_SUBSTRUCTURE_V1, payload_length - spi_size - - PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } case TRANSFORM_ATTRIBUTES: - { - if (payload_length < TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRANSFORM_ATTRIBUTE, - payload_length - TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } case TRANSFORM_ATTRIBUTES_V1: + case TRAFFIC_SELECTORS: { - if (payload_length < TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH || + if (payload_length < header_length || !parse_list(this, rule_number, output + rule->offset, - TRANSFORM_ATTRIBUTE_V1, - payload_length - TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH)) + map_wrapped_payload(rule->type), + payload_length - header_length)) { pld->destroy(pld); return PARSE_ERROR; } break; } - case CONFIGURATION_ATTRIBUTES: + /* chunks */ + case NONCE_DATA: + case ID_DATA: + case AUTH_DATA: + case CERT_DATA: + case CERTREQ_DATA: + case EAP_DATA: + case SPIS: + case VID_DATA: + case CONFIGURATION_ATTRIBUTE_VALUE: + case KEY_EXCHANGE_DATA: + case KEY_EXCHANGE_DATA_V1: + case NOTIFICATION_DATA: + case ENCRYPTED_DATA: + case UNKNOWN_DATA: { - if (payload_length < CP_PAYLOAD_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - CONFIGURATION_ATTRIBUTE, - payload_length - CP_PAYLOAD_HEADER_LENGTH)) + if (payload_length < header_length || + !parse_chunk(this, rule_number, output + rule->offset, + payload_length - header_length)) { pld->destroy(pld); return PARSE_ERROR; @@ -619,148 +607,6 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case NONCE_DATA: - { - if (payload_length < NONCE_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - NONCE_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case ID_DATA: - { - if (payload_length < ID_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - ID_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case AUTH_DATA: - { - if (payload_length < AUTH_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - AUTH_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case CERT_DATA: - { - if (payload_length < CERT_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - CERT_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case CERTREQ_DATA: - { - if (payload_length < CERTREQ_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - CERTREQ_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case EAP_DATA: - { - if (payload_length < EAP_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - EAP_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case SPIS: - { - if (payload_length < DELETE_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - DELETE_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case VID_DATA: - { - if (payload_length < VENDOR_ID_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - VENDOR_ID_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case CONFIGURATION_ATTRIBUTE_VALUE: - { - if (!parse_chunk(this, rule_number, output + rule->offset, - attribute_length)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case KEY_EXCHANGE_DATA: - { - if (payload_length < KE_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - KE_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case KEY_EXCHANGE_DATA_V1: - { - if (payload_length < KE_PAYLOAD_V1_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - KE_PAYLOAD_V1_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case NOTIFICATION_DATA: - { - if (payload_length < NOTIFY_PAYLOAD_HEADER_LENGTH + spi_size || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - NOTIFY_PAYLOAD_HEADER_LENGTH - spi_size)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case ENCRYPTED_DATA: - { - if (payload_length < ENCRYPTION_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - ENCRYPTION_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } case TS_TYPE: { if (!parse_uint8(this, rule_number, output + rule->offset)) @@ -783,29 +629,6 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case TRAFFIC_SELECTORS: - { - if (payload_length < TS_PAYLOAD_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRAFFIC_SELECTOR_SUBSTRUCTURE, - payload_length - TS_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case UNKNOWN_DATA: - { - if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - UNKNOWN_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } default: { DBG1(DBG_ENC, " no rule to parse rule %d %N", diff --git a/src/libcharon/encoding/payloads/auth_payload.c b/src/libcharon/encoding/payloads/auth_payload.c index 3825244e2..57dc58f2a 100644 --- a/src/libcharon/encoding/payloads/auth_payload.c +++ b/src/libcharon/encoding/payloads/auth_payload.c @@ -126,6 +126,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_auth_payload_t *this) +{ + return 8; +} + METHOD(payload_t, get_type, payload_type_t, private_auth_payload_t *this) { @@ -167,7 +173,7 @@ METHOD(auth_payload_t, set_data, void, { free(this->auth_data.ptr); this->auth_data = chunk_clone(data); - this->payload_length = AUTH_PAYLOAD_HEADER_LENGTH + this->auth_data.len; + this->payload_length = get_header_length(this) + this->auth_data.len; } METHOD(auth_payload_t, get_data, chunk_t, @@ -195,6 +201,7 @@ auth_payload_t *auth_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -208,7 +215,7 @@ auth_payload_t *auth_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = AUTH_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/auth_payload.h b/src/libcharon/encoding/payloads/auth_payload.h index e4c4e6ae3..521fe1d19 100644 --- a/src/libcharon/encoding/payloads/auth_payload.h +++ b/src/libcharon/encoding/payloads/auth_payload.h @@ -28,11 +28,6 @@ typedef struct auth_payload_t auth_payload_t; #include #include -/** - * Length of a auth payload without the auth data in bytes. - */ -#define AUTH_PAYLOAD_HEADER_LENGTH 8 - /** * Class representing an IKEv2 AUTH payload. * diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c index 8f6deb89c..565be7f34 100644 --- a/src/libcharon/encoding/payloads/cert_payload.c +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -173,6 +173,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_cert_payload_t *this) +{ + return 5; +} + METHOD(payload_t, get_type, payload_type_t, private_cert_payload_t *this) { @@ -270,6 +276,7 @@ cert_payload_t *cert_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -283,7 +290,7 @@ cert_payload_t *cert_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = CERT_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), ); return &this->public; } @@ -312,7 +319,7 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) free(this); return NULL; } - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + this->payload_length = get_header_length(this) + this->data.len; return &this->public; } @@ -325,7 +332,7 @@ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url) this->encoding = ENC_X509_HASH_AND_URL; this->data = chunk_cat("cc", hash, chunk_create(url, strlen(url))); - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + this->payload_length = get_header_length(this) + this->data.len; return &this->public; } @@ -338,6 +345,6 @@ cert_payload_t *cert_payload_create_custom(cert_encoding_t type, chunk_t data) this->encoding = type; this->data = data; - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + this->payload_length = get_header_length(this) + this->data.len; return &this->public; } diff --git a/src/libcharon/encoding/payloads/cert_payload.h b/src/libcharon/encoding/payloads/cert_payload.h index 21b503a40..6eb79c8ed 100644 --- a/src/libcharon/encoding/payloads/cert_payload.h +++ b/src/libcharon/encoding/payloads/cert_payload.h @@ -30,11 +30,6 @@ typedef enum cert_encoding_t cert_encoding_t; #include #include -/** - * Length of a cert payload without the cert data in bytes. - */ -#define CERT_PAYLOAD_HEADER_LENGTH 5 - /** * Certifcate encodings, as in RFC4306 */ diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c index ec46e9277..dc685e651 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.c +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -129,6 +129,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_certreq_payload_t *this) +{ + return 5; +} + METHOD(payload_t, get_type, payload_type_t, private_certreq_payload_t *this) { @@ -241,6 +247,7 @@ certreq_payload_t *certreq_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -253,7 +260,7 @@ certreq_payload_t *certreq_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = CERTREQ_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h index 914063628..421ad6d58 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.h +++ b/src/libcharon/encoding/payloads/certreq_payload.h @@ -28,11 +28,6 @@ typedef struct certreq_payload_t certreq_payload_t; #include #include -/** - * Length of a CERTREQ payload without the CERTREQ data in bytes. - */ -#define CERTREQ_PAYLOAD_HEADER_LENGTH 5 - /** * Class representing an IKEv2 CERTREQ payload. * diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index a657ef13a..8746b9b9e 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -161,6 +161,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_configuration_attribute_t *this) +{ + return 4; +} + METHOD(payload_t, get_type, payload_type_t, private_configuration_attribute_t *this) { @@ -181,7 +187,7 @@ METHOD(payload_t, set_next_type, void, METHOD(payload_t, get_length, size_t, private_configuration_attribute_t *this) { - return this->value.len + CONFIGURATION_ATTRIBUTE_HEADER_LENGTH; + return get_header_length(this) + this->value.len; } METHOD(configuration_attribute_t, get_cattr_type, configuration_attribute_type_t, @@ -215,6 +221,7 @@ configuration_attribute_t *configuration_attribute_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, diff --git a/src/libcharon/encoding/payloads/configuration_attribute.h b/src/libcharon/encoding/payloads/configuration_attribute.h index 6e4b018bb..e216ee366 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.h +++ b/src/libcharon/encoding/payloads/configuration_attribute.h @@ -28,11 +28,6 @@ typedef struct configuration_attribute_t configuration_attribute_t; #include #include -/** - * Configuration attribute header length in bytes. - */ -#define CONFIGURATION_ATTRIBUTE_HEADER_LENGTH 4 - /** * Class representing an IKEv2-CONFIGURATION Attribute. * diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c index 4e782dd88..05f16c33f 100644 --- a/src/libcharon/encoding/payloads/cp_payload.c +++ b/src/libcharon/encoding/payloads/cp_payload.c @@ -149,6 +149,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_cp_payload_t *this) +{ + return 8; +} + METHOD(payload_t, get_type, payload_type_t, private_cp_payload_t *this) { @@ -175,7 +181,7 @@ static void compute_length(private_cp_payload_t *this) enumerator_t *enumerator; payload_t *attribute; - this->payload_length = CP_PAYLOAD_HEADER_LENGTH; + this->payload_length = get_header_length(this); enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attribute)) @@ -230,6 +236,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -242,7 +249,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = CP_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .attributes = linked_list_create(), .type = type, ); diff --git a/src/libcharon/encoding/payloads/cp_payload.h b/src/libcharon/encoding/payloads/cp_payload.h index afae6091a..bc6bdee50 100644 --- a/src/libcharon/encoding/payloads/cp_payload.h +++ b/src/libcharon/encoding/payloads/cp_payload.h @@ -30,11 +30,6 @@ typedef struct cp_payload_t cp_payload_t; #include #include -/** - * CP_PAYLOAD length in bytes without any proposal substructure. - */ -#define CP_PAYLOAD_HEADER_LENGTH 8 - /** * Config Type of an Configuration Payload. */ diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index b396135be..5f0af8c86 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -152,6 +152,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_delete_payload_t *this) +{ + return 8; +} + METHOD(payload_t, get_payload_type, payload_type_t, private_delete_payload_t *this) { @@ -258,6 +264,7 @@ delete_payload_t *delete_payload_create(protocol_id_t protocol_id) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -270,7 +277,7 @@ delete_payload_t *delete_payload_create(protocol_id_t protocol_id) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = DELETE_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .protocol_id = protocol_id, .spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0, ); diff --git a/src/libcharon/encoding/payloads/delete_payload.h b/src/libcharon/encoding/payloads/delete_payload.h index 026829f97..ebafe04fb 100644 --- a/src/libcharon/encoding/payloads/delete_payload.h +++ b/src/libcharon/encoding/payloads/delete_payload.h @@ -28,11 +28,6 @@ typedef struct delete_payload_t delete_payload_t; #include #include -/** - * Length of a delete payload without the SPI in bytes. - */ -#define DELETE_PAYLOAD_HEADER_LENGTH 8 - /** * Class representing an IKEv2 DELETE payload. * diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index 581547499..47a9b1673 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -150,6 +150,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_eap_payload_t *this) +{ + return 4; +} + METHOD(payload_t, get_payload_type, payload_type_t, private_eap_payload_t *this) { @@ -251,6 +257,7 @@ eap_payload_t *eap_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -265,7 +272,7 @@ eap_payload_t *eap_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = EAP_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h index 60d9c99d2..e63db7d88 100644 --- a/src/libcharon/encoding/payloads/eap_payload.h +++ b/src/libcharon/encoding/payloads/eap_payload.h @@ -28,11 +28,6 @@ typedef struct eap_payload_t eap_payload_t; #include #include -/** - * Length of a EAP payload without the EAP Message in bytes. - */ -#define EAP_PAYLOAD_HEADER_LENGTH 4 - /** * Class representing an IKEv2 EAP payload. * diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c index b0b863b36..08c64fb51 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.c +++ b/src/libcharon/encoding/payloads/encryption_payload.c @@ -122,6 +122,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_encryption_payload_t *this) +{ + return 4; +} + METHOD(payload_t, get_type, payload_type_t, private_encryption_payload_t *this) { @@ -173,7 +179,7 @@ static void compute_length(private_encryption_payload_t *this) length += this->aead->get_icv_size(this->aead); } } - length += ENCRYPTION_PAYLOAD_HEADER_LENGTH; + length += get_header_length(this); this->payload_length = length; } @@ -463,6 +469,7 @@ encryption_payload_t *encryption_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -478,7 +485,7 @@ encryption_payload_t *encryption_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = ENCRYPTION_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .payloads = linked_list_create(), ); diff --git a/src/libcharon/encoding/payloads/encryption_payload.h b/src/libcharon/encoding/payloads/encryption_payload.h index e99c42fb7..3cdc54b37 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.h +++ b/src/libcharon/encoding/payloads/encryption_payload.h @@ -29,11 +29,6 @@ typedef struct encryption_payload_t encryption_payload_t; #include #include -/** - * Encrpytion payload length in bytes without IV and following data. - */ -#define ENCRYPTION_PAYLOAD_HEADER_LENGTH 4 - /** * The encryption payload as described in RFC section 3.14. */ diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index 1d42f1595..b94c72b60 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -141,6 +141,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_id_payload_t *this) +{ + return 8; +} + METHOD(payload_t, get_type, payload_type_t, private_id_payload_t *this) { @@ -190,6 +196,7 @@ id_payload_t *id_payload_create(payload_type_t payload_type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -200,7 +207,7 @@ id_payload_t *id_payload_create(payload_type_t payload_type) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = ID_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .payload_type = payload_type, ); return &this->public; diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h index 99831f85f..c24b8ffc6 100644 --- a/src/libcharon/encoding/payloads/id_payload.h +++ b/src/libcharon/encoding/payloads/id_payload.h @@ -29,11 +29,6 @@ typedef struct id_payload_t id_payload_t; #include #include -/** - * Length of a id payload without the data in bytes. - */ -#define ID_PAYLOAD_HEADER_LENGTH 8 - /** * Object representing an IKEv2 ID payload. * diff --git a/src/libcharon/encoding/payloads/ike_header.c b/src/libcharon/encoding/payloads/ike_header.c index 97c6d8c26..54e04658c 100644 --- a/src/libcharon/encoding/payloads/ike_header.c +++ b/src/libcharon/encoding/payloads/ike_header.c @@ -251,6 +251,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_ike_header_t *this) +{ + return IKE_HEADER_LENGTH; +} + METHOD(payload_t, get_type, payload_type_t, private_ike_header_t *this) { @@ -438,6 +444,7 @@ ike_header_t *ike_header_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, diff --git a/src/libcharon/encoding/payloads/ke_payload.c b/src/libcharon/encoding/payloads/ke_payload.c index 183e722a2..a6e5217aa 100644 --- a/src/libcharon/encoding/payloads/ke_payload.c +++ b/src/libcharon/encoding/payloads/ke_payload.c @@ -157,6 +157,16 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings_v1); } +METHOD(payload_t, get_header_length, int, + private_ke_payload_t *this) +{ + if (this->type == KEY_EXCHANGE) + { + return 8; + } + return 4; +} + METHOD(payload_t, get_type, payload_type_t, private_ke_payload_t *this) { @@ -212,6 +222,7 @@ ke_payload_t *ke_payload_create(payload_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -223,14 +234,10 @@ ke_payload_t *ke_payload_create(payload_type_t type) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = KE_PAYLOAD_HEADER_LENGTH, .dh_group_number = MODP_NONE, .type = type, ); - if (type == KEY_EXCHANGE_V1) - { - this->payload_length = KE_PAYLOAD_V1_HEADER_LENGTH; - } + this->payload_length = get_header_length(this); return &this->public; } diff --git a/src/libcharon/encoding/payloads/ke_payload.h b/src/libcharon/encoding/payloads/ke_payload.h index c448ceff6..5942954d9 100644 --- a/src/libcharon/encoding/payloads/ke_payload.h +++ b/src/libcharon/encoding/payloads/ke_payload.h @@ -30,16 +30,6 @@ typedef struct ke_payload_t ke_payload_t; #include #include -/** - * KE payload length in bytes without any key exchange data (IKEv2). - */ -#define KE_PAYLOAD_HEADER_LENGTH 8 - -/** - * KE payload length in bytes without any key exchange data (IKEv1). - */ -#define KE_PAYLOAD_V1_HEADER_LENGTH 4 - /** * Class representing an IKEv1 or IKEv2 key exchange payload. */ diff --git a/src/libcharon/encoding/payloads/nonce_payload.c b/src/libcharon/encoding/payloads/nonce_payload.c index 86222c13a..1e0cf5579 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.c +++ b/src/libcharon/encoding/payloads/nonce_payload.c @@ -117,6 +117,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_nonce_payload_t *this) +{ + return 4; +} + METHOD(payload_t, get_type, payload_type_t, private_nonce_payload_t *this) { @@ -145,7 +151,7 @@ METHOD(nonce_payload_t, set_nonce, void, private_nonce_payload_t *this, chunk_t nonce) { this->nonce = chunk_clone(nonce); - this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + nonce.len; + this->payload_length = get_header_length(this) + nonce.len; } METHOD(nonce_payload_t, get_nonce, chunk_t, @@ -173,6 +179,7 @@ nonce_payload_t *nonce_payload_create(payload_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -184,7 +191,7 @@ nonce_payload_t *nonce_payload_create(payload_type_t type) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = NONCE_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .type = type, ); return &this->public; diff --git a/src/libcharon/encoding/payloads/nonce_payload.h b/src/libcharon/encoding/payloads/nonce_payload.h index 3be2e2e13..5c47f5f9f 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.h +++ b/src/libcharon/encoding/payloads/nonce_payload.h @@ -32,11 +32,6 @@ typedef struct nonce_payload_t nonce_payload_t; */ #define NONCE_SIZE 32 -/** - * Length of a nonce payload without a nonce in bytes. - */ -#define NONCE_PAYLOAD_HEADER_LENGTH 4 - /** * Object representing an IKEv1/IKEv2 Nonce payload. */ diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index d8f45b9b4..f2e1267c6 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -430,6 +430,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_notify_payload_t *this) +{ + return 8 + this->spi_size; +} + METHOD(payload_t, get_type, payload_type_t, private_notify_payload_t *this) { @@ -451,19 +457,9 @@ METHOD(payload_t, set_next_type, void, /** * recompute the payloads length. */ -static void compute_length (private_notify_payload_t *this) +static void compute_length(private_notify_payload_t *this) { - size_t length = NOTIFY_PAYLOAD_HEADER_LENGTH; - - if (this->notification_data.ptr != NULL) - { - length += this->notification_data.len; - } - if (this->spi.ptr != NULL) - { - length += this->spi.len; - } - this->payload_length = length; + this->payload_length = get_header_length(this) + this->notification_data.len; } METHOD(payload_t, get_length, size_t, @@ -565,6 +561,7 @@ notify_payload_t *notify_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -582,8 +579,8 @@ notify_payload_t *notify_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH, ); + compute_length(this); return &this->public; } diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index 35feb4871..91a3cac0f 100644 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -32,11 +32,6 @@ typedef struct notify_payload_t notify_payload_t; #include #include -/** - * Notify payload length in bytes without any spi and notification data. - */ -#define NOTIFY_PAYLOAD_HEADER_LENGTH 8 - /** * Notify message types. * diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index 963c5f090..0060e3730 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -276,6 +276,13 @@ struct payload_t { */ int (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules); + /** + * Get non-variable header length for a variable length payload. + * + * @return fixed length of the payload + */ + int (*get_header_length)(payload_t *this); + /** * Get type of payload. * diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 3b663da86..16d5794ae 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -308,6 +308,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings_v1); } +METHOD(payload_t, get_header_length, int, + private_proposal_substructure_t *this) +{ + return 8 + this->spi_size; +} + METHOD(payload_t, get_type, payload_type_t, private_proposal_substructure_t *this) { @@ -334,7 +340,7 @@ static void compute_length(private_proposal_substructure_t *this) payload_t *transform; this->transforms_count = 0; - this->proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH + this->spi.len; + this->proposal_length = get_header_length(this); enumerator = this->transforms->create_enumerator(this->transforms); while (enumerator->enumerate(enumerator, &transform)) { @@ -692,6 +698,7 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -710,10 +717,10 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH, .transforms = linked_list_create(), .type = type, ); + compute_length(this); return &this->public; } diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index 86ccd5b8b..72bbdd64f 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -30,12 +30,6 @@ typedef struct proposal_substructure_t proposal_substructure_t; #include #include - -/** - * Length of the proposal substructure header (without spi). - */ -#define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8 - /** * Class representing an IKEv1/IKEv2 proposal substructure. */ diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 32251e28b..66e994b43 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -214,6 +214,16 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings_v2); } +METHOD(payload_t, get_header_length, int, + private_sa_payload_t *this) +{ + if (this->type == SECURITY_ASSOCIATION_V1) + { + return 12; + } + return 4; +} + METHOD(payload_t, get_type, payload_type_t, private_sa_payload_t *this) { @@ -239,21 +249,15 @@ static void compute_length(private_sa_payload_t *this) { enumerator_t *enumerator; payload_t *current; - size_t length = SA_PAYLOAD_HEADER_LENGTH; - if (this->type == SECURITY_ASSOCIATION_V1) - { - length = SA_PAYLOAD_V1_HEADER_LENGTH; - } + this->payload_length = get_header_length(this); enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, (void **)¤t)) { - length += current->get_length(current); + this->payload_length += current->get_length(current); } enumerator->destroy(enumerator); - - this->payload_length = length; } METHOD(payload_t, get_length, size_t, @@ -367,6 +371,7 @@ sa_payload_t *sa_payload_create(payload_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h index 11fc774e5..16d462e65 100644 --- a/src/libcharon/encoding/payloads/sa_payload.h +++ b/src/libcharon/encoding/payloads/sa_payload.h @@ -29,16 +29,6 @@ typedef struct sa_payload_t sa_payload_t; #include #include -/** - * SECURITY_ASSOCIATION length in bytes without any proposal substructure. - */ -#define SA_PAYLOAD_HEADER_LENGTH 4 - -/** - * SECURITY_ASSOCIATION_V1 length in bytes without any proposal substructure. - */ -#define SA_PAYLOAD_V1_HEADER_LENGTH 12 - /** * Class representing an IKEv1 or IKEv2 SA Payload. * diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.c b/src/libcharon/encoding/payloads/traffic_selector_substructure.c index c213441ab..378f5bbc3 100644 --- a/src/libcharon/encoding/payloads/traffic_selector_substructure.c +++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.c @@ -155,6 +155,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_traffic_selector_substructure_t *this) +{ + return 8; +} + METHOD(payload_t, get_type, payload_type_t, private_traffic_selector_substructure_t *this) { @@ -207,6 +213,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -216,7 +223,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create() .get_traffic_selector = _get_traffic_selector, .destroy = _destroy, }, - .payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH, + .payload_length = get_header_length(this), /* must be set to be valid */ .ts_type = TS_IPV4_ADDR_RANGE, ); @@ -238,7 +245,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create_from_traff this->end_port = ts->get_to_port(ts); this->starting_address = chunk_clone(ts->get_from_address(ts)); this->ending_address = chunk_clone(ts->get_to_address(ts)); - this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH + + this->payload_length = get_header_length(this) + this->ending_address.len + this->starting_address.len; return &this->public; diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.h b/src/libcharon/encoding/payloads/traffic_selector_substructure.h index 0109fd7f5..1ad5fb526 100644 --- a/src/libcharon/encoding/payloads/traffic_selector_substructure.h +++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.h @@ -29,11 +29,6 @@ typedef struct traffic_selector_substructure_t traffic_selector_substructure_t; #include #include -/** - * Length of a TRAFFIC SELECTOR SUBSTRUCTURE without start and end address. - */ -#define TRAFFIC_SELECTOR_HEADER_LENGTH 8 - /** * Class representing an IKEv2 TRAFFIC SELECTOR. * diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index fa344019b..474362fca 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -141,6 +141,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_transform_attribute_t *this) +{ + return 0; +} + METHOD(payload_t, get_type, payload_type_t, private_transform_attribute_t *this) { @@ -258,6 +264,7 @@ transform_attribute_t *transform_attribute_create(payload_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c index da022ca75..63464e9f3 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.c +++ b/src/libcharon/encoding/payloads/transform_substructure.c @@ -174,6 +174,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings_v1); } +METHOD(payload_t, get_header_length, int, + private_transform_substructure_t *this) +{ + return 8; +} + METHOD(payload_t, get_type, payload_type_t, private_transform_substructure_t *this) { @@ -194,7 +200,7 @@ static void compute_length(private_transform_substructure_t *this) enumerator_t *enumerator; payload_t *attribute; - this->transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH; + this->transform_length = get_header_length(this); enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attribute)) { @@ -269,6 +275,7 @@ transform_substructure_t *transform_substructure_create(payload_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -283,7 +290,7 @@ transform_substructure_t *transform_substructure_create(payload_type_t type) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH, + .transform_length = get_header_length(this), .attributes = linked_list_create(), .type = type, ); diff --git a/src/libcharon/encoding/payloads/transform_substructure.h b/src/libcharon/encoding/payloads/transform_substructure.h index 7b1071275..947df24f9 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.h +++ b/src/libcharon/encoding/payloads/transform_substructure.h @@ -39,11 +39,6 @@ typedef struct transform_substructure_t transform_substructure_t; */ #define TRANSFORM_TYPE_VALUE 3 -/** - * Length of the transform substructure header in bytes. - */ -#define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8 - /** * Class representing an IKEv1/IKEv2 transform substructure. */ diff --git a/src/libcharon/encoding/payloads/ts_payload.c b/src/libcharon/encoding/payloads/ts_payload.c index 8f4508a9c..df47b8892 100644 --- a/src/libcharon/encoding/payloads/ts_payload.c +++ b/src/libcharon/encoding/payloads/ts_payload.c @@ -152,6 +152,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_ts_payload_t *this) +{ + return 8; +} + METHOD(payload_t, get_type, payload_type_t, private_ts_payload_t *this) { @@ -182,7 +188,7 @@ static void compute_length(private_ts_payload_t *this) enumerator_t *enumerator; payload_t *subst; - this->payload_length = TS_PAYLOAD_HEADER_LENGTH; + this->payload_length = get_header_length(this); this->ts_num = 0; enumerator = this->substrs->create_enumerator(this->substrs); while (enumerator->enumerate(enumerator, &subst)) @@ -250,6 +256,7 @@ ts_payload_t *ts_payload_create(bool is_initiator) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -262,7 +269,7 @@ ts_payload_t *ts_payload_create(bool is_initiator) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = TS_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .is_initiator = is_initiator, .substrs = linked_list_create(), ); diff --git a/src/libcharon/encoding/payloads/ts_payload.h b/src/libcharon/encoding/payloads/ts_payload.h index 88ca00bc9..5a92655dc 100644 --- a/src/libcharon/encoding/payloads/ts_payload.h +++ b/src/libcharon/encoding/payloads/ts_payload.h @@ -30,11 +30,6 @@ typedef struct ts_payload_t ts_payload_t; #include #include -/** - * Length of a TS payload without the Traffic selectors. - */ -#define TS_PAYLOAD_HEADER_LENGTH 8 - /** * Class representing an IKEv2 TS payload. * diff --git a/src/libcharon/encoding/payloads/unknown_payload.c b/src/libcharon/encoding/payloads/unknown_payload.c index 9f5c6ef98..29dfa9da4 100644 --- a/src/libcharon/encoding/payloads/unknown_payload.c +++ b/src/libcharon/encoding/payloads/unknown_payload.c @@ -102,10 +102,6 @@ static encoding_rule_t encodings[] = { METHOD(payload_t, verify, status_t, private_unknown_payload_t *this) { - if (this->payload_length != UNKNOWN_PAYLOAD_HEADER_LENGTH + this->data.len) - { - return FAILED; - } return SUCCESS; } @@ -116,6 +112,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_unknown_payload_t *this) +{ + return 4; +} + METHOD(payload_t, get_payload_type, payload_type_t, private_unknown_payload_t *this) { @@ -171,6 +173,7 @@ unknown_payload_t *unknown_payload_create(payload_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -182,7 +185,7 @@ unknown_payload_t *unknown_payload_create(payload_type_t type) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .type = type, ); @@ -201,7 +204,7 @@ unknown_payload_t *unknown_payload_create_data(payload_type_t type, this = (private_unknown_payload_t*)unknown_payload_create(type); this->data = data; this->critical = critical; - this->payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH + data.len; + this->payload_length = get_header_length(this) + data.len; return &this->public; } diff --git a/src/libcharon/encoding/payloads/unknown_payload.h b/src/libcharon/encoding/payloads/unknown_payload.h index 5ae85331b..326b550cd 100644 --- a/src/libcharon/encoding/payloads/unknown_payload.h +++ b/src/libcharon/encoding/payloads/unknown_payload.h @@ -27,11 +27,6 @@ typedef struct unknown_payload_t unknown_payload_t; #include #include -/** - * Header length of the unknown payload. - */ -#define UNKNOWN_PAYLOAD_HEADER_LENGTH 4 - /** * Payload which can't be processed further. * diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.c b/src/libcharon/encoding/payloads/vendor_id_payload.c index 45669879b..8a1d9970d 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.c +++ b/src/libcharon/encoding/payloads/vendor_id_payload.c @@ -112,6 +112,12 @@ METHOD(payload_t, get_encoding_rules, int, return countof(encodings); } +METHOD(payload_t, get_header_length, int, + private_vendor_id_payload_t *this) +{ + return 4; +} + METHOD(payload_t, get_type, payload_type_t, private_vendor_id_payload_t *this) { @@ -162,6 +168,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type, .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -172,7 +179,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH + data.len, + .payload_length = get_header_length(this) + data.len, .data = data, .type = type, ); diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.h b/src/libcharon/encoding/payloads/vendor_id_payload.h index 4943af436..9a814777b 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.h +++ b/src/libcharon/encoding/payloads/vendor_id_payload.h @@ -27,11 +27,6 @@ typedef struct vendor_id_payload_t vendor_id_payload_t; #include #include -/** - * Length of a VENDOR ID payload without the VID data in bytes. - */ -#define VENDOR_ID_PAYLOAD_HEADER_LENGTH 4 - /** * Class representing an IKEv1/IKEv2 VENDOR ID payload. * diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index 2f024900e..9e4fddf5a 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -38,6 +38,8 @@ #define BLOCK_THRESHOLD_DEFAULT 5 /** length of the secret to use for cookie calculation */ #define SECRET_LENGTH 16 +/** Length of a notify payload header */ +#define NOTIFY_PAYLOAD_HEADER_LENGTH 8 typedef struct private_receiver_t private_receiver_t; From f34b452d56c8bf516aaef5daaff85f1309c5b4c5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 13:47:08 +0100 Subject: [PATCH 035/534] Implement second exchange in IKEv1 main mode --- src/libcharon/sa/tasks/main_mode.c | 170 ++++++++++++++++++++++++----- 1 file changed, 144 insertions(+), 26 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index e8bd62554..530568a8d 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -54,6 +54,34 @@ struct private_main_mode_t { * selected IKE proposal */ proposal_t *proposal; + + /** + * DH exchange + */ + diffie_hellman_t *dh; + + /** + * Received public DH value from peer + */ + chunk_t dh_value; + + /** + * Initiators nonce + */ + chunk_t nonce_i; + + /** + * Responder nonce + */ + chunk_t nonce_r; + + /** states of main mode */ + enum { + MM_INIT, + MM_SA, + MM_KE, + MM_ID, + } state; }; METHOD(task_t, build_i, status_t, @@ -66,43 +94,128 @@ METHOD(task_t, build_i, status_t, METHOD(task_t, process_r, status_t, private_main_mode_t *this, message_t *message) { - this->config = this->ike_sa->get_ike_cfg(this->ike_sa); - DBG0(DBG_IKE, "%H is initiating a Main Mode", message->get_source(message)); - this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); - - if (!this->proposal) + switch (this->state) { - linked_list_t *list; - sa_payload_t *sa_payload; - - sa_payload = (sa_payload_t*)message->get_payload(message, - SECURITY_ASSOCIATION_V1); - if (!sa_payload) + case MM_INIT: { - DBG1(DBG_IKE, "SA payload missing"); - return FAILED; - } - list = sa_payload->get_proposals(sa_payload); - this->proposal = this->config->select_proposal(this->config, list, FALSE); - if (!this->proposal) - { - DBG1(DBG_IKE, "no proposal found"); - return FAILED; + linked_list_t *list; + sa_payload_t *sa_payload; + + this->config = this->ike_sa->get_ike_cfg(this->ike_sa); + DBG0(DBG_IKE, "%H is initiating a Main Mode", + message->get_source(message)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return FAILED; + } + list = sa_payload->get_proposals(sa_payload); + this->proposal = this->config->select_proposal(this->config, + list, FALSE); + if (!this->proposal) + { + DBG1(DBG_IKE, "no proposal found"); + return FAILED; + } + this->state = MM_SA; + return NEED_MORE; } + case MM_SA: + { + ke_payload_t *ke_payload; + nonce_payload_t *nonce_payload; + u_int16_t group; + + ke_payload = (ke_payload_t*)message->get_payload(message, + KEY_EXCHANGE_V1); + if (!ke_payload) + { + DBG1(DBG_IKE, "KE payload missing"); + return FAILED; + } + this->dh_value = ke_payload->get_key_exchange_data(ke_payload); + this->dh_value = chunk_clone(this->dh_value); + + if (!this->proposal->get_algorithm(this->proposal, + DIFFIE_HELLMAN_GROUP, &group, NULL)) + { + DBG1(DBG_IKE, "DH group selection failed"); + return FAILED; + } + this->dh = lib->crypto->create_dh(lib->crypto, group); + if (!this->dh) + { + DBG1(DBG_IKE, "negotiated DH group not supported"); + return FAILED; + } + this->dh->set_other_public_value(this->dh, this->dh_value); + + + nonce_payload = (nonce_payload_t*)message->get_payload(message, + NONCE_V1); + if (!nonce_payload) + { + DBG1(DBG_IKE, "Nonce payload missing"); + return FAILED; + } + this->nonce_i = nonce_payload->get_nonce(nonce_payload); + /* TODO-IKEv1: verify nonce length */ + + this->state = MM_KE; + return NEED_MORE; + } + default: + return FAILED; } - return NEED_MORE; } METHOD(task_t, build_r, status_t, private_main_mode_t *this, message_t *message) { - sa_payload_t *sa_payload; + switch (this->state) + { + case MM_SA: + { + sa_payload_t *sa_payload; - sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1, - this->proposal); - message->add_payload(message, &sa_payload->payload_interface); - return NEED_MORE; + sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1, + this->proposal); + message->add_payload(message, &sa_payload->payload_interface); + return NEED_MORE; + } + case MM_KE: + { + ke_payload_t *ke_payload; + nonce_payload_t *nonce_payload; + rng_t *rng; + + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, + this->dh); + message->add_payload(message, &ke_payload->payload_interface); + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "no RNG found to create nonce"); + return FAILED; + } + /* TODO-IKEv1: nonce size? */ + rng->allocate_bytes(rng, 20, &this->nonce_r); + rng->destroy(rng); + + nonce_payload = nonce_payload_create(NONCE_V1); + nonce_payload->set_nonce(nonce_payload, this->nonce_r); + message->add_payload(message, &nonce_payload->payload_interface); + return NEED_MORE; + } + default: + return FAILED; + } } METHOD(task_t, process_i, status_t, @@ -128,6 +241,10 @@ METHOD(task_t, destroy, void, private_main_mode_t *this) { DESTROY_IF(this->proposal); + DESTROY_IF(this->dh); + free(this->dh_value.ptr); + free(this->nonce_i.ptr); + free(this->nonce_r.ptr); free(this); } @@ -148,6 +265,7 @@ main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator) }, .ike_sa = ike_sa, .initiator = initiator, + .state = MM_INIT, ); if (initiator) From 2a36037ec7d11674800c4437d6e7ebcef0a9d705 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 13:46:02 +0000 Subject: [PATCH 036/534] Extended ID payload for (non-TS) IKEv1 use --- src/libcharon/encoding/payloads/id_payload.c | 83 +++++++++++++++----- src/libcharon/encoding/payloads/id_payload.h | 18 ++--- src/libcharon/encoding/payloads/payload.c | 1 + 3 files changed, 73 insertions(+), 29 deletions(-) diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index b94c72b60..f936e9a2c 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -28,19 +28,14 @@ typedef struct private_id_payload_t private_id_payload_t; /** * Private data of an id_payload_t object. - * */ struct private_id_payload_t { + /** * Public id_payload_t interface. */ id_payload_t public; - /** - * one of ID_INITIATOR, ID_RESPONDER - */ - payload_type_t payload_type; - /** * Next payload type. */ @@ -75,15 +70,27 @@ struct private_id_payload_t { * The contained id data value. */ chunk_t id_data; + + /** + * Tunneled protocol ID for IKEv1 quick modes. + */ + u_int8_t protocol_id; + + /** + * Tunneled port for IKEv1 quick modes. + */ + u_int16_t port; + + /** + * one of ID_INITIATOR, ID_RESPONDER and IDv1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a ID payload - * - * The defined offsets are the positions in a object of type - * private_id_payload_t. + * Encoding rules for an IKEv2 ID payload */ -static encoding_rule_t encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_id_payload_t, next_payload) }, /* the critical bit */ @@ -105,7 +112,7 @@ static encoding_rule_t encodings[] = { { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[1])}, { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[2])}, /* some id data bytes, length is defined in PAYLOAD_LENGTH */ - { ID_DATA, offsetof(private_id_payload_t, id_data) } + { ID_DATA, offsetof(private_id_payload_t, id_data) }, }; /* @@ -122,6 +129,39 @@ static encoding_rule_t encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for an IKEv1 ID payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_id_payload_t, next_payload) }, + /* Reserved Byte is skipped */ + { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[0])}, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) }, + /* 1 Byte ID type*/ + { U_INT_8, offsetof(private_id_payload_t, id_type) }, + { U_INT_8, offsetof(private_id_payload_t, protocol_id) }, + { U_INT_16, offsetof(private_id_payload_t, port) }, + /* some id data bytes, length is defined in PAYLOAD_LENGTH */ + { ID_DATA, offsetof(private_id_payload_t, id_data) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ID Type ! Protocol ID ! Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Identification Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + METHOD(payload_t, verify, status_t, private_id_payload_t *this) { @@ -137,8 +177,13 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, int, private_id_payload_t *this, encoding_rule_t **rules) { - *rules = encodings; - return countof(encodings); + if (this->type == ID_V1) + { + *rules = encodings_v1; + return countof(encodings_v1); + } + *rules = encodings_v2; + return countof(encodings_v2); } METHOD(payload_t, get_header_length, int, @@ -150,7 +195,7 @@ METHOD(payload_t, get_header_length, int, METHOD(payload_t, get_type, payload_type_t, private_id_payload_t *this) { - return this->payload_type; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -187,7 +232,7 @@ METHOD2(payload_t, id_payload_t, destroy, void, /* * Described in header. */ -id_payload_t *id_payload_create(payload_type_t payload_type) +id_payload_t *id_payload_create(payload_type_t type) { private_id_payload_t *this; @@ -208,7 +253,7 @@ id_payload_t *id_payload_create(payload_type_t payload_type) }, .next_payload = NO_PAYLOAD, .payload_length = get_header_length(this), - .payload_type = payload_type, + .type = type, ); return &this->public; } @@ -216,12 +261,12 @@ id_payload_t *id_payload_create(payload_type_t payload_type) /* * Described in header. */ -id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, +id_payload_t *id_payload_create_from_identification(payload_type_t type, identification_t *id) { private_id_payload_t *this; - this = (private_id_payload_t*)id_payload_create(payload_type); + this = (private_id_payload_t*)id_payload_create(type); this->id_data = chunk_clone(id->get_encoding(id)); this->id_type = id->get_type(id); this->payload_length += this->id_data.len; diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h index c24b8ffc6..8ae90d20f 100644 --- a/src/libcharon/encoding/payloads/id_payload.h +++ b/src/libcharon/encoding/payloads/id_payload.h @@ -30,9 +30,7 @@ typedef struct id_payload_t id_payload_t; #include /** - * Object representing an IKEv2 ID payload. - * - * The ID payload format is described in RFC section 3.5. + * Object representing an IKEv1 or an IKEv2 ID payload. */ struct id_payload_t { @@ -57,19 +55,19 @@ struct id_payload_t { /** * Creates an empty id_payload_t object. * - * @param payload_type one of ID_INITIATOR, ID_RESPONDER - * @return id_payload_t object + * @param type one of ID_INITIATOR, ID_RESPONDER and ID_V1 + * @return id_payload_t object */ id_payload_t *id_payload_create(payload_type_t payload_type); /** * Creates an id_payload_t from an existing identification_t object. * - * @param payload_type one of ID_INITIATOR, ID_RESPONDER - * @param identification identification_t object - * @return id_payload_t object + * @param type one of ID_INITIATOR, ID_RESPONDER and ID_V1 + * @param id identification_t object + * @return id_payload_t object */ -id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, - identification_t *identification); +id_payload_t *id_payload_create_from_identification(payload_type_t type, + identification_t *id); #endif /** ID_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 3882e00bf..014d3c525 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -184,6 +184,7 @@ payload_t *payload_create(payload_type_t type) return (payload_t*)nonce_payload_create(type); case ID_INITIATOR: case ID_RESPONDER: + case ID_V1: #ifdef ME case ID_PEER: #endif /* ME */ From ee50a2938557c4fa67a76304dbeb37abfe6ad253 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 15:00:04 +0100 Subject: [PATCH 037/534] Implemented IKEv1 hash payload --- src/libcharon/Makefile.am | 1 + src/libcharon/encoding/generator.c | 1 + src/libcharon/encoding/parser.c | 1 + src/libcharon/encoding/payloads/encodings.c | 1 + src/libcharon/encoding/payloads/encodings.h | 10 + .../encoding/payloads/hash_payload.c | 171 ++++++++++++++++++ .../encoding/payloads/hash_payload.h | 66 +++++++ 7 files changed, 251 insertions(+) create mode 100644 src/libcharon/encoding/payloads/hash_payload.c create mode 100644 src/libcharon/encoding/payloads/hash_payload.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index a3b72253d..7de82e353 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -38,6 +38,7 @@ encoding/payloads/transform_substructure.c encoding/payloads/transform_substruct encoding/payloads/ts_payload.c encoding/payloads/ts_payload.h \ encoding/payloads/unknown_payload.c encoding/payloads/unknown_payload.h \ encoding/payloads/vendor_id_payload.c encoding/payloads/vendor_id_payload.h \ +encoding/payloads/hash_payload.c encoding/payloads/hash_payload.h \ kernel/kernel_handler.c kernel/kernel_handler.h \ network/receiver.c network/receiver.h network/sender.c network/sender.h \ network/packet.c network/packet.h network/socket.c network/socket.h \ diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 5f1a5e8a4..9cb1cdc5b 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -452,6 +452,7 @@ METHOD(generator_t, generate_payload, void, case KEY_EXCHANGE_DATA_V1: case NOTIFICATION_DATA: case NONCE_DATA: + case HASH_DATA: case ID_DATA: case AUTH_DATA: case CERT_DATA: diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 719c94254..77923e74b 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -534,6 +534,7 @@ METHOD(parser_t, parse_payload, status_t, } /* chunks */ case NONCE_DATA: + case HASH_DATA: case ID_DATA: case AUTH_DATA: case CERT_DATA: diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index 582847048..303ccca8a 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -49,6 +49,7 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "TS_TYPE", "ADDRESS", "NONCE_DATA", + "HASH_DATA", "ID_DATA", "AUTH_DATA", "CERT_DATA", diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index 0e9a44e92..d0355228e 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -404,6 +404,16 @@ enum encoding_type_t { */ NONCE_DATA, + /** + * Representating a Hash Data field. + * + * When generating the content of the chunkt pointing to + * is written. + * + * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. + */ + HASH_DATA, + /** * Representating a ID Data field. * diff --git a/src/libcharon/encoding/payloads/hash_payload.c b/src/libcharon/encoding/payloads/hash_payload.c new file mode 100644 index 000000000..ff968ee25 --- /dev/null +++ b/src/libcharon/encoding/payloads/hash_payload.c @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 + +#include "hash_payload.h" + +#include + +typedef struct private_hash_payload_t private_hash_payload_t; + +/** + * Private data of an hash_payload_t object. + */ +struct private_hash_payload_t { + + /** + * Public hash_payload_t interface. + */ + hash_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Reserved byte + */ + u_int8_t reserved; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * The contained hash value. + */ + chunk_t hash; +}; + +/** + * Encoding rules for an IKEv1 hash payload + */ +static encoding_rule_t encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_hash_payload_t, next_payload) }, + { RESERVED_BYTE, offsetof(private_hash_payload_t, reserved) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_hash_payload_t, payload_length) }, + /* Hash Data is from variable size */ + { HASH_DATA, offsetof(private_hash_payload_t, hash) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Hash Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +METHOD(payload_t, verify, status_t, + private_hash_payload_t *this) +{ + return SUCCESS; +} + +METHOD(payload_t, get_encoding_rules, int, + private_hash_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_hash_payload_t *this) +{ + return 4; +} + +METHOD(payload_t, get_type, payload_type_t, + private_hash_payload_t *this) +{ + return HASH_V1; +} + +METHOD(payload_t, get_next_type, payload_type_t, + private_hash_payload_t *this) +{ + return this->next_payload; +} + +METHOD(payload_t, set_next_type, void, + private_hash_payload_t *this, payload_type_t type) +{ + this->next_payload = type; +} + +METHOD(payload_t, get_length, size_t, + private_hash_payload_t *this) +{ + return this->payload_length; +} + +METHOD(hash_payload_t, set_hash, void, + private_hash_payload_t *this, chunk_t hash) +{ + free(this->hash.ptr); + this->hash = chunk_clone(hash); + this->payload_length = get_header_length(this) + hash.len; +} + +METHOD(hash_payload_t, get_hash, chunk_t, + private_hash_payload_t *this) +{ + return this->hash; +} + +METHOD2(payload_t, hash_payload_t, destroy, void, + private_hash_payload_t *this) +{ + free(this->hash.ptr); + free(this); +} + +/* + * Described in header + */ +hash_payload_t *hash_payload_create(payload_type_t type) +{ + private_hash_payload_t *this; + + INIT(this, + .public = { + .payload_interface = { + .verify = _verify, + .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, + .get_length = _get_length, + .get_next_type = _get_next_type, + .set_next_type = _set_next_type, + .get_type = _get_type, + .destroy = _destroy, + }, + .set_hash = _set_hash, + .get_hash = _get_hash, + .destroy = _destroy, + }, + .next_payload = NO_PAYLOAD, + .payload_length = get_header_length(this), + ); + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/hash_payload.h b/src/libcharon/encoding/payloads/hash_payload.h new file mode 100644 index 000000000..9f4b6e59b --- /dev/null +++ b/src/libcharon/encoding/payloads/hash_payload.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup hash_payload hash_payload + * @{ @ingroup payloads + */ + +#ifndef HASH_PAYLOAD_H_ +#define HASH_PAYLOAD_H_ + +typedef struct hash_payload_t hash_payload_t; + +#include +#include + +/** + * Object representing an IKEv1 hash payload. + */ +struct hash_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Set the hash value. + * + * @param hash chunk containing the hash, will be cloned + */ + void (*set_hash) (hash_payload_t *this, chunk_t hash); + + /** + * Get the hash value. + * + * @return chunkt to internal hash data + */ + chunk_t (*get_hash) (hash_payload_t *this); + + /** + * Destroys an hash_payload_t object. + */ + void (*destroy) (hash_payload_t *this); +}; + +/** + * Creates an empty hash_payload_t object. + * + * @return hash_payload_t object + */ +hash_payload_t *hash_payload_create(); + +#endif /** HASH_PAYLOAD_H_ @}*/ From 95a26523afc0d2a997cd1d4f738c287ae045ae4e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 14:20:16 +0000 Subject: [PATCH 038/534] Use a generic encoding type for all variable length chunks --- src/libcharon/encoding/generator.c | 16 +- src/libcharon/encoding/parser.c | 17 +-- .../encoding/payloads/auth_payload.c | 2 +- .../encoding/payloads/cert_payload.c | 2 +- .../encoding/payloads/certreq_payload.c | 2 +- .../payloads/configuration_attribute.c | 2 +- .../encoding/payloads/delete_payload.c | 2 +- src/libcharon/encoding/payloads/eap_payload.c | 2 +- src/libcharon/encoding/payloads/encodings.c | 18 +-- src/libcharon/encoding/payloads/encodings.h | 139 +----------------- .../encoding/payloads/encryption_payload.c | 2 +- .../encoding/payloads/hash_payload.c | 2 +- src/libcharon/encoding/payloads/id_payload.c | 4 +- src/libcharon/encoding/payloads/ke_payload.c | 4 +- .../encoding/payloads/nonce_payload.c | 2 +- .../encoding/payloads/notify_payload.c | 2 +- .../encoding/payloads/unknown_payload.c | 2 +- .../encoding/payloads/vendor_id_payload.c | 2 +- 18 files changed, 23 insertions(+), 199 deletions(-) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 9cb1cdc5b..d6828e7f9 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -448,21 +448,7 @@ METHOD(generator_t, generate_payload, void, break; case ADDRESS: case SPI: - case KEY_EXCHANGE_DATA: - case KEY_EXCHANGE_DATA_V1: - case NOTIFICATION_DATA: - case NONCE_DATA: - case HASH_DATA: - case ID_DATA: - case AUTH_DATA: - case CERT_DATA: - case CERTREQ_DATA: - case SPIS: - case CONFIGURATION_ATTRIBUTE_VALUE: - case VID_DATA: - case EAP_DATA: - case ENCRYPTED_DATA: - case UNKNOWN_DATA: + case CHUNK_DATA: generate_from_chunk(this, rules[i].offset); break; case PROPOSALS: diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 77923e74b..1876212aa 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -532,22 +532,7 @@ METHOD(parser_t, parse_payload, status_t, } break; } - /* chunks */ - case NONCE_DATA: - case HASH_DATA: - case ID_DATA: - case AUTH_DATA: - case CERT_DATA: - case CERTREQ_DATA: - case EAP_DATA: - case SPIS: - case VID_DATA: - case CONFIGURATION_ATTRIBUTE_VALUE: - case KEY_EXCHANGE_DATA: - case KEY_EXCHANGE_DATA_V1: - case NOTIFICATION_DATA: - case ENCRYPTED_DATA: - case UNKNOWN_DATA: + case CHUNK_DATA: { if (payload_length < header_length || !parse_chunk(this, rule_number, output + rule->offset, diff --git a/src/libcharon/encoding/payloads/auth_payload.c b/src/libcharon/encoding/payloads/auth_payload.c index 57dc58f2a..2410a1aaa 100644 --- a/src/libcharon/encoding/payloads/auth_payload.c +++ b/src/libcharon/encoding/payloads/auth_payload.c @@ -96,7 +96,7 @@ static encoding_rule_t encodings[] = { { RESERVED_BYTE, offsetof(private_auth_payload_t, reserved_byte[1]) }, { RESERVED_BYTE, offsetof(private_auth_payload_t, reserved_byte[2]) }, /* some auth data bytes, length is defined in PAYLOAD_LENGTH */ - { AUTH_DATA, offsetof(private_auth_payload_t, auth_data) } + { CHUNK_DATA, offsetof(private_auth_payload_t, auth_data) } }; /* diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c index 565be7f34..1ef93b724 100644 --- a/src/libcharon/encoding/payloads/cert_payload.c +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -113,7 +113,7 @@ static encoding_rule_t encodings[] = { /* 1 Byte CERT type*/ { U_INT_8, offsetof(private_cert_payload_t, encoding) }, /* some cert data bytes, length is defined in PAYLOAD_LENGTH */ - { CERT_DATA, offsetof(private_cert_payload_t, data) } + { CHUNK_DATA, offsetof(private_cert_payload_t, data) } }; /* diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c index dc685e651..69e80ad7e 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.c +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -90,7 +90,7 @@ static encoding_rule_t encodings[] = { /* 1 Byte CERTREQ type*/ { U_INT_8, offsetof(private_certreq_payload_t, encoding) }, /* some certreq data bytes, length is defined in PAYLOAD_LENGTH */ - { CERTREQ_DATA, offsetof(private_certreq_payload_t, data) } + { CHUNK_DATA, offsetof(private_certreq_payload_t, data) } }; /* diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index 8746b9b9e..88e43fa3d 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -70,7 +70,7 @@ static encoding_rule_t encodings[] = { /* Length of attribute value */ { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length) }, /* Value of attribute if attribute format flag is zero */ - { CONFIGURATION_ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) } + { CHUNK_DATA, offsetof(private_configuration_attribute_t, value) } }; /* diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index 5f0af8c86..425bde0c3 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -98,7 +98,7 @@ static encoding_rule_t encodings[] = { { U_INT_8, offsetof(private_delete_payload_t, spi_size) }, { U_INT_16, offsetof(private_delete_payload_t, spi_count) }, /* some delete data bytes, length is defined in PAYLOAD_LENGTH */ - { SPIS, offsetof(private_delete_payload_t, spis) } + { CHUNK_DATA, offsetof(private_delete_payload_t, spis) } }; /* diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index 47a9b1673..9982f05a1 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -81,7 +81,7 @@ static encoding_rule_t encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length) }, /* chunt to data, starting at "code" */ - { EAP_DATA, offsetof(private_eap_payload_t, data) }, + { CHUNK_DATA, offsetof(private_eap_payload_t, data) }, }; /* diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index 303ccca8a..3fe2e6be6 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -17,7 +17,7 @@ #include "encodings.h" -ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, +ENUM(encoding_type_names, U_INT_4, IKE_SPI, "U_INT_4", "U_INT_8", "U_INT_16", @@ -29,9 +29,6 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "HEADER_LENGTH", "SPI_SIZE", "SPI", - "KEY_EXCHANGE_DATA", - "KEY_EXCHANGE_DATA_V1", - "NOTIFICATION_DATA", "PROPOSALS", "PROPOSALS_V1", "TRANSFORMS", @@ -39,7 +36,6 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "TRANSFORM_ATTRIBUTES", "TRANSFORM_ATTRIBUTES_V1", "CONFIGURATION_ATTRIBUTES", - "CONFIGURATION_ATTRIBUTE_VALUE", "ATTRIBUTE_FORMAT", "ATTRIBUTE_TYPE", "ATTRIBUTE_LENGTH_OR_VALUE", @@ -48,16 +44,6 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "TRAFFIC_SELECTORS", "TS_TYPE", "ADDRESS", - "NONCE_DATA", - "HASH_DATA", - "ID_DATA", - "AUTH_DATA", - "CERT_DATA", - "CERTREQ_DATA", - "EAP_DATA", - "SPIS", - "VID_DATA", - "UNKNOWN_DATA", + "CHUNK_DATA", "IKE_SPI", - "ENCRYPTED_DATA", ); diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index d0355228e..f6208b828 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -186,31 +186,6 @@ enum encoding_type_t { */ SPI, - /** - * Representating a Key Exchange Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - KEY_EXCHANGE_DATA, - - /** - * Same as KEY_EXCHANGE_DATA, but for KEY_EXCHANGE_V1 - */ - KEY_EXCHANGE_DATA_V1, - - /** - * Representating a Notification field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - spi size - 8) bytes are read and written into the chunk pointing to. - */ - NOTIFICATION_DATA, - /** * Representating one or more proposal substructures. * @@ -278,15 +253,6 @@ enum encoding_type_t { */ CONFIGURATION_ATTRIBUTES, - /** - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - CONFIGURATION_ATTRIBUTE_VALUE, - /** * Representing a 1 Bit flag specifying the format of a transform attribute. * @@ -299,6 +265,7 @@ enum encoding_type_t { * is moved 1 bit forward afterwards. */ ATTRIBUTE_FORMAT, + /** * Representing a 15 Bit unsigned int value used as attribute type * in an attribute transform. @@ -395,104 +362,9 @@ enum encoding_type_t { ADDRESS, /** - * Representating a Nonce Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. + * Representing a variable length byte field. */ - NONCE_DATA, - - /** - * Representating a Hash Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - HASH_DATA, - - /** - * Representating a ID Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - ID_DATA, - - /** - * Representating a AUTH Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - AUTH_DATA, - - /** - * Representating a CERT Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to. - */ - CERT_DATA, - - /** - * Representating a CERTREQ Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to. - */ - CERTREQ_DATA, - - /** - * Representating an EAP message field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - EAP_DATA, - - /** - * Representating the SPIS field in a DELETE payload. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - SPIS, - - /** - * Representating the VID DATA field in a VENDOR ID payload. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - VID_DATA, - - /** - * Representating the DATA of an unknown payload. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - UNKNOWN_DATA, + CHUNK_DATA, /** * Representating an IKE_SPI field in an IKEv2 Header. @@ -503,11 +375,6 @@ enum encoding_type_t { * When parsing 8 bytes are read and written into the u_int64_t pointing to. */ IKE_SPI, - - /** - * Representing the encrypted data body of a encryption payload. - */ - ENCRYPTED_DATA, }; /** diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c index 08c64fb51..bb9969d0b 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.c +++ b/src/libcharon/encoding/payloads/encryption_payload.c @@ -87,7 +87,7 @@ static encoding_rule_t encodings[] = { /* Length of the whole encryption payload*/ { PAYLOAD_LENGTH, offsetof(private_encryption_payload_t, payload_length) }, /* encrypted data, stored in a chunk. contains iv, data, padding */ - { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) }, + { CHUNK_DATA, offsetof(private_encryption_payload_t, encrypted) }, }; /* diff --git a/src/libcharon/encoding/payloads/hash_payload.c b/src/libcharon/encoding/payloads/hash_payload.c index ff968ee25..9542b1c03 100644 --- a/src/libcharon/encoding/payloads/hash_payload.c +++ b/src/libcharon/encoding/payloads/hash_payload.c @@ -62,7 +62,7 @@ static encoding_rule_t encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_hash_payload_t, payload_length) }, /* Hash Data is from variable size */ - { HASH_DATA, offsetof(private_hash_payload_t, hash) }, + { CHUNK_DATA, offsetof(private_hash_payload_t, hash) }, }; /* diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index f936e9a2c..108d56bd8 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -112,7 +112,7 @@ static encoding_rule_t encodings_v2[] = { { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[1])}, { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[2])}, /* some id data bytes, length is defined in PAYLOAD_LENGTH */ - { ID_DATA, offsetof(private_id_payload_t, id_data) }, + { CHUNK_DATA, offsetof(private_id_payload_t, id_data) }, }; /* @@ -144,7 +144,7 @@ static encoding_rule_t encodings_v1[] = { { U_INT_8, offsetof(private_id_payload_t, protocol_id) }, { U_INT_16, offsetof(private_id_payload_t, port) }, /* some id data bytes, length is defined in PAYLOAD_LENGTH */ - { ID_DATA, offsetof(private_id_payload_t, id_data) }, + { CHUNK_DATA, offsetof(private_id_payload_t, id_data) }, }; /* diff --git a/src/libcharon/encoding/payloads/ke_payload.c b/src/libcharon/encoding/payloads/ke_payload.c index a6e5217aa..438ea46b9 100644 --- a/src/libcharon/encoding/payloads/ke_payload.c +++ b/src/libcharon/encoding/payloads/ke_payload.c @@ -98,7 +98,7 @@ static encoding_rule_t encodings_v2[] = { { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[0])}, { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[1])}, /* Key Exchange Data is from variable size */ - { KEY_EXCHANGE_DATA, offsetof(private_ke_payload_t, key_exchange_data)}, + { CHUNK_DATA, offsetof(private_ke_payload_t, key_exchange_data)}, }; /* @@ -123,7 +123,7 @@ static encoding_rule_t encodings_v1[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_ke_payload_t, payload_length) }, /* Key Exchange Data is from variable size */ - { KEY_EXCHANGE_DATA_V1, offsetof(private_ke_payload_t, key_exchange_data)}, + { CHUNK_DATA, offsetof(private_ke_payload_t, key_exchange_data)}, }; /* diff --git a/src/libcharon/encoding/payloads/nonce_payload.c b/src/libcharon/encoding/payloads/nonce_payload.c index 1e0cf5579..58ef70a0e 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.c +++ b/src/libcharon/encoding/payloads/nonce_payload.c @@ -86,7 +86,7 @@ static encoding_rule_t encodings[] = { /* Length of the whole nonce payload*/ { PAYLOAD_LENGTH, offsetof(private_nonce_payload_t, payload_length) }, /* some nonce bytes, lenth is defined in PAYLOAD_LENGTH */ - { NONCE_DATA, offsetof(private_nonce_payload_t, nonce) }, + { CHUNK_DATA, offsetof(private_nonce_payload_t, nonce) }, }; /* 1 2 3 diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index f2e1267c6..7dab941b8 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -287,7 +287,7 @@ static encoding_rule_t encodings[] = { /* SPI as variable length field*/ { SPI, offsetof(private_notify_payload_t, spi) }, /* Key Exchange Data is from variable size */ - { NOTIFICATION_DATA,offsetof(private_notify_payload_t, notification_data) } + { CHUNK_DATA, offsetof(private_notify_payload_t, notification_data) } }; /* diff --git a/src/libcharon/encoding/payloads/unknown_payload.c b/src/libcharon/encoding/payloads/unknown_payload.c index 29dfa9da4..fe7ced20b 100644 --- a/src/libcharon/encoding/payloads/unknown_payload.c +++ b/src/libcharon/encoding/payloads/unknown_payload.c @@ -84,7 +84,7 @@ static encoding_rule_t encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_unknown_payload_t, payload_length) }, /* some unknown data bytes, length is defined in PAYLOAD_LENGTH */ - { UNKNOWN_DATA, offsetof(private_unknown_payload_t, data) }, + { CHUNK_DATA, offsetof(private_unknown_payload_t, data) }, }; /* diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.c b/src/libcharon/encoding/payloads/vendor_id_payload.c index 8a1d9970d..0c1df56e2 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.c +++ b/src/libcharon/encoding/payloads/vendor_id_payload.c @@ -84,7 +84,7 @@ static encoding_rule_t encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_vendor_id_payload_t, payload_length)}, /* some vendor_id data bytes, length is defined in PAYLOAD_LENGTH */ - { VID_DATA, offsetof(private_vendor_id_payload_t, data) } + { CHUNK_DATA, offsetof(private_vendor_id_payload_t, data) } }; /* From f62a7c7c7192d791eb4c10e7ff4d09cf54c7d4da Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 15:44:42 +0100 Subject: [PATCH 039/534] Use a generic list encoding rule we can use to specify the wrapped payload type --- src/libcharon/encoding/generator.c | 16 ++-- src/libcharon/encoding/parser.c | 46 ++-------- src/libcharon/encoding/payloads/cp_payload.c | 34 +++---- src/libcharon/encoding/payloads/encodings.c | 8 -- src/libcharon/encoding/payloads/encodings.h | 91 +++---------------- .../encoding/payloads/proposal_substructure.c | 12 +-- src/libcharon/encoding/payloads/sa_payload.c | 12 +-- .../payloads/transform_substructure.c | 32 ++++--- src/libcharon/encoding/payloads/ts_payload.c | 5 +- 9 files changed, 77 insertions(+), 179 deletions(-) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index d6828e7f9..a378426ab 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -451,14 +451,14 @@ METHOD(generator_t, generate_payload, void, case CHUNK_DATA: generate_from_chunk(this, rules[i].offset); break; - case PROPOSALS: - case PROPOSALS_V1: - case TRANSFORMS: - case TRANSFORMS_V1: - case TRANSFORM_ATTRIBUTES: - case TRANSFORM_ATTRIBUTES_V1: - case CONFIGURATION_ATTRIBUTES: - case TRAFFIC_SELECTORS: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE: + case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE: { linked_list_t *proposals; enumerator_t *enumerator; diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 1876212aa..e599b84d9 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -358,34 +358,6 @@ static bool parse_chunk(private_parser_t *this, int rule_number, return TRUE; } -/** - * Map a encoding type to a encoded payload - */ -static payload_type_t map_wrapped_payload(encoding_type_t type) -{ - switch (type) - { - case PROPOSALS: - return PROPOSAL_SUBSTRUCTURE; - case PROPOSALS_V1: - return PROPOSAL_SUBSTRUCTURE_V1; - case TRANSFORMS: - return TRANSFORM_SUBSTRUCTURE; - case TRANSFORMS_V1: - return TRANSFORM_SUBSTRUCTURE_V1; - case TRANSFORM_ATTRIBUTES: - return TRANSFORM_ATTRIBUTE; - case TRANSFORM_ATTRIBUTES_V1: - return TRANSFORM_ATTRIBUTE_V1; - case CONFIGURATION_ATTRIBUTES: - return CONFIGURATION_ATTRIBUTE; - case TRAFFIC_SELECTORS: - return TRAFFIC_SELECTOR_SUBSTRUCTURE; - default: - return NO_PAYLOAD; - } -} - METHOD(parser_t, parse_payload, status_t, private_parser_t *this, payload_type_t payload_type, payload_t **payload) { @@ -513,18 +485,18 @@ METHOD(parser_t, parse_payload, status_t, } break; } - /* lists */ - case PROPOSALS: - case PROPOSALS_V1: - case TRANSFORMS: - case TRANSFORMS_V1: - case TRANSFORM_ATTRIBUTES: - case TRANSFORM_ATTRIBUTES_V1: - case TRAFFIC_SELECTORS: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE: + case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE: { if (payload_length < header_length || !parse_list(this, rule_number, output + rule->offset, - map_wrapped_payload(rule->type), + rule->type - PAYLOAD_LIST, payload_length - header_length)) { pld->destroy(pld); diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c index 05f16c33f..1813c9790 100644 --- a/src/libcharon/encoding/payloads/cp_payload.c +++ b/src/libcharon/encoding/payloads/cp_payload.c @@ -85,27 +85,27 @@ struct private_cp_payload_t { */ static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, + { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_cp_payload_t, critical) }, + { FLAG, offsetof(private_cp_payload_t, critical) }, /* 7 Bit reserved bits */ - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, /* Length of the whole CP payload*/ - { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, - /* Proposals are stored in a proposal substructure, - offset points to a linked_list_t pointer */ - { U_INT_8, offsetof(private_cp_payload_t, type) }, + { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, + { U_INT_8, offsetof(private_cp_payload_t, type) }, /* 3 reserved bytes */ - { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, - { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[1])}, - { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[2])}, - { CONFIGURATION_ATTRIBUTES, offsetof(private_cp_payload_t, attributes) } + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[1])}, + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[2])}, + /* list of configuration attributes in a list */ + { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE, + offsetof(private_cp_payload_t, attributes) }, }; /* diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index 3fe2e6be6..3dc8ee4ec 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -29,19 +29,11 @@ ENUM(encoding_type_names, U_INT_4, IKE_SPI, "HEADER_LENGTH", "SPI_SIZE", "SPI", - "PROPOSALS", - "PROPOSALS_V1", - "TRANSFORMS", - "TRANSFORMS_V1", - "TRANSFORM_ATTRIBUTES", - "TRANSFORM_ATTRIBUTES_V1", - "CONFIGURATION_ATTRIBUTES", "ATTRIBUTE_FORMAT", "ATTRIBUTE_TYPE", "ATTRIBUTE_LENGTH_OR_VALUE", "CONFIGURATION_ATTRIBUTE_LENGTH", "ATTRIBUTE_VALUE", - "TRAFFIC_SELECTORS", "TS_TYPE", "ADDRESS", "CHUNK_DATA", diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index f6208b828..dde495bc2 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -186,73 +186,6 @@ enum encoding_type_t { */ SPI, - /** - * Representating one or more proposal substructures. - * - * The offset points to a linked_list_t pointer. - * - * When generating the proposal_substructure_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed proposal_substructure_t objects have - * to be stored in the pointed linked_list. - */ - PROPOSALS, - - /** - * Same as PROPOSALS, but for IKEv1 in a SECURITY_ASSOCIATION_V1 - */ - PROPOSALS_V1, - - /** - * Representating one or more transform substructures. - * - * The offset points to a linked_list_t pointer. - * - * When generating the transform_substructure_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed transform_substructure_t objects have - * to be stored in the pointed linked_list. - */ - TRANSFORMS, - - /** - * Same as TRANSFORMS, but for IKEv1 in a PROPOSAL_SUBSTRUCTURE_V1. - */ - TRANSFORMS_V1, - - /** - * Representating one or more Attributes of a transform substructure. - * - * The offset points to a linked_list_t pointer. - * - * When generating the transform_attribute_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed transform_attribute_t objects have - * to be stored in the pointed linked_list. - */ - TRANSFORM_ATTRIBUTES, - - /** - * Same as TRANSFORM_ATTRIBUTES, but for IKEv1 in TRANSFORMS_V1. - */ - TRANSFORM_ATTRIBUTES_V1, - - /** - * Representating one or more Attributes of a configuration payload. - * - * The offset points to a linked_list_t pointer. - * - * When generating the configuration_attribute_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed configuration_attribute_t objects have - * to be stored in the pointed linked_list. - */ - CONFIGURATION_ATTRIBUTES, - /** * Representing a 1 Bit flag specifying the format of a transform attribute. * @@ -322,19 +255,6 @@ enum encoding_type_t { */ ATTRIBUTE_VALUE, - /** - * Representating one or more Traffic selectors of a TS payload. - * - * The offset points to a linked_list_t pointer. - * - * When generating the traffic_selector_substructure_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed traffic_selector_substructure_t objects have - * to be stored in the pointed linked_list. - */ - TRAFFIC_SELECTORS, - /** * Representating a Traffic selector type field. * @@ -375,6 +295,17 @@ enum encoding_type_t { * When parsing 8 bytes are read and written into the u_int64_t pointing to. */ IKE_SPI, + + /** + * Reprensenting a field containing a set of wrapped payloads. + * + * This type is not used directly, but as an offset to the wrapped payloads. + * The type of the wrapped payload is added to this encoding type. + * + * @note As payload types are added to this encoding type, it has + * to be the last in encoding_type_t. + */ + PAYLOAD_LIST = 1000 /* no comma, read above! */ }; /** diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 16d5794ae..aa3f0674f 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -112,9 +112,9 @@ static encoding_rule_t encodings_v1[] = { { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) }, /* SPI is a chunk of variable size*/ { SPI, offsetof(private_proposal_substructure_t, spi) }, - /* Transforms are stored in a transform substructure, - offset points to a linked_list_t pointer */ - { TRANSFORMS_V1, offsetof(private_proposal_substructure_t, transforms) } + /* Transforms are stored in a transform substructure list */ + { PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1, + offsetof(private_proposal_substructure_t, transforms) }, }; /** @@ -137,9 +137,9 @@ static encoding_rule_t encodings_v2[] = { { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) }, /* SPI is a chunk of variable size*/ { SPI, offsetof(private_proposal_substructure_t, spi) }, - /* Transforms are stored in a transform substructure, - offset points to a linked_list_t pointer */ - { TRANSFORMS, offsetof(private_proposal_substructure_t, transforms) } + /* Transforms are stored in a transform substructure list */ + { PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE, + offsetof(private_proposal_substructure_t, transforms) }, }; /* diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 66e994b43..29c671d8e 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -99,9 +99,9 @@ static encoding_rule_t encodings_v1[] = { { U_INT_32, offsetof(private_sa_payload_t, doi) }, /* Situation*/ { U_INT_32, offsetof(private_sa_payload_t, situation) }, - /* Proposals are stored in a proposal substructure, - offset points to a linked_list_t pointer */ - { PROPOSALS_V1, offsetof(private_sa_payload_t, proposals) }, + /* Proposals are stored in a proposal substructure list */ + { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1, + offsetof(private_sa_payload_t, proposals) }, }; /* @@ -138,9 +138,9 @@ static encoding_rule_t encodings_v2[] = { { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, /* Length of the whole SA payload*/ { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, - /* Proposals are stored in a proposal substructure, - offset points to a linked_list_t pointer */ - { PROPOSALS, offsetof(private_sa_payload_t, proposals) }, + /* Proposals are stored in a proposal substructure list */ + { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE, + offsetof(private_sa_payload_t, proposals) }, }; /* diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c index 63464e9f3..9ee8b48db 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.c +++ b/src/libcharon/encoding/payloads/transform_substructure.c @@ -83,19 +83,20 @@ struct private_transform_substructure_t { */ static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, + { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, /* 1 Reserved Byte */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, /* Length of the whole transform substructure*/ - { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, + { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, /* transform type */ - { U_INT_8, offsetof(private_transform_substructure_t, transform_ton) }, + { U_INT_8, offsetof(private_transform_substructure_t, transform_ton) }, /* transform identifier, as used by IKEv1 */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, /* transform identifier, as used by IKEv2 */ - { U_INT_16, offsetof(private_transform_substructure_t, transform_id_v2) }, + { U_INT_16, offsetof(private_transform_substructure_t, transform_id_v2) }, /* Attributes in a transform attribute list */ - { TRANSFORM_ATTRIBUTES, offsetof(private_transform_substructure_t, attributes) } + { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE, + offsetof(private_transform_substructure_t, attributes) } }; /** @@ -103,20 +104,21 @@ static encoding_rule_t encodings_v2[] = { */ static encoding_rule_t encodings_v1[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, + { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, /* 1 Reserved Byte */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, /* Length of the whole transform substructure*/ - { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, + { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, /* transform number */ - { U_INT_8, offsetof(private_transform_substructure_t, transform_ton)}, + { U_INT_8, offsetof(private_transform_substructure_t, transform_ton)}, /* transform identifier, as used by IKEv1 */ - { U_INT_8, offsetof(private_transform_substructure_t, transform_id_v1) }, + { U_INT_8, offsetof(private_transform_substructure_t, transform_id_v1) }, /* transform identifier, as used by IKEv2 */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[2]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[2]) }, /* Attributes in a transform attribute list */ - { TRANSFORM_ATTRIBUTES_V1, offsetof(private_transform_substructure_t, attributes) } + { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1, + offsetof(private_transform_substructure_t, attributes) } }; /* diff --git a/src/libcharon/encoding/payloads/ts_payload.c b/src/libcharon/encoding/payloads/ts_payload.c index df47b8892..a7678da73 100644 --- a/src/libcharon/encoding/payloads/ts_payload.c +++ b/src/libcharon/encoding/payloads/ts_payload.c @@ -102,8 +102,9 @@ static encoding_rule_t encodings[] = { { RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[0])}, { RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[1])}, { RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[2])}, - /* some ts data bytes, length is defined in PAYLOAD_LENGTH */ - { TRAFFIC_SELECTORS,offsetof(private_ts_payload_t, substrs) } + /* wrapped list of traffic selectors substructures */ + { PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE, + offsetof(private_ts_payload_t, substrs) }, }; /* From 6ab936f046b1f560b971763808c257fa9dbafd5a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 17 Nov 2011 16:19:47 +0100 Subject: [PATCH 040/534] Use keymat_t as common interface, renamed current implementation to _v2. --- src/libcharon/Makefile.am | 3 +- src/libcharon/sa/ike_sa.c | 5 +- src/libcharon/sa/keymat.h | 8 ---- src/libcharon/sa/{keymat.c => keymat_v2.c} | 53 +++++++++++----------- src/libcharon/sa/keymat_v2.h | 47 +++++++++++++++++++ 5 files changed, 79 insertions(+), 37 deletions(-) rename src/libcharon/sa/{keymat.c => keymat_v2.c} (93%) create mode 100644 src/libcharon/sa/keymat_v2.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 7de82e353..6607bb017 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -68,7 +68,8 @@ sa/ike_sa.c sa/ike_sa.h \ sa/ike_sa_id.c sa/ike_sa_id.h \ sa/ike_sa_manager.c sa/ike_sa_manager.h \ sa/task_manager.h sa/task_manager_v2.c sa/task_manager_v2.h \ -sa/task_manager_v1.c sa/task_manager_v1.h sa/keymat.c sa/keymat.h \ +sa/task_manager_v1.c sa/task_manager_v1.h \ +sa/keymat.h sa/keymat_v2.c sa/keymat_v2.h \ sa/shunt_manager.c sa/shunt_manager.h \ sa/trap_manager.c sa/trap_manager.h \ sa/tasks/child_create.c sa/tasks/child_create.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 03d834538..ee3220d1b 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -713,7 +714,7 @@ METHOD(ike_sa_t, reset, void, flush_auth_cfgs(this); this->keymat->destroy(this->keymat); - this->keymat = keymat_create(this->ike_sa_id->is_initiator(this->ike_sa_id)); + this->keymat = &(keymat_v2_create(this->ike_sa_id->is_initiator(this->ike_sa_id))->keymat); this->task_manager->reset(this->task_manager, 0, 0); } @@ -2195,7 +2196,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .other_host = host_create_any(AF_INET), .my_id = identification_create_from_encoding(ID_ANY, chunk_empty), .other_id = identification_create_from_encoding(ID_ANY, chunk_empty), - .keymat = keymat_create(ike_sa_id->is_initiator(ike_sa_id)), .state = IKE_CREATED, .stats[STAT_INBOUND] = time_monotonic(NULL), .stats[STAT_OUTBOUND] = time_monotonic(NULL), @@ -2209,6 +2209,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) .keepalive_interval = lib->settings->get_time(lib->settings, "charon.keep_alive", KEEPALIVE_INTERVAL), ); + this->keymat = &(keymat_v2_create(ike_sa_id->is_initiator(ike_sa_id))->keymat); this->task_manager = &(task_manager_v2_create(&this->public)->task_manager); this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index 11e0fa79a..c50d93322 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -147,12 +147,4 @@ struct keymat_t { void (*destroy)(keymat_t *this); }; -/** - * Create a keymat instance. - * - * @param initiator TRUE if we are the initiator - * @return keymat instance - */ -keymat_t *keymat_create(bool initiator); - #endif /** KEYMAT_H_ @}*/ diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat_v2.c similarity index 93% rename from src/libcharon/sa/keymat.c rename to src/libcharon/sa/keymat_v2.c index 33ece24b2..562a72f14 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat_v2.c @@ -13,22 +13,22 @@ * for more details. */ -#include "keymat.h" +#include "keymat_v2.h" #include #include -typedef struct private_keymat_t private_keymat_t; +typedef struct private_keymat_v2_t private_keymat_v2_t; /** * Private data of an keymat_t object. */ -struct private_keymat_t { +struct private_keymat_v2_t { /** - * Public keymat_t interface. + * Public keymat_v2_t interface. */ - keymat_t public; + keymat_v2_t public; /** * IKE_SA Role, initiator or responder @@ -125,7 +125,7 @@ static int lookup_keylen(keylen_entry_t *list, int algo) } METHOD(keymat_t, create_dh, diffie_hellman_t*, - private_keymat_t *this, diffie_hellman_group_t group) + private_keymat_v2_t *this, diffie_hellman_group_t group) { return lib->crypto->create_dh(lib->crypto, group);; } @@ -133,7 +133,7 @@ METHOD(keymat_t, create_dh, diffie_hellman_t*, /** * Derive IKE keys for a combined AEAD algorithm */ -static bool derive_ike_aead(private_keymat_t *this, u_int16_t alg, +static bool derive_ike_aead(private_keymat_v2_t *this, u_int16_t alg, u_int16_t key_size, prf_plus_t *prf_plus) { aead_t *aead_i, *aead_r; @@ -177,7 +177,7 @@ static bool derive_ike_aead(private_keymat_t *this, u_int16_t alg, /** * Derive IKE keys for traditional encryption and MAC algorithms */ -static bool derive_ike_traditional(private_keymat_t *this, u_int16_t enc_alg, +static bool derive_ike_traditional(private_keymat_v2_t *this, u_int16_t enc_alg, u_int16_t enc_size, u_int16_t int_alg, prf_plus_t *prf_plus) { crypter_t *crypter_i, *crypter_r; @@ -245,7 +245,7 @@ static bool derive_ike_traditional(private_keymat_t *this, u_int16_t enc_alg, } METHOD(keymat_t, derive_ike_keys, bool, - private_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh, + private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, pseudo_random_function_t rekey_function, chunk_t rekey_skd) { @@ -421,7 +421,7 @@ METHOD(keymat_t, derive_ike_keys, bool, } METHOD(keymat_t, derive_child_keys, bool, - private_keymat_t *this, proposal_t *proposal, diffie_hellman_t *dh, + private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r) { @@ -526,20 +526,20 @@ METHOD(keymat_t, derive_child_keys, bool, } METHOD(keymat_t, get_skd, pseudo_random_function_t, - private_keymat_t *this, chunk_t *skd) + private_keymat_v2_t *this, chunk_t *skd) { *skd = this->skd; return this->prf_alg; } METHOD(keymat_t, get_aead, aead_t*, - private_keymat_t *this, bool in) + private_keymat_v2_t *this, bool in) { return in ? this->aead_in : this->aead_out; } METHOD(keymat_t, get_auth_octets, chunk_t, - private_keymat_t *this, bool verify, chunk_t ike_sa_init, + private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce, identification_t *id, char reserved[3]) { chunk_t chunk, idx, octets; @@ -569,7 +569,7 @@ METHOD(keymat_t, get_auth_octets, chunk_t, #define IKEV2_KEY_PAD_LENGTH 17 METHOD(keymat_t, get_psk_sig, chunk_t, - private_keymat_t *this, bool verify, chunk_t ike_sa_init, + private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce, chunk_t secret, identification_t *id, char reserved[3]) { chunk_t key_pad, key, sig, octets; @@ -595,7 +595,7 @@ METHOD(keymat_t, get_psk_sig, chunk_t, } METHOD(keymat_t, destroy, void, - private_keymat_t *this) + private_keymat_v2_t *this) { DESTROY_IF(this->aead_in); DESTROY_IF(this->aead_out); @@ -609,20 +609,22 @@ METHOD(keymat_t, destroy, void, /** * See header */ -keymat_t *keymat_create(bool initiator) +keymat_v2_t *keymat_v2_create(bool initiator) { - private_keymat_t *this; + private_keymat_v2_t *this; INIT(this, .public = { - .create_dh = _create_dh, - .derive_ike_keys = _derive_ike_keys, - .derive_child_keys = _derive_child_keys, - .get_skd = _get_skd, - .get_aead = _get_aead, - .get_auth_octets = _get_auth_octets, - .get_psk_sig = _get_psk_sig, - .destroy = _destroy, + .keymat = { + .create_dh = _create_dh, + .derive_ike_keys = _derive_ike_keys, + .derive_child_keys = _derive_child_keys, + .get_skd = _get_skd, + .get_aead = _get_aead, + .get_auth_octets = _get_auth_octets, + .get_psk_sig = _get_psk_sig, + .destroy = _destroy, + }, }, .initiator = initiator, .prf_alg = PRF_UNDEFINED, @@ -630,4 +632,3 @@ keymat_t *keymat_create(bool initiator) return &this->public; } - diff --git a/src/libcharon/sa/keymat_v2.h b/src/libcharon/sa/keymat_v2.h new file mode 100644 index 000000000..6026a0296 --- /dev/null +++ b/src/libcharon/sa/keymat_v2.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup keymat_v2 keymat_v2 + * @{ @ingroup sa + */ + +#ifndef KEYMAT_V2_H_ +#define KEYMAT_V2_H_ + +#include + +typedef struct keymat_v2_t keymat_v2_t; + +/** + * Derivation and management of sensitive keying material, IKEv2 variant. + */ +struct keymat_v2_t { + + /** + * Implements keymat_t. + */ + keymat_t keymat; +}; + +/** + * Create a keymat instance. + * + * @param initiator TRUE if we are the initiator + * @return keymat instance + */ +keymat_v2_t *keymat_v2_create(bool initiator); + +#endif /** KEYMAT_V2_H_ @}*/ From 0fc9acdd235de4636da626e967f67e80a207879b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 17 Nov 2011 16:22:34 +0100 Subject: [PATCH 041/534] Added stub for IKEv1 keymat_t implementation. --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/keymat_v1.c | 130 +++++++++++++++++++++++++++++++++++ src/libcharon/sa/keymat_v1.h | 47 +++++++++++++ 3 files changed, 178 insertions(+) create mode 100644 src/libcharon/sa/keymat_v1.c create mode 100644 src/libcharon/sa/keymat_v1.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 6607bb017..c4ba18c5f 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -70,6 +70,7 @@ sa/ike_sa_manager.c sa/ike_sa_manager.h \ sa/task_manager.h sa/task_manager_v2.c sa/task_manager_v2.h \ sa/task_manager_v1.c sa/task_manager_v1.h \ sa/keymat.h sa/keymat_v2.c sa/keymat_v2.h \ +sa/keymat_v1.c sa/keymat_v1.h \ sa/shunt_manager.c sa/shunt_manager.h \ sa/trap_manager.c sa/trap_manager.h \ sa/tasks/child_create.c sa/tasks/child_create.h \ diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c new file mode 100644 index 000000000..f73366d43 --- /dev/null +++ b/src/libcharon/sa/keymat_v1.c @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "keymat_v1.h" + +#include + +typedef struct private_keymat_v1_t private_keymat_v1_t; + +/** + * Private data of an keymat_t object. + */ +struct private_keymat_v1_t { + + /** + * Public keymat_v1_t interface. + */ + keymat_v1_t public; + + /** + * IKE_SA Role, initiator or responder + */ + bool initiator; + + /** + * General purpose PRF + */ + prf_t *prf; + + /** + * Negotiated PRF algorithm + */ + pseudo_random_function_t prf_alg; + +}; + +METHOD(keymat_t, create_dh, diffie_hellman_t*, + private_keymat_v1_t *this, diffie_hellman_group_t group) +{ + return lib->crypto->create_dh(lib->crypto, group);; +} + +METHOD(keymat_t, derive_ike_keys, bool, + private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, + pseudo_random_function_t rekey_function, chunk_t rekey_skd) +{ + return FALSE; +} + +METHOD(keymat_t, derive_child_keys, bool, + private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r) +{ + return FALSE; +} + +METHOD(keymat_t, get_skd, pseudo_random_function_t, + private_keymat_v1_t *this, chunk_t *skd) +{ + *skd = chunk_empty; + return this->prf_alg; +} + +METHOD(keymat_t, get_aead, aead_t*, + private_keymat_v1_t *this, bool in) +{ + return NULL; +} + +METHOD(keymat_t, get_auth_octets, chunk_t, + private_keymat_v1_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, identification_t *id, char reserved[3]) +{ + return chunk_empty; +} + +METHOD(keymat_t, get_psk_sig, chunk_t, + private_keymat_v1_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, chunk_t secret, identification_t *id, char reserved[3]) +{ + return chunk_empty; +} + +METHOD(keymat_t, destroy, void, + private_keymat_v1_t *this) +{ + DESTROY_IF(this->prf); + free(this); +} + +/** + * See header + */ +keymat_v1_t *keymat_v1_create(bool initiator) +{ + private_keymat_v1_t *this; + + INIT(this, + .public = { + .keymat = { + .create_dh = _create_dh, + .derive_ike_keys = _derive_ike_keys, + .derive_child_keys = _derive_child_keys, + .get_skd = _get_skd, + .get_aead = _get_aead, + .get_auth_octets = _get_auth_octets, + .get_psk_sig = _get_psk_sig, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .prf_alg = PRF_UNDEFINED, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h new file mode 100644 index 000000000..68057fa06 --- /dev/null +++ b/src/libcharon/sa/keymat_v1.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup keymat_v1 keymat_v1 + * @{ @ingroup sa + */ + +#ifndef KEYMAT_V1_H_ +#define KEYMAT_V1_H_ + +#include + +typedef struct keymat_v1_t keymat_v1_t; + +/** + * Derivation and management of sensitive keying material, IKEv1 variant. + */ +struct keymat_v1_t { + + /** + * Implements keymat_t. + */ + keymat_t keymat; +}; + +/** + * Create a keymat instance. + * + * @param initiator TRUE if we are the initiator + * @return keymat instance + */ +keymat_v1_t *keymat_v1_create(bool initiator); + +#endif /** KEYMAT_V1_H_ @}*/ From 0b611540ef1f9587ffb1ab85c111ba6c4132d053 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 17 Nov 2011 16:26:52 +0100 Subject: [PATCH 042/534] Store IKE version of an SA on ike_sa_t. --- src/libcharon/plugins/ha/ha_dispatcher.c | 2 +- src/libcharon/sa/ike_sa.c | 18 ++++++++++++++++-- src/libcharon/sa/ike_sa.h | 14 ++++++++++---- src/libcharon/sa/ike_sa_manager.c | 13 ++++++++----- src/libcharon/sa/ike_sa_manager.h | 4 +++- src/libcharon/sa/tasks/ike_reauth.c | 5 ++++- src/libcharon/sa/tasks/ike_rekey.c | 9 ++++++--- 7 files changed, 48 insertions(+), 17 deletions(-) diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 0a89e640a..f430fee94 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -89,7 +89,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message switch (attribute) { case HA_IKE_ID: - ike_sa = ike_sa_create(value.ike_sa_id); + ike_sa = ike_sa_create(value.ike_sa_id, IKEV2); break; case HA_IKE_REKEY_ID: old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index ee3220d1b..b59586b8a 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -86,6 +86,11 @@ struct private_ike_sa_t { */ ike_sa_id_t *ike_sa_id; + /** + * IKE version of this SA. + */ + ike_version_t version; + /** * unique numerical ID for this IKE_SA. */ @@ -1328,6 +1333,12 @@ METHOD(ike_sa_t, get_id, ike_sa_id_t*, return this->ike_sa_id; } +METHOD(ike_sa_t, get_version, ike_version_t, + private_ike_sa_t *this) +{ + return this->version; +} + METHOD(ike_sa_t, get_my_id, identification_t*, private_ike_sa_t *this) { @@ -1606,7 +1617,8 @@ METHOD(ike_sa_t, reestablish, status_t, return FAILED; } - new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE); + new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, + this->version, TRUE); new->set_peer_cfg(new, this->peer_cfg); host = this->other_host; new->set_other_host(new, host->clone(host)); @@ -2105,13 +2117,14 @@ METHOD(ike_sa_t, destroy, void, /* * Described in header. */ -ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) +ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, ike_version_t version) { private_ike_sa_t *this; static u_int32_t unique_id = 0; INIT(this, .public = { + .get_version = _get_version, .get_state = _get_state, .set_state = _set_state, .get_name = _get_name, @@ -2191,6 +2204,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) #endif /* ME */ }, .ike_sa_id = ike_sa_id->clone(ike_sa_id), + .version = version, .child_sas = linked_list_create(), .my_host = host_create_any(AF_INET), .other_host = host_create_any(AF_INET), diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index cf23de300..21f7c7452 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -269,6 +269,11 @@ struct ike_sa_t { */ ike_sa_id_t* (*get_id) (ike_sa_t *this); + /** + * Gets the IKE version of the SA + */ + ike_version_t (*get_version)(ike_sa_t *this); + /** * Get the numerical ID uniquely defining this IKE_SA. * @@ -288,7 +293,7 @@ struct ike_sa_t { * * @param state state to set for the IKE_SA */ - void (*set_state) (ike_sa_t *this, ike_sa_state_t ike_sa); + void (*set_state) (ike_sa_t *this, ike_sa_state_t state); /** * Get the name of the connection this IKE_SA uses. @@ -951,11 +956,12 @@ struct ike_sa_t { }; /** - * Creates an ike_sa_t object with a specific ID. + * Creates an ike_sa_t object with a specific ID and IKE version. * - * @param ike_sa_id ike_sa_id_t object to associate with new IKE_SA + * @param ike_sa_id ike_sa_id_t to associate with new IKE_SA/ISAKMP_SA + * @param version IKE version of this SA * @return ike_sa_t object */ -ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id); +ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id, ike_version_t version); #endif /** IKE_SA_H_ @}*/ diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 6b2d17386..62f9cc971 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -941,7 +941,7 @@ METHOD(ike_sa_manager_t, checkout, ike_sa_t*, } METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, - private_ike_sa_manager_t* this, bool initiator) + private_ike_sa_manager_t* this, ike_version_t version, bool initiator) { ike_sa_id_t *ike_sa_id; ike_sa_t *ike_sa; @@ -954,7 +954,7 @@ METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, { ike_sa_id = ike_sa_id_create(0, get_spi(this), FALSE); } - ike_sa = ike_sa_create(ike_sa_id); + ike_sa = ike_sa_create(ike_sa_id, version); ike_sa_id->destroy(ike_sa_id); DBG2(DBG_MGR, "created IKE_SA %s[%u]", ike_sa->get_name(ike_sa), @@ -970,6 +970,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, entry_t *entry; ike_sa_t *ike_sa = NULL; ike_sa_id_t *id; + ike_version_t ike_version; bool is_init = FALSE; id = message->get_ike_sa_id(message); @@ -985,6 +986,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (message->get_exchange_type(message) == IKE_SA_INIT && message->get_request(message)) { + ike_version = IKEV2; is_init = TRUE; } } @@ -993,6 +995,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (message->get_exchange_type(message) == ID_PROT || message->get_exchange_type(message) == AGGRESSIVE) { + ike_version = IKEV1; is_init = TRUE; } } @@ -1034,7 +1037,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, /* no IKE_SA found, create a new one */ id->set_responder_spi(id, get_spi(this)); entry = entry_create(); - entry->ike_sa = ike_sa_create(id); + entry->ike_sa = ike_sa_create(id, ike_version); entry->ike_sa_id = id->clone(id); segment = put_entry(this, entry); @@ -1103,7 +1106,7 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*, if (!this->reuse_ikesa) { /* IKE_SA reuse disable by config */ - ike_sa = checkout_new(this, TRUE); + ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE); charon->bus->set_sa(charon->bus, ike_sa); return ike_sa; } @@ -1139,7 +1142,7 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*, if (!ike_sa) { /* no IKE_SA using such a config, hand out a new */ - ike_sa = checkout_new(this, TRUE); + ike_sa = checkout_new(this, peer_cfg->get_ike_version(peer_cfg), TRUE); } charon->bus->set_sa(charon->bus, ike_sa); return ike_sa; diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index 5e542e7df..bf75b76bb 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -52,10 +52,12 @@ struct ike_sa_manager_t { /** * Create and check out a new IKE_SA. * + * @param version IKE version of this SA * @param initiator TRUE for initiator, FALSE otherwise * @returns created and checked out IKE_SA */ - ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, bool initiator); + ike_sa_t* (*checkout_new) (ike_sa_manager_t* this, ike_version_t version, + bool initiator); /** * Checkout an IKE_SA by a message. diff --git a/src/libcharon/sa/tasks/ike_reauth.c b/src/libcharon/sa/tasks/ike_reauth.c index 6cda0dd25..197849d88 100644 --- a/src/libcharon/sa/tasks/ike_reauth.c +++ b/src/libcharon/sa/tasks/ike_reauth.c @@ -54,6 +54,7 @@ METHOD(task_t, process_i, status_t, ike_sa_t *new; host_t *host; enumerator_t *enumerator; + ike_version_t version; child_sa_t *child_sa; peer_cfg_t *peer_cfg; @@ -74,7 +75,9 @@ METHOD(task_t, process_i, status_t, return FAILED; } - new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, TRUE); + version = this->ike_sa->get_version(this->ike_sa); + new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, version, + TRUE); new->set_peer_cfg(new, peer_cfg); host = this->ike_sa->get_other_host(this->ike_sa); diff --git a/src/libcharon/sa/tasks/ike_rekey.c b/src/libcharon/sa/tasks/ike_rekey.c index 826d6e192..c089edab5 100644 --- a/src/libcharon/sa/tasks/ike_rekey.c +++ b/src/libcharon/sa/tasks/ike_rekey.c @@ -129,8 +129,9 @@ METHOD(task_t, build_i, status_t, /* create new SA only on first try */ if (this->new_sa == NULL) { - this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, - TRUE); + ike_version_t version = this->ike_sa->get_version(this->ike_sa); + this->new_sa = charon->ike_sa_manager->checkout_new( + charon->ike_sa_manager, version, TRUE); peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); other_host = this->ike_sa->get_other_host(this->ike_sa); @@ -148,6 +149,7 @@ METHOD(task_t, process_r, status_t, private_ike_rekey_t *this, message_t *message) { enumerator_t *enumerator; + ike_version_t version; peer_cfg_t *peer_cfg; child_sa_t *child_sa; @@ -175,8 +177,9 @@ METHOD(task_t, process_r, status_t, } enumerator->destroy(enumerator); + version = this->ike_sa->get_version(this->ike_sa); this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, - FALSE); + version, FALSE); peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); From 4b64a1a17d57586483a27d2ddcc4b3390f25ef94 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 17 Nov 2011 16:45:14 +0100 Subject: [PATCH 043/534] Added factory function to create keymat_t implementations. --- src/libcharon/Makefile.am | 2 +- src/libcharon/sa/ike_sa.c | 7 ++++--- src/libcharon/sa/keymat.c | 33 +++++++++++++++++++++++++++++++++ src/libcharon/sa/keymat.h | 14 ++++++++++++-- 4 files changed, 50 insertions(+), 6 deletions(-) create mode 100644 src/libcharon/sa/keymat.c diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index c4ba18c5f..5defff677 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -69,7 +69,7 @@ sa/ike_sa_id.c sa/ike_sa_id.h \ sa/ike_sa_manager.c sa/ike_sa_manager.h \ sa/task_manager.h sa/task_manager_v2.c sa/task_manager_v2.h \ sa/task_manager_v1.c sa/task_manager_v1.h \ -sa/keymat.h sa/keymat_v2.c sa/keymat_v2.h \ +sa/keymat.h sa/keymat.c sa/keymat_v2.c sa/keymat_v2.h \ sa/keymat_v1.c sa/keymat_v1.h \ sa/shunt_manager.c sa/shunt_manager.h \ sa/trap_manager.c sa/trap_manager.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index b59586b8a..e060c5a42 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -719,7 +718,8 @@ METHOD(ike_sa_t, reset, void, flush_auth_cfgs(this); this->keymat->destroy(this->keymat); - this->keymat = &(keymat_v2_create(this->ike_sa_id->is_initiator(this->ike_sa_id))->keymat); + this->keymat = keymat_create(this->version, + this->ike_sa_id->is_initiator(this->ike_sa_id)); this->task_manager->reset(this->task_manager, 0, 0); } @@ -2210,6 +2210,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, ike_version_t version) .other_host = host_create_any(AF_INET), .my_id = identification_create_from_encoding(ID_ANY, chunk_empty), .other_id = identification_create_from_encoding(ID_ANY, chunk_empty), + .keymat = keymat_create(version, ike_sa_id->is_initiator(ike_sa_id)), .state = IKE_CREATED, .stats[STAT_INBOUND] = time_monotonic(NULL), .stats[STAT_OUTBOUND] = time_monotonic(NULL), @@ -2223,7 +2224,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, ike_version_t version) .keepalive_interval = lib->settings->get_time(lib->settings, "charon.keep_alive", KEEPALIVE_INTERVAL), ); - this->keymat = &(keymat_v2_create(ike_sa_id->is_initiator(ike_sa_id))->keymat); + this->task_manager = &(task_manager_v2_create(&this->public)->task_manager); this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c new file mode 100644 index 000000000..7b5c95c1a --- /dev/null +++ b/src/libcharon/sa/keymat.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "keymat.h" +#include "keymat_v1.h" +#include "keymat_v2.h" + +/** + * See header + */ +keymat_t *keymat_create(ike_version_t version, bool initiator) +{ + switch (version) + { + case IKEV1: + return &keymat_v1_create(initiator)->keymat; + case IKEV2: + return &keymat_v2_create(initiator)->keymat; + } + return NULL; +} diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index c50d93322..7867898c1 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -21,15 +21,16 @@ #ifndef KEYMAT_H_ #define KEYMAT_H_ +typedef struct keymat_t keymat_t; + #include #include #include #include #include +#include /* for ike_version_t */ #include -typedef struct keymat_t keymat_t; - /** * Derivation an management of sensitive keying material. */ @@ -147,4 +148,13 @@ struct keymat_t { void (*destroy)(keymat_t *this); }; +/** + * Create the appropriate keymat_t implementation based on the IKE version. + * + * @param version requested IKE version + * @param initiator TRUE if we are initiator + * @return keymat_t implmenetation + */ +keymat_t *keymat_create(ike_version_t version, bool initiator); + #endif /** KEYMAT_H_ @}*/ From 273f2f80546a794141fd56b513c97985c629ab93 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 17 Nov 2011 16:54:25 +0100 Subject: [PATCH 044/534] Added factory function to create task_manager_t implementations. --- src/libcharon/Makefile.am | 2 +- src/libcharon/sa/ike_sa.c | 3 +-- src/libcharon/sa/task_manager.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 3 deletions(-) create mode 100644 src/libcharon/sa/task_manager.c diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 5defff677..9b9bac085 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -67,7 +67,7 @@ sa/child_sa.c sa/child_sa.h \ sa/ike_sa.c sa/ike_sa.h \ sa/ike_sa_id.c sa/ike_sa_id.h \ sa/ike_sa_manager.c sa/ike_sa_manager.h \ -sa/task_manager.h sa/task_manager_v2.c sa/task_manager_v2.h \ +sa/task_manager.h sa/task_manager.c sa/task_manager_v2.c sa/task_manager_v2.h \ sa/task_manager_v1.c sa/task_manager_v1.h \ sa/keymat.h sa/keymat.c sa/keymat_v2.c sa/keymat_v2.h \ sa/keymat_v1.c sa/keymat_v1.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index e060c5a42..36ceea121 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include @@ -2225,7 +2224,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, ike_version_t version) "charon.keep_alive", KEEPALIVE_INTERVAL), ); - this->task_manager = &(task_manager_v2_create(&this->public)->task_manager); + this->task_manager = task_manager_create(&this->public); this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); return &this->public; diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c new file mode 100644 index 000000000..eea2320e0 --- /dev/null +++ b/src/libcharon/sa/task_manager.c @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 "task_manager.h" +#include "task_manager_v1.h" +#include "task_manager_v2.h" + +/** + * See header + */ +task_manager_t *task_manager_create(ike_sa_t *ike_sa) +{ + switch (ike_sa->get_version(ike_sa)) + { + case IKEV1: + return &task_manager_v1_create(ike_sa)->task_manager; + case IKEV2: + return &task_manager_v2_create(ike_sa)->task_manager; + } + return NULL; +} From 043ed1b346fcc2130be8ff8a5a3bd503dfb1ac22 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 17 Nov 2011 17:06:14 +0100 Subject: [PATCH 045/534] Memory leak fixed. --- src/libcharon/sa/tasks/main_mode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 530568a8d..fa0ee259c 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -117,6 +117,7 @@ METHOD(task_t, process_r, status_t, list = sa_payload->get_proposals(sa_payload); this->proposal = this->config->select_proposal(this->config, list, FALSE); + list->destroy_offset(list, offsetof(proposal_t, destroy)); if (!this->proposal) { DBG1(DBG_IKE, "no proposal found"); From 04ee2b7fed91b4430ba4870a2f1b98ee3e228f50 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 18:01:41 +0100 Subject: [PATCH 046/534] Added IKEv1 support to notify payload --- src/conftest/hooks/add_notify.c | 2 +- src/conftest/hooks/unencrypted_notify.c | 2 +- src/libcharon/encoding/message.c | 29 +-- .../encoding/payloads/endpoint_notify.c | 2 +- .../encoding/payloads/notify_payload.c | 187 ++++++++++++------ .../encoding/payloads/notify_payload.h | 20 +- src/libcharon/encoding/payloads/payload.c | 7 +- src/libcharon/encoding/payloads/payload.h | 2 +- .../encoding/payloads/proposal_substructure.c | 4 +- src/libcharon/sa/tasks/child_rekey.c | 6 +- src/libcharon/sa/tasks/ike_natd.c | 2 +- 11 files changed, 177 insertions(+), 86 deletions(-) diff --git a/src/conftest/hooks/add_notify.c b/src/conftest/hooks/add_notify.c index de46ca81f..a9731960b 100644 --- a/src/conftest/hooks/add_notify.c +++ b/src/conftest/hooks/add_notify.c @@ -89,7 +89,7 @@ METHOD(listener_t, message, bool, { data = chunk_clone(chunk_create(this->data, strlen(this->data))); } - notify = notify_payload_create_from_protocol_and_type( + notify = notify_payload_create_from_protocol_and_type(NOTIFY, this->esp ? PROTO_ESP : PROTO_IKE, type); notify->set_spi(notify, this->spi); if (data.len) diff --git a/src/conftest/hooks/unencrypted_notify.c b/src/conftest/hooks/unencrypted_notify.c index 507f30cae..958e33e98 100644 --- a/src/conftest/hooks/unencrypted_notify.c +++ b/src/conftest/hooks/unencrypted_notify.c @@ -84,7 +84,7 @@ METHOD(listener_t, ike_updown, bool, { data = chunk_clone(chunk_create(this->data, strlen(this->data))); } - notify = notify_payload_create_from_protocol_and_type( + notify = notify_payload_create_from_protocol_and_type(NOTIFY, this->esp ? PROTO_ESP : PROTO_IKE, type); notify->set_spi(notify, this->spi); if (data.len) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 6640b7696..0789da4b7 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -425,7 +425,7 @@ static payload_order_t me_connect_r_order[] = { */ static payload_rule_t id_prot_i_rules[] = { /* payload type min max encr suff */ - {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, {NONCE_V1, 0, 1, FALSE, FALSE}, @@ -450,7 +450,7 @@ static payload_order_t id_prot_i_order[] = { {SIGNATURE_V1, 0}, {HASH_V1, 0}, {CERTIFICATE_REQUEST_V1, 0}, - {NOTIFICATION_V1, 0}, + {NOTIFY_V1, 0}, {VENDOR_ID_V1, 0}, }; @@ -459,7 +459,7 @@ static payload_order_t id_prot_i_order[] = { */ static payload_rule_t id_prot_r_rules[] = { /* payload type min max encr suff */ - {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, {NONCE_V1, 0, 1, FALSE, FALSE}, @@ -484,7 +484,7 @@ static payload_order_t id_prot_r_order[] = { {SIGNATURE_V1, 0}, {HASH_V1, 0}, {CERTIFICATE_REQUEST_V1, 0}, - {NOTIFICATION_V1, 0}, + {NOTIFY_V1, 0}, {VENDOR_ID_V1, 0}, }; @@ -493,7 +493,7 @@ static payload_order_t id_prot_r_order[] = { */ static payload_rule_t aggressive_i_rules[] = { /* payload type min max encr suff */ - {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, {NONCE_V1, 0, 1, FALSE, FALSE}, @@ -518,7 +518,7 @@ static payload_order_t aggressive_i_order[] = { {SIGNATURE_V1, 0}, {HASH_V1, 0}, {CERTIFICATE_REQUEST_V1, 0}, - {NOTIFICATION_V1, 0}, + {NOTIFY_V1, 0}, {VENDOR_ID_V1, 0}, }; @@ -527,7 +527,7 @@ static payload_order_t aggressive_i_order[] = { */ static payload_rule_t aggressive_r_rules[] = { /* payload type min max encr suff */ - {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, {NONCE_V1, 0, 1, FALSE, FALSE}, @@ -552,7 +552,7 @@ static payload_order_t aggressive_r_order[] = { {SIGNATURE_V1, 0}, {HASH_V1, 0}, {CERTIFICATE_REQUEST_V1, 0}, - {NOTIFICATION_V1, 0}, + {NOTIFY_V1, 0}, {VENDOR_ID_V1, 0}, }; @@ -561,7 +561,7 @@ static payload_order_t aggressive_r_order[] = { */ static payload_rule_t informational_i_rules_v1[] = { /* payload type min max encr suff */ - {NOTIFICATION_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, }; @@ -571,7 +571,7 @@ static payload_rule_t informational_i_rules_v1[] = { */ static payload_order_t informational_i_order_v1[] = { /* payload type notify type */ - {NOTIFICATION_V1, 0}, + {NOTIFY_V1, 0}, {DELETE_V1, 0}, {VENDOR_ID_V1, 0}, }; @@ -930,7 +930,14 @@ METHOD(message_t, add_notify, void, payload->destroy(payload); } } - notify = notify_payload_create(); + if (this->major_version == IKEV2_MAJOR_VERSION) + { + notify = notify_payload_create(NOTIFY); + } + else + { + notify = notify_payload_create(NOTIFY_V1); + } notify->set_notify_type(notify, type); notify->set_notification_data(notify, data); add_payload(this, (payload_t*)notify); diff --git a/src/libcharon/encoding/payloads/endpoint_notify.c b/src/libcharon/encoding/payloads/endpoint_notify.c index 1ead0a052..8dc1c1955 100644 --- a/src/libcharon/encoding/payloads/endpoint_notify.c +++ b/src/libcharon/encoding/payloads/endpoint_notify.c @@ -227,7 +227,7 @@ METHOD(endpoint_notify_t, build_notify, notify_payload_t*, chunk_t data; notify_payload_t *notify; - notify = notify_payload_create(); + notify = notify_payload_create(NOTIFICATION); notify->set_notify_type(notify, ME_ENDPOINT); data = build_notification_data(this); notify->set_notification_data(notify, data); diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index 7dab941b8..a5ffb0693 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -38,7 +38,8 @@ ENUM_NEXT(notify_type_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVALID_SPI"); ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, "NO_PROPOSAL_CHOSEN"); -ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, +ENUM_NEXT(notify_type_names, PAYLOAD_MALFORMED, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, + "PAYLOAD_MALFORMED", "INVALID_KE_PAYLOAD"); ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, "AUTHENTICATION_FAILED"); @@ -99,7 +100,9 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, IPSEC_REPLAY_COUNTER_SYNC, MS_NOTI "IKEV2_REPLAY_COUNTER_SYNC_SUPPORTED", "IKEV2_MESSAGE_ID_SYNC", "IPSEC_REPLAY_COUNTER_SYNC"); -ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, IPSEC_REPLAY_COUNTER_SYNC, +ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, IPSEC_REPLAY_COUNTER_SYNC, + "INITIAL_CONTACT"); +ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, INITIAL_CONTACT_IKEV1, "USE_BEET_MODE"); ENUM_NEXT(notify_type_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE, "ME_MEDIATION", @@ -125,7 +128,8 @@ ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVAL_SPI"); ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, "NO_PROP"); -ENUM_NEXT(notify_type_short_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, +ENUM_NEXT(notify_type_short_names, PAYLOAD_MALFORMED, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, + "PLD_MAL", "INVAL_KE"); ENUM_NEXT(notify_type_short_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, "AUTH_FAILED"); @@ -186,7 +190,9 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, IPSEC_REPLAY_COUNTER_SYNC, M "RPL_CTR_SYN_SUP", "MSG_ID_SYN", "RPL_CTR_SYN"); -ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, IPSEC_REPLAY_COUNTER_SYNC, +ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, IPSEC_REPLAY_COUNTER_SYNC, + "INITIAL_CONTACT"); +ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, INITIAL_CONTACT_IKEV1, "BEET_MODE"); ENUM_NEXT(notify_type_short_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE, "ME_MED", @@ -224,13 +230,18 @@ struct private_notify_payload_t { /** * reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. */ u_int16_t payload_length; + /** + * Domain of interpretation, IKEv1 only. + */ + u_int32_t doi; + /** * Protocol id. */ @@ -254,40 +265,42 @@ struct private_notify_payload_t { /** * Notification data. */ - chunk_t notification_data; + chunk_t notify_data; + + /** + * Type of payload, NOTIFY or NOTIFY_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a IKEv2-Notify Payload. - * - * The defined offsets are the positions in a object of type - * private_notify_payload_t. + * Encoding rules for an IKEv2 notification payload */ -static encoding_rule_t encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, + { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_notify_payload_t, critical) }, + { FLAG, offsetof(private_notify_payload_t, critical) }, /* 7 Bit reserved bits, nowhere stored */ - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) }, /* Length of the whole payload*/ - { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) }, + { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) }, /* Protocol ID as 8 bit field*/ - { U_INT_8, offsetof(private_notify_payload_t, protocol_id) }, + { U_INT_8, offsetof(private_notify_payload_t, protocol_id) }, /* SPI Size as 8 bit field*/ - { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) }, + { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) }, /* Notify message type as 16 bit field*/ - { U_INT_16, offsetof(private_notify_payload_t, notify_type) }, + { U_INT_16, offsetof(private_notify_payload_t, notify_type) }, /* SPI as variable length field*/ - { SPI, offsetof(private_notify_payload_t, spi) }, + { SPI, offsetof(private_notify_payload_t, spi) }, /* Key Exchange Data is from variable size */ - { CHUNK_DATA, offsetof(private_notify_payload_t, notification_data) } + { CHUNK_DATA, offsetof(private_notify_payload_t, notify_data) }, }; /* @@ -307,6 +320,57 @@ static encoding_rule_t encodings[] = { ! ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for an IKEv1 notification payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, + /* 8 reserved bits */ + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[7]) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) }, + /* DOI as 32 bit field*/ + { U_INT_32, offsetof(private_notify_payload_t, doi) }, + /* Protocol ID as 8 bit field*/ + { U_INT_8, offsetof(private_notify_payload_t, protocol_id) }, + /* SPI Size as 8 bit field*/ + { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) }, + /* Notify message type as 16 bit field*/ + { U_INT_16, offsetof(private_notify_payload_t, notify_type) }, + /* SPI as variable length field*/ + { SPI, offsetof(private_notify_payload_t, spi) }, + /* Key Exchange Data is from variable size */ + { CHUNK_DATA, offsetof(private_notify_payload_t, notify_data) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Protocol ID ! SPI Size ! Notify Message Type ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Security Parameter Index (SPI) ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Notification Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_notify_payload_t *this) @@ -329,7 +393,7 @@ METHOD(payload_t, verify, status_t, { case INVALID_KE_PAYLOAD: { - if (this->notification_data.len != 2) + if (this->notify_data.len != 2) { bad_length = TRUE; } @@ -339,7 +403,7 @@ METHOD(payload_t, verify, status_t, case NAT_DETECTION_DESTINATION_IP: case ME_CONNECTAUTH: { - if (this->notification_data.len != HASH_SIZE_SHA1) + if (this->notify_data.len != HASH_SIZE_SHA1) { bad_length = TRUE; } @@ -349,7 +413,7 @@ METHOD(payload_t, verify, status_t, case INVALID_MAJOR_VERSION: case NO_PROPOSAL_CHOSEN: { - if (this->notification_data.len != 0) + if (this->notify_data.len != 0) { bad_length = TRUE; } @@ -357,7 +421,7 @@ METHOD(payload_t, verify, status_t, } case ADDITIONAL_IP4_ADDRESS: { - if (this->notification_data.len != 4) + if (this->notify_data.len != 4) { bad_length = TRUE; } @@ -365,7 +429,7 @@ METHOD(payload_t, verify, status_t, } case ADDITIONAL_IP6_ADDRESS: { - if (this->notification_data.len != 16) + if (this->notify_data.len != 16) { bad_length = TRUE; } @@ -373,7 +437,7 @@ METHOD(payload_t, verify, status_t, } case AUTH_LIFETIME: { - if (this->notification_data.len != 4) + if (this->notify_data.len != 4) { bad_length = TRUE; } @@ -381,30 +445,30 @@ METHOD(payload_t, verify, status_t, } case IPCOMP_SUPPORTED: { - if (this->notification_data.len != 3) + if (this->notify_data.len != 3) { bad_length = TRUE; } break; } case ME_ENDPOINT: - if (this->notification_data.len != 8 && - this->notification_data.len != 12 && - this->notification_data.len != 24) + if (this->notify_data.len != 8 && + this->notify_data.len != 12 && + this->notify_data.len != 24) { bad_length = TRUE; } break; case ME_CONNECTID: - if (this->notification_data.len < 4 || - this->notification_data.len > 16) + if (this->notify_data.len < 4 || + this->notify_data.len > 16) { bad_length = TRUE; } break; case ME_CONNECTKEY: - if (this->notification_data.len < 16 || - this->notification_data.len > 32) + if (this->notify_data.len < 16 || + this->notify_data.len > 32) { bad_length = TRUE; } @@ -417,7 +481,7 @@ METHOD(payload_t, verify, status_t, { DBG1(DBG_ENC, "invalid notify data length for %N (%d)", notify_type_names, this->notify_type, - this->notification_data.len); + this->notify_data.len); return FAILED; } return SUCCESS; @@ -426,20 +490,29 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, int, private_notify_payload_t *this, encoding_rule_t **rules) { - *rules = encodings; - return countof(encodings); + if (this->type == NOTIFY) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); } METHOD(payload_t, get_header_length, int, private_notify_payload_t *this) { - return 8 + this->spi_size; + if (this->type == NOTIFY) + { + return 8 + this->spi_size; + } + return 12 + this->spi_size; } METHOD(payload_t, get_type, payload_type_t, private_notify_payload_t *this) { - return NOTIFY; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -459,7 +532,7 @@ METHOD(payload_t, set_next_type, void, */ static void compute_length(private_notify_payload_t *this) { - this->payload_length = get_header_length(this) + this->notification_data.len; + this->payload_length = get_header_length(this) + this->notify_data.len; } METHOD(payload_t, get_length, size_t, @@ -530,21 +603,21 @@ METHOD(notify_payload_t, set_spi, void, METHOD(notify_payload_t, get_notification_data, chunk_t, private_notify_payload_t *this) { - return this->notification_data; + return this->notify_data; } METHOD(notify_payload_t, set_notification_data, void, private_notify_payload_t *this, chunk_t data) { - free(this->notification_data.ptr); - this->notification_data = chunk_clone(data); + free(this->notify_data.ptr); + this->notify_data = chunk_clone(data); compute_length(this); } METHOD2(payload_t, notify_payload_t, destroy, void, private_notify_payload_t *this) { - free(this->notification_data.ptr); + free(this->notify_data.ptr); free(this->spi.ptr); free(this); } @@ -552,7 +625,7 @@ METHOD2(payload_t, notify_payload_t, destroy, void, /* * Described in header */ -notify_payload_t *notify_payload_create() +notify_payload_t *notify_payload_create(payload_type_t type) { private_notify_payload_t *this; @@ -578,7 +651,9 @@ notify_payload_t *notify_payload_create() .set_notification_data = _set_notification_data, .destroy = _destroy, }, + .doi = IKEV1_DOI_IPSEC, .next_payload = NO_PAYLOAD, + .type = type, ); compute_length(this); return &this->public; @@ -588,12 +663,12 @@ notify_payload_t *notify_payload_create() * Described in header. */ notify_payload_t *notify_payload_create_from_protocol_and_type( - protocol_id_t protocol_id, notify_type_t notify_type) + payload_type_t type, protocol_id_t protocol, notify_type_t notify) { - notify_payload_t *notify = notify_payload_create(); + notify_payload_t *this = notify_payload_create(type); - notify->set_notify_type(notify, notify_type); - notify->set_protocol_id(notify, protocol_id); + this->set_notify_type(this, notify); + this->set_protocol_id(this, protocol); - return notify; + return this; } diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index 91a3cac0f..1fc310962 100644 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -33,19 +33,23 @@ typedef struct notify_payload_t notify_payload_t; #include /** - * Notify message types. - * - * See IKEv2 RFC 3.10.1. + * Notify message types for IKEv2, and a subset for IKEv1. */ enum notify_type_t { /* notify error messages */ UNSUPPORTED_CRITICAL_PAYLOAD = 1, + /* IKEv1 alias */ + INVALID_PAYLOAD_TYPE = 1, INVALID_IKE_SPI = 4, INVALID_MAJOR_VERSION = 5, INVALID_SYNTAX = 7, + /* IKEv1 alias */ + INVALID_EXCHANGE_TYPE = 7, INVALID_MESSAGE_ID = 9, INVALID_SPI = 11, NO_PROPOSAL_CHOSEN = 14, + /* IKEv1 only */ + PAYLOAD_MALFORMED = 16, INVALID_KE_PAYLOAD = 17, AUTHENTICATION_FAILED = 24, SINGLE_PAIR_REQUIRED = 34, @@ -122,6 +126,8 @@ enum notify_type_t { IKEV2_REPLAY_COUNTER_SYNC_SUPPORTED = 16421, IKEV2_MESSAGE_ID_SYNC = 16422, IPSEC_REPLAY_COUNTER_SYNC = 16423, + /* IKEv1 initial contact */ + INITIAL_CONTACT_IKEV1 = 24578, /* BEET mode, not even a draft yet. private use */ USE_BEET_MODE = 40961, /* IKE-ME, private use */ @@ -229,18 +235,20 @@ struct notify_payload_t { /** * Creates an empty notify_payload_t object * + * @param type payload type, NOTIFY or NOTIFY_V1 * @return created notify_payload_t object */ -notify_payload_t *notify_payload_create(void); +notify_payload_t *notify_payload_create(payload_type_t type); /** * Creates an notify_payload_t object of specific type for specific protocol id. * - * @param protocol_id protocol id (IKE, AH or ESP) + * @param type payload type, NOTIFY or NOTIFY_V1 + * @param protocol protocol id (IKE, AH or ESP) * @param type notify type (see notify_type_t) * @return notify_payload_t object */ notify_payload_t *notify_payload_create_from_protocol_and_type( - protocol_id_t protocol_id, notify_type_t type); + payload_type_t type, protocol_id_t protocol, notify_type_t notify); #endif /** NOTIFY_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 014d3c525..95f1601ed 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -50,7 +50,7 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, VENDOR_ID_V1, NO_PAYLOAD, "HASH_V1", "SIGNATURE_V1", "NONCE_V1", - "NOTIFICATION_V1", + "NOTIFY_V1", "DELETE_V1", "VENDOR_ID_V1"); ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, VENDOR_ID_V1, @@ -111,7 +111,7 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION_V1, VENDOR_ID_V1, NO_PA "HASH", "SIG", "No", - "NO", + "N", "D", "V"); ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, VENDOR_ID_V1, @@ -205,7 +205,8 @@ payload_t *payload_create(payload_type_t type) case KEY_EXCHANGE_V1: return (payload_t*)ke_payload_create(type); case NOTIFY: - return (payload_t*)notify_payload_create(); + case NOTIFY_V1: + return (payload_t*)notify_payload_create(type); case DELETE: return (payload_t*)delete_payload_create(0); case VENDOR_ID: diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index 0060e3730..84871cfb6 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -100,7 +100,7 @@ enum payload_type_t { /** * Notification payload. */ - NOTIFICATION_V1 = 11, + NOTIFY_V1 = 11, /** * Delete payload. diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index aa3f0674f..20f4e223d 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -780,10 +780,10 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, } enumerator->destroy(enumerator); - /* TODO-IKEv1: Add lifetime, non-fixed auth-method and other attributes */ + /* TODO-IKEv1: Add lifetime, non-fixed auth-method and other attributes transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_PSK)); + TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_PSK));*/ add_transform_substructure(this, transform); } diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/tasks/child_rekey.c index 76d185590..bcdf093b8 100644 --- a/src/libcharon/sa/tasks/child_rekey.c +++ b/src/libcharon/sa/tasks/child_rekey.c @@ -153,8 +153,8 @@ METHOD(task_t, build_i, status_t, config = this->child_sa->get_config(this->child_sa); /* we just need the rekey notify ... */ - notify = notify_payload_create_from_protocol_and_type(this->protocol, - REKEY_SA); + notify = notify_payload_create_from_protocol_and_type(NOTIFY, + this->protocol, REKEY_SA); notify->set_spi(notify, this->spi); message->add_payload(message, (payload_t*)notify); @@ -462,7 +462,7 @@ child_rekey_t *child_rekey_create(ike_sa_t *ike_sa, protocol_id_t protocol, .protocol = protocol, .spi = spi, ); - + if (protocol != PROTO_NONE) { this->public.task.build = _build_i; diff --git a/src/libcharon/sa/tasks/ike_natd.c b/src/libcharon/sa/tasks/ike_natd.c index f06a518fa..6b658f8b1 100644 --- a/src/libcharon/sa/tasks/ike_natd.c +++ b/src/libcharon/sa/tasks/ike_natd.c @@ -152,7 +152,7 @@ static notify_payload_t *build_natd_payload(private_ike_natd_t *this, { hash = generate_natd_hash(this, ike_sa_id, host); } - notify = notify_payload_create(); + notify = notify_payload_create(NOTIFY); notify->set_notify_type(notify, type); notify->set_notification_data(notify, hash); chunk_free(&hash); From cf6cd5aa4b55a1f6e9df37acf466d229fc728ace Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 17 Nov 2011 18:14:51 +0100 Subject: [PATCH 047/534] Added IKEv1 support to delete payload --- .../encoding/payloads/delete_payload.c | 87 ++++++++++++++++--- .../encoding/payloads/delete_payload.h | 8 +- src/libcharon/encoding/payloads/payload.c | 3 +- src/libcharon/sa/tasks/child_delete.c | 4 +- src/libcharon/sa/tasks/ike_delete.c | 2 +- 5 files changed, 83 insertions(+), 21 deletions(-) diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index 425bde0c3..7cf14cd25 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -24,9 +24,9 @@ typedef struct private_delete_payload_t private_delete_payload_t; /** * Private data of an delete_payload_t object. - * */ struct private_delete_payload_t { + /** * Public delete_payload_t interface. */ @@ -45,13 +45,18 @@ struct private_delete_payload_t { /** * reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. */ u_int16_t payload_length; + /** + * IKEv1 Domain of Interpretation + */ + u_int32_t doi; + /** * Protocol ID. */ @@ -71,15 +76,17 @@ struct private_delete_payload_t { * The contained SPI's. */ chunk_t spis; + + /** + * Payload type, DELETE or DELETE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a DELETE payload - * - * The defined offsets are the positions in a object of type - * private_delete_payload_t. + * Encoding rules for an IKEv2 delete payload. */ -static encoding_rule_t encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, /* the critical bit */ @@ -98,7 +105,7 @@ static encoding_rule_t encodings[] = { { U_INT_8, offsetof(private_delete_payload_t, spi_size) }, { U_INT_16, offsetof(private_delete_payload_t, spi_count) }, /* some delete data bytes, length is defined in PAYLOAD_LENGTH */ - { CHUNK_DATA, offsetof(private_delete_payload_t, spis) } + { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, }; /* @@ -115,6 +122,48 @@ static encoding_rule_t encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for an IKEv1 delete payload. + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, + /* 8 Bit reserved bits */ + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[7]) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length) }, + /* Domain of interpretation */ + { U_INT_32, offsetof(private_delete_payload_t, doi) }, + { U_INT_8, offsetof(private_delete_payload_t, protocol_id) }, + { U_INT_8, offsetof(private_delete_payload_t, spi_size) }, + { U_INT_16, offsetof(private_delete_payload_t, spi_count) }, + /* some delete data bytes, length is defined in PAYLOAD_LENGTH */ + { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload !C! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Protocol ID ! SPI Size ! # of SPIs ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Security Parameter Index(es) (SPI) ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_delete_payload_t *this) { @@ -148,20 +197,29 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, int, private_delete_payload_t *this, encoding_rule_t **rules) { - *rules = encodings; - return countof(encodings); + if (this->type == DELETE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); } METHOD(payload_t, get_header_length, int, private_delete_payload_t *this) { - return 8; + if (this->type == DELETE) + { + return 8; + } + return 12; } METHOD(payload_t, get_payload_type, payload_type_t, private_delete_payload_t *this) { - return DELETE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -255,7 +313,8 @@ METHOD2(payload_t, delete_payload_t, destroy, void, /* * Described in header */ -delete_payload_t *delete_payload_create(protocol_id_t protocol_id) +delete_payload_t *delete_payload_create(payload_type_t type, + protocol_id_t protocol_id) { private_delete_payload_t *this; @@ -278,8 +337,10 @@ delete_payload_t *delete_payload_create(protocol_id_t protocol_id) }, .next_payload = NO_PAYLOAD, .payload_length = get_header_length(this), + .doi = IKEV1_DOI_IPSEC, .protocol_id = protocol_id, .spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0, + .type = type, ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/delete_payload.h b/src/libcharon/encoding/payloads/delete_payload.h index ebafe04fb..0ee0d4f7a 100644 --- a/src/libcharon/encoding/payloads/delete_payload.h +++ b/src/libcharon/encoding/payloads/delete_payload.h @@ -29,9 +29,7 @@ typedef struct delete_payload_t delete_payload_t; #include /** - * Class representing an IKEv2 DELETE payload. - * - * The DELETE payload format is described in RFC section 3.11. + * Class representing an IKEv1 or a IKEv2 DELETE payload. */ struct delete_payload_t { @@ -70,9 +68,11 @@ struct delete_payload_t { /** * Creates an empty delete_payload_t object. * + * @param type DELETE or DELETE_V1 * @param protocol_id protocol, such as AH|ESP * @return delete_payload_t object */ -delete_payload_t *delete_payload_create(protocol_id_t protocol_id); +delete_payload_t *delete_payload_create(payload_type_t type, + protocol_id_t protocol_id); #endif /** DELETE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 95f1601ed..9dc26773a 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -208,7 +208,8 @@ payload_t *payload_create(payload_type_t type) case NOTIFY_V1: return (payload_t*)notify_payload_create(type); case DELETE: - return (payload_t*)delete_payload_create(0); + case DELETE_V1: + return (payload_t*)delete_payload_create(type, 0); case VENDOR_ID: case VENDOR_ID_V1: return (payload_t*)vendor_id_payload_create(type); diff --git a/src/libcharon/sa/tasks/child_delete.c b/src/libcharon/sa/tasks/child_delete.c index dc4b30dd3..e73074675 100644 --- a/src/libcharon/sa/tasks/child_delete.c +++ b/src/libcharon/sa/tasks/child_delete.c @@ -87,7 +87,7 @@ static void build_payloads(private_child_delete_t *this, message_t *message) case PROTO_ESP: if (esp == NULL) { - esp = delete_payload_create(PROTO_ESP); + esp = delete_payload_create(DELETE, PROTO_ESP); message->add_payload(message, (payload_t*)esp); } esp->add_spi(esp, spi); @@ -97,7 +97,7 @@ static void build_payloads(private_child_delete_t *this, message_t *message) case PROTO_AH: if (ah == NULL) { - ah = delete_payload_create(PROTO_AH); + ah = delete_payload_create(DELETE, PROTO_AH); message->add_payload(message, (payload_t*)ah); } ah->add_spi(ah, spi); diff --git a/src/libcharon/sa/tasks/ike_delete.c b/src/libcharon/sa/tasks/ike_delete.c index 8f253ce6b..fc24a6e94 100644 --- a/src/libcharon/sa/tasks/ike_delete.c +++ b/src/libcharon/sa/tasks/ike_delete.c @@ -65,7 +65,7 @@ METHOD(task_t, build_i, status_t, this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); - delete_payload = delete_payload_create(PROTO_IKE); + delete_payload = delete_payload_create(DELETE, PROTO_IKE); message->add_payload(message, (payload_t*)delete_payload); if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING) From 72b3146092fdf426a13fbc50f10b2cfab5ecd9c4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 09:16:54 +0100 Subject: [PATCH 048/534] Re-enable static inclusion of PSK auth method into IKEv1 proposal --- src/libcharon/encoding/payloads/proposal_substructure.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 20f4e223d..aa3f0674f 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -780,10 +780,10 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, } enumerator->destroy(enumerator); - /* TODO-IKEv1: Add lifetime, non-fixed auth-method and other attributes + /* TODO-IKEv1: Add lifetime, non-fixed auth-method and other attributes */ transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_PSK));*/ + TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_PSK)); add_transform_substructure(this, transform); } From 558f79f76d624d4f47df2b1668ad6d8492100b89 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 09:50:22 +0100 Subject: [PATCH 049/534] Added missing task manager factory declaration --- src/libcharon/sa/task_manager.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index b6cf5404c..42a04fb64 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -194,4 +194,12 @@ struct task_manager_t { void (*destroy) (task_manager_t *this); }; +/** + * Create a task manager instance for the correct IKE version. + * + * @param ike_sa IKE_SA to create a task manager for + * @return task manager implementation for IKE version + */ +task_manager_t *task_manager_create(ike_sa_t *ike_sa); + #endif /** TASK_MANAGER_H_ @}*/ From cf1772f68544828e13be59415262995e85ef3436 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 10:08:18 +0100 Subject: [PATCH 050/534] Do not ignore configs for IKEv1 in charon anymore --- src/libcharon/plugins/smp/smp.c | 5 ---- src/libcharon/plugins/stroke/stroke_control.c | 24 ------------------- src/libcharon/plugins/stroke/stroke_list.c | 3 +-- .../processing/jobs/start_action_job.c | 5 ---- src/starter/confread.c | 2 +- src/starter/starter.c | 18 +++++--------- 6 files changed, 8 insertions(+), 49 deletions(-) diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c index 2743b7224..0db287480 100644 --- a/src/libcharon/plugins/smp/smp.c +++ b/src/libcharon/plugins/smp/smp.c @@ -302,11 +302,6 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write ike_cfg_t *ike_cfg; linked_list_t *list; - if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) - { /* only IKEv2 connections yet */ - continue; - } - /* */ xmlTextWriterStartElement(writer, "peerconfig"); xmlTextWriterWriteElement(writer, "name", peer_cfg->get_name(peer_cfg)); diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index 5897862c3..98f57b56c 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -126,14 +126,6 @@ METHOD(stroke_control_t, initiate, void, msg->initiate.name); if (peer_cfg) { - if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) - { - DBG1(DBG_CFG, "ignoring initiation request for %N config", - ike_version_names, peer_cfg->get_ike_version(peer_cfg)); - peer_cfg->destroy(peer_cfg); - return; - } - child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name); if (child_cfg == NULL) { @@ -161,10 +153,6 @@ METHOD(stroke_control_t, initiate, void, NULL, NULL, NULL, NULL); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) - { - continue; - } child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name); if (child_cfg) { @@ -568,14 +556,6 @@ METHOD(stroke_control_t, route, void, msg->route.name); if (peer_cfg) { - if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) - { - DBG1(DBG_CFG, "ignoring initiation request for %N config", - ike_version_names, peer_cfg->get_ike_version(peer_cfg)); - peer_cfg->destroy(peer_cfg); - return; - } - child_cfg = get_child_from_peer(peer_cfg, msg->route.name); if (child_cfg == NULL) { @@ -603,10 +583,6 @@ METHOD(stroke_control_t, route, void, NULL, NULL, NULL, NULL); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) - { - continue; - } child_cfg = get_child_from_peer(peer_cfg, msg->route.name); if (child_cfg) { diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index 4145a7962..2246e748d 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -489,8 +489,7 @@ METHOD(stroke_list_t, status, void, charon->backends, NULL, NULL, NULL, NULL); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != IKEV2 || - (name && !streq(name, peer_cfg->get_name(peer_cfg)))) + if (name && !streq(name, peer_cfg->get_name(peer_cfg))) { continue; } diff --git a/src/libcharon/processing/jobs/start_action_job.c b/src/libcharon/processing/jobs/start_action_job.c index 0019a1145..efb53acea 100644 --- a/src/libcharon/processing/jobs/start_action_job.c +++ b/src/libcharon/processing/jobs/start_action_job.c @@ -49,11 +49,6 @@ METHOD(job_t, execute, void, NULL, NULL, NULL, NULL); while (enumerator->enumerate(enumerator, &peer_cfg)) { - if (peer_cfg->get_ike_version(peer_cfg) != IKEV2) - { - continue; - } - children = peer_cfg->create_child_cfg_enumerator(peer_cfg); while (children->enumerate(children, &child_cfg)) { diff --git a/src/starter/confread.c b/src/starter/confread.c index 089be1aa5..1da4eb025 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -466,7 +466,7 @@ static void handle_dns_failure(const char *label, starter_end_t *end, plog("# fallback to %s=%%any due to '%%' prefix or %sallowany=yes", label, label); } - else if (!end->host || conn->keyexchange == KEY_EXCHANGE_IKEV1) + else if (!end->host) { /* declare an error */ cfg->err++; diff --git a/src/starter/starter.c b/src/starter/starter.c index 44e21431c..15c50c44b 100644 --- a/src/starter/starter.c +++ b/src/starter/starter.c @@ -764,14 +764,11 @@ int main (int argc, char **argv) if (conn->startup == STARTUP_START) { - if (conn->keyexchange != KEY_EXCHANGE_IKEV1) + if (starter_charon_pid()) { - if (starter_charon_pid()) - { - starter_stroke_initiate_conn(conn); - } + starter_stroke_initiate_conn(conn); } - else + if (conn->keyexchange == KEY_EXCHANGE_IKEV1) { if (starter_pluto_pid()) { @@ -781,14 +778,11 @@ int main (int argc, char **argv) } else if (conn->startup == STARTUP_ROUTE) { - if (conn->keyexchange != KEY_EXCHANGE_IKEV1) + if (starter_charon_pid()) { - if (starter_charon_pid()) - { - starter_stroke_route_conn(conn); - } + starter_stroke_route_conn(conn); } - else + if (conn->keyexchange == KEY_EXCHANGE_IKEV1) { if (starter_pluto_pid()) { From 9cc63d2cf070338ef7b4c4e35348b2ee314a1cc9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 10:55:23 +0100 Subject: [PATCH 051/534] Added enum name for MAIN_MODE task --- src/libcharon/sa/tasks/task.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index 0d7383141..fae9c7b59 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -17,7 +17,7 @@ #include "task.h" #ifdef ME -ENUM(task_type_names, IKE_INIT, CHILD_REKEY, +ENUM(task_type_names, IKE_INIT, MAIN_MODE, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", @@ -35,9 +35,10 @@ ENUM(task_type_names, IKE_INIT, CHILD_REKEY, "CHILD_CREATE", "CHILD_DELETE", "CHILD_REKEY", + "MAIN_MODE", ); #else -ENUM(task_type_names, IKE_INIT, CHILD_REKEY, +ENUM(task_type_names, IKE_INIT, MAIN_MODE, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", @@ -54,5 +55,6 @@ ENUM(task_type_names, IKE_INIT, CHILD_REKEY, "CHILD_CREATE", "CHILD_DELETE", "CHILD_REKEY", + "MAIN_MODE", ); #endif /* ME */ From 26b55dc6c84cbe165a47728d376c652f157723c2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 10:56:02 +0100 Subject: [PATCH 052/534] Implemented first two exchanges of Main Mode as initiator --- src/libcharon/sa/ike_sa.c | 70 ++++++---- src/libcharon/sa/task_manager_v1.c | 210 ++++++++++++++++++++++++++++- src/libcharon/sa/tasks/main_mode.c | 136 +++++++++++++++++-- 3 files changed, 376 insertions(+), 40 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 36ceea121..e7478bd38 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -1129,31 +1130,39 @@ METHOD(ike_sa_t, initiate, status_t, set_condition(this, COND_ORIGINAL_INITIATOR, TRUE); - task = (task_t*)ike_vendor_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_init_create(&this->public, TRUE, NULL); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_natd_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_pre_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_auth_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_post_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_config_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - if (this->peer_cfg->use_mobike(this->peer_cfg)) + if (this->version == IKEV1) { - task = (task_t*)ike_mobike_create(&this->public, TRUE); + task = (task_t*)main_mode_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); } + else + { + task = (task_t*)ike_vendor_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_init_create(&this->public, TRUE, NULL); + this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_natd_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_cert_pre_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_auth_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_cert_post_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_config_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); + if (this->peer_cfg->use_mobike(this->peer_cfg)) + { + task = (task_t*)ike_mobike_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); + } #ifdef ME - task = (task_t*)ike_me_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_me_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); #endif /* ME */ + } } #ifdef ME @@ -1172,15 +1181,22 @@ METHOD(ike_sa_t, initiate, status_t, #endif /* ME */ { /* normal IKE_SA with CHILD_SA */ - task = (task_t*)child_create_create(&this->public, child_cfg, FALSE, - tsi, tsr); - child_cfg->destroy(child_cfg); - if (reqid) + if (this->version == IKEV2) { - child_create_t *child_create = (child_create_t*)task; - child_create->use_reqid(child_create, reqid); + task = (task_t*)child_create_create(&this->public, child_cfg, FALSE, + tsi, tsr); + if (reqid) + { + child_create_t *child_create = (child_create_t*)task; + child_create->use_reqid(child_create, reqid); + } + this->task_manager->queue_task(this->task_manager, task); } - this->task_manager->queue_task(this->task_manager, task); + else + { + /* TODO-IKEv1: create quick mode task */ + } + child_cfg->destroy(child_cfg); #ifdef ME if (this->peer_cfg->get_mediated_by(this->peer_cfg)) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 7eb81fc44..99263aa5d 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -154,10 +154,155 @@ METHOD(task_manager_t, retransmit, status_t, return FAILED; } +/** + * move a task of a specific type from the queue to the active list + */ +static bool activate_task(private_task_manager_t *this, task_type_t type) +{ + enumerator_t *enumerator; + task_t *task; + bool found = FALSE; + + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) + { + if (task->get_type(task) == type) + { + DBG2(DBG_IKE, " activating %N task", task_type_names, type); + this->queued_tasks->remove_at(this->queued_tasks, enumerator); + this->active_tasks->insert_last(this->active_tasks, task); + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + METHOD(task_manager_t, initiate, status_t, private_task_manager_t *this) { - return FAILED; + enumerator_t *enumerator; + task_t *task; + message_t *message; + host_t *me, *other; + status_t status; + exchange_type_t exchange = 0; + + if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED) + { + DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress", + exchange_type_names, this->initiating.type); + /* do not initiate if we already have a message in the air */ + return SUCCESS; + } + + if (this->active_tasks->get_count(this->active_tasks) == 0) + { + DBG2(DBG_IKE, "activating new tasks"); + switch (this->ike_sa->get_state(this->ike_sa)) + { + case IKE_CREATED: + if (activate_task(this, MAIN_MODE)) + { + exchange = ID_PROT; + } + break; + default: + break; + } + } + else + { + DBG2(DBG_IKE, "reinitiating already active tasks"); + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) + { + DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); + switch (task->get_type(task)) + { + case MAIN_MODE: + exchange = ID_PROT; + break; + default: + continue; + } + break; + } + enumerator->destroy(enumerator); + } + + if (exchange == 0) + { + DBG2(DBG_IKE, "nothing to initiate"); + /* nothing to do yet... */ + return SUCCESS; + } + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + + message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); + if (exchange != ID_PROT) + { + /* TODO-IKEv1: Set random message id */ + } + message->set_source(message, me->clone(me)); + message->set_destination(message, other->clone(other)); + message->set_exchange_type(message, exchange); + this->initiating.type = exchange; + this->initiating.retransmitted = 0; + + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->build(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + task->destroy(task); + break; + case NEED_MORE: + /* processed, but task needs another exchange */ + break; + case FAILED: + default: + if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) + { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + } + /* FALL */ + case DESTROY_ME: + /* critical failure, destroy IKE_SA */ + enumerator->destroy(enumerator); + message->destroy(message); + flush(this); + return DESTROY_ME; + } + } + enumerator->destroy(enumerator); + + /* update exchange type if a task changed it */ + this->initiating.type = message->get_exchange_type(message); + + status = this->ike_sa->generate_message(this->ike_sa, message, + &this->initiating.packet); + if (status != SUCCESS) + { + /* message generation failed. There is nothing more to do than to + * close the SA */ + message->destroy(message); + flush(this); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; + } + message->destroy(message); + + charon->sender->send(charon->sender, + this->initiating.packet->clone(this->initiating.packet)); + + return SUCCESS; } /** @@ -310,11 +455,62 @@ static status_t process_request(private_task_manager_t *this, return build_response(this, message); } +/** + * handle an incoming response message + */ +static status_t process_response(private_task_manager_t *this, + message_t *message) +{ + enumerator_t *enumerator; + task_t *task; + + if (message->get_exchange_type(message) != this->initiating.type) + { + DBG1(DBG_IKE, "received %N response, but expected %N", + exchange_type_names, message->get_exchange_type(message), + exchange_type_names, this->initiating.type); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; + } + + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void*)&task)) + { + switch (task->process(task, message)) + { + case SUCCESS: + /* task completed, remove it */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + task->destroy(task); + break; + case NEED_MORE: + /* processed, but task needs another exchange */ + break; + case FAILED: + default: + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + /* FALL */ + case DESTROY_ME: + /* critical failure, destroy IKE_SA */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + enumerator->destroy(enumerator); + task->destroy(task); + return DESTROY_ME; + } + } + enumerator->destroy(enumerator); + + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + this->initiating.packet->destroy(this->initiating.packet); + this->initiating.packet = NULL; + + return initiate(this); +} + METHOD(task_manager_t, process_message, status_t, private_task_manager_t *this, message_t *msg) { - /* TODO-IKEv1: detect request/response */ - if (TRUE) + if (this->active_tasks->get_count(this->active_tasks) == 0) { /* TODO-IKEv1: detect mainmode retransmission */ charon->bus->message(charon->bus, msg, TRUE); @@ -326,8 +522,12 @@ METHOD(task_manager_t, process_message, status_t, } else { - /* TODO-IKEv1: handle response */ - return DESTROY_ME; + charon->bus->message(charon->bus, msg, FALSE); + if (process_response(this, msg) != SUCCESS) + { + flush(this); + return DESTROY_ME; + } } return SUCCESS; } diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index fa0ee259c..d2e89210f 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -48,7 +48,7 @@ struct private_main_mode_t { /** * IKE config to establish */ - ike_cfg_t *config; + ike_cfg_t *ike_cfg; /** * selected IKE proposal @@ -87,8 +87,74 @@ struct private_main_mode_t { METHOD(task_t, build_i, status_t, private_main_mode_t *this, message_t *message) { - /* TODO-IKEv1: initiate mainmode */ - return FAILED; + switch (this->state) + { + case MM_INIT: + { + sa_payload_t *sa_payload; + linked_list_t *proposals; + + this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + proposals = this->ike_cfg->get_proposals(this->ike_cfg); + + sa_payload = sa_payload_create_from_proposal_list( + SECURITY_ASSOCIATION_V1, proposals); + proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); + + message->add_payload(message, &sa_payload->payload_interface); + + this->state = MM_SA; + return NEED_MORE; + } + case MM_SA: + { + ke_payload_t *ke_payload; + nonce_payload_t *nonce_payload; + u_int16_t group; + rng_t *rng; + + if (!this->proposal->get_algorithm(this->proposal, + DIFFIE_HELLMAN_GROUP, &group, NULL)) + { + DBG1(DBG_IKE, "DH group selection failed"); + return FAILED; + } + this->dh = lib->crypto->create_dh(lib->crypto, group); + if (!this->dh) + { + DBG1(DBG_IKE, "negotiated DH group not supported"); + return FAILED; + } + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, + this->dh); + message->add_payload(message, &ke_payload->payload_interface); + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "no RNG found to create nonce"); + return FAILED; + } + /* TODO-IKEv1: nonce size? */ + rng->allocate_bytes(rng, 20, &this->nonce_i); + rng->destroy(rng); + + nonce_payload = nonce_payload_create(NONCE_V1); + nonce_payload->set_nonce(nonce_payload, this->nonce_i); + message->add_payload(message, &nonce_payload->payload_interface); + + this->state = MM_KE; + return NEED_MORE; + } + default: + return FAILED; + } } METHOD(task_t, process_r, status_t, @@ -102,7 +168,7 @@ METHOD(task_t, process_r, status_t, linked_list_t *list; sa_payload_t *sa_payload; - this->config = this->ike_sa->get_ike_cfg(this->ike_sa); + this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); DBG0(DBG_IKE, "%H is initiating a Main Mode", message->get_source(message)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); @@ -115,8 +181,8 @@ METHOD(task_t, process_r, status_t, return FAILED; } list = sa_payload->get_proposals(sa_payload); - this->proposal = this->config->select_proposal(this->config, - list, FALSE); + this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, + list, FALSE); list->destroy_offset(list, offsetof(proposal_t, destroy)); if (!this->proposal) { @@ -222,8 +288,62 @@ METHOD(task_t, build_r, status_t, METHOD(task_t, process_i, status_t, private_main_mode_t *this, message_t *message) { - /* TODO-IKEv1: process main mode as initiator */ - return FAILED; + switch (this->state) + { + case MM_SA: + { + linked_list_t *list; + sa_payload_t *sa_payload; + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return FAILED; + } + list = sa_payload->get_proposals(sa_payload); + this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, + list, FALSE); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no proposal found"); + return FAILED; + } + return NEED_MORE; + } + case MM_KE: + { + ke_payload_t *ke_payload; + nonce_payload_t *nonce_payload; + + ke_payload = (ke_payload_t*)message->get_payload(message, + KEY_EXCHANGE_V1); + if (!ke_payload) + { + DBG1(DBG_IKE, "KE payload missing"); + return FAILED; + } + this->dh_value = ke_payload->get_key_exchange_data(ke_payload); + this->dh_value = chunk_clone(this->dh_value); + this->dh->set_other_public_value(this->dh, this->dh_value); + + nonce_payload = (nonce_payload_t*)message->get_payload(message, + NONCE_V1); + if (!nonce_payload) + { + DBG1(DBG_IKE, "Nonce payload missing"); + return FAILED; + } + this->nonce_r = nonce_payload->get_nonce(nonce_payload); + /* TODO-IKEv1: verify nonce length */ + + return NEED_MORE; + } + default: + return FAILED; + } } METHOD(task_t, get_type, task_type_t, From 764ee21d83fa93aedaf6effbc841a55d7340f2e7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 14:30:15 +0100 Subject: [PATCH 053/534] ts.get_subnet() returns TRUE if the selector actually is a subnet --- src/libstrongswan/selectors/traffic_selector.c | 6 ++++-- src/libstrongswan/selectors/traffic_selector.h | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libstrongswan/selectors/traffic_selector.c b/src/libstrongswan/selectors/traffic_selector.c index b1bcf1b2d..8b862a8dc 100644 --- a/src/libstrongswan/selectors/traffic_selector.c +++ b/src/libstrongswan/selectors/traffic_selector.c @@ -571,7 +571,7 @@ METHOD(traffic_selector_t, includes, bool, return FALSE; } -METHOD(traffic_selector_t, to_subnet, void, +METHOD(traffic_selector_t, to_subnet, bool, private_traffic_selector_t *this, host_t **net, u_int8_t *mask) { /* there is no way to do this cleanly, as the address range may @@ -597,7 +597,7 @@ METHOD(traffic_selector_t, to_subnet, void, break; default: /* unreachable */ - return; + return FALSE; } net_chunk.ptr = malloc(net_chunk.len); @@ -616,6 +616,8 @@ METHOD(traffic_selector_t, to_subnet, void, *net = host_create_from_chunk(family, net_chunk, port); chunk_free(&net_chunk); + + return this->netbits != NON_SUBNET_ADDRESS_RANGE; } METHOD(traffic_selector_t, clone_, traffic_selector_t*, diff --git a/src/libstrongswan/selectors/traffic_selector.h b/src/libstrongswan/selectors/traffic_selector.h index 257da3f24..67b5da5bf 100644 --- a/src/libstrongswan/selectors/traffic_selector.h +++ b/src/libstrongswan/selectors/traffic_selector.h @@ -203,8 +203,9 @@ struct traffic_selector_t { * * @param net converted subnet (has to be freed) * @param mask converted net mask + * @return TRUE if traffic selector matches exactly to the subnet */ - void (*to_subnet) (traffic_selector_t *this, host_t **net, u_int8_t *mask); + bool (*to_subnet) (traffic_selector_t *this, host_t **net, u_int8_t *mask); /** * Destroys the ts object From e4a8fd72cb5e1c8ceb0b9573cd24efaa4bff2627 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 14:31:13 +0100 Subject: [PATCH 054/534] Added IKEv1 ID payload <-> traffic selector conversion functions --- src/libcharon/encoding/payloads/id_payload.c | 146 ++++++++++++++++++- src/libcharon/encoding/payloads/id_payload.h | 16 ++ 2 files changed, 158 insertions(+), 4 deletions(-) diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index 108d56bd8..dec08de00 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -161,14 +161,26 @@ static encoding_rule_t encodings_v1[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ - METHOD(payload_t, verify, status_t, private_id_payload_t *this) { - if (this->id_type == 0 || this->id_type == 4) + bool bad_length = FALSE; + + switch (this->id_type) { - /* reserved IDs */ - DBG1(DBG_ENC, "received ID with reserved type %d", this->id_type); + case ID_IPV4_ADDR_RANGE: + case ID_IPV4_ADDR_SUBNET: + bad_length = this->id_data.len != 8; + break; + case ID_IPV6_ADDR_RANGE: + case ID_IPV6_ADDR_SUBNET: + bad_length = this->id_data.len != 32; + break; + } + if (bad_length) + { + DBG1(DBG_ENC, "invalid %N length (%d bytes)", + id_type_names, this->id_type, this->id_data.len); return FAILED; } return SUCCESS; @@ -222,6 +234,71 @@ METHOD(id_payload_t, get_identification, identification_t*, return identification_create_from_encoding(this->id_type, this->id_data); } +/** + * Create a traffic selector from an range ID + */ +static traffic_selector_t *get_ts_from_range(private_id_payload_t *this, + ts_type_t type) +{ + return traffic_selector_create_from_bytes(this->protocol_id, type, + chunk_create(this->id_data.ptr, this->id_data.len / 2), this->port, + chunk_skip(this->id_data, this->id_data.len / 2), this->port ?: 65535); +} + +/** + * Create a traffic selector from an subnet ID + */ +static traffic_selector_t *get_ts_from_subnet(private_id_payload_t *this, + ts_type_t type) +{ + chunk_t net, netmask; + int i; + + net = chunk_create(this->id_data.ptr, this->id_data.len / 2); + netmask = chunk_skip(this->id_data, this->id_data.len / 2); + for (i = 0; i < net.len; i++) + { + netmask.ptr[i] = (netmask.ptr[i] ^ 0xFF) | net.ptr[i]; + } + return traffic_selector_create_from_bytes(this->protocol_id, type, + net, this->port, netmask, this->port ?: 65535); +} + +METHOD(id_payload_t, get_ts, traffic_selector_t*, + private_id_payload_t *this) +{ + switch (this->id_type) + { + case ID_IPV4_ADDR_SUBNET: + if (this->id_data.len == 8) + { + return get_ts_from_subnet(this, TS_IPV4_ADDR_RANGE); + } + break; + case ID_IPV6_ADDR_SUBNET: + if (this->id_data.len == 32) + { + return get_ts_from_subnet(this, TS_IPV6_ADDR_RANGE); + } + break; + case ID_IPV4_ADDR_RANGE: + if (this->id_data.len == 8) + { + return get_ts_from_range(this, TS_IPV4_ADDR_RANGE); + } + break; + case ID_IPV6_ADDR_RANGE: + if (this->id_data.len == 32) + { + return get_ts_from_range(this, TS_IPV6_ADDR_RANGE); + } + break; + default: + break; + } + return NULL; +} + METHOD2(payload_t, id_payload_t, destroy, void, private_id_payload_t *this) { @@ -249,6 +326,7 @@ id_payload_t *id_payload_create(payload_type_t type) .destroy = _destroy, }, .get_identification = _get_identification, + .get_ts = _get_ts, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, @@ -273,3 +351,63 @@ id_payload_t *id_payload_create_from_identification(payload_type_t type, return &this->public; } + +/* + * Described in header. + */ +id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts) +{ + private_id_payload_t *this; + u_int8_t mask; + host_t *net; + + this = (private_id_payload_t*)id_payload_create(ID_V1); + + if (ts->to_subnet(ts, &net, &mask)) + { + u_int8_t netmask[16], len, byte; + + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) + { + this->id_type = ID_IPV4_ADDR_SUBNET; + len = 4; + } + else + { + this->id_type = ID_IPV6_ADDR_SUBNET; + len = 16; + } + memset(netmask, 0, sizeof(netmask)); + for (byte = 0; byte < sizeof(netmask); byte++) + { + if (mask < 8) + { + netmask[byte] = 0xFF << (8 - mask); + break; + } + netmask[byte] = 0xFF; + mask -= 8; + } + this->id_data = chunk_cat("cc", net->get_address(net), + chunk_create(netmask, len)); + } + else + { + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) + { + this->id_type = ID_IPV4_ADDR_RANGE; + } + else + { + this->id_type = ID_IPV6_ADDR_RANGE; + } + this->id_data = chunk_cat("cc", + ts->get_from_address(ts), ts->get_to_address(ts)); + } + this->port = ts->get_from_port(ts); + this->protocol_id = ts->get_protocol(ts); + + net->destroy(net); + + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h index 8ae90d20f..bc6920012 100644 --- a/src/libcharon/encoding/payloads/id_payload.h +++ b/src/libcharon/encoding/payloads/id_payload.h @@ -28,6 +28,7 @@ typedef struct id_payload_t id_payload_t; #include #include #include +#include /** * Object representing an IKEv1 or an IKEv2 ID payload. @@ -46,6 +47,13 @@ struct id_payload_t { */ identification_t *(*get_identification) (id_payload_t *this); + /** + * Creates a traffic selector form a ID_ADDR_SUBNET/RANGE identity. + * + * @return traffic selector, NULL on failure + */ + traffic_selector_t* (*get_ts)(id_payload_t *this); + /** * Destroys an id_payload_t object. */ @@ -70,4 +78,12 @@ id_payload_t *id_payload_create(payload_type_t payload_type); id_payload_t *id_payload_create_from_identification(payload_type_t type, identification_t *id); +/** + * Create an IKEv1 ID_ADDR_SUBNET/RANGE identity from a traffic selector. + * + * @param ts traffic selector + * @return ID_V1 id_paylad_t object. + */ +id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts); + #endif /** ID_PAYLOAD_H_ @}*/ From 6c2b7d4ed9befd4f9e573a2c75c32eaefe8eca19 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 16:12:15 +0100 Subject: [PATCH 055/534] Partially implemented third main mode exchange (identities) --- src/libcharon/sa/tasks/main_mode.c | 186 ++++++++++++++++++++++++++++- 1 file changed, 184 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index d2e89210f..4468482af 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -22,6 +22,7 @@ #include #include #include +#include typedef struct private_main_mode_t private_main_mode_t; @@ -50,6 +51,21 @@ struct private_main_mode_t { */ ike_cfg_t *ike_cfg; + /** + * Peer config to use + */ + peer_cfg_t *peer_cfg; + + /** + * Local authentication configuration + */ + auth_cfg_t *my_auth; + + /** + * Remote authentication configuration + */ + auth_cfg_t *other_auth; + /** * selected IKE proposal */ @@ -80,10 +96,24 @@ struct private_main_mode_t { MM_INIT, MM_SA, MM_KE, - MM_ID, + MM_AUTH, } state; }; +/** + * Get the first authentcation config from peer config + */ +static auth_cfg_t *get_auth_cfg(private_main_mode_t *this, bool local) +{ + enumerator_t *enumerator; + auth_cfg_t *cfg = NULL; + + enumerator = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, + local); + enumerator->enumerate(enumerator, &cfg); + return cfg; +} + METHOD(task_t, build_i, status_t, private_main_mode_t *this, message_t *message) { @@ -152,12 +182,44 @@ METHOD(task_t, build_i, status_t, this->state = MM_KE; return NEED_MORE; } + case MM_KE: + { + id_payload_t *id_payload; + identification_t *id; + + this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->peer_cfg->get_ref(this->peer_cfg); + + this->my_auth = get_auth_cfg(this, TRUE); + this->other_auth = get_auth_cfg(this, FALSE); + if (!this->my_auth || !this->other_auth) + { + DBG1(DBG_CFG, "no auth config found"); + return FAILED; + } + id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY); + if (!id) + { + DBG1(DBG_CFG, "own identity not known"); + return FAILED; + } + + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); + + id_payload = id_payload_create_from_identification(ID_V1, id); + message->add_payload(message, &id_payload->payload_interface); + + /* TODO-IKEv1: authenticate */ + + this->state = MM_AUTH; + return NEED_MORE; + } default: return FAILED; } } -METHOD(task_t, process_r, status_t, +METHOD(task_t, process_r, status_t, private_main_mode_t *this, message_t *message) { switch (this->state) @@ -173,6 +235,10 @@ METHOD(task_t, process_r, status_t, message->get_source(message)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + this->ike_sa->update_hosts(this->ike_sa, + message->get_destination(message), + message->get_source(message), TRUE); + sa_payload = (sa_payload_t*)message->get_payload(message, SECURITY_ASSOCIATION_V1); if (!sa_payload) @@ -236,6 +302,55 @@ METHOD(task_t, process_r, status_t, this->state = MM_KE; return NEED_MORE; } + case MM_KE: + { + enumerator_t *enumerator; + id_payload_t *id_payload; + identification_t *id, *any; + + id_payload = (id_payload_t*)message->get_payload(message, ID_V1); + if (!id_payload) + { + DBG1(DBG_IKE, "IDii payload missing"); + return FAILED; + } + + id = id_payload->get_identification(id_payload); + any = identification_create_from_encoding(ID_ANY, chunk_empty); + enumerator = charon->backends->create_peer_cfg_enumerator( + charon->backends, + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + any, id); + if (!enumerator->enumerate(enumerator, &this->peer_cfg)) + { + DBG1(DBG_IKE, "no peer config found"); + id->destroy(id); + any->destroy(any); + enumerator->destroy(enumerator); + return FAILED; + } + this->peer_cfg->get_ref(this->peer_cfg); + enumerator->destroy(enumerator); + any->destroy(any); + + this->ike_sa->set_other_id(this->ike_sa, id); + + this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); + + this->my_auth = get_auth_cfg(this, TRUE); + this->other_auth = get_auth_cfg(this, FALSE); + if (!this->my_auth || !this->other_auth) + { + DBG1(DBG_CFG, "auth config missing"); + return FAILED; + } + + /* TODO-IKEv1: authenticate peer */ + + this->state = MM_AUTH; + return NEED_MORE; + } default: return FAILED; } @@ -280,6 +395,37 @@ METHOD(task_t, build_r, status_t, message->add_payload(message, &nonce_payload->payload_interface); return NEED_MORE; } + case MM_AUTH: + { + id_payload_t *id_payload; + identification_t *id; + + id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY); + if (!id) + { + DBG1(DBG_CFG, "own identity not known"); + return FAILED; + } + + this->ike_sa->set_my_id(this->ike_sa, id); + + id_payload = id_payload_create_from_identification(ID_V1, id); + message->add_payload(message, &id_payload->payload_interface); + + /* TODO-IKEv1: authenticate us */ + + /* TODO-IKEv1: check for XAUTH rounds, queue them */ + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + return SUCCESS; + } default: return FAILED; } @@ -341,6 +487,41 @@ METHOD(task_t, process_i, status_t, return NEED_MORE; } + case MM_AUTH: + { + id_payload_t *id_payload; + identification_t *id; + + id_payload = (id_payload_t*)message->get_payload(message, ID_V1); + if (!id_payload) + { + DBG1(DBG_IKE, "IDir payload missing"); + return FAILED; + } + id = id_payload->get_identification(id_payload); + if (!id->matches(id, this->other_auth->get(this->other_auth, + AUTH_RULE_IDENTITY))) + { + DBG1(DBG_IKE, "IDir does not match"); + id->destroy(id); + return FAILED; + } + this->ike_sa->set_other_id(this->ike_sa, id); + + /* TODO-IKEv1: verify auth */ + + /* TODO-IKEv1: check for XAUTH rounds, queue them */ + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + return SUCCESS; + } default: return FAILED; } @@ -361,6 +542,7 @@ METHOD(task_t, migrate, void, METHOD(task_t, destroy, void, private_main_mode_t *this) { + DESTROY_IF(this->peer_cfg); DESTROY_IF(this->proposal); DESTROY_IF(this->dh); free(this->dh_value.ptr); From 31fc14e394203be67a711801819a73a7365f9800 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 17:14:36 +0100 Subject: [PATCH 056/534] Verify IKEv1 nonce size, send 32 byte nonces --- .../encoding/payloads/nonce_payload.c | 21 ++++++++++++++++++- src/libcharon/sa/tasks/main_mode.c | 8 ++----- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/libcharon/encoding/payloads/nonce_payload.c b/src/libcharon/encoding/payloads/nonce_payload.c index 58ef70a0e..3c5eeb535 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.c +++ b/src/libcharon/encoding/payloads/nonce_payload.c @@ -19,6 +19,7 @@ #include "nonce_payload.h" +#include #include typedef struct private_nonce_payload_t private_nonce_payload_t; @@ -103,8 +104,26 @@ static encoding_rule_t encodings[] = { METHOD(payload_t, verify, status_t, private_nonce_payload_t *this) { - if (this->nonce.len < 16 || this->nonce.len > 256) + bool bad_length = FALSE; + + if (this->nonce.len > 256) { + bad_length = TRUE; + } + if (this->type == NONCE && + this->nonce.len < 16) + { + bad_length = TRUE; + } + if (this->type == NONCE_V1 && + this->nonce.len < 8) + { + bad_length = TRUE; + } + if (bad_length) + { + DBG1(DBG_ENC, "%N payload has invalid length (%d bytes)", + payload_type_names, this->type, this->nonce.len); return FAILED; } return SUCCESS; diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 4468482af..2de9c0e9f 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -171,8 +171,7 @@ METHOD(task_t, build_i, status_t, DBG1(DBG_IKE, "no RNG found to create nonce"); return FAILED; } - /* TODO-IKEv1: nonce size? */ - rng->allocate_bytes(rng, 20, &this->nonce_i); + rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_i); rng->destroy(rng); nonce_payload = nonce_payload_create(NONCE_V1); @@ -297,7 +296,6 @@ METHOD(task_t, process_r, status_t, return FAILED; } this->nonce_i = nonce_payload->get_nonce(nonce_payload); - /* TODO-IKEv1: verify nonce length */ this->state = MM_KE; return NEED_MORE; @@ -386,8 +384,7 @@ METHOD(task_t, build_r, status_t, DBG1(DBG_IKE, "no RNG found to create nonce"); return FAILED; } - /* TODO-IKEv1: nonce size? */ - rng->allocate_bytes(rng, 20, &this->nonce_r); + rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_r); rng->destroy(rng); nonce_payload = nonce_payload_create(NONCE_V1); @@ -483,7 +480,6 @@ METHOD(task_t, process_i, status_t, return FAILED; } this->nonce_r = nonce_payload->get_nonce(nonce_payload); - /* TODO-IKEv1: verify nonce length */ return NEED_MORE; } From c311d22d0f62b68bf0e69c110d94b569788c0fd3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 18 Nov 2011 17:49:53 +0100 Subject: [PATCH 057/534] Don't clone chunk in message.get_packet_data --- src/conftest/hooks/pretend_auth.c | 2 +- src/libcharon/encoding/message.c | 2 +- src/libcharon/encoding/message.h | 4 ++-- src/libcharon/sa/ike_sa_manager.c | 7 +++---- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c index dd6ab9959..ff99900f2 100644 --- a/src/conftest/hooks/pretend_auth.c +++ b/src/conftest/hooks/pretend_auth.c @@ -135,7 +135,7 @@ static void process_auth_request(private_pretend_auth_t *this, static void process_init_response(private_pretend_auth_t *this, ike_sa_t *ike_sa, message_t *message) { - this->ike_init = message->get_packet_data(message); + this->ike_init = chunk_clone(message->get_packet_data(message)); } /** diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 0789da4b7..afa9b1956 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1404,7 +1404,7 @@ METHOD(message_t, get_packet_data, chunk_t, { return chunk_empty; } - return chunk_clone(this->packet->get_data(this->packet)); + return this->packet->get_data(this->packet); } METHOD(message_t, parse_header, status_t, diff --git a/src/libcharon/encoding/message.h b/src/libcharon/encoding/message.h index 20f3c16d7..dd18b4bd9 100644 --- a/src/libcharon/encoding/message.h +++ b/src/libcharon/encoding/message.h @@ -344,9 +344,9 @@ struct message_t { packet_t * (*get_packet) (message_t *this); /** - * Returns a clone of the internal stored packet_t data. + * Returns a chunk pointing to internal packet_t data. * - * @return clone of the internal stored packet_t data. + * @return packet data. */ chunk_t (*get_packet_data) (message_t *this); diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 62f9cc971..556459064 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1004,11 +1004,10 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (is_init && this->hasher) { /* First request. Check for an IKE_SA with such a message hash. */ - chunk_t data, hash; + chunk_t hash; - data = message->get_packet_data(message); - this->hasher->allocate_hash(this->hasher, data, &hash); - chunk_free(&data); + this->hasher->allocate_hash(this->hasher, + message->get_packet_data(message), &hash); if (get_entry_by_hash(this, id, hash, &entry, &segment) == SUCCESS) { From 5f1aef65ceb800401f5ff699b827651f4cd8e302 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 09:10:50 +0100 Subject: [PATCH 058/534] Fixed proposal numbering check in sa_payload --- src/libcharon/encoding/payloads/sa_payload.c | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 29c671d8e..7433f1ad1 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -174,16 +174,6 @@ METHOD(payload_t, verify, status_t, { current_number = substruct->get_proposal_number(substruct); if (current_number < expected_number) - { - if (current_number != expected_number + 1) - { - DBG1(DBG_ENC, "proposal number is %d, expected %d or %d", - current_number, expected_number, expected_number + 1); - status = FAILED; - break; - } - } - else if (current_number < expected_number) { DBG1(DBG_ENC, "proposal number smaller than previous"); status = FAILED; From 5789320f5c34b07a1ea36543f43922ec3fb9fd2d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 10:10:29 +0100 Subject: [PATCH 059/534] Fix rule selection in transform substructure --- src/libcharon/encoding/payloads/transform_substructure.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c index 9ee8b48db..a4a920b60 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.c +++ b/src/libcharon/encoding/payloads/transform_substructure.c @@ -167,7 +167,7 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, int, private_transform_substructure_t *this, encoding_rule_t **rules) { - if (this->type == TRANSFORM_ATTRIBUTE) + if (this->type == TRANSFORM_SUBSTRUCTURE) { *rules = encodings_v2; return countof(encodings_v2); From 4ea258538e396949b6c8c626e80bf8cc3c191dc3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 10:10:48 +0100 Subject: [PATCH 060/534] Update header length after each parsed rule, as it might change when parsing SPI size --- src/libcharon/encoding/parser.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index e599b84d9..39ce2db67 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -380,12 +380,13 @@ METHOD(parser_t, parse_payload, status_t, /* base pointer for output, avoids casting in every rule */ output = pld; - - header_length = pld->get_header_length(pld); /* parse the payload with its own rulse */ rule_count = pld->get_encoding_rules(pld, &this->rules); for (rule_number = 0; rule_number < rule_count; rule_number++) { + /* update header length for each rule, as it is dynamic (SPIs) */ + header_length = pld->get_header_length(pld); + rule = &(this->rules[rule_number]); DBG2(DBG_ENC, " parsing rule %d %N", rule_number, encoding_type_names, rule->type); From cbb6d765bc29963f3faaf945e4b321204a2f6cd2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 10:22:50 +0100 Subject: [PATCH 061/534] Fixed length calculation of delete payload --- src/libcharon/encoding/payloads/delete_payload.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index 7cf14cd25..f5bdb3809 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -211,9 +211,9 @@ METHOD(payload_t, get_header_length, int, { if (this->type == DELETE) { - return 8; + return 8 + this->spi_size; } - return 12; + return 12 + this->spi_size; } METHOD(payload_t, get_payload_type, payload_type_t, @@ -255,6 +255,7 @@ METHOD(delete_payload_t, add_spi, void, case PROTO_ESP: this->spi_count++; this->payload_length += sizeof(spi); + this->spi_size += sizeof(spi); this->spis = chunk_cat("mc", this->spis, chunk_from_thing(spi)); break; default: @@ -336,11 +337,12 @@ delete_payload_t *delete_payload_create(payload_type_t type, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = get_header_length(this), .doi = IKEV1_DOI_IPSEC, .protocol_id = protocol_id, .spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0, .type = type, ); + this->payload_length = get_header_length(this); + return &this->public; } From 2b04aa46ea3cbfa9e1d013e10ebbfe268a803232 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 11:20:34 +0100 Subject: [PATCH 062/534] Added a quick mode task stub --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/tasks/quick_mode.c | 164 ++++++++++++++++++++++++++++ src/libcharon/sa/tasks/quick_mode.h | 52 +++++++++ src/libcharon/sa/tasks/task.c | 6 +- src/libcharon/sa/tasks/task.h | 2 + 5 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 src/libcharon/sa/tasks/quick_mode.c create mode 100644 src/libcharon/sa/tasks/quick_mode.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 9b9bac085..e3c73a879 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -90,6 +90,7 @@ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ +sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ sa/tasks/task.c sa/tasks/task.h daemon.lo : $(top_builddir)/config.status diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c new file mode 100644 index 000000000..5db02b241 --- /dev/null +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "quick_mode.h" + +#include + +#include + +typedef struct private_quick_mode_t private_quick_mode_t; + +/** + * Private members of a quick_mode_t task. + */ +struct private_quick_mode_t { + + /** + * Public methods and task_t interface. + */ + quick_mode_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Traffic selector of initiator + */ + traffic_selector_t *tsi; + + /** + * Traffic selector of responder + */ + traffic_selector_t *tsr; + + /** + * Initiators nonce + */ + chunk_t nonce_i; + + /** + * Responder nonce + */ + chunk_t nonce_r; + + /** + * selected CHILD_SA proposal + */ + proposal_t *proposal; + + /** + * Config of CHILD_SA to establish + */ + child_cfg_t *config; + + /** + * CHILD_SA we are about to establish + */ + child_sa_t *child_sa; + + /** states of quick mode */ + enum { + QM_INIT, + } state; +}; + +METHOD(task_t, build_i, status_t, + private_quick_mode_t *this, message_t *message) +{ + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_quick_mode_t *this, message_t *message) +{ + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_quick_mode_t *this, message_t *message) +{ + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_quick_mode_t *this, message_t *message) +{ + return SUCCESS; +} + +METHOD(task_t, get_type, task_type_t, + private_quick_mode_t *this) +{ + return TASK_QUICK_MODE; +} + +METHOD(task_t, migrate, void, + private_quick_mode_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_quick_mode_t *this) +{ + chunk_free(&this->nonce_i); + chunk_free(&this->nonce_r); + DESTROY_IF(this->tsi); + DESTROY_IF(this->tsr); + DESTROY_IF(this->proposal); + DESTROY_IF(this->child_sa); + DESTROY_IF(this->config); + free(this); +} + +/* + * Described in header. + */ +quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, + traffic_selector_t *tsi, traffic_selector_t *tsr) +{ + private_quick_mode_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .tsi = tsi ? tsi->clone(tsi) : NULL, + .tsr = tsr ? tsr->clone(tsr) : NULL, + .config = config, + .state = QM_INIT, + ); + + if (config) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/tasks/quick_mode.h b/src/libcharon/sa/tasks/quick_mode.h new file mode 100644 index 000000000..358296c2e --- /dev/null +++ b/src/libcharon/sa/tasks/quick_mode.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup quick_mode quick_mode + * @{ @ingroup tasks + */ + +#ifndef QUICK_MODE_H_ +#define QUICK_MODE_H_ + +typedef struct quick_mode_t quick_mode_t; + +#include +#include +#include + +/** + * IKEv1 quick mode, establishes a CHILD_SA in IKEv1. + */ +struct quick_mode_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new quick_mode task. + * + * @param config child_cfg if task initiator, NULL if responder + * @param tsi source of triggering packet, or NULL + * @param tsr destination of triggering packet, or NULL + * @return task to handle by the task_manager + */ +quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, + traffic_selector_t *tsi, traffic_selector_t *tsr); + +#endif /** QUICK_MODE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index fae9c7b59..2889409af 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -17,7 +17,7 @@ #include "task.h" #ifdef ME -ENUM(task_type_names, IKE_INIT, MAIN_MODE, +ENUM(task_type_names, IKE_INIT, TASK_QUICK_MODE, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", @@ -36,9 +36,10 @@ ENUM(task_type_names, IKE_INIT, MAIN_MODE, "CHILD_DELETE", "CHILD_REKEY", "MAIN_MODE", + "QUICK_MODE", ); #else -ENUM(task_type_names, IKE_INIT, MAIN_MODE, +ENUM(task_type_names, IKE_INIT, TASK_QUICK_MODE, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", @@ -56,5 +57,6 @@ ENUM(task_type_names, IKE_INIT, MAIN_MODE, "CHILD_DELETE", "CHILD_REKEY", "MAIN_MODE", + "QUICK_MODE", ); #endif /* ME */ diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 6ceb2690f..8d78053ad 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -71,6 +71,8 @@ enum task_type_t { CHILD_REKEY, /** IKEv1 main mode */ MAIN_MODE, + /** IKEv1 quick mode */ + TASK_QUICK_MODE, }; /** From 73aaf76be31dbdb2c6ed697dafc5606e8100ecc9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 11:21:21 +0100 Subject: [PATCH 063/534] Implemented basic message id handling for IKEv1 --- src/libcharon/sa/task_manager_v1.c | 81 +++++++++++++++++++----------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 99263aa5d..41976986e 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -54,6 +54,11 @@ struct private_task_manager_t { */ ike_sa_t *ike_sa; + /** + * RNG to create message IDs + */ + rng_t *rng; + /** * Exchange we are currently handling as responder */ @@ -111,11 +116,6 @@ struct private_task_manager_t { */ linked_list_t *passive_tasks; - /** - * the task manager has been reset - */ - bool reset; - /** * Number of times we retransmit messages before giving up */ @@ -187,7 +187,13 @@ METHOD(task_manager_t, initiate, status_t, message_t *message; host_t *me, *other; status_t status; - exchange_type_t exchange = 0; + exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED; + + if (!this->rng) + { + DBG1(DBG_IKE, "no RNG supported"); + return FAILED; + } if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED) { @@ -232,7 +238,7 @@ METHOD(task_manager_t, initiate, status_t, enumerator->destroy(enumerator); } - if (exchange == 0) + if (exchange == EXCHANGE_TYPE_UNDEFINED) { DBG2(DBG_IKE, "nothing to initiate"); /* nothing to do yet... */ @@ -245,7 +251,9 @@ METHOD(task_manager_t, initiate, status_t, message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); if (exchange != ID_PROT) { - /* TODO-IKEv1: Set random message id */ + this->rng->get_bytes(this->rng, sizeof(this->initiating.mid), + (void*)&this->initiating.mid); + message->set_message_id(message, this->initiating.mid); } message->set_source(message, me->clone(me)); message->set_destination(message, other->clone(other)); @@ -333,7 +341,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) /* send response along the path the request came in */ message->set_source(message, me->clone(me)); message->set_destination(message, other->clone(other)); - message->set_message_id(message, this->responding.mid); + message->set_message_id(message, request->get_message_id(request)); message->set_request(message, FALSE); enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); @@ -510,17 +518,14 @@ static status_t process_response(private_task_manager_t *this, METHOD(task_manager_t, process_message, status_t, private_task_manager_t *this, message_t *msg) { - if (this->active_tasks->get_count(this->active_tasks) == 0) - { - /* TODO-IKEv1: detect mainmode retransmission */ - charon->bus->message(charon->bus, msg, TRUE); - if (process_request(this, msg) != SUCCESS) - { - flush(this); - return DESTROY_ME; - } - } - else + u_int32_t hash, mid; + + mid = msg->get_message_id(msg); + hash = chunk_hash(msg->get_packet_data(msg)); + + if ((mid && mid == this->initiating.mid) || + (this->initiating.mid == 0 && + this->active_tasks->get_count(this->active_tasks))) { charon->bus->message(charon->bus, msg, FALSE); if (process_response(this, msg) != SUCCESS) @@ -529,6 +534,31 @@ METHOD(task_manager_t, process_message, status_t, return DESTROY_ME; } } + else + { + if ((mid && mid == this->responding.mid) || + hash == this->responding.mid) + { + DBG1(DBG_IKE, "received retransmit of request with ID %d, " + "retransmitting response", mid); + charon->sender->send(charon->sender, + this->responding.packet->clone(this->responding.packet)); + return SUCCESS; + } + + charon->bus->message(charon->bus, msg, TRUE); + if (process_request(this, msg) != SUCCESS) + { + flush(this); + return DESTROY_ME; + } + + if (!mid) + { + mid = hash; + } + this->responding.mid = mid; + } return SUCCESS; } @@ -564,20 +594,11 @@ METHOD(task_manager_t, busy, bool, METHOD(task_manager_t, incr_mid, void, private_task_manager_t *this, bool initiate) { - if (initiate) - { - this->initiating.mid++; - } - else - { - this->responding.mid++; - } } METHOD(task_manager_t, reset, void, private_task_manager_t *this, u_int32_t initiate, u_int32_t respond) { - } METHOD(task_manager_t, create_task_enumerator, enumerator_t*, @@ -607,6 +628,7 @@ METHOD(task_manager_t, destroy, void, DESTROY_IF(this->responding.packet); DESTROY_IF(this->initiating.packet); + DESTROY_IF(this->rng); free(this); } @@ -634,6 +656,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) }, .ike_sa = ike_sa, .initiating.type = EXCHANGE_TYPE_UNDEFINED, + .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK), .queued_tasks = linked_list_create(), .active_tasks = linked_list_create(), .passive_tasks = linked_list_create(), From 9124e3425baad91166b23707c061299a8f135300 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 11:42:53 +0100 Subject: [PATCH 064/534] Fixed reference counting bugs in main mode --- src/libcharon/sa/tasks/main_mode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 2de9c0e9f..4d0c570d9 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -111,6 +111,7 @@ static auth_cfg_t *get_auth_cfg(private_main_mode_t *this, bool local) enumerator = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, local); enumerator->enumerate(enumerator, &cfg); + enumerator->destroy(enumerator); return cfg; } @@ -404,7 +405,7 @@ METHOD(task_t, build_r, status_t, return FAILED; } - this->ike_sa->set_my_id(this->ike_sa, id); + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); From 9e40e3e9fa2d450dc2cce10130423206884f21c9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 11:51:16 +0100 Subject: [PATCH 065/534] Added message encoding rules for quick mode --- src/libcharon/encoding/message.c | 65 ++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index afa9b1956..7535f412c 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -575,6 +575,63 @@ static payload_order_t informational_i_order_v1[] = { {DELETE_V1, 0}, {VENDOR_ID_V1, 0}, }; + +/** + * Message rule for QUICK_MODE from initiator. + */ +static payload_rule_t quick_mode_i_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 2, TRUE, FALSE}, + {NONCE_V1, 0, 1, TRUE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE}, + {ID_V1, 0, 2, TRUE, FALSE}, +}; + +/** + * payload order for QUICK_MODE from initiator. + */ +static payload_order_t quick_mode_i_order[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {HASH_V1, 0}, + {SECURITY_ASSOCIATION_V1, 0}, + {NONCE_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {ID_V1, 0}, +}; + +/** + * Message rule for QUICK_MODE from responder. + */ +static payload_rule_t quick_mode_r_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 2, TRUE, FALSE}, + {NONCE_V1, 0, 1, TRUE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE}, + {ID_V1, 0, 2, TRUE, FALSE}, +}; + +/** + * payload order for QUICK_MODE from responder. + */ +static payload_order_t quick_mode_r_order[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {HASH_V1, 0}, + {SECURITY_ASSOCIATION_V1, 0}, + {NONCE_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {ID_V1, 0}, +}; + #endif /* USE_IKEV1 */ /** @@ -644,6 +701,14 @@ static message_rule_t message_rules[] = { countof(informational_i_rules_v1), informational_i_rules_v1, countof(informational_i_order_v1), informational_i_order_v1, }, + {QUICK_MODE, TRUE, TRUE, + countof(quick_mode_i_rules), quick_mode_i_rules, + countof(quick_mode_i_order), quick_mode_i_order, + }, + {QUICK_MODE, FALSE, TRUE, + countof(quick_mode_r_rules), quick_mode_r_rules, + countof(quick_mode_r_order), quick_mode_r_order, + }, /* TODO-IKEv1: define rules for other exchanges */ #endif /* USE_IKEV1 */ }; From 3bd5fcc8328af1241599e8bf0ef673d120dff798 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 11:54:29 +0100 Subject: [PATCH 066/534] Print message ID as unsigned integer --- src/libcharon/encoding/message.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 7535f412c..2bd52ec4c 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1100,7 +1100,7 @@ static char* get_string(private_message_t *this, char *buf, int len) memset(buf, 0, len); len--; - written = snprintf(pos, len, "%N %s %d [", + written = snprintf(pos, len, "%N %s %u [", exchange_type_names, this->exchange_type, this->is_request ? "request" : "response", this->message_id); From 744c0801531a6418ff46002caf6ce2123409d405 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 11:56:58 +0100 Subject: [PATCH 067/534] Initiate and respond to quick mode task (stub) --- src/libcharon/sa/ike_sa.c | 7 ++++--- src/libcharon/sa/task_manager_v1.c | 16 ++++++++++++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index e7478bd38..11901884b 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -1190,13 +1191,13 @@ METHOD(ike_sa_t, initiate, status_t, 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); } else { - /* TODO-IKEv1: create quick mode task */ + task = (task_t*)quick_mode_create(&this->public, child_cfg, + tsi, tsr); } - child_cfg->destroy(child_cfg); + this->task_manager->queue_task(this->task_manager, task); #ifdef ME if (this->peer_cfg->get_mediated_by(this->peer_cfg)) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 41976986e..6cc2d7592 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -18,6 +18,7 @@ #include #include +#include typedef struct exchange_t exchange_t; @@ -214,6 +215,12 @@ METHOD(task_manager_t, initiate, status_t, exchange = ID_PROT; } break; + case IKE_ESTABLISHED: + if (activate_task(this, TASK_QUICK_MODE)) + { + exchange = QUICK_MODE; + } + break; default: break; } @@ -230,6 +237,9 @@ METHOD(task_manager_t, initiate, status_t, case MAIN_MODE: exchange = ID_PROT; break; + case TASK_QUICK_MODE: + exchange = QUICK_MODE; + break; default: continue; } @@ -423,8 +433,10 @@ static status_t process_request(private_task_manager_t *this, /* TODO-IKEv1: agressive mode */ return FAILED; case QUICK_MODE: - /* TODO-IKEv1: quick mode */ - return FAILED; + task = (task_t *)quick_mode_create(this->ike_sa, NULL, + NULL, NULL); + this->passive_tasks->insert_last(this->passive_tasks, task); + break; case INFORMATIONAL_V1: /* TODO-IKEv1: informational */ return FAILED; From a09972df2bdffcef03add226be3f9bd8dc6e3962 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 12:18:24 +0100 Subject: [PATCH 068/534] Added a generic TASK_ prefix to all task types --- src/libcharon/sa/ike_sa.c | 2 +- src/libcharon/sa/task_manager_v1.c | 4 +- src/libcharon/sa/task_manager_v2.c | 77 +++++++++++----------- src/libcharon/sa/tasks/child_create.c | 2 +- src/libcharon/sa/tasks/child_create.h | 2 +- src/libcharon/sa/tasks/child_delete.c | 2 +- src/libcharon/sa/tasks/child_rekey.c | 14 ++-- src/libcharon/sa/tasks/child_rekey.h | 4 +- src/libcharon/sa/tasks/ike_auth.c | 2 +- src/libcharon/sa/tasks/ike_auth.h | 2 +- src/libcharon/sa/tasks/ike_auth_lifetime.c | 2 +- src/libcharon/sa/tasks/ike_auth_lifetime.h | 6 +- src/libcharon/sa/tasks/ike_cert_post.c | 2 +- src/libcharon/sa/tasks/ike_cert_pre.c | 2 +- src/libcharon/sa/tasks/ike_config.c | 2 +- src/libcharon/sa/tasks/ike_config.h | 2 +- src/libcharon/sa/tasks/ike_delete.c | 2 +- src/libcharon/sa/tasks/ike_dpd.c | 2 +- src/libcharon/sa/tasks/ike_init.c | 2 +- src/libcharon/sa/tasks/ike_init.h | 4 +- src/libcharon/sa/tasks/ike_me.c | 2 +- src/libcharon/sa/tasks/ike_me.h | 2 +- src/libcharon/sa/tasks/ike_mobike.c | 4 +- src/libcharon/sa/tasks/ike_natd.c | 2 +- src/libcharon/sa/tasks/ike_reauth.c | 2 +- src/libcharon/sa/tasks/ike_rekey.c | 14 ++-- src/libcharon/sa/tasks/ike_rekey.h | 6 +- src/libcharon/sa/tasks/ike_vendor.c | 2 +- src/libcharon/sa/tasks/main_mode.c | 2 +- src/libcharon/sa/tasks/task.c | 8 +-- src/libcharon/sa/tasks/task.h | 36 +++++----- 31 files changed, 109 insertions(+), 108 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 11901884b..1f8799890 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1715,7 +1715,7 @@ static void requeue_init_tasks(private_ike_sa_t *this) this->task_manager, TASK_QUEUE_QUEUED); while (enumerator->enumerate(enumerator, &task)) { - if (task->get_type(task) == IKE_INIT) + if (task->get_type(task) == TASK_IKE_INIT) { has_init = TRUE; break; diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 6cc2d7592..c96adaa39 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -210,7 +210,7 @@ METHOD(task_manager_t, initiate, status_t, switch (this->ike_sa->get_state(this->ike_sa)) { case IKE_CREATED: - if (activate_task(this, MAIN_MODE)) + if (activate_task(this, TASK_MAIN_MODE)) { exchange = ID_PROT; } @@ -234,7 +234,7 @@ METHOD(task_manager_t, initiate, status_t, DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); switch (task->get_type(task)) { - case MAIN_MODE: + case TASK_MAIN_MODE: exchange = ID_PROT; break; case TASK_QUICK_MODE: diff --git a/src/libcharon/sa/task_manager_v2.c b/src/libcharon/sa/task_manager_v2.c index 158c04b5b..6148a814c 100644 --- a/src/libcharon/sa/task_manager_v2.c +++ b/src/libcharon/sa/task_manager_v2.c @@ -211,7 +211,7 @@ METHOD(task_manager_t, retransmit, status_t, enumerator = this->active_tasks->create_enumerator(this->active_tasks); while (enumerator->enumerate(enumerator, (void*)&task)) { - if (task->get_type(task) == IKE_MOBIKE) + if (task->get_type(task) == TASK_IKE_MOBIKE) { mobike = (ike_mobike_t*)task; if (!mobike->is_probing(mobike)) @@ -303,78 +303,78 @@ METHOD(task_manager_t, initiate, status_t, switch (this->ike_sa->get_state(this->ike_sa)) { case IKE_CREATED: - activate_task(this, IKE_VENDOR); - if (activate_task(this, IKE_INIT)) + activate_task(this, TASK_IKE_VENDOR); + if (activate_task(this, TASK_IKE_INIT)) { this->initiating.mid = 0; exchange = IKE_SA_INIT; - activate_task(this, IKE_NATD); - activate_task(this, IKE_CERT_PRE); + activate_task(this, TASK_IKE_NATD); + activate_task(this, TASK_IKE_CERT_PRE); #ifdef ME - /* this task has to be activated before the IKE_AUTHENTICATE + /* this task has to be activated before the TASK_IKE_AUTH * task, because that task pregenerates the packet after * which no payloads can be added to the message anymore. */ - activate_task(this, IKE_ME); + activate_task(this, TASK_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); - activate_task(this, IKE_MOBIKE); + activate_task(this, TASK_IKE_AUTH); + activate_task(this, TASK_IKE_CERT_POST); + activate_task(this, TASK_IKE_CONFIG); + activate_task(this, TASK_CHILD_CREATE); + activate_task(this, TASK_IKE_AUTH_LIFETIME); + activate_task(this, TASK_IKE_MOBIKE); } break; case IKE_ESTABLISHED: - if (activate_task(this, CHILD_CREATE)) + if (activate_task(this, TASK_CHILD_CREATE)) { exchange = CREATE_CHILD_SA; break; } - if (activate_task(this, CHILD_DELETE)) + if (activate_task(this, TASK_CHILD_DELETE)) { exchange = INFORMATIONAL; break; } - if (activate_task(this, CHILD_REKEY)) + if (activate_task(this, TASK_CHILD_REKEY)) { exchange = CREATE_CHILD_SA; break; } - if (activate_task(this, IKE_DELETE)) + if (activate_task(this, TASK_IKE_DELETE)) { exchange = INFORMATIONAL; break; } - if (activate_task(this, IKE_REKEY)) + if (activate_task(this, TASK_IKE_REKEY)) { exchange = CREATE_CHILD_SA; break; } - if (activate_task(this, IKE_REAUTH)) + if (activate_task(this, TASK_IKE_REAUTH)) { exchange = INFORMATIONAL; break; } - if (activate_task(this, IKE_MOBIKE)) + if (activate_task(this, TASK_IKE_MOBIKE)) { exchange = INFORMATIONAL; break; } - if (activate_task(this, IKE_DPD)) + if (activate_task(this, TASK_IKE_DPD)) { exchange = INFORMATIONAL; break; } #ifdef ME - if (activate_task(this, IKE_ME)) + if (activate_task(this, TASK_IKE_ME)) { exchange = ME_CONNECT; break; } #endif /* ME */ case IKE_REKEYING: - if (activate_task(this, IKE_DELETE)) + if (activate_task(this, TASK_IKE_DELETE)) { exchange = INFORMATIONAL; break; @@ -393,18 +393,18 @@ METHOD(task_manager_t, initiate, status_t, DBG2(DBG_IKE, " %N task", task_type_names, task->get_type(task)); switch (task->get_type(task)) { - case IKE_INIT: + case TASK_IKE_INIT: exchange = IKE_SA_INIT; break; - case IKE_AUTHENTICATE: + case TASK_IKE_AUTH: exchange = IKE_AUTH; break; - case CHILD_CREATE: - case CHILD_REKEY: - case IKE_REKEY: + case TASK_CHILD_CREATE: + case TASK_CHILD_REKEY: + case TASK_IKE_REKEY: exchange = CREATE_CHILD_SA; break; - case IKE_MOBIKE: + case TASK_IKE_MOBIKE: exchange = INFORMATIONAL; break; default: @@ -555,8 +555,9 @@ static bool handle_collisions(private_task_manager_t *this, task_t *task) type = task->get_type(task); /* do we have to check */ - if (type == IKE_REKEY || type == CHILD_REKEY || - type == CHILD_DELETE || type == IKE_DELETE || type == IKE_REAUTH) + if (type == TASK_IKE_REKEY || type == TASK_CHILD_REKEY || + type == TASK_CHILD_DELETE || type == TASK_IKE_DELETE || + type == TASK_IKE_REAUTH) { /* find an exchange collision, and notify these tasks */ enumerator = this->active_tasks->create_enumerator(this->active_tasks); @@ -564,17 +565,17 @@ static bool handle_collisions(private_task_manager_t *this, task_t *task) { switch (active->get_type(active)) { - case IKE_REKEY: - if (type == IKE_REKEY || type == IKE_DELETE || - type == IKE_REAUTH) + case TASK_IKE_REKEY: + if (type == TASK_IKE_REKEY || type == TASK_IKE_DELETE || + type == TASK_IKE_REAUTH) { ike_rekey_t *rekey = (ike_rekey_t*)active; rekey->collide(rekey, task); break; } continue; - case CHILD_REKEY: - if (type == CHILD_REKEY || type == CHILD_DELETE) + case TASK_CHILD_REKEY: + if (type == TASK_CHILD_REKEY || type == TASK_CHILD_DELETE) { child_rekey_t *rekey = (child_rekey_t*)active; rekey->collide(rekey, task); @@ -977,7 +978,7 @@ METHOD(task_manager_t, process_message, status_t, METHOD(task_manager_t, queue_task, void, private_task_manager_t *this, task_t *task) { - if (task->get_type(task) == IKE_MOBIKE) + if (task->get_type(task) == TASK_IKE_MOBIKE) { /* there is no need to queue more than one mobike task */ enumerator_t *enumerator; task_t *current; @@ -985,7 +986,7 @@ METHOD(task_manager_t, queue_task, void, enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); while (enumerator->enumerate(enumerator, (void**)¤t)) { - if (current->get_type(current) == IKE_MOBIKE) + if (current->get_type(current) == TASK_IKE_MOBIKE) { enumerator->destroy(enumerator); task->destroy(task); diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index 46382a2a0..7a89e6f62 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -1212,7 +1212,7 @@ METHOD(child_create_t, get_lower_nonce, chunk_t, METHOD(task_t, get_type, task_type_t, private_child_create_t *this) { - return CHILD_CREATE; + return TASK_CHILD_CREATE; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/child_create.h b/src/libcharon/sa/tasks/child_create.h index 5dedeb8b1..fdec3bbb9 100644 --- a/src/libcharon/sa/tasks/child_create.h +++ b/src/libcharon/sa/tasks/child_create.h @@ -29,7 +29,7 @@ typedef struct child_create_t child_create_t; #include /** - * Task of type CHILD_CREATE, established a new CHILD_SA. + * Task of type TASK_CHILD_CREATE, established a new CHILD_SA. * * This task may be included in the IKE_AUTH message or in a separate * CREATE_CHILD_SA exchange. diff --git a/src/libcharon/sa/tasks/child_delete.c b/src/libcharon/sa/tasks/child_delete.c index e73074675..c5151abf1 100644 --- a/src/libcharon/sa/tasks/child_delete.c +++ b/src/libcharon/sa/tasks/child_delete.c @@ -324,7 +324,7 @@ METHOD(task_t, build_r, status_t, METHOD(task_t, get_type, task_type_t, private_child_delete_t *this) { - return CHILD_DELETE; + return TASK_CHILD_DELETE; } METHOD(child_delete_t , get_child, child_sa_t*, diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/tasks/child_rekey.c index bcdf093b8..fa916c4e5 100644 --- a/src/libcharon/sa/tasks/child_rekey.c +++ b/src/libcharon/sa/tasks/child_rekey.c @@ -224,7 +224,7 @@ static child_sa_t *handle_collision(private_child_rekey_t *this) { child_sa_t *to_delete; - if (this->collision->get_type(this->collision) == CHILD_REKEY) + if (this->collision->get_type(this->collision) == TASK_CHILD_REKEY) { chunk_t this_nonce, other_nonce; private_child_rekey_t *other = (private_child_rekey_t*)this->collision; @@ -311,7 +311,7 @@ METHOD(task_t, process_i, status_t, /* establishing new child failed, reuse old. but not when we * received a delete in the meantime */ if (!(this->collision && - this->collision->get_type(this->collision) == CHILD_DELETE)) + this->collision->get_type(this->collision) == TASK_CHILD_DELETE)) { job_t *job; u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); @@ -362,7 +362,7 @@ METHOD(task_t, process_i, status_t, METHOD(task_t, get_type, task_type_t, private_child_rekey_t *this) { - return CHILD_REKEY; + return TASK_CHILD_REKEY; } METHOD(child_rekey_t, collide, void, @@ -370,7 +370,7 @@ METHOD(child_rekey_t, collide, void, { /* the task manager only detects exchange collision, but not if * the collision is for the same child. we check it here. */ - if (other->get_type(other) == CHILD_REKEY) + if (other->get_type(other) == TASK_CHILD_REKEY) { private_child_rekey_t *rekey = (private_child_rekey_t*)other; if (rekey->child_sa != this->child_sa) @@ -380,7 +380,7 @@ METHOD(child_rekey_t, collide, void, return; } } - else if (other->get_type(other) == CHILD_DELETE) + else if (other->get_type(other) == TASK_CHILD_DELETE) { child_delete_t *del = (child_delete_t*)other; if (del->get_child(del) == this->child_create->get_child(this->child_create)) @@ -403,8 +403,8 @@ METHOD(child_rekey_t, collide, void, other->destroy(other); return; } - DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, CHILD_REKEY, - task_type_names, other->get_type(other)); + DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, + TASK_CHILD_REKEY, task_type_names, other->get_type(other)); DESTROY_IF(this->collision); this->collision = other; } diff --git a/src/libcharon/sa/tasks/child_rekey.h b/src/libcharon/sa/tasks/child_rekey.h index 9b1aea5fa..3ba417611 100644 --- a/src/libcharon/sa/tasks/child_rekey.h +++ b/src/libcharon/sa/tasks/child_rekey.h @@ -29,7 +29,7 @@ typedef struct child_rekey_t child_rekey_t; #include /** - * Task of type CHILD_REKEY, rekey an established CHILD_SA. + * Task of type TASK_CHILD_REKEY, rekey an established CHILD_SA. */ struct child_rekey_t { @@ -51,7 +51,7 @@ struct child_rekey_t { }; /** - * Create a new CHILD_REKEY task. + * Create a new TASK_CHILD_REKEY task. * * @param ike_sa IKE_SA this task works for * @param protocol protocol of CHILD_SA to rekey, PROTO_NONE as responder diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/tasks/ike_auth.c index af2c30f71..4a92385ee 100644 --- a/src/libcharon/sa/tasks/ike_auth.c +++ b/src/libcharon/sa/tasks/ike_auth.c @@ -1023,7 +1023,7 @@ peer_auth_failed: METHOD(task_t, get_type, task_type_t, private_ike_auth_t *this) { - return IKE_AUTHENTICATE; + return TASK_IKE_AUTH; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_auth.h b/src/libcharon/sa/tasks/ike_auth.h index 132907941..c6c0100b0 100644 --- a/src/libcharon/sa/tasks/ike_auth.h +++ b/src/libcharon/sa/tasks/ike_auth.h @@ -46,7 +46,7 @@ struct ike_auth_t { }; /** - * Create a new task of type IKE_AUTHENTICATE. + * Create a new task of type TASK_IKE_AUTH. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if task is the initiator of an exchange diff --git a/src/libcharon/sa/tasks/ike_auth_lifetime.c b/src/libcharon/sa/tasks/ike_auth_lifetime.c index a57cfd075..31e3bffca 100644 --- a/src/libcharon/sa/tasks/ike_auth_lifetime.c +++ b/src/libcharon/sa/tasks/ike_auth_lifetime.c @@ -124,7 +124,7 @@ METHOD(task_t, process_i, status_t, METHOD(task_t, get_type, task_type_t, private_ike_auth_lifetime_t *this) { - return IKE_AUTH_LIFETIME; + return TASK_IKE_AUTH_LIFETIME; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_auth_lifetime.h b/src/libcharon/sa/tasks/ike_auth_lifetime.h index 3b129b9e3..9052f4274 100644 --- a/src/libcharon/sa/tasks/ike_auth_lifetime.h +++ b/src/libcharon/sa/tasks/ike_auth_lifetime.h @@ -28,7 +28,7 @@ typedef struct ike_auth_lifetime_t ike_auth_lifetime_t; #include /** - * Task of type IKE_AUTH_LIFETIME, implements RFC4478. + * Task of type TASK_IKE_AUTH_LIFETIME, implements RFC4478. * * This task exchanges lifetimes for IKE_AUTH to force a client to * reauthenticate before the responders lifetime reaches the limit. @@ -42,7 +42,7 @@ struct ike_auth_lifetime_t { }; /** - * Create a new IKE_AUTH_LIFETIME task. + * Create a new TASK_IKE_AUTH_LIFETIME task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if taks is initiated by us @@ -50,4 +50,4 @@ struct ike_auth_lifetime_t { */ ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator); -#endif /** IKE_MOBIKE_H_ @}*/ +#endif /** IKE_AUTH_LIFETIME_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_cert_post.c b/src/libcharon/sa/tasks/ike_cert_post.c index 94af50eae..f2986dc50 100644 --- a/src/libcharon/sa/tasks/ike_cert_post.c +++ b/src/libcharon/sa/tasks/ike_cert_post.c @@ -207,7 +207,7 @@ METHOD(task_t, process_i, status_t, METHOD(task_t, get_type, task_type_t, private_ike_cert_post_t *this) { - return IKE_CERT_POST; + return TASK_IKE_CERT_POST; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_cert_pre.c b/src/libcharon/sa/tasks/ike_cert_pre.c index 1919ed0a6..0de2efd38 100644 --- a/src/libcharon/sa/tasks/ike_cert_pre.c +++ b/src/libcharon/sa/tasks/ike_cert_pre.c @@ -479,7 +479,7 @@ METHOD(task_t, process_i, status_t, METHOD(task_t, get_type, task_type_t, private_ike_cert_pre_t *this) { - return IKE_CERT_PRE; + return TASK_IKE_CERT_PRE; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_config.c b/src/libcharon/sa/tasks/ike_config.c index 4ef9c56a5..6623730d1 100644 --- a/src/libcharon/sa/tasks/ike_config.c +++ b/src/libcharon/sa/tasks/ike_config.c @@ -385,7 +385,7 @@ METHOD(task_t, process_i, status_t, METHOD(task_t, get_type, task_type_t, private_ike_config_t *this) { - return IKE_CONFIG; + return TASK_IKE_CONFIG; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_config.h b/src/libcharon/sa/tasks/ike_config.h index 8cef08697..d343761c1 100644 --- a/src/libcharon/sa/tasks/ike_config.h +++ b/src/libcharon/sa/tasks/ike_config.h @@ -28,7 +28,7 @@ typedef struct ike_config_t ike_config_t; #include /** - * Task of type IKE_CONFIG, sets up a virtual IP and other + * Task of type TASK_IKE_CONFIG, sets up a virtual IP and other * configurations for an IKE_SA. */ struct ike_config_t { diff --git a/src/libcharon/sa/tasks/ike_delete.c b/src/libcharon/sa/tasks/ike_delete.c index fc24a6e94..29ac87258 100644 --- a/src/libcharon/sa/tasks/ike_delete.c +++ b/src/libcharon/sa/tasks/ike_delete.c @@ -149,7 +149,7 @@ METHOD(task_t, build_r, status_t, METHOD(task_t, get_type, task_type_t, private_ike_delete_t *this) { - return IKE_DELETE; + return TASK_IKE_DELETE; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_dpd.c b/src/libcharon/sa/tasks/ike_dpd.c index 106eff87c..28ccc2efe 100644 --- a/src/libcharon/sa/tasks/ike_dpd.c +++ b/src/libcharon/sa/tasks/ike_dpd.c @@ -46,7 +46,7 @@ METHOD(task_t, return_success, status_t, METHOD(task_t, get_type, task_type_t, private_ike_dpd_t *this) { - return IKE_DPD; + return TASK_IKE_DPD; } diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/tasks/ike_init.c index aa514bffc..390756706 100644 --- a/src/libcharon/sa/tasks/ike_init.c +++ b/src/libcharon/sa/tasks/ike_init.c @@ -507,7 +507,7 @@ METHOD(task_t, process_i, status_t, METHOD(task_t, get_type, task_type_t, private_ike_init_t *this) { - return IKE_INIT; + return TASK_IKE_INIT; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_init.h b/src/libcharon/sa/tasks/ike_init.h index 4b7f60416..6855ac839 100644 --- a/src/libcharon/sa/tasks/ike_init.h +++ b/src/libcharon/sa/tasks/ike_init.h @@ -28,7 +28,7 @@ typedef struct ike_init_t ike_init_t; #include /** - * Task of type IKE_INIT, creates an IKE_SA without authentication. + * Task of type TASK_IKE_INIT, creates an IKE_SA without authentication. * * The authentication of is handle in the ike_auth task. */ @@ -48,7 +48,7 @@ struct ike_init_t { }; /** - * Create a new IKE_INIT task. + * Create a new TASK_IKE_INIT task. * * @param ike_sa IKE_SA this task works for (new one when rekeying) * @param initiator TRUE if task is the original initiator diff --git a/src/libcharon/sa/tasks/ike_me.c b/src/libcharon/sa/tasks/ike_me.c index 8f90efcc3..333c13635 100644 --- a/src/libcharon/sa/tasks/ike_me.c +++ b/src/libcharon/sa/tasks/ike_me.c @@ -750,7 +750,7 @@ METHOD(ike_me_t, relay, void, METHOD(task_t, get_type, task_type_t, private_ike_me_t *this) { - return IKE_ME; + return TASK_IKE_ME; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_me.h b/src/libcharon/sa/tasks/ike_me.h index 31285a426..74dd1dedf 100644 --- a/src/libcharon/sa/tasks/ike_me.h +++ b/src/libcharon/sa/tasks/ike_me.h @@ -28,7 +28,7 @@ typedef struct ike_me_t ike_me_t; #include /** - * Task of type IKE_ME, detects and handles IKE-ME extensions. + * Task of type TASK_IKE_ME, detects and handles IKE-ME extensions. * * This tasks handles the ME_MEDIATION Notify exchange to setup a mediation * connection, allows to initiate mediated connections using ME_CONNECT diff --git a/src/libcharon/sa/tasks/ike_mobike.c b/src/libcharon/sa/tasks/ike_mobike.c index da8834c1d..6719bddd6 100644 --- a/src/libcharon/sa/tasks/ike_mobike.c +++ b/src/libcharon/sa/tasks/ike_mobike.c @@ -53,7 +53,7 @@ struct private_ike_mobike_t { chunk_t cookie2; /** - * NAT discovery reusing the IKE_NATD task + * NAT discovery reusing the TASK_IKE_NATD task */ ike_natd_t *natd; @@ -587,7 +587,7 @@ METHOD(ike_mobike_t, is_probing, bool, METHOD(task_t, get_type, task_type_t, private_ike_mobike_t *this) { - return IKE_MOBIKE; + return TASK_IKE_MOBIKE; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_natd.c b/src/libcharon/sa/tasks/ike_natd.c index 6b658f8b1..3de0ab1b4 100644 --- a/src/libcharon/sa/tasks/ike_natd.c +++ b/src/libcharon/sa/tasks/ike_natd.c @@ -385,7 +385,7 @@ METHOD(task_t, process_r, status_t, METHOD(task_t, get_type, task_type_t, private_ike_natd_t *this) { - return IKE_NATD; + return TASK_IKE_NATD; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_reauth.c b/src/libcharon/sa/tasks/ike_reauth.c index 197849d88..38c7a4272 100644 --- a/src/libcharon/sa/tasks/ike_reauth.c +++ b/src/libcharon/sa/tasks/ike_reauth.c @@ -150,7 +150,7 @@ METHOD(task_t, process_i, status_t, METHOD(task_t, get_type, task_type_t, private_ike_reauth_t *this) { - return IKE_REAUTH; + return TASK_IKE_REAUTH; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/ike_rekey.c b/src/libcharon/sa/tasks/ike_rekey.c index c089edab5..a0d346040 100644 --- a/src/libcharon/sa/tasks/ike_rekey.c +++ b/src/libcharon/sa/tasks/ike_rekey.c @@ -52,7 +52,7 @@ struct private_ike_rekey_t { bool initiator; /** - * the IKE_INIT task which is reused to simplify rekeying + * the TASK_IKE_INIT task which is reused to simplify rekeying */ ike_init_t *ike_init; @@ -233,8 +233,8 @@ METHOD(task_t, process_i, status_t, case FAILED: /* rekeying failed, fallback to old SA */ if (!(this->collision && ( - this->collision->get_type(this->collision) == IKE_DELETE || - this->collision->get_type(this->collision) == IKE_REAUTH))) + this->collision->get_type(this->collision) == TASK_IKE_DELETE || + this->collision->get_type(this->collision) == TASK_IKE_REAUTH))) { job_t *job; u_int32_t retry = RETRY_INTERVAL - (random() % RETRY_JITTER); @@ -256,7 +256,7 @@ METHOD(task_t, process_i, status_t, /* check for collisions */ if (this->collision && - this->collision->get_type(this->collision) == IKE_REKEY) + this->collision->get_type(this->collision) == TASK_IKE_REKEY) { private_ike_rekey_t *other = (private_ike_rekey_t*)this->collision; @@ -326,14 +326,14 @@ METHOD(task_t, process_i, status_t, METHOD(task_t, get_type, task_type_t, private_ike_rekey_t *this) { - return IKE_REKEY; + return TASK_IKE_REKEY; } METHOD(ike_rekey_t, collide, void, private_ike_rekey_t* this, task_t *other) { - DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, IKE_REKEY, - task_type_names, other->get_type(other)); + DBG1(DBG_IKE, "detected %N collision with %N", task_type_names, + TASK_IKE_REKEY, task_type_names, other->get_type(other)); DESTROY_IF(this->collision); this->collision = other; } diff --git a/src/libcharon/sa/tasks/ike_rekey.h b/src/libcharon/sa/tasks/ike_rekey.h index 1c9550768..6a9d59b0e 100644 --- a/src/libcharon/sa/tasks/ike_rekey.h +++ b/src/libcharon/sa/tasks/ike_rekey.h @@ -28,7 +28,7 @@ typedef struct ike_rekey_t ike_rekey_t; #include /** - * Task of type IKE_REKEY, rekey an established IKE_SA. + * Task of type TASK_IKE_REKEY, rekey an established IKE_SA. */ struct ike_rekey_t { @@ -50,11 +50,11 @@ struct ike_rekey_t { }; /** - * Create a new IKE_REKEY task. + * Create a new TASK_IKE_REKEY task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE for initiator, FALSE for responder - * @return IKE_REKEY task to handle by the task_manager + * @return TASK_IKE_REKEY task to handle by the task_manager */ ike_rekey_t *ike_rekey_create(ike_sa_t *ike_sa, bool initiator); diff --git a/src/libcharon/sa/tasks/ike_vendor.c b/src/libcharon/sa/tasks/ike_vendor.c index b3a7dddfa..7b3cc6e91 100644 --- a/src/libcharon/sa/tasks/ike_vendor.c +++ b/src/libcharon/sa/tasks/ike_vendor.c @@ -107,7 +107,7 @@ METHOD(task_t, migrate, void, METHOD(task_t, get_type, task_type_t, private_ike_vendor_t *this) { - return IKE_VENDOR; + return TASK_IKE_VENDOR; } METHOD(task_t, destroy, void, diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 4d0c570d9..2d9acf611 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -527,7 +527,7 @@ METHOD(task_t, process_i, status_t, METHOD(task_t, get_type, task_type_t, private_main_mode_t *this) { - return MAIN_MODE; + return TASK_MAIN_MODE; } METHOD(task_t, migrate, void, diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index 2889409af..83d0478ca 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -17,11 +17,11 @@ #include "task.h" #ifdef ME -ENUM(task_type_names, IKE_INIT, TASK_QUICK_MODE, +ENUM(task_type_names, TASK_IKE_INIT, TASK_QUICK_MODE, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", - "IKE_AUTHENTICATE", + "IKE_AUTH", "IKE_AUTH_LIFETIME", "IKE_CERT_PRE", "IKE_CERT_POST", @@ -39,11 +39,11 @@ ENUM(task_type_names, IKE_INIT, TASK_QUICK_MODE, "QUICK_MODE", ); #else -ENUM(task_type_names, IKE_INIT, TASK_QUICK_MODE, +ENUM(task_type_names, TASK_IKE_INIT, TASK_QUICK_MODE, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", - "IKE_AUTHENTICATE", + "IKE_AUTH", "IKE_AUTH_LIFETIME", "IKE_CERT_PRE", "IKE_CERT_POST", diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 8d78053ad..8a8143967 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -34,43 +34,43 @@ typedef struct task_t task_t; */ enum task_type_t { /** establish an unauthenticated IKE_SA */ - IKE_INIT, + TASK_IKE_INIT, /** detect NAT situation */ - IKE_NATD, + TASK_IKE_NATD, /** handle MOBIKE stuff */ - IKE_MOBIKE, + TASK_IKE_MOBIKE, /** authenticate the initiated IKE_SA */ - IKE_AUTHENTICATE, + TASK_IKE_AUTH, /** AUTH_LIFETIME negotiation, RFC4478 */ - IKE_AUTH_LIFETIME, + TASK_IKE_AUTH_LIFETIME, /** certificate processing before authentication (certreqs, cert parsing) */ - IKE_CERT_PRE, + TASK_IKE_CERT_PRE, /** certificate processing after authentication (certs payload generation) */ - IKE_CERT_POST, + TASK_IKE_CERT_POST, /** Configuration payloads, virtual IP and such */ - IKE_CONFIG, + TASK_IKE_CONFIG, /** rekey an IKE_SA */ - IKE_REKEY, + TASK_IKE_REKEY, /** reestablish a complete IKE_SA */ - IKE_REAUTH, + TASK_IKE_REAUTH, /** delete an IKE_SA */ - IKE_DELETE, + TASK_IKE_DELETE, /** liveness check */ - IKE_DPD, + TASK_IKE_DPD, /** Vendor ID processing */ - IKE_VENDOR, + TASK_IKE_VENDOR, #ifdef ME /** handle ME stuff */ - IKE_ME, + TASK_IKE_ME, #endif /* ME */ /** establish a CHILD_SA within an IKE_SA */ - CHILD_CREATE, + TASK_CHILD_CREATE, /** delete an established CHILD_SA */ - CHILD_DELETE, + TASK_CHILD_DELETE, /** rekey an CHILD_SA */ - CHILD_REKEY, + TASK_CHILD_REKEY, /** IKEv1 main mode */ - MAIN_MODE, + TASK_MAIN_MODE, /** IKEv1 quick mode */ TASK_QUICK_MODE, }; From a0563846b0aebb692cb81647862807712d173e59 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 18 Nov 2011 10:56:48 +0100 Subject: [PATCH 069/534] Moved version specific keymat functions to specific interfaces. --- src/conftest/hooks/pretend_auth.c | 5 +- src/conftest/hooks/rebuild_auth.c | 5 +- .../sa/authenticators/eap_authenticator.c | 11 +-- .../sa/authenticators/psk_authenticator.c | 9 +- .../sa/authenticators/pubkey_authenticator.c | 9 +- src/libcharon/sa/keymat.h | 89 +------------------ src/libcharon/sa/keymat_v1.c | 19 ---- src/libcharon/sa/keymat_v2.c | 22 ++--- src/libcharon/sa/keymat_v2.h | 88 ++++++++++++++++++ src/libcharon/sa/tasks/child_create.c | 11 ++- src/libcharon/sa/tasks/ike_init.c | 21 +++-- 11 files changed, 142 insertions(+), 147 deletions(-) diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c index ff99900f2..f91b6bf9b 100644 --- a/src/conftest/hooks/pretend_auth.c +++ b/src/conftest/hooks/pretend_auth.c @@ -15,6 +15,7 @@ #include "hook.h" +#include #include #include #include @@ -190,7 +191,7 @@ static bool build_auth(private_pretend_auth_t *this, auth_payload_t *auth_payload; auth_method_t auth_method; signature_scheme_t scheme; - keymat_t *keymat; + keymat_v2_t *keymat; auth = auth_cfg_create(); private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, this->id, auth); @@ -235,7 +236,7 @@ static bool build_auth(private_pretend_auth_t *this, key_type_names, private->get_type(private)); return FALSE; } - keymat = ike_sa->get_keymat(ike_sa); + keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); octets = keymat->get_auth_octets(keymat, TRUE, this->ike_init, this->nonce, this->id, this->reserved); if (!private->sign(private, scheme, octets, &auth_data)) diff --git a/src/conftest/hooks/rebuild_auth.c b/src/conftest/hooks/rebuild_auth.c index 993c952e0..cf9b113cc 100644 --- a/src/conftest/hooks/rebuild_auth.c +++ b/src/conftest/hooks/rebuild_auth.c @@ -15,6 +15,7 @@ #include "hook.h" +#include #include #include #include @@ -62,7 +63,7 @@ static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa, auth_payload_t *auth_payload; auth_method_t auth_method; signature_scheme_t scheme; - keymat_t *keymat; + keymat_v2_t *keymat; identification_t *id; char reserved[3]; generator_t *generator; @@ -137,7 +138,7 @@ static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa, id->destroy(id); return FALSE; } - keymat = ike_sa->get_keymat(ike_sa); + keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); octets = keymat->get_auth_octets(keymat, FALSE, this->ike_init, this->nonce, id, reserved); if (!private->sign(private, scheme, octets, &auth_data)) diff --git a/src/libcharon/sa/authenticators/eap_authenticator.c b/src/libcharon/sa/authenticators/eap_authenticator.c index c85a45fb3..d36d544e8 100644 --- a/src/libcharon/sa/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/authenticators/eap_authenticator.c @@ -16,6 +16,7 @@ #include "eap_authenticator.h" #include +#include #include #include #include @@ -376,7 +377,7 @@ static eap_payload_t* client_process_eap(private_eap_authenticator_t *this, if (vendor) { DBG1(DBG_IKE, "server requested vendor specific EAP method %d-%d ", - "(id 0x%02X)", type, vendor, in->get_identifier(in)); + "(id 0x%02X)", type, vendor, in->get_identifier(in)); } else { @@ -419,7 +420,7 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message, chunk_t auth_data, recv_auth_data; identification_t *other_id; auth_cfg_t *auth; - keymat_t *keymat; + keymat_v2_t *keymat; auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); @@ -429,7 +430,7 @@ static bool verify_auth(private_eap_authenticator_t *this, message_t *message, return FALSE; } other_id = this->ike_sa->get_other_id(this->ike_sa); - keymat = this->ike_sa->get_keymat(this->ike_sa); + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); auth_data = keymat->get_psk_sig(keymat, TRUE, init, nonce, this->msk, other_id, this->reserved); recv_auth_data = auth_payload->get_data(auth_payload); @@ -459,10 +460,10 @@ static void build_auth(private_eap_authenticator_t *this, message_t *message, auth_payload_t *auth_payload; identification_t *my_id; chunk_t auth_data; - keymat_t *keymat; + keymat_v2_t *keymat; my_id = this->ike_sa->get_my_id(this->ike_sa); - keymat = this->ike_sa->get_keymat(this->ike_sa); + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N", my_id, auth_class_names, AUTH_CLASS_EAP); diff --git a/src/libcharon/sa/authenticators/psk_authenticator.c b/src/libcharon/sa/authenticators/psk_authenticator.c index 21fc0f9b8..26c722530 100644 --- a/src/libcharon/sa/authenticators/psk_authenticator.c +++ b/src/libcharon/sa/authenticators/psk_authenticator.c @@ -18,6 +18,7 @@ #include #include +#include typedef struct private_psk_authenticator_t private_psk_authenticator_t; @@ -59,9 +60,9 @@ METHOD(authenticator_t, build, status_t, auth_payload_t *auth_payload; shared_key_t *key; chunk_t auth_data; - keymat_t *keymat; + keymat_v2_t *keymat; - keymat = this->ike_sa->get_keymat(this->ike_sa); + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); my_id = this->ike_sa->get_my_id(this->ike_sa); other_id = this->ike_sa->get_other_id(this->ike_sa); DBG1(DBG_IKE, "authentication of '%Y' (myself) with %N", @@ -96,14 +97,14 @@ METHOD(authenticator_t, process, status_t, enumerator_t *enumerator; bool authenticated = FALSE; int keys_found = 0; - keymat_t *keymat; + keymat_v2_t *keymat; auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); if (!auth_payload) { return FAILED; } - keymat = this->ike_sa->get_keymat(this->ike_sa); + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); recv_auth_data = auth_payload->get_data(auth_payload); my_id = this->ike_sa->get_my_id(this->ike_sa); other_id = this->ike_sa->get_other_id(this->ike_sa); diff --git a/src/libcharon/sa/authenticators/pubkey_authenticator.c b/src/libcharon/sa/authenticators/pubkey_authenticator.c index 247891670..df5b06ae6 100644 --- a/src/libcharon/sa/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/authenticators/pubkey_authenticator.c @@ -19,6 +19,7 @@ #include #include +#include typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t; @@ -64,7 +65,7 @@ METHOD(authenticator_t, build, status_t, auth_payload_t *auth_payload; auth_method_t auth_method; signature_scheme_t scheme; - keymat_t *keymat; + keymat_v2_t *keymat; id = this->ike_sa->get_my_id(this->ike_sa); auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); @@ -110,7 +111,7 @@ METHOD(authenticator_t, build, status_t, key_type_names, private->get_type(private)); return status; } - keymat = this->ike_sa->get_keymat(this->ike_sa); + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); octets = keymat->get_auth_octets(keymat, FALSE, this->ike_sa_init, this->nonce, id, this->reserved); if (private->sign(private, scheme, octets, &auth_data)) @@ -144,7 +145,7 @@ METHOD(authenticator_t, process, status_t, key_type_t key_type = KEY_ECDSA; signature_scheme_t scheme; status_t status = NOT_FOUND; - keymat_t *keymat; + keymat_v2_t *keymat; auth_payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); if (!auth_payload) @@ -174,7 +175,7 @@ METHOD(authenticator_t, process, status_t, } auth_data = auth_payload->get_data(auth_payload); id = this->ike_sa->get_other_id(this->ike_sa); - keymat = this->ike_sa->get_keymat(this->ike_sa); + keymat = (keymat_v2_t*)this->ike_sa->get_keymat(this->ike_sa); octets = keymat->get_auth_octets(keymat, TRUE, this->ike_sa_init, this->nonce, id, this->reserved); auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index 7867898c1..5860044b6 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -46,58 +46,8 @@ struct keymat_t { * @param group diffie hellman group * @return DH object, NULL if group not supported */ - diffie_hellman_t* (*create_dh)(keymat_t *this, diffie_hellman_group_t group); - - /** - * Derive keys for the IKE_SA. - * - * These keys are not handed out, but are used by the associated signers, - * crypters and authentication functions. - * - * @param proposal selected algorithms - * @param dh diffie hellman key allocated by create_dh() - * @param nonce_i initiators nonce value - * @param nonce_r responders nonce value - * @param id IKE_SA identifier - * @param rekey_prf PRF of old SA if rekeying, PRF_UNDEFINED otherwise - * @param rekey_sdk SKd of old SA if rekeying - * @return TRUE on success - */ - bool (*derive_ike_keys)(keymat_t *this, proposal_t *proposal, - diffie_hellman_t *dh, chunk_t nonce_i, - chunk_t nonce_r, ike_sa_id_t *id, - pseudo_random_function_t rekey_function, - chunk_t rekey_skd); - /** - * Derive keys for a CHILD_SA. - * - * The keys for the CHILD_SA are allocated in the integ and encr chunks. - * An implementation might hand out encrypted keys only, which are - * decrypted in the kernel before use. - * If no PFS is used for the CHILD_SA, dh can be NULL. - * - * @param proposal selected algorithms - * @param dh diffie hellman key allocated by create_dh(), or NULL - * @param nonce_i initiators nonce value - * @param nonce_r responders nonce value - * @param encr_i chunk to write initiators encryption key to - * @param integ_i chunk to write initiators integrity key to - * @param encr_r chunk to write responders encryption key to - * @param integ_r chunk to write responders integrity key to - * @return TRUE on success - */ - bool (*derive_child_keys)(keymat_t *this, - proposal_t *proposal, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, - chunk_t *encr_i, chunk_t *integ_i, - chunk_t *encr_r, chunk_t *integ_r); - /** - * Get SKd to pass to derive_ikey_keys() during rekeying. - * - * @param skd chunk to write SKd to (internal data) - * @return PRF function to derive keymat - */ - pseudo_random_function_t (*get_skd)(keymat_t *this, chunk_t *skd); + diffie_hellman_t* (*create_dh)(keymat_t *this, + diffie_hellman_group_t group); /* * Get a AEAD transform to en-/decrypt and sign/verify IKE messages. @@ -107,41 +57,6 @@ struct keymat_t { */ aead_t* (*get_aead)(keymat_t *this, bool in); - /** - * Generate octets to use for authentication procedure (RFC4306 2.15). - * - * This method creates the plain octets and is usually signed by a private - * key. PSK and EAP authentication include a secret into the data, use - * the get_psk_sig() method instead. - * - * @param verify TRUE to create for verfification, FALSE to sign - * @param ike_sa_init encoded ike_sa_init message - * @param nonce nonce value - * @param id identity - * @param reserved reserved bytes of id_payload - * @return authentication octets - */ - chunk_t (*get_auth_octets)(keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, identification_t *id, - char reserved[3]); - /** - * Build the shared secret signature used for PSK and EAP authentication. - * - * This method wraps the get_auth_octets() method and additionally - * includes the secret into the signature. If no secret is given, SK_p is - * used as secret (used for EAP methods without MSK). - * - * @param verify TRUE to create for verfification, FALSE to sign - * @param ike_sa_init encoded ike_sa_init message - * @param nonce nonce value - * @param secret optional secret to include into signature - * @param id identity - * @param reserved reserved bytes of id_payload - * @return signature octets - */ - chunk_t (*get_psk_sig)(keymat_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, chunk_t secret, - identification_t *id, char reserved[3]); /** * Destroy a keymat_t. */ diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index f73366d43..e4f58a499 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -81,20 +81,6 @@ METHOD(keymat_t, get_aead, aead_t*, return NULL; } -METHOD(keymat_t, get_auth_octets, chunk_t, - private_keymat_v1_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, identification_t *id, char reserved[3]) -{ - return chunk_empty; -} - -METHOD(keymat_t, get_psk_sig, chunk_t, - private_keymat_v1_t *this, bool verify, chunk_t ike_sa_init, - chunk_t nonce, chunk_t secret, identification_t *id, char reserved[3]) -{ - return chunk_empty; -} - METHOD(keymat_t, destroy, void, private_keymat_v1_t *this) { @@ -113,12 +99,7 @@ keymat_v1_t *keymat_v1_create(bool initiator) .public = { .keymat = { .create_dh = _create_dh, - .derive_ike_keys = _derive_ike_keys, - .derive_child_keys = _derive_child_keys, - .get_skd = _get_skd, .get_aead = _get_aead, - .get_auth_octets = _get_auth_octets, - .get_psk_sig = _get_psk_sig, .destroy = _destroy, }, }, diff --git a/src/libcharon/sa/keymat_v2.c b/src/libcharon/sa/keymat_v2.c index 562a72f14..9fd17328f 100644 --- a/src/libcharon/sa/keymat_v2.c +++ b/src/libcharon/sa/keymat_v2.c @@ -127,7 +127,7 @@ static int lookup_keylen(keylen_entry_t *list, int algo) METHOD(keymat_t, create_dh, diffie_hellman_t*, private_keymat_v2_t *this, diffie_hellman_group_t group) { - return lib->crypto->create_dh(lib->crypto, group);; + return lib->crypto->create_dh(lib->crypto, group); } /** @@ -244,7 +244,7 @@ static bool derive_ike_traditional(private_keymat_v2_t *this, u_int16_t enc_alg, return TRUE; } -METHOD(keymat_t, derive_ike_keys, bool, +METHOD(keymat_v2_t, derive_ike_keys, bool, private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, pseudo_random_function_t rekey_function, chunk_t rekey_skd) @@ -420,7 +420,7 @@ METHOD(keymat_t, derive_ike_keys, bool, return TRUE; } -METHOD(keymat_t, derive_child_keys, bool, +METHOD(keymat_v2_t, derive_child_keys, bool, private_keymat_v2_t *this, proposal_t *proposal, diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r) @@ -525,7 +525,7 @@ METHOD(keymat_t, derive_child_keys, bool, return TRUE; } -METHOD(keymat_t, get_skd, pseudo_random_function_t, +METHOD(keymat_v2_t, get_skd, pseudo_random_function_t, private_keymat_v2_t *this, chunk_t *skd) { *skd = this->skd; @@ -538,7 +538,7 @@ METHOD(keymat_t, get_aead, aead_t*, return in ? this->aead_in : this->aead_out; } -METHOD(keymat_t, get_auth_octets, chunk_t, +METHOD(keymat_v2_t, get_auth_octets, chunk_t, private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce, identification_t *id, char reserved[3]) { @@ -568,7 +568,7 @@ METHOD(keymat_t, get_auth_octets, chunk_t, #define IKEV2_KEY_PAD "Key Pad for IKEv2" #define IKEV2_KEY_PAD_LENGTH 17 -METHOD(keymat_t, get_psk_sig, chunk_t, +METHOD(keymat_v2_t, get_psk_sig, chunk_t, private_keymat_v2_t *this, bool verify, chunk_t ike_sa_init, chunk_t nonce, chunk_t secret, identification_t *id, char reserved[3]) { @@ -617,14 +617,14 @@ keymat_v2_t *keymat_v2_create(bool initiator) .public = { .keymat = { .create_dh = _create_dh, - .derive_ike_keys = _derive_ike_keys, - .derive_child_keys = _derive_child_keys, - .get_skd = _get_skd, .get_aead = _get_aead, - .get_auth_octets = _get_auth_octets, - .get_psk_sig = _get_psk_sig, .destroy = _destroy, }, + .derive_ike_keys = _derive_ike_keys, + .derive_child_keys = _derive_child_keys, + .get_skd = _get_skd, + .get_auth_octets = _get_auth_octets, + .get_psk_sig = _get_psk_sig, }, .initiator = initiator, .prf_alg = PRF_UNDEFINED, diff --git a/src/libcharon/sa/keymat_v2.h b/src/libcharon/sa/keymat_v2.h index 6026a0296..b33e71344 100644 --- a/src/libcharon/sa/keymat_v2.h +++ b/src/libcharon/sa/keymat_v2.h @@ -34,6 +34,94 @@ struct keymat_v2_t { * Implements keymat_t. */ keymat_t keymat; + + /** + * Derive keys for the IKE_SA. + * + * These keys are not handed out, but are used by the associated signers, + * crypters and authentication functions. + * + * @param proposal selected algorithms + * @param dh diffie hellman key allocated by create_dh() + * @param nonce_i initiators nonce value + * @param nonce_r responders nonce value + * @param id IKE_SA identifier + * @param rekey_prf PRF of old SA if rekeying, PRF_UNDEFINED otherwise + * @param rekey_sdk SKd of old SA if rekeying + * @return TRUE on success + */ + bool (*derive_ike_keys)(keymat_v2_t *this, proposal_t *proposal, + diffie_hellman_t *dh, chunk_t nonce_i, + chunk_t nonce_r, ike_sa_id_t *id, + pseudo_random_function_t rekey_function, + chunk_t rekey_skd); + + /** + * Derive keys for a CHILD_SA. + * + * The keys for the CHILD_SA are allocated in the integ and encr chunks. + * An implementation might hand out encrypted keys only, which are + * decrypted in the kernel before use. + * If no PFS is used for the CHILD_SA, dh can be NULL. + * + * @param proposal selected algorithms + * @param dh diffie hellman key allocated by create_dh(), or NULL + * @param nonce_i initiators nonce value + * @param nonce_r responders nonce value + * @param encr_i chunk to write initiators encryption key to + * @param integ_i chunk to write initiators integrity key to + * @param encr_r chunk to write responders encryption key to + * @param integ_r chunk to write responders integrity key to + * @return TRUE on success + */ + bool (*derive_child_keys)(keymat_v2_t *this, + proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, + chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r); + /** + * Get SKd to pass to derive_ikey_keys() during rekeying. + * + * @param skd chunk to write SKd to (internal data) + * @return PRF function to derive keymat + */ + pseudo_random_function_t (*get_skd)(keymat_v2_t *this, chunk_t *skd); + + /** + * Generate octets to use for authentication procedure (RFC4306 2.15). + * + * This method creates the plain octets and is usually signed by a private + * key. PSK and EAP authentication include a secret into the data, use + * the get_psk_sig() method instead. + * + * @param verify TRUE to create for verfification, FALSE to sign + * @param ike_sa_init encoded ike_sa_init message + * @param nonce nonce value + * @param id identity + * @param reserved reserved bytes of id_payload + * @return authentication octets + */ + chunk_t (*get_auth_octets)(keymat_v2_t *this, bool verify, + chunk_t ike_sa_init, chunk_t nonce, + identification_t *id, char reserved[3]); + /** + * Build the shared secret signature used for PSK and EAP authentication. + * + * This method wraps the get_auth_octets() method and additionally + * includes the secret into the signature. If no secret is given, SK_p is + * used as secret (used for EAP methods without MSK). + * + * @param verify TRUE to create for verfification, FALSE to sign + * @param ike_sa_init encoded ike_sa_init message + * @param nonce nonce value + * @param secret optional secret to include into signature + * @param id identity + * @param reserved reserved bytes of id_payload + * @return signature octets + */ + chunk_t (*get_psk_sig)(keymat_v2_t *this, bool verify, chunk_t ike_sa_init, + chunk_t nonce, chunk_t secret, + identification_t *id, char reserved[3]); }; /** diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index 7a89e6f62..b0d50efa6 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -18,6 +18,7 @@ #include "child_create.h" #include +#include #include #include #include @@ -109,7 +110,7 @@ struct private_child_create_t { /** * IKE_SAs keymat */ - keymat_t *keymat; + keymat_v2_t *keymat; /** * mode the new CHILD_SA uses (transport/tunnel/beet) @@ -683,7 +684,8 @@ static void process_payloads(private_child_create_t *this, message_t *message) if (!this->initiator) { this->dh_group = ke_payload->get_dh_group_number(ke_payload); - this->dh = this->keymat->create_dh(this->keymat, this->dh_group); + this->dh = this->keymat->keymat.create_dh( + &this->keymat->keymat, this->dh_group); } if (this->dh) { @@ -815,7 +817,8 @@ METHOD(task_t, build_i, status_t, if (this->dh_group != MODP_NONE) { - this->dh = this->keymat->create_dh(this->keymat, this->dh_group); + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + this->dh_group); } if (this->config->use_ipcomp(this->config)) @@ -1307,7 +1310,7 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, .packet_tsi = tsi ? tsi->clone(tsi) : NULL, .packet_tsr = tsr ? tsr->clone(tsr) : NULL, .dh_group = MODP_NONE, - .keymat = ike_sa->get_keymat(ike_sa), + .keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa), .mode = MODE_TUNNEL, .tfcv3 = TRUE, .ipcomp = IPCOMP_NONE, diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/tasks/ike_init.c index 390756706..868680bb6 100644 --- a/src/libcharon/sa/tasks/ike_init.c +++ b/src/libcharon/sa/tasks/ike_init.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -68,7 +69,7 @@ struct private_ike_init_t { /** * Keymat derivation (from IKE_SA) */ - keymat_t *keymat; + keymat_v2_t *keymat; /** * nonce chosen by us @@ -199,8 +200,8 @@ static void process_payloads(private_ike_init_t *this, message_t *message) this->dh_group = ke_payload->get_dh_group_number(ke_payload); if (!this->initiator) { - this->dh = this->keymat->create_dh(this->keymat, - this->dh_group); + this->dh = this->keymat->keymat.create_dh( + &this->keymat->keymat, this->dh_group); } if (this->dh) { @@ -245,7 +246,8 @@ METHOD(task_t, build_i, status_t, if (!this->dh) { this->dh_group = this->config->get_dh_group(this->config); - this->dh = this->keymat->create_dh(this->keymat, this->dh_group); + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + this->dh_group); if (!this->dh) { DBG1(DBG_IKE, "configured DH group %N not supported", @@ -329,7 +331,7 @@ METHOD(task_t, process_r, status_t, static bool derive_keys(private_ike_init_t *this, chunk_t nonce_i, chunk_t nonce_r) { - keymat_t *old_keymat; + keymat_v2_t *old_keymat; pseudo_random_function_t prf_alg = PRF_UNDEFINED; chunk_t skd = chunk_empty; ike_sa_id_t *id; @@ -338,7 +340,7 @@ static bool derive_keys(private_ike_init_t *this, if (this->old_sa) { /* rekeying: Include old SKd, use old PRF, apply SPI */ - old_keymat = this->old_sa->get_keymat(this->old_sa); + old_keymat = (keymat_v2_t*)this->old_sa->get_keymat(this->old_sa); prf_alg = old_keymat->get_skd(old_keymat, &skd); if (this->initiator) { @@ -517,10 +519,11 @@ METHOD(task_t, migrate, void, chunk_free(&this->other_nonce); this->ike_sa = ike_sa; - this->keymat = ike_sa->get_keymat(ike_sa); + this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); this->proposal = NULL; DESTROY_IF(this->dh); - this->dh = this->keymat->create_dh(this->keymat, this->dh_group); + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + this->dh_group); } METHOD(task_t, destroy, void, @@ -567,7 +570,7 @@ ike_init_t *ike_init_create(ike_sa_t *ike_sa, bool initiator, ike_sa_t *old_sa) .ike_sa = ike_sa, .initiator = initiator, .dh_group = MODP_NONE, - .keymat = ike_sa->get_keymat(ike_sa), + .keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa), .old_sa = old_sa, ); From 50d493808c84fb042244119d41f65ee9fa76f358 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 11:05:43 +0100 Subject: [PATCH 070/534] Avoid compiler warnings due to extended enums. --- src/libcharon/encoding/generator.c | 2 +- src/libcharon/encoding/parser.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index a378426ab..c6819292a 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -423,7 +423,7 @@ METHOD(generator_t, generate_payload, void, { DBG2(DBG_ENC, " generating rule %d %N", i, encoding_type_names, rules[i].type); - switch (rules[i].type) + switch ((int)rules[i].type) { case U_INT_4: case U_INT_8: diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 39ce2db67..1a7f297da 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -390,7 +390,7 @@ METHOD(parser_t, parse_payload, status_t, rule = &(this->rules[rule_number]); DBG2(DBG_ENC, " parsing rule %d %N", rule_number, encoding_type_names, rule->type); - switch (rule->type) + switch ((int)rule->type) { case U_INT_4: { From 0cec72df400b7009c839248872b030450d20fe02 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 11:18:08 +0100 Subject: [PATCH 071/534] Provide keymat_t to message_t to encrypt/decrypt data. --- src/libcharon/encoding/message.c | 15 ++++++++------- src/libcharon/encoding/message.h | 14 +++++++------- src/libcharon/sa/ike_sa.c | 6 ++---- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 2bd52ec4c..79cc86ed4 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -24,10 +24,8 @@ #include #include -#include #include #include -#include #include #include #include @@ -1334,13 +1332,14 @@ METHOD(message_t, disable_sort, void, } METHOD(message_t, generate, status_t, - private_message_t *this, aead_t *aead, packet_t **packet) + private_message_t *this, keymat_t *keymat, packet_t **packet) { generator_t *generator; ike_header_t *ike_header; payload_t *payload, *next; encryption_payload_t *encryption = NULL; enumerator_t *enumerator; + aead_t *aead; chunk_t chunk; char str[BUF_LEN]; u_int32_t *lenpos; @@ -1374,6 +1373,7 @@ METHOD(message_t, generate, status_t, DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); + aead = keymat->get_aead(keymat, FALSE); if (aead && this->rule->encrypted) { encryption = wrap_payloads(this); @@ -1609,13 +1609,14 @@ static status_t parse_payloads(private_message_t *this) /** * Decrypt payload from the encryption payload */ -static status_t decrypt_payloads(private_message_t *this, aead_t *aead) +static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) { bool was_encrypted = FALSE; payload_t *payload, *previous = NULL; enumerator_t *enumerator; payload_rule_t *rule; payload_type_t type; + aead_t *aead; status_t status = SUCCESS; enumerator = this->payloads->create_enumerator(this->payloads); @@ -1641,6 +1642,7 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead) status = VERIFY_ERROR; break; } + aead = keymat->get_aead(keymat, TRUE); encryption->set_transform(encryption, aead); chunk = this->packet->get_data(this->packet); if (chunk.len < encryption->get_length(encryption)) @@ -1752,7 +1754,7 @@ static status_t verify(private_message_t *this) } METHOD(message_t, parse_body, status_t, - private_message_t *this, aead_t *aead) + private_message_t *this, keymat_t *keymat) { status_t status = SUCCESS; char str[BUF_LEN]; @@ -1775,7 +1777,7 @@ METHOD(message_t, parse_body, status_t, return status; } - status = decrypt_payloads(this, aead); + status = decrypt_payloads(this, keymat); if (status != SUCCESS) { DBG1(DBG_ENC, "could not decrypt payloads"); @@ -1872,4 +1874,3 @@ message_t *message_create(int major, int minor) return this; } - diff --git a/src/libcharon/encoding/message.h b/src/libcharon/encoding/message.h index dd18b4bd9..6f3c7967f 100644 --- a/src/libcharon/encoding/message.h +++ b/src/libcharon/encoding/message.h @@ -27,15 +27,15 @@ typedef struct message_t message_t; #include -#include #include #include #include +#include +#include #include -#include /** - * This class is used to represent an IKEv2-Message. + * This class is used to represent an IKE-Message. * * The message handles parsing and generation of payloads * via parser_t/generator_t. Encryption is done transparently @@ -228,7 +228,7 @@ struct message_t { * If there are encrypted payloads, they get decrypted and verified using * the given aead transform (if given). * - * @param aead aead transform to verify/decrypt message + * @param keymat keymat to verify/decrypt message * @return * - SUCCESS if parsing successful * - PARSE_ERROR if message parsing failed @@ -236,7 +236,7 @@ struct message_t { * - FAILED if integrity check failed * - INVALID_STATE if aead not supplied, but needed */ - status_t (*parse_body) (message_t *this, aead_t *aead); + status_t (*parse_body) (message_t *this, keymat_t *keymat); /** * Generates the UDP packet of specific message. @@ -247,7 +247,7 @@ struct message_t { * Generation is only done once, multiple calls will just return a copy * of the packet. * - * @param aead aead transform to encrypt/sign message + * @param keymat keymat to encrypt/sign message * @param packet copy of generated packet * @return * - SUCCESS if packet could be generated @@ -255,7 +255,7 @@ struct message_t { * - NOT_FOUND if no rules found for message generation * - INVALID_STATE if aead not supplied but needed. */ - status_t (*generate) (message_t *this, aead_t *aead, packet_t **packet); + status_t (*generate) (message_t *this, keymat_t *keymat, packet_t **packet); /** * Check if the message has already been encoded using generate(). diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 1f8799890..b9b2bb82e 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -920,8 +920,7 @@ METHOD(ike_sa_t, generate_message, status_t, this->stats[STAT_OUTBOUND] = time_monotonic(NULL); message->set_ike_sa_id(message, this->ike_sa_id); charon->bus->message(charon->bus, message, FALSE); - return message->generate(message, - this->keymat->get_aead(this->keymat, FALSE), packet); + return message->generate(message, this->keymat, packet); } /** @@ -1227,8 +1226,7 @@ METHOD(ike_sa_t, process_message, status_t, is_request = message->get_request(message); - status = message->parse_body(message, - this->keymat->get_aead(this->keymat, TRUE)); + status = message->parse_body(message, this->keymat); if (status == SUCCESS) { /* check for unsupported critical payloads */ enumerator_t *enumerator; From 3d59c5c3820f51ad875beb539f37020bf0582096 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 11:24:38 +0100 Subject: [PATCH 072/534] Update cached hosts on ike_sa_t when processing IKEv1 messages. --- src/libcharon/sa/task_manager_v1.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index c96adaa39..9be034fb2 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -531,14 +531,20 @@ METHOD(task_manager_t, process_message, status_t, private_task_manager_t *this, message_t *msg) { u_int32_t hash, mid; + host_t *me, *other; mid = msg->get_message_id(msg); hash = chunk_hash(msg->get_packet_data(msg)); + /* TODO-IKEv1: update hosts more selectively */ + me = msg->get_destination(msg); + other = msg->get_source(msg); + if ((mid && mid == this->initiating.mid) || (this->initiating.mid == 0 && this->active_tasks->get_count(this->active_tasks))) { + this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); charon->bus->message(charon->bus, msg, FALSE); if (process_response(this, msg) != SUCCESS) { @@ -557,7 +563,7 @@ METHOD(task_manager_t, process_message, status_t, this->responding.packet->clone(this->responding.packet)); return SUCCESS; } - + this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); charon->bus->message(charon->bus, msg, TRUE); if (process_request(this, msg) != SUCCESS) { From b05d91edd7774e3bfe99146fe9557ff6bac90469 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 11:41:37 +0100 Subject: [PATCH 073/534] Added IKEv1 key derivation with support for AUTH_CLASS_PSK. --- src/libcharon/sa/keymat_v1.c | 200 ++++++++++++++++++++++++++++++----- src/libcharon/sa/keymat_v1.h | 22 ++++ 2 files changed, 198 insertions(+), 24 deletions(-) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index e4f58a499..59791e27a 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -44,35 +44,183 @@ struct private_keymat_v1_t { */ pseudo_random_function_t prf_alg; + /** + * Key used for authentication during main mode + */ + chunk_t skeyid; + + /** + * Key to derive key material from for non-ISAKMP SAs, rekeying + */ + chunk_t skeyid_d; + + /** + * Key used for authentication after main mode + */ + chunk_t skeyid_a; }; +/** + * Constants used in key derivation. + */ +static const chunk_t octet_0 = chunk_from_chars(0x00); +static const chunk_t octet_1 = chunk_from_chars(0x01); +static const chunk_t octet_2 = chunk_from_chars(0x02); + + +/** + * Converts integrity algorithm to PRF algorithm + */ +static u_int16_t auth_to_prf(u_int16_t alg) +{ + switch (alg) + { + case AUTH_HMAC_SHA1_96: + return PRF_HMAC_SHA1; + case AUTH_HMAC_SHA2_256_128: + return PRF_HMAC_SHA2_256; + case AUTH_HMAC_SHA2_384_192: + return PRF_HMAC_SHA2_384; + case AUTH_HMAC_SHA2_512_256: + return PRF_HMAC_SHA2_512; + case AUTH_HMAC_MD5_96: + return PRF_HMAC_MD5; + case AUTH_AES_XCBC_96: + return PRF_AES128_XCBC; + default: + return PRF_UNDEFINED; + } +} + +/** + * Adjust the key length for PRF algorithms that expect a fixed key length. + */ +static void adjust_keylen(u_int16_t alg, chunk_t *key) +{ + 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. */ + key->len = min(key->len, 16); + break; + default: + /* all other algorithms use variable key length */ + break; + } +} + +METHOD(keymat_v1_t, derive_ike_keys, bool, + private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, + auth_class_t auth, shared_key_t *shared_key) +{ + chunk_t g_xy, g_xi, g_xr, dh_me, spi_i, spi_r, nonces, data, skeyid_e; + u_int16_t alg; + + spi_i = chunk_alloca(sizeof(u_int64_t)); + spi_r = chunk_alloca(sizeof(u_int64_t)); + + if (!proposal->get_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, &alg, NULL)) + { /* no PRF negotiated, use HMAC version of integrity algorithm instead */ + if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL) + || (alg = auth_to_prf(alg)) == PRF_UNDEFINED) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, PSEUDO_RANDOM_FUNCTION); + return FALSE; + } + } + this->prf_alg = alg; + this->prf = lib->crypto->create_prf(lib->crypto, alg); + if (!this->prf) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, PSEUDO_RANDOM_FUNCTION, + pseudo_random_function_names, alg); + return FALSE; + } + if (this->prf->get_block_size(this->prf) < + this->prf->get_key_size(this->prf)) + { /* TODO-IKEv1: support PRF output expansion (RFC 2409, Appendix B) */ + DBG1(DBG_IKE, "expansion of %N %N output not supported!", + transform_type_names, PSEUDO_RANDOM_FUNCTION, + pseudo_random_function_names, alg); + return FALSE; + } + + if (dh->get_shared_secret(dh, &g_xy) != SUCCESS) + { + return FALSE; + } + DBG4(DBG_IKE, "shared Diffie Hellman secret %B", &g_xy); + + *((u_int64_t*)spi_i.ptr) = id->get_initiator_spi(id); + *((u_int64_t*)spi_r.ptr) = id->get_responder_spi(id); + nonces = chunk_cata("cc", nonce_i, nonce_r); + + switch (auth) + { + case AUTH_CLASS_PSK: + { /* SKEYID = prf(pre-shared-key, Ni_b | Nr_b) */ + chunk_t psk; + if (!shared_key) + { + chunk_clear(&g_xy); + return FALSE; + } + psk = shared_key->get_key(shared_key); + adjust_keylen(alg, &psk); + this->prf->set_key(this->prf, psk); + this->prf->allocate_bytes(this->prf, nonces, &this->skeyid); + break; + } + case AUTH_CLASS_PUBKEY: + { + /* signatures : SKEYID = prf(Ni_b | Nr_b, g^xy) + * pubkey encr: SKEYID = prf(hash(Ni_b | Nr_b), CKY-I | CKY-R) */ + /* TODO-IKEv1: implement key derivation for other schemes, + * fall for now */ + } + default: + /* authentication class not supported */ + chunk_clear(&g_xy); + return FALSE; + } + adjust_keylen(alg, &this->skeyid); + DBG4(DBG_IKE, "SKEYID %B", &this->skeyid); + + /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */ + data = chunk_cat("cccc", g_xy, spi_i, spi_r, octet_0); + this->prf->set_key(this->prf, this->skeyid); + this->prf->allocate_bytes(this->prf, data, &this->skeyid_d); + chunk_clear(&data); + DBG4(DBG_IKE, "SKEYID_d %B", &this->skeyid_d); + + /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */ + data = chunk_cat("ccccc", this->skeyid_d, g_xy, spi_i, spi_r, octet_1); + this->prf->set_key(this->prf, this->skeyid); + this->prf->allocate_bytes(this->prf, data, &this->skeyid_a); + chunk_clear(&data); + DBG4(DBG_IKE, "SKEYID_a %B", &this->skeyid_a); + + /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */ + data = chunk_cat("ccccc", this->skeyid_a, g_xy, spi_i, spi_r, octet_2); + this->prf->set_key(this->prf, this->skeyid); + this->prf->allocate_bytes(this->prf, data, &skeyid_e); + chunk_clear(&data); + DBG4(DBG_IKE, "SKEYID_e %B", &skeyid_e); + + chunk_clear(&g_xy); + + return TRUE; +} + METHOD(keymat_t, create_dh, diffie_hellman_t*, private_keymat_v1_t *this, diffie_hellman_group_t group) { - return lib->crypto->create_dh(lib->crypto, group);; -} - -METHOD(keymat_t, derive_ike_keys, bool, - private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, - pseudo_random_function_t rekey_function, chunk_t rekey_skd) -{ - return FALSE; -} - -METHOD(keymat_t, derive_child_keys, bool, - private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, - chunk_t *encr_r, chunk_t *integ_r) -{ - return FALSE; -} - -METHOD(keymat_t, get_skd, pseudo_random_function_t, - private_keymat_v1_t *this, chunk_t *skd) -{ - *skd = chunk_empty; - return this->prf_alg; + return lib->crypto->create_dh(lib->crypto, group); } METHOD(keymat_t, get_aead, aead_t*, @@ -85,6 +233,9 @@ METHOD(keymat_t, destroy, void, private_keymat_v1_t *this) { DESTROY_IF(this->prf); + chunk_clear(&this->skeyid); + chunk_clear(&this->skeyid_d); + chunk_clear(&this->skeyid_a); free(this); } @@ -102,6 +253,7 @@ keymat_v1_t *keymat_v1_create(bool initiator) .get_aead = _get_aead, .destroy = _destroy, }, + .derive_ike_keys = _derive_ike_keys, }, .initiator = initiator, .prf_alg = PRF_UNDEFINED, diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h index 68057fa06..e85d239e9 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/keymat_v1.h @@ -34,6 +34,28 @@ struct keymat_v1_t { * Implements keymat_t. */ keymat_t keymat; + + /** + * Derive keys for the IKE_SA. + * + * These keys are not handed out, but are used by the associated signers, + * crypters and authentication functions. + * + * @param proposal selected algorithms + * @param dh diffie hellman key allocated by create_dh() + * @param dh_other public DH value from other peer + * @param nonce_i initiators nonce value + * @param nonce_r responders nonce value + * @param id IKE_SA identifier + * @param auth authentication method + * @param shared_key PSK in case of AUTH_CLASS_PSK, NULL otherwise + * @return TRUE on success + */ + bool (*derive_ike_keys)(keymat_v1_t *this, proposal_t *proposal, + diffie_hellman_t *dh, chunk_t dh_other, + chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, + auth_class_t auth, shared_key_t *shared_key); + }; /** From aadb9e83550ab24e393c1a0622ed117c984362a9 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 11:43:43 +0100 Subject: [PATCH 074/534] Added a simple AEAD wrapper for IKEv1 encryption/decryption. --- src/libcharon/sa/keymat_v1.c | 156 ++++++++++++++++++++++++++++++++++- 1 file changed, 155 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 59791e27a..3592a3e22 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -44,6 +44,11 @@ struct private_keymat_v1_t { */ pseudo_random_function_t prf_alg; + /** + * Crypter wrapped in an aead_t interface + */ + aead_t *aead; + /** * Key used for authentication during main mode */ @@ -67,6 +72,148 @@ static const chunk_t octet_0 = chunk_from_chars(0x00); static const chunk_t octet_1 = chunk_from_chars(0x01); static const chunk_t octet_2 = chunk_from_chars(0x02); +/** + * Simple aead_t implementation without support for authentication. + */ +typedef struct { + /** implements aead_t interface */ + aead_t aead; + /** crypter to be used */ + crypter_t *crypter; +} private_aead_t; + + +METHOD(aead_t, encrypt, void, + private_aead_t *this, chunk_t plain, chunk_t assoc, chunk_t iv, + chunk_t *encrypted) +{ + this->crypter->encrypt(this->crypter, plain, iv, encrypted); +} + +METHOD(aead_t, decrypt, bool, + private_aead_t *this, chunk_t encrypted, chunk_t assoc, chunk_t iv, + chunk_t *plain) +{ + this->crypter->decrypt(this->crypter, encrypted, iv, plain); + return TRUE; +} + +METHOD(aead_t, get_block_size, size_t, + private_aead_t *this) +{ + return this->crypter->get_block_size(this->crypter); +} + +METHOD(aead_t, get_icv_size, size_t, + private_aead_t *this) +{ + return 0; +} + +METHOD(aead_t, get_iv_size, size_t, + private_aead_t *this) +{ + /* in order to create the messages properly we return 0 here */ + return 0; +} + +METHOD(aead_t, get_key_size, size_t, + private_aead_t *this) +{ + return this->crypter->get_key_size(this->crypter); +} + +METHOD(aead_t, set_key, void, + private_aead_t *this, chunk_t key) +{ + this->crypter->set_key(this->crypter, key); +} + +METHOD(aead_t, aead_destroy, void, + private_aead_t *this) +{ + this->crypter->destroy(this->crypter); + free(this); +} + +/** + * Expand SKEYID_e according to Appendix B in RFC 2409. + * TODO-IKEv1: verify keys (e.g. for weak keys, see Appendix B) + */ +static chunk_t expand_skeyid_e(chunk_t skeyid_e, size_t key_size, prf_t *prf) +{ + size_t block_size; + chunk_t seed, ka; + int i; + + if (skeyid_e.len >= key_size) + { /* no expansion required, reduce to key_size */ + skeyid_e.len = key_size; + return skeyid_e; + } + block_size = prf->get_block_size(prf); + ka = chunk_alloc((key_size / block_size + 1) * block_size); + ka.len = key_size; + + /* Ka = K1 | K2 | ..., K1 = prf(SKEYID_e, 0), K2 = prf(SKEYID_e, K1) ... */ + prf->set_key(prf, skeyid_e); + seed = octet_0; + for (i = 0; i < key_size; i += block_size) + { + prf->get_bytes(prf, seed, ka.ptr + i); + seed = chunk_create(ka.ptr + i, block_size); + } + chunk_clear(&skeyid_e); + return ka; +} + +/** + * Create a simple implementation of the aead_t interface which only encrypts + * or decrypts data. + */ +static aead_t *create_aead(proposal_t *proposal, prf_t *prf, chunk_t skeyid_e) +{ + private_aead_t *this; + u_int16_t alg, key_size; + crypter_t *crypter; + chunk_t ka; + + if (!proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &alg, + &key_size)) + { + DBG1(DBG_IKE, "no %N selected", + transform_type_names, ENCRYPTION_ALGORITHM); + return NULL; + } + crypter = lib->crypto->create_crypter(lib->crypto, alg, key_size / 8); + if (!crypter) + { + DBG1(DBG_IKE, "%N %N (key size %d) not supported!", + transform_type_names, ENCRYPTION_ALGORITHM, + encryption_algorithm_names, alg, key_size); + return NULL; + } + key_size = crypter->get_key_size(crypter); + ka = expand_skeyid_e(skeyid_e, crypter->get_key_size(crypter), prf); + DBG4(DBG_IKE, "encryption key Ka %B", &ka); + crypter->set_key(crypter, ka); + chunk_clear(&ka); + + INIT(this, + .aead = { + .encrypt = _encrypt, + .decrypt = _decrypt, + .get_block_size = _get_block_size, + .get_icv_size = _get_icv_size, + .get_iv_size = _get_iv_size, + .get_key_size = _get_key_size, + .set_key = _set_key, + .destroy = _aead_destroy, + }, + .crypter = crypter, + ); + return &this->aead; +} /** * Converts integrity algorithm to PRF algorithm @@ -214,6 +361,12 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, chunk_clear(&g_xy); + this->aead = create_aead(proposal, this->prf, skeyid_e); + if (!this->aead) + { + return FALSE; + } + return TRUE; } @@ -226,13 +379,14 @@ METHOD(keymat_t, create_dh, diffie_hellman_t*, METHOD(keymat_t, get_aead, aead_t*, private_keymat_v1_t *this, bool in) { - return NULL; + return this->aead; } METHOD(keymat_t, destroy, void, private_keymat_v1_t *this) { DESTROY_IF(this->prf); + DESTROY_IF(this->aead); chunk_clear(&this->skeyid); chunk_clear(&this->skeyid_d); chunk_clear(&this->skeyid_a); From 0463674971183a72dcc5923e26ff21c7a6a4efed Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 11:46:18 +0100 Subject: [PATCH 075/534] Use key derivation in IKEv1 main mode (PSK authentication). --- src/libcharon/sa/tasks/main_mode.c | 81 +++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 2d9acf611..89ecaf408 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2011 Martin Willi * Copyright (C) 2011 revosec AG * @@ -18,6 +21,7 @@ #include #include +#include #include #include #include @@ -76,6 +80,11 @@ struct private_main_mode_t { */ diffie_hellman_t *dh; + /** + * Keymat derivation (from SA) + */ + keymat_v1_t *keymat; + /** * Received public DH value from peer */ @@ -156,7 +165,8 @@ METHOD(task_t, build_i, status_t, DBG1(DBG_IKE, "DH group selection failed"); return FAILED; } - this->dh = lib->crypto->create_dh(lib->crypto, group); + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + group); if (!this->dh) { DBG1(DBG_IKE, "negotiated DH group not supported"); @@ -355,6 +365,68 @@ METHOD(task_t, process_r, status_t, } } +/** + * Lookup a shared secret for this IKE_SA + */ +static shared_key_t *lookup_shared_key(private_main_mode_t *this) +{ + host_t *me, *other; + identification_t *my_id, *other_id; + shared_key_t *shared_key; + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + my_id = identification_create_from_sockaddr(me->get_sockaddr(me)); + other_id = identification_create_from_sockaddr(other->get_sockaddr(other)); + if (!my_id || !other_id) + { + DESTROY_IF(my_id); + DESTROY_IF(other_id); + return NULL; + } + shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, my_id, + other_id); + if (!shared_key) + { + DBG1(DBG_IKE, "no shared key found for %H - %H", me, other); + } + my_id->destroy(my_id); + other_id->destroy(other_id); + return shared_key; +} + +/** + * Derive key material for this IKE_SA + */ +static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, + chunk_t nonce_r) +{ + ike_sa_id_t *id = this->ike_sa->get_id(this->ike_sa); + shared_key_t *shared_key = NULL; + auth_class_t auth; + + /* TODO-IKEv1: support other authentication classes */ + auth = AUTH_CLASS_PSK; + switch (auth) + { + case AUTH_CLASS_PSK: + shared_key = lookup_shared_key(this); + break; + default: + break; + } + if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh, + this->dh_value, nonce_i, nonce_r, id, auth, shared_key)) + { + DESTROY_IF(shared_key); + return FALSE; + } + DESTROY_IF(shared_key); + charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, nonce_i, nonce_r, + NULL); + return TRUE; +} + METHOD(task_t, build_r, status_t, private_main_mode_t *this, message_t *message) { @@ -388,6 +460,12 @@ METHOD(task_t, build_r, status_t, rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_r); rng->destroy(rng); + if (!derive_keys(this, this->nonce_i, this->nonce_r)) + { + DBG1(DBG_IKE, "key derivation failed"); + return FAILED; + } + nonce_payload = nonce_payload_create(NONCE_V1); nonce_payload->set_nonce(nonce_payload, this->nonce_r); message->add_payload(message, &nonce_payload->payload_interface); @@ -564,6 +642,7 @@ main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator) }, }, .ike_sa = ike_sa, + .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa), .initiator = initiator, .state = MM_INIT, ); From 6f5f8ee4b59484e15cc1cba356cfe37b6c4a9c23 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 11:53:23 +0100 Subject: [PATCH 076/534] Use modified encryption payload to encrypt/decrypt complete IKEv1 messages. --- src/libcharon/encoding/generator.c | 1 + src/libcharon/encoding/parser.c | 10 ++ src/libcharon/encoding/payloads/encodings.c | 3 +- src/libcharon/encoding/payloads/encodings.h | 5 + .../encoding/payloads/encryption_payload.c | 131 +++++++++++++++++- .../encoding/payloads/encryption_payload.h | 3 +- src/libcharon/encoding/payloads/payload.c | 3 +- src/libcharon/encoding/payloads/payload.h | 15 +- 8 files changed, 156 insertions(+), 15 deletions(-) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index c6819292a..2c9298e11 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -449,6 +449,7 @@ METHOD(generator_t, generate_payload, void, case ADDRESS: case SPI: case CHUNK_DATA: + case ENCRYPTED_DATA: generate_from_chunk(this, rules[i].offset); break; case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE: diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 1a7f297da..b93651bbe 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -516,6 +516,16 @@ METHOD(parser_t, parse_payload, status_t, } break; } + case ENCRYPTED_DATA: + { + if (!parse_chunk(this, rule_number, output + rule->offset, + this->input_roof - this->byte_pos)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } case ATTRIBUTE_FORMAT: { if (!parse_bit(this, rule_number, output + rule->offset)) diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index 3dc8ee4ec..7306dcf10 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -17,7 +17,7 @@ #include "encodings.h" -ENUM(encoding_type_names, U_INT_4, IKE_SPI, +ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "U_INT_4", "U_INT_8", "U_INT_16", @@ -38,4 +38,5 @@ ENUM(encoding_type_names, U_INT_4, IKE_SPI, "ADDRESS", "CHUNK_DATA", "IKE_SPI", + "ENCRYPTED", ); diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index dde495bc2..124814ff5 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -296,6 +296,11 @@ enum encoding_type_t { */ IKE_SPI, + /** + * Representating an encrypted IKEv1 message. + */ + ENCRYPTED_DATA, + /** * Reprensenting a field containing a set of wrapped payloads. * diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c index bb9969d0b..425e58621 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.c +++ b/src/libcharon/encoding/payloads/encryption_payload.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2010 revosec AG + * Copyright (C) 2011 Tobias Brunner * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -71,6 +72,11 @@ struct private_encryption_payload_t { * Contained payloads */ linked_list_t *payloads; + + /** + * Type of payload, ENCRYPTED or ENCRYPTED_V1 + */ + payload_type_t type; }; /** @@ -79,7 +85,7 @@ struct private_encryption_payload_t { * The defined offsets are the positions in a object of type * private_encryption_payload_t. */ -static encoding_rule_t encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_encryption_payload_t, next_payload) }, /* Critical and 7 reserved bits, all stored for reconstruction */ @@ -109,6 +115,29 @@ static encoding_rule_t encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules to parse or generate a complete encrypted IKEv1 message. + * + * The defined offsets are the positions in a object of type + * private_encryption_payload_t. + */ +static encoding_rule_t encodings_v1[] = { + /* encrypted data, stored in a chunk */ + { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Message Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Encrypted IKE Payloads ! + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! Padding (0-255 octets) ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_encryption_payload_t *this) { @@ -118,20 +147,29 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, int, private_encryption_payload_t *this, encoding_rule_t **rules) { - *rules = encodings; - return countof(encodings); + if (this->type == ENCRYPTED) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); } METHOD(payload_t, get_header_length, int, private_encryption_payload_t *this) { - return 4; + if (this->type == ENCRYPTED) + { + return 4; + } + return 0; } METHOD(payload_t, get_type, payload_type_t, private_encryption_payload_t *this) { - return ENCRYPTED; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -143,7 +181,8 @@ METHOD(payload_t, get_next_type, payload_type_t, METHOD(payload_t, set_next_type, void, private_encryption_payload_t *this, payload_type_t type) { - /* the next payload is set during add */ + /* the next payload is set during add, still allow this for IKEv1 */ + this->next_payload = type; } /** @@ -340,6 +379,47 @@ METHOD(encryption_payload_t, encrypt, bool, return TRUE; } +METHOD(encryption_payload_t, encrypt_v1, bool, + private_encryption_payload_t *this, chunk_t iv) +{ + generator_t *generator; + chunk_t plain, padding; + size_t bs; + + if (this->aead == NULL) + { + DBG1(DBG_ENC, "encryption failed, transform missing"); + chunk_free(&iv); + return FALSE; + } + + generator = generator_create(); + plain = generate(this, generator); + bs = this->aead->get_block_size(this->aead); + padding.len = bs - (plain.len % bs); + + /* prepare data to encrypt: + * | plain | padding | */ + free(this->encrypted.ptr); + this->encrypted = chunk_alloc(plain.len + padding.len); + memcpy(this->encrypted.ptr, plain.ptr, plain.len); + plain.ptr = this->encrypted.ptr; + padding.ptr = plain.ptr + plain.len; + memset(padding.ptr, 0, padding.len); + generator->destroy(generator); + + DBG3(DBG_ENC, "encrypting payloads:"); + DBG3(DBG_ENC, "plain %B", &plain); + DBG3(DBG_ENC, "padding %B", &padding); + + this->aead->encrypt(this->aead, this->encrypted, chunk_empty, iv, NULL); + chunk_free(&iv); + + DBG3(DBG_ENC, "encrypted %B", &this->encrypted); + + return TRUE; +} + /** * Parse the payloads after decryption. */ @@ -443,6 +523,36 @@ METHOD(encryption_payload_t, decrypt, status_t, return parse(this, plain); } +METHOD(encryption_payload_t, decrypt_v1, status_t, + private_encryption_payload_t *this, chunk_t iv) +{ + if (this->aead == NULL) + { + DBG1(DBG_ENC, "decryption failed, transform missing"); + chunk_free(&iv); + return INVALID_STATE; + } + + /* data must be a multiple of block size */ + if (iv.len != this->aead->get_block_size(this->aead) || + this->encrypted.len < iv.len || this->encrypted.len % iv.len) + { + DBG1(DBG_ENC, "decryption failed, invalid length"); + chunk_free(&iv); + return FAILED; + } + + DBG3(DBG_ENC, "decrypting payloads:"); + DBG3(DBG_ENC, "encrypted %B", &this->encrypted); + + this->aead->decrypt(this->aead, this->encrypted, chunk_empty, iv, NULL); + chunk_free(&iv); + + DBG3(DBG_ENC, "plain %B", &this->encrypted); + + return parse(this, this->encrypted); +} + METHOD(encryption_payload_t, set_transform, void, private_encryption_payload_t *this, aead_t* aead) { @@ -460,7 +570,7 @@ METHOD2(payload_t, encryption_payload_t, destroy, void, /* * Described in header */ -encryption_payload_t *encryption_payload_create() +encryption_payload_t *encryption_payload_create(payload_type_t type) { private_encryption_payload_t *this; @@ -487,7 +597,14 @@ encryption_payload_t *encryption_payload_create() .next_payload = NO_PAYLOAD, .payload_length = get_header_length(this), .payloads = linked_list_create(), + .type = type, ); + if (type == ENCRYPTED_V1) + { + this->public.encrypt = _encrypt_v1; + this->public.decrypt = _decrypt_v1; + } + return &this->public; } diff --git a/src/libcharon/encoding/payloads/encryption_payload.h b/src/libcharon/encoding/payloads/encryption_payload.h index 3cdc54b37..60774bde0 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.h +++ b/src/libcharon/encoding/payloads/encryption_payload.h @@ -97,8 +97,9 @@ struct encryption_payload_t { /** * Creates an empty encryption_payload_t object. * + * @param type ENCRYPTED or ENCRYPTED_V1 * @return encryption_payload_t object */ -encryption_payload_t *encryption_payload_create(void); +encryption_payload_t *encryption_payload_create(payload_type_t type); #endif /** ENCRYPTION_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 9dc26773a..2f22503e6 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -220,7 +220,8 @@ payload_t *payload_create(payload_type_t type) case EXTENSIBLE_AUTHENTICATION: return (payload_t*)eap_payload_create(); case ENCRYPTED: - return (payload_t*)encryption_payload_create(); + case ENCRYPTED_V1: + return (payload_t*)encryption_payload_create(type); default: return (payload_t*)unknown_payload_create(type); } diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index 84871cfb6..e4ed76abf 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -247,6 +247,11 @@ enum payload_type_t { * CONFIGURATION_ATTRIBUTE, attribute in a configuration payload. */ CONFIGURATION_ATTRIBUTE, + + /** + * This is not really a payload, but rather the complete IKEv1 message. + */ + ENCRYPTED_V1, }; /** @@ -286,35 +291,35 @@ struct payload_t { /** * Get type of payload. * - * @return type of this payload + * @return type of this payload */ payload_type_t (*get_type) (payload_t *this); /** * Get type of next payload or NO_PAYLOAD (0) if this is the last one. * - * @return type of next payload + * @return type of next payload */ payload_type_t (*get_next_type) (payload_t *this); /** * Set type of next payload. * - * @param type type of next payload + * @param type type of next payload */ void (*set_next_type) (payload_t *this,payload_type_t type); /** * Get length of payload. * - * @return length of this payload + * @return length of this payload */ size_t (*get_length) (payload_t *this); /** * Verifies payload structure and makes consistence check. * - * @return SUCCESS, FAILED if consistence not given + * @return SUCCESS, FAILED if consistence not given */ status_t (*verify) (payload_t *this); From b6f0029497c7aead1116c908f0b14b02a56a1769 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 13:11:16 +0100 Subject: [PATCH 077/534] Added IV generation to keymat_v1_t. --- src/libcharon/sa/keymat_v1.c | 198 +++++++++++++++++++++++++++++++++++ src/libcharon/sa/keymat_v1.h | 31 ++++++ 2 files changed, 229 insertions(+) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 3592a3e22..891f6a21e 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -16,9 +16,27 @@ #include "keymat_v1.h" #include +#include typedef struct private_keymat_v1_t private_keymat_v1_t; +/** + * Max. number of IVs to track. + */ +#define MAX_IV 3 + +/** + * Data stored for IVs + */ +typedef struct { + /** message ID */ + u_int32_t mid; + /** current IV */ + chunk_t iv; + /** last block of encrypted message */ + chunk_t last_block; +} iv_data_t; + /** * Private data of an keymat_t object. */ @@ -49,6 +67,11 @@ struct private_keymat_v1_t { */ aead_t *aead; + /** + * Hasher used for IV generation + */ + hasher_t *hasher; + /** * Key used for authentication during main mode */ @@ -63,8 +86,30 @@ struct private_keymat_v1_t { * Key used for authentication after main mode */ chunk_t skeyid_a; + + /** + * Phase 1 IV + */ + iv_data_t phase1_iv; + + /** + * Keep track of IVs for exchanges after phase 1. We store only a limited + * number of IVs in an MRU sort of way. Stores iv_data_t objects. + */ + linked_list_t *ivs; }; + +/** + * Destroy an iv_data_t object. + */ +static void iv_data_destroy(iv_data_t *this) +{ + chunk_free(&this->last_block); + chunk_free(&this->iv); + free(this); +} + /** * Constants used in key derivation. */ @@ -239,6 +284,28 @@ static u_int16_t auth_to_prf(u_int16_t alg) } } +/** + * Converts integrity algorithm to hash algorithm + */ +static u_int16_t auth_to_hash(u_int16_t alg) +{ + switch (alg) + { + case AUTH_HMAC_SHA1_96: + return HASH_SHA1; + case AUTH_HMAC_SHA2_256_128: + return HASH_SHA256; + case AUTH_HMAC_SHA2_384_192: + return HASH_SHA384; + case AUTH_HMAC_SHA2_512_256: + return HASH_SHA512; + case AUTH_HMAC_MD5_96: + return HASH_MD5; + default: + return HASH_UNKNOWN; + } +} + /** * Adjust the key length for PRF algorithms that expect a fixed key length. */ @@ -367,9 +434,132 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, return FALSE; } + if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL) || + (alg = auth_to_hash(alg)) == HASH_UNKNOWN) + { + DBG1(DBG_IKE, "no %N selected", transform_type_names, HASH_ALGORITHM); + return FALSE; + } + this->hasher = lib->crypto->create_hasher(lib->crypto, alg); + if (!this->hasher) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, HASH_ALGORITHM, + hash_algorithm_names, alg); + return FALSE; + } + + dh->get_my_public_value(dh, &dh_me); + g_xi = this->initiator ? dh_me : dh_other; + g_xr = this->initiator ? dh_other : dh_me; + + /* initial IV = hash(g^xi | g^xr) */ + data = chunk_cata("cc", g_xi, g_xr); + this->hasher->allocate_hash(this->hasher, data, &this->phase1_iv.iv); + if (this->phase1_iv.iv.len > this->aead->get_block_size(this->aead)) + { + this->phase1_iv.iv.len = this->aead->get_block_size(this->aead); + } + chunk_free(&dh_me); + DBG4(DBG_IKE, "initial IV %B", &this->phase1_iv.iv); + return TRUE; } +/** + * Generate an IV + */ +static void generate_iv(private_keymat_v1_t *this, iv_data_t *iv) +{ + if (iv->mid == 0 || iv->iv.ptr) + { /* use last block of previous encrypted message */ + chunk_free(&iv->iv); + iv->iv = iv->last_block; + iv->last_block = chunk_empty; + } + else + { + /* initial phase 2 IV = hash(last_phase1_block | mid) */ + u_int32_t net = htonl(iv->mid); + chunk_t data = chunk_cata("cc", this->phase1_iv.iv, + chunk_from_thing(net)); + this->hasher->allocate_hash(this->hasher, data, &iv->iv); + if (iv->iv.len > this->aead->get_block_size(this->aead)) + { + iv->iv.len = this->aead->get_block_size(this->aead); + } + } + DBG4(DBG_IKE, "next IV for MID %u %B", iv->mid, &iv->iv); +} + +/** + * Try to find an IV for the given message ID, if not found, generate it. + */ +static iv_data_t *lookup_iv(private_keymat_v1_t *this, u_int32_t mid) +{ + enumerator_t *enumerator; + iv_data_t *iv, *found = NULL; + + if (mid == 0) + { + return &this->phase1_iv; + } + + enumerator = this->ivs->create_enumerator(this->ivs); + while (enumerator->enumerate(enumerator, &iv)) + { + if (iv->mid == mid) + { /* IV gets moved to the front of the list */ + this->ivs->remove_at(this->ivs, enumerator); + found = iv; + break; + } + } + enumerator->destroy(enumerator); + if (!found) + { + INIT(found, + .mid = mid, + ); + generate_iv(this, found); + } + this->ivs->insert_first(this->ivs, found); + /* remove least recently used IV if maximum reached */ + if (this->ivs->get_count(this->ivs) > MAX_IV && + this->ivs->remove_last(this->ivs, (void**)&iv) == SUCCESS) + { + iv_data_destroy(iv); + } + return found; +} + +METHOD(keymat_v1_t, get_iv, chunk_t, + private_keymat_v1_t *this, u_int32_t mid) +{ + return chunk_clone(lookup_iv(this, mid)->iv); +} + +METHOD(keymat_v1_t, update_iv, void, + private_keymat_v1_t *this, u_int32_t mid, chunk_t last_block) +{ + iv_data_t *iv = lookup_iv(this, mid); + if (iv) + { /* update last block */ + chunk_free(&iv->last_block); + iv->last_block = chunk_clone(last_block); + } +} + +METHOD(keymat_v1_t, confirm_iv, void, + private_keymat_v1_t *this, u_int32_t mid) +{ + iv_data_t *iv = lookup_iv(this, mid); + if (iv) + { + generate_iv(this, iv); + } +} + METHOD(keymat_t, create_dh, diffie_hellman_t*, private_keymat_v1_t *this, diffie_hellman_group_t group) { @@ -387,9 +577,13 @@ METHOD(keymat_t, destroy, void, { DESTROY_IF(this->prf); DESTROY_IF(this->aead); + DESTROY_IF(this->hasher); chunk_clear(&this->skeyid); chunk_clear(&this->skeyid_d); chunk_clear(&this->skeyid_a); + chunk_free(&this->phase1_iv.iv); + chunk_free(&this->phase1_iv.last_block); + this->ivs->destroy_function(this->ivs, (void*)iv_data_destroy); free(this); } @@ -408,7 +602,11 @@ keymat_v1_t *keymat_v1_create(bool initiator) .destroy = _destroy, }, .derive_ike_keys = _derive_ike_keys, + .get_iv = _get_iv, + .update_iv = _update_iv, + .confirm_iv = _confirm_iv, }, + .ivs = linked_list_create(), .initiator = initiator, .prf_alg = PRF_UNDEFINED, ); diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h index e85d239e9..54d4d4392 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/keymat_v1.h @@ -56,6 +56,37 @@ struct keymat_v1_t { chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, auth_class_t auth, shared_key_t *shared_key); + /** + * Returns the IV for a message with the given message ID. + * + * @param mid message ID + * @return IV (needs to be freed) + */ + chunk_t (*get_iv)(keymat_v1_t *this, u_int32_t mid); + + /** + * Updates the IV for the next message with the given message ID. + * + * A call of confirm_iv() is required in order to actually make the IV + * available. This is needed for the inbound case where we store the last + * block of the encrypted message but want to update the IV only after + * verification of the decrypted message. + * + * @param mid message ID + * @param last_block last block of encrypted message (gets cloned) + */ + void (*update_iv)(keymat_v1_t *this, u_int32_t mid, chunk_t last_block); + + /** + * Confirms the updated IV for the given message ID. + * + * To actually make the new IV available via get_iv this method has to + * be called after update_iv. + * + * @param mid message ID + */ + void (*confirm_iv)(keymat_v1_t *this, u_int32_t mid); + }; /** From 477e856a15da725a674aa5783ff563c5123d230e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 13:19:19 +0100 Subject: [PATCH 078/534] Decrypt IKEv1 messages. --- src/libcharon/encoding/message.c | 46 +++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 79cc86ed4..a368d96cd 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -1566,6 +1567,23 @@ static status_t parse_payloads(private_message_t *this) payload_t *payload; status_t status; + if (this->is_encrypted) + { /* wrap the whole encrypted IKEv1 message in a special encryption + * payload which is then handled just like a regular payload */ + encryption_payload_t *encryption; + status = this->parser->parse_payload(this->parser, ENCRYPTED_V1, + (payload_t**)&encryption); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "failed to wrap encrypted IKEv1 message"); + return PARSE_ERROR; + } + encryption->payload_interface.set_next_type((payload_t*)encryption, + this->first_payload); + this->payloads->insert_last(this->payloads, encryption); + return SUCCESS; + } + while (type != NO_PAYLOAD) { DBG2(DBG_ENC, "starting parsing a %N payload", @@ -1626,11 +1644,12 @@ static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) DBG2(DBG_ENC, "process payload of type %N", payload_type_names, type); - if (type == ENCRYPTED) + if (type == ENCRYPTED || type == ENCRYPTED_V1) { encryption_payload_t *encryption; payload_t *encrypted; chunk_t chunk; + size_t bs; encryption = (encryption_payload_t*)payload; @@ -1643,15 +1662,29 @@ static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) break; } aead = keymat->get_aead(keymat, TRUE); + bs = aead->get_block_size(aead); encryption->set_transform(encryption, aead); chunk = this->packet->get_data(this->packet); - if (chunk.len < encryption->get_length(encryption)) + if (chunk.len < encryption->get_length(encryption) || + chunk.len < bs) { DBG1(DBG_ENC, "invalid payload length"); status = VERIFY_ERROR; break; } - chunk.len -= encryption->get_length(encryption); + if (type == ENCRYPTED_V1) + { /* instead of associated data we provide the IV, we also update + * the IV with the last encrypted block */ + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; + chunk_t last_block = chunk_create(chunk.ptr + chunk.len - bs, + bs); + chunk = keymat_v1->get_iv(keymat_v1, this->message_id); + keymat_v1->update_iv(keymat_v1, this->message_id, last_block); + } + else + { + chunk.len -= encryption->get_length(encryption); + } status = encryption->decrypt(encryption, chunk); if (status != SUCCESS) { @@ -1792,6 +1825,13 @@ METHOD(message_t, parse_body, status_t, DBG1(DBG_ENC, "parsed %s", get_string(this, str, sizeof(str))); + if (this->is_encrypted) + { /* TODO-IKEv1: this should be done later when we know this is no + * retransmit */ + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; + keymat_v1->confirm_iv(keymat_v1, this->message_id); + } + return SUCCESS; } From c92f2cf36deca2d3917020fc8c41abb8ada316ca Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 13:24:17 +0100 Subject: [PATCH 079/534] Encrypt IKEv1 messages. --- src/libcharon/encoding/message.c | 85 +++++++++++++++++++++++++------- 1 file changed, 67 insertions(+), 18 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index a368d96cd..d088a7bf7 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1279,9 +1279,10 @@ static void order_payloads(private_message_t *this) } /** - * Wrap payloads in a encryption payload + * Wrap payloads in an encryption payload */ -static encryption_payload_t* wrap_payloads(private_message_t *this) +static encryption_payload_t* wrap_payloads(private_message_t *this, + payload_type_t encryption_type) { encryption_payload_t *encryption; linked_list_t *payloads; @@ -1295,7 +1296,7 @@ static encryption_payload_t* wrap_payloads(private_message_t *this) payloads->insert_last(payloads, current); } - encryption = encryption_payload_create(); + encryption = encryption_payload_create(encryption_type); while (payloads->remove_first(payloads, (void**)¤t) == SUCCESS) { payload_rule_t *rule; @@ -1308,8 +1309,8 @@ static encryption_payload_t* wrap_payloads(private_message_t *this) { encrypt = rule->encrypted; } - if (encrypt) - { + if (encrypt || this->is_encrypted) + { /* encryption is forced for IKEv1 */ DBG2(DBG_ENC, "insert payload %N to encryption payload", payload_type_names, type); encryption->add_payload(encryption, current); @@ -1335,16 +1336,18 @@ METHOD(message_t, disable_sort, void, METHOD(message_t, generate, status_t, private_message_t *this, keymat_t *keymat, packet_t **packet) { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; generator_t *generator; ike_header_t *ike_header; payload_t *payload, *next; encryption_payload_t *encryption = NULL; + payload_type_t next_type; enumerator_t *enumerator; aead_t *aead; chunk_t chunk; char str[BUF_LEN]; u_int32_t *lenpos; - bool *reserved; + bool encrypted = FALSE, *reserved; int i; if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED) @@ -1374,10 +1377,33 @@ METHOD(message_t, generate, status_t, DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); - aead = keymat->get_aead(keymat, FALSE); - if (aead && this->rule->encrypted) + if (this->major_version == IKEV2_MAJOR_VERSION) { - encryption = wrap_payloads(this); + encrypted = this->rule->encrypted; + } + else + { /* if at least one payload requires encryption, encrypt the message */ + /* TODO-IKEV1: set is_encrypted externally instead of this check? */ + enumerator = this->payloads->create_enumerator(this->payloads); + while (enumerator->enumerate(enumerator, (void**)&payload)) + { + payload_rule_t *rule; + rule = get_payload_rule(this, payload->get_type(payload)); + if (rule && rule->encrypted) + { + this->is_encrypted = TRUE; + encrypted = TRUE; + break; + } + } + enumerator->destroy(enumerator); + } + + aead = keymat->get_aead(keymat, FALSE); + if (aead && encrypted) + { + encryption = wrap_payloads(this, this->is_encrypted ? ENCRYPTED_V1 + : ENCRYPTED); } else { @@ -1395,6 +1421,10 @@ METHOD(message_t, generate, status_t, ike_header->set_initiator_flag(ike_header, this->ike_sa_id->is_initiator(this->ike_sa_id)); } + else + { + ike_header->set_encryption_flag(ike_header, this->is_encrypted); + } ike_header->set_initiator_spi(ike_header, this->ike_sa_id->get_initiator_spi(this->ike_sa_id)); ike_header->set_responder_spi(ike_header, @@ -1422,20 +1452,32 @@ METHOD(message_t, generate, status_t, payload = next; } enumerator->destroy(enumerator); - payload->set_next_type(payload, encryption ? ENCRYPTED : NO_PAYLOAD); + if (this->is_encrypted) + { /* for encrypted IKEv1 messages */ + next_type = encryption->payload_interface.get_next_type( + (payload_t*)encryption); + } + else + { + next_type = encryption ? ENCRYPTED : NO_PAYLOAD; + } + payload->set_next_type(payload, next_type); generator->generate_payload(generator, payload); ike_header->destroy(ike_header); if (encryption) { - u_int32_t *lenpos; - - /* build associated data (without header of encryption payload) */ - chunk = generator->get_chunk(generator, &lenpos); + if (this->is_encrypted) + { /* for IKEv1 instead of associated data we provide the IV */ + chunk = keymat_v1->get_iv(keymat_v1, this->message_id); + } + else + { /* build associated data (without header of encryption payload) */ + chunk = generator->get_chunk(generator, &lenpos); + /* fill in length, including encryption payload */ + htoun32(lenpos, chunk.len + encryption->get_length(encryption)); + } encryption->set_transform(encryption, aead); - /* fill in length, including encryption payload */ - htoun32(lenpos, chunk.len + encryption->get_length(encryption)); - this->payloads->insert_last(this->payloads, encryption); if (!encryption->encrypt(encryption, chunk)) { @@ -1447,8 +1489,15 @@ METHOD(message_t, generate, status_t, chunk = generator->get_chunk(generator, &lenpos); htoun32(lenpos, chunk.len); this->packet->set_data(this->packet, chunk_clone(chunk)); + if (this->is_encrypted) + { /* update the IV for the next IKEv1 message */ + chunk_t last_block; + size_t bs = aead->get_block_size(aead); + last_block = chunk_create(chunk.ptr + chunk.len - bs, bs); + keymat_v1->update_iv(keymat_v1, this->message_id, last_block); + keymat_v1->confirm_iv(keymat_v1, this->message_id); + } generator->destroy(generator); - *packet = this->packet->clone(this->packet); return SUCCESS; } From d66199884f92ff157e8702a5cf6f83c7fdc6fdd7 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 13:26:27 +0100 Subject: [PATCH 080/534] Set flags on message according to IKE version when parsing header. --- src/libcharon/encoding/message.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index d088a7bf7..e7a48344b 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1559,10 +1559,16 @@ METHOD(message_t, parse_header, status_t, this->exchange_type = ike_header->get_exchange_type(ike_header); this->message_id = ike_header->get_message_id(ike_header); - this->is_request = !ike_header->get_response_flag(ike_header); - this->is_encrypted = ike_header->get_encryption_flag(ike_header); this->major_version = ike_header->get_maj_version(ike_header); this->minor_version = ike_header->get_min_version(ike_header); + if (this->major_version == IKEV2_MAJOR_VERSION) + { + this->is_request = !ike_header->get_response_flag(ike_header); + } + else + { + this->is_encrypted = ike_header->get_encryption_flag(ike_header); + } this->first_payload = ike_header->payload_interface.get_next_type( &ike_header->payload_interface); for (i = 0; i < countof(this->reserved); i++) From 780ce7724d0655062e95094ce970473c28a2023a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 15:16:51 +0100 Subject: [PATCH 081/534] Strings for ENCRYPTED_V1 payload added. --- src/libcharon/encoding/payloads/payload.c | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 2f22503e6..69fd47b4a 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -73,7 +73,7 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, V #ifdef ME ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, "ID_PEER"); -ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, +ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, ID_PEER, "HEADER", "PROPOSAL_SUBSTRUCTURE", "PROPOSAL_SUBSTRUCTURE_V1", @@ -82,9 +82,10 @@ ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, "TRANSFORM_ATTRIBUTE", "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", - "CONFIGURATION_ATTRIBUTE"); + "CONFIGURATION_ATTRIBUTE", + "ENCRYPTED_V1"); #else -ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, EXTENSIBLE_AUTHENTICATION, +ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, EXTENSIBLE_AUTHENTICATION, "HEADER", "PROPOSAL_SUBSTRUCTURE", "PROPOSAL_SUBSTRUCTURE_V1", @@ -93,9 +94,10 @@ ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, EXTENSIBLE_AUTHEN "TRANSFORM_ATTRIBUTE", "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", - "CONFIGURATION_ATTRIBUTE"); + "CONFIGURATION_ATTRIBUTE", + "ENCRYPTED_V1"); #endif /* ME */ -ENUM_END(payload_type_names, CONFIGURATION_ATTRIBUTE); +ENUM_END(payload_type_names, ENCRYPTED_V1); /* short forms of payload names */ ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD, @@ -134,7 +136,7 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICAT #ifdef ME ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, "IDp"); -ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, +ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, ID_PEER, "HDR", "PROP", "PROP", @@ -143,9 +145,10 @@ ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, "TRANSATTR", "TRANSATTR", "TSSUB", - "CATTR"); + "CATTR", + "E"); #else -ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, EXTENSIBLE_AUTHENTICATION, +ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, EXTENSIBLE_AUTHENTICATION, "HDR", "PROP", "PROP", @@ -154,9 +157,10 @@ ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, EXTENSIBLE_ "TRANSATTR", "TRANSATTR", "TSSUB", - "CATTR"); + "CATTR", + "E"); #endif /* ME */ -ENUM_END(payload_type_short_names, CONFIGURATION_ATTRIBUTE); +ENUM_END(payload_type_short_names, ENCRYPTED_V1); /* * see header From 42a69b05abec61f145fc06f7cec68ef4deba76b0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 21 Nov 2011 15:18:40 +0100 Subject: [PATCH 082/534] String for ENCRYPTED_DATA fixed. --- src/libcharon/encoding/payloads/encodings.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index 7306dcf10..7515c947f 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -38,5 +38,5 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "ADDRESS", "CHUNK_DATA", "IKE_SPI", - "ENCRYPTED", + "ENCRYPTED_DATA", ); From 7fcd26f4fcdcb9e519fb7deacf869237e1df3012 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 13:43:48 +0100 Subject: [PATCH 083/534] Fix payload length of id_payload created from a traffic selector --- src/libcharon/encoding/payloads/id_payload.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index dec08de00..317cbd624 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -406,6 +406,7 @@ id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts) } this->port = ts->get_from_port(ts); this->protocol_id = ts->get_protocol(ts); + this->payload_length += this->id_data.len; net->destroy(net); From 059d694a6b26273e3d33a080580b00b6d3c4284f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 14:36:05 +0100 Subject: [PATCH 084/534] Derive IKE keys as IKEv1 initiator, too --- src/libcharon/sa/tasks/main_mode.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 89ecaf408..8b2b4c0d9 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -560,6 +560,12 @@ METHOD(task_t, process_i, status_t, } this->nonce_r = nonce_payload->get_nonce(nonce_payload); + if (!derive_keys(this, this->nonce_i, this->nonce_r)) + { + DBG1(DBG_IKE, "key derivation failed"); + return FAILED; + } + return NEED_MORE; } case MM_AUTH: From e1f9d6476e50e7d486a26a9f6d8f6a16e70304e0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 16:41:16 +0100 Subject: [PATCH 085/534] Register HASH_V1 in payload factory --- src/libcharon/encoding/payloads/payload.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 69fd47b4a..83fd1cb1c 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -34,6 +34,7 @@ #include #include #include +#include #include @@ -217,6 +218,8 @@ payload_t *payload_create(payload_type_t type) case VENDOR_ID: case VENDOR_ID_V1: return (payload_t*)vendor_id_payload_create(type); + case HASH_V1: + return (payload_t*)hash_payload_create(); case CONFIGURATION: return (payload_t*)cp_payload_create(); case CONFIGURATION_ATTRIBUTE: From 4eee34ac4902c8c45877237a974cf667ecb61c7f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 16:41:48 +0100 Subject: [PATCH 086/534] Added keymat_v1_t.get_hash() to calculate authentication hashes --- src/libcharon/sa/keymat_v1.c | 38 ++++++++++++++++++++++++++++++++++++ src/libcharon/sa/keymat_v1.h | 15 ++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 891f6a21e..c8846fa46 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -466,6 +466,43 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, return TRUE; } +METHOD(keymat_v1_t, get_hash, chunk_t, + private_keymat_v1_t *this, bool initiator, chunk_t dh, chunk_t dh_other, + ike_sa_id_t *ike_sa_id, chunk_t sa_i, identification_t *id) +{ + chunk_t hash, data; + u_int64_t spi, spi_other; + /* TODO-IKEv1: get real bytes from ID header? */ + u_int8_t id_header[4] = { id->get_type(id), 0, 0, 0 }; + + /* HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b ) + * HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b ) + */ + if (initiator) + { + spi = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_other = ike_sa_id->get_responder_spi(ike_sa_id); + } + else + { + spi_other = ike_sa_id->get_initiator_spi(ike_sa_id); + spi = ike_sa_id->get_responder_spi(ike_sa_id); + } + data = chunk_cat("ccccccc", dh, dh_other, + chunk_from_thing(spi), chunk_from_thing(spi_other), + sa_i, chunk_from_thing(id_header), id->get_encoding(id)); + + DBG3(DBG_IKE, "HASH_%c data %B", initiator ? 'I' : 'R', &data); + + this->prf->set_key(this->prf, this->skeyid); + this->prf->allocate_bytes(this->prf, data, &hash); + + DBG3(DBG_IKE, "HASH_%c %B", initiator ? 'I' : 'R', &hash); + + free(data.ptr); + return hash; +} + /** * Generate an IV */ @@ -602,6 +639,7 @@ keymat_v1_t *keymat_v1_create(bool initiator) .destroy = _destroy, }, .derive_ike_keys = _derive_ike_keys, + .get_hash = _get_hash, .get_iv = _get_iv, .update_iv = _update_iv, .confirm_iv = _confirm_iv, diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h index 54d4d4392..142c835bb 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/keymat_v1.h @@ -56,6 +56,21 @@ struct keymat_v1_t { chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, auth_class_t auth, shared_key_t *shared_key); + /** + * Get HASH data for authentication. + * + * @param initiatior TRUE to create HASH_I, FALSE for HASH_R + * @param dh public DH value of peer to create HASH for + * @param dh_other others public DH value + * @param ike_sa_id IKE_SA identifier + * @param sa_i encoded SA payload of initiator + * @param id ID of peer to create hash for + * @return allocated HASH data + */ + chunk_t (*get_hash)(keymat_v1_t *this, bool initiator, + chunk_t dh, chunk_t dh_other, ike_sa_id_t *ike_sa_id, + chunk_t sa_i, identification_t *id); + /** * Returns the IV for a message with the given message ID. * From 1b99befac3103fe3b9f66a63883a1ca9d2dfc840 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 17:16:39 +0100 Subject: [PATCH 087/534] Create and verify PSK HASH payloads in IKEv1 main mode --- src/libcharon/sa/tasks/main_mode.c | 126 ++++++++++++++++++++++++++--- 1 file changed, 117 insertions(+), 9 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 8b2b4c0d9..1af76763f 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -27,6 +27,7 @@ #include #include #include +#include typedef struct private_main_mode_t private_main_mode_t; @@ -100,6 +101,11 @@ struct private_main_mode_t { */ chunk_t nonce_r; + /** + * Encoded SA initiator payload used for authentication + */ + chunk_t sa_payload; + /** states of main mode */ enum { MM_INIT, @@ -124,6 +130,30 @@ static auth_cfg_t *get_auth_cfg(private_main_mode_t *this, bool local) return cfg; } +/** + * Save the encoded SA payload of a message + */ +static bool save_sa_payload(private_main_mode_t *this, message_t *message, + sa_payload_t *sa_payload) +{ + payload_t *payload; + chunk_t data; + + /* TODO-IKEv1: handle other payloads in front of SA? */ + payload = &sa_payload->payload_interface; + data = message->get_packet_data(message); + if (data.len >= IKE_HEADER_LENGTH + payload->get_length(payload)) + { + /* Get SA payload without 4 byte fixed header */ + data = chunk_skip(data, IKE_HEADER_LENGTH); + data.len = payload->get_length(payload); + data = chunk_skip(data, 4); + this->sa_payload = chunk_clone(data); + return TRUE; + } + return FALSE; +} + METHOD(task_t, build_i, status_t, private_main_mode_t *this, message_t *message) { @@ -133,6 +163,7 @@ METHOD(task_t, build_i, status_t, { sa_payload_t *sa_payload; linked_list_t *proposals; + packet_t *packet; this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H", @@ -149,6 +180,20 @@ METHOD(task_t, build_i, status_t, message->add_payload(message, &sa_payload->payload_interface); + /* pregenerate message to store SA payload */ + if (this->ike_sa->generate_message(this->ike_sa, message, + &packet) != SUCCESS) + { + DBG1(DBG_IKE, "pregenerating SA payload failed"); + return FAILED; + } + packet->destroy(packet); + if (!save_sa_payload(this, message, sa_payload)) + { + DBG1(DBG_IKE, "SA payload invalid"); + return FAILED; + } + this->state = MM_SA; return NEED_MORE; } @@ -195,7 +240,9 @@ METHOD(task_t, build_i, status_t, case MM_KE: { id_payload_t *id_payload; + hash_payload_t *hash_payload; identification_t *id; + chunk_t hash, dh; this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); this->peer_cfg->get_ref(this->peer_cfg); @@ -219,7 +266,15 @@ METHOD(task_t, build_i, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - /* TODO-IKEv1: authenticate */ + this->dh->get_my_public_value(this->dh, &dh); + hash = this->keymat->get_hash(this->keymat, TRUE, + dh, this->dh_value, this->ike_sa->get_id(this->ike_sa), + this->sa_payload, id); + free(dh.ptr); + hash_payload = hash_payload_create(); + hash_payload->set_hash(hash_payload, hash); + free(hash.ptr); + message->add_payload(message, &hash_payload->payload_interface); this->state = MM_AUTH; return NEED_MORE; @@ -236,7 +291,6 @@ METHOD(task_t, process_r, status_t, { case MM_INIT: { - linked_list_t *list; sa_payload_t *sa_payload; @@ -251,11 +305,12 @@ METHOD(task_t, process_r, status_t, sa_payload = (sa_payload_t*)message->get_payload(message, SECURITY_ASSOCIATION_V1); - if (!sa_payload) + if (!sa_payload || !save_sa_payload(this, message, sa_payload)) { - DBG1(DBG_IKE, "SA payload missing"); + DBG1(DBG_IKE, "SA payload missing or invalid"); return FAILED; } + list = sa_payload->get_proposals(sa_payload); this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, list, FALSE); @@ -298,7 +353,6 @@ METHOD(task_t, process_r, status_t, } this->dh->set_other_public_value(this->dh, this->dh_value); - nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1); if (!nonce_payload) @@ -315,7 +369,9 @@ METHOD(task_t, process_r, status_t, { enumerator_t *enumerator; id_payload_t *id_payload; + hash_payload_t *hash_payload; identification_t *id, *any; + chunk_t hash, dh; id_payload = (id_payload_t*)message->get_payload(message, ID_V1); if (!id_payload) @@ -351,11 +407,30 @@ METHOD(task_t, process_r, status_t, this->other_auth = get_auth_cfg(this, FALSE); if (!this->my_auth || !this->other_auth) { - DBG1(DBG_CFG, "auth config missing"); + DBG1(DBG_IKE, "auth config missing"); return FAILED; } - /* TODO-IKEv1: authenticate peer */ + hash_payload = (hash_payload_t*)message->get_payload(message, + HASH_V1); + if (!hash_payload) + { + DBG1(DBG_IKE, "hash payload missing"); + return FAILED; + } + hash = hash_payload->get_hash(hash_payload); + this->dh->get_my_public_value(this->dh, &dh); + hash = this->keymat->get_hash(this->keymat, TRUE, + this->dh_value, dh, this->ike_sa->get_id(this->ike_sa), + this->sa_payload, id); + free(dh.ptr); + if (!chunk_equals(hash, hash_payload->get_hash(hash_payload))) + { + DBG1(DBG_IKE, "calculated hash does not match to hash payload"); + free(hash.ptr); + return FAILED; + } + free(hash.ptr); this->state = MM_AUTH; return NEED_MORE; @@ -439,6 +514,7 @@ METHOD(task_t, build_r, status_t, sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1, this->proposal); message->add_payload(message, &sa_payload->payload_interface); + return NEED_MORE; } case MM_KE: @@ -474,7 +550,9 @@ METHOD(task_t, build_r, status_t, case MM_AUTH: { id_payload_t *id_payload; + hash_payload_t *hash_payload; identification_t *id; + chunk_t hash, dh; id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY); if (!id) @@ -488,7 +566,15 @@ METHOD(task_t, build_r, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - /* TODO-IKEv1: authenticate us */ + this->dh->get_my_public_value(this->dh, &dh); + hash = this->keymat->get_hash(this->keymat, FALSE, + dh, this->dh_value, this->ike_sa->get_id(this->ike_sa), + this->sa_payload, id); + free(dh.ptr); + hash_payload = hash_payload_create(); + hash_payload->set_hash(hash_payload, hash); + free(hash.ptr); + message->add_payload(message, &hash_payload->payload_interface); /* TODO-IKEv1: check for XAUTH rounds, queue them */ DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", @@ -571,7 +657,9 @@ METHOD(task_t, process_i, status_t, case MM_AUTH: { id_payload_t *id_payload; + hash_payload_t *hash_payload; identification_t *id; + chunk_t hash, dh; id_payload = (id_payload_t*)message->get_payload(message, ID_V1); if (!id_payload) @@ -589,7 +677,26 @@ METHOD(task_t, process_i, status_t, } this->ike_sa->set_other_id(this->ike_sa, id); - /* TODO-IKEv1: verify auth */ + hash_payload = (hash_payload_t*)message->get_payload(message, + HASH_V1); + if (!hash_payload) + { + DBG1(DBG_IKE, "hash payload missing"); + return FAILED; + } + hash = hash_payload->get_hash(hash_payload); + this->dh->get_my_public_value(this->dh, &dh); + hash = this->keymat->get_hash(this->keymat, FALSE, + this->dh_value, dh, this->ike_sa->get_id(this->ike_sa), + this->sa_payload, id); + free(dh.ptr); + if (!chunk_equals(hash, hash_payload->get_hash(hash_payload))) + { + DBG1(DBG_IKE, "calculated hash does not match to hash payload"); + free(hash.ptr); + return FAILED; + } + free(hash.ptr); /* TODO-IKEv1: check for XAUTH rounds, queue them */ DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", @@ -629,6 +736,7 @@ METHOD(task_t, destroy, void, free(this->dh_value.ptr); free(this->nonce_i.ptr); free(this->nonce_r.ptr); + free(this->sa_payload.ptr); free(this); } From 17ec1c74de4c1ceb642e47d4767bd5b323908cfe Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 17:18:43 +0100 Subject: [PATCH 088/534] Don't compare initiator flag in IKE_SA manager, pass initiator parameter to IKE_SA constructor --- src/libcharon/plugins/ha/ha_dispatcher.c | 3 ++- src/libcharon/sa/ike_sa.c | 5 +++-- src/libcharon/sa/ike_sa.h | 4 +++- src/libcharon/sa/ike_sa_id.c | 14 ++------------ src/libcharon/sa/ike_sa_manager.c | 7 +++---- 5 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index f430fee94..71c458a89 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -89,7 +89,8 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message switch (attribute) { case HA_IKE_ID: - ike_sa = ike_sa_create(value.ike_sa_id, IKEV2); + ike_sa = ike_sa_create(value.ike_sa_id, + value.ike_sa_id->is_initiator(value.ike_sa_id), IKEV2); break; case HA_IKE_REKEY_ID: old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index b9b2bb82e..d2dffea8b 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -2131,7 +2131,8 @@ METHOD(ike_sa_t, destroy, void, /* * Described in header. */ -ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, ike_version_t version) +ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, + ike_version_t version) { private_ike_sa_t *this; static u_int32_t unique_id = 0; @@ -2224,7 +2225,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, ike_version_t version) .other_host = host_create_any(AF_INET), .my_id = identification_create_from_encoding(ID_ANY, chunk_empty), .other_id = identification_create_from_encoding(ID_ANY, chunk_empty), - .keymat = keymat_create(version, ike_sa_id->is_initiator(ike_sa_id)), + .keymat = keymat_create(version, initiator), .state = IKE_CREATED, .stats[STAT_INBOUND] = time_monotonic(NULL), .stats[STAT_OUTBOUND] = time_monotonic(NULL), diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 21f7c7452..2708b0be6 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -959,9 +959,11 @@ struct ike_sa_t { * Creates an ike_sa_t object with a specific ID and IKE version. * * @param ike_sa_id ike_sa_id_t to associate with new IKE_SA/ISAKMP_SA + * @param initiator TRUE to create this IKE_SA as initiator * @param version IKE version of this SA * @return ike_sa_t object */ -ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id, ike_version_t version); +ike_sa_t *ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, + ike_version_t version); #endif /** IKE_SA_H_ @}*/ diff --git a/src/libcharon/sa/ike_sa_id.c b/src/libcharon/sa/ike_sa_id.c index bea4c2124..fb73bdd81 100644 --- a/src/libcharon/sa/ike_sa_id.c +++ b/src/libcharon/sa/ike_sa_id.c @@ -77,18 +77,8 @@ METHOD(ike_sa_id_t, equals, bool, { return FALSE; } - if ((this->is_initiator_flag == other->is_initiator_flag) && - (this->initiator_spi == other->initiator_spi) && - (this->responder_spi == other->responder_spi)) - { - /* private_ike_sa_id's are equal */ - return TRUE; - } - else - { - /* private_ike_sa_id's are not equal */ - return FALSE; - } + return this->initiator_spi == other->initiator_spi && + this->responder_spi == other->responder_spi; } METHOD(ike_sa_id_t, replace_values, void, diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 556459064..ffbc2ec3b 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -163,7 +163,6 @@ static entry_t *entry_create() static bool entry_match_by_hash(entry_t *entry, ike_sa_id_t *id, chunk_t *hash) { return id->get_responder_spi(id) == 0 && - id->is_initiator(id) == entry->ike_sa_id->is_initiator(entry->ike_sa_id) && id->get_initiator_spi(id) == entry->ike_sa_id->get_initiator_spi(entry->ike_sa_id) && chunk_equals(*hash, entry->init_hash); } @@ -179,7 +178,6 @@ static bool entry_match_by_id(entry_t *entry, ike_sa_id_t *id) } if ((id->get_responder_spi(id) == 0 || entry->ike_sa_id->get_responder_spi(entry->ike_sa_id) == 0) && - id->is_initiator(id) == entry->ike_sa_id->is_initiator(entry->ike_sa_id) && id->get_initiator_spi(id) == entry->ike_sa_id->get_initiator_spi(entry->ike_sa_id)) { /* this is TRUE for IKE_SAs that we initiated but have not yet received a response */ @@ -954,7 +952,7 @@ METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, { ike_sa_id = ike_sa_id_create(0, get_spi(this), FALSE); } - ike_sa = ike_sa_create(ike_sa_id, version); + ike_sa = ike_sa_create(ike_sa_id, initiator, version); ike_sa_id->destroy(ike_sa_id); DBG2(DBG_MGR, "created IKE_SA %s[%u]", ike_sa->get_name(ike_sa), @@ -1036,7 +1034,8 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, /* no IKE_SA found, create a new one */ id->set_responder_spi(id, get_spi(this)); entry = entry_create(); - entry->ike_sa = ike_sa_create(id, ike_version); + /* a new SA checked out by message is a responder SA */ + entry->ike_sa = ike_sa_create(id, FALSE, ike_version); entry->ike_sa_id = id->clone(id); segment = put_entry(this, entry); From 12b6a68a5f78900fb1b14b97f826f55a7dee2817 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 17:32:19 +0100 Subject: [PATCH 089/534] Add missing keymat cast to avoid compiler warning --- src/libcharon/sa/tasks/child_create.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index b0d50efa6..79ca6cf5a 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -1240,7 +1240,7 @@ METHOD(task_t, migrate, void, } this->ike_sa = ike_sa; - this->keymat = ike_sa->get_keymat(ike_sa); + this->keymat = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); this->proposal = NULL; this->proposals = NULL; this->tsi = NULL; From cc9629d87cb913d0587634b55b05dcf7129875b2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 17:40:42 +0100 Subject: [PATCH 090/534] Partially implemented IKEv1 ESP proposal en-/decoding --- .../encoding/payloads/proposal_substructure.c | 75 ++++++++++++++++++- 1 file changed, 73 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index aa3f0674f..8ef993138 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -616,7 +616,38 @@ static void add_to_proposal_v1_ike(proposal_t *proposal, static void add_to_proposal_v1_esp(proposal_t *proposal, transform_substructure_t *transform) { - /* TODO-IKEv1: create ESP proposals */ + transform_attribute_type_t type; + transform_attribute_t *tattr; + enumerator_t *enumerator; + u_int16_t value, key_length = 0; + + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &tattr)) + { + type = tattr->get_attribute_type(tattr); + value = tattr->get_value(tattr); + switch (type) + { + case TATTR_PH2_KEY_LENGTH: + key_length = value; + break; + case TATTR_PH2_AUTH_ALGORITHM: + proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, + get_alg_from_ikev1(INTEGRITY_ALGORITHM, value), 0); + break; + default: + /* TODO-IKEv1: lifetimes other attributes */ + break; + } + } + enumerator->destroy(enumerator); + + /* TODO-IKEv1: handle ESN attribute */ + proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, + NO_EXT_SEQ_NUMBERS, 0); + + proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, + transform->get_transform_id(transform), key_length); } METHOD(proposal_substructure_t, get_proposal, proposal_t*, @@ -794,7 +825,47 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, proposal_t *proposal) { - /* TODO-IKEv1: add ESP proposal to transform substr */ + transform_substructure_t *transform = NULL; + u_int16_t alg, key_size; + enumerator_t *enumerator; + + enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, + 0, alg); + if (key_size) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_KEY_LENGTH, key_size)); + } + } + enumerator->destroy(enumerator); + if (!transform) + { + return; + } + + enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); + while (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg); + if (alg) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_AUTH_ALGORITHM, alg)); + } + } + enumerator->destroy(enumerator); + + /* TODO-IKEv1: Add lifetime and other attributes, non-fixes ESN */ + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_EXT_SEQ_NUMBER, NO_EXT_SEQ_NUMBERS)); + + add_transform_substructure(this, transform); } /** From 21b7db99c6c725575a8652b37103813ed39dcc02 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 21 Nov 2011 17:56:39 +0100 Subject: [PATCH 091/534] Implemented quick mode protocol handling, no CHILD_SA or HASH payloads yet --- src/libcharon/sa/task_manager_v1.c | 3 +- src/libcharon/sa/tasks/quick_mode.c | 298 +++++++++++++++++++++++++++- 2 files changed, 294 insertions(+), 7 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 9be034fb2..1764a8036 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -454,7 +454,8 @@ static status_t process_request(private_task_manager_t *this, /* task completed, remove it */ this->passive_tasks->remove_at(this->passive_tasks, enumerator); task->destroy(task); - break; + enumerator->destroy(enumerator); + return SUCCESS; case NEED_MORE: /* processed, but task needs at least another call to build() */ break; diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 5db02b241..aa6e4e6f1 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -18,6 +18,9 @@ #include #include +#include +#include +#include typedef struct private_quick_mode_t private_quick_mode_t; @@ -74,31 +77,316 @@ struct private_quick_mode_t { /** states of quick mode */ enum { QM_INIT, + QM_NEGOTIATED, } state; }; METHOD(task_t, build_i, status_t, private_quick_mode_t *this, message_t *message) { - return NEED_MORE; + switch (this->state) + { + case QM_INIT: + { + sa_payload_t *sa_payload; + nonce_payload_t *nonce_payload; + id_payload_t *id_payload; + traffic_selector_t *ts; + linked_list_t *list; + rng_t *rng; + + list = this->config->get_proposals(this->config, TRUE); + sa_payload = sa_payload_create_from_proposal_list( + SECURITY_ASSOCIATION_V1, list); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + message->add_payload(message, &sa_payload->payload_interface); + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "no RNG found to create nonce"); + return FAILED; + } + rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_i); + rng->destroy(rng); + nonce_payload = nonce_payload_create(NONCE_V1); + nonce_payload->set_nonce(nonce_payload, this->nonce_i); + message->add_payload(message, &nonce_payload->payload_interface); + + list = this->config->get_traffic_selectors(this->config, TRUE, NULL, + this->ike_sa->get_my_host(this->ike_sa)); + if (list->get_first(list, (void**)&ts) != SUCCESS) + { + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + DBG1(DBG_IKE, "traffic selector missing"); + return FAILED; + } + id_payload = id_payload_create_from_ts(ts); + this->tsi = ts->clone(ts); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + message->add_payload(message, &id_payload->payload_interface); + + list = this->config->get_traffic_selectors(this->config, FALSE, NULL, + this->ike_sa->get_other_host(this->ike_sa)); + if (list->get_first(list, (void**)&ts) != SUCCESS) + { + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + DBG1(DBG_IKE, "traffic selector missing"); + return FAILED; + } + id_payload = id_payload_create_from_ts(ts); + this->tsr = ts->clone(ts); + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + message->add_payload(message, &id_payload->payload_interface); + + /* TODO-IKEv1: Add HASH(1) */ + + return NEED_MORE; + } + case QM_NEGOTIATED: + { + /* TODO-IKEv1: Send HASH(3) */ + return SUCCESS; + } + default: + return FAILED; + } } METHOD(task_t, process_r, status_t, private_quick_mode_t *this, message_t *message) { - return NEED_MORE; + switch (this->state) + { + case QM_INIT: + { + sa_payload_t *sa_payload; + nonce_payload_t *nonce_payload; + id_payload_t *id_payload; + payload_t *payload; + linked_list_t *tsi, *tsr, *list; + peer_cfg_t *peer_cfg; + host_t *me, *other; + enumerator_t *enumerator; + bool first = TRUE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == ID_V1) + { + id_payload = (id_payload_t*)payload; + + if (first) + { + this->tsi = id_payload->get_ts(id_payload); + first = FALSE; + } + else + { + this->tsr = id_payload->get_ts(id_payload); + break; + } + } + } + enumerator->destroy(enumerator); + + /* TODO-IKEv1: create host2host TS if ID payloads missing */ + + me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (!me) + { + me = this->ike_sa->get_my_host(this->ike_sa); + } + other = this->ike_sa->get_virtual_ip(this->ike_sa, FALSE); + if (!other) + { + other = this->ike_sa->get_other_host(this->ike_sa); + } + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + tsi = linked_list_create(); + tsr = linked_list_create(); + tsi->insert_last(tsi, this->tsi); + tsr->insert_last(tsr, this->tsr); + this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi, + me, other); + tsi->destroy(tsi); + tsr->destroy(tsr); + if (!this->config) + { + DBG1(DBG_IKE, "no child config found"); + return FAILED; + } + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "sa payload missing"); + return FAILED; + } + list = sa_payload->get_proposals(sa_payload); + this->proposal = this->config->select_proposal(this->config, + list, TRUE, FALSE); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no matching proposal found"); + return FAILED; + } + + nonce_payload = (nonce_payload_t*)message->get_payload(message, + NONCE_V1); + if (!nonce_payload) + { + DBG1(DBG_IKE, "Nonce payload missing"); + return FAILED; + } + this->nonce_i = nonce_payload->get_nonce(nonce_payload); + + /* TODO-IKEv1: verify HASH(1) */ + + return NEED_MORE; + } + case QM_NEGOTIATED: + { + /* TODO-IKEv1: verify HASH(3) */ + + return SUCCESS; + } + default: + return FAILED; + } } METHOD(task_t, build_r, status_t, private_quick_mode_t *this, message_t *message) { - return SUCCESS; + switch (this->state) + { + case QM_INIT: + { + sa_payload_t *sa_payload; + nonce_payload_t *nonce_payload; + id_payload_t *id_payload; + rng_t *rng; + + sa_payload = sa_payload_create_from_proposal( + SECURITY_ASSOCIATION_V1, this->proposal); + message->add_payload(message, &sa_payload->payload_interface); + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "no RNG found to create nonce"); + return FAILED; + } + rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_r); + rng->destroy(rng); + nonce_payload = nonce_payload_create(NONCE_V1); + nonce_payload->set_nonce(nonce_payload, this->nonce_r); + message->add_payload(message, &nonce_payload->payload_interface); + + id_payload = id_payload_create_from_ts(this->tsi); + message->add_payload(message, &id_payload->payload_interface); + id_payload = id_payload_create_from_ts(this->tsr); + message->add_payload(message, &id_payload->payload_interface); + + /* TODO-IKEv1: add HASH(2) */ + + this->state = QM_NEGOTIATED; + return NEED_MORE; + } + default: + return FAILED; + } } METHOD(task_t, process_i, status_t, private_quick_mode_t *this, message_t *message) { - return SUCCESS; + switch (this->state) + { + case QM_INIT: + { + sa_payload_t *sa_payload; + nonce_payload_t *nonce_payload; + id_payload_t *id_payload; + payload_t *payload; + traffic_selector_t *tsi = NULL, *tsr = NULL; + linked_list_t *list; + enumerator_t *enumerator; + bool first = TRUE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == ID_V1) + { + id_payload = (id_payload_t*)payload; + + if (first) + { + tsi = id_payload->get_ts(id_payload); + first = FALSE; + } + else + { + tsr = id_payload->get_ts(id_payload); + break; + } + } + } + enumerator->destroy(enumerator); + + /* TODO-IKEv1: create host2host TS if ID payloads missing */ + + if (!tsr->is_contained_in(tsr, this->tsr) || + !tsi->is_contained_in(tsi, this->tsi)) + { + tsi->destroy(tsi); + tsr->destroy(tsr); + DBG1(DBG_IKE, "TS mismatch"); + return FAILED; + } + this->tsi->destroy(this->tsi); + this->tsr->destroy(this->tsr); + this->tsi = tsi; + this->tsr = tsr; + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "sa payload missing"); + return FAILED; + } + list = sa_payload->get_proposals(sa_payload); + this->proposal = this->config->select_proposal(this->config, + list, TRUE, FALSE); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no matching proposal found"); + return FAILED; + } + nonce_payload = (nonce_payload_t*)message->get_payload(message, + NONCE_V1); + if (!nonce_payload) + { + DBG1(DBG_IKE, "Nonce payload missing"); + return FAILED; + } + this->nonce_r = nonce_payload->get_nonce(nonce_payload); + + /* TODO-IKEv1: verify HASH(2) */ + + this->state = QM_NEGOTIATED; + return NEED_MORE; + } + default: + return FAILED; + } } METHOD(task_t, get_type, task_type_t, @@ -143,8 +431,6 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, }, }, .ike_sa = ike_sa, - .tsi = tsi ? tsi->clone(tsi) : NULL, - .tsr = tsr ? tsr->clone(tsr) : NULL, .config = config, .state = QM_INIT, ); From 73380c86856368c61fe1e951617ab97f06ee1fcf Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 08:56:01 +0100 Subject: [PATCH 092/534] Skip any payloads in front of SA to extract initiators SA bytes --- src/libcharon/sa/tasks/main_mode.c | 34 +++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 1af76763f..a727170ae 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -133,20 +133,34 @@ static auth_cfg_t *get_auth_cfg(private_main_mode_t *this, bool local) /** * Save the encoded SA payload of a message */ -static bool save_sa_payload(private_main_mode_t *this, message_t *message, - sa_payload_t *sa_payload) +static bool save_sa_payload(private_main_mode_t *this, message_t *message) { - payload_t *payload; + enumerator_t *enumerator; + payload_t *payload, *sa = NULL; chunk_t data; + size_t offset = IKE_HEADER_LENGTH; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) + { + sa = payload; + break; + } + else + { + offset += payload->get_length(payload); + } + } + enumerator->destroy(enumerator); - /* TODO-IKEv1: handle other payloads in front of SA? */ - payload = &sa_payload->payload_interface; data = message->get_packet_data(message); - if (data.len >= IKE_HEADER_LENGTH + payload->get_length(payload)) + if (sa && data.len >= offset + sa->get_length(sa)) { /* Get SA payload without 4 byte fixed header */ - data = chunk_skip(data, IKE_HEADER_LENGTH); - data.len = payload->get_length(payload); + data = chunk_skip(data, offset); + data.len = sa->get_length(sa); data = chunk_skip(data, 4); this->sa_payload = chunk_clone(data); return TRUE; @@ -188,7 +202,7 @@ METHOD(task_t, build_i, status_t, return FAILED; } packet->destroy(packet); - if (!save_sa_payload(this, message, sa_payload)) + if (!save_sa_payload(this, message)) { DBG1(DBG_IKE, "SA payload invalid"); return FAILED; @@ -305,7 +319,7 @@ METHOD(task_t, process_r, status_t, sa_payload = (sa_payload_t*)message->get_payload(message, SECURITY_ASSOCIATION_V1); - if (!sa_payload || !save_sa_payload(this, message, sa_payload)) + if (!sa_payload || !save_sa_payload(this, message)) { DBG1(DBG_IKE, "SA payload missing or invalid"); return FAILED; From a0f851cfe016ad380814235c5718be20d6807ef1 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 09:14:57 +0100 Subject: [PATCH 093/534] Refactored main mode HASH payload processing --- src/libcharon/sa/tasks/main_mode.c | 116 ++++++++++++++--------------- 1 file changed, 56 insertions(+), 60 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index a727170ae..b26e3b8a6 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -168,6 +168,58 @@ static bool save_sa_payload(private_main_mode_t *this, message_t *message) return FALSE; } +/** + * Build main mode hash payloads + */ +static void build_hash(private_main_mode_t *this, bool initiator, + message_t *message, identification_t *id) +{ + hash_payload_t *hash_payload; + chunk_t hash, dh; + + this->dh->get_my_public_value(this->dh, &dh); + hash = this->keymat->get_hash(this->keymat, initiator, dh, this->dh_value, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); + free(dh.ptr); + + hash_payload = hash_payload_create(); + hash_payload->set_hash(hash_payload, hash); + free(hash.ptr); + + message->add_payload(message, &hash_payload->payload_interface); +} + +/** + * Verify main mode hash payload + */ +static bool verify_hash(private_main_mode_t *this, bool initiator, + message_t *message, identification_t *id) +{ + hash_payload_t *hash_payload; + chunk_t hash, dh; + bool equal; + + hash_payload = (hash_payload_t*)message->get_payload(message, + HASH_V1); + if (!hash_payload) + { + DBG1(DBG_IKE, "HASH payload missing in message"); + return FALSE; + } + hash = hash_payload->get_hash(hash_payload); + this->dh->get_my_public_value(this->dh, &dh); + hash = this->keymat->get_hash(this->keymat, initiator, this->dh_value, dh, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); + free(dh.ptr); + equal = chunk_equals(hash, hash_payload->get_hash(hash_payload)); + free(hash.ptr); + if (!equal) + { + DBG1(DBG_IKE, "calculated HASH does not match HASH payload"); + } + return equal; +} + METHOD(task_t, build_i, status_t, private_main_mode_t *this, message_t *message) { @@ -254,9 +306,7 @@ METHOD(task_t, build_i, status_t, case MM_KE: { id_payload_t *id_payload; - hash_payload_t *hash_payload; identification_t *id; - chunk_t hash, dh; this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); this->peer_cfg->get_ref(this->peer_cfg); @@ -280,15 +330,7 @@ METHOD(task_t, build_i, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - this->dh->get_my_public_value(this->dh, &dh); - hash = this->keymat->get_hash(this->keymat, TRUE, - dh, this->dh_value, this->ike_sa->get_id(this->ike_sa), - this->sa_payload, id); - free(dh.ptr); - hash_payload = hash_payload_create(); - hash_payload->set_hash(hash_payload, hash); - free(hash.ptr); - message->add_payload(message, &hash_payload->payload_interface); + build_hash(this, TRUE, message, id); this->state = MM_AUTH; return NEED_MORE; @@ -383,9 +425,7 @@ METHOD(task_t, process_r, status_t, { enumerator_t *enumerator; id_payload_t *id_payload; - hash_payload_t *hash_payload; identification_t *id, *any; - chunk_t hash, dh; id_payload = (id_payload_t*)message->get_payload(message, ID_V1); if (!id_payload) @@ -425,26 +465,10 @@ METHOD(task_t, process_r, status_t, return FAILED; } - hash_payload = (hash_payload_t*)message->get_payload(message, - HASH_V1); - if (!hash_payload) + if (!verify_hash(this, TRUE, message, id)) { - DBG1(DBG_IKE, "hash payload missing"); return FAILED; } - hash = hash_payload->get_hash(hash_payload); - this->dh->get_my_public_value(this->dh, &dh); - hash = this->keymat->get_hash(this->keymat, TRUE, - this->dh_value, dh, this->ike_sa->get_id(this->ike_sa), - this->sa_payload, id); - free(dh.ptr); - if (!chunk_equals(hash, hash_payload->get_hash(hash_payload))) - { - DBG1(DBG_IKE, "calculated hash does not match to hash payload"); - free(hash.ptr); - return FAILED; - } - free(hash.ptr); this->state = MM_AUTH; return NEED_MORE; @@ -564,9 +588,7 @@ METHOD(task_t, build_r, status_t, case MM_AUTH: { id_payload_t *id_payload; - hash_payload_t *hash_payload; identification_t *id; - chunk_t hash, dh; id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY); if (!id) @@ -580,15 +602,7 @@ METHOD(task_t, build_r, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - this->dh->get_my_public_value(this->dh, &dh); - hash = this->keymat->get_hash(this->keymat, FALSE, - dh, this->dh_value, this->ike_sa->get_id(this->ike_sa), - this->sa_payload, id); - free(dh.ptr); - hash_payload = hash_payload_create(); - hash_payload->set_hash(hash_payload, hash); - free(hash.ptr); - message->add_payload(message, &hash_payload->payload_interface); + build_hash(this, FALSE, message, id); /* TODO-IKEv1: check for XAUTH rounds, queue them */ DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", @@ -671,9 +685,7 @@ METHOD(task_t, process_i, status_t, case MM_AUTH: { id_payload_t *id_payload; - hash_payload_t *hash_payload; identification_t *id; - chunk_t hash, dh; id_payload = (id_payload_t*)message->get_payload(message, ID_V1); if (!id_payload) @@ -691,26 +703,10 @@ METHOD(task_t, process_i, status_t, } this->ike_sa->set_other_id(this->ike_sa, id); - hash_payload = (hash_payload_t*)message->get_payload(message, - HASH_V1); - if (!hash_payload) + if (!verify_hash(this, FALSE, message, id)) { - DBG1(DBG_IKE, "hash payload missing"); return FAILED; } - hash = hash_payload->get_hash(hash_payload); - this->dh->get_my_public_value(this->dh, &dh); - hash = this->keymat->get_hash(this->keymat, FALSE, - this->dh_value, dh, this->ike_sa->get_id(this->ike_sa), - this->sa_payload, id); - free(dh.ptr); - if (!chunk_equals(hash, hash_payload->get_hash(hash_payload))) - { - DBG1(DBG_IKE, "calculated hash does not match to hash payload"); - free(hash.ptr); - return FAILED; - } - free(hash.ptr); /* TODO-IKEv1: check for XAUTH rounds, queue them */ DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", From a0b52db079b78fdd14f326c174619eee12d2a57a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 09:32:30 +0100 Subject: [PATCH 094/534] Refactored main mode NONCE/KE payload processing --- src/libcharon/sa/tasks/main_mode.c | 139 +++++++++++++---------------- 1 file changed, 63 insertions(+), 76 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index b26e3b8a6..c02095ac2 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -220,6 +220,65 @@ static bool verify_hash(private_main_mode_t *this, bool initiator, return equal; } +/** + * Generate and add NONCE, KE payload + */ +static bool add_nonce_ke(private_main_mode_t *this, chunk_t *nonce, + message_t *message) +{ + nonce_payload_t *nonce_payload; + ke_payload_t *ke_payload; + rng_t *rng; + + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, + this->dh); + message->add_payload(message, &ke_payload->payload_interface); + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "no RNG found to create nonce"); + return FALSE; + } + rng->allocate_bytes(rng, NONCE_SIZE, nonce); + rng->destroy(rng); + + nonce_payload = nonce_payload_create(NONCE_V1); + nonce_payload->set_nonce(nonce_payload, *nonce); + message->add_payload(message, &nonce_payload->payload_interface); + + return TRUE; +} + +/** + * Extract nonce from NONCE payload, process KE payload + */ +static bool get_nonce_ke(private_main_mode_t *this, chunk_t *nonce, + message_t *message) +{ + nonce_payload_t *nonce_payload; + ke_payload_t *ke_payload; + + ke_payload = (ke_payload_t*)message->get_payload(message, KEY_EXCHANGE_V1); + if (!ke_payload) + { + DBG1(DBG_IKE, "KE payload missing in message"); + return FALSE; + } + this->dh_value = chunk_clone(ke_payload->get_key_exchange_data(ke_payload)); + this->dh->set_other_public_value(this->dh, this->dh_value); + + nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1); + if (!nonce_payload) + { + DBG1(DBG_IKE, "NONCE payload missing in message"); + return FALSE; + } + *nonce = nonce_payload->get_nonce(nonce_payload); + + return TRUE; +} + METHOD(task_t, build_i, status_t, private_main_mode_t *this, message_t *message) { @@ -265,10 +324,7 @@ METHOD(task_t, build_i, status_t, } case MM_SA: { - ke_payload_t *ke_payload; - nonce_payload_t *nonce_payload; u_int16_t group; - rng_t *rng; if (!this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) @@ -283,23 +339,10 @@ METHOD(task_t, build_i, status_t, DBG1(DBG_IKE, "negotiated DH group not supported"); return FAILED; } - ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, - this->dh); - message->add_payload(message, &ke_payload->payload_interface); - - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!add_nonce_ke(this, &this->nonce_i, message)) { - DBG1(DBG_IKE, "no RNG found to create nonce"); return FAILED; } - rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_i); - rng->destroy(rng); - - nonce_payload = nonce_payload_create(NONCE_V1); - nonce_payload->set_nonce(nonce_payload, this->nonce_i); - message->add_payload(message, &nonce_payload->payload_interface); - this->state = MM_KE; return NEED_MORE; } @@ -381,20 +424,8 @@ METHOD(task_t, process_r, status_t, } case MM_SA: { - ke_payload_t *ke_payload; - nonce_payload_t *nonce_payload; u_int16_t group; - ke_payload = (ke_payload_t*)message->get_payload(message, - KEY_EXCHANGE_V1); - if (!ke_payload) - { - DBG1(DBG_IKE, "KE payload missing"); - return FAILED; - } - this->dh_value = ke_payload->get_key_exchange_data(ke_payload); - this->dh_value = chunk_clone(this->dh_value); - if (!this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) { @@ -407,17 +438,10 @@ METHOD(task_t, process_r, status_t, DBG1(DBG_IKE, "negotiated DH group not supported"); return FAILED; } - this->dh->set_other_public_value(this->dh, this->dh_value); - - nonce_payload = (nonce_payload_t*)message->get_payload(message, - NONCE_V1); - if (!nonce_payload) + if (!get_nonce_ke(this, &this->nonce_i, message)) { - DBG1(DBG_IKE, "Nonce payload missing"); return FAILED; } - this->nonce_i = nonce_payload->get_nonce(nonce_payload); - this->state = MM_KE; return NEED_MORE; } @@ -557,32 +581,15 @@ METHOD(task_t, build_r, status_t, } case MM_KE: { - ke_payload_t *ke_payload; - nonce_payload_t *nonce_payload; - rng_t *rng; - - ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, - this->dh); - message->add_payload(message, &ke_payload->payload_interface); - - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!add_nonce_ke(this, &this->nonce_r, message)) { - DBG1(DBG_IKE, "no RNG found to create nonce"); return FAILED; } - rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_r); - rng->destroy(rng); - if (!derive_keys(this, this->nonce_i, this->nonce_r)) { DBG1(DBG_IKE, "key derivation failed"); return FAILED; } - - nonce_payload = nonce_payload_create(NONCE_V1); - nonce_payload->set_nonce(nonce_payload, this->nonce_r); - message->add_payload(message, &nonce_payload->payload_interface); return NEED_MORE; } case MM_AUTH: @@ -651,35 +658,15 @@ METHOD(task_t, process_i, status_t, } case MM_KE: { - ke_payload_t *ke_payload; - nonce_payload_t *nonce_payload; - - ke_payload = (ke_payload_t*)message->get_payload(message, - KEY_EXCHANGE_V1); - if (!ke_payload) + if (!get_nonce_ke(this, &this->nonce_r, message)) { - DBG1(DBG_IKE, "KE payload missing"); return FAILED; } - this->dh_value = ke_payload->get_key_exchange_data(ke_payload); - this->dh_value = chunk_clone(this->dh_value); - this->dh->set_other_public_value(this->dh, this->dh_value); - - nonce_payload = (nonce_payload_t*)message->get_payload(message, - NONCE_V1); - if (!nonce_payload) - { - DBG1(DBG_IKE, "Nonce payload missing"); - return FAILED; - } - this->nonce_r = nonce_payload->get_nonce(nonce_payload); - if (!derive_keys(this, this->nonce_i, this->nonce_r)) { DBG1(DBG_IKE, "key derivation failed"); return FAILED; } - return NEED_MORE; } case MM_AUTH: From 21da1087a52c051b6958881150a4ef1a1a03d35b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 22 Nov 2011 09:41:58 +0100 Subject: [PATCH 095/534] Fixed diagram of IKEv1 encrypted "payload". --- src/libcharon/encoding/payloads/encryption_payload.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c index 425e58621..f3c4b3996 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.c +++ b/src/libcharon/encoding/payloads/encryption_payload.c @@ -130,8 +130,6 @@ static encoding_rule_t encodings_v1[] = { 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Message Length ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Encrypted IKE Payloads ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! Padding (0-255 octets) ! From 8c5e78ae4f738661aa47c1c5befb1b03415db1f2 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 22 Nov 2011 09:44:09 +0100 Subject: [PATCH 096/534] Fixed creation of endpoint notifies. --- src/libcharon/encoding/payloads/endpoint_notify.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/endpoint_notify.c b/src/libcharon/encoding/payloads/endpoint_notify.c index 8dc1c1955..25fb42acd 100644 --- a/src/libcharon/encoding/payloads/endpoint_notify.c +++ b/src/libcharon/encoding/payloads/endpoint_notify.c @@ -227,7 +227,7 @@ METHOD(endpoint_notify_t, build_notify, notify_payload_t*, chunk_t data; notify_payload_t *notify; - notify = notify_payload_create(NOTIFICATION); + notify = notify_payload_create(NOTIFY); notify->set_notify_type(notify, ME_ENDPOINT); data = build_notification_data(this); notify->set_notification_data(notify, data); From 4c6dfbb26bb353434bcb5bb6fa7b13fb0e447226 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 22 Nov 2011 09:46:31 +0100 Subject: [PATCH 097/534] Added missing comma after ME_CONNECT declaration. --- src/libcharon/encoding/payloads/ike_header.h | 27 ++++++++++---------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/libcharon/encoding/payloads/ike_header.h b/src/libcharon/encoding/payloads/ike_header.h index 2ee247873..a63d379b5 100644 --- a/src/libcharon/encoding/payloads/ike_header.h +++ b/src/libcharon/encoding/payloads/ike_header.h @@ -115,11 +115,12 @@ enum exchange_type_t{ * IKE_SESSION_RESUME (RFC 5723). */ IKE_SESSION_RESUME = 38, + #ifdef ME /** * ME_CONNECT */ - ME_CONNECT = 240 + ME_CONNECT = 240, #endif /* ME */ /** @@ -146,7 +147,7 @@ struct ike_header_t { /** * Get the initiator spi. * - * @return initiator_spi + * @return initiator_spi */ u_int64_t (*get_initiator_spi) (ike_header_t *this); @@ -160,7 +161,7 @@ struct ike_header_t { /** * Get the responder spi. * - * @return responder_spi + * @return responder_spi */ u_int64_t (*get_responder_spi) (ike_header_t *this); @@ -174,7 +175,7 @@ struct ike_header_t { /** * Get the major version. * - * @return major version + * @return major version */ u_int8_t (*get_maj_version) (ike_header_t *this); @@ -188,7 +189,7 @@ struct ike_header_t { /** * Get the minor version. * - * @return minor version + * @return minor version */ u_int8_t (*get_min_version) (ike_header_t *this); @@ -202,7 +203,7 @@ struct ike_header_t { /** * Get the response flag. * - * @return response flag + * @return response flag */ bool (*get_response_flag) (ike_header_t *this); @@ -216,7 +217,7 @@ struct ike_header_t { /** * Get "higher version supported"-flag. * - * @return version flag + * @return version flag */ bool (*get_version_flag) (ike_header_t *this); @@ -230,7 +231,7 @@ struct ike_header_t { /** * Get the initiator flag. * - * @return initiator flag + * @return initiator flag */ bool (*get_initiator_flag) (ike_header_t *this); @@ -244,7 +245,7 @@ struct ike_header_t { /** * Get the encryption flag. * - * @return encryption flag + * @return encryption flag */ bool (*get_encryption_flag) (ike_header_t *this); @@ -258,7 +259,7 @@ struct ike_header_t { /** * Get the commit flag. * - * @return commit flag + * @return commit flag */ bool (*get_commit_flag) (ike_header_t *this); @@ -272,7 +273,7 @@ struct ike_header_t { /** * Get the authentication only flag. * - * @return authonly flag + * @return authonly flag */ bool (*get_authonly_flag) (ike_header_t *this); @@ -286,7 +287,7 @@ struct ike_header_t { /** * Get the exchange type. * - * @return exchange type + * @return exchange type */ u_int8_t (*get_exchange_type) (ike_header_t *this); @@ -300,7 +301,7 @@ struct ike_header_t { /** * Get the message id. * - * @return message id + * @return message id */ u_int32_t (*get_message_id) (ike_header_t *this); From f5c00960862b1aeb0ed3d6e18f24e9f4d98dff70 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 12:37:08 +0100 Subject: [PATCH 098/534] Hardcode some SA lifetimes until we can configure them dynamically --- .../encoding/payloads/proposal_substructure.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 8ef993138..f0b6041bf 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -815,6 +815,12 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_PSK)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_LIFE_DURATION, 10800)); add_transform_substructure(this, transform); } @@ -864,6 +870,12 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH2_EXT_SEQ_NUMBER, NO_EXT_SEQ_NUMBERS)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, 3600)); add_transform_substructure(this, transform); } From d4f6686c6963e7e92d41f82317c9865c377b9412 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 14:38:43 +0100 Subject: [PATCH 099/534] Extended PRF+ by a non-counting variant as used by IKEv1 --- src/libcharon/sa/keymat_v2.c | 6 +- src/libstrongswan/crypto/prf_plus.c | 87 ++++++++++++++--------------- src/libstrongswan/crypto/prf_plus.h | 22 ++------ 3 files changed, 50 insertions(+), 65 deletions(-) diff --git a/src/libcharon/sa/keymat_v2.c b/src/libcharon/sa/keymat_v2.c index 9fd17328f..e8081cba0 100644 --- a/src/libcharon/sa/keymat_v2.c +++ b/src/libcharon/sa/keymat_v2.c @@ -316,7 +316,7 @@ METHOD(keymat_v2_t, derive_ike_keys, bool, this->prf->set_key(this->prf, fixed_nonce); this->prf->allocate_bytes(this->prf, secret, &skeyseed); this->prf->set_key(this->prf, skeyseed); - prf_plus = prf_plus_create(this->prf, prf_plus_seed); + prf_plus = prf_plus_create(this->prf, TRUE, prf_plus_seed); } else { @@ -336,7 +336,7 @@ METHOD(keymat_v2_t, derive_ike_keys, bool, rekey_prf->set_key(rekey_prf, rekey_skd); rekey_prf->allocate_bytes(rekey_prf, secret, &skeyseed); rekey_prf->set_key(rekey_prf, skeyseed); - prf_plus = prf_plus_create(rekey_prf, prf_plus_seed); + prf_plus = prf_plus_create(rekey_prf, TRUE, prf_plus_seed); } DBG4(DBG_IKE, "SKEYSEED %B", &skeyseed); @@ -503,7 +503,7 @@ METHOD(keymat_v2_t, derive_child_keys, bool, } this->prf->set_key(this->prf, this->skd); - prf_plus = prf_plus_create(this->prf, seed); + prf_plus = prf_plus_create(this->prf, TRUE, seed); prf_plus->allocate_bytes(prf_plus, enc_size, encr_i); prf_plus->allocate_bytes(prf_plus, int_size, integ_i); diff --git a/src/libstrongswan/crypto/prf_plus.c b/src/libstrongswan/crypto/prf_plus.c index 8e815e608..d932d86b2 100644 --- a/src/libstrongswan/crypto/prf_plus.c +++ b/src/libstrongswan/crypto/prf_plus.c @@ -25,6 +25,7 @@ typedef struct private_prf_plus_t private_prf_plus_t; * */ struct private_prf_plus_t { + /** * Public interface of prf_plus_t. */ @@ -48,42 +49,43 @@ struct private_prf_plus_t { /** * Already given out bytes in current buffer. */ - size_t given_out; + size_t used; /** - * Octet which will be appended to the seed. + * Octet which will be appended to the seed, 0 if not used */ - u_int8_t appending_octet; + u_int8_t counter; }; METHOD(prf_plus_t, get_bytes, void, private_prf_plus_t *this, size_t length, u_int8_t *buffer) { - chunk_t appending_chunk; - size_t bytes_in_round; - size_t total_bytes_written = 0; - - appending_chunk.ptr = &(this->appending_octet); - appending_chunk.len = 1; + size_t round, written = 0; while (length > 0) - { /* still more to do... */ - if (this->buffer.len == this->given_out) - { /* no bytes left in buffer, get next*/ + { + if (this->buffer.len == this->used) + { /* buffer used, get next round */ this->prf->get_bytes(this->prf, this->buffer, NULL); - this->prf->get_bytes(this->prf, this->seed, NULL); - this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr); - this->given_out = 0; - this->appending_octet++; + if (this->counter) + { + this->prf->get_bytes(this->prf, this->seed, NULL); + this->prf->get_bytes(this->prf, chunk_from_thing(this->counter), + this->buffer.ptr); + } + else + { + this->prf->get_bytes(this->prf, this->seed, this->buffer.ptr); + } + this->counter++; + this->used = 0; } - /* how many bytes can we write in this round ? */ - bytes_in_round = min(length, this->buffer.len - this->given_out); - /* copy bytes from buffer with offset */ - memcpy(buffer + total_bytes_written, this->buffer.ptr + this->given_out, bytes_in_round); + round = min(length, this->buffer.len - this->used); + memcpy(buffer + written, this->buffer.ptr + this->used, round); - length -= bytes_in_round; - this->given_out += bytes_in_round; - total_bytes_written += bytes_in_round; + length -= round; + this->used += round; + written += round; } } @@ -92,8 +94,7 @@ METHOD(prf_plus_t, allocate_bytes, void, { if (length) { - chunk->ptr = malloc(length); - chunk->len = length; + *chunk = chunk_alloc(length); get_bytes(this, length, chunk->ptr); } else @@ -113,10 +114,9 @@ METHOD(prf_plus_t, destroy, void, /* * Description in header. */ -prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed) +prf_plus_t *prf_plus_create(prf_t *prf, bool counter, chunk_t seed) { private_prf_plus_t *this; - chunk_t appending_chunk; INIT(this, .public = { @@ -125,25 +125,22 @@ prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed) .destroy = _destroy, }, .prf = prf, + .buffer = chunk_alloc(prf->get_block_size(prf)), + .seed = chunk_clone(seed), ); - /* allocate buffer for prf output */ - this->buffer.len = prf->get_block_size(prf); - this->buffer.ptr = malloc(this->buffer.len); + if (counter) + { + this->counter = 0x01; + this->prf->get_bytes(this->prf, this->seed, NULL); + this->prf->get_bytes(this->prf, chunk_from_thing(this->counter), + this->buffer.ptr); + this->counter++; + } + else + { + this->prf->get_bytes(this->prf, this->seed, this->buffer.ptr); + } - this->appending_octet = 0x01; - - /* clone seed */ - this->seed.ptr = clalloc(seed.ptr, seed.len); - this->seed.len = seed.len; - - /* do the first run */ - appending_chunk.ptr = &(this->appending_octet); - appending_chunk.len = 1; - this->prf->get_bytes(this->prf, this->seed, NULL); - this->prf->get_bytes(this->prf, appending_chunk, this->buffer.ptr); - this->given_out = 0; - this->appending_octet++; - - return &(this->public); + return &this->public; } diff --git a/src/libstrongswan/crypto/prf_plus.h b/src/libstrongswan/crypto/prf_plus.h index 4179f2695..668f12c02 100644 --- a/src/libstrongswan/crypto/prf_plus.h +++ b/src/libstrongswan/crypto/prf_plus.h @@ -27,19 +27,13 @@ typedef struct prf_plus_t prf_plus_t; #include /** - * Implementation of the prf+ function described in IKEv2 RFC. - * - * This class implements the prf+ algorithm. Internally it uses a pseudo random - * function, which implements the prf_t interface. - * See IKEv2 RFC 2.13. + * Implementation of the prf+ function used in IKEv1/IKEv2 keymat extension. */ struct prf_plus_t { + /** * Get pseudo random bytes. * - * Get the next few bytes of the prf+ output. Space - * must be allocated by the caller. - * * @param length number of bytes to get * @param buffer pointer where the generated bytes will be written */ @@ -48,9 +42,6 @@ struct prf_plus_t { /** * Allocate pseudo random bytes. * - * Get the next few bytes of the prf+ output. This function - * will allocate the required space. - * * @param length number of bytes to get * @param chunk chunk which will hold generated bytes */ @@ -65,14 +56,11 @@ struct prf_plus_t { /** * Creates a new prf_plus_t object. * - * Seed will be cloned. prf will - * not be cloned, must be destroyed outside after - * prf_plus_t usage. - * - * @param prf prf object to use + * @param prf prf object to use, must be destroyd after prf+. + * @param counter use an appending counter byte (for IKEv2 variant) * @param seed input seed for prf * @return prf_plus_t object */ -prf_plus_t *prf_plus_create(prf_t *prf, chunk_t seed); +prf_plus_t *prf_plus_create(prf_t *prf, bool counter, chunk_t seed); #endif /** PRF_PLUS_H_ @}*/ From 6cd72730bf1930ca63882f59a96c6d598f4bc1b2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 14:54:50 +0100 Subject: [PATCH 100/534] Moved keymat key length lookup functions to keymat.c --- src/libcharon/sa/keymat.c | 57 ++++++++++++++++++++++++++++++++++++ src/libcharon/sa/keymat.h | 16 ++++++++++ src/libcharon/sa/keymat_v2.c | 57 ++---------------------------------- 3 files changed, 75 insertions(+), 55 deletions(-) diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c index 7b5c95c1a..2fa4423e1 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat.c @@ -31,3 +31,60 @@ keymat_t *keymat_create(ike_version_t version, bool initiator) } return NULL; } + +/** + * Implicit key length for an algorithm + */ +typedef struct { + /** IKEv2 algorithm identifier */ + int alg; + /** key length in bits */ + int len; +} keylen_entry_t; + +/** + * See header. + */ +int keymat_get_keylen_encr(encryption_algorithm_t alg) +{ + keylen_entry_t map[] = { + {ENCR_DES, 64}, + {ENCR_3DES, 192}, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (map[i].alg == alg) + { + return map[i].len; + } + } + return 0; +} + +/** + * See header. + */ +int keymat_get_keylen_integ(integrity_algorithm_t alg) +{ + keylen_entry_t map[] = { + {AUTH_HMAC_MD5_96, 128}, + {AUTH_HMAC_SHA1_96, 160}, + {AUTH_HMAC_SHA2_256_96, 256}, + {AUTH_HMAC_SHA2_256_128, 256}, + {AUTH_HMAC_SHA2_384_192, 384}, + {AUTH_HMAC_SHA2_512_256, 512}, + {AUTH_AES_XCBC_96, 128}, + }; + int i; + + for (i = 0; i < countof(map); i++) + { + if (map[i].alg == alg) + { + return map[i].len; + } + } + return 0; +} diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index 5860044b6..5395c3776 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -72,4 +72,20 @@ struct keymat_t { */ keymat_t *keymat_create(ike_version_t version, bool initiator); +/** + * Look up the key length of an encryption algorithm. + * + * @param alg algorithm to get key length for + * @return key length in bits + */ +int keymat_get_keylen_encr(encryption_algorithm_t alg); + +/** + * Look up the key length of an integrity algorithm. + * + * @param alg algorithm to get key length for + * @return key length in bits + */ +int keymat_get_keylen_integ(integrity_algorithm_t alg); + #endif /** KEYMAT_H_ @}*/ diff --git a/src/libcharon/sa/keymat_v2.c b/src/libcharon/sa/keymat_v2.c index e8081cba0..aacff0a99 100644 --- a/src/libcharon/sa/keymat_v2.c +++ b/src/libcharon/sa/keymat_v2.c @@ -71,59 +71,6 @@ struct private_keymat_v2_t { chunk_t skp_verify; }; -typedef struct keylen_entry_t keylen_entry_t; - -/** - * Implicit key length for an algorithm - */ -struct keylen_entry_t { - /** IKEv2 algorithm identifier */ - int algo; - /** key length in bits */ - int len; -}; - -#define END_OF_LIST -1 - -/** - * Keylen for encryption algos - */ -keylen_entry_t keylen_enc[] = { - {ENCR_DES, 64}, - {ENCR_3DES, 192}, - {END_OF_LIST, 0} -}; - -/** - * Keylen for integrity algos - */ -keylen_entry_t keylen_int[] = { - {AUTH_HMAC_MD5_96, 128}, - {AUTH_HMAC_SHA1_96, 160}, - {AUTH_HMAC_SHA2_256_96, 256}, - {AUTH_HMAC_SHA2_256_128, 256}, - {AUTH_HMAC_SHA2_384_192, 384}, - {AUTH_HMAC_SHA2_512_256, 512}, - {AUTH_AES_XCBC_96, 128}, - {END_OF_LIST, 0} -}; - -/** - * Lookup key length of an algorithm - */ -static int lookup_keylen(keylen_entry_t *list, int algo) -{ - while (list->algo != END_OF_LIST) - { - if (algo == list->algo) - { - return list->len; - } - list++; - } - return 0; -} - METHOD(keymat_t, create_dh, diffie_hellman_t*, private_keymat_v2_t *this, diffie_hellman_group_t group) { @@ -448,7 +395,7 @@ METHOD(keymat_v2_t, derive_child_keys, bool, if (!enc_size) { - enc_size = lookup_keylen(keylen_enc, enc_alg); + enc_size = keymat_get_keylen_encr(enc_alg); } if (enc_alg != ENCR_NULL && !enc_size) { @@ -490,7 +437,7 @@ METHOD(keymat_v2_t, derive_child_keys, bool, if (!int_size) { - int_size = lookup_keylen(keylen_int, int_alg); + int_size = keymat_get_keylen_integ(int_alg); } if (!int_size) { From ff2a2ad33ab3ed062ce51ea4a0b69c9e741b812b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 14:58:17 +0100 Subject: [PATCH 101/534] Implemented IKEv1 keymat CHILD_SA key derivation function --- src/libcharon/sa/keymat_v1.c | 114 +++++++++++++++++++++++++++++++++++ src/libcharon/sa/keymat_v1.h | 17 ++++++ 2 files changed, 131 insertions(+) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index c8846fa46..57b96754d 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -466,6 +466,119 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, return TRUE; } +METHOD(keymat_v1_t, derive_child_keys, bool, + private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, + chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r) +{ + u_int16_t enc_alg, int_alg, enc_size = 0, int_size = 0; + u_int8_t protocol; + u_int32_t spi; + prf_plus_t *prf_plus; + chunk_t seed, secret = chunk_empty; + + /* KEYMAT = prf+(SKEYID_d, [ g(qm)^xy | ] protocol | SPI | Ni_b | Nr_b) */ + + protocol = proposal->get_protocol(proposal); + spi = proposal->get_spi(proposal); + + if (dh) + { + if (dh->get_shared_secret(dh, &secret) != SUCCESS) + { + return FALSE; + } + DBG4(DBG_CHD, "DH secret %B", &secret); + } + seed = chunk_cata("mcc", secret, chunk_from_thing(protocol), + chunk_from_thing(spi), nonce_i, nonce_r); + DBG4(DBG_CHD, "seed %B", &seed); + + if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, + &enc_alg, &enc_size)) + { + DBG2(DBG_CHD, " using %N for encryption", + encryption_algorithm_names, enc_alg); + + if (!enc_size) + { + enc_size = keymat_get_keylen_encr(enc_alg); + } + if (enc_alg != ENCR_NULL && !enc_size) + { + DBG1(DBG_CHD, "no keylength defined for %N", + encryption_algorithm_names, enc_alg); + return FALSE; + } + /* to bytes */ + enc_size /= 8; + + /* CCM/GCM/CTR/GMAC needs additional bytes */ + switch (enc_alg) + { + case ENCR_AES_CCM_ICV8: + case ENCR_AES_CCM_ICV12: + case ENCR_AES_CCM_ICV16: + case ENCR_CAMELLIA_CCM_ICV8: + case ENCR_CAMELLIA_CCM_ICV12: + case ENCR_CAMELLIA_CCM_ICV16: + enc_size += 3; + break; + case ENCR_AES_GCM_ICV8: + case ENCR_AES_GCM_ICV12: + case ENCR_AES_GCM_ICV16: + case ENCR_AES_CTR: + case ENCR_NULL_AUTH_AES_GMAC: + enc_size += 4; + break; + default: + break; + } + } + + if (proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, + &int_alg, &int_size)) + { + DBG2(DBG_CHD, " using %N for integrity", + integrity_algorithm_names, int_alg); + + if (!int_size) + { + int_size = keymat_get_keylen_integ(int_alg); + } + if (!int_size) + { + DBG1(DBG_CHD, "no keylength defined for %N", + integrity_algorithm_names, int_alg); + return FALSE; + } + /* to bytes */ + int_size /= 8; + } + + this->prf->set_key(this->prf, this->skeyid_d); + prf_plus = prf_plus_create(this->prf, FALSE, seed); + + prf_plus->allocate_bytes(prf_plus, enc_size, encr_i); + prf_plus->allocate_bytes(prf_plus, int_size, integ_i); + prf_plus->allocate_bytes(prf_plus, enc_size, encr_r); + prf_plus->allocate_bytes(prf_plus, int_size, integ_r); + + prf_plus->destroy(prf_plus); + + if (enc_size) + { + DBG4(DBG_CHD, "encryption initiator key %B", encr_i); + DBG4(DBG_CHD, "encryption responder key %B", encr_r); + } + if (int_size) + { + DBG4(DBG_CHD, "integrity initiator key %B", integ_i); + DBG4(DBG_CHD, "integrity responder key %B", integ_r); + } + return TRUE; +} + METHOD(keymat_v1_t, get_hash, chunk_t, private_keymat_v1_t *this, bool initiator, chunk_t dh, chunk_t dh_other, ike_sa_id_t *ike_sa_id, chunk_t sa_i, identification_t *id) @@ -639,6 +752,7 @@ keymat_v1_t *keymat_v1_create(bool initiator) .destroy = _destroy, }, .derive_ike_keys = _derive_ike_keys, + .derive_child_keys = _derive_child_keys, .get_hash = _get_hash, .get_iv = _get_iv, .update_iv = _update_iv, diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h index 142c835bb..fb5a1b684 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/keymat_v1.h @@ -56,6 +56,23 @@ struct keymat_v1_t { chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, auth_class_t auth, shared_key_t *shared_key); + /** + * Derive keys for the CHILD_SA. + * + * @param proposal selected algorithms + * @param dh diffie hellman key, NULL if none used + * @param nonce_i quick mode initiator nonce + * @param nonce_r quick mode responder nonce + * @param encr_i allocated initiators encryption key + * @param integ_i allocated initiators integrity key + * @param encr_r allocated responders encryption key + * @param integ_r allocated responders integrity key + */ + bool (*derive_child_keys)(keymat_v1_t *this, proposal_t *proposal, + diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, + chunk_t *encr_i, chunk_t *integ_i, + chunk_t *encr_r, chunk_t *integ_r); + /** * Get HASH data for authentication. * From 5351d63c79850ba19eb81b3d26b9679826257179 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 15:24:24 +0100 Subject: [PATCH 102/534] Install negotiated IKEv1 CHILD_SA negotiated in quick mode --- src/libcharon/sa/tasks/quick_mode.c | 163 ++++++++++++++++++++++++++++ 1 file changed, 163 insertions(+) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index aa6e4e6f1..987b8d5f4 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -39,6 +40,11 @@ struct private_quick_mode_t { */ ike_sa_t *ike_sa; + /** + * TRUE if we are initiating quick mode + */ + bool initiator; + /** * Traffic selector of initiator */ @@ -59,6 +65,16 @@ struct private_quick_mode_t { */ chunk_t nonce_r; + /** + * Initiators ESP SPI + */ + u_int32_t spi_i; + + /** + * Responder ESP SPI + */ + u_int32_t spi_r; + /** * selected CHILD_SA proposal */ @@ -74,6 +90,11 @@ struct private_quick_mode_t { */ child_sa_t *child_sa; + /** + * IKEv1 keymat + */ + keymat_v1_t *keymat; + /** states of quick mode */ enum { QM_INIT, @@ -81,6 +102,100 @@ struct private_quick_mode_t { } state; }; +/** + * Install negotiated CHILD_SA + */ +static bool install(private_quick_mode_t *this) +{ + status_t status, status_i, status_o; + chunk_t encr_i, encr_r, integ_i, integ_r; + linked_list_t *tsi, *tsr; + + this->child_sa->set_proposal(this->child_sa, this->proposal); + this->child_sa->set_state(this->child_sa, CHILD_INSTALLING); + this->child_sa->set_mode(this->child_sa, MODE_TUNNEL); + this->child_sa->set_protocol(this->child_sa, + this->proposal->get_protocol(this->proposal)); + + status_i = status_o = FAILED; + encr_i = encr_r = integ_i = integ_r = chunk_empty; + tsi = linked_list_create(); + tsr = linked_list_create(); + tsi->insert_last(tsi, this->tsi); + tsr->insert_last(tsr, this->tsr); + if (this->keymat->derive_child_keys(this->keymat, this->proposal, NULL, + this->nonce_i, this->nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) + { + if (this->initiator) + { + status_i = this->child_sa->install(this->child_sa, encr_r, integ_r, + this->spi_i, 0, TRUE, FALSE, tsi, tsr); + status_o = this->child_sa->install(this->child_sa, encr_i, integ_i, + this->spi_r, 0, FALSE, FALSE, tsi, tsr); + } + else + { + status_i = this->child_sa->install(this->child_sa, encr_i, integ_i, + this->spi_r, 0, TRUE, FALSE, tsr, tsi); + status_o = this->child_sa->install(this->child_sa, encr_r, integ_r, + this->spi_i, 0, FALSE, FALSE, tsr, tsi); + } + } + chunk_clear(&integ_i); + chunk_clear(&integ_r); + chunk_clear(&encr_i); + chunk_clear(&encr_r); + + if (status_i != SUCCESS || status_o != SUCCESS) + { + DBG1(DBG_IKE, "unable to install %s%s%sIPsec SA (SAD) in kernel", + (status_i != SUCCESS) ? "inbound " : "", + (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "", + (status_o != SUCCESS) ? "outbound " : ""); + tsi->destroy(tsi); + tsr->destroy(tsr); + return FALSE; + } + + if (this->initiator) + { + status = this->child_sa->add_policies(this->child_sa, tsi, tsr); + } + else + { + status = this->child_sa->add_policies(this->child_sa, tsr, tsi); + } + tsi->destroy(tsi); + tsr->destroy(tsr); + if (status != SUCCESS) + { + DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); + return FALSE; + } + + charon->bus->child_keys(charon->bus, this->child_sa, this->initiator, + NULL, this->nonce_i, this->nonce_r); + + /* add to IKE_SA, and remove from task */ + this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); + this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); + + DBG0(DBG_IKE, "CHILD_SA %s{%d} established " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + this->child_sa->get_name(this->child_sa), + this->child_sa->get_reqid(this->child_sa), + ntohl(this->child_sa->get_spi(this->child_sa, TRUE)), + ntohl(this->child_sa->get_spi(this->child_sa, FALSE)), + this->child_sa->get_traffic_selectors(this->child_sa, TRUE), + this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); + + charon->bus->child_updown(charon->bus, this->child_sa, TRUE); + + this->child_sa = NULL; + + return TRUE; +} + METHOD(task_t, build_i, status_t, private_quick_mode_t *this, message_t *message) { @@ -88,14 +203,35 @@ METHOD(task_t, build_i, status_t, { case QM_INIT: { + enumerator_t *enumerator; sa_payload_t *sa_payload; nonce_payload_t *nonce_payload; id_payload_t *id_payload; traffic_selector_t *ts; linked_list_t *list; + proposal_t *proposal; rng_t *rng; + this->child_sa = child_sa_create( + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->config, 0, FALSE); + list = this->config->get_proposals(this->config, TRUE); + + this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + if (!this->spi_i) + { + DBG1(DBG_IKE, "allocating SPI from kernel failed"); + return FAILED; + } + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &proposal)) + { + proposal->set_spi(proposal, this->spi_i); + } + enumerator->destroy(enumerator); + sa_payload = sa_payload_create_from_proposal_list( SECURITY_ASSOCIATION_V1, list); list->destroy_offset(list, offsetof(proposal_t, destroy)); @@ -234,6 +370,7 @@ METHOD(task_t, process_r, status_t, DBG1(DBG_IKE, "no matching proposal found"); return FAILED; } + this->spi_i = this->proposal->get_spi(this->proposal); nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1); @@ -246,12 +383,21 @@ METHOD(task_t, process_r, status_t, /* TODO-IKEv1: verify HASH(1) */ + this->child_sa = child_sa_create( + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->config, 0, FALSE); return NEED_MORE; } case QM_NEGOTIATED: { /* TODO-IKEv1: verify HASH(3) */ + if (!install(this)) + { + return FAILED; + } + return SUCCESS; } default: @@ -271,6 +417,14 @@ METHOD(task_t, build_r, status_t, id_payload_t *id_payload; rng_t *rng; + this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); + if (!this->spi_r) + { + DBG1(DBG_IKE, "allocating SPI from kernel failed"); + return FAILED; + } + this->proposal->set_spi(this->proposal, this->spi_r); + sa_payload = sa_payload_create_from_proposal( SECURITY_ASSOCIATION_V1, this->proposal); message->add_payload(message, &sa_payload->payload_interface); @@ -370,6 +524,8 @@ METHOD(task_t, process_i, status_t, DBG1(DBG_IKE, "no matching proposal found"); return FAILED; } + this->spi_r = this->proposal->get_spi(this->proposal); + nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1); if (!nonce_payload) @@ -381,6 +537,11 @@ METHOD(task_t, process_i, status_t, /* TODO-IKEv1: verify HASH(2) */ + if (!install(this)) + { + return FAILED; + } + this->state = QM_NEGOTIATED; return NEED_MORE; } @@ -431,7 +592,9 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, }, }, .ike_sa = ike_sa, + .initiator = config != NULL, .config = config, + .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa), .state = QM_INIT, ); From cd89f1a07429f457c0759ef00dfa68d02f224735 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 16:16:19 +0100 Subject: [PATCH 103/534] Only add the first algorithm of a kind to IKEv1 transforms --- src/libcharon/encoding/payloads/proposal_substructure.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index f0b6041bf..0555cba93 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -770,7 +770,7 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, 0, IKEV1_TRANSID_KEY_IKE); enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); - while (enumerator->enumerate(enumerator, &alg, &key_size)) + if (enumerator->enumerate(enumerator, &alg, &key_size)) { alg = get_ikev1_from_alg(ENCRYPTION_ALGORITHM, alg); if (alg) @@ -790,7 +790,7 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, /* encode the integrity algorithm as hash and assume use the same PRF */ enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); - while (enumerator->enumerate(enumerator, &alg, &key_size)) + if (enumerator->enumerate(enumerator, &alg, &key_size)) { alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg); if (alg) @@ -803,7 +803,7 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, enumerator->destroy(enumerator); enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); - while (enumerator->enumerate(enumerator, &alg, &key_size)) + if (enumerator->enumerate(enumerator, &alg, &key_size)) { transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, @@ -854,7 +854,7 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, } enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); - while (enumerator->enumerate(enumerator, &alg, &key_size)) + if (enumerator->enumerate(enumerator, &alg, &key_size)) { alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg); if (alg) From f9450fc9f79a17275c7fb4d9404948ab1b407f2c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 16:28:44 +0100 Subject: [PATCH 104/534] Remove public sa_payload.add_proposal() method --- src/libcharon/encoding/payloads/sa_payload.c | 23 ++++++++++---------- src/libcharon/encoding/payloads/sa_payload.h | 7 ------ 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 7433f1ad1..899584196 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -256,8 +256,10 @@ METHOD(payload_t, get_length, size_t, return this->payload_length; } -METHOD(sa_payload_t, add_proposal, void, - private_sa_payload_t *this, proposal_t *proposal) +/** + * Create a transform substructure from a proposal, add to payload + */ +static void add_proposal(private_sa_payload_t *this, proposal_t *proposal) { proposal_substructure_t *substruct, *last; payload_type_t subtype = PROPOSAL_SUBSTRUCTURE; @@ -368,7 +370,6 @@ sa_payload_t *sa_payload_create(payload_type_t type) .get_type = _get_type, .destroy = _destroy, }, - .add_proposal = _add_proposal, .get_proposals = _get_proposals, .create_substructure_enumerator = _create_substructure_enumerator, .destroy = _destroy, @@ -392,19 +393,19 @@ sa_payload_t *sa_payload_create(payload_type_t type) sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type, linked_list_t *proposals) { - sa_payload_t *this; + private_sa_payload_t *this; enumerator_t *enumerator; proposal_t *proposal; - this = sa_payload_create(type); + this = (private_sa_payload_t*)sa_payload_create(type); enumerator = proposals->create_enumerator(proposals); while (enumerator->enumerate(enumerator, &proposal)) { - this->add_proposal(this, proposal); + add_proposal(this, proposal); } enumerator->destroy(enumerator); - return this; + return &this->public; } /* @@ -413,10 +414,10 @@ sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type, sa_payload_t *sa_payload_create_from_proposal(payload_type_t type, proposal_t *proposal) { - sa_payload_t *this; + private_sa_payload_t *this; - this = sa_payload_create(type); - this->add_proposal(this, proposal); + this = (private_sa_payload_t*)sa_payload_create(type); + add_proposal(this, proposal); - return this; + return &this->public; } diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h index 16d462e65..d6c6b6036 100644 --- a/src/libcharon/encoding/payloads/sa_payload.h +++ b/src/libcharon/encoding/payloads/sa_payload.h @@ -48,13 +48,6 @@ struct sa_payload_t { */ linked_list_t *(*get_proposals) (sa_payload_t *this); - /** - * Add a child proposal (AH/ESP) to the payload. - * - * @param proposal child proposal to add to the payload - */ - void (*add_proposal) (sa_payload_t *this, proposal_t *proposal); - /** * Create an enumerator over all proposal substructures. * From 62a27ba347042fe8cafc500520f0e2cf036b07d4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 16:47:17 +0100 Subject: [PATCH 105/534] Encode multiple IKEv1 proposals in a single transform substructure --- .../encoding/payloads/proposal_substructure.c | 52 ++++++++++++++++--- .../encoding/payloads/proposal_substructure.h | 13 ++++- src/libcharon/encoding/payloads/sa_payload.c | 20 +++++-- 3 files changed, 73 insertions(+), 12 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 0555cba93..a1c58afb6 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -760,14 +760,14 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type) * Add an IKEv1 IKE proposal to the substructure */ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, - proposal_t *proposal) + proposal_t *proposal, int number) { transform_substructure_t *transform; u_int16_t alg, key_size; enumerator_t *enumerator; transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, - 0, IKEV1_TRANSID_KEY_IKE); + number, IKEV1_TRANSID_KEY_IKE); enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); if (enumerator->enumerate(enumerator, &alg, &key_size)) @@ -829,7 +829,7 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, * Add an IKEv1 ESP proposal to the substructure */ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, - proposal_t *proposal) + proposal_t *proposal, int number) { transform_substructure_t *transform = NULL; u_int16_t alg, key_size; @@ -839,7 +839,7 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, if (enumerator->enumerate(enumerator, &alg, &key_size)) { transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, - 0, alg); + number, alg); if (key_size) { transform->add_transform_attribute(transform, @@ -968,10 +968,10 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( switch (proposal->get_protocol(proposal)) { case PROTO_IKE: - set_from_proposal_v1_ike(this, proposal); + set_from_proposal_v1_ike(this, proposal, 0); break; case PROTO_ESP: - set_from_proposal_v1_esp(this, proposal); + set_from_proposal_v1_esp(this, proposal, 0); break; default: break; @@ -1003,3 +1003,43 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( return &this->public; } + +/** + * See header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposals( + linked_list_t *proposals) +{ + private_proposal_substructure_t *this = NULL; + enumerator_t *enumerator; + proposal_t *proposal; + int number = 0; + + enumerator = proposals->create_enumerator(proposals); + while (enumerator->enumerate(enumerator, &proposal)) + { + if (!this) + { + this = (private_proposal_substructure_t*) + proposal_substructure_create_from_proposal( + PROPOSAL_SUBSTRUCTURE_V1, proposal); + } + else + { + switch (proposal->get_protocol(proposal)) + { + case PROTO_IKE: + set_from_proposal_v1_ike(this, proposal, ++number); + break; + case PROTO_ESP: + set_from_proposal_v1_esp(this, proposal, ++number); + break; + default: + break; + } + } + } + enumerator->destroy(enumerator); + + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index 72bbdd64f..79a6ca238 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -127,10 +127,19 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type); * Creates a proposal_substructure_t from a proposal_t. * * @param type PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 - * @param proposal proposal to build a substruct out of it - * @return proposal_substructure_t object + * @param proposal proposal to build a substruct out of it + * @return proposal_substructure_t object */ proposal_substructure_t *proposal_substructure_create_from_proposal( payload_type_t type, proposal_t *proposal); +/** + * Creates a proposal_substructure_t from a list of proposal_t (IKEv1 only). + * + * @param proposal proposal to build a substruct out of it + * @return IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1 + */ +proposal_substructure_t *proposal_substructure_create_from_proposals( + linked_list_t *proposals); + #endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 899584196..becc4243d 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -398,13 +398,25 @@ sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type, proposal_t *proposal; this = (private_sa_payload_t*)sa_payload_create(type); - enumerator = proposals->create_enumerator(proposals); - while (enumerator->enumerate(enumerator, &proposal)) + if (type == SECURITY_ASSOCIATION) { - add_proposal(this, proposal); + enumerator = proposals->create_enumerator(proposals); + while (enumerator->enumerate(enumerator, &proposal)) + { + add_proposal(this, proposal); + } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); + else + { /* IKEv1 encodes multiple proposals in a single substructure + * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */ + proposal_substructure_t *substruct; + substruct = proposal_substructure_create_from_proposals(proposals); + substruct->set_is_last_proposal(substruct, TRUE); + this->proposals->insert_last(this->proposals, substruct); + compute_length(this); + } return &this->public; } From d50152a70bb109624d05249e11dda6c28a9a6422 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 22 Nov 2011 17:04:07 +0100 Subject: [PATCH 106/534] Parse proposal substructure with multiple IKEv1 transforms to multiple proposals --- .../encoding/payloads/proposal_substructure.c | 47 ++++++++++--------- .../encoding/payloads/proposal_substructure.h | 6 +-- src/libcharon/encoding/payloads/sa_payload.c | 14 +++--- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index a1c58afb6..66fa8997b 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -650,18 +650,35 @@ static void add_to_proposal_v1_esp(proposal_t *proposal, transform->get_transform_id(transform), key_length); } -METHOD(proposal_substructure_t, get_proposal, proposal_t*, - private_proposal_substructure_t *this) +METHOD(proposal_substructure_t, get_proposals, void, + private_proposal_substructure_t *this, linked_list_t *proposals) { transform_substructure_t *transform; enumerator_t *enumerator; - proposal_t *proposal; + proposal_t *proposal = NULL; + u_int64_t spi = 0; - proposal = proposal_create(this->protocol_id, this->proposal_number); + switch (this->spi.len) + { + case 4: + spi = *((u_int32_t*)this->spi.ptr); + break; + case 8: + spi = *((u_int64_t*)this->spi.ptr); + break; + default: + break; + } enumerator = this->transforms->create_enumerator(this->transforms); while (enumerator->enumerate(enumerator, &transform)) { + if (!proposal) + { + proposal = proposal_create(this->protocol_id, this->proposal_number); + proposal->set_spi(proposal, spi); + proposals->insert_last(proposals, proposal); + } if (this->type == PROPOSAL_SUBSTRUCTURE) { add_to_proposal_v2(proposal, transform); @@ -679,27 +696,11 @@ METHOD(proposal_substructure_t, get_proposal, proposal_t*, default: break; } - /* TODO-IKEv1: We currently accept the first set of transforms - * in a substructure only. We need to return multiple proposals, - * but this messes up proposal numbering, as we don't support - * transform numbering. */ - break; + /* create a new proposal for each transform in IKEv1 */ + proposal = NULL; } } enumerator->destroy(enumerator); - - switch (this->spi.len) - { - case 4: - proposal->set_spi(proposal, *((u_int32_t*)this->spi.ptr)); - break; - case 8: - proposal->set_spi(proposal, *((u_int64_t*)this->spi.ptr)); - break; - default: - break; - } - return proposal; } METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*, @@ -741,7 +742,7 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type) .set_protocol_id = _set_protocol_id, .get_protocol_id = _get_protocol_id, .set_is_last_proposal = _set_is_last_proposal, - .get_proposal = _get_proposal, + .get_proposals = _get_proposals, .create_substructure_enumerator = _create_substructure_enumerator, .set_spi = _set_spi, .get_spi = _get_spi, diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index 79a6ca238..496a352ca 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -96,11 +96,11 @@ struct proposal_substructure_t { void (*set_spi) (proposal_substructure_t *this, chunk_t spi); /** - * Get a proposal_t from the propsal_substructure_t. + * Get proposals contained in a propsal_substructure_t. * - * @return proposal_t + * @param list list to add created proposals to */ - proposal_t * (*get_proposal) (proposal_substructure_t *this); + void (*get_proposals) (proposal_substructure_t *this, linked_list_t *list); /** * Create an enumerator over transform substructures. diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index becc4243d..05695fce2 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -297,8 +297,8 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*, int ignore_struct_number = 0; enumerator_t *enumerator; proposal_substructure_t *substruct; - linked_list_t *list; proposal_t *proposal; + linked_list_t *list; if (this->type == SECURITY_ASSOCIATION_V1) { /* IKEv1 proposals start with 0 */ @@ -320,18 +320,16 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*, if (ignore_struct_number < struct_number) { /* remove an already added, if first of series */ - list->remove_last(list, (void**)&proposal); - proposal->destroy(proposal); + if (list->remove_last(list, (void**)&proposal) == SUCCESS) + { + proposal->destroy(proposal); + } ignore_struct_number = struct_number; } continue; } struct_number++; - proposal = substruct->get_proposal(substruct); - if (proposal) - { - list->insert_last(list, proposal); - } + substruct->get_proposals(substruct, list); } enumerator->destroy(enumerator); return list; From 9769b76cabbca4b97bcccfe69b6455c8c0c162ad Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Wed, 23 Nov 2011 08:04:52 +0100 Subject: [PATCH 107/534] Updated the CERT payload to work for both IKEv1 and IKEv2. --- .../encoding/payloads/cert_payload.c | 24 ++++++++++++------- .../encoding/payloads/cert_payload.h | 15 ++++++++---- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c index 1ef93b724..cf97e9613 100644 --- a/src/libcharon/encoding/payloads/cert_payload.c +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -86,6 +86,11 @@ struct private_cert_payload_t { * TRUE if the "Hash and URL" data is invalid */ bool invalid_hash_and_url; + + /** + * The payload type. + */ + payload_type_t type; }; /** @@ -182,7 +187,7 @@ METHOD(payload_t, get_header_length, int, METHOD(payload_t, get_type, payload_type_t, private_cert_payload_t *this) { - return CERTIFICATE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -267,7 +272,7 @@ METHOD2(payload_t, cert_payload_t, destroy, void, /* * Described in header */ -cert_payload_t *cert_payload_create() +cert_payload_t *cert_payload_create(payload_type_t type) { private_cert_payload_t *this; @@ -291,6 +296,7 @@ cert_payload_t *cert_payload_create() }, .next_payload = NO_PAYLOAD, .payload_length = get_header_length(this), + .type = type, ); return &this->public; } @@ -298,9 +304,9 @@ cert_payload_t *cert_payload_create() /* * Described in header */ -cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) +cert_payload_t *cert_payload_create_from_cert(certificate_t *cert, payload_type_t type) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(type); switch (cert->get_type(cert)) { @@ -326,9 +332,9 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) /* * Described in header */ -cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url) +cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url, payload_type_t type) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(type); this->encoding = ENC_X509_HASH_AND_URL; this->data = chunk_cat("cc", hash, chunk_create(url, strlen(url))); @@ -339,11 +345,11 @@ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url) /* * Described in header */ -cert_payload_t *cert_payload_create_custom(cert_encoding_t type, chunk_t data) +cert_payload_t *cert_payload_create_custom(cert_encoding_t encoding, chunk_t data, payload_type_t type) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(type); - this->encoding = type; + this->encoding = encoding; this->data = data; this->payload_length = get_header_length(this) + this->data.len; return &this->public; diff --git a/src/libcharon/encoding/payloads/cert_payload.h b/src/libcharon/encoding/payloads/cert_payload.h index 6eb79c8ed..c237d7dea 100644 --- a/src/libcharon/encoding/payloads/cert_payload.h +++ b/src/libcharon/encoding/payloads/cert_payload.h @@ -108,34 +108,39 @@ struct cert_payload_t { /** * Creates an empty certificate payload. * + * @param type payload type (for IKEv1 or IKEv2) + * @param cert certificate to embed * @return cert_payload_t object */ -cert_payload_t *cert_payload_create(void); +cert_payload_t *cert_payload_create(payload_type_t type); /** * Creates a certificate payload with an embedded certificate. * + * @param type payload type (for IKEv1 or IKEv2) * @param cert certificate to embed * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_from_cert(certificate_t *cert); +cert_payload_t *cert_payload_create_from_cert(certificate_t *cert, payload_type_t type); /** * Creates a certificate payload with hash and URL encoding of a certificate. * + * @param type payload type (for IKEv1 or IKEv2) * @param hash hash of the DER encoded certificate (get's cloned) * @param url the URL to locate the certificate (get's cloned) * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url); +cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url, payload_type_t type); /** * Creates a custom certificate payload using type and associated data. * - * @param type encoding type of certificate + * @param type payload type (for IKEv1 or IKEv2) + * @param encoding encoding type of certificate * @param data associated data (gets owned) * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_custom(cert_encoding_t type, chunk_t data); +cert_payload_t *cert_payload_create_custom(cert_encoding_t encoding, chunk_t data, payload_type_t type); #endif /** CERT_PAYLOAD_H_ @}*/ From 54a8a94fa9009437e4c4d7df52d881fc1203c2ac Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Wed, 23 Nov 2011 08:29:54 +0100 Subject: [PATCH 108/534] IKEv1 ConfigMode: Added TRANSACTION exchange type. Added attribute_payload (IKEv2 equiv cp_payload) and data_attribute (IKEv2 equiv configuration_attribute) payload types. Did not combine with IKEv2 because it wasn't trivial to do so. This might be a task worth investigating in the future, because there is a decent amount of shared code here. --- src/libcharon/Makefile.am | 2 + src/libcharon/encoding/message.c | 26 +++++++++++++ src/libcharon/encoding/payloads/ike_header.c | 12 +++--- src/libcharon/encoding/payloads/ike_header.h | 6 ++- src/libcharon/encoding/payloads/payload.c | 41 +++++++++++++------- src/libcharon/encoding/payloads/payload.h | 11 ++++++ 6 files changed, 78 insertions(+), 20 deletions(-) diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index e3c73a879..d76ba491c 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -15,11 +15,13 @@ daemon.c daemon.h \ encoding/generator.c encoding/generator.h \ encoding/message.c encoding/message.h \ encoding/parser.c encoding/parser.h \ +encoding/payloads/attribute_payload_v1.c encoding/payloads/attribute_payload_v1.h \ encoding/payloads/auth_payload.c encoding/payloads/auth_payload.h \ encoding/payloads/cert_payload.c encoding/payloads/cert_payload.h \ encoding/payloads/certreq_payload.c encoding/payloads/certreq_payload.h \ encoding/payloads/configuration_attribute.c encoding/payloads/configuration_attribute.h \ encoding/payloads/cp_payload.c encoding/payloads/cp_payload.h \ +encoding/payloads/data_attribute_v1.c encoding/payloads/data_attribute_v1.h \ encoding/payloads/delete_payload.c encoding/payloads/delete_payload.h \ encoding/payloads/eap_payload.c encoding/payloads/eap_payload.h \ encoding/payloads/encodings.c encoding/payloads/encodings.h \ diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index e7a48344b..e84f9a123 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -631,6 +631,24 @@ static payload_order_t quick_mode_r_order[] = { {ID_V1, 0}, }; +/** + * Message rule for TRANSACTION. + */ +static payload_rule_t transaction_payload_rules_v1[] = { +/* payload type min max encr suff */ + {HASH_V1, 0, 1, TRUE, FALSE}, + {ATTRIBUTE_V1, 1, 1, FALSE, FALSE}, +}; + +/** + * Payload order for TRANSACTION. + */ +static payload_order_t transaction_payload_order_v1[] = { +/* payload type notify type */ + {HASH_V1, 0}, + {ATTRIBUTE_V1, 0}, +}; + #endif /* USE_IKEV1 */ /** @@ -708,6 +726,14 @@ static message_rule_t message_rules[] = { countof(quick_mode_r_rules), quick_mode_r_rules, countof(quick_mode_r_order), quick_mode_r_order, }, + {TRANSACTION, TRUE, TRUE, + countof(transaction_payload_rules_v1), transaction_payload_rules_v1, + countof(transaction_payload_order_v1), transaction_payload_order_v1, + }, + {TRANSACTION, FALSE, TRUE, + countof(transaction_payload_rules_v1), transaction_payload_rules_v1, + countof(transaction_payload_order_v1), transaction_payload_order_v1, + }, /* TODO-IKEv1: define rules for other exchanges */ #endif /* USE_IKEV1 */ }; diff --git a/src/libcharon/encoding/payloads/ike_header.c b/src/libcharon/encoding/payloads/ike_header.c index 54e04658c..58b624192 100644 --- a/src/libcharon/encoding/payloads/ike_header.c +++ b/src/libcharon/encoding/payloads/ike_header.c @@ -114,12 +114,13 @@ struct private_ike_header_t { u_int32_t length; }; -ENUM_BEGIN(exchange_type_names, ID_PROT, INFORMATIONAL_V1, +ENUM_BEGIN(exchange_type_names, ID_PROT, TRANSACTION, "ID_PROT", "AUTH_ONLY", "AGGRESSIVE", - "INFORMATIONAL_V1"); -ENUM_NEXT(exchange_type_names, QUICK_MODE, IKE_SESSION_RESUME, INFORMATIONAL_V1, + "INFORMATIONAL_V1", + "TRANSACTION"); +ENUM_NEXT(exchange_type_names, QUICK_MODE, IKE_SESSION_RESUME, TRANSACTION, "QUICK_MODE", "NEW_GROUP_MODE", "IKE_SA_INIT", @@ -172,10 +173,10 @@ static encoding_rule_t encodings[] = { /* 4 Byte message id, stored in the field message_id */ { U_INT_32, offsetof(private_ike_header_t, message_id) }, /* 4 Byte length fied, stored in the field length */ - { HEADER_LENGTH,offsetof(private_ike_header_t, length) }, + { HEADER_LENGTH, offsetof(private_ike_header_t, length) } }; -/* 1 2 3 +/* 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! IKE_SA Initiator's SPI ! @@ -206,6 +207,7 @@ METHOD(payload_t, verify, status_t, /* fall */ case AUTH_ONLY: case INFORMATIONAL_V1: + case TRANSACTION: case QUICK_MODE: case NEW_GROUP_MODE: if (this->maj_version != IKEV1_MAJOR_VERSION) diff --git a/src/libcharon/encoding/payloads/ike_header.h b/src/libcharon/encoding/payloads/ike_header.h index a63d379b5..e6b7d0dff 100644 --- a/src/libcharon/encoding/payloads/ike_header.h +++ b/src/libcharon/encoding/payloads/ike_header.h @@ -81,6 +81,11 @@ enum exchange_type_t{ */ INFORMATIONAL_V1 = 5, + /** + * Transaction (ISAKMP Cfg Mode "draft-ietf-ipsec-isakmp-mode-cfg-05") + */ + TRANSACTION = 6, + /** * Quick Mode */ @@ -138,7 +143,6 @@ extern enum_name_t *exchange_type_names; * An object of this type represents an IKE header of either IKEv1 or IKEv2. */ struct ike_header_t { - /** * The payload_t interface. */ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 83fd1cb1c..7d6fa6674 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -20,6 +20,7 @@ #include #include + #include #include #include @@ -37,10 +38,12 @@ #include #include +#include +#include ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD, "NO_PAYLOAD"); -ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, VENDOR_ID_V1, NO_PAYLOAD, +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, ATTRIBUTE_V1, NO_PAYLOAD, "SECURITY_ASSOCIATION_V1", "PROPOSAL_V1", "TRANSFORM_V1", @@ -53,8 +56,9 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, VENDOR_ID_V1, NO_PAYLOAD, "NONCE_V1", "NOTIFY_V1", "DELETE_V1", - "VENDOR_ID_V1"); -ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, VENDOR_ID_V1, + "VENDOR_ID_V1", + "ATTRIBUTE_V1"); +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, ATTRIBUTE_V1, "SECURITY_ASSOCIATION", "KEY_EXCHANGE", "ID_INITIATOR", @@ -74,7 +78,7 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, V #ifdef ME ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, "ID_PEER"); -ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, ID_PEER, +ENUM_NEXT(payload_type_names, HEADER, DATA_ATTRIBUTE_V1, ID_PEER, "HEADER", "PROPOSAL_SUBSTRUCTURE", "PROPOSAL_SUBSTRUCTURE_V1", @@ -84,9 +88,10 @@ ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, ID_PEER, "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", "CONFIGURATION_ATTRIBUTE", - "ENCRYPTED_V1"); + "ENCRYPTED_V1", + "DATA_ATTRIBUTE_V1"); #else -ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, EXTENSIBLE_AUTHENTICATION, +ENUM_NEXT(payload_type_names, HEADER, DATA_ATTRIBUTE_V1, EXTENSIBLE_AUTHENTICATION, "HEADER", "PROPOSAL_SUBSTRUCTURE", "PROPOSAL_SUBSTRUCTURE_V1", @@ -96,9 +101,10 @@ ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, EXTENSIBLE_AUTHENTICATION, "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", "CONFIGURATION_ATTRIBUTE", - "ENCRYPTED_V1"); + "ENCRYPTED_V1", + "DATA_ATTRIBUTE_V1"); #endif /* ME */ -ENUM_END(payload_type_names, ENCRYPTED_V1); +ENUM_END(payload_type_names, DATA_ATTRIBUTE_V1); /* short forms of payload names */ ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD, @@ -137,7 +143,7 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICAT #ifdef ME ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, "IDp"); -ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, ID_PEER, +ENUM_NEXT(payload_type_short_names, HEADER, DATA_ATTRIBUTE_V1, ID_PEER, "HDR", "PROP", "PROP", @@ -147,9 +153,10 @@ ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, ID_PEER, "TRANSATTR", "TSSUB", "CATTR", - "E"); + "E", + "DATAATTR"); #else -ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, EXTENSIBLE_AUTHENTICATION, +ENUM_NEXT(payload_type_short_names, HEADER, DATA_ATTRIBUTE_V1, EXTENSIBLE_AUTHENTICATION, "HDR", "PROP", "PROP", @@ -159,9 +166,10 @@ ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, EXTENSIBLE_AUTHENTICAT "TRANSATTR", "TSSUB", "CATTR", - "E"); + "E", + "DATAATTR"); #endif /* ME */ -ENUM_END(payload_type_short_names, ENCRYPTED_V1); +ENUM_END(payload_type_short_names, DATA_ATTRIBUTE_V1); /* * see header @@ -197,7 +205,8 @@ payload_t *payload_create(payload_type_t type) case AUTHENTICATION: return (payload_t*)auth_payload_create(); case CERTIFICATE: - return (payload_t*)cert_payload_create(); + case CERTIFICATE_V1: + return (payload_t*)cert_payload_create(type); case CERTIFICATE_REQUEST: return (payload_t*)certreq_payload_create(); case TRAFFIC_SELECTOR_SUBSTRUCTURE: @@ -229,6 +238,10 @@ payload_t *payload_create(payload_type_t type) case ENCRYPTED: case ENCRYPTED_V1: return (payload_t*)encryption_payload_create(type); + case ATTRIBUTE_V1: + return (payload_t*)attribute_payload_v1_create(); + case DATA_ATTRIBUTE_V1: + return (payload_t*)data_attribute_v1_create(); default: return (payload_t*)unknown_payload_create(type); } diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index e4ed76abf..f55099fe7 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -112,6 +112,11 @@ enum payload_type_t { */ VENDOR_ID_V1 = 13, + /** + * Attribute payload (ISAKMP Cfg Mode "draft-ietf-ipsec-isakmp-mode-cfg-05") + */ + ATTRIBUTE_V1 = 14, + /** * The security association (SA) payload containing proposals. */ @@ -252,6 +257,12 @@ enum payload_type_t { * This is not really a payload, but rather the complete IKEv1 message. */ ENCRYPTED_V1, + + /** + * DATA_ATTRIBUTE, attribute in an ATTRIBUTE payload. + */ + DATA_ATTRIBUTE_V1, + }; /** From c71760570ea014f2f85a9a7961c4d88ea2e4c0a5 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Wed, 23 Nov 2011 08:36:22 +0100 Subject: [PATCH 109/534] IKEv1 ConfigMode: Added the payload handlers for attribute_payload and data_attribute payload types. --- .../encoding/payloads/attribute_payload_v1.c | 231 ++++++++++++++++ .../encoding/payloads/attribute_payload_v1.h | 93 +++++++ .../encoding/payloads/data_attribute_v1.c | 260 ++++++++++++++++++ .../encoding/payloads/data_attribute_v1.h | 88 ++++++ 4 files changed, 672 insertions(+) create mode 100644 src/libcharon/encoding/payloads/attribute_payload_v1.c create mode 100644 src/libcharon/encoding/payloads/attribute_payload_v1.h create mode 100644 src/libcharon/encoding/payloads/data_attribute_v1.c create mode 100644 src/libcharon/encoding/payloads/data_attribute_v1.h diff --git a/src/libcharon/encoding/payloads/attribute_payload_v1.c b/src/libcharon/encoding/payloads/attribute_payload_v1.c new file mode 100644 index 000000000..3aa0bc3a1 --- /dev/null +++ b/src/libcharon/encoding/payloads/attribute_payload_v1.c @@ -0,0 +1,231 @@ + +#include + +#include "attribute_payload_v1.h" + +#include +#include + +ENUM(config_type_v1_names, ISAKMP_CFG_REQUEST, ISAKMP_CFG_ACK, + "ISAKMP_CFG_REQUEST", + "ISAKMP_CFG_REPLY", + "ISAKMP_CFG_SET", + "ISAKMP_CFG_ACK", +); + +typedef struct private_attribute_payload_v1_t private_attribute_payload_v1_t; + +/** + * Private data of an attribute_payload_v1_t object. + */ +struct private_attribute_payload_v1_t { + + /** + * Public cp_payload_t interface. + */ + attribute_payload_v1_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * List of attributes, as configuration_attribute_t + */ + linked_list_t *attributes; + + /** + * Reserved bytes + */ + u_int8_t reserved_byte[2]; + + /** + * Identifier + */ + u_int16_t identifier; + + /** + * Config Type. + */ + u_int8_t type; +}; + +/** + * Encoding rules to parse or generate a IKEv2-CP Payload + * + * The defined offsets are the positions in a object of type + * private_attribute_payload_v1_t. + */ +encoding_rule_t attribute_payload_v1_encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_attribute_payload_v1_t, next_payload) }, + /* reserved byte */ + { RESERVED_BYTE, offsetof(private_attribute_payload_v1_t, reserved_byte[0]) }, + /* Length of the whole Attribute payload*/ + { PAYLOAD_LENGTH, offsetof(private_attribute_payload_v1_t, payload_length) }, + /* Config type */ + { U_INT_8, offsetof(private_attribute_payload_v1_t, type) }, + /* 3 reserved bytes */ + { RESERVED_BYTE, offsetof(private_attribute_payload_v1_t, reserved_byte[1])}, + + /* Identifier */ + { U_INT_16, offsetof(private_attribute_payload_v1_t, identifier)}, + + /* List of configuration attributes */ + { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE, offsetof(private_attribute_payload_v1_t, attributes) } +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! CFG Type ! RESERVED ! Identifier ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Configuration Attributes ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +METHOD(payload_t, verify, status_t, + private_attribute_payload_v1_t *this) +{ + status_t status = SUCCESS; + enumerator_t *enumerator; + payload_t *attribute; + + enumerator = this->attributes->create_enumerator(this->attributes); + while (enumerator->enumerate(enumerator, &attribute)) + { + status = attribute->verify(attribute); + if (status != SUCCESS) + { + break; + } + } + enumerator->destroy(enumerator); + return status; +} + +METHOD(payload_t, get_encoding_rules, void, + private_attribute_payload_v1_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = attribute_payload_v1_encodings; + *rule_count = countof(attribute_payload_v1_encodings); +} + +METHOD(payload_t, get_type, payload_type_t, + private_attribute_payload_v1_t *this) +{ + return ATTRIBUTE_V1; +} + +METHOD(payload_t, get_next_type, payload_type_t, + private_attribute_payload_v1_t *this) +{ + return this->next_payload; +} + +METHOD(payload_t, set_next_type, void, + private_attribute_payload_v1_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * recompute the length of the payload. + */ +static void compute_length(private_attribute_payload_v1_t *this) +{ + enumerator_t *enumerator; + payload_t *attribute; + + this->payload_length = ATTRIBUTE_PAYLOAD_V1_HEADER_LENGTH; + + enumerator = this->attributes->create_enumerator(this->attributes); + while (enumerator->enumerate(enumerator, &attribute)) + { + this->payload_length += attribute->get_length(attribute); + } + enumerator->destroy(enumerator); +} + +METHOD(payload_t, get_length, size_t, + private_attribute_payload_v1_t *this) +{ + return this->payload_length; +} + +METHOD(attribute_payload_v1_t, create_attribute_enumerator, enumerator_t*, + private_attribute_payload_v1_t *this) +{ + return this->attributes->create_enumerator(this->attributes); +} + +METHOD(attribute_payload_v1_t, add_attribute, void, + private_attribute_payload_v1_t *this, data_attribute_v1_t *attribute) +{ + this->attributes->insert_last(this->attributes, attribute); + compute_length(this); +} + +METHOD(attribute_payload_v1_t, get_config_type, config_type_v1_t, + private_attribute_payload_v1_t *this) +{ + return this->type; +} + +METHOD2(payload_t, attribute_payload_v1_t, destroy, void, + private_attribute_payload_v1_t *this) +{ + this->attributes->destroy_offset(this->attributes, + offsetof(data_attribute_v1_t, destroy)); + free(this); +} + +/* + * Described in header. + */ +attribute_payload_v1_t *attribute_payload_v1_create_type(config_type_v1_t type) +{ + private_attribute_payload_v1_t *this; + + INIT(this, + .public = { + .payload_interface = { + .verify = _verify, + .get_encoding_rules = _get_encoding_rules, + .get_length = _get_length, + .get_next_type = _get_next_type, + .set_next_type = _set_next_type, + .get_type = _get_type, + .destroy = _destroy, + }, + .create_attribute_enumerator = _create_attribute_enumerator, + .add_attribute = _add_attribute, + .get_type = _get_config_type, + .destroy = _destroy, + }, + .next_payload = NO_PAYLOAD, + .payload_length = ATTRIBUTE_PAYLOAD_V1_HEADER_LENGTH, + .attributes = linked_list_create(), + .type = type, + ); + return &this->public; +} + +/* + * Described in header. + */ +attribute_payload_v1_t *attribute_payload_v1_create() +{ + return attribute_payload_v1_create_type(ISAKMP_CFG_REQUEST); +} diff --git a/src/libcharon/encoding/payloads/attribute_payload_v1.h b/src/libcharon/encoding/payloads/attribute_payload_v1.h new file mode 100644 index 000000000..d59d9981e --- /dev/null +++ b/src/libcharon/encoding/payloads/attribute_payload_v1.h @@ -0,0 +1,93 @@ + +/** + * @defgroup attribute_payload_v1 attribute_payload_v1 + * @{ @ingroup payloads + */ + +#ifndef ATTRIBUTE_PAYLOAD_V1_H_ +#define ATTRIBUTE_PAYLOAD_V1_H_ + +typedef enum config_type_v1_t config_type_v1_t; +typedef struct attribute_payload_v1_t attribute_payload_v1_t; + +#include +#include +#include +#include + +/** + * ATTRIBUTE_PAYLOAD_V1 length in bytes without any proposal substructure. + */ +#define ATTRIBUTE_PAYLOAD_V1_HEADER_LENGTH 8 + +/** + * Config Type of an Attribute Payload. + */ +enum config_type_v1_t { + ISAKMP_CFG_REQUEST = 1, + ISAKMP_CFG_REPLY = 2, + ISAKMP_CFG_SET = 3, + ISAKMP_CFG_ACK = 4, +}; + +/** + * enum name for config_type_v1_t. + */ +extern enum_name_t *config_type_v1_names; + +/** + * Class representing an ISAKMP Config Mode Attribute Payload. + * + * The Attribute Payload format is described in draft-ietf-ipsec-isakmp-mode-cfg-o5.txt section 3.2. + */ +struct attribute_payload_v1_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Creates an enumerator of stored data_attribute_v1_t objects. + * + * @return enumerator over configration_attribute_t + */ + enumerator_t *(*create_attribute_enumerator) (attribute_payload_v1_t *this); + + /** + * Adds a configuration attribute to the attribute payload. + * + * @param attribute attribute to add + */ + void (*add_attribute)(attribute_payload_v1_t *this, + data_attribute_v1_t *attribute); + + /** + * Get the attribute payload type. + * + * @return type of attribute payload + */ + config_type_v1_t (*get_type) (attribute_payload_v1_t *this); + + /** + * Destroys an attribute_payload_v1_t object. + */ + void (*destroy) (attribute_payload_v1_t *this); +}; + +/** + * Creates an empty attribute payload + * + * @return empty attribute payload + */ +attribute_payload_v1_t *attribute_payload_v1_create(); + +/** + * Creates an attribute_payload_v1_t with type and value + * + * @param config_type type of attribute payload to create + * @return created attribute payload + */ +attribute_payload_v1_t *attribute_payload_v1_create_type(config_type_v1_t config_type); + +#endif /** ATTRIBUTE_PAYLOAD_V1_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/data_attribute_v1.c b/src/libcharon/encoding/payloads/data_attribute_v1.c new file mode 100644 index 000000000..37f7c0072 --- /dev/null +++ b/src/libcharon/encoding/payloads/data_attribute_v1.c @@ -0,0 +1,260 @@ + +#include + +#include "data_attribute_v1.h" + +#include +#include +#include + +typedef struct private_data_attribute_v1_t private_data_attribute_v1_t; + +/** + * Private data of an data_attribute_v1_t object. + */ +struct private_data_attribute_v1_t { + + /** + * Public data_attribute_v1_t interface. + */ + data_attribute_v1_t public; + + /** + * Reserved bit + */ + bool af_flag; + + /** + * Type of the attribute. + */ + u_int16_t type; + + /** + * Length of the attribute. + */ + u_int16_t length_or_value; + + /** + * Attribute value as chunk. + */ + chunk_t value; +}; + +/** + * Encoding rules to parse or generate a configuration attribute. + * + * The defined offsets are the positions in a object of type + * private_data_attribute_v1_t. + */ +encoding_rule_t data_attribute_v1_encodings[] = { + /* AF Flag */ + { FLAG, offsetof(private_data_attribute_v1_t, af_flag)}, + /* type of the attribute as 15 bit unsigned integer */ + { ATTRIBUTE_TYPE, offsetof(private_data_attribute_v1_t, type) }, + /* Length of attribute value */ + { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_data_attribute_v1_t, length_or_value) }, + /* Value of attribute if attribute format flag is zero */ + { ATTRIBUTE_VALUE, offsetof(private_data_attribute_v1_t, value) } +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + !R| Attribute Type ! Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + ~ Value ~ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +METHOD(payload_t, verify, status_t, + private_data_attribute_v1_t *this) +{ + bool failed = FALSE; + + if (this->length_or_value != this->value.len) + { + DBG1(DBG_ENC, "invalid attribute length"); + return FAILED; + } + + switch (this->type) + { + case INTERNAL_IP4_ADDRESS: + case INTERNAL_IP4_NETMASK: + case INTERNAL_IP4_DNS: + case INTERNAL_IP4_NBNS: + case INTERNAL_ADDRESS_EXPIRY: + case INTERNAL_IP4_DHCP: + if (this->length_or_value != 0 && this->length_or_value != 4) + { + failed = TRUE; + } + break; + case INTERNAL_IP4_SUBNET: + if (this->length_or_value != 0 && this->length_or_value != 8) + { + failed = TRUE; + } + break; + case INTERNAL_IP6_ADDRESS: + case INTERNAL_IP6_SUBNET: + if (this->length_or_value != 0 && this->length_or_value != 17) + { + failed = TRUE; + } + break; + case INTERNAL_IP6_DNS: + case INTERNAL_IP6_NBNS: + case INTERNAL_IP6_DHCP: + if (this->length_or_value != 0 && this->length_or_value != 16) + { + failed = TRUE; + } + break; + case SUPPORTED_ATTRIBUTES: + if (this->length_or_value % 2) + { + failed = TRUE; + } + break; + case APPLICATION_VERSION: + /* any length acceptable */ + break; + default: + DBG1(DBG_ENC, "unknown attribute type %N", + configuration_attribute_type_names, this->type); + break; + } + + if (failed) + { + DBG1(DBG_ENC, "invalid attribute length %d for %N", + this->length_or_value, configuration_attribute_type_names, this->type); + return FAILED; + } + return SUCCESS; +} + +METHOD(payload_t, get_encoding_rules, void, + private_data_attribute_v1_t *this, encoding_rule_t **rules, + size_t *rule_count) +{ + *rules = data_attribute_v1_encodings; + *rule_count = countof(data_attribute_v1_encodings); +} + +METHOD(payload_t, get_header_length, int, + private_data_attribute_v1_t *this) +{ + return 4; +} + +METHOD(payload_t, get_type, payload_type_t, + private_data_attribute_v1_t *this) +{ + return DATA_ATTRIBUTE_V1; +} + +METHOD(payload_t, get_next_type, payload_type_t, + private_data_attribute_v1_t *this) +{ + return NO_PAYLOAD; +} + +METHOD(payload_t, set_next_type, void, + private_data_attribute_v1_t *this, payload_type_t type) +{ +} + +METHOD(payload_t, get_length, size_t, + private_data_attribute_v1_t *this) +{ + return get_header_length(this) + this->value.len; +} + +METHOD(data_attribute_v1_t, get_dattr_type, configuration_attribute_type_t, + private_data_attribute_v1_t *this) +{ + return this->type; +} + +METHOD(data_attribute_v1_t, get_value, u_int16_t, + private_data_attribute_v1_t *this) +{ + return this->length_or_value; +} + +METHOD(data_attribute_v1_t, get_value_chunk, chunk_t, + private_data_attribute_v1_t *this) +{ + return this->value; +} + +METHOD2(payload_t, data_attribute_v1_t, destroy, void, + private_data_attribute_v1_t *this) +{ + free(this->value.ptr); + free(this); +} + +/* + * Described in header. + */ +data_attribute_v1_t *data_attribute_v1_create() +{ + private_data_attribute_v1_t *this; + + INIT(this, + .public = { + .payload_interface = { + .verify = _verify, + .get_encoding_rules = _get_encoding_rules, + .get_length = _get_length, + .get_next_type = _get_next_type, + .set_next_type = _set_next_type, + .get_type = _get_type, + .destroy = _destroy, + }, + .get_value_chunk = _get_value_chunk, + .get_type = _get_dattr_type, + .destroy = _destroy, + }, + ); + return &this->public; +} + +/* + * Described in header. + */ +data_attribute_v1_t *data_attribute_v1_create_value( + configuration_attribute_type_t type, chunk_t value) +{ + private_data_attribute_v1_t *this; + + this = (private_data_attribute_v1_t*)data_attribute_v1_create(); + this->type = ((u_int16_t)type) & 0x7FFF; + this->value = chunk_clone(value); + this->length_or_value = value.len; + this->af_flag = FALSE; + + return &this->public; +} + +/* + * Described in header. + */ +data_attribute_v1_t *data_attribute_v1_create_basic( + configuration_attribute_type_t type, u_int16_t value) +{ + private_data_attribute_v1_t *this; + + this = (private_data_attribute_v1_t*)data_attribute_v1_create(); + this->type = ((u_int16_t)type) & 0x7FFF; + this->length_or_value = value; + this->af_flag = TRUE; + + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/data_attribute_v1.h b/src/libcharon/encoding/payloads/data_attribute_v1.h new file mode 100644 index 000000000..568b3143a --- /dev/null +++ b/src/libcharon/encoding/payloads/data_attribute_v1.h @@ -0,0 +1,88 @@ + +/** + * @defgroup data_attribute_v1 data_attribute_v1 + * @{ @ingroup payloads + */ + +#ifndef DATA_ATTRIBUTE_V1_H_ +#define DATA_ATTRIBUTE_V1_H_ + +typedef struct data_attribute_v1_t data_attribute_v1_t; + +#include +#include +#include + +/** + * Configuration attribute header length in bytes. + */ +#define DATA_ATTRIBUTE_V1_HEADER_LENGTH 4 + +/** + * Class representing an IKEv1-Data Attribute. + * + * The DATA_ATTRIBUTE_V1 format is described in RFC section 3.15.1. + */ +struct data_attribute_v1_t { + + /** + * Implements payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the type of the attribute. + * + * @return type of the data attribute + */ + configuration_attribute_type_t (*get_type)(data_attribute_v1_t *this); + + /** + * Returns the value of the attribute. + * + * @return the basic internal value + */ + u_int16_t (*get_value) (data_attribute_v1_t *this); + + /** + * Returns the value of the attribute. + * + * @return chunk_t pointing to the internal value + */ + chunk_t (*get_value_chunk) (data_attribute_v1_t *this); + + /** + * Destroys an configuration_attribute_t object. + */ + void (*destroy) (data_attribute_v1_t *this); +}; + +/** + * Creates an empty data attribute. + * + * @return created data attribute + */ +data_attribute_v1_t *data_attribute_v1_create(); + +/** + * Creates a data attribute with type and value. + * + * @param type type of data attribute + * @param value value, gets cloned + * @return created data attribute + */ +data_attribute_v1_t *data_attribute_v1_create_value( + configuration_attribute_type_t type, chunk_t value); + + +/** + * Creates a data attribute with type and value. + * + * @param type type of data attribute + * @param value value + * @return created data attribute + */ +data_attribute_v1_t *data_attribute_v1_create_basic( + configuration_attribute_type_t type, u_int16_t value); + +#endif /** DATA_ATTRIBUTE_V1_H_ @}*/ From 79e9f776dc37caf5512fc4816cd7a01159042f96 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Wed, 23 Nov 2011 08:40:18 +0100 Subject: [PATCH 110/534] Updates ike_cert_post task with modifications needed for dealing with updated cert_payload class. --- src/libcharon/sa/tasks/ike_cert_post.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/tasks/ike_cert_post.c b/src/libcharon/sa/tasks/ike_cert_post.c index f2986dc50..ba5d76baa 100644 --- a/src/libcharon/sa/tasks/ike_cert_post.c +++ b/src/libcharon/sa/tasks/ike_cert_post.c @@ -62,14 +62,14 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL)) { - return cert_payload_create_from_cert(cert); + return cert_payload_create_from_cert(cert, CERTIFICATE); } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!hasher) { DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported"); - return cert_payload_create_from_cert(cert); + return cert_payload_create_from_cert(cert, CERTIFICATE); } if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded)) @@ -86,12 +86,12 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr, CERT_X509, id); if (enumerator->enumerate(enumerator, &url)) { - payload = cert_payload_create_from_hash_and_url(hash, url); + payload = cert_payload_create_from_hash_and_url(hash, url, CERTIFICATE); DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url); } else { - payload = cert_payload_create_from_cert(cert); + payload = cert_payload_create_from_cert(cert, CERTIFICATE); } enumerator->destroy(enumerator); chunk_free(&hash); @@ -154,7 +154,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) { if (type == AUTH_RULE_IM_CERT) { - payload = cert_payload_create_from_cert(cert); + payload = cert_payload_create_from_cert(cert, CERTIFICATE); if (payload) { DBG1(DBG_IKE, "sending issuer cert \"%Y\"", From 23f4e4b42d10a914f5a480d938282916aa6c124e Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Wed, 23 Nov 2011 08:55:59 +0100 Subject: [PATCH 111/534] IKEv1 XAUTH: Added ability to configure XAUTH+PSK. Added task to handle XAUTH requests. Modified task_manager_v1 to enable it to initiate new tasks immediately after finishing a response. --- src/libcharon/Makefile.am | 3 +- src/libcharon/plugins/stroke/stroke_config.c | 4 + src/libcharon/sa/ike_sa.c | 10 + src/libcharon/sa/ike_sa.h | 10 + src/libcharon/sa/task_manager_v1.c | 61 +++++- src/libcharon/sa/tasks/ike_vendor.c | 28 +++ src/libcharon/sa/tasks/task.h | 2 + src/libcharon/sa/tasks/xauth_request.c | 185 +++++++++++++++++++ src/libcharon/sa/tasks/xauth_request.h | 37 ++++ src/libstrongswan/credentials/auth_cfg.h | 2 + 10 files changed, 335 insertions(+), 7 deletions(-) create mode 100644 src/libcharon/sa/tasks/xauth_request.c create mode 100644 src/libcharon/sa/tasks/xauth_request.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index d76ba491c..2bead3beb 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -93,7 +93,8 @@ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ -sa/tasks/task.c sa/tasks/task.h +sa/tasks/task.c sa/tasks/task.h \ +sa/tasks/xauth_request.c sa/tasks/xauth_request.h daemon.lo : $(top_builddir)/config.status diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 4a49704ef..97d2a7836 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -469,6 +469,10 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, { cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); } + else if (streq(auth, "xauthpsk")) + { + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH_PSK); + } else if (strneq(auth, "eap", 3)) { enumerator_t *enumerator; diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index d2dffea8b..0da289ada 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -2128,6 +2129,15 @@ METHOD(ike_sa_t, destroy, void, free(this); } +METHOD(ike_sa_t, initiate_xauth, void, + private_ike_sa_t *this) +{ + xauth_request_t *xauth_request_task = xauth_request_create(this, TRUE); + this->task_manager->queue_task(this->task_manager, (task_t*)xauth_request_task); + + this->task_manager->initiate_later(this->task_manager); +} + /* * Described in header. */ diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 2708b0be6..ecfb04e02 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -102,6 +102,11 @@ enum ike_extension_t { * peer is probably a Windows 7 RAS client */ EXT_MS_WINDOWS = (1<<6), + + /** + * peer supports XAuth authentication, draft-ietf-ipsec-isakmp-xauth-06 + */ + EXT_XAUTH = (1<<7), }; /** @@ -953,6 +958,11 @@ struct ike_sa_t { * Destroys a ike_sa_t object. */ void (*destroy) (ike_sa_t *this); + + /** + * Initiate XAUTH authentication + */ + status_t (*initiate_xauth)(ike_sa_t *this); }; /** diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 1764a8036..fbc8da7cc 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -131,6 +131,13 @@ struct private_task_manager_t { * Base to calculate retransmission timeout */ double retransmit_base; + + /** + * Flag to tell the task manager to initiate a transaction at + * a later time. + */ + bool initiate_later_flag; + }; /** @@ -149,12 +156,6 @@ static void flush(private_task_manager_t *this) this->active_tasks = linked_list_create(); } -METHOD(task_manager_t, retransmit, status_t, - private_task_manager_t *this, u_int32_t message_id) -{ - return FAILED; -} - /** * move a task of a specific type from the queue to the active list */ @@ -180,6 +181,49 @@ static bool activate_task(private_task_manager_t *this, task_type_t type) return found; } +METHOD(task_manager_t, retransmit, status_t, + private_task_manager_t *this, u_int32_t message_id) +{ + if (message_id == this->initiating.mid) + { + u_int32_t timeout; + job_t *job; + enumerator_t *enumerator; + packet_t *packet; + task_t *task; + + if (this->initiating.retransmitted <= this->retransmit_tries) + { + timeout = (u_int32_t)(this->retransmit_timeout * 1000.0 * + pow(this->retransmit_base, this->initiating.retransmitted)); + } + else + { + DBG1(DBG_IKE, "giving up after %d retransmits", + this->initiating.retransmitted - 1); + if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) + { + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + } + return DESTROY_ME; + } + + if (this->initiating.retransmitted) + { + DBG1(DBG_IKE, "retransmit %d of request with message ID %d", + this->initiating.retransmitted, message_id); + } + packet = this->initiating.packet->clone(this->initiating.packet); + charon->sender->send(charon->sender, packet); + + this->initiating.retransmitted++; + job = (job_t*)retransmit_job_create(this->initiating.mid, + this->ike_sa->get_id(this->ike_sa)); + lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout); + } + return SUCCESS; +} + METHOD(task_manager_t, initiate, status_t, private_task_manager_t *this) { @@ -220,6 +264,11 @@ METHOD(task_manager_t, initiate, status_t, { exchange = QUICK_MODE; } + + if (activate_task(this, TASK_XAUTH_REQUEST)) + { + exchange = TRANSACTION; + } break; default: break; diff --git a/src/libcharon/sa/tasks/ike_vendor.c b/src/libcharon/sa/tasks/ike_vendor.c index 7b3cc6e91..b8fe9fe91 100644 --- a/src/libcharon/sa/tasks/ike_vendor.c +++ b/src/libcharon/sa/tasks/ike_vendor.c @@ -49,6 +49,10 @@ static chunk_t strongswan_vid = chunk_from_chars( 0x22,0x51,0x61,0x3b,0x2e,0xbe,0x5b,0xeb ); +static chunk_t xauth6_vid = chunk_from_chars( + 0x09,0x00,0x26,0x89,0xdf,0xd6,0xb7,0x12 +); + METHOD(task_t, build, status_t, private_ike_vendor_t *this, message_t *message) { @@ -60,6 +64,11 @@ METHOD(task_t, build, status_t, vid = vendor_id_payload_create_data(VENDOR_ID, chunk_clone(strongswan_vid)); message->add_payload(message, &vid->payload_interface); + + vid = vendor_id_payload_create_data(VENDOR_ID, + chunk_clone(xauth6_vid)); + message->add_payload(message, &vid->payload_interface); + } return this->initiator ? NEED_MORE : SUCCESS; @@ -92,6 +101,25 @@ METHOD(task_t, process, status_t, DBG1(DBG_ENC, "received unknown vendor id: %#B", &data); } } + + if (payload->get_type(payload) == VENDOR_ID_V1) + { + vendor_id_payload_t *vid; + chunk_t data; + + vid = (vendor_id_payload_t*)payload; + data = vid->get_data(vid); + + if (chunk_equals(data, xauth6_vid)) + { + DBG1(DBG_IKE, "received XAuth vendor id"); + this->ike_sa->enable_extension(this->ike_sa, EXT_XAUTH); + } + else + { + DBG1(DBG_ENC, "received unknown vendor id: %#B", &data); + } + } } enumerator->destroy(enumerator); diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 8a8143967..ad41bae7f 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -73,6 +73,8 @@ enum task_type_t { TASK_MAIN_MODE, /** IKEv1 quick mode */ TASK_QUICK_MODE, + /** Request the user/pass with XAUTH */ + TASK_XAUTH_REQUEST, }; /** diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c new file mode 100644 index 000000000..a50d0fb43 --- /dev/null +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -0,0 +1,185 @@ + +#include "xauth_request.h" + +#include +#include +#include +#include +#include +#include + +typedef struct private_xauth_request_t private_xauth_request_t; + +/** + * Private members of a xauth_request_t task. + */ +struct private_xauth_request_t { + + /** + * Public methods and task_t interface. + */ + xauth_request_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * virtual ip + */ + host_t *virtual_ip; + + /** + * list of attributes requested and its handler, entry_t + */ + linked_list_t *requested; +}; + +/** + * Entry for a requested attribute and the requesting handler + */ +typedef struct { + /** attribute requested */ + configuration_attribute_type_t type; + /** handler requesting this attribute */ + attribute_handler_t *handler; +} entry_t; + +/** + * Scan for configuration payloads and attributes + */ +static void process_payloads(private_xauth_request_t *this, message_t *message) +{ +} + +METHOD(task_t, build_i, status_t, + private_xauth_request_t *this, message_t *message) +{ + attribute_payload_v1_t *ap = NULL; + chunk_t chunk = chunk_empty; + data_attribute_v1_t *da = NULL; + hash_payload_t *hash_payload = NULL; + generator_t *generator; + chunk_t attr_chunk; + chunk_t mid_chunk; + u_int32_t *lenpos; + u_int32_t message_id; + keymat_t *keymat; + prf_t *prf; + chunk_t hash_in, hash_out; + + DBG1(DBG_IKE, "BUILDING XAUTH REQUEST PACKET"); + /* TODO1: Create ATTR payload */ + ap = attribute_payload_v1_create(); + + da = data_attribute_v1_create_value(XAUTH_USER_NAME, chunk); + ap->add_attribute(ap, da); + + da = data_attribute_v1_create_value(XAUTH_USER_PASSWORD, chunk); + ap->add_attribute(ap, da); + + /* Create HASH payload */ + hash_payload = hash_payload_create(); + /* TODO1: Add data into the hash */ + + /* Calculate the chunk for the ATTR payload */ + generator = generator_create(); + ap->payload_interface.set_next_type(&ap->payload_interface, NO_PAYLOAD); + generator->generate_payload(generator, (payload_t *)ap); + attr_chunk = generator->get_chunk(generator, &lenpos); + + /* Get the message ID in network order */ + htoun32(&message_id, message->get_message_id(message)); + mid_chunk = chunk_from_thing(message_id); + + /* Get the hashed data */ + hash_in = chunk_cat("cc", mid_chunk, attr_chunk); + + message->add_payload(message, (payload_t *)hash_payload); + message->add_payload(message, (payload_t *)ap); + + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_xauth_request_t *this, message_t *message) +{ + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_xauth_request_t *this, message_t *message) +{ + return NEED_MORE; +} + +METHOD(task_t, process_i, status_t, + private_xauth_request_t *this, message_t *message) +{ + return NEED_MORE; +} + +METHOD(task_t, get_type, task_type_t, + private_xauth_request_t *this) +{ + return TASK_XAUTH_REQUEST; +} + +METHOD(task_t, migrate, void, + private_xauth_request_t *this, ike_sa_t *ike_sa) +{ + DESTROY_IF(this->virtual_ip); + + this->ike_sa = ike_sa; + this->virtual_ip = NULL; + this->requested->destroy_function(this->requested, free); + this->requested = linked_list_create(); +} + +METHOD(task_t, destroy, void, + private_xauth_request_t *this) +{ + DESTROY_IF(this->virtual_ip); + this->requested->destroy_function(this->requested, free); + free(this); +} + +/* + * Described in header. + */ +xauth_request_t *xauth_request_create(ike_sa_t *ike_sa, bool initiator) +{ + private_xauth_request_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + .requested = linked_list_create(), + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/tasks/xauth_request.h b/src/libcharon/sa/tasks/xauth_request.h new file mode 100644 index 000000000..6324ca0de --- /dev/null +++ b/src/libcharon/sa/tasks/xauth_request.h @@ -0,0 +1,37 @@ + +/** + * @defgroup xauth_request xauth_request + * @{ @ingroup tasks + */ + +#ifndef XAUTH_REQUEST_H_ +#define XAUTH_REQUEST_H_ + +typedef struct xauth_request_t xauth_request_t; + +#include +#include +#include + +/** + * Task of type XAUTH_REQUEST, gets the username and password from the ISAKMP_SA + * initializer. + */ +struct xauth_request_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new xauth_request task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE for initiator + * @return ike_config task to handle by the task_manager + */ +xauth_request_t *xauth_request_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** XAUTH_REQUEST_H_ @}*/ diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index 7e747c37d..2554b3f2e 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -42,6 +42,8 @@ enum auth_class_t { AUTH_CLASS_PSK = 2, /** authentication using EAP */ AUTH_CLASS_EAP = 3, + /** authentication using pre-shared secrets in combination with XAuth */ + AUTH_CLASS_XAUTH_PSK = 4, }; /** From df99e976be113cb55d7d38061e546bc8f0377c95 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Wed, 23 Nov 2011 10:15:52 +0100 Subject: [PATCH 112/534] Temp fix for compile error with XAUTH code. --- src/libcharon/sa/ike_sa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 0da289ada..05622a316 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -2135,7 +2135,7 @@ METHOD(ike_sa_t, initiate_xauth, void, xauth_request_t *xauth_request_task = xauth_request_create(this, TRUE); this->task_manager->queue_task(this->task_manager, (task_t*)xauth_request_task); - this->task_manager->initiate_later(this->task_manager); +// this->task_manager->initiate_later(this->task_manager); } /* From 017d98bf39e3824829cf17be1723b460a2ddeb4e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 11:26:04 +0100 Subject: [PATCH 113/534] Merged IKEv1 attribute payload/data into configuration payload/attribute --- src/libcharon/Makefile.am | 2 - src/libcharon/encoding/message.c | 10 +- .../encoding/payloads/attribute_payload_v1.c | 231 ---------------- .../encoding/payloads/attribute_payload_v1.h | 93 ------- .../payloads/configuration_attribute.c | 146 +++++++--- .../payloads/configuration_attribute.h | 39 ++- src/libcharon/encoding/payloads/cp_payload.c | 84 +++++- src/libcharon/encoding/payloads/cp_payload.h | 16 +- .../encoding/payloads/data_attribute_v1.c | 260 ------------------ .../encoding/payloads/data_attribute_v1.h | 88 ------ src/libcharon/encoding/payloads/payload.c | 56 ++-- src/libcharon/encoding/payloads/payload.h | 17 +- src/libcharon/sa/tasks/ike_config.c | 23 +- src/libcharon/sa/tasks/xauth_request.c | 26 +- 14 files changed, 275 insertions(+), 816 deletions(-) delete mode 100644 src/libcharon/encoding/payloads/attribute_payload_v1.c delete mode 100644 src/libcharon/encoding/payloads/attribute_payload_v1.h delete mode 100644 src/libcharon/encoding/payloads/data_attribute_v1.c delete mode 100644 src/libcharon/encoding/payloads/data_attribute_v1.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 2bead3beb..a813e97f1 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -15,13 +15,11 @@ daemon.c daemon.h \ encoding/generator.c encoding/generator.h \ encoding/message.c encoding/message.h \ encoding/parser.c encoding/parser.h \ -encoding/payloads/attribute_payload_v1.c encoding/payloads/attribute_payload_v1.h \ encoding/payloads/auth_payload.c encoding/payloads/auth_payload.h \ encoding/payloads/cert_payload.c encoding/payloads/cert_payload.h \ encoding/payloads/certreq_payload.c encoding/payloads/certreq_payload.h \ encoding/payloads/configuration_attribute.c encoding/payloads/configuration_attribute.h \ encoding/payloads/cp_payload.c encoding/payloads/cp_payload.h \ -encoding/payloads/data_attribute_v1.c encoding/payloads/data_attribute_v1.h \ encoding/payloads/delete_payload.c encoding/payloads/delete_payload.h \ encoding/payloads/eap_payload.c encoding/payloads/eap_payload.h \ encoding/payloads/encodings.c encoding/payloads/encodings.h \ diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index e84f9a123..032fc1b1c 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -635,9 +635,9 @@ static payload_order_t quick_mode_r_order[] = { * Message rule for TRANSACTION. */ static payload_rule_t transaction_payload_rules_v1[] = { -/* payload type min max encr suff */ - {HASH_V1, 0, 1, TRUE, FALSE}, - {ATTRIBUTE_V1, 1, 1, FALSE, FALSE}, +/* payload type min max encr suff */ + {HASH_V1, 0, 1, TRUE, FALSE}, + {CONFIGURATION_V1, 1, 1, FALSE, FALSE}, }; /** @@ -645,8 +645,8 @@ static payload_rule_t transaction_payload_rules_v1[] = { */ static payload_order_t transaction_payload_order_v1[] = { /* payload type notify type */ - {HASH_V1, 0}, - {ATTRIBUTE_V1, 0}, + {HASH_V1, 0}, + {CONFIGURATION_V1, 0}, }; #endif /* USE_IKEV1 */ diff --git a/src/libcharon/encoding/payloads/attribute_payload_v1.c b/src/libcharon/encoding/payloads/attribute_payload_v1.c deleted file mode 100644 index 3aa0bc3a1..000000000 --- a/src/libcharon/encoding/payloads/attribute_payload_v1.c +++ /dev/null @@ -1,231 +0,0 @@ - -#include - -#include "attribute_payload_v1.h" - -#include -#include - -ENUM(config_type_v1_names, ISAKMP_CFG_REQUEST, ISAKMP_CFG_ACK, - "ISAKMP_CFG_REQUEST", - "ISAKMP_CFG_REPLY", - "ISAKMP_CFG_SET", - "ISAKMP_CFG_ACK", -); - -typedef struct private_attribute_payload_v1_t private_attribute_payload_v1_t; - -/** - * Private data of an attribute_payload_v1_t object. - */ -struct private_attribute_payload_v1_t { - - /** - * Public cp_payload_t interface. - */ - attribute_payload_v1_t public; - - /** - * Next payload type. - */ - u_int8_t next_payload; - - /** - * Length of this payload. - */ - u_int16_t payload_length; - - /** - * List of attributes, as configuration_attribute_t - */ - linked_list_t *attributes; - - /** - * Reserved bytes - */ - u_int8_t reserved_byte[2]; - - /** - * Identifier - */ - u_int16_t identifier; - - /** - * Config Type. - */ - u_int8_t type; -}; - -/** - * Encoding rules to parse or generate a IKEv2-CP Payload - * - * The defined offsets are the positions in a object of type - * private_attribute_payload_v1_t. - */ -encoding_rule_t attribute_payload_v1_encodings[] = { - /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_attribute_payload_v1_t, next_payload) }, - /* reserved byte */ - { RESERVED_BYTE, offsetof(private_attribute_payload_v1_t, reserved_byte[0]) }, - /* Length of the whole Attribute payload*/ - { PAYLOAD_LENGTH, offsetof(private_attribute_payload_v1_t, payload_length) }, - /* Config type */ - { U_INT_8, offsetof(private_attribute_payload_v1_t, type) }, - /* 3 reserved bytes */ - { RESERVED_BYTE, offsetof(private_attribute_payload_v1_t, reserved_byte[1])}, - - /* Identifier */ - { U_INT_16, offsetof(private_attribute_payload_v1_t, identifier)}, - - /* List of configuration attributes */ - { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE, offsetof(private_attribute_payload_v1_t, attributes) } -}; - -/* - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! Next Payload ! RESERVED ! Payload Length ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! CFG Type ! RESERVED ! Identifier ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ! ! - ~ Configuration Attributes ~ - ! ! - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ - -METHOD(payload_t, verify, status_t, - private_attribute_payload_v1_t *this) -{ - status_t status = SUCCESS; - enumerator_t *enumerator; - payload_t *attribute; - - enumerator = this->attributes->create_enumerator(this->attributes); - while (enumerator->enumerate(enumerator, &attribute)) - { - status = attribute->verify(attribute); - if (status != SUCCESS) - { - break; - } - } - enumerator->destroy(enumerator); - return status; -} - -METHOD(payload_t, get_encoding_rules, void, - private_attribute_payload_v1_t *this, encoding_rule_t **rules, size_t *rule_count) -{ - *rules = attribute_payload_v1_encodings; - *rule_count = countof(attribute_payload_v1_encodings); -} - -METHOD(payload_t, get_type, payload_type_t, - private_attribute_payload_v1_t *this) -{ - return ATTRIBUTE_V1; -} - -METHOD(payload_t, get_next_type, payload_type_t, - private_attribute_payload_v1_t *this) -{ - return this->next_payload; -} - -METHOD(payload_t, set_next_type, void, - private_attribute_payload_v1_t *this,payload_type_t type) -{ - this->next_payload = type; -} - -/** - * recompute the length of the payload. - */ -static void compute_length(private_attribute_payload_v1_t *this) -{ - enumerator_t *enumerator; - payload_t *attribute; - - this->payload_length = ATTRIBUTE_PAYLOAD_V1_HEADER_LENGTH; - - enumerator = this->attributes->create_enumerator(this->attributes); - while (enumerator->enumerate(enumerator, &attribute)) - { - this->payload_length += attribute->get_length(attribute); - } - enumerator->destroy(enumerator); -} - -METHOD(payload_t, get_length, size_t, - private_attribute_payload_v1_t *this) -{ - return this->payload_length; -} - -METHOD(attribute_payload_v1_t, create_attribute_enumerator, enumerator_t*, - private_attribute_payload_v1_t *this) -{ - return this->attributes->create_enumerator(this->attributes); -} - -METHOD(attribute_payload_v1_t, add_attribute, void, - private_attribute_payload_v1_t *this, data_attribute_v1_t *attribute) -{ - this->attributes->insert_last(this->attributes, attribute); - compute_length(this); -} - -METHOD(attribute_payload_v1_t, get_config_type, config_type_v1_t, - private_attribute_payload_v1_t *this) -{ - return this->type; -} - -METHOD2(payload_t, attribute_payload_v1_t, destroy, void, - private_attribute_payload_v1_t *this) -{ - this->attributes->destroy_offset(this->attributes, - offsetof(data_attribute_v1_t, destroy)); - free(this); -} - -/* - * Described in header. - */ -attribute_payload_v1_t *attribute_payload_v1_create_type(config_type_v1_t type) -{ - private_attribute_payload_v1_t *this; - - INIT(this, - .public = { - .payload_interface = { - .verify = _verify, - .get_encoding_rules = _get_encoding_rules, - .get_length = _get_length, - .get_next_type = _get_next_type, - .set_next_type = _set_next_type, - .get_type = _get_type, - .destroy = _destroy, - }, - .create_attribute_enumerator = _create_attribute_enumerator, - .add_attribute = _add_attribute, - .get_type = _get_config_type, - .destroy = _destroy, - }, - .next_payload = NO_PAYLOAD, - .payload_length = ATTRIBUTE_PAYLOAD_V1_HEADER_LENGTH, - .attributes = linked_list_create(), - .type = type, - ); - return &this->public; -} - -/* - * Described in header. - */ -attribute_payload_v1_t *attribute_payload_v1_create() -{ - return attribute_payload_v1_create_type(ISAKMP_CFG_REQUEST); -} diff --git a/src/libcharon/encoding/payloads/attribute_payload_v1.h b/src/libcharon/encoding/payloads/attribute_payload_v1.h deleted file mode 100644 index d59d9981e..000000000 --- a/src/libcharon/encoding/payloads/attribute_payload_v1.h +++ /dev/null @@ -1,93 +0,0 @@ - -/** - * @defgroup attribute_payload_v1 attribute_payload_v1 - * @{ @ingroup payloads - */ - -#ifndef ATTRIBUTE_PAYLOAD_V1_H_ -#define ATTRIBUTE_PAYLOAD_V1_H_ - -typedef enum config_type_v1_t config_type_v1_t; -typedef struct attribute_payload_v1_t attribute_payload_v1_t; - -#include -#include -#include -#include - -/** - * ATTRIBUTE_PAYLOAD_V1 length in bytes without any proposal substructure. - */ -#define ATTRIBUTE_PAYLOAD_V1_HEADER_LENGTH 8 - -/** - * Config Type of an Attribute Payload. - */ -enum config_type_v1_t { - ISAKMP_CFG_REQUEST = 1, - ISAKMP_CFG_REPLY = 2, - ISAKMP_CFG_SET = 3, - ISAKMP_CFG_ACK = 4, -}; - -/** - * enum name for config_type_v1_t. - */ -extern enum_name_t *config_type_v1_names; - -/** - * Class representing an ISAKMP Config Mode Attribute Payload. - * - * The Attribute Payload format is described in draft-ietf-ipsec-isakmp-mode-cfg-o5.txt section 3.2. - */ -struct attribute_payload_v1_t { - - /** - * The payload_t interface. - */ - payload_t payload_interface; - - /** - * Creates an enumerator of stored data_attribute_v1_t objects. - * - * @return enumerator over configration_attribute_t - */ - enumerator_t *(*create_attribute_enumerator) (attribute_payload_v1_t *this); - - /** - * Adds a configuration attribute to the attribute payload. - * - * @param attribute attribute to add - */ - void (*add_attribute)(attribute_payload_v1_t *this, - data_attribute_v1_t *attribute); - - /** - * Get the attribute payload type. - * - * @return type of attribute payload - */ - config_type_v1_t (*get_type) (attribute_payload_v1_t *this); - - /** - * Destroys an attribute_payload_v1_t object. - */ - void (*destroy) (attribute_payload_v1_t *this); -}; - -/** - * Creates an empty attribute payload - * - * @return empty attribute payload - */ -attribute_payload_v1_t *attribute_payload_v1_create(); - -/** - * Creates an attribute_payload_v1_t with type and value - * - * @param config_type type of attribute payload to create - * @return created attribute payload - */ -attribute_payload_v1_t *attribute_payload_v1_create_type(config_type_v1_t config_type); - -#endif /** ATTRIBUTE_PAYLOAD_V1_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index 88e43fa3d..58173077d 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -36,41 +36,48 @@ struct private_configuration_attribute_t { configuration_attribute_t public; /** - * Reserved bit + * Value encoded in length field? + */ + bool af_flag; + + /** + * Reserved bit (af_flag in IKEv2) */ bool reserved; /** * Type of the attribute. */ - u_int16_t type; + u_int16_t attr_type; /** - * Length of the attribute. + * Length of the attribute, value if af_flag set. */ - u_int16_t length; + u_int16_t length_or_value; /** * Attribute value as chunk. */ chunk_t value; + + /** + * Payload type, CONFIGURATION_ATTRIBUTE or DATA_ATTRIBUTE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a configuration attribute. - * - * The defined offsets are the positions in a object of type - * private_configuration_attribute_t. + * Encoding rules for a IKEv2 configuration attribute / IKEv1 data attribute */ -static encoding_rule_t encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 reserved bit */ - { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved)}, + { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved) }, /* type of the attribute as 15 bit unsigned integer */ - { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, type) }, + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, /* Length of attribute value */ - { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length) }, + { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length_or_value)}, /* Value of attribute if attribute format flag is zero */ - { CHUNK_DATA, offsetof(private_configuration_attribute_t, value) } + { CHUNK_DATA, offsetof(private_configuration_attribute_t, value) }, }; /* @@ -85,18 +92,39 @@ static encoding_rule_t encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for a IKEv1 data attribute + */ +static encoding_rule_t encodings_v1[] = { + /* AF Flag */ + { FLAG, offsetof(private_configuration_attribute_t, af_flag) }, + /* type of the attribute as 15 bit unsigned integer */ + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, type) }, + /* Length of attribute value */ + { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_configuration_attribute_t, length_or_value)}, + /* Value of attribute if attribute format flag is zero */ + { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + !F| Attribute Type ! Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + ~ Value ~ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + METHOD(payload_t, verify, status_t, private_configuration_attribute_t *this) { bool failed = FALSE; - if (this->length != this->value.len) - { - DBG1(DBG_ENC, "invalid attribute length"); - return FAILED; - } - - switch (this->type) + switch (this->attr_type) { case INTERNAL_IP4_ADDRESS: case INTERNAL_IP4_NETMASK: @@ -104,20 +132,20 @@ METHOD(payload_t, verify, status_t, case INTERNAL_IP4_NBNS: case INTERNAL_ADDRESS_EXPIRY: case INTERNAL_IP4_DHCP: - if (this->length != 0 && this->length != 4) + if (this->length_or_value != 0 && this->length_or_value != 4) { failed = TRUE; } break; case INTERNAL_IP4_SUBNET: - if (this->length != 0 && this->length != 8) + if (this->length_or_value != 0 && this->length_or_value != 8) { failed = TRUE; } break; case INTERNAL_IP6_ADDRESS: case INTERNAL_IP6_SUBNET: - if (this->length != 0 && this->length != 17) + if (this->length_or_value != 0 && this->length_or_value != 17) { failed = TRUE; } @@ -125,13 +153,13 @@ METHOD(payload_t, verify, status_t, case INTERNAL_IP6_DNS: case INTERNAL_IP6_NBNS: case INTERNAL_IP6_DHCP: - if (this->length != 0 && this->length != 16) + if (this->length_or_value != 0 && this->length_or_value != 16) { failed = TRUE; } break; case SUPPORTED_ATTRIBUTES: - if (this->length % 2) + if (this->length_or_value % 2) { failed = TRUE; } @@ -141,14 +169,15 @@ METHOD(payload_t, verify, status_t, break; default: DBG1(DBG_ENC, "unknown attribute type %N", - configuration_attribute_type_names, this->type); + configuration_attribute_type_names, this->attr_type); break; } if (failed) { DBG1(DBG_ENC, "invalid attribute length %d for %N", - this->length, configuration_attribute_type_names, this->type); + this->length_or_value, configuration_attribute_type_names, + this->attr_type); return FAILED; } return SUCCESS; @@ -157,8 +186,13 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, int, private_configuration_attribute_t *this, encoding_rule_t **rules) { - *rules = encodings; - return countof(encodings); + if (this->type == CONFIGURATION_ATTRIBUTE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); } METHOD(payload_t, get_header_length, int, @@ -170,7 +204,7 @@ METHOD(payload_t, get_header_length, int, METHOD(payload_t, get_type, payload_type_t, private_configuration_attribute_t *this) { - return CONFIGURATION_ATTRIBUTE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -193,15 +227,29 @@ METHOD(payload_t, get_length, size_t, METHOD(configuration_attribute_t, get_cattr_type, configuration_attribute_type_t, private_configuration_attribute_t *this) { - return this->type; + return this->attr_type; } -METHOD(configuration_attribute_t, get_value, chunk_t, +METHOD(configuration_attribute_t, get_chunk, chunk_t, private_configuration_attribute_t *this) { + if (this->af_flag) + { + return chunk_from_thing(this->length_or_value); + } return this->value; } +METHOD(configuration_attribute_t, get_value, u_int16_t, + private_configuration_attribute_t *this) +{ + if (this->af_flag) + { + return this->length_or_value; + } + return 0; +} + METHOD2(payload_t, configuration_attribute_t, destroy, void, private_configuration_attribute_t *this) { @@ -212,7 +260,7 @@ METHOD2(payload_t, configuration_attribute_t, destroy, void, /* * Described in header. */ -configuration_attribute_t *configuration_attribute_create() +configuration_attribute_t *configuration_attribute_create(payload_type_t type) { private_configuration_attribute_t *this; @@ -228,10 +276,12 @@ configuration_attribute_t *configuration_attribute_create() .get_type = _get_type, .destroy = _destroy, }, + .get_chunk = _get_chunk, .get_value = _get_value, .get_type = _get_cattr_type, .destroy = _destroy, }, + .type = type ); return &this->public; } @@ -239,15 +289,33 @@ configuration_attribute_t *configuration_attribute_create() /* * Described in header. */ -configuration_attribute_t *configuration_attribute_create_value( - configuration_attribute_type_t type, chunk_t value) +configuration_attribute_t *configuration_attribute_create_chunk( + payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk) { private_configuration_attribute_t *this; - this = (private_configuration_attribute_t*)configuration_attribute_create(); - this->type = ((u_int16_t)type) & 0x7FFF; - this->value = chunk_clone(value); - this->length = value.len; + this = (private_configuration_attribute_t*) + configuration_attribute_create(type); + this->attr_type = ((u_int16_t)attr_type) & 0x7FFF; + this->value = chunk_clone(chunk); + this->length_or_value = chunk.len; + + return &this->public; +} + +/* + * Described in header. + */ +configuration_attribute_t *configuration_attribute_create_value( + configuration_attribute_type_t attr_type, u_int16_t value) +{ + private_configuration_attribute_t *this; + + this = (private_configuration_attribute_t*) + configuration_attribute_create(CONFIGURATION_ATTRIBUTE_V1); + this->attr_type = ((u_int16_t)attr_type) & 0x7FFF; + this->length_or_value = value; + this->af_flag = TRUE; return &this->public; } diff --git a/src/libcharon/encoding/payloads/configuration_attribute.h b/src/libcharon/encoding/payloads/configuration_attribute.h index e216ee366..ecc0f9c07 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.h +++ b/src/libcharon/encoding/payloads/configuration_attribute.h @@ -29,9 +29,7 @@ typedef struct configuration_attribute_t configuration_attribute_t; #include /** - * Class representing an IKEv2-CONFIGURATION Attribute. - * - * The CONFIGURATION ATTRIBUTE format is described in RFC section 3.15.1. + * Class representing an IKEv2 configuration attribute / IKEv1 data attribute. */ struct configuration_attribute_t { @@ -48,11 +46,18 @@ struct configuration_attribute_t { configuration_attribute_type_t (*get_type)(configuration_attribute_t *this); /** - * Returns the value of the attribute. + * Returns the value of the attribute as chunk. * * @return chunk_t pointing to the internal value */ - chunk_t (*get_value) (configuration_attribute_t *this); + chunk_t (*get_chunk) (configuration_attribute_t *this); + + /** + * Returns the 2 byte value of the attribute as u_int16. + * + * @return attribute value + */ + u_int16_t (*get_value) (configuration_attribute_t *this); /** * Destroys an configuration_attribute_t object. @@ -63,18 +68,30 @@ struct configuration_attribute_t { /** * Creates an empty configuration attribute. * - * @return created configuration attribute + * @param type CONFIGURATION_ATTRIBUTE or CONFIGURATION_ATTRIBUTE_V1 + * @return created configuration attribute */ -configuration_attribute_t *configuration_attribute_create(); +configuration_attribute_t *configuration_attribute_create(payload_type_t type); /** * Creates a configuration attribute with type and value. * - * @param type type of configuration attribute - * @param value value, gets cloned - * @return created configuration attribute + * @param type CONFIGURATION_ATTRIBUTE or CONFIGURATION_ATTRIBUTE_V1 + * @param attr_type type of configuration attribute + * @param chunk attribute value, gets cloned + * @return created configuration attribute + */ +configuration_attribute_t *configuration_attribute_create_chunk( + payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk); + +/** + * Creates a IKEv1 configuration attribute with 2 bytes value (IKEv1 only). + * + * @param attr_type type of configuration attribute + * @param value attribute value, gets cloned + * @return created CONFIGURATION_ATTRIBUTE_V1 configuration attribute */ configuration_attribute_t *configuration_attribute_create_value( - configuration_attribute_type_t type, chunk_t value); + configuration_attribute_type_t attr_type, u_int16_t value); #endif /** CONFIGURATION_ATTRIBUTE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c index 1813c9790..9ecb15006 100644 --- a/src/libcharon/encoding/payloads/cp_payload.c +++ b/src/libcharon/encoding/payloads/cp_payload.c @@ -44,7 +44,7 @@ struct private_cp_payload_t { /** * Next payload type. */ - u_int8_t next_payload; + u_int8_t next_payload; /** * Critical flag. @@ -66,6 +66,11 @@ struct private_cp_payload_t { */ u_int16_t payload_length; + /** + * Identifier field, IKEv1 only + */ + u_int16_t identifier; + /** * List of attributes, as configuration_attribute_t */ @@ -74,16 +79,18 @@ struct private_cp_payload_t { /** * Config Type. */ - u_int8_t type; + u_int8_t cfg_type; + + /** + * CONFIGURATION or CONFIGURATION_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a IKEv2-CP Payload - * - * The defined offsets are the positions in a object of type - * private_cp_payload_t. + * Encoding rules to for an IKEv2 configuration payload */ -static encoding_rule_t encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, /* the critical bit */ @@ -98,7 +105,7 @@ static encoding_rule_t encodings[] = { { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, /* Length of the whole CP payload*/ { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, - { U_INT_8, offsetof(private_cp_payload_t, type) }, + { U_INT_8, offsetof(private_cp_payload_t, cfg_type) }, /* 3 reserved bytes */ { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[1])}, @@ -122,6 +129,47 @@ static encoding_rule_t encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules to for an IKEv1 configuration payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, + /* the critical bit */ + { FLAG, offsetof(private_cp_payload_t, critical) }, + /* 7 Bit reserved bits */ + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, + /* Length of the whole CP payload*/ + { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, + { U_INT_8, offsetof(private_cp_payload_t, cfg_type) }, + /* 1 reserved bytes */ + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, + { U_INT_16, offsetof(private_cp_payload_t, identifier)}, + /* list of configuration attributes in a list */ + { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE, + offsetof(private_cp_payload_t, attributes) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! CFG Type ! RESERVED ! Identifier ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Configuration Attributes ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_cp_payload_t *this) { @@ -145,8 +193,13 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, int, private_cp_payload_t *this, encoding_rule_t **rules) { - *rules = encodings; - return countof(encodings); + if (this->type == CONFIGURATION) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); } METHOD(payload_t, get_header_length, int, @@ -158,7 +211,7 @@ METHOD(payload_t, get_header_length, int, METHOD(payload_t, get_type, payload_type_t, private_cp_payload_t *this) { - return CONFIGURATION; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -213,7 +266,7 @@ METHOD(cp_payload_t, add_attribute, void, METHOD(cp_payload_t, get_config_type, config_type_t, private_cp_payload_t *this) { - return this->type; + return this->cfg_type; } METHOD2(payload_t, cp_payload_t, destroy, void, @@ -227,7 +280,7 @@ METHOD2(payload_t, cp_payload_t, destroy, void, /* * Described in header. */ -cp_payload_t *cp_payload_create_type(config_type_t type) +cp_payload_t *cp_payload_create_type(payload_type_t type, config_type_t cfg_type) { private_cp_payload_t *this; @@ -251,6 +304,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type) .next_payload = NO_PAYLOAD, .payload_length = get_header_length(this), .attributes = linked_list_create(), + .cfg_type = cfg_type, .type = type, ); return &this->public; @@ -259,7 +313,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type) /* * Described in header. */ -cp_payload_t *cp_payload_create() +cp_payload_t *cp_payload_create(payload_type_t type) { - return cp_payload_create_type(CFG_REQUEST); + return cp_payload_create_type(type, CFG_REQUEST); } diff --git a/src/libcharon/encoding/payloads/cp_payload.h b/src/libcharon/encoding/payloads/cp_payload.h index bc6bdee50..0e3cf53bc 100644 --- a/src/libcharon/encoding/payloads/cp_payload.h +++ b/src/libcharon/encoding/payloads/cp_payload.h @@ -46,9 +46,7 @@ enum config_type_t { extern enum_name_t *config_type_names; /** - * Class representing an IKEv2-CP Payload. - * - * The CP Payload format is described in RFC section 3.15. + * Class representing an IKEv2 configuration / IKEv1 attribute payload. */ struct cp_payload_t { @@ -88,16 +86,18 @@ struct cp_payload_t { /** * Creates an empty configuration payload * - * @return empty configuration payload + * @param type payload type, CONFIGURATION or CONFIGURATION_V1 + * @return empty configuration payload */ -cp_payload_t *cp_payload_create(); +cp_payload_t *cp_payload_create(payload_type_t type); /** * Creates an cp_payload_t with type and value * - * @param config_type type of configuration payload to create - * @return created configuration payload + * @param type payload type, CONFIGURATION or CONFIGURATION_V1 + * @param cfg_type type of configuration payload to create + * @return created configuration payload */ -cp_payload_t *cp_payload_create_type(config_type_t config_type); +cp_payload_t *cp_payload_create_type(payload_type_t type, config_type_t cfg_type); #endif /** CP_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/data_attribute_v1.c b/src/libcharon/encoding/payloads/data_attribute_v1.c deleted file mode 100644 index 37f7c0072..000000000 --- a/src/libcharon/encoding/payloads/data_attribute_v1.c +++ /dev/null @@ -1,260 +0,0 @@ - -#include - -#include "data_attribute_v1.h" - -#include -#include -#include - -typedef struct private_data_attribute_v1_t private_data_attribute_v1_t; - -/** - * Private data of an data_attribute_v1_t object. - */ -struct private_data_attribute_v1_t { - - /** - * Public data_attribute_v1_t interface. - */ - data_attribute_v1_t public; - - /** - * Reserved bit - */ - bool af_flag; - - /** - * Type of the attribute. - */ - u_int16_t type; - - /** - * Length of the attribute. - */ - u_int16_t length_or_value; - - /** - * Attribute value as chunk. - */ - chunk_t value; -}; - -/** - * Encoding rules to parse or generate a configuration attribute. - * - * The defined offsets are the positions in a object of type - * private_data_attribute_v1_t. - */ -encoding_rule_t data_attribute_v1_encodings[] = { - /* AF Flag */ - { FLAG, offsetof(private_data_attribute_v1_t, af_flag)}, - /* type of the attribute as 15 bit unsigned integer */ - { ATTRIBUTE_TYPE, offsetof(private_data_attribute_v1_t, type) }, - /* Length of attribute value */ - { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_data_attribute_v1_t, length_or_value) }, - /* Value of attribute if attribute format flag is zero */ - { ATTRIBUTE_VALUE, offsetof(private_data_attribute_v1_t, value) } -}; - -/* - 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - !R| Attribute Type ! Length | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - ~ Value ~ - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -*/ - -METHOD(payload_t, verify, status_t, - private_data_attribute_v1_t *this) -{ - bool failed = FALSE; - - if (this->length_or_value != this->value.len) - { - DBG1(DBG_ENC, "invalid attribute length"); - return FAILED; - } - - switch (this->type) - { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_NETMASK: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case INTERNAL_ADDRESS_EXPIRY: - case INTERNAL_IP4_DHCP: - if (this->length_or_value != 0 && this->length_or_value != 4) - { - failed = TRUE; - } - break; - case INTERNAL_IP4_SUBNET: - if (this->length_or_value != 0 && this->length_or_value != 8) - { - failed = TRUE; - } - break; - case INTERNAL_IP6_ADDRESS: - case INTERNAL_IP6_SUBNET: - if (this->length_or_value != 0 && this->length_or_value != 17) - { - failed = TRUE; - } - break; - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: - case INTERNAL_IP6_DHCP: - if (this->length_or_value != 0 && this->length_or_value != 16) - { - failed = TRUE; - } - break; - case SUPPORTED_ATTRIBUTES: - if (this->length_or_value % 2) - { - failed = TRUE; - } - break; - case APPLICATION_VERSION: - /* any length acceptable */ - break; - default: - DBG1(DBG_ENC, "unknown attribute type %N", - configuration_attribute_type_names, this->type); - break; - } - - if (failed) - { - DBG1(DBG_ENC, "invalid attribute length %d for %N", - this->length_or_value, configuration_attribute_type_names, this->type); - return FAILED; - } - return SUCCESS; -} - -METHOD(payload_t, get_encoding_rules, void, - private_data_attribute_v1_t *this, encoding_rule_t **rules, - size_t *rule_count) -{ - *rules = data_attribute_v1_encodings; - *rule_count = countof(data_attribute_v1_encodings); -} - -METHOD(payload_t, get_header_length, int, - private_data_attribute_v1_t *this) -{ - return 4; -} - -METHOD(payload_t, get_type, payload_type_t, - private_data_attribute_v1_t *this) -{ - return DATA_ATTRIBUTE_V1; -} - -METHOD(payload_t, get_next_type, payload_type_t, - private_data_attribute_v1_t *this) -{ - return NO_PAYLOAD; -} - -METHOD(payload_t, set_next_type, void, - private_data_attribute_v1_t *this, payload_type_t type) -{ -} - -METHOD(payload_t, get_length, size_t, - private_data_attribute_v1_t *this) -{ - return get_header_length(this) + this->value.len; -} - -METHOD(data_attribute_v1_t, get_dattr_type, configuration_attribute_type_t, - private_data_attribute_v1_t *this) -{ - return this->type; -} - -METHOD(data_attribute_v1_t, get_value, u_int16_t, - private_data_attribute_v1_t *this) -{ - return this->length_or_value; -} - -METHOD(data_attribute_v1_t, get_value_chunk, chunk_t, - private_data_attribute_v1_t *this) -{ - return this->value; -} - -METHOD2(payload_t, data_attribute_v1_t, destroy, void, - private_data_attribute_v1_t *this) -{ - free(this->value.ptr); - free(this); -} - -/* - * Described in header. - */ -data_attribute_v1_t *data_attribute_v1_create() -{ - private_data_attribute_v1_t *this; - - INIT(this, - .public = { - .payload_interface = { - .verify = _verify, - .get_encoding_rules = _get_encoding_rules, - .get_length = _get_length, - .get_next_type = _get_next_type, - .set_next_type = _set_next_type, - .get_type = _get_type, - .destroy = _destroy, - }, - .get_value_chunk = _get_value_chunk, - .get_type = _get_dattr_type, - .destroy = _destroy, - }, - ); - return &this->public; -} - -/* - * Described in header. - */ -data_attribute_v1_t *data_attribute_v1_create_value( - configuration_attribute_type_t type, chunk_t value) -{ - private_data_attribute_v1_t *this; - - this = (private_data_attribute_v1_t*)data_attribute_v1_create(); - this->type = ((u_int16_t)type) & 0x7FFF; - this->value = chunk_clone(value); - this->length_or_value = value.len; - this->af_flag = FALSE; - - return &this->public; -} - -/* - * Described in header. - */ -data_attribute_v1_t *data_attribute_v1_create_basic( - configuration_attribute_type_t type, u_int16_t value) -{ - private_data_attribute_v1_t *this; - - this = (private_data_attribute_v1_t*)data_attribute_v1_create(); - this->type = ((u_int16_t)type) & 0x7FFF; - this->length_or_value = value; - this->af_flag = TRUE; - - return &this->public; -} diff --git a/src/libcharon/encoding/payloads/data_attribute_v1.h b/src/libcharon/encoding/payloads/data_attribute_v1.h deleted file mode 100644 index 568b3143a..000000000 --- a/src/libcharon/encoding/payloads/data_attribute_v1.h +++ /dev/null @@ -1,88 +0,0 @@ - -/** - * @defgroup data_attribute_v1 data_attribute_v1 - * @{ @ingroup payloads - */ - -#ifndef DATA_ATTRIBUTE_V1_H_ -#define DATA_ATTRIBUTE_V1_H_ - -typedef struct data_attribute_v1_t data_attribute_v1_t; - -#include -#include -#include - -/** - * Configuration attribute header length in bytes. - */ -#define DATA_ATTRIBUTE_V1_HEADER_LENGTH 4 - -/** - * Class representing an IKEv1-Data Attribute. - * - * The DATA_ATTRIBUTE_V1 format is described in RFC section 3.15.1. - */ -struct data_attribute_v1_t { - - /** - * Implements payload_t interface. - */ - payload_t payload_interface; - - /** - * Get the type of the attribute. - * - * @return type of the data attribute - */ - configuration_attribute_type_t (*get_type)(data_attribute_v1_t *this); - - /** - * Returns the value of the attribute. - * - * @return the basic internal value - */ - u_int16_t (*get_value) (data_attribute_v1_t *this); - - /** - * Returns the value of the attribute. - * - * @return chunk_t pointing to the internal value - */ - chunk_t (*get_value_chunk) (data_attribute_v1_t *this); - - /** - * Destroys an configuration_attribute_t object. - */ - void (*destroy) (data_attribute_v1_t *this); -}; - -/** - * Creates an empty data attribute. - * - * @return created data attribute - */ -data_attribute_v1_t *data_attribute_v1_create(); - -/** - * Creates a data attribute with type and value. - * - * @param type type of data attribute - * @param value value, gets cloned - * @return created data attribute - */ -data_attribute_v1_t *data_attribute_v1_create_value( - configuration_attribute_type_t type, chunk_t value); - - -/** - * Creates a data attribute with type and value. - * - * @param type type of data attribute - * @param value value - * @return created data attribute - */ -data_attribute_v1_t *data_attribute_v1_create_basic( - configuration_attribute_type_t type, u_int16_t value); - -#endif /** DATA_ATTRIBUTE_V1_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 7d6fa6674..3a411606c 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -38,12 +38,9 @@ #include #include -#include -#include - ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD, "NO_PAYLOAD"); -ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, ATTRIBUTE_V1, NO_PAYLOAD, +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, NO_PAYLOAD, "SECURITY_ASSOCIATION_V1", "PROPOSAL_V1", "TRANSFORM_V1", @@ -57,8 +54,8 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, ATTRIBUTE_V1, NO_PAYLOAD, "NOTIFY_V1", "DELETE_V1", "VENDOR_ID_V1", - "ATTRIBUTE_V1"); -ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, ATTRIBUTE_V1, + "CONFIGURATION_V1"); +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, CONFIGURATION_V1, "SECURITY_ASSOCIATION", "KEY_EXCHANGE", "ID_INITIATOR", @@ -78,7 +75,7 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, A #ifdef ME ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, "ID_PEER"); -ENUM_NEXT(payload_type_names, HEADER, DATA_ATTRIBUTE_V1, ID_PEER, +ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, ID_PEER, "HEADER", "PROPOSAL_SUBSTRUCTURE", "PROPOSAL_SUBSTRUCTURE_V1", @@ -88,10 +85,10 @@ ENUM_NEXT(payload_type_names, HEADER, DATA_ATTRIBUTE_V1, ID_PEER, "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", "CONFIGURATION_ATTRIBUTE", - "ENCRYPTED_V1", - "DATA_ATTRIBUTE_V1"); + "CONFIGURATION_ATTRIBUTE_V1", + "ENCRYPTED_V1"); #else -ENUM_NEXT(payload_type_names, HEADER, DATA_ATTRIBUTE_V1, EXTENSIBLE_AUTHENTICATION, +ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, EXTENSIBLE_AUTHENTICATION, "HEADER", "PROPOSAL_SUBSTRUCTURE", "PROPOSAL_SUBSTRUCTURE_V1", @@ -101,15 +98,15 @@ ENUM_NEXT(payload_type_names, HEADER, DATA_ATTRIBUTE_V1, EXTENSIBLE_AUTHENTICATI "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", "CONFIGURATION_ATTRIBUTE", - "ENCRYPTED_V1", - "DATA_ATTRIBUTE_V1"); + "CONFIGURATION_ATTRIBUTE_V1", + "ENCRYPTED_V1"); #endif /* ME */ -ENUM_END(payload_type_names, DATA_ATTRIBUTE_V1); +ENUM_END(payload_type_names, ENCRYPTED_V1); /* short forms of payload names */ ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD, "--"); -ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION_V1, VENDOR_ID_V1, NO_PAYLOAD, +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, NO_PAYLOAD, "SA", "PROP", "TRANS", @@ -122,8 +119,9 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION_V1, VENDOR_ID_V1, NO_PA "No", "N", "D", - "V"); -ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, VENDOR_ID_V1, + "V", + "CP"); +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, CONFIGURATION_V1, "SA", "KE", "IDi", @@ -143,7 +141,7 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICAT #ifdef ME ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, "IDp"); -ENUM_NEXT(payload_type_short_names, HEADER, DATA_ATTRIBUTE_V1, ID_PEER, +ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, ID_PEER, "HDR", "PROP", "PROP", @@ -153,10 +151,10 @@ ENUM_NEXT(payload_type_short_names, HEADER, DATA_ATTRIBUTE_V1, ID_PEER, "TRANSATTR", "TSSUB", "CATTR", - "E", - "DATAATTR"); + "CATTR", + "E"); #else -ENUM_NEXT(payload_type_short_names, HEADER, DATA_ATTRIBUTE_V1, EXTENSIBLE_AUTHENTICATION, +ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, EXTENSIBLE_AUTHENTICATION, "HDR", "PROP", "PROP", @@ -166,10 +164,10 @@ ENUM_NEXT(payload_type_short_names, HEADER, DATA_ATTRIBUTE_V1, EXTENSIBLE_AUTHEN "TRANSATTR", "TSSUB", "CATTR", - "E", - "DATAATTR"); + "CATTR", + "E"); #endif /* ME */ -ENUM_END(payload_type_short_names, DATA_ATTRIBUTE_V1); +ENUM_END(payload_type_short_names, ENCRYPTED_V1); /* * see header @@ -230,18 +228,16 @@ payload_t *payload_create(payload_type_t type) case HASH_V1: return (payload_t*)hash_payload_create(); case CONFIGURATION: - return (payload_t*)cp_payload_create(); + case CONFIGURATION_V1: + return (payload_t*)cp_payload_create(type); case CONFIGURATION_ATTRIBUTE: - return (payload_t*)configuration_attribute_create(); + case CONFIGURATION_ATTRIBUTE_V1: + return (payload_t*)configuration_attribute_create(type); case EXTENSIBLE_AUTHENTICATION: return (payload_t*)eap_payload_create(); case ENCRYPTED: case ENCRYPTED_V1: return (payload_t*)encryption_payload_create(type); - case ATTRIBUTE_V1: - return (payload_t*)attribute_payload_v1_create(); - case DATA_ATTRIBUTE_V1: - return (payload_t*)data_attribute_v1_create(); default: return (payload_t*)unknown_payload_create(type); } @@ -260,7 +256,7 @@ bool payload_is_known(payload_type_t type) { return TRUE; } - if (type >= SECURITY_ASSOCIATION_V1 && type <= VENDOR_ID_V1) + if (type >= SECURITY_ASSOCIATION_V1 && type <= CONFIGURATION_V1) { return TRUE; } diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index f55099fe7..6209b0822 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -113,9 +113,9 @@ enum payload_type_t { VENDOR_ID_V1 = 13, /** - * Attribute payload (ISAKMP Cfg Mode "draft-ietf-ipsec-isakmp-mode-cfg-05") + * Attribute payload (ISAKMP Mode Config, aka configuration payload. */ - ATTRIBUTE_V1 = 14, + CONFIGURATION_V1 = 14, /** * The security association (SA) payload containing proposals. @@ -249,20 +249,19 @@ enum payload_type_t { TRAFFIC_SELECTOR_SUBSTRUCTURE, /** - * CONFIGURATION_ATTRIBUTE, attribute in a configuration payload. + * CONFIGURATION_ATTRIBUTE, IKEv2 attribute in a configuration payload. */ CONFIGURATION_ATTRIBUTE, + /** + * CONFIGURATION_ATTRIBUTE_V1, IKEv1 attribute in a configuration payload. + */ + CONFIGURATION_ATTRIBUTE_V1, + /** * This is not really a payload, but rather the complete IKEv1 message. */ ENCRYPTED_V1, - - /** - * DATA_ATTRIBUTE, attribute in an ATTRIBUTE payload. - */ - DATA_ATTRIBUTE_V1, - }; /** diff --git a/src/libcharon/sa/tasks/ike_config.c b/src/libcharon/sa/tasks/ike_config.c index 6623730d1..332af465b 100644 --- a/src/libcharon/sa/tasks/ike_config.c +++ b/src/libcharon/sa/tasks/ike_config.c @@ -98,7 +98,8 @@ static configuration_attribute_t *build_vip(host_t *vip) chunk = chunk_cata("cc", chunk, prefix); } } - return configuration_attribute_create_value(type, chunk); + return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE, + type, chunk); } /** @@ -128,11 +129,11 @@ static void handle_attribute(private_ike_config_t *this, /* and pass it to the handle function */ handler = hydra->attributes->handle(hydra->attributes, this->ike_sa->get_other_id(this->ike_sa), handler, - ca->get_type(ca), ca->get_value(ca)); + ca->get_type(ca), ca->get_chunk(ca)); if (handler) { this->ike_sa->add_configuration_attribute(this->ike_sa, - handler, ca->get_type(ca), ca->get_value(ca)); + handler, ca->get_type(ca), ca->get_chunk(ca)); } } @@ -153,7 +154,7 @@ static void process_attribute(private_ike_config_t *this, /* fall */ case INTERNAL_IP6_ADDRESS: { - addr = ca->get_value(ca); + addr = ca->get_chunk(ca); if (addr.len == 0) { ip = host_create_any(family); @@ -252,7 +253,7 @@ METHOD(task_t, build_i, status_t, } if (vip) { - cp = cp_payload_create_type(CFG_REQUEST); + cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST); cp->add_attribute(cp, build_vip(vip)); } @@ -266,10 +267,11 @@ METHOD(task_t, build_i, status_t, /* create configuration attribute */ DBG2(DBG_IKE, "building %N attribute", configuration_attribute_type_names, type); - ca = configuration_attribute_create_value(type, data); + ca = configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE, + type, data); if (!cp) { - cp = cp_payload_create_type(CFG_REQUEST); + cp = cp_payload_create_type(CONFIGURATION, CFG_REQUEST); } cp->add_attribute(cp, ca); @@ -335,7 +337,7 @@ METHOD(task_t, build_r, status_t, DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id); this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip); - cp = cp_payload_create_type(CFG_REPLY); + cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY); cp->add_attribute(cp, build_vip(vip)); } @@ -346,12 +348,13 @@ METHOD(task_t, build_r, status_t, { if (!cp) { - cp = cp_payload_create_type(CFG_REPLY); + cp = cp_payload_create_type(CONFIGURATION, CFG_REPLY); } DBG2(DBG_IKE, "building %N attribute", configuration_attribute_type_names, type); cp->add_attribute(cp, - configuration_attribute_create_value(type, value)); + configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE, + type, value)); } enumerator->destroy(enumerator); diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c index a50d0fb43..60914beef 100644 --- a/src/libcharon/sa/tasks/xauth_request.c +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -3,8 +3,7 @@ #include #include -#include -#include +#include #include #include @@ -61,10 +60,9 @@ static void process_payloads(private_xauth_request_t *this, message_t *message) METHOD(task_t, build_i, status_t, private_xauth_request_t *this, message_t *message) { - attribute_payload_v1_t *ap = NULL; + cp_payload_t *cp; chunk_t chunk = chunk_empty; - data_attribute_v1_t *da = NULL; - hash_payload_t *hash_payload = NULL; + hash_payload_t *hash_payload; generator_t *generator; chunk_t attr_chunk; chunk_t mid_chunk; @@ -76,13 +74,11 @@ METHOD(task_t, build_i, status_t, DBG1(DBG_IKE, "BUILDING XAUTH REQUEST PACKET"); /* TODO1: Create ATTR payload */ - ap = attribute_payload_v1_create(); - - da = data_attribute_v1_create_value(XAUTH_USER_NAME, chunk); - ap->add_attribute(ap, da); - - da = data_attribute_v1_create_value(XAUTH_USER_PASSWORD, chunk); - ap->add_attribute(ap, da); + cp = cp_payload_create(CONFIGURATION_V1); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk)); /* Create HASH payload */ hash_payload = hash_payload_create(); @@ -90,8 +86,8 @@ METHOD(task_t, build_i, status_t, /* Calculate the chunk for the ATTR payload */ generator = generator_create(); - ap->payload_interface.set_next_type(&ap->payload_interface, NO_PAYLOAD); - generator->generate_payload(generator, (payload_t *)ap); + cp->payload_interface.set_next_type(&cp->payload_interface, NO_PAYLOAD); + generator->generate_payload(generator, (payload_t *)cp); attr_chunk = generator->get_chunk(generator, &lenpos); /* Get the message ID in network order */ @@ -102,7 +98,7 @@ METHOD(task_t, build_i, status_t, hash_in = chunk_cat("cc", mid_chunk, attr_chunk); message->add_payload(message, (payload_t *)hash_payload); - message->add_payload(message, (payload_t *)ap); + message->add_payload(message, (payload_t *)cp); return NEED_MORE; } From 384c1a32a220e27f2a462fa07e64f8eebdfbec0a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 11:27:03 +0100 Subject: [PATCH 114/534] XAUTH is initiated based on configuration, no need to call externally --- src/libcharon/sa/ike_sa.c | 9 --------- src/libcharon/sa/ike_sa.h | 5 ----- src/libcharon/sa/task_manager_v1.c | 7 ------- 3 files changed, 21 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 05622a316..6be8471f2 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -2129,15 +2129,6 @@ METHOD(ike_sa_t, destroy, void, free(this); } -METHOD(ike_sa_t, initiate_xauth, void, - private_ike_sa_t *this) -{ - xauth_request_t *xauth_request_task = xauth_request_create(this, TRUE); - this->task_manager->queue_task(this->task_manager, (task_t*)xauth_request_task); - -// this->task_manager->initiate_later(this->task_manager); -} - /* * Described in header. */ diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index ecfb04e02..2753fca1c 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -958,11 +958,6 @@ struct ike_sa_t { * Destroys a ike_sa_t object. */ void (*destroy) (ike_sa_t *this); - - /** - * Initiate XAUTH authentication - */ - status_t (*initiate_xauth)(ike_sa_t *this); }; /** diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index fbc8da7cc..8bec310a7 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -131,13 +131,6 @@ struct private_task_manager_t { * Base to calculate retransmission timeout */ double retransmit_base; - - /** - * Flag to tell the task manager to initiate a transaction at - * a later time. - */ - bool initiate_later_flag; - }; /** From b6016fcab3b34305b3abafc7e02af7cf7d9946f2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 11:27:47 +0100 Subject: [PATCH 115/534] Fixed a config reference leak in IKEv2 initiate --- src/libcharon/sa/tasks/child_create.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index 79ca6cf5a..e40f34dc9 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -1323,7 +1323,6 @@ child_create_t *child_create_create(ike_sa_t *ike_sa, this->public.task.build = _build_i; this->public.task.process = _process_i; this->initiator = TRUE; - config->get_ref(config); } else { From d6cec44b2400589a746649862326f72490288544 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 23 Nov 2011 12:11:49 +0100 Subject: [PATCH 116/534] Fixed conftests after extending CERT payload. --- src/conftest/hooks/ike_auth_fill.c | 2 +- src/conftest/hooks/pretend_auth.c | 4 ++-- src/libcharon/encoding/payloads/cert_payload.c | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/conftest/hooks/ike_auth_fill.c b/src/conftest/hooks/ike_auth_fill.c index 052a4be08..ac26d1bfe 100644 --- a/src/conftest/hooks/ike_auth_fill.c +++ b/src/conftest/hooks/ike_auth_fill.c @@ -108,7 +108,7 @@ METHOD(listener_t, message, bool, diff = this->bytes - size - CERT_PAYLOAD_HEADER_LENGTH; data = chunk_alloc(diff); memset(data.ptr, 0x12, data.len); - pld = cert_payload_create_custom(201, data); + pld = cert_payload_create_custom(201, data, CERTIFICATE); message->add_payload(message, &pld->payload_interface); DBG1(DBG_CFG, "inserting %d dummy bytes certificate payload", diff); } diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c index f91b6bf9b..560864db5 100644 --- a/src/conftest/hooks/pretend_auth.c +++ b/src/conftest/hooks/pretend_auth.c @@ -154,7 +154,7 @@ static void build_certs(private_pretend_auth_t *this, cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); if (cert) { - payload = cert_payload_create_from_cert(cert); + payload = cert_payload_create_from_cert(cert, CERTIFICATE); if (payload) { DBG1(DBG_IKE, "pretending end entity cert \"%Y\"", @@ -167,7 +167,7 @@ static void build_certs(private_pretend_auth_t *this, { if (type == AUTH_RULE_IM_CERT) { - payload = cert_payload_create_from_cert(cert); + payload = cert_payload_create_from_cert(cert, CERTIFICATE); if (payload) { DBG1(DBG_IKE, "pretending issuer cert \"%Y\"", diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c index cf97e9613..af726ad62 100644 --- a/src/libcharon/encoding/payloads/cert_payload.c +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -332,7 +332,8 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert, payload_type_ /* * Described in header */ -cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url, payload_type_t type) +cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url, + payload_type_t type) { private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(type); @@ -345,7 +346,8 @@ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url, p /* * Described in header */ -cert_payload_t *cert_payload_create_custom(cert_encoding_t encoding, chunk_t data, payload_type_t type) +cert_payload_t *cert_payload_create_custom(cert_encoding_t encoding, + chunk_t data, payload_type_t type) { private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(type); From f3cc8589b1e025f3f077d8ca96db4eb31cc20597 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 23 Nov 2011 12:35:10 +0100 Subject: [PATCH 117/534] Fixed header length calculation of DELETE payload. --- src/libcharon/encoding/payloads/delete_payload.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index f5bdb3809..5609ea766 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -88,9 +88,9 @@ struct private_delete_payload_t { */ static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, + { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_delete_payload_t, critical) }, + { FLAG, offsetof(private_delete_payload_t, critical) }, /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) }, @@ -105,7 +105,7 @@ static encoding_rule_t encodings_v2[] = { { U_INT_8, offsetof(private_delete_payload_t, spi_size) }, { U_INT_16, offsetof(private_delete_payload_t, spi_count) }, /* some delete data bytes, length is defined in PAYLOAD_LENGTH */ - { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, + { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, }; /* @@ -145,7 +145,7 @@ static encoding_rule_t encodings_v1[] = { { U_INT_8, offsetof(private_delete_payload_t, spi_size) }, { U_INT_16, offsetof(private_delete_payload_t, spi_count) }, /* some delete data bytes, length is defined in PAYLOAD_LENGTH */ - { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, + { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, }; /* @@ -211,9 +211,9 @@ METHOD(payload_t, get_header_length, int, { if (this->type == DELETE) { - return 8 + this->spi_size; + return 8; } - return 12 + this->spi_size; + return 12; } METHOD(payload_t, get_payload_type, payload_type_t, From 1e5dd62bb28ca177e813723327703ff93ba3d3b4 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 23 Nov 2011 12:35:58 +0100 Subject: [PATCH 118/534] Fixed verification of DELETE_V1 payloads. --- .../encoding/payloads/delete_payload.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index 5609ea766..79070a79f 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -178,10 +178,19 @@ METHOD(payload_t, verify, status_t, break; case PROTO_IKE: case 0: - /* IKE deletion has no spi assigned! */ - if (this->spi_size != 0) - { - return FAILED; + if (this->type == DELETE) + { /* IKEv2 deletion has no spi assigned! */ + if (this->spi_size != 0) + { + return FAILED; + } + } + else + { /* IKEv1 uses the two concatenated ISAKMP cookies as SPI */ + if (this->spi_size != 16) + { + return FAILED; + } } break; default: From cd200cb821df307aec441308b74dbd8d94c73589 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 23 Nov 2011 13:17:46 +0100 Subject: [PATCH 119/534] Authenticate and verify Phase 2 IKEv1 messages with appropriate hashes. --- src/libcharon/encoding/message.c | 46 ++++++- src/libcharon/sa/keymat_v1.c | 212 +++++++++++++++++++++++++++++++ src/libcharon/sa/keymat_v1.h | 9 ++ 3 files changed, 265 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 032fc1b1c..f53be0036 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -1408,7 +1409,19 @@ METHOD(message_t, generate, status_t, encrypted = this->rule->encrypted; } else - { /* if at least one payload requires encryption, encrypt the message */ + { + /* get a hash for this message, if any is required */ + chunk_t hash = keymat_v1->get_hash_phase2(keymat_v1, &this->public); + if (hash.ptr) + { /* insert a HASH payload as first payload */ + hash_payload_t *hash_payload = hash_payload_create(); + hash_payload->set_hash(hash_payload, hash); + this->payloads->insert_first(this->payloads, + (payload_t*)hash_payload); + chunk_free(&hash); + } + + /* if at least one payload requires encryption, encrypt the message */ /* TODO-IKEV1: set is_encrypted externally instead of this check? */ enumerator = this->payloads->create_enumerator(this->payloads); while (enumerator->enumerate(enumerator, (void**)&payload)) @@ -1821,7 +1834,7 @@ static status_t verify(private_message_t *this) DBG2(DBG_ENC, "verifying message structure"); - /* check for payloads with wrong count*/ + /* check for payloads with wrong count */ for (i = 0; i < this->rule->rule_count; i++) { enumerator_t *enumerator; @@ -1906,6 +1919,35 @@ METHOD(message_t, parse_body, status_t, DBG1(DBG_ENC, "parsed %s", get_string(this, str, sizeof(str))); + if (this->major_version == IKEV1_MAJOR_VERSION) + { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; + chunk_t hash; + hash = keymat_v1->get_hash_phase2(keymat_v1, &this->public); + if (hash.ptr) + { + hash_payload_t *hash_payload; + chunk_t other_hash; + if (this->first_payload != HASH_V1) + { + DBG1(DBG_ENC, "expected HASH payload as first payload"); + chunk_free(&hash); + return VERIFY_ERROR; + } + hash_payload = (hash_payload_t*)get_payload(this, HASH_V1); + other_hash = hash_payload->get_hash(hash_payload); + if (!chunk_equals(hash, other_hash)) + { + DBG1(DBG_ENC, "our hash does not match received %B", + &other_hash); + chunk_free(&hash); + return VERIFY_ERROR; + } + DBG2(DBG_ENC, "verified IKEv1 message with hash %B", &hash); + chunk_free(&hash); + } + } + if (this->is_encrypted) { /* TODO-IKEv1: this should be done later when we know this is no * retransmit */ diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 57b96754d..8b9ac498c 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -16,6 +16,8 @@ #include "keymat_v1.h" #include +#include +#include #include typedef struct private_keymat_v1_t private_keymat_v1_t; @@ -25,6 +27,11 @@ typedef struct private_keymat_v1_t private_keymat_v1_t; */ #define MAX_IV 3 +/** + * Max. number of Quick Modes to track. + */ +#define MAX_QM 2 + /** * Data stored for IVs */ @@ -97,6 +104,12 @@ struct private_keymat_v1_t { * number of IVs in an MRU sort of way. Stores iv_data_t objects. */ linked_list_t *ivs; + + /** + * Keep track of Nonces during Quick Mode exchanges. Only a limited number + * of QMs are tracked at the same time. Stores qm_data_t objects. + */ + linked_list_t *qms; }; @@ -110,6 +123,28 @@ static void iv_data_destroy(iv_data_t *this) free(this); } +/** + * Data stored for Quick Mode exchanges + */ +typedef struct { + /** message ID */ + u_int32_t mid; + /** Ni_b (Nonce from first message) */ + chunk_t n_i; + /** Nr_b (Nonce from second message) */ + chunk_t n_r; +} qm_data_t; + +/** + * Destroy a qm_data_t object. + */ +static void qm_data_destroy(qm_data_t *this) +{ + chunk_free(&this->n_i); + chunk_free(&this->n_r); + free(this); +} + /** * Constants used in key derivation. */ @@ -616,6 +651,180 @@ METHOD(keymat_v1_t, get_hash, chunk_t, return hash; } +/** + * Get the nonce value found in the given message. + * Returns FALSE if none is found. + */ +static bool get_nonce(message_t *message, chunk_t *n) +{ + nonce_payload_t *nonce; + nonce = (nonce_payload_t*)message->get_payload(message, NONCE_V1); + if (nonce) + { + *n = nonce->get_nonce(nonce); + return TRUE; + } + return FALSE; +} + +/** + * Generate the message data in order to generate the hashes. + */ +static chunk_t get_message_data(message_t *message, generator_t *generator) +{ + payload_t *payload, *next; + enumerator_t *enumerator; + u_int32_t *lenpos; + + if (message->is_encoded(message)) + { /* inbound, although the message is generated, we cannot access the + * cleartext message data, so generate it anyway */ + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == HASH_V1) + { + continue; + } + generator->generate_payload(generator, payload); + } + enumerator->destroy(enumerator); + } + else + { + /* outbound, generate the payloads (there is no HASH payload yet) */ + enumerator = message->create_payload_enumerator(message); + if (enumerator->enumerate(enumerator, &payload)) + { + while (enumerator->enumerate(enumerator, &next)) + { + payload->set_next_type(payload, next->get_type(next)); + generator->generate_payload(generator, payload); + payload = next; + } + payload->set_next_type(payload, NO_PAYLOAD); + generator->generate_payload(generator, payload); + } + enumerator->destroy(enumerator); + } + return generator->get_chunk(generator, &lenpos); +} + +/** + * Try to find data about a Quick Mode with the given message ID, + * if none is found, state is generated. + */ +static qm_data_t *lookup_quick_mode(private_keymat_v1_t *this, u_int32_t mid) +{ + enumerator_t *enumerator; + qm_data_t *qm, *found = NULL; + + enumerator = this->qms->create_enumerator(this->qms); + while (enumerator->enumerate(enumerator, &qm)) + { + if (qm->mid == mid) + { /* state gets moved to the front of the list */ + this->qms->remove_at(this->qms, enumerator); + found = qm; + break; + } + } + enumerator->destroy(enumerator); + if (!found) + { + INIT(found, + .mid = mid, + ); + } + this->qms->insert_first(this->qms, found); + /* remove least recently used state if maximum reached */ + if (this->qms->get_count(this->qms) > MAX_QM && + this->qms->remove_last(this->qms, (void**)&qm) == SUCCESS) + { + qm_data_destroy(qm); + } + return found; +} + +METHOD(keymat_v1_t, get_hash_phase2, chunk_t, + private_keymat_v1_t *this, message_t *message) +{ + u_int32_t mid = message->get_message_id(message), mid_n = htonl(mid); + chunk_t data = chunk_empty, hash = chunk_empty; + bool add_message = TRUE; + char *name = "Hash"; + + /* Hashes are simple for most exchanges in Phase 2: + * Hash = prf(SKEYID_a, M-ID | Complete message after HASH payload) + * For Quick Mode there are three hashes: + * Hash(1) = same as above + * Hash(2) = prf(SKEYID_a, M-ID | Ni_b | Message after HASH payload) + * Hash(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) + * So, for Quick Mode we keep track of the nonce values. + */ + switch (message->get_exchange_type(message)) + { + case QUICK_MODE: + { + qm_data_t *qm = lookup_quick_mode(this, mid); + if (!qm->n_i.ptr) + { /* Hash(1) = prf(SKEYID_a, M-ID | Message after HASH payload) */ + name = "Hash(1)"; + if (!get_nonce(message, &qm->n_i)) + { + return hash; + } + data = chunk_from_thing(mid_n); + } + else if (!qm->n_r.ptr) + { /* Hash(2) = prf(SKEYID_a, M-ID | Ni_b | Message after HASH) */ + name = "Hash(2)"; + if (!get_nonce(message, &qm->n_r)) + { + return hash; + } + data = chunk_cata("cc", chunk_from_thing(mid_n), qm->n_i); + } + else + { /* Hash(3) = prf(SKEYID_a, 0 | M-ID | Ni_b | Nr_b) */ + name = "Hash(3)"; + data = chunk_cata("cccc", octet_0, chunk_from_thing(mid_n), + qm->n_i, qm->n_r); + add_message = FALSE; + /* we don't need the state anymore */ + this->qms->remove(this->qms, qm, NULL); + qm_data_destroy(qm); + } + break; + } + case TRANSACTION: + case INFORMATIONAL_V1: + /* Hash = prf(SKEYID_a, M-ID | Message after HASH payload) */ + data = chunk_from_thing(mid_n); + break; + default: + break; + } + if (data.ptr) + { + this->prf->set_key(this->prf, this->skeyid_a); + if (add_message) + { + generator_t *generator = generator_create(); + chunk_t msg = get_message_data(message, generator); + this->prf->allocate_bytes(this->prf, data, NULL); + this->prf->allocate_bytes(this->prf, msg, &hash); + generator->destroy(generator); + } + else + { + this->prf->allocate_bytes(this->prf, data, &hash); + } + DBG3(DBG_IKE, "%s %B", name, &hash); + } + return hash; +} + /** * Generate an IV */ @@ -734,6 +943,7 @@ METHOD(keymat_t, destroy, void, chunk_free(&this->phase1_iv.iv); chunk_free(&this->phase1_iv.last_block); this->ivs->destroy_function(this->ivs, (void*)iv_data_destroy); + this->qms->destroy_function(this->qms, (void*)qm_data_destroy); free(this); } @@ -754,11 +964,13 @@ keymat_v1_t *keymat_v1_create(bool initiator) .derive_ike_keys = _derive_ike_keys, .derive_child_keys = _derive_child_keys, .get_hash = _get_hash, + .get_hash_phase2 = _get_hash_phase2, .get_iv = _get_iv, .update_iv = _update_iv, .confirm_iv = _confirm_iv, }, .ivs = linked_list_create(), + .qms = linked_list_create(), .initiator = initiator, .prf_alg = PRF_UNDEFINED, ); diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h index fb5a1b684..e2d5cf657 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/keymat_v1.h @@ -88,6 +88,15 @@ struct keymat_v1_t { chunk_t dh, chunk_t dh_other, ike_sa_id_t *ike_sa_id, chunk_t sa_i, identification_t *id); + /** + * Get HASH data for integrity/authentication in Phase 2 exchanges. + * + * @param message message to generate the HASH data for + * @return allocated HASH data + */ + chunk_t (*get_hash_phase2)(keymat_v1_t *this, message_t *message); + + /** * Returns the IV for a message with the given message ID. * From 7a7f486df6c4d0f87de0146ce1c10315c0e75093 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 13:56:21 +0100 Subject: [PATCH 120/534] Include hardcoded tunnel mode attribute in porposal, remove ESN attribute --- src/libcharon/encoding/payloads/proposal_substructure.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 66fa8997b..6173d07db 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -867,10 +867,10 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, } enumerator->destroy(enumerator); - /* TODO-IKEv1: Add lifetime and other attributes, non-fixes ESN */ + /* TODO-IKEv1: Add lifetime and other attributes, ESN */ transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH2_EXT_SEQ_NUMBER, NO_EXT_SEQ_NUMBERS)); + TATTR_PH2_ENCAP_MODE, IKEV1_ENCAP_TUNNEL)); transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); From 9cc8bd4fd25b7b16323643633c36f75cdc42784a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 13:56:51 +0100 Subject: [PATCH 121/534] Use a dedicated message hash to detect IKEv1 retransmissions --- src/libcharon/sa/task_manager_v1.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 8bec310a7..c415b4edb 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -69,6 +69,11 @@ struct private_task_manager_t { */ u_int32_t mid; + /** + * Hash of a previously received message + */ + u_int32_t hash; + /** * packet for retransmission */ @@ -85,6 +90,11 @@ struct private_task_manager_t { */ u_int32_t mid; + /** + * Hash of a previously received message + */ + u_int32_t hash; + /** * how many times we have retransmitted so far */ @@ -577,7 +587,6 @@ METHOD(task_manager_t, process_message, status_t, host_t *me, *other; mid = msg->get_message_id(msg); - hash = chunk_hash(msg->get_packet_data(msg)); /* TODO-IKEv1: update hosts more selectively */ me = msg->get_destination(msg); @@ -597,8 +606,8 @@ METHOD(task_manager_t, process_message, status_t, } else { - if ((mid && mid == this->responding.mid) || - hash == this->responding.mid) + hash = chunk_hash(msg->get_packet_data(msg)); + if (hash == this->responding.hash) { DBG1(DBG_IKE, "received retransmit of request with ID %d, " "retransmitting response", mid); @@ -614,11 +623,8 @@ METHOD(task_manager_t, process_message, status_t, return DESTROY_ME; } - if (!mid) - { - mid = hash; - } this->responding.mid = mid; + this->responding.hash = hash; } return SUCCESS; } From 85f5c478bfa1ae861c36f1c24f4578f13166e91b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 14:05:19 +0100 Subject: [PATCH 122/534] Fix seed construction for IKEv1 key derivation --- src/libcharon/sa/keymat_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 8b9ac498c..3ec8083cf 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -525,7 +525,7 @@ METHOD(keymat_v1_t, derive_child_keys, bool, } DBG4(DBG_CHD, "DH secret %B", &secret); } - seed = chunk_cata("mcc", secret, chunk_from_thing(protocol), + seed = chunk_cata("mcccc", secret, chunk_from_thing(protocol), chunk_from_thing(spi), nonce_i, nonce_r); DBG4(DBG_CHD, "seed %B", &seed); From a7910b1c6e59da37f70bb63c39e9c0615b44eeff Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 14:26:24 +0100 Subject: [PATCH 123/534] Derive IKEv1 CHILD_SA keymat twice, once for each IPsec SA --- src/libcharon/sa/keymat_v1.c | 47 +++++++++++++++-------------- src/libcharon/sa/keymat_v1.h | 5 ++- src/libcharon/sa/tasks/quick_mode.c | 3 +- 3 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 3ec8083cf..97a21e022 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -503,32 +503,14 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, METHOD(keymat_v1_t, derive_child_keys, bool, private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, - chunk_t *encr_r, chunk_t *integ_r) + u_int32_t spi_i, u_int32_t spi_r, chunk_t nonce_i, chunk_t nonce_r, + chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r) { u_int16_t enc_alg, int_alg, enc_size = 0, int_size = 0; u_int8_t protocol; - u_int32_t spi; prf_plus_t *prf_plus; chunk_t seed, secret = chunk_empty; - /* KEYMAT = prf+(SKEYID_d, [ g(qm)^xy | ] protocol | SPI | Ni_b | Nr_b) */ - - protocol = proposal->get_protocol(proposal); - spi = proposal->get_spi(proposal); - - if (dh) - { - if (dh->get_shared_secret(dh, &secret) != SUCCESS) - { - return FALSE; - } - DBG4(DBG_CHD, "DH secret %B", &secret); - } - seed = chunk_cata("mcccc", secret, chunk_from_thing(protocol), - chunk_from_thing(spi), nonce_i, nonce_r); - DBG4(DBG_CHD, "seed %B", &seed); - if (proposal->get_algorithm(proposal, ENCRYPTION_ALGORITHM, &enc_alg, &enc_size)) { @@ -591,16 +573,37 @@ METHOD(keymat_v1_t, derive_child_keys, bool, int_size /= 8; } + /* KEYMAT = prf+(SKEYID_d, [ g(qm)^xy | ] protocol | SPI | Ni_b | Nr_b) */ this->prf->set_key(this->prf, this->skeyid_d); - prf_plus = prf_plus_create(this->prf, FALSE, seed); + protocol = proposal->get_protocol(proposal); + if (dh) + { + if (dh->get_shared_secret(dh, &secret) != SUCCESS) + { + return FALSE; + } + DBG4(DBG_CHD, "DH secret %B", &secret); + } + seed = chunk_cata("ccccc", secret, chunk_from_thing(protocol), + chunk_from_thing(spi_r), nonce_i, nonce_r); + DBG4(DBG_CHD, "initiator SA seed %B", &seed); + + prf_plus = prf_plus_create(this->prf, FALSE, seed); prf_plus->allocate_bytes(prf_plus, enc_size, encr_i); prf_plus->allocate_bytes(prf_plus, int_size, integ_i); + prf_plus->destroy(prf_plus); + + seed = chunk_cata("ccccc", secret, chunk_from_thing(protocol), + chunk_from_thing(spi_i), nonce_i, nonce_r); + DBG4(DBG_CHD, "responder SA seed %B", &seed); + prf_plus = prf_plus_create(this->prf, FALSE, seed); prf_plus->allocate_bytes(prf_plus, enc_size, encr_r); prf_plus->allocate_bytes(prf_plus, int_size, integ_r); - prf_plus->destroy(prf_plus); + chunk_clear(&secret); + if (enc_size) { DBG4(DBG_CHD, "encryption initiator key %B", encr_i); diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h index e2d5cf657..eb07e3a0c 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/keymat_v1.h @@ -61,6 +61,8 @@ struct keymat_v1_t { * * @param proposal selected algorithms * @param dh diffie hellman key, NULL if none used + * @param spi_i SPI chosen by initiatior + * @param spi_r SPI chosen by responder * @param nonce_i quick mode initiator nonce * @param nonce_r quick mode responder nonce * @param encr_i allocated initiators encryption key @@ -69,7 +71,8 @@ struct keymat_v1_t { * @param integ_r allocated responders integrity key */ bool (*derive_child_keys)(keymat_v1_t *this, proposal_t *proposal, - diffie_hellman_t *dh, chunk_t nonce_i, chunk_t nonce_r, + diffie_hellman_t *dh, u_int32_t spi_i, u_int32_t spi_r, + chunk_t nonce_i, chunk_t nonce_r, chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r); diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 987b8d5f4..8586d9abf 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -124,7 +124,8 @@ static bool install(private_quick_mode_t *this) tsi->insert_last(tsi, this->tsi); tsr->insert_last(tsr, this->tsr); if (this->keymat->derive_child_keys(this->keymat, this->proposal, NULL, - this->nonce_i, this->nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) + this->spi_i, this->spi_r, this->nonce_i, this->nonce_r, + &encr_i, &integ_i, &encr_r, &integ_r)) { if (this->initiator) { From 3e246c48832795f88f83e69f7c09ee74f9ac6142 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 14:31:17 +0100 Subject: [PATCH 124/534] Generate a new mid only after we start a new task (and exchange) --- src/libcharon/sa/task_manager_v1.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index c415b4edb..55bc8b7f9 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -236,6 +236,7 @@ METHOD(task_manager_t, initiate, status_t, host_t *me, *other; status_t status; exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED; + bool new_mid = FALSE; if (!this->rng) { @@ -266,11 +267,14 @@ METHOD(task_manager_t, initiate, status_t, if (activate_task(this, TASK_QUICK_MODE)) { exchange = QUICK_MODE; + new_mid = TRUE; + break; } - if (activate_task(this, TASK_XAUTH_REQUEST)) { exchange = TRANSACTION; + new_mid = TRUE; + break; } break; default: @@ -311,12 +315,12 @@ METHOD(task_manager_t, initiate, status_t, other = this->ike_sa->get_other_host(this->ike_sa); message = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); - if (exchange != ID_PROT) + if (new_mid) { this->rng->get_bytes(this->rng, sizeof(this->initiating.mid), (void*)&this->initiating.mid); - message->set_message_id(message, this->initiating.mid); } + message->set_message_id(message, this->initiating.mid); message->set_source(message, me->clone(me)); message->set_destination(message, other->clone(other)); message->set_exchange_type(message, exchange); From da063ec95e2877031cd202b16ad0e9c21325983e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 14:33:03 +0100 Subject: [PATCH 125/534] Fixed task_manager_v1 compiler warnings --- src/libcharon/sa/task_manager_v1.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 55bc8b7f9..cecb87902 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -16,9 +16,12 @@ #include "task_manager_v1.h" +#include + #include #include #include +#include typedef struct exchange_t exchange_t; @@ -190,10 +193,8 @@ METHOD(task_manager_t, retransmit, status_t, if (message_id == this->initiating.mid) { u_int32_t timeout; - job_t *job; - enumerator_t *enumerator; packet_t *packet; - task_t *task; + job_t *job; if (this->initiating.retransmitted <= this->retransmit_tries) { From d020d4d695c2d69ad5e29be2d97d6c33d89b9327 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 14:41:07 +0100 Subject: [PATCH 126/534] Print message payload names after prepending IKEv1 HASH payload --- src/libcharon/encoding/message.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index f53be0036..440b014c0 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1402,8 +1402,6 @@ METHOD(message_t, generate, status_t, order_payloads(this); } - DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); - if (this->major_version == IKEV2_MAJOR_VERSION) { encrypted = this->rule->encrypted; @@ -1438,6 +1436,8 @@ METHOD(message_t, generate, status_t, enumerator->destroy(enumerator); } + DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); + aead = keymat->get_aead(keymat, FALSE); if (aead && encrypted) { From f4e21faa989998974e198ecb2d33521c612e29bf Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 23 Nov 2011 15:23:20 +0100 Subject: [PATCH 127/534] Fixed encryption of IKEv2 messages. --- src/libcharon/encoding/message.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 440b014c0..aa774e0c3 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1505,7 +1505,8 @@ METHOD(message_t, generate, status_t, ike_header->destroy(ike_header); if (encryption) - { + { /* set_transform() has to be called before get_length() */ + encryption->set_transform(encryption, aead); if (this->is_encrypted) { /* for IKEv1 instead of associated data we provide the IV */ chunk = keymat_v1->get_iv(keymat_v1, this->message_id); @@ -1516,7 +1517,6 @@ METHOD(message_t, generate, status_t, /* fill in length, including encryption payload */ htoun32(lenpos, chunk.len + encryption->get_length(encryption)); } - encryption->set_transform(encryption, aead); this->payloads->insert_last(this->payloads, encryption); if (!encryption->encrypt(encryption, chunk)) { From 97265a8927c290466eb8899d99da9b3cf921969f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 23 Nov 2011 15:30:41 +0100 Subject: [PATCH 128/534] Removed redundant '=>' when logging binary data in parser and generator. --- src/libcharon/encoding/generator.c | 8 ++++---- src/libcharon/encoding/parser.c | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 2c9298e11..077648224 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -311,14 +311,14 @@ static void generate_u_int_type(private_generator_t *this, case CONFIGURATION_ATTRIBUTE_LENGTH: { u_int16_t val = htons(*((u_int16_t*)(this->data_struct + offset))); - DBG3(DBG_ENC, " => %b", &val, sizeof(u_int16_t)); + DBG3(DBG_ENC, " %b", &val, sizeof(u_int16_t)); write_bytes_to_buffer(this, &val, sizeof(u_int16_t)); break; } case U_INT_32: { u_int32_t val = htonl(*((u_int32_t*)(this->data_struct + offset))); - DBG3(DBG_ENC, " => %b", &val, sizeof(u_int32_t)); + DBG3(DBG_ENC, " %b", &val, sizeof(u_int32_t)); write_bytes_to_buffer(this, &val, sizeof(u_int32_t)); break; } @@ -327,7 +327,7 @@ static void generate_u_int_type(private_generator_t *this, /* 64 bit are written as-is, no host order conversion */ write_bytes_to_buffer(this, this->data_struct + offset, sizeof(u_int64_t)); - DBG3(DBG_ENC, " => %b", this->data_struct + offset, + DBG3(DBG_ENC, " %b", this->data_struct + offset, sizeof(u_int64_t)); break; } @@ -385,7 +385,7 @@ static void generate_from_chunk(private_generator_t *this, u_int32_t offset) } value = (chunk_t *)(this->data_struct + offset); - DBG3(DBG_ENC, " => %B", value); + DBG3(DBG_ENC, " %B", value); write_bytes_to_buffer(this, value->ptr, value->len); } diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index b93651bbe..3f4bb15a9 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -254,7 +254,7 @@ static bool parse_bytes(private_parser_t *this, int rule_number, if (output_pos) { memcpy(output_pos, this->byte_pos, bytes); - DBG3(DBG_ENC, " => %b", output_pos, bytes); + DBG3(DBG_ENC, " %b", output_pos, bytes); } this->byte_pos += bytes; return TRUE; @@ -352,7 +352,7 @@ static bool parse_chunk(private_parser_t *this, int rule_number, { *output_pos = chunk_alloc(length); memcpy(output_pos->ptr, this->byte_pos, length); - DBG3(DBG_ENC, " => %b", output_pos->ptr, length); + DBG3(DBG_ENC, " %b", output_pos->ptr, length); } this->byte_pos += length; return TRUE; From c4c5950458e7db16fe8cad16ab0cd153b4813263 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 23 Nov 2011 15:55:00 +0100 Subject: [PATCH 129/534] Create host-to-host traffic selectors if quick mode identities missing --- src/libcharon/sa/tasks/quick_mode.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 8586d9abf..0c4e18c1c 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -303,7 +303,7 @@ METHOD(task_t, process_r, status_t, payload_t *payload; linked_list_t *tsi, *tsr, *list; peer_cfg_t *peer_cfg; - host_t *me, *other; + host_t *me, *other, *host; enumerator_t *enumerator; bool first = TRUE; @@ -328,7 +328,18 @@ METHOD(task_t, process_r, status_t, } enumerator->destroy(enumerator); - /* TODO-IKEv1: create host2host TS if ID payloads missing */ + if (!this->tsi) + { + host = this->ike_sa->get_other_host(this->ike_sa); + this->tsi = traffic_selector_create_from_subnet(host->clone(host), + host->get_family(host) == AF_INET ? 32 : 128, 0, 0); + } + if (!this->tsr) + { + host = this->ike_sa->get_my_host(this->ike_sa); + this->tsr = traffic_selector_create_from_subnet(host->clone(host), + host->get_family(host) == AF_INET ? 32 : 128, 0, 0); + } me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); if (!me) @@ -471,6 +482,7 @@ METHOD(task_t, process_i, status_t, traffic_selector_t *tsi = NULL, *tsr = NULL; linked_list_t *list; enumerator_t *enumerator; + host_t *host; bool first = TRUE; enumerator = message->create_payload_enumerator(message); @@ -494,7 +506,18 @@ METHOD(task_t, process_i, status_t, } enumerator->destroy(enumerator); - /* TODO-IKEv1: create host2host TS if ID payloads missing */ + if (!tsr) + { + host = this->ike_sa->get_other_host(this->ike_sa); + tsr = traffic_selector_create_from_subnet(host->clone(host), + host->get_family(host) == AF_INET ? 32 : 128, 0, 0); + } + if (!tsi) + { + host = this->ike_sa->get_my_host(this->ike_sa); + tsi = traffic_selector_create_from_subnet(host->clone(host), + host->get_family(host) == AF_INET ? 32 : 128, 0, 0); + } if (!tsr->is_contained_in(tsr, this->tsr) || !tsi->is_contained_in(tsi, this->tsi)) From 78f7728c3041011f0b4aac89454774874b6a348b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 23 Nov 2011 16:08:40 +0100 Subject: [PATCH 130/534] No need to build a HASH payload in XAUTH task. It gets added automatically when the message is generated. --- src/libcharon/sa/tasks/xauth_request.c | 30 -------------------------- 1 file changed, 30 deletions(-) diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c index 60914beef..14ee75afd 100644 --- a/src/libcharon/sa/tasks/xauth_request.c +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -4,8 +4,6 @@ #include #include #include -#include -#include typedef struct private_xauth_request_t private_xauth_request_t; @@ -62,15 +60,6 @@ METHOD(task_t, build_i, status_t, { cp_payload_t *cp; chunk_t chunk = chunk_empty; - hash_payload_t *hash_payload; - generator_t *generator; - chunk_t attr_chunk; - chunk_t mid_chunk; - u_int32_t *lenpos; - u_int32_t message_id; - keymat_t *keymat; - prf_t *prf; - chunk_t hash_in, hash_out; DBG1(DBG_IKE, "BUILDING XAUTH REQUEST PACKET"); /* TODO1: Create ATTR payload */ @@ -79,25 +68,6 @@ METHOD(task_t, build_i, status_t, CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk)); cp->add_attribute(cp, configuration_attribute_create_chunk( CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk)); - - /* Create HASH payload */ - hash_payload = hash_payload_create(); - /* TODO1: Add data into the hash */ - - /* Calculate the chunk for the ATTR payload */ - generator = generator_create(); - cp->payload_interface.set_next_type(&cp->payload_interface, NO_PAYLOAD); - generator->generate_payload(generator, (payload_t *)cp); - attr_chunk = generator->get_chunk(generator, &lenpos); - - /* Get the message ID in network order */ - htoun32(&message_id, message->get_message_id(message)); - mid_chunk = chunk_from_thing(message_id); - - /* Get the hashed data */ - hash_in = chunk_cat("cc", mid_chunk, attr_chunk); - - message->add_payload(message, (payload_t *)hash_payload); message->add_payload(message, (payload_t *)cp); return NEED_MORE; From 818330aafed8cae07c3232d25e70b2a7eafe6766 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 09:51:40 +0100 Subject: [PATCH 131/534] Refactored NONCE payload handling in quick mode --- src/libcharon/sa/tasks/quick_mode.c | 95 +++++++++++++++-------------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 0c4e18c1c..70bde9086 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -197,6 +197,50 @@ static bool install(private_quick_mode_t *this) return TRUE; } +/** + * Generate and add NONCE + */ +static bool add_nonce(private_quick_mode_t *this, chunk_t *nonce, + message_t *message) +{ + nonce_payload_t *nonce_payload; + rng_t *rng; + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "no RNG found to create nonce"); + return FALSE; + } + rng->allocate_bytes(rng, NONCE_SIZE, nonce); + rng->destroy(rng); + + nonce_payload = nonce_payload_create(NONCE_V1); + nonce_payload->set_nonce(nonce_payload, *nonce); + message->add_payload(message, &nonce_payload->payload_interface); + + return TRUE; +} + +/** + * Extract nonce from NONCE payload + */ +static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce, + message_t *message) +{ + nonce_payload_t *nonce_payload; + + nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1); + if (!nonce_payload) + { + DBG1(DBG_IKE, "NONCE payload missing in message"); + return FALSE; + } + *nonce = nonce_payload->get_nonce(nonce_payload); + + return TRUE; +} + METHOD(task_t, build_i, status_t, private_quick_mode_t *this, message_t *message) { @@ -206,12 +250,10 @@ METHOD(task_t, build_i, status_t, { enumerator_t *enumerator; sa_payload_t *sa_payload; - nonce_payload_t *nonce_payload; id_payload_t *id_payload; traffic_selector_t *ts; linked_list_t *list; proposal_t *proposal; - rng_t *rng; this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), @@ -238,17 +280,10 @@ METHOD(task_t, build_i, status_t, list->destroy_offset(list, offsetof(proposal_t, destroy)); message->add_payload(message, &sa_payload->payload_interface); - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!add_nonce(this, &this->nonce_i, message)) { - DBG1(DBG_IKE, "no RNG found to create nonce"); return FAILED; } - rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_i); - rng->destroy(rng); - nonce_payload = nonce_payload_create(NONCE_V1); - nonce_payload->set_nonce(nonce_payload, this->nonce_i); - message->add_payload(message, &nonce_payload->payload_interface); list = this->config->get_traffic_selectors(this->config, TRUE, NULL, this->ike_sa->get_my_host(this->ike_sa)); @@ -276,13 +311,10 @@ METHOD(task_t, build_i, status_t, list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); message->add_payload(message, &id_payload->payload_interface); - /* TODO-IKEv1: Add HASH(1) */ - return NEED_MORE; } case QM_NEGOTIATED: { - /* TODO-IKEv1: Send HASH(3) */ return SUCCESS; } default: @@ -298,7 +330,6 @@ METHOD(task_t, process_r, status_t, case QM_INIT: { sa_payload_t *sa_payload; - nonce_payload_t *nonce_payload; id_payload_t *id_payload; payload_t *payload; linked_list_t *tsi, *tsr, *list; @@ -384,17 +415,10 @@ METHOD(task_t, process_r, status_t, } this->spi_i = this->proposal->get_spi(this->proposal); - nonce_payload = (nonce_payload_t*)message->get_payload(message, - NONCE_V1); - if (!nonce_payload) + if (!get_nonce(this, &this->nonce_i, message)) { - DBG1(DBG_IKE, "Nonce payload missing"); return FAILED; } - this->nonce_i = nonce_payload->get_nonce(nonce_payload); - - /* TODO-IKEv1: verify HASH(1) */ - this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), @@ -403,13 +427,10 @@ METHOD(task_t, process_r, status_t, } case QM_NEGOTIATED: { - /* TODO-IKEv1: verify HASH(3) */ - if (!install(this)) { return FAILED; } - return SUCCESS; } default: @@ -425,9 +446,7 @@ METHOD(task_t, build_r, status_t, case QM_INIT: { sa_payload_t *sa_payload; - nonce_payload_t *nonce_payload; id_payload_t *id_payload; - rng_t *rng; this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); if (!this->spi_r) @@ -441,25 +460,16 @@ METHOD(task_t, build_r, status_t, SECURITY_ASSOCIATION_V1, this->proposal); message->add_payload(message, &sa_payload->payload_interface); - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) + if (!add_nonce(this, &this->nonce_r, message)) { - DBG1(DBG_IKE, "no RNG found to create nonce"); return FAILED; } - rng->allocate_bytes(rng, NONCE_SIZE, &this->nonce_r); - rng->destroy(rng); - nonce_payload = nonce_payload_create(NONCE_V1); - nonce_payload->set_nonce(nonce_payload, this->nonce_r); - message->add_payload(message, &nonce_payload->payload_interface); id_payload = id_payload_create_from_ts(this->tsi); message->add_payload(message, &id_payload->payload_interface); id_payload = id_payload_create_from_ts(this->tsr); message->add_payload(message, &id_payload->payload_interface); - /* TODO-IKEv1: add HASH(2) */ - this->state = QM_NEGOTIATED; return NEED_MORE; } @@ -476,7 +486,6 @@ METHOD(task_t, process_i, status_t, case QM_INIT: { sa_payload_t *sa_payload; - nonce_payload_t *nonce_payload; id_payload_t *id_payload; payload_t *payload; traffic_selector_t *tsi = NULL, *tsr = NULL; @@ -550,22 +559,14 @@ METHOD(task_t, process_i, status_t, } this->spi_r = this->proposal->get_spi(this->proposal); - nonce_payload = (nonce_payload_t*)message->get_payload(message, - NONCE_V1); - if (!nonce_payload) + if (!get_nonce(this, &this->nonce_r, message)) { - DBG1(DBG_IKE, "Nonce payload missing"); return FAILED; } - this->nonce_r = nonce_payload->get_nonce(nonce_payload); - - /* TODO-IKEv1: verify HASH(2) */ - if (!install(this)) { return FAILED; } - this->state = QM_NEGOTIATED; return NEED_MORE; } From c4b8539f93a9f9f21288c890d9932a998ee526c7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 10:20:59 +0100 Subject: [PATCH 132/534] Refactored traffic selector handling in quick mode --- src/libcharon/sa/tasks/quick_mode.c | 265 +++++++++++++++------------- 1 file changed, 143 insertions(+), 122 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 70bde9086..0675fe4ed 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -241,6 +241,137 @@ static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce, return TRUE; } +/** + * Select a traffic selector from configuration + */ +static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator) +{ + traffic_selector_t *ts; + linked_list_t *list; + host_t *host; + + if (initiator) + { + host = this->ike_sa->get_my_host(this->ike_sa); + } + else + { + host = this->ike_sa->get_other_host(this->ike_sa); + } + list = this->config->get_traffic_selectors(this->config, initiator, + NULL, host); + if (list->get_first(list, (void**)&ts) == SUCCESS) + { + if (list->get_count(list) > 1) + { + DBG1(DBG_IKE, "configuration has more than one %s traffic selector," + " using first IKEv1", initiator ? "initiator" : "responder"); + } + ts = ts->clone(ts); + } + else + { + DBG1(DBG_IKE, "%s traffic selector missing in configuration", + initiator ? "initiator" : "responder"); + ts = NULL; + } + list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); + return ts; +} + +/** + * Add selected traffic selectors to message + */ +static void add_ts(private_quick_mode_t *this, message_t *message) +{ + id_payload_t *id_payload; + + id_payload = id_payload_create_from_ts(this->tsi); + message->add_payload(message, &id_payload->payload_interface); + id_payload = id_payload_create_from_ts(this->tsr); + message->add_payload(message, &id_payload->payload_interface); +} + +/** + * Get traffic selectors from received message + */ +static bool get_ts(private_quick_mode_t *this, message_t *message, + bool initiator) +{ + traffic_selector_t *tsi = NULL, *tsr = NULL; + enumerator_t *enumerator; + id_payload_t *id_payload; + payload_t *payload; + host_t *hsi, *hsr; + bool first = TRUE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == ID_V1) + { + id_payload = (id_payload_t*)payload; + + if (first) + { + tsi = id_payload->get_ts(id_payload); + first = FALSE; + } + else + { + tsr = id_payload->get_ts(id_payload); + break; + } + } + } + enumerator->destroy(enumerator); + + /* create host2host selectors if ID payloads missing */ + if (initiator) + { + hsi = this->ike_sa->get_my_host(this->ike_sa); + hsr = this->ike_sa->get_other_host(this->ike_sa); + } + else + { + hsr = this->ike_sa->get_my_host(this->ike_sa); + hsi = this->ike_sa->get_other_host(this->ike_sa); + } + if (!tsi) + { + tsi = traffic_selector_create_from_subnet(hsi->clone(hsi), + hsi->get_family(hsi) == AF_INET ? 32 : 128, 0, 0); + } + if (!tsr) + { + tsr = traffic_selector_create_from_subnet(hsr->clone(hsr), + hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0); + } + if (initiator) + { + /* check if peer selection valid */ + if (!tsr->is_contained_in(tsr, this->tsr) || + !tsi->is_contained_in(tsi, this->tsi)) + { + DBG1(DBG_IKE, "peer selected invalid traffic selectors: ", + "%R for %R, %R for %R", tsi, this->tsi, tsr, this->tsr); + tsi->destroy(tsi); + tsr->destroy(tsr); + return FALSE; + } + this->tsi->destroy(this->tsi); + this->tsr->destroy(this->tsr); + this->tsi = tsi; + this->tsr = tsr; + } + else + { + this->tsi = tsi; + this->tsr = tsr; + } + return TRUE; +} + METHOD(task_t, build_i, status_t, private_quick_mode_t *this, message_t *message) { @@ -250,8 +381,6 @@ METHOD(task_t, build_i, status_t, { enumerator_t *enumerator; sa_payload_t *sa_payload; - id_payload_t *id_payload; - traffic_selector_t *ts; linked_list_t *list; proposal_t *proposal; @@ -284,33 +413,13 @@ METHOD(task_t, build_i, status_t, { return FAILED; } - - list = this->config->get_traffic_selectors(this->config, TRUE, NULL, - this->ike_sa->get_my_host(this->ike_sa)); - if (list->get_first(list, (void**)&ts) != SUCCESS) + this->tsi = select_ts(this, TRUE); + this->tsr = select_ts(this, FALSE); + if (!this->tsi || !this->tsr) { - list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); - DBG1(DBG_IKE, "traffic selector missing"); return FAILED; } - id_payload = id_payload_create_from_ts(ts); - this->tsi = ts->clone(ts); - list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); - message->add_payload(message, &id_payload->payload_interface); - - list = this->config->get_traffic_selectors(this->config, FALSE, NULL, - this->ike_sa->get_other_host(this->ike_sa)); - if (list->get_first(list, (void**)&ts) != SUCCESS) - { - list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); - DBG1(DBG_IKE, "traffic selector missing"); - return FAILED; - } - id_payload = id_payload_create_from_ts(ts); - this->tsr = ts->clone(ts); - list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); - message->add_payload(message, &id_payload->payload_interface); - + add_ts(this, message); return NEED_MORE; } case QM_NEGOTIATED: @@ -330,48 +439,14 @@ METHOD(task_t, process_r, status_t, case QM_INIT: { sa_payload_t *sa_payload; - id_payload_t *id_payload; - payload_t *payload; linked_list_t *tsi, *tsr, *list; peer_cfg_t *peer_cfg; - host_t *me, *other, *host; - enumerator_t *enumerator; - bool first = TRUE; + host_t *me, *other; - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) + if (!get_ts(this, message, FALSE)) { - if (payload->get_type(payload) == ID_V1) - { - id_payload = (id_payload_t*)payload; - - if (first) - { - this->tsi = id_payload->get_ts(id_payload); - first = FALSE; - } - else - { - this->tsr = id_payload->get_ts(id_payload); - break; - } - } + return FAILED; } - enumerator->destroy(enumerator); - - if (!this->tsi) - { - host = this->ike_sa->get_other_host(this->ike_sa); - this->tsi = traffic_selector_create_from_subnet(host->clone(host), - host->get_family(host) == AF_INET ? 32 : 128, 0, 0); - } - if (!this->tsr) - { - host = this->ike_sa->get_my_host(this->ike_sa); - this->tsr = traffic_selector_create_from_subnet(host->clone(host), - host->get_family(host) == AF_INET ? 32 : 128, 0, 0); - } - me = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); if (!me) { @@ -446,7 +521,6 @@ METHOD(task_t, build_r, status_t, case QM_INIT: { sa_payload_t *sa_payload; - id_payload_t *id_payload; this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); if (!this->spi_r) @@ -464,11 +538,7 @@ METHOD(task_t, build_r, status_t, { return FAILED; } - - id_payload = id_payload_create_from_ts(this->tsi); - message->add_payload(message, &id_payload->payload_interface); - id_payload = id_payload_create_from_ts(this->tsr); - message->add_payload(message, &id_payload->payload_interface); + add_ts(this, message); this->state = QM_NEGOTIATED; return NEED_MORE; @@ -486,60 +556,7 @@ METHOD(task_t, process_i, status_t, case QM_INIT: { sa_payload_t *sa_payload; - id_payload_t *id_payload; - payload_t *payload; - traffic_selector_t *tsi = NULL, *tsr = NULL; linked_list_t *list; - enumerator_t *enumerator; - host_t *host; - bool first = TRUE; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == ID_V1) - { - id_payload = (id_payload_t*)payload; - - if (first) - { - tsi = id_payload->get_ts(id_payload); - first = FALSE; - } - else - { - tsr = id_payload->get_ts(id_payload); - break; - } - } - } - enumerator->destroy(enumerator); - - if (!tsr) - { - host = this->ike_sa->get_other_host(this->ike_sa); - tsr = traffic_selector_create_from_subnet(host->clone(host), - host->get_family(host) == AF_INET ? 32 : 128, 0, 0); - } - if (!tsi) - { - host = this->ike_sa->get_my_host(this->ike_sa); - tsi = traffic_selector_create_from_subnet(host->clone(host), - host->get_family(host) == AF_INET ? 32 : 128, 0, 0); - } - - if (!tsr->is_contained_in(tsr, this->tsr) || - !tsi->is_contained_in(tsi, this->tsi)) - { - tsi->destroy(tsi); - tsr->destroy(tsr); - DBG1(DBG_IKE, "TS mismatch"); - return FAILED; - } - this->tsi->destroy(this->tsi); - this->tsr->destroy(this->tsr); - this->tsi = tsi; - this->tsr = tsr; sa_payload = (sa_payload_t*)message->get_payload(message, SECURITY_ASSOCIATION_V1); @@ -563,6 +580,10 @@ METHOD(task_t, process_i, status_t, { return FAILED; } + if (!get_ts(this, message, TRUE)) + { + return FAILED; + } if (!install(this)) { return FAILED; From 4e0bc9af229d31e481da1000fc3231ce8a59a505 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 10:28:49 +0100 Subject: [PATCH 133/534] Add quick mode ID payloads only if establishing a non-host2host tunnel --- src/libcharon/sa/tasks/quick_mode.c | 37 +++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 0675fe4ed..2a12e671d 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -282,14 +282,37 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator) /** * Add selected traffic selectors to message */ -static void add_ts(private_quick_mode_t *this, message_t *message) +static void add_ts(private_quick_mode_t *this, message_t *message, + bool initiator) { id_payload_t *id_payload; + host_t *hsi, *hsr; - id_payload = id_payload_create_from_ts(this->tsi); - message->add_payload(message, &id_payload->payload_interface); - id_payload = id_payload_create_from_ts(this->tsr); - message->add_payload(message, &id_payload->payload_interface); + if (initiator) + { + hsi = this->ike_sa->get_my_host(this->ike_sa); + hsr = this->ike_sa->get_other_host(this->ike_sa); + } + else + { + hsr = this->ike_sa->get_my_host(this->ike_sa); + hsi = this->ike_sa->get_other_host(this->ike_sa); + } + /* add ID payload only if negotiating non host2host tunnels */ + if (!this->tsi->is_host(this->tsi, hsi) || + !this->tsr->is_host(this->tsr, hsr) || + this->tsi->get_protocol(this->tsi) || + this->tsr->get_protocol(this->tsr) || + this->tsi->get_from_port(this->tsi) || + this->tsr->get_from_port(this->tsr) || + this->tsi->get_to_port(this->tsi) != 65535 || + this->tsr->get_to_port(this->tsr) != 65535) + { + id_payload = id_payload_create_from_ts(this->tsi); + message->add_payload(message, &id_payload->payload_interface); + id_payload = id_payload_create_from_ts(this->tsr); + message->add_payload(message, &id_payload->payload_interface); + } } /** @@ -419,7 +442,7 @@ METHOD(task_t, build_i, status_t, { return FAILED; } - add_ts(this, message); + add_ts(this, message, TRUE); return NEED_MORE; } case QM_NEGOTIATED: @@ -538,7 +561,7 @@ METHOD(task_t, build_r, status_t, { return FAILED; } - add_ts(this, message); + add_ts(this, message, FALSE); this->state = QM_NEGOTIATED; return NEED_MORE; From 9cc38c8efb4e0f0e7354a62c1e42e0eba04248c1 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 10:33:43 +0100 Subject: [PATCH 134/534] Use quick mode task initiator flag instead of passing it as parameter --- src/libcharon/sa/tasks/quick_mode.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 2a12e671d..eb9312d2b 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -265,7 +265,7 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator) if (list->get_count(list) > 1) { DBG1(DBG_IKE, "configuration has more than one %s traffic selector," - " using first IKEv1", initiator ? "initiator" : "responder"); + " using first only", initiator ? "initiator" : "responder"); } ts = ts->clone(ts); } @@ -282,13 +282,12 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator) /** * Add selected traffic selectors to message */ -static void add_ts(private_quick_mode_t *this, message_t *message, - bool initiator) +static void add_ts(private_quick_mode_t *this, message_t *message) { id_payload_t *id_payload; host_t *hsi, *hsr; - if (initiator) + if (this->initiator) { hsi = this->ike_sa->get_my_host(this->ike_sa); hsr = this->ike_sa->get_other_host(this->ike_sa); @@ -318,8 +317,7 @@ static void add_ts(private_quick_mode_t *this, message_t *message, /** * Get traffic selectors from received message */ -static bool get_ts(private_quick_mode_t *this, message_t *message, - bool initiator) +static bool get_ts(private_quick_mode_t *this, message_t *message) { traffic_selector_t *tsi = NULL, *tsr = NULL; enumerator_t *enumerator; @@ -350,7 +348,7 @@ static bool get_ts(private_quick_mode_t *this, message_t *message, enumerator->destroy(enumerator); /* create host2host selectors if ID payloads missing */ - if (initiator) + if (this->initiator) { hsi = this->ike_sa->get_my_host(this->ike_sa); hsr = this->ike_sa->get_other_host(this->ike_sa); @@ -370,7 +368,7 @@ static bool get_ts(private_quick_mode_t *this, message_t *message, tsr = traffic_selector_create_from_subnet(hsr->clone(hsr), hsr->get_family(hsr) == AF_INET ? 32 : 128, 0, 0); } - if (initiator) + if (this->initiator) { /* check if peer selection valid */ if (!tsr->is_contained_in(tsr, this->tsr) || @@ -442,7 +440,7 @@ METHOD(task_t, build_i, status_t, { return FAILED; } - add_ts(this, message, TRUE); + add_ts(this, message); return NEED_MORE; } case QM_NEGOTIATED: @@ -466,7 +464,7 @@ METHOD(task_t, process_r, status_t, peer_cfg_t *peer_cfg; host_t *me, *other; - if (!get_ts(this, message, FALSE)) + if (!get_ts(this, message)) { return FAILED; } @@ -561,7 +559,7 @@ METHOD(task_t, build_r, status_t, { return FAILED; } - add_ts(this, message, FALSE); + add_ts(this, message); this->state = QM_NEGOTIATED; return NEED_MORE; @@ -603,7 +601,7 @@ METHOD(task_t, process_i, status_t, { return FAILED; } - if (!get_ts(this, message, TRUE)) + if (!get_ts(this, message)) { return FAILED; } From adf7b76f4c7e01963ab0fac1f7e2456d501a55fc Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 11:12:59 +0100 Subject: [PATCH 135/534] IKEv1 XAuth: Temporarilty add an "initiate_later" flag to the task manager. When set to TRUE it will cause "initiate" to be called when the current process_response call is finished. This change should be reverted once we have a better method in place. --- src/libcharon/sa/task_manager.h | 5 +++++ src/libcharon/sa/task_manager_v1.c | 27 ++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 42a04fb64..f0a1921c0 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -192,6 +192,11 @@ struct task_manager_t { * Destroy the task_manager_t. */ void (*destroy) (task_manager_t *this); + + /** + * Signals the task manager to initiate immediately after completing a response + */ + void (*initiate_later) (task_manager_t *this); }; /** diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index cecb87902..13d95b4fa 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -144,6 +144,11 @@ struct private_task_manager_t { * Base to calculate retransmission timeout */ double retransmit_base; + + /** + * Signal to the task manager that we need to initiate a transaction after the response is sent. + */ + bool initiate_later_flag; }; /** @@ -297,6 +302,10 @@ METHOD(task_manager_t, initiate, status_t, case TASK_QUICK_MODE: exchange = QUICK_MODE; break; + case TASK_XAUTH_REQUEST: + exchange = TRANSACTION; + new_mid = TRUE; + break; default: continue; } @@ -477,6 +486,7 @@ static status_t process_request(private_task_manager_t *this, { enumerator_t *enumerator; task_t *task = NULL; + status_t process_status; if (this->passive_tasks->get_count(this->passive_tasks) == 0) { /* create tasks depending on request type, if not already some queued */ @@ -530,7 +540,14 @@ static status_t process_request(private_task_manager_t *this, } enumerator->destroy(enumerator); - return build_response(this, message); + process_status = build_response(this, message); + + if(((process_status == SUCCESS) || (process_status == NEED_MORE)) && (this->initiate_later_flag == TRUE)) + { + this->initiate_later_flag = FALSE; + return initiate(this); + } + return process_status; } /** @@ -704,6 +721,12 @@ METHOD(task_manager_t, destroy, void, free(this); } +METHOD(task_manager_t, initiate_later, void, + private_task_manager_t *this) +{ + this->initiate_later_flag = TRUE; +} + /* * see header file */ @@ -724,6 +747,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .busy = _busy, .create_task_enumerator = _create_task_enumerator, .destroy = _destroy, + .initiate_later = _initiate_later, }, }, .ike_sa = ike_sa, @@ -738,6 +762,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) "charon.retransmit_timeout", RETRANSMIT_TIMEOUT), .retransmit_base = lib->settings->get_double(lib->settings, "charon.retransmit_base", RETRANSMIT_BASE), + .initiate_later_flag = FALSE, ); return &this->public; From e3bb68841a3a441d6770ec76ae14176b71f70495 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 11:21:43 +0100 Subject: [PATCH 136/534] IKEv1 XAuth: Added temporary "initiate_xauth" public method to ike_sa_t. This allows us to initiate an XAuth password authentication exchange after responding to the final message of Main Mode. This change should be reverted once we have a better method to initiate this exchange. --- src/libcharon/sa/ike_sa.c | 13 +++++++++++++ src/libcharon/sa/ike_sa.h | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 6be8471f2..088fd0ab5 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -2129,6 +2129,18 @@ METHOD(ike_sa_t, destroy, void, free(this); } +METHOD(ike_sa_t, initiate_xauth, void, + private_ike_sa_t *this) +{ + if(this->extensions & EXT_XAUTH) + { + xauth_request_t *xauth_request_task = xauth_request_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, (task_t*)xauth_request_task); + + this->task_manager->initiate_later(this->task_manager); + } +} + /* * Described in header. */ @@ -2218,6 +2230,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .callback = _callback, .respond = _respond, #endif /* ME */ + .initiate_xauth = _initiate_xauth, }, .ike_sa_id = ike_sa_id->clone(ike_sa_id), .version = version, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 2753fca1c..f21585525 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -958,6 +958,11 @@ struct ike_sa_t { * Destroys a ike_sa_t object. */ void (*destroy) (ike_sa_t *this); + + /** + * Initiate an XAuth transaction + */ + void (*initiate_xauth) (ike_sa_t *this); }; /** From 01685247b0ea9666793c80b28879d6866a333be1 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 11:26:04 +0100 Subject: [PATCH 137/534] IKEv1 XAuth: Added ike_vendor task to the ID_PROT exchange type processing. We need to process vendor payloads to check to see if our peer understands XAuth before using any of these payload types. --- src/libcharon/sa/task_manager_v1.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 13d95b4fa..32f847f8a 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -493,6 +494,8 @@ static status_t process_request(private_task_manager_t *this, switch (message->get_exchange_type(message)) { case ID_PROT: + task = (task_t *)ike_vendor_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); break; From 0b6811b4a7a26176b8fc102ef6ee398edaa289cb Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 11:30:19 +0100 Subject: [PATCH 138/534] IKEv1 ConfigMode: Fixed cp_payload to use CONFIGURATION_ATTRIBUTE_V1 in all appropriate places, so the parsing is done correctly. --- src/libcharon/encoding/generator.c | 1 + src/libcharon/encoding/parser.c | 1 + src/libcharon/encoding/payloads/cp_payload.c | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 077648224..43b157cc1 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -459,6 +459,7 @@ METHOD(generator_t, generate_payload, void, case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE: case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1: case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1: case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE: { linked_list_t *proposals; diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 3f4bb15a9..14e2cc7a0 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -493,6 +493,7 @@ METHOD(parser_t, parse_payload, status_t, case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE: case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1: case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1: case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE: { if (payload_length < header_length || diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c index 9ecb15006..c8cffa3f7 100644 --- a/src/libcharon/encoding/payloads/cp_payload.c +++ b/src/libcharon/encoding/payloads/cp_payload.c @@ -152,7 +152,7 @@ static encoding_rule_t encodings_v1[] = { { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, { U_INT_16, offsetof(private_cp_payload_t, identifier)}, /* list of configuration attributes in a list */ - { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE, + { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1, offsetof(private_cp_payload_t, attributes) }, }; From ece4ed3fcda19e4a8e4c3d017e0f270c5dd62593 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 11:33:38 +0100 Subject: [PATCH 139/534] IKEv1 ConfigMode: Fix configuration_attribute encoding rules for IKEv1 to use the attribute type instead of the internal only payload type. --- src/libcharon/encoding/payloads/configuration_attribute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index 58173077d..fe2e42bc4 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -99,7 +99,7 @@ static encoding_rule_t encodings_v1[] = { /* AF Flag */ { FLAG, offsetof(private_configuration_attribute_t, af_flag) }, /* type of the attribute as 15 bit unsigned integer */ - { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, type) }, + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, /* Length of attribute value */ { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_configuration_attribute_t, length_or_value)}, /* Value of attribute if attribute format flag is zero */ From 8b30286fcf99707dfd22601877c7b30c661ce4a2 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 11:37:36 +0100 Subject: [PATCH 140/534] IKEv1 XAuth: Add XAUTH authentication types to the enum. Added the ability to switch between hardcoded PSK and XAUTH_INIT_PSK authentications using a flag, default to PSK. --- .../encoding/payloads/proposal_substructure.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 6173d07db..924f5cb48 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -237,6 +237,16 @@ typedef enum { IKEV1_AUTH_RSA_SIG = 3, IKEV1_AUTH_RSA_ENC = 4, IKEV1_AUTH_RSA_ENC_REV = 5, + IKEV1_AUTH_XAUTH_INIT_PSK = 65001, + IKEV1_AUTH_XAUTH_RESP_PSK = 65002, + IKEV1_AUTH_XAUTH_INIT_DSS = 65003, + IKEV1_AUTH_XAUTH_RESP_DSS = 65004, + IKEV1_AUTH_XAUTH_INIT_RSA = 65005, + IKEV1_AUTH_XAUTH_RESP_RSA = 65006, + IKEV1_AUTH_XAUTH_INIT_RSA_ENC = 65007, + IKEV1_AUTH_XAUTH_RESP_RSA_ENC = 65008, + IKEV1_AUTH_XAUTH_INIT_RSA_ENC_REV = 65009, + IKEV1_AUTH_XAUTH_RESP_RSA_ENC_REV = 65010, } ikev1_auth_method_t; METHOD(payload_t, verify, status_t, @@ -813,9 +823,16 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, enumerator->destroy(enumerator); /* TODO-IKEv1: Add lifetime, non-fixed auth-method and other attributes */ + if(1) /* TODO-IKEv1: Change to 0 if XAUTH is desired. */ + { transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_PSK)); + }else{ + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_XAUTH_INIT_PSK)); + } transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH1_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); From 2d97ec0d35eedacd1633e61cd7825f6dd546f3c0 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 11:40:55 +0100 Subject: [PATCH 141/534] IKEv1 XAuth: Added ability to initiate the XAuth transactions under a flag, default not to initiate XAuth. --- src/libcharon/sa/tasks/main_mode.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index c02095ac2..d3d1cbe87 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -611,7 +611,6 @@ METHOD(task_t, build_r, status_t, build_hash(this, FALSE, message, id); - /* TODO-IKEv1: check for XAUTH rounds, queue them */ DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa), @@ -621,6 +620,11 @@ METHOD(task_t, build_r, status_t, this->ike_sa->get_other_id(this->ike_sa)); this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + /* TODO-IKEv1: Check the proposal for XAuthInit* auth modes */ + /* TODO-IKEv1: check for XAUTH rounds, queue them */ + if(0) /* TODO-IKEv1: Change to 1 if XAUTH is desired. */ + this->ike_sa->initiate_xauth(this->ike_sa); return SUCCESS; } default: From cc50df9e6c951318955df7d95786c7dbe79d9489 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 11:46:02 +0100 Subject: [PATCH 142/534] IKEv1 XAuth: XAuthInitPreShared working for XAuth initiator (Main Mode responder). Creates USER/PASS request, retrieves the result and sends status. --- src/libcharon/sa/tasks/xauth_request.c | 138 ++++++++++++++++++++++--- 1 file changed, 123 insertions(+), 15 deletions(-) diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c index 14ee75afd..09ddb90f4 100644 --- a/src/libcharon/sa/tasks/xauth_request.c +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -7,6 +7,11 @@ typedef struct private_xauth_request_t private_xauth_request_t; +enum { + XAUTH_STATUS_FAIL = 0, + XAUTH_STATUS_OK = 1, +}; + /** * Private members of a xauth_request_t task. */ @@ -36,6 +41,29 @@ struct private_xauth_request_t { * list of attributes requested and its handler, entry_t */ linked_list_t *requested; + + /** + * The user name + */ + chunk_t user_name; + + /** + * The user pass + */ + chunk_t user_pass; + + /** + * The current state of the task + */ + enum { + TASK_XAUTH_INIT, + TASK_XAUTH_PASS_DONE, + } state; + + /** + * The status of the XAuth request + */ + status_t status; }; /** @@ -48,28 +76,35 @@ typedef struct { attribute_handler_t *handler; } entry_t; -/** - * Scan for configuration payloads and attributes - */ -static void process_payloads(private_xauth_request_t *this, message_t *message) -{ -} - METHOD(task_t, build_i, status_t, private_xauth_request_t *this, message_t *message) { cp_payload_t *cp; chunk_t chunk = chunk_empty; - DBG1(DBG_IKE, "BUILDING XAUTH REQUEST PACKET"); - /* TODO1: Create ATTR payload */ - cp = cp_payload_create(CONFIGURATION_V1); - cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk)); - cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk)); + switch(this->state) + { + case TASK_XAUTH_INIT: + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk)); + break; + case TASK_XAUTH_PASS_DONE: + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET); + cp->add_attribute(cp, configuration_attribute_create_value( + XAUTH_STATUS, + (this->status == FAILED ? XAUTH_STATUS_FAIL : XAUTH_STATUS_OK))); + break; + default: + return FAILED; + + } + /* Add the payloads into the message */ message->add_payload(message, (payload_t *)cp); + return NEED_MORE; } @@ -88,7 +123,77 @@ METHOD(task_t, build_r, status_t, METHOD(task_t, process_i, status_t, private_xauth_request_t *this, message_t *message) { - return NEED_MORE; + cp_payload_t *cp_payload; + enumerator_t *enumerator; + configuration_attribute_t *ca; + chunk_t status_chunk = chunk_empty; + + cp_payload = (cp_payload_t *)message->get_payload(message, CONFIGURATION_V1); + enumerator = cp_payload->create_attribute_enumerator(cp_payload); + while (enumerator->enumerate(enumerator, &ca)) + { + switch(ca->get_type(ca)) + { + case XAUTH_USER_NAME: + this->user_name = ca->get_chunk(ca); + break; + case XAUTH_USER_PASSWORD: + this->user_pass = ca->get_chunk(ca); + break; + case XAUTH_STATUS: + status_chunk = ca->get_chunk(ca); + break; + default: + DBG3(DBG_IKE, "Unknown config attribute type %d, ignored", ca->get_type(ca)); + } + } + enumerator->destroy(enumerator); + + switch(this->state) + { + case TASK_XAUTH_INIT: + + if(cp_payload->get_type(cp_payload) != CFG_REPLY) + { + DBG1(DBG_IKE, "ERROR: ConfigMode payload is not a reply"); + return FAILED; + } + + this->state = TASK_XAUTH_PASS_DONE; + if((this->user_name.len == 0) || (this->user_pass.len == 0)) + { + DBG1(DBG_IKE, "ERROR: Did not get user name or user pass, aborting"); + this->status = FAILED; + /* We should close out the XAuth negotiation cleanly by sending a "failed" message */ + return NEED_MORE; + } + + /* TODO-IKEv1: Do actual user/pass verification */ +// if(!chunk_compare(this->user_name, this->user_pass)) +// { +// this->status = FAILED; +// DBG1(DBG_IKE, "ERROR: user/pass verification failure"); + /* We should close out the XAuth negotiation cleanly by sending a "failed" message */ +// return NEED_MORE; +// } + + this->status = SUCCESS; + return NEED_MORE; + case TASK_XAUTH_PASS_DONE: + if(cp_payload->get_type(cp_payload) != CFG_ACK) + { + DBG1(DBG_IKE, "ERROR: ConfigMode payload is not a status ack"); + return FAILED; + } + if(status_chunk.len != 0) + { + DBG1(DBG_IKE, "Status payload of an ack had data, hmm...."); + } + + DBG1(DBG_IKE, "Done with XAUTH!!!"); + return this->status; + } + return FAILED; } METHOD(task_t, get_type, task_type_t, @@ -134,6 +239,9 @@ xauth_request_t *xauth_request_create(ike_sa_t *ike_sa, bool initiator) .initiator = initiator, .ike_sa = ike_sa, .requested = linked_list_create(), + .user_name = chunk_empty, + .user_pass = chunk_empty, + .state = TASK_XAUTH_INIT, ); if (initiator) From 46897273d76c9f1cfa4fa6f2184adb5e84f01836 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 16:35:22 +0100 Subject: [PATCH 143/534] IKEv1 XAuth: Added new "swap_initiator" method to the standard task_t interface. This is needed for when we move a task from the passive queue to the active one. I'm not a huge fan of this method of doing things. Perhaps we should change task_t to have build_i, build_r, process_i, and process_r methods, and call the appropriate one from the task manager, since we have these methods for most tasks anyways. --- src/libcharon/sa/tasks/task.h | 5 +++++ src/libcharon/sa/tasks/xauth_request.c | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index ad41bae7f..eebfb7a57 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -151,6 +151,11 @@ struct task_t { * Destroys a task_t object. */ void (*destroy) (task_t *this); + + /** + * Swaps the initiator flag in a task (if applicable, NULL OK) + */ + void (*swap_initiator) (task_t *this); }; #endif /** TASK_H_ @}*/ diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c index 09ddb90f4..0a35889e1 100644 --- a/src/libcharon/sa/tasks/xauth_request.c +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -221,6 +221,23 @@ METHOD(task_t, destroy, void, free(this); } +METHOD(task_t, swap_initiator, void, + private_xauth_request_t *this) +{ + if(this->initiator) + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + this->initiator = FALSE; + } + else + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + this->initiator = TRUE; + } +} + /* * Described in header. */ @@ -234,6 +251,7 @@ xauth_request_t *xauth_request_create(ike_sa_t *ike_sa, bool initiator) .get_type = _get_type, .migrate = _migrate, .destroy = _destroy, + .swap_initiator = _swap_initiator, }, }, .initiator = initiator, From b94f248ea967aef936db3a323134c030b4f05add Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 16:48:41 +0100 Subject: [PATCH 144/534] IKEv1 XAuth: Added new MIGRATE status type to status_t. When a task returns this status from a build or process method, it is a signal to the task manager that it should treat it as if the task returned SUCCESS. Additionally it will migrate all remaining tasks from the current queue to a different one, calling swap_initiator for each applicable task. Finally, the task manager will call "initiate", if applicable, to kick off tasks in the "queued_tasks" queue. Task queue relocation mapping: passive_tasks moves to queued_tasks (which is then fed to active by the initiate call). active_tasks moves to passive_tasks --- src/libcharon/sa/task_manager_v1.c | 48 ++++++++++++++++++++++++++++++ src/libstrongswan/utils.h | 6 ++++ 2 files changed, 54 insertions(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 32f847f8a..d5474d962 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -234,6 +234,25 @@ METHOD(task_manager_t, retransmit, status_t, return SUCCESS; } +void migrate_tasks(linked_list_t *from, linked_list_t *to) +{ + enumerator_t *enumerator; + task_t *task; + + enumerator = from->create_enumerator(from); + while(enumerator->enumerate(enumerator, (void**)&task)) + { + DBG4(DBG_IKE, " Migrating %N task to new queue", task_type_names, task->get_type(task)); + if(task->swap_initiator) + { + task->swap_initiator(task); + } + to->insert_last(to, task); + from->remove_at(from, enumerator); + } + enumerator->destroy(enumerator); +} + METHOD(task_manager_t, initiate, status_t, private_task_manager_t *this) { @@ -348,6 +367,13 @@ METHOD(task_manager_t, initiate, status_t, this->active_tasks->remove_at(this->active_tasks, enumerator); task->destroy(task); break; + case MIGRATE: + /* task completed, remove it */ + this->active_tasks->remove_at(this->active_tasks, enumerator); + task->destroy(task); + /* migrate the remaining active tasks to the passive queue */ + migrate_tasks(this->active_tasks, this->passive_tasks); + break; case NEED_MORE: /* processed, but task needs another exchange */ break; @@ -409,6 +435,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) host_t *me, *other; bool delete = FALSE; status_t status; + bool migrate = FALSE; me = request->get_destination(request); other = request->get_source(request); @@ -426,6 +453,9 @@ static status_t build_response(private_task_manager_t *this, message_t *request) { switch (task->build(task, message)) { + case MIGRATE: + migrate = TRUE; + /* FALL */ case SUCCESS: /* task completed, remove it */ this->passive_tasks->remove_at(this->passive_tasks, enumerator); @@ -472,6 +502,14 @@ static status_t build_response(private_task_manager_t *this, message_t *request) charon->sender->send(charon->sender, this->responding.packet->clone(this->responding.packet)); + + if (migrate) + { + migrate_tasks(this->passive_tasks, this->queued_tasks); + /* Kick off the newly installed tasks */ + initiate(this); + } + if (delete) { return DESTROY_ME; @@ -526,6 +564,16 @@ static status_t process_request(private_task_manager_t *this, task->destroy(task); enumerator->destroy(enumerator); return SUCCESS; + case MIGRATE: + /* task completed, remove it */ + this->passive_tasks->remove_at(this->passive_tasks, enumerator); + task->destroy(task); + enumerator->destroy(enumerator); + /* migrate the remaining tasks */ + migrate_tasks(this->passive_tasks, this->queued_tasks); + /* Kick off the newly installed tasks */ + initiate(this); + return SUCCESS; case NEED_MORE: /* processed, but task needs at least another call to build() */ break; diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h index 0f06fec6a..f98de4139 100644 --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -299,6 +299,12 @@ enum status_t { * Another call to the method is required. */ NEED_MORE, + + /** + * For tasks only, same as SUCCESS, but also migrate all remaining tasks + * in the current queue to the opposite queue (passive->active or active->passive) + */ + MIGRATE, }; /** From b03c700d08aed1b29f02867608f9bc0037d2ae8f Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 24 Nov 2011 16:57:10 +0100 Subject: [PATCH 145/534] IKEv1 XAuth: Changed the xauth_request task to use the new MIGRATE status. --- src/libcharon/sa/task_manager_v1.c | 3 +++ src/libcharon/sa/tasks/main_mode.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index d5474d962..2b22bcdb5 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -22,6 +22,7 @@ #include #include #include +#include #include typedef struct exchange_t exchange_t; @@ -536,6 +537,8 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t *)xauth_request_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); break; case AGGRESSIVE: /* TODO-IKEv1: agressive mode */ diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index d3d1cbe87..f59276714 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -624,7 +624,7 @@ METHOD(task_t, build_r, status_t, /* TODO-IKEv1: Check the proposal for XAuthInit* auth modes */ /* TODO-IKEv1: check for XAUTH rounds, queue them */ if(0) /* TODO-IKEv1: Change to 1 if XAUTH is desired. */ - this->ike_sa->initiate_xauth(this->ike_sa); + return MIGRATE; return SUCCESS; } default: From d08269c700d19bc362e6bd070abf69e87c42f025 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 11:38:37 +0100 Subject: [PATCH 146/534] Added a get_rekey/reauth_time() jitter parameter to get time without randomization --- src/libcharon/config/peer_cfg.c | 8 ++++---- src/libcharon/config/peer_cfg.h | 10 ++++++---- src/libcharon/sa/ike_sa.c | 4 ++-- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index 73b5f5f9f..fbdfa25e2 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -341,13 +341,13 @@ METHOD(peer_cfg_t, get_keyingtries, u_int32_t, } METHOD(peer_cfg_t, get_rekey_time, u_int32_t, - private_peer_cfg_t *this) + private_peer_cfg_t *this, bool jitter) { if (this->rekey_time == 0) { return 0; } - if (this->jitter_time == 0) + if (this->jitter_time == 0 || !jitter) { return this->rekey_time; } @@ -355,13 +355,13 @@ METHOD(peer_cfg_t, get_rekey_time, u_int32_t, } METHOD(peer_cfg_t, get_reauth_time, u_int32_t, - private_peer_cfg_t *this) + private_peer_cfg_t *this, bool jitter) { if (this->reauth_time == 0) { return 0; } - if (this->jitter_time == 0) + if (this->jitter_time == 0 || !jitter) { return this->reauth_time; } diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index 6096f6413..33309d116 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -227,18 +227,20 @@ struct peer_cfg_t { u_int32_t (*get_keyingtries) (peer_cfg_t *this); /** - * Get a time to start rekeying (is randomized with jitter). + * Get a time to start rekeying. * + * @param jitter remove a jitter value to randomize time * @return time in s when to start rekeying, 0 disables rekeying */ - u_int32_t (*get_rekey_time)(peer_cfg_t *this); + u_int32_t (*get_rekey_time)(peer_cfg_t *this, bool jitter); /** - * Get a time to start reauthentication (is randomized with jitter). + * Get a time to start reauthentication. * + * @param jitter remove a jitter value to randomize time * @return time in s when to start reauthentication, 0 disables it */ - u_int32_t (*get_reauth_time)(peer_cfg_t *this); + u_int32_t (*get_reauth_time)(peer_cfg_t *this, bool jitter); /** * Get the timeout of a rekeying/reauthenticating SA. diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 088fd0ab5..b789424c0 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -642,7 +642,7 @@ METHOD(ike_sa_t, set_state, void, /* schedule rekeying if we have a time which is smaller than * an already scheduled rekeying */ - t = this->peer_cfg->get_rekey_time(this->peer_cfg); + t = this->peer_cfg->get_rekey_time(this->peer_cfg, TRUE); if (t && (this->stats[STAT_REKEY] == 0 || (this->stats[STAT_REKEY] > t + this->stats[STAT_ESTABLISHED]))) { @@ -651,7 +651,7 @@ METHOD(ike_sa_t, set_state, void, lib->scheduler->schedule_job(lib->scheduler, job, t); DBG1(DBG_IKE, "scheduling rekeying in %ds", t); } - t = this->peer_cfg->get_reauth_time(this->peer_cfg); + t = this->peer_cfg->get_reauth_time(this->peer_cfg, TRUE); if (t && (this->stats[STAT_REAUTH] == 0 || (this->stats[STAT_REAUTH] > t + this->stats[STAT_ESTABLISHED]))) { From e174e0d4455e30a8d9a1900916a195f20588afdb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 11:39:31 +0100 Subject: [PATCH 147/534] Added not-yet used sa_payload parameters used in IKEv1 --- src/conftest/hooks/custom_proposal.c | 3 +- src/conftest/hooks/pretend_auth.c | 3 +- src/conftest/hooks/set_proposal_number.c | 2 +- src/libcharon/encoding/payloads/sa_payload.c | 106 ++++++++++++++++++ src/libcharon/encoding/payloads/sa_payload.h | 76 +++++++++++-- .../sa/authenticators/authenticator.h | 6 + src/libcharon/sa/tasks/child_create.c | 6 +- src/libcharon/sa/tasks/ike_init.c | 6 +- src/libcharon/sa/tasks/main_mode.c | 8 +- src/libcharon/sa/tasks/quick_mode.c | 8 +- src/libhydra/kernel/kernel_ipsec.h | 2 + 11 files changed, 194 insertions(+), 32 deletions(-) diff --git a/src/conftest/hooks/custom_proposal.c b/src/conftest/hooks/custom_proposal.c index 9522335b1..4acea18ce 100644 --- a/src/conftest/hooks/custom_proposal.c +++ b/src/conftest/hooks/custom_proposal.c @@ -145,8 +145,7 @@ METHOD(listener_t, message, bool, proposal->get_protocol(proposal), proposal->get_spi(proposal)); DBG1(DBG_CFG, "injecting custom proposal: %#P", new_props); - new = sa_payload_create_from_proposal_list( - SECURITY_ASSOCIATION, new_props); + new = sa_payload_create_from_proposals_v2(new_props); message->add_payload(message, (payload_t*)new); new_props->destroy_offset(new_props, offsetof(proposal_t, destroy)); } diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c index 560864db5..b8f961403 100644 --- a/src/conftest/hooks/pretend_auth.c +++ b/src/conftest/hooks/pretend_auth.c @@ -295,8 +295,7 @@ static void process_auth_response(private_pretend_auth_t *this, if (this->proposal) { message->add_payload(message, (payload_t*) - sa_payload_create_from_proposal(SECURITY_ASSOCIATION, - this->proposal)); + sa_payload_create_from_proposal_v2(this->proposal)); } if (this->tsi) { diff --git a/src/conftest/hooks/set_proposal_number.c b/src/conftest/hooks/set_proposal_number.c index 32b0155cb..839ca1f37 100644 --- a/src/conftest/hooks/set_proposal_number.c +++ b/src/conftest/hooks/set_proposal_number.c @@ -121,7 +121,7 @@ METHOD(listener_t, message, bool, } enumerator->destroy(enumerator); } - sa = sa_payload_create_from_proposal_list(SECURITY_ASSOCIATION, updated); + sa = sa_payload_create_from_proposals_v2(updated); list->destroy_offset(list, offsetof(proposal_t, destroy)); updated->destroy_offset(updated, offsetof(proposal_t, destroy)); message->add_payload(message, (payload_t*)sa); diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 05695fce2..385517bdd 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -341,6 +341,31 @@ METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*, return this->proposals->create_enumerator(this->proposals); } +METHOD(sa_payload_t, get_lifetime, u_int32_t, + private_sa_payload_t *this) +{ + return 0; +} + +METHOD(sa_payload_t, get_lifebytes, u_int64_t, + private_sa_payload_t *this) +{ + return 0; +} + +METHOD(sa_payload_t, get_auth_method, auth_method_t, + private_sa_payload_t *this) +{ + return AUTH_NONE; +} + +METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t, + private_sa_payload_t *this, bool *udp) +{ + *udp = FALSE; + return MODE_NONE; +} + METHOD2(payload_t, sa_payload_t, destroy, void, private_sa_payload_t *this) { @@ -370,6 +395,10 @@ sa_payload_t *sa_payload_create(payload_type_t type) }, .get_proposals = _get_proposals, .create_substructure_enumerator = _create_substructure_enumerator, + .get_lifetime = _get_lifetime, + .get_lifebytes = _get_lifebytes, + .get_auth_method = _get_auth_method, + .get_encap_mode = _get_encap_mode, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, @@ -431,3 +460,80 @@ sa_payload_t *sa_payload_create_from_proposal(payload_type_t type, return &this->public; } + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals) +{ + private_sa_payload_t *this; + enumerator_t *enumerator; + proposal_t *proposal; + + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); + enumerator = proposals->create_enumerator(proposals); + while (enumerator->enumerate(enumerator, &proposal)) + { + add_proposal(this, proposal); + } + enumerator->destroy(enumerator); + + return &this->public; +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal) +{ + private_sa_payload_t *this; + + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); + add_proposal(this, proposal); + + return &this->public; + +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) +{ + proposal_substructure_t *substruct; + private_sa_payload_t *this; + + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); + + /* IKEv1 encodes multiple proposals in a single substructure + * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */ + substruct = proposal_substructure_create_from_proposals(proposals); + substruct->set_is_last_proposal(substruct, TRUE); + this->proposals->insert_last(this->proposals, substruct); + compute_length(this); + + return &this->public; +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) +{ + proposal_substructure_t *substruct; + private_sa_payload_t *this; + + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1); + + substruct = proposal_substructure_create_from_proposal( + PROPOSAL_SUBSTRUCTURE_V1, proposal); + substruct->set_is_last_proposal(substruct, TRUE); + this->proposals->insert_last(this->proposals, substruct); + compute_length(this); + + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h index d6c6b6036..dfba47749 100644 --- a/src/libcharon/encoding/payloads/sa_payload.h +++ b/src/libcharon/encoding/payloads/sa_payload.h @@ -28,6 +28,8 @@ typedef struct sa_payload_t sa_payload_t; #include #include #include +#include +#include /** * Class representing an IKEv1 or IKEv2 SA Payload. @@ -48,6 +50,35 @@ struct sa_payload_t { */ linked_list_t *(*get_proposals) (sa_payload_t *this); + /** + * Get the (shortest) lifetime of a proposal (IKEv1 only). + * + * @return lifetime, in seconds + */ + u_int32_t (*get_lifetime)(sa_payload_t *this); + + /** + * Get the (shortest) life duration of a proposal (IKEv1 only). + * + * @return life duration, in bytes + */ + u_int64_t (*get_lifebytes)(sa_payload_t *this); + + /** + * Get the first authentication method from the proposal (IKEv1 only). + * + * @return auth method, or AUTH_NONE + */ + auth_method_t (*get_auth_method)(sa_payload_t *this); + + /** + * Get the (first) encapsulation mode from a proposal (IKEv1 only). + * + * @param udp set to TRUE if UDP encapsulation used + * @return ipsec encapsulation mode + */ + ipsec_mode_t (*get_encap_mode)(sa_payload_t *this, bool *udp); + /** * Create an enumerator over all proposal substructures. * @@ -70,26 +101,49 @@ struct sa_payload_t { sa_payload_t *sa_payload_create(payload_type_t type); /** - * Creates a sa_payload_t object from a list of proposals. + * Creates an IKEv2 sa_payload_t object from a list of proposals. * - * @param type SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1 * @param proposals list of proposals to build the payload from * @return sa_payload_t object */ -sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type, - linked_list_t *proposals); +sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals); /** - * Creates a sa_payload_t object from a single proposal. + * Creates an IKEv2 sa_payload_t object from a single proposal. * - * This is only for convenience. Use sa_payload_create_from_proposal_list - * if you want to add more than one proposal. - * - * @param type SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1 * @param proposal proposal from which the payload should be built. * @return sa_payload_t object */ -sa_payload_t *sa_payload_create_from_proposal(payload_type_t type, - proposal_t *proposal); +sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal); + +/** + * Creates an IKEv1 sa_payload_t object from a list of proposals. + * + * @param proposals list of proposals to build the payload from + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @return sa_payload_t object + */ +sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); + +/** + * Creates an IKEv1 sa_payload_t object from a single proposal. + * + * @param proposal proposal from which the payload should be built. + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @return sa_payload_t object + */ +sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); #endif /** SA_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticators/authenticator.h index d27e006a3..a3850bb7f 100644 --- a/src/libcharon/sa/authenticators/authenticator.h +++ b/src/libcharon/sa/authenticators/authenticator.h @@ -34,6 +34,12 @@ typedef struct authenticator_t authenticator_t; * Method to use for authentication, as defined in IKEv2. */ enum auth_method_t { + + /** + * No authentication used. + */ + AUTH_NONE = 0, + /** * Computed as specified in section 2.15 of RFC using * an RSA private key over a PKCS#1 padded hash. diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/tasks/child_create.c index e40f34dc9..79d082138 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/tasks/child_create.c @@ -527,13 +527,11 @@ static void build_payloads(private_child_create_t *this, message_t *message) /* add SA payload */ if (this->initiator) { - sa_payload = sa_payload_create_from_proposal_list(SECURITY_ASSOCIATION, - this->proposals); + sa_payload = sa_payload_create_from_proposals_v2(this->proposals); } else { - sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION, - this->proposal); + sa_payload = sa_payload_create_from_proposal_v2(this->proposal); } message->add_payload(message, (payload_t*)sa_payload); diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/tasks/ike_init.c index 868680bb6..3b0c4e8f8 100644 --- a/src/libcharon/sa/tasks/ike_init.c +++ b/src/libcharon/sa/tasks/ike_init.c @@ -133,8 +133,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message) enumerator->destroy(enumerator); } - sa_payload = sa_payload_create_from_proposal_list(SECURITY_ASSOCIATION, - proposal_list); + sa_payload = sa_payload_create_from_proposals_v2(proposal_list); proposal_list->destroy_offset(proposal_list, offsetof(proposal_t, destroy)); } else @@ -144,8 +143,7 @@ static void build_payloads(private_ike_init_t *this, message_t *message) /* include SPI of new IKE_SA when we are rekeying */ this->proposal->set_spi(this->proposal, id->get_responder_spi(id)); } - sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION, - this->proposal); + sa_payload = sa_payload_create_from_proposal_v2(this->proposal); } message->add_payload(message, (payload_t*)sa_payload); diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index f59276714..12ec5f71b 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -299,8 +299,8 @@ METHOD(task_t, build_i, status_t, proposals = this->ike_cfg->get_proposals(this->ike_cfg); - sa_payload = sa_payload_create_from_proposal_list( - SECURITY_ASSOCIATION_V1, proposals); + sa_payload = sa_payload_create_from_proposals_v1(proposals, + 0, 0, AUTH_NONE, MODE_NONE, FALSE); proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); message->add_payload(message, &sa_payload->payload_interface); @@ -573,8 +573,8 @@ METHOD(task_t, build_r, status_t, { sa_payload_t *sa_payload; - sa_payload = sa_payload_create_from_proposal(SECURITY_ASSOCIATION_V1, - this->proposal); + sa_payload = sa_payload_create_from_proposal_v1(this->proposal, + 0, 0, AUTH_NONE, MODE_NONE, FALSE); message->add_payload(message, &sa_payload->payload_interface); return NEED_MORE; diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index eb9312d2b..1d5e6b521 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -425,8 +425,8 @@ METHOD(task_t, build_i, status_t, } enumerator->destroy(enumerator); - sa_payload = sa_payload_create_from_proposal_list( - SECURITY_ASSOCIATION_V1, list); + sa_payload = sa_payload_create_from_proposals_v1(list, + 0, 0, AUTH_NONE, MODE_NONE, FALSE); list->destroy_offset(list, offsetof(proposal_t, destroy)); message->add_payload(message, &sa_payload->payload_interface); @@ -551,8 +551,8 @@ METHOD(task_t, build_r, status_t, } this->proposal->set_spi(this->proposal, this->spi_r); - sa_payload = sa_payload_create_from_proposal( - SECURITY_ASSOCIATION_V1, this->proposal); + sa_payload = sa_payload_create_from_proposal_v1(this->proposal, + 0, 0, AUTH_NONE, MODE_NONE, FALSE); message->add_payload(message, &sa_payload->payload_interface); if (!add_nonce(this, &this->nonce_r, message)) diff --git a/src/libhydra/kernel/kernel_ipsec.h b/src/libhydra/kernel/kernel_ipsec.h index ddb63283c..7af76a321 100644 --- a/src/libhydra/kernel/kernel_ipsec.h +++ b/src/libhydra/kernel/kernel_ipsec.h @@ -43,6 +43,8 @@ typedef struct mark_t mark_t; * Mode of an IPsec SA. */ enum ipsec_mode_t { + /** not using any encapsulation */ + MODE_NONE = 0, /** transport mode, no inner address */ MODE_TRANSPORT = 1, /** tunnel mode, inner and outer addresses */ From 132d5c56dedd4e0977f7ce746fcccc7613e15ace Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 14:51:04 +0100 Subject: [PATCH 148/534] Exchange IKEv1 SA specific proposal data with SA payload --- src/libcharon/sa/tasks/main_mode.c | 82 +++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 12ec5f71b..263439b00 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -106,6 +106,16 @@ struct private_main_mode_t { */ chunk_t sa_payload; + /** + * Negotiated SA lifetime + */ + u_int32_t lifetime; + + /** + * Negotiated authentication method + */ + auth_method_t auth_method; + /** states of main mode */ enum { MM_INIT, @@ -279,6 +289,23 @@ static bool get_nonce_ke(private_main_mode_t *this, chunk_t *nonce, return TRUE; } +/** + * Get auth method to use + */ +static auth_method_t get_auth_method(private_main_mode_t *this) +{ + switch ((uintptr_t)this->my_auth->get(this->my_auth, AUTH_RULE_AUTH_CLASS)) + { + case AUTH_CLASS_PSK: + return AUTH_PSK; + case AUTH_CLASS_PUBKEY: + /* TODO-IKEv1: look for a key, return RSA or ECDSA */ + default: + /* TODO-IKEv1: XAUTH methods */ + return AUTH_RSA; + } +} + METHOD(task_t, build_i, status_t, private_main_mode_t *this, message_t *message) { @@ -297,10 +324,28 @@ METHOD(task_t, build_i, status_t, this->ike_sa->get_other_host(this->ike_sa)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); - proposals = this->ike_cfg->get_proposals(this->ike_cfg); + this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->peer_cfg->get_ref(this->peer_cfg); + this->my_auth = get_auth_cfg(this, TRUE); + this->other_auth = get_auth_cfg(this, FALSE); + if (!this->my_auth || !this->other_auth) + { + DBG1(DBG_CFG, "no auth config found"); + return FAILED; + } + + proposals = this->ike_cfg->get_proposals(this->ike_cfg); + this->auth_method = get_auth_method(this); + this->lifetime = this->peer_cfg->get_reauth_time(this->peer_cfg, + FALSE); + if (!this->lifetime) + { /* fall back to rekey time of no rekey time configured */ + this->lifetime = this->peer_cfg->get_rekey_time(this->peer_cfg, + FALSE); + } sa_payload = sa_payload_create_from_proposals_v1(proposals, - 0, 0, AUTH_NONE, MODE_NONE, FALSE); + this->lifetime, 0, this->auth_method, MODE_NONE, FALSE); proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); message->add_payload(message, &sa_payload->payload_interface); @@ -351,16 +396,6 @@ METHOD(task_t, build_i, status_t, id_payload_t *id_payload; identification_t *id; - this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - this->peer_cfg->get_ref(this->peer_cfg); - - this->my_auth = get_auth_cfg(this, TRUE); - this->other_auth = get_auth_cfg(this, FALSE); - if (!this->my_auth || !this->other_auth) - { - DBG1(DBG_CFG, "no auth config found"); - return FAILED; - } id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY); if (!id) { @@ -419,6 +454,10 @@ METHOD(task_t, process_r, status_t, DBG1(DBG_IKE, "no proposal found"); return FAILED; } + + this->auth_method = sa_payload->get_auth_method(sa_payload); + this->lifetime = sa_payload->get_lifetime(sa_payload); + this->state = MM_SA; return NEED_MORE; } @@ -574,7 +613,7 @@ METHOD(task_t, build_r, status_t, sa_payload_t *sa_payload; sa_payload = sa_payload_create_from_proposal_v1(this->proposal, - 0, 0, AUTH_NONE, MODE_NONE, FALSE); + this->lifetime, 0, this->auth_method, MODE_NONE, FALSE); message->add_payload(message, &sa_payload->payload_interface); return NEED_MORE; @@ -641,6 +680,8 @@ METHOD(task_t, process_i, status_t, { linked_list_t *list; sa_payload_t *sa_payload; + auth_method_t auth_method; + u_int32_t lifetime; sa_payload = (sa_payload_t*)message->get_payload(message, SECURITY_ASSOCIATION_V1); @@ -658,6 +699,21 @@ METHOD(task_t, process_i, status_t, DBG1(DBG_IKE, "no proposal found"); return FAILED; } + + lifetime = sa_payload->get_lifetime(sa_payload); + if (lifetime != this->lifetime) + { + DBG1(DBG_IKE, "received lifetime %us does not match configured " + "%us, using lower value", lifetime, this->lifetime); + } + this->lifetime = min(this->lifetime, lifetime); + auth_method = sa_payload->get_auth_method(sa_payload); + if (auth_method != this->auth_method) + { + DBG1(DBG_IKE, "received %N authentication, but configured %N, " + "continue with configured", auth_method_names, auth_method, + auth_method_names, this->auth_method); + } return NEED_MORE; } case MM_KE: From cd0017d452d2525eb2249829d0062a0919fae8c4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 15:25:00 +0100 Subject: [PATCH 149/534] Exchange IKEv1 ESP SA proposal information --- src/libcharon/sa/tasks/quick_mode.c | 68 ++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 1d5e6b521..353a1dba2 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -95,6 +95,16 @@ struct private_quick_mode_t { */ keymat_v1_t *keymat; + /** + * Negotiated lifetime of new SA + */ + u_int32_t lifetime; + + /** + * Negotaited lifebytes of new SA + */ + u_int64_t lifebytes; + /** states of quick mode */ enum { QM_INIT, @@ -393,6 +403,49 @@ static bool get_ts(private_quick_mode_t *this, message_t *message) return TRUE; } +/** + * Look up lifetimes + */ +static void get_lifetimes(private_quick_mode_t *this) +{ + lifetime_cfg_t *lft; + + lft = this->config->get_lifetime(this->config); + if (lft->time.life) + { + this->lifetime = lft->time.life; + } + else if (lft->bytes.life) + { + this->lifebytes = lft->bytes.life; + } + free(lft); +} + +/** + * Check and apply lifetimes + */ +static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload) +{ + u_int32_t lifetime; + u_int64_t lifebytes; + + lifetime = sa_payload->get_lifetime(sa_payload); + lifebytes = sa_payload->get_lifebytes(sa_payload); + if (this->lifetime != lifetime) + { + DBG1(DBG_IKE, "received %us lifetime, configured %us, using lower", + lifetime, this->lifetime); + this->lifetime = min(this->lifetime, lifetime); + } + if (this->lifebytes != lifebytes) + { + DBG1(DBG_IKE, "received %llu lifebytes, configured %llu, using lower", + lifebytes, this->lifebytes); + this->lifebytes = min(this->lifebytes, lifebytes); + } +} + METHOD(task_t, build_i, status_t, private_quick_mode_t *this, message_t *message) { @@ -425,8 +478,10 @@ METHOD(task_t, build_i, status_t, } enumerator->destroy(enumerator); + get_lifetimes(this); sa_payload = sa_payload_create_from_proposals_v1(list, - 0, 0, AUTH_NONE, MODE_NONE, FALSE); + this->lifetime, this->lifebytes, AUTH_NONE, + this->config->get_mode(this->config), FALSE); list->destroy_offset(list, offsetof(proposal_t, destroy)); message->add_payload(message, &sa_payload->payload_interface); @@ -504,6 +559,10 @@ METHOD(task_t, process_r, status_t, this->proposal = this->config->select_proposal(this->config, list, TRUE, FALSE); list->destroy_offset(list, offsetof(proposal_t, destroy)); + + get_lifetimes(this); + apply_lifetimes(this, sa_payload); + if (!this->proposal) { DBG1(DBG_IKE, "no matching proposal found"); @@ -515,6 +574,8 @@ METHOD(task_t, process_r, status_t, { return FAILED; } + + this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), @@ -552,7 +613,8 @@ METHOD(task_t, build_r, status_t, this->proposal->set_spi(this->proposal, this->spi_r); sa_payload = sa_payload_create_from_proposal_v1(this->proposal, - 0, 0, AUTH_NONE, MODE_NONE, FALSE); + this->lifetime, this->lifebytes, AUTH_NONE, + this->config->get_mode(this->config), FALSE); message->add_payload(message, &sa_payload->payload_interface); if (!add_nonce(this, &this->nonce_r, message)) @@ -597,6 +659,8 @@ METHOD(task_t, process_i, status_t, } this->spi_r = this->proposal->get_spi(this->proposal); + apply_lifetimes(this, sa_payload); + if (!get_nonce(this, &this->nonce_r, message)) { return FAILED; From fbebc2a068942d16c20f8439b140027395ba25a0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 12:52:11 +0100 Subject: [PATCH 150/534] Implemented encoding of additional IKEv1 proposal attributes --- .../encoding/payloads/proposal_substructure.c | 163 ++++++++++++------ .../encoding/payloads/proposal_substructure.h | 41 ++++- src/libcharon/encoding/payloads/sa_payload.c | 69 +------- .../encoding/payloads/transform_attribute.c | 19 +- .../encoding/payloads/transform_attribute.h | 4 +- 5 files changed, 173 insertions(+), 123 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 924f5cb48..11d684f5e 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -572,6 +572,41 @@ static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value) return 0; } +/** + * Get IKEv1 authentication attribute from auth_method_t + */ +static u_int16_t get_ikev1_auth(auth_method_t method) +{ + switch (method) + { + case AUTH_RSA: + return IKEV1_AUTH_RSA_SIG; + case AUTH_DSS: + return IKEV1_AUTH_DSS_SIG; + default: + /* TODO-IKEv1: Handle XAUTH methods */ + /* TODO-IKEv1: Handle ECDSA methods */ + case AUTH_PSK: + return IKEV1_AUTH_PSK; + } +} + +/** + * Get IKEv1 encapsulation mode + */ +static u_int16_t get_ikev1_mode(ipsec_mode_t mode, bool udp) +{ + switch (mode) + { + case MODE_TUNNEL: + return udp ? IKEV1_ENCAP_UDP_TUNNEL : IKEV1_ENCAP_TUNNEL; + case MODE_TRANSPORT: + return udp ? IKEV1_ENCAP_UDP_TRANSPORT : IKEV1_ENCAP_TRANSPORT; + default: + return IKEV1_ENCAP_TUNNEL; + } +} + /** * Add an IKE transform to a proposal for IKEv1 */ @@ -771,7 +806,8 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type) * Add an IKEv1 IKE proposal to the substructure */ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, - proposal_t *proposal, int number) + proposal_t *proposal, u_int32_t lifetime, + auth_method_t method, int number) { transform_substructure_t *transform; u_int16_t alg, key_size; @@ -822,23 +858,15 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, } enumerator->destroy(enumerator); - /* TODO-IKEv1: Add lifetime, non-fixed auth-method and other attributes */ - if(1) /* TODO-IKEv1: Change to 0 if XAUTH is desired. */ - { transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_PSK)); - }else{ - transform->add_transform_attribute(transform, - transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH1_AUTH_METHOD, IKEV1_AUTH_XAUTH_INIT_PSK)); - } + TATTR_PH1_AUTH_METHOD, get_ikev1_auth(method))); transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH1_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH1_LIFE_DURATION, 10800)); + TATTR_PH1_LIFE_DURATION, lifetime)); add_transform_substructure(this, transform); } @@ -847,7 +875,8 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, * Add an IKEv1 ESP proposal to the substructure */ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, - proposal_t *proposal, int number) + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + ipsec_mode_t mode, bool udp, int number) { transform_substructure_t *transform = NULL; u_int16_t alg, key_size; @@ -884,16 +913,27 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, } enumerator->destroy(enumerator); - /* TODO-IKEv1: Add lifetime and other attributes, ESN */ - transform->add_transform_attribute(transform, - transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH2_ENCAP_MODE, IKEV1_ENCAP_TUNNEL)); transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp))); + if (lifetime) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); - transform->add_transform_attribute(transform, - transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, - TATTR_PH2_SA_LIFE_DURATION, 3600)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifetime)); + } + else if (lifebytes) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000)); + } add_transform_substructure(this, transform); } @@ -965,36 +1005,14 @@ static void set_from_proposal_v2(private_proposal_substructure_t *this, enumerator->destroy(enumerator); } -/* - * Described in header. +/** + * Set SPI and other data from proposal, compute length */ -proposal_substructure_t *proposal_substructure_create_from_proposal( - payload_type_t type, proposal_t *proposal) +static void set_data(private_proposal_substructure_t *this, proposal_t *proposal) { - private_proposal_substructure_t *this; u_int64_t spi64; u_int32_t spi32; - this = (private_proposal_substructure_t*)proposal_substructure_create(type); - - if (type == PROPOSAL_SUBSTRUCTURE) - { - set_from_proposal_v2(this, proposal); - } - else - { - switch (proposal->get_protocol(proposal)) - { - case PROTO_IKE: - set_from_proposal_v1_ike(this, proposal, 0); - break; - case PROTO_ESP: - set_from_proposal_v1_esp(this, proposal, 0); - break; - default: - break; - } - } /* add SPI, if necessary */ switch (proposal->get_protocol(proposal)) { @@ -1018,6 +1036,20 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( this->proposal_number = proposal->get_number(proposal); this->protocol_id = proposal->get_protocol(proposal); compute_length(this); +} + +/* + * Described in header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v2( + proposal_t *proposal) +{ + private_proposal_substructure_t *this; + + this = (private_proposal_substructure_t*) + proposal_substructure_create(SECURITY_ASSOCIATION); + set_from_proposal_v2(this, proposal); + set_data(this, proposal); return &this->public; } @@ -1025,8 +1057,37 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( /** * See header. */ -proposal_substructure_t *proposal_substructure_create_from_proposals( - linked_list_t *proposals) +proposal_substructure_t *proposal_substructure_create_from_proposal_v1( + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) +{ + private_proposal_substructure_t *this; + + this = (private_proposal_substructure_t*) + proposal_substructure_create(PROPOSAL_SUBSTRUCTURE_V1); + switch (proposal->get_protocol(proposal)) + { + case PROTO_IKE: + set_from_proposal_v1_ike(this, proposal, lifetime, auth, 0); + break; + case PROTO_ESP: + set_from_proposal_v1_esp(this, proposal, lifetime, + lifebytes, mode, udp, 0); + break; + default: + break; + } + set_data(this, proposal); + + return &this->public; +} + +/** + * See header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposals_v1( + linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) { private_proposal_substructure_t *this = NULL; enumerator_t *enumerator; @@ -1039,18 +1100,20 @@ proposal_substructure_t *proposal_substructure_create_from_proposals( if (!this) { this = (private_proposal_substructure_t*) - proposal_substructure_create_from_proposal( - PROPOSAL_SUBSTRUCTURE_V1, proposal); + proposal_substructure_create_from_proposal_v1( + proposal, lifetime, lifebytes, auth, mode, udp); } else { switch (proposal->get_protocol(proposal)) { case PROTO_IKE: - set_from_proposal_v1_ike(this, proposal, ++number); + set_from_proposal_v1_ike(this, proposal, lifetime, + auth, ++number); break; case PROTO_ESP: - set_from_proposal_v1_esp(this, proposal, ++number); + set_from_proposal_v1_esp(this, proposal, lifetime, + lifebytes, mode, udp, ++number); break; default: break; diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index 496a352ca..de06f916f 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -29,6 +29,8 @@ typedef struct proposal_substructure_t proposal_substructure_t; #include #include #include +#include +#include /** * Class representing an IKEv1/IKEv2 proposal substructure. @@ -124,22 +126,43 @@ struct proposal_substructure_t { proposal_substructure_t *proposal_substructure_create(payload_type_t type); /** - * Creates a proposal_substructure_t from a proposal_t. + * Creates an IKEv2 proposal_substructure_t from a proposal_t. * - * @param type PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 * @param proposal proposal to build a substruct out of it - * @return proposal_substructure_t object + * @return proposal_substructure_t PROPOSAL_SUBSTRUCTURE */ -proposal_substructure_t *proposal_substructure_create_from_proposal( - payload_type_t type, proposal_t *proposal); +proposal_substructure_t *proposal_substructure_create_from_proposal_v2( + proposal_t *proposal); +/** + * Creates an IKEv1 proposal_substructure_t from a proposal_t. + * + * @param proposal proposal to build a substruct out of it + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * + * + * @return proposal_substructure_t object PROPOSAL_SUBSTRUCTURE_V1 + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v1( + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); /** - * Creates a proposal_substructure_t from a list of proposal_t (IKEv1 only). + * Creates an IKEv1 proposal_substructure_t from a list of proposal_t. * - * @param proposal proposal to build a substruct out of it + * @param proposals list of proposal_t to encode in a substructure + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation * @return IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1 */ -proposal_substructure_t *proposal_substructure_create_from_proposals( - linked_list_t *proposals); +proposal_substructure_t *proposal_substructure_create_from_proposals_v1( + linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); #endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 385517bdd..5f739c94a 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -259,17 +259,12 @@ METHOD(payload_t, get_length, size_t, /** * Create a transform substructure from a proposal, add to payload */ -static void add_proposal(private_sa_payload_t *this, proposal_t *proposal) +static void add_proposal_v2(private_sa_payload_t *this, proposal_t *proposal) { proposal_substructure_t *substruct, *last; - payload_type_t subtype = PROPOSAL_SUBSTRUCTURE; u_int count; - if (this->type == SECURITY_ASSOCIATION_V1) - { - subtype = PROPOSAL_SUBSTRUCTURE_V1; - } - substruct = proposal_substructure_create_from_proposal(subtype, proposal); + substruct = proposal_substructure_create_from_proposal_v2(proposal); count = this->proposals->get_count(this->proposals); if (count > 0) { @@ -414,53 +409,6 @@ sa_payload_t *sa_payload_create(payload_type_t type) return &this->public; } -/* - * Described in header. - */ -sa_payload_t *sa_payload_create_from_proposal_list(payload_type_t type, - linked_list_t *proposals) -{ - private_sa_payload_t *this; - enumerator_t *enumerator; - proposal_t *proposal; - - this = (private_sa_payload_t*)sa_payload_create(type); - if (type == SECURITY_ASSOCIATION) - { - enumerator = proposals->create_enumerator(proposals); - while (enumerator->enumerate(enumerator, &proposal)) - { - add_proposal(this, proposal); - } - enumerator->destroy(enumerator); - } - else - { /* IKEv1 encodes multiple proposals in a single substructure - * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */ - proposal_substructure_t *substruct; - - substruct = proposal_substructure_create_from_proposals(proposals); - substruct->set_is_last_proposal(substruct, TRUE); - this->proposals->insert_last(this->proposals, substruct); - compute_length(this); - } - return &this->public; -} - -/* - * Described in header. - */ -sa_payload_t *sa_payload_create_from_proposal(payload_type_t type, - proposal_t *proposal) -{ - private_sa_payload_t *this; - - this = (private_sa_payload_t*)sa_payload_create(type); - add_proposal(this, proposal); - - return &this->public; -} - /* * Described in header. */ @@ -474,7 +422,7 @@ sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals) enumerator = proposals->create_enumerator(proposals); while (enumerator->enumerate(enumerator, &proposal)) { - add_proposal(this, proposal); + add_proposal_v2(this, proposal); } enumerator->destroy(enumerator); @@ -489,7 +437,7 @@ sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal) private_sa_payload_t *this; this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); - add_proposal(this, proposal); + add_proposal_v2(this, proposal); return &this->public; @@ -505,11 +453,12 @@ sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, proposal_substructure_t *substruct; private_sa_payload_t *this; - this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1); /* IKEv1 encodes multiple proposals in a single substructure * TODO-IKEv1: Encode ESP+AH proposals in two different substructs */ - substruct = proposal_substructure_create_from_proposals(proposals); + substruct = proposal_substructure_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp); substruct->set_is_last_proposal(substruct, TRUE); this->proposals->insert_last(this->proposals, substruct); compute_length(this); @@ -529,8 +478,8 @@ sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1); - substruct = proposal_substructure_create_from_proposal( - PROPOSAL_SUBSTRUCTURE_V1, proposal); + substruct = proposal_substructure_create_from_proposal_v1(proposal, + lifetime, lifebytes, auth, mode, udp); substruct->set_is_last_proposal(substruct, TRUE); this->proposals->insert_last(this->proposals, substruct); compute_length(this); diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 474362fca..7e8a9c7c7 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -290,13 +290,28 @@ transform_attribute_t *transform_attribute_create(payload_type_t type) * Described in header. */ transform_attribute_t *transform_attribute_create_value(payload_type_t type, - transform_attribute_type_t kind, u_int16_t value) + transform_attribute_type_t kind, u_int64_t value) { transform_attribute_t *attribute; attribute = transform_attribute_create(type); attribute->set_attribute_type(attribute, kind); - attribute->set_value(attribute, value); + if (value <= UINT16_MAX) + { + attribute->set_value(attribute, value); + } + else if (value <= UINT32_MAX) + { + u_int32_t val32; + + val32 = htonl(value); + attribute->set_value_chunk(attribute, chunk_from_thing(val32)); + } + else + { + value = htobe64(value); + attribute->set_value_chunk(attribute, chunk_from_thing(value)); + } return attribute; } diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h index eedb3be21..52e5d8412 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.h +++ b/src/libcharon/encoding/payloads/transform_attribute.h @@ -163,7 +163,7 @@ struct transform_attribute_t { transform_attribute_t *transform_attribute_create(payload_type_t type); /** - * Creates a two byte value attribute for a given attribute kind. + * Creates a two byte value or a larger attribute for a given attribute kind. * * @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 * @param kind attribute kind @@ -171,6 +171,6 @@ transform_attribute_t *transform_attribute_create(payload_type_t type); * @return transform_attribute_t object */ transform_attribute_t *transform_attribute_create_value(payload_type_t type, - transform_attribute_type_t kind, u_int16_t value); + transform_attribute_type_t kind, u_int64_t value); #endif /** TRANSFORM_ATTRIBUTE_H_ @}*/ From 914ec2dbf29ea70a397418860fb304196131d845 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 15:25:22 +0100 Subject: [PATCH 151/534] Implemented IKEv1 attribute encoding in SA payload --- .../encoding/payloads/proposal_substructure.c | 155 ++++++++++++++++++ .../encoding/payloads/proposal_substructure.h | 29 ++++ src/libcharon/encoding/payloads/sa_payload.c | 53 +++++- .../encoding/payloads/transform_attribute.c | 16 +- .../encoding/payloads/transform_attribute.h | 2 +- 5 files changed, 247 insertions(+), 8 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 11d684f5e..ca19ba700 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -754,6 +754,157 @@ METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*, return this->transforms->create_enumerator(this->transforms); } +/** + * Get an attribute from a selected transform + */ +static u_int64_t get_attr_tfrm(transform_substructure_t *transform, + transform_attribute_type_t type) +{ + enumerator_t *enumerator; + transform_attribute_t *attr; + u_int64_t value = 0; + + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &attr)) + { + if (attr->get_attribute_type(attr) == type) + { + value = attr->get_value(attr); + break; + } + } + enumerator->destroy(enumerator); + return value; +} + + +/** + * Get an attribute from any transform, 0 if not found + */ +static u_int64_t get_attr(private_proposal_substructure_t *this, + transform_attribute_type_t type, transform_substructure_t **sel) +{ + transform_substructure_t *transform; + enumerator_t *enumerator; + u_int64_t value = 0; + + enumerator = this->transforms->create_enumerator(this->transforms); + while (enumerator->enumerate(enumerator, &transform)) + { + value = get_attr_tfrm(transform, type); + if (value) + { + if (sel) + { + *sel = transform; + } + break; + } + } + enumerator->destroy(enumerator); + return value; +} + +METHOD(proposal_substructure_t, get_lifetime, u_int32_t, + private_proposal_substructure_t *this) +{ + transform_substructure_t *transform; + transform_attribute_type_t type; + + switch (this->protocol_id) + { + case PROTO_IKE: + type = get_attr(this, TATTR_PH1_LIFE_TYPE, &transform); + if (type == IKEV1_LIFE_TYPE_SECONDS) + { + return get_attr_tfrm(transform, TATTR_PH1_LIFE_DURATION); + } + break; + case PROTO_ESP: + type = get_attr(this, TATTR_PH2_SA_LIFE_TYPE, &transform); + if (type == IKEV1_LIFE_TYPE_SECONDS) + { + return get_attr_tfrm(transform, TATTR_PH2_SA_LIFE_DURATION); + } + else if (type != IKEV1_LIFE_TYPE_KILOBYTES) + { /* default to 8 hours, RFC 2407 */ + return 28800; + } + break; + default: + break; + } + return 0; +} + +METHOD(proposal_substructure_t, get_lifebytes, u_int64_t, + private_proposal_substructure_t *this) +{ + transform_substructure_t *transform; + transform_attribute_type_t type; + + switch (this->protocol_id) + { + case PROTO_IKE: + type = get_attr(this, TATTR_PH1_LIFE_TYPE, &transform); + if (type == IKEV1_LIFE_TYPE_KILOBYTES) + { + return get_attr_tfrm(transform, TATTR_PH1_LIFE_DURATION); + } + break; + case PROTO_ESP: + type = get_attr(this, TATTR_PH2_SA_LIFE_TYPE, &transform); + if (type == IKEV1_LIFE_TYPE_KILOBYTES) + { + return get_attr_tfrm(transform, TATTR_PH1_LIFE_DURATION); + } + break; + default: + break; + } + return 0; + +} + +METHOD(proposal_substructure_t, get_auth_method, auth_method_t, + private_proposal_substructure_t *this) +{ + switch (get_attr(this, TATTR_PH1_AUTH_METHOD, NULL)) + { + case IKEV1_AUTH_PSK: + return AUTH_PSK; + case IKEV1_AUTH_RSA_SIG: + return AUTH_RSA; + case IKEV1_AUTH_DSS_SIG: + return AUTH_DSS; + default: + /* TODO-IKEv1: XAUTH, ECDSA sigs */ + return AUTH_NONE; + } +} + +METHOD(proposal_substructure_t, get_encap_mode, ipsec_mode_t, + private_proposal_substructure_t *this, bool *udp) +{ + *udp = FALSE; + switch (get_attr(this, TATTR_PH2_ENCAP_MODE, NULL)) + { + case IKEV1_ENCAP_TRANSPORT: + return MODE_TRANSPORT; + case IKEV1_ENCAP_TUNNEL: + return MODE_TRANSPORT; + case IKEV1_ENCAP_UDP_TRANSPORT: + *udp = TRUE; + return MODE_TRANSPORT; + case IKEV1_ENCAP_UDP_TUNNEL: + *udp = TRUE; + return MODE_TUNNEL; + default: + /* default to TUNNEL, RFC 2407 says implementation specific */ + return MODE_TUNNEL; + } +} + METHOD2(payload_t, proposal_substructure_t, destroy, void, private_proposal_substructure_t *this) { @@ -791,6 +942,10 @@ proposal_substructure_t *proposal_substructure_create(payload_type_t type) .create_substructure_enumerator = _create_substructure_enumerator, .set_spi = _set_spi, .get_spi = _get_spi, + .get_lifetime = _get_lifetime, + .get_lifebytes = _get_lifebytes, + .get_auth_method = _get_auth_method, + .get_encap_mode = _get_encap_mode, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index de06f916f..03b26e127 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -111,6 +111,35 @@ struct proposal_substructure_t { */ enumerator_t* (*create_substructure_enumerator)(proposal_substructure_t *this); + /** + * Get the (shortest) lifetime of a proposal (IKEv1 only). + * + * @return lifetime, in seconds + */ + u_int32_t (*get_lifetime)(proposal_substructure_t *this); + + /** + * Get the (shortest) life duration of a proposal (IKEv1 only). + * + * @return life duration, in bytes + */ + u_int64_t (*get_lifebytes)(proposal_substructure_t *this); + + /** + * Get the first authentication method from the proposal (IKEv1 only). + * + * @return auth method, or AUTH_NONE + */ + auth_method_t (*get_auth_method)(proposal_substructure_t *this); + + /** + * Get the (first) encapsulation mode from a proposal (IKEv1 only). + * + * @param udp set to TRUE if UDP encapsulation used + * @return ipsec encapsulation mode + */ + ipsec_mode_t (*get_encap_mode)(proposal_substructure_t *this, bool *udp); + /** * Destroys an proposal_substructure_t object. */ diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 5f739c94a..254916c55 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -339,26 +339,69 @@ METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*, METHOD(sa_payload_t, get_lifetime, u_int32_t, private_sa_payload_t *this) { - return 0; + proposal_substructure_t *substruct; + enumerator_t *enumerator; + u_int32_t lifetime = 0; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + lifetime = substruct->get_lifetime(substruct); + } + enumerator->destroy(enumerator); + + return lifetime; } METHOD(sa_payload_t, get_lifebytes, u_int64_t, private_sa_payload_t *this) { - return 0; + proposal_substructure_t *substruct; + enumerator_t *enumerator; + u_int64_t lifebytes = 0; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + lifebytes = substruct->get_lifebytes(substruct); + } + enumerator->destroy(enumerator); + + return lifebytes; } METHOD(sa_payload_t, get_auth_method, auth_method_t, private_sa_payload_t *this) { - return AUTH_NONE; + proposal_substructure_t *substruct; + enumerator_t *enumerator; + auth_method_t method = AUTH_NONE; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + method = substruct->get_auth_method(substruct); + } + enumerator->destroy(enumerator); + + return method; } METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t, private_sa_payload_t *this, bool *udp) { - *udp = FALSE; - return MODE_NONE; + proposal_substructure_t *substruct; + enumerator_t *enumerator; + ipsec_mode_t mode = MODE_NONE; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + mode = substruct->get_encap_mode(substruct, udp); + } + enumerator->destroy(enumerator); + + return mode; } METHOD2(payload_t, sa_payload_t, destroy, void, diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 7e8a9c7c7..0be39316a 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -209,10 +209,22 @@ METHOD(transform_attribute_t, get_value_chunk, chunk_t, return this->attribute_value; } -METHOD(transform_attribute_t, get_value, u_int16_t, +METHOD(transform_attribute_t, get_value, u_int64_t, private_transform_attribute_t *this) { - return this->attribute_length_or_value; + u_int64_t value = 0; + + if (this->attribute_format) + { + return this->attribute_length_or_value; + } + if (this->attribute_value.len > sizeof(value)) + { + return UINT64_MAX; + } + memcpy(((char*)&value) + sizeof(value) - this->attribute_value.len, + this->attribute_value.ptr, this->attribute_value.len); + return be64toh(value); } METHOD(transform_attribute_t, set_attribute_type, void, diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h index 52e5d8412..7eed40b3e 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.h +++ b/src/libcharon/encoding/payloads/transform_attribute.h @@ -109,7 +109,7 @@ struct transform_attribute_t { * * @return value */ - u_int16_t (*get_value) (transform_attribute_t *this); + u_int64_t (*get_value) (transform_attribute_t *this); /** * Sets the value of the attribute. From eeca2af81c22e04532585d0dd2a5284bd83d8f5c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 15:32:13 +0100 Subject: [PATCH 152/534] Removed obsolete transform attribute setters --- .../encoding/payloads/transform_attribute.c | 73 +++---------------- .../encoding/payloads/transform_attribute.h | 32 +------- 2 files changed, 13 insertions(+), 92 deletions(-) diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 0be39316a..50b5b77cc 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -174,31 +174,6 @@ METHOD(payload_t, get_length, size_t, return this->attribute_length_or_value + 4; } -METHOD(transform_attribute_t, set_value_chunk, void, - private_transform_attribute_t *this, chunk_t value) -{ - chunk_free(&this->attribute_value); - - if (value.len != 2) - { - this->attribute_value = chunk_clone(value); - this->attribute_length_or_value = value.len; - this->attribute_format = FALSE; - } - else - { - memcpy(&this->attribute_length_or_value, value.ptr, value.len); - } -} - -METHOD(transform_attribute_t, set_value, void, - private_transform_attribute_t *this, u_int16_t value) -{ - chunk_free(&this->attribute_value); - this->attribute_length_or_value = value; - this->attribute_format = TRUE; -} - METHOD(transform_attribute_t, get_value_chunk, chunk_t, private_transform_attribute_t *this) { @@ -227,36 +202,12 @@ METHOD(transform_attribute_t, get_value, u_int64_t, return be64toh(value); } -METHOD(transform_attribute_t, set_attribute_type, void, - private_transform_attribute_t *this, u_int16_t type) -{ - this->attribute_type = type & 0x7FFF; -} - METHOD(transform_attribute_t, get_attribute_type, u_int16_t, private_transform_attribute_t *this) { return this->attribute_type; } -METHOD(transform_attribute_t, clone_, transform_attribute_t*, - private_transform_attribute_t *this) -{ - private_transform_attribute_t *new; - - new = (private_transform_attribute_t*)transform_attribute_create(this->type); - - new->attribute_format = this->attribute_format; - new->attribute_type = this->attribute_type; - new->attribute_length_or_value = this->attribute_length_or_value; - - if (!new->attribute_format) - { - new->attribute_value = chunk_clone(this->attribute_value); - } - return &new->public; -} - METHOD2(payload_t, transform_attribute_t, destroy, void, private_transform_attribute_t *this) { @@ -283,16 +234,12 @@ transform_attribute_t *transform_attribute_create(payload_type_t type) .get_type = _get_type, .destroy = _destroy, }, - .set_value_chunk = _set_value_chunk, - .set_value = _set_value, .get_value_chunk = _get_value_chunk, .get_value = _get_value, - .set_attribute_type = _set_attribute_type, .get_attribute_type = _get_attribute_type, - .clone = _clone_, .destroy = _destroy, }, - .attribute_format = TRUE, + .attribute_format = FALSE, .type = type, ); return &this->public; @@ -304,26 +251,30 @@ transform_attribute_t *transform_attribute_create(payload_type_t type) transform_attribute_t *transform_attribute_create_value(payload_type_t type, transform_attribute_type_t kind, u_int64_t value) { - transform_attribute_t *attribute; + private_transform_attribute_t *this; - attribute = transform_attribute_create(type); - attribute->set_attribute_type(attribute, kind); + this = (private_transform_attribute_t*)transform_attribute_create(type); + + this->attribute_type = kind & 0x7FFF; if (value <= UINT16_MAX) { - attribute->set_value(attribute, value); + this->attribute_length_or_value = value; + this->attribute_format = TRUE; } else if (value <= UINT32_MAX) { u_int32_t val32; val32 = htonl(value); - attribute->set_value_chunk(attribute, chunk_from_thing(val32)); + this->attribute_value = chunk_clone(chunk_from_thing(val32)); + this->attribute_length_or_value = sizeof(val32); } else { value = htobe64(value); - attribute->set_value_chunk(attribute, chunk_from_thing(value)); + this->attribute_value = chunk_clone(chunk_from_thing(value)); + this->attribute_length_or_value = sizeof(value); } - return attribute; + return &this->public; } diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h index 7eed40b3e..23897a50a 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.h +++ b/src/libcharon/encoding/payloads/transform_attribute.h @@ -98,7 +98,7 @@ struct transform_attribute_t { * * Returned data are not copied. * - * @return chunk_t pointing to the value + * @return chunk_t pointing to internal value */ chunk_t (*get_value_chunk) (transform_attribute_t *this); @@ -111,29 +111,6 @@ struct transform_attribute_t { */ u_int64_t (*get_value) (transform_attribute_t *this); - /** - * Sets the value of the attribute. - * - * Value is getting copied. - * - * @param value chunk_t pointing to the value to set - */ - void (*set_value_chunk) (transform_attribute_t *this, chunk_t value); - - /** - * Sets the value of the attribute. - * - * @param value value to set - */ - void (*set_value) (transform_attribute_t *this, u_int16_t value); - - /** - * Sets the type of the attribute. - * - * @param type type to set (most significant bit is set to zero) - */ - void (*set_attribute_type) (transform_attribute_t *this, u_int16_t type); - /** * get the type of the attribute. * @@ -141,13 +118,6 @@ struct transform_attribute_t { */ u_int16_t (*get_attribute_type) (transform_attribute_t *this); - /** - * Clones an transform_attribute_t object. - * - * @return cloned transform_attribute_t object - */ - transform_attribute_t * (*clone) (transform_attribute_t *this); - /** * Destroys an transform_attribute_t object. */ From b4e815354c5b225e718dca4beb59656fdac98875 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 16:07:13 +0100 Subject: [PATCH 153/534] Map auth_class to auth method and IKEv1 proposal attribute --- .../encoding/payloads/proposal_substructure.c | 12 ++++++++++-- src/libcharon/plugins/stroke/stroke_config.c | 4 ++++ src/libcharon/sa/authenticators/authenticator.h | 10 ++++++++++ src/libcharon/sa/tasks/main_mode.c | 5 +++++ src/libstrongswan/credentials/auth_cfg.h | 2 ++ 5 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index ca19ba700..7f075f103 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -583,8 +583,12 @@ static u_int16_t get_ikev1_auth(auth_method_t method) return IKEV1_AUTH_RSA_SIG; case AUTH_DSS: return IKEV1_AUTH_DSS_SIG; + case AUTH_XAUTH_INIT_PSK: + return IKEV1_AUTH_XAUTH_INIT_PSK; + case AUTH_XAUTH_INIT_RSA: + return IKEV1_AUTH_XAUTH_INIT_RSA; default: - /* TODO-IKEv1: Handle XAUTH methods */ + /* TODO-IKEv1: Handle other XAUTH methods */ /* TODO-IKEv1: Handle ECDSA methods */ case AUTH_PSK: return IKEV1_AUTH_PSK; @@ -877,8 +881,12 @@ METHOD(proposal_substructure_t, get_auth_method, auth_method_t, return AUTH_RSA; case IKEV1_AUTH_DSS_SIG: return AUTH_DSS; + case IKEV1_AUTH_XAUTH_INIT_PSK: + return AUTH_XAUTH_INIT_PSK; + case IKEV1_AUTH_XAUTH_INIT_RSA: + return AUTH_XAUTH_INIT_RSA; default: - /* TODO-IKEv1: XAUTH, ECDSA sigs */ + /* TODO-IKEv1: other XAUTH, ECDSA sigs */ return AUTH_NONE; } } diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 97d2a7836..0d612f10e 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -473,6 +473,10 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, { cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH_PSK); } + else if (streq(auth, "xauthrsasig")) + { + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH_PUBKEY); + } else if (strneq(auth, "eap", 3)) { enumerator_t *enumerator; diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticators/authenticator.h index a3850bb7f..81164772d 100644 --- a/src/libcharon/sa/authenticators/authenticator.h +++ b/src/libcharon/sa/authenticators/authenticator.h @@ -73,6 +73,16 @@ enum auth_method_t { * ECDSA with SHA-512 on the P-521 curve as specified in RFC 4754 */ AUTH_ECDSA_521 = 11, + + /** + * IKEv1 initiator XAUTH with PSK, outside of IANA range + */ + AUTH_XAUTH_INIT_PSK = 256, + + /** + * IKEv1 initiator XAUTH with RSA, outside of IANA range + */ + AUTH_XAUTH_INIT_RSA, }; /** diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 263439b00..8a1ac6c9a 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -298,6 +298,10 @@ static auth_method_t get_auth_method(private_main_mode_t *this) { case AUTH_CLASS_PSK: return AUTH_PSK; + case AUTH_CLASS_XAUTH_PSK: + return AUTH_XAUTH_INIT_PSK; + case AUTH_CLASS_XAUTH_PUBKEY: + return AUTH_XAUTH_INIT_RSA; case AUTH_CLASS_PUBKEY: /* TODO-IKEv1: look for a key, return RSA or ECDSA */ default: @@ -586,6 +590,7 @@ static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, switch (auth) { case AUTH_CLASS_PSK: + case AUTH_CLASS_XAUTH_PSK: shared_key = lookup_shared_key(this); break; default: diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index 2554b3f2e..ea98470fe 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -44,6 +44,8 @@ enum auth_class_t { AUTH_CLASS_EAP = 3, /** authentication using pre-shared secrets in combination with XAuth */ AUTH_CLASS_XAUTH_PSK = 4, + /** authentication using public keys in combination with XAuth */ + AUTH_CLASS_XAUTH_PUBKEY = 5, }; /** From abf97847863e59fb9fab95a68c4e1e242975aa45 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 16:11:05 +0100 Subject: [PATCH 154/534] Pass concrete auth_method to key derivation, as we have that as a responder --- src/libcharon/sa/keymat_v1.c | 8 +++++--- src/libcharon/sa/keymat_v1.h | 2 +- src/libcharon/sa/tasks/main_mode.c | 7 ++----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 97a21e022..392032369 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -363,7 +363,7 @@ static void adjust_keylen(u_int16_t alg, chunk_t *key) METHOD(keymat_v1_t, derive_ike_keys, bool, private_keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, - auth_class_t auth, shared_key_t *shared_key) + auth_method_t auth, shared_key_t *shared_key) { chunk_t g_xy, g_xi, g_xr, dh_me, spi_i, spi_r, nonces, data, skeyid_e; u_int16_t alg; @@ -411,7 +411,8 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, switch (auth) { - case AUTH_CLASS_PSK: + case AUTH_PSK: + case AUTH_XAUTH_INIT_PSK: { /* SKEYID = prf(pre-shared-key, Ni_b | Nr_b) */ chunk_t psk; if (!shared_key) @@ -425,7 +426,8 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, this->prf->allocate_bytes(this->prf, nonces, &this->skeyid); break; } - case AUTH_CLASS_PUBKEY: + case AUTH_RSA: + case AUTH_XAUTH_INIT_RSA: { /* signatures : SKEYID = prf(Ni_b | Nr_b, g^xy) * pubkey encr: SKEYID = prf(hash(Ni_b | Nr_b), CKY-I | CKY-R) */ diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h index eb07e3a0c..28b9c1900 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/keymat_v1.h @@ -54,7 +54,7 @@ struct keymat_v1_t { bool (*derive_ike_keys)(keymat_v1_t *this, proposal_t *proposal, diffie_hellman_t *dh, chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_id_t *id, - auth_class_t auth, shared_key_t *shared_key); + auth_method_t auth, shared_key_t *shared_key); /** * Derive keys for the CHILD_SA. diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 8a1ac6c9a..133a7f00e 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -583,11 +583,8 @@ static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, { ike_sa_id_t *id = this->ike_sa->get_id(this->ike_sa); shared_key_t *shared_key = NULL; - auth_class_t auth; - /* TODO-IKEv1: support other authentication classes */ - auth = AUTH_CLASS_PSK; - switch (auth) + switch (this->auth_method) { case AUTH_CLASS_PSK: case AUTH_CLASS_XAUTH_PSK: @@ -597,7 +594,7 @@ static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, break; } if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh, - this->dh_value, nonce_i, nonce_r, id, auth, shared_key)) + this->dh_value, nonce_i, nonce_r, id, this->auth_method, shared_key)) { DESTROY_IF(shared_key); return FALSE; From a2f8fc97112b63966566a71bdcf20aedd1f413c2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 24 Nov 2011 16:32:14 +0100 Subject: [PATCH 155/534] Use a dedicated IKEv1 vendor ID task to fix using IKEv2 payloads in IKEv1 --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/ike_sa.c | 3 + src/libcharon/sa/task_manager_v1.c | 4 +- src/libcharon/sa/tasks/ike_vendor.c | 28 ----- src/libcharon/sa/tasks/ike_vendor_v1.c | 161 +++++++++++++++++++++++++ src/libcharon/sa/tasks/ike_vendor_v1.h | 49 ++++++++ src/libcharon/sa/tasks/task.c | 8 +- src/libcharon/sa/tasks/task.h | 2 + 8 files changed, 225 insertions(+), 31 deletions(-) create mode 100644 src/libcharon/sa/tasks/ike_vendor_v1.c create mode 100644 src/libcharon/sa/tasks/ike_vendor_v1.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index a813e97f1..6f3151ac5 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -89,6 +89,7 @@ sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ +sa/tasks/ike_vendor_v1.c sa/tasks/ike_vendor_v1.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ sa/tasks/task.c sa/tasks/task.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index b789424c0..7bccfbbc7 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -1133,6 +1134,8 @@ METHOD(ike_sa_t, initiate, status_t, if (this->version == IKEV1) { + task = (task_t*)ike_vendor_v1_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); task = (task_t*)main_mode_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); } diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 2b22bcdb5..eaab362e6 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -23,6 +23,7 @@ #include #include #include +#include #include typedef struct exchange_t exchange_t; @@ -285,6 +286,7 @@ METHOD(task_manager_t, initiate, status_t, switch (this->ike_sa->get_state(this->ike_sa)) { case IKE_CREATED: + activate_task(this, TASK_VENDOR_V1); if (activate_task(this, TASK_MAIN_MODE)) { exchange = ID_PROT; @@ -533,7 +535,7 @@ static status_t process_request(private_task_manager_t *this, switch (message->get_exchange_type(message)) { case ID_PROT: - task = (task_t *)ike_vendor_create(this->ike_sa, FALSE); + task = (task_t *)ike_vendor_v1_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); diff --git a/src/libcharon/sa/tasks/ike_vendor.c b/src/libcharon/sa/tasks/ike_vendor.c index b8fe9fe91..7b3cc6e91 100644 --- a/src/libcharon/sa/tasks/ike_vendor.c +++ b/src/libcharon/sa/tasks/ike_vendor.c @@ -49,10 +49,6 @@ static chunk_t strongswan_vid = chunk_from_chars( 0x22,0x51,0x61,0x3b,0x2e,0xbe,0x5b,0xeb ); -static chunk_t xauth6_vid = chunk_from_chars( - 0x09,0x00,0x26,0x89,0xdf,0xd6,0xb7,0x12 -); - METHOD(task_t, build, status_t, private_ike_vendor_t *this, message_t *message) { @@ -64,11 +60,6 @@ METHOD(task_t, build, status_t, vid = vendor_id_payload_create_data(VENDOR_ID, chunk_clone(strongswan_vid)); message->add_payload(message, &vid->payload_interface); - - vid = vendor_id_payload_create_data(VENDOR_ID, - chunk_clone(xauth6_vid)); - message->add_payload(message, &vid->payload_interface); - } return this->initiator ? NEED_MORE : SUCCESS; @@ -101,25 +92,6 @@ METHOD(task_t, process, status_t, DBG1(DBG_ENC, "received unknown vendor id: %#B", &data); } } - - if (payload->get_type(payload) == VENDOR_ID_V1) - { - vendor_id_payload_t *vid; - chunk_t data; - - vid = (vendor_id_payload_t*)payload; - data = vid->get_data(vid); - - if (chunk_equals(data, xauth6_vid)) - { - DBG1(DBG_IKE, "received XAuth vendor id"); - this->ike_sa->enable_extension(this->ike_sa, EXT_XAUTH); - } - else - { - DBG1(DBG_ENC, "received unknown vendor id: %#B", &data); - } - } } enumerator->destroy(enumerator); diff --git a/src/libcharon/sa/tasks/ike_vendor_v1.c b/src/libcharon/sa/tasks/ike_vendor_v1.c new file mode 100644 index 000000000..bf857a314 --- /dev/null +++ b/src/libcharon/sa/tasks/ike_vendor_v1.c @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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_vendor_v1.h" + +#include +#include + +typedef struct private_ike_vendor_v1_t private_ike_vendor_v1_t; + +/** + * Private data of an ike_vendor_v1_t object. + */ +struct private_ike_vendor_v1_t { + + /** + * Public ike_vendor_v1_t interface. + */ + ike_vendor_v1_t public; + + /** + * Associated IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * Are we the inititator of this task + */ + bool initiator; +}; + +static chunk_t xauth6_vid = chunk_from_chars( + 0x09,0x00,0x26,0x89,0xdf,0xd6,0xb7,0x12 +); + +/** + * strongSwan specific vendor ID without version, MD5("strongSwan") + */ +static chunk_t strongswan_vid = chunk_from_chars( + 0x88,0x2f,0xe5,0x6d,0x6f,0xd2,0x0d,0xbc, + 0x22,0x51,0x61,0x3b,0x2e,0xbe,0x5b,0xeb +); + +/** + * Add a vendor ID to message + */ +static void add_vendor_id(private_ike_vendor_v1_t *this, message_t *message, + chunk_t vid) +{ + vendor_id_payload_t *vid_payload; + + vid_payload = vendor_id_payload_create_data(VENDOR_ID_V1, chunk_clone(vid)); + message->add_payload(message, &vid_payload->payload_interface); +} + +METHOD(task_t, build, status_t, + private_ike_vendor_v1_t *this, message_t *message) +{ + + if (lib->settings->get_bool(lib->settings, + "charon.send_vendor_id", FALSE)) + { + add_vendor_id(this, message, strongswan_vid); + } + + add_vendor_id(this, message, xauth6_vid); + + return this->initiator ? NEED_MORE : SUCCESS; +} + +METHOD(task_t, process, status_t, + private_ike_vendor_v1_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == VENDOR_ID_V1) + { + vendor_id_payload_t *vid; + chunk_t data; + + vid = (vendor_id_payload_t*)payload; + data = vid->get_data(vid); + + if (chunk_equals(data, strongswan_vid)) + { + DBG1(DBG_IKE, "received strongSwan vendor id"); + this->ike_sa->enable_extension(this->ike_sa, EXT_STRONGSWAN); + } + else if (chunk_equals(data, xauth6_vid)) + { + DBG1(DBG_IKE, "received XAuth vendor id"); + this->ike_sa->enable_extension(this->ike_sa, EXT_XAUTH); + } + else + { + DBG1(DBG_ENC, "received unknown vendor id: %#B", &data); + } + } + } + enumerator->destroy(enumerator); + + return this->initiator ? SUCCESS : NEED_MORE; +} + +METHOD(task_t, migrate, void, + private_ike_vendor_v1_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_vendor_v1_t *this) +{ + return TASK_VENDOR_V1; +} + +METHOD(task_t, destroy, void, + private_ike_vendor_v1_t *this) +{ + free(this); +} + +/** + * See header + */ +ike_vendor_v1_t *ike_vendor_v1_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_vendor_v1_t *this; + + INIT(this, + .public = { + .task = { + .build = _build, + .process = _process, + .migrate = _migrate, + .get_type = _get_type, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/tasks/ike_vendor_v1.h b/src/libcharon/sa/tasks/ike_vendor_v1.h new file mode 100644 index 000000000..60e96ebdc --- /dev/null +++ b/src/libcharon/sa/tasks/ike_vendor_v1.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_vendor_v1 ike_vendor_v1 + * @{ @ingroup tasks + */ + +#ifndef IKE_VENDOR_V1_H_ +#define IKE_VENDOR_V1_H_ + +typedef struct ike_vendor_v1_t ike_vendor_v1_t; + +#include +#include +#include + +/** + * Vendor ID processing task for IKEv1. + */ +struct ike_vendor_v1_t { + + /** + * Implements task interface. + */ + task_t task; +}; + +/** + * Create a ike_vendor_v1 instance. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + */ +ike_vendor_v1_t *ike_vendor_v1_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** ike_vendor_v1_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index 83d0478ca..d0eed77e3 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -17,7 +17,7 @@ #include "task.h" #ifdef ME -ENUM(task_type_names, TASK_IKE_INIT, TASK_QUICK_MODE, +ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", @@ -37,9 +37,11 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_QUICK_MODE, "CHILD_REKEY", "MAIN_MODE", "QUICK_MODE", + "VENDOR_V1", + "XAUTH_REQUEST", ); #else -ENUM(task_type_names, TASK_IKE_INIT, TASK_QUICK_MODE, +ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", @@ -58,5 +60,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_QUICK_MODE, "CHILD_REKEY", "MAIN_MODE", "QUICK_MODE", + "VENDOR_V1", + "XAUTH_REQUEST", ); #endif /* ME */ diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index eebfb7a57..e76ffcd8c 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -73,6 +73,8 @@ enum task_type_t { TASK_MAIN_MODE, /** IKEv1 quick mode */ TASK_QUICK_MODE, + /** IKEv1 vendor ID payload handling */ + TASK_VENDOR_V1, /** Request the user/pass with XAUTH */ TASK_XAUTH_REQUEST, }; From 2c49c5318671988e110e5d234fbed1855717f00f Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 25 Nov 2011 08:24:30 +0100 Subject: [PATCH 156/534] IKEv1 XAuth: Fix main mode to work with XAuth PSK. --- src/libcharon/sa/tasks/main_mode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 133a7f00e..694c3f41e 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -586,8 +586,8 @@ static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, switch (this->auth_method) { - case AUTH_CLASS_PSK: - case AUTH_CLASS_XAUTH_PSK: + case AUTH_PSK: + case AUTH_XAUTH_INIT_PSK: shared_key = lookup_shared_key(this); break; default: From e63cb7f816f986231e225a4e77400aaf9adb95fa Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 25 Nov 2011 08:41:41 +0100 Subject: [PATCH 157/534] Revert "IKEv1 XAuth: Temporarilty add an "initiate_later" flag to the task manager. When set to TRUE it will cause "initiate" to be called when the current process_response call is finished. This change should be reverted once we have a better method in place." This reverts commit c6c28f4ac522dd8afb457847bca79eee77f78706. Revert "IKEv1 XAuth: Added temporary "initiate_xauth" public method to ike_sa_t. This allows us to initiate an XAuth password authentication exchange after responding to the final message of Main Mode. This change should be reverted once we have a better method to initiate this exchange." This reverts commit 5529dc50477e25df9dd5f3c442bb1521c0baf225. --- src/libcharon/sa/ike_sa.c | 13 ------------- src/libcharon/sa/ike_sa.h | 5 ----- src/libcharon/sa/task_manager.h | 5 ----- src/libcharon/sa/task_manager_v1.c | 27 +-------------------------- 4 files changed, 1 insertion(+), 49 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 7bccfbbc7..841fde34b 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -2132,18 +2132,6 @@ METHOD(ike_sa_t, destroy, void, free(this); } -METHOD(ike_sa_t, initiate_xauth, void, - private_ike_sa_t *this) -{ - if(this->extensions & EXT_XAUTH) - { - xauth_request_t *xauth_request_task = xauth_request_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, (task_t*)xauth_request_task); - - this->task_manager->initiate_later(this->task_manager); - } -} - /* * Described in header. */ @@ -2233,7 +2221,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .callback = _callback, .respond = _respond, #endif /* ME */ - .initiate_xauth = _initiate_xauth, }, .ike_sa_id = ike_sa_id->clone(ike_sa_id), .version = version, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index f21585525..2753fca1c 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -958,11 +958,6 @@ struct ike_sa_t { * Destroys a ike_sa_t object. */ void (*destroy) (ike_sa_t *this); - - /** - * Initiate an XAuth transaction - */ - void (*initiate_xauth) (ike_sa_t *this); }; /** diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index f0a1921c0..42a04fb64 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -192,11 +192,6 @@ struct task_manager_t { * Destroy the task_manager_t. */ void (*destroy) (task_manager_t *this); - - /** - * Signals the task manager to initiate immediately after completing a response - */ - void (*initiate_later) (task_manager_t *this); }; /** diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index eaab362e6..65bab998e 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -147,11 +147,6 @@ struct private_task_manager_t { * Base to calculate retransmission timeout */ double retransmit_base; - - /** - * Signal to the task manager that we need to initiate a transaction after the response is sent. - */ - bool initiate_later_flag; }; /** @@ -325,10 +320,6 @@ METHOD(task_manager_t, initiate, status_t, case TASK_QUICK_MODE: exchange = QUICK_MODE; break; - case TASK_XAUTH_REQUEST: - exchange = TRANSACTION; - new_mid = TRUE; - break; default: continue; } @@ -528,7 +519,6 @@ static status_t process_request(private_task_manager_t *this, { enumerator_t *enumerator; task_t *task = NULL; - status_t process_status; if (this->passive_tasks->get_count(this->passive_tasks) == 0) { /* create tasks depending on request type, if not already some queued */ @@ -596,14 +586,7 @@ static status_t process_request(private_task_manager_t *this, } enumerator->destroy(enumerator); - process_status = build_response(this, message); - - if(((process_status == SUCCESS) || (process_status == NEED_MORE)) && (this->initiate_later_flag == TRUE)) - { - this->initiate_later_flag = FALSE; - return initiate(this); - } - return process_status; + return build_response(this, message); } /** @@ -777,12 +760,6 @@ METHOD(task_manager_t, destroy, void, free(this); } -METHOD(task_manager_t, initiate_later, void, - private_task_manager_t *this) -{ - this->initiate_later_flag = TRUE; -} - /* * see header file */ @@ -803,7 +780,6 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .busy = _busy, .create_task_enumerator = _create_task_enumerator, .destroy = _destroy, - .initiate_later = _initiate_later, }, }, .ike_sa = ike_sa, @@ -818,7 +794,6 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) "charon.retransmit_timeout", RETRANSMIT_TIMEOUT), .retransmit_base = lib->settings->get_double(lib->settings, "charon.retransmit_base", RETRANSMIT_BASE), - .initiate_later_flag = FALSE, ); return &this->public; From 52ac2cebe2136980e372bc435f4318746bbaf8e4 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 25 Nov 2011 08:45:42 +0100 Subject: [PATCH 158/534] IKEv1 XAuth: Fix XAuth task so that it reinitiates. --- src/libcharon/sa/task_manager_v1.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 65bab998e..e672879ea 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -320,6 +320,10 @@ METHOD(task_manager_t, initiate, status_t, case TASK_QUICK_MODE: exchange = QUICK_MODE; break; + case TASK_XAUTH_REQUEST: + exchange = TRANSACTION; + new_mid = TRUE; + break; default: continue; } From fd24c700fb280d56483d239af6448d5d433e2400 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 11:25:45 +0100 Subject: [PATCH 159/534] Use proper enum types in proposal_substructure. --- src/libcharon/encoding/payloads/proposal_substructure.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 7f075f103..f758d1fbe 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -813,7 +813,7 @@ METHOD(proposal_substructure_t, get_lifetime, u_int32_t, private_proposal_substructure_t *this) { transform_substructure_t *transform; - transform_attribute_type_t type; + ikev1_life_type_t type; switch (this->protocol_id) { @@ -845,7 +845,7 @@ METHOD(proposal_substructure_t, get_lifebytes, u_int64_t, private_proposal_substructure_t *this) { transform_substructure_t *transform; - transform_attribute_type_t type; + ikev1_life_type_t type; switch (this->protocol_id) { From 38d189eee9b8c0b2c2f82a691dc7a3af2d9432fa Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 11:26:20 +0100 Subject: [PATCH 160/534] Compiler warning fixed in prf_plus_t. --- src/libstrongswan/crypto/prf_plus.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libstrongswan/crypto/prf_plus.c b/src/libstrongswan/crypto/prf_plus.c index d932d86b2..29f61197d 100644 --- a/src/libstrongswan/crypto/prf_plus.c +++ b/src/libstrongswan/crypto/prf_plus.c @@ -42,9 +42,9 @@ struct private_prf_plus_t { chunk_t seed; /** - * Buffer to store current PRF result. + * Octet which will be appended to the seed, 0 if not used */ - chunk_t buffer; + u_int8_t counter; /** * Already given out bytes in current buffer. @@ -52,9 +52,9 @@ struct private_prf_plus_t { size_t used; /** - * Octet which will be appended to the seed, 0 if not used + * Buffer to store current PRF result. */ - u_int8_t counter; + chunk_t buffer; }; METHOD(prf_plus_t, get_bytes, void, @@ -125,8 +125,8 @@ prf_plus_t *prf_plus_create(prf_t *prf, bool counter, chunk_t seed) .destroy = _destroy, }, .prf = prf, - .buffer = chunk_alloc(prf->get_block_size(prf)), .seed = chunk_clone(seed), + .buffer = chunk_alloc(prf->get_block_size(prf)), ); if (counter) From 44ff1153e8e5445c02c7174a2a3431a9c11a49a4 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 14:48:57 +0100 Subject: [PATCH 161/534] Addded ike_sa_t.set_statistic to set timestamps from task manager. --- src/libcharon/sa/ike_sa.c | 10 ++++++++++ src/libcharon/sa/ike_sa.h | 8 ++++++++ 2 files changed, 18 insertions(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 841fde34b..50b9d2f03 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -322,6 +322,15 @@ METHOD(ike_sa_t, get_statistic, u_int32_t, return 0; } +METHOD(ike_sa_t, set_statistic, void, + private_ike_sa_t *this, statistic_t kind, u_int32_t value) +{ + if (kind < STAT_MAX) + { + this->stats[kind] = value; + } +} + METHOD(ike_sa_t, get_my_host, host_t*, private_ike_sa_t *this) { @@ -2148,6 +2157,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .set_state = _set_state, .get_name = _get_name, .get_statistic = _get_statistic, + .set_statistic = _set_statistic, .process_message = _process_message, .initiate = _initiate, .get_ike_cfg = _get_ike_cfg, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 2753fca1c..832f8f141 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -315,6 +315,14 @@ struct ike_sa_t { */ u_int32_t (*get_statistic)(ike_sa_t *this, statistic_t kind); + /** + * Set statistic value of the IKE_SA. + * + * @param kind kind of value to update + * @param value value as integer + */ + void (*set_statistic)(ike_sa_t *this, statistic_t kind, u_int32_t value); + /** * Get the own host address. * From 68c6863bbb0aa6cf1308c28985de2abd9dce8d41 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 15:53:23 +0100 Subject: [PATCH 162/534] Moved main part of message processing to task managers. This will allow individual error handling for each IKE version and should allow better handling of IKEv1 retransmits. --- src/libcharon/sa/ike_sa.c | 160 +---------------------- src/libcharon/sa/task_manager_v1.c | 40 +++++- src/libcharon/sa/task_manager_v2.c | 197 ++++++++++++++++++++++++++--- 3 files changed, 225 insertions(+), 172 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 50b9d2f03..a66d2a848 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -53,7 +53,6 @@ #include #include #include -#include #ifdef ME #include @@ -934,41 +933,6 @@ METHOD(ike_sa_t, generate_message, status_t, return message->generate(message, this->keymat, packet); } -/** - * send a notify back to the sender - */ -static void send_notify_response(private_ike_sa_t *this, message_t *request, - notify_type_t type, chunk_t data) -{ - message_t *response; - packet_t *packet; - - response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); - response->set_exchange_type(response, request->get_exchange_type(request)); - response->set_request(response, FALSE); - response->set_message_id(response, request->get_message_id(request)); - response->add_notify(response, FALSE, type, data); - if (this->my_host->is_anyaddr(this->my_host)) - { - this->my_host->destroy(this->my_host); - this->my_host = request->get_destination(request); - this->my_host = this->my_host->clone(this->my_host); - } - if (this->other_host->is_anyaddr(this->other_host)) - { - this->other_host->destroy(this->other_host); - this->other_host = request->get_source(request); - this->other_host = this->other_host->clone(this->other_host); - } - response->set_source(response, this->my_host->clone(this->my_host)); - response->set_destination(response, this->other_host->clone(this->other_host)); - if (generate_message(this, response, &packet) == SUCCESS) - { - charon->sender->send(charon->sender, packet); - } - response->destroy(response); -} - METHOD(ike_sa_t, set_kmaddress, void, private_ike_sa_t *this, host_t *local, host_t *remote) { @@ -1229,127 +1193,17 @@ METHOD(ike_sa_t, process_message, status_t, private_ike_sa_t *this, message_t *message) { status_t status; - bool is_request; - u_int8_t type = 0; - if (this->state == IKE_PASSIVE) { /* do not handle messages in passive state */ return FAILED; } - - is_request = message->get_request(message); - - status = message->parse_body(message, this->keymat); - if (status == SUCCESS) - { /* check for unsupported critical payloads */ - enumerator_t *enumerator; - unknown_payload_t *unknown; - payload_t *payload; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - unknown = (unknown_payload_t*)payload; - type = payload->get_type(payload); - if (!payload_is_known(type) && - unknown->is_critical(unknown)) - { - DBG1(DBG_ENC, "payload type %N is not supported, " - "but its critical!", payload_type_names, type); - status = NOT_SUPPORTED; - } - } - enumerator->destroy(enumerator); - } - if (status != SUCCESS) - { - if (is_request) - { - switch (status) - { - case NOT_SUPPORTED: - DBG1(DBG_IKE, "critical unknown payloads found"); - if (is_request) - { - send_notify_response(this, message, - UNSUPPORTED_CRITICAL_PAYLOAD, - chunk_from_thing(type)); - this->task_manager->incr_mid(this->task_manager, FALSE); - } - break; - case PARSE_ERROR: - DBG1(DBG_IKE, "message parsing failed"); - if (is_request) - { - send_notify_response(this, message, - INVALID_SYNTAX, chunk_empty); - this->task_manager->incr_mid(this->task_manager, FALSE); - } - break; - case VERIFY_ERROR: - DBG1(DBG_IKE, "message verification failed"); - if (is_request) - { - send_notify_response(this, message, - INVALID_SYNTAX, chunk_empty); - this->task_manager->incr_mid(this->task_manager, FALSE); - } - break; - case FAILED: - DBG1(DBG_IKE, "integrity check failed"); - /* ignored */ - break; - case INVALID_STATE: - DBG1(DBG_IKE, "found encrypted message, but no keys available"); - default: - break; - } - } - DBG1(DBG_IKE, "%N %s with message ID %d processing failed", - exchange_type_names, message->get_exchange_type(message), - message->get_request(message) ? "request" : "response", - message->get_message_id(message)); - - if (this->state == IKE_CREATED) - { /* invalid initiation attempt, close SA */ - return DESTROY_ME; - } - } - else - { - /* if this IKE_SA is virgin, we check for a config */ - if (this->ike_cfg == NULL) - { - job_t *job; - host_t *me = message->get_destination(message), - *other = message->get_source(message); - this->ike_cfg = charon->backends->get_ike_cfg(charon->backends, - me, other); - if (this->ike_cfg == NULL) - { - /* no config found for these hosts, destroy */ - DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", - me, other, notify_type_names, NO_PROPOSAL_CHOSEN); - send_notify_response(this, message, - NO_PROPOSAL_CHOSEN, chunk_empty); - return DESTROY_ME; - } - /* add a timeout if peer does not establish it completely */ - job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, FALSE); - lib->scheduler->schedule_job(lib->scheduler, job, - lib->settings->get_int(lib->settings, - "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); - } - this->stats[STAT_INBOUND] = time_monotonic(NULL); - status = this->task_manager->process_message(this->task_manager, - message); - if (message->get_exchange_type(message) == IKE_AUTH && - this->state == IKE_ESTABLISHED && - lib->settings->get_bool(lib->settings, - "charon.flush_auth_cfg", FALSE)) - { /* authentication completed */ - flush_auth_cfgs(this); - } + status = this->task_manager->process_message(this->task_manager, message); + if (message->get_exchange_type(message) == IKE_AUTH && + this->state == IKE_ESTABLISHED && + lib->settings->get_bool(lib->settings, + "charon.flush_auth_cfg", FALSE)) + { /* authentication completed */ + flush_auth_cfgs(this); } return status; } diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index e672879ea..9e94d96db 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2007 Tobias Brunner - * Copyright (C) 2007-2010 Martin Willi + * Copyright (C) 2007-2011 Tobias Brunner + * Copyright (C) 2007-2011 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include #include #include +#include typedef struct exchange_t exchange_t; @@ -650,13 +651,44 @@ METHOD(task_manager_t, process_message, status_t, { u_int32_t hash, mid; host_t *me, *other; + status_t status; - mid = msg->get_message_id(msg); + status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); + if (status != SUCCESS) + { + return status; + } - /* TODO-IKEv1: update hosts more selectively */ me = msg->get_destination(msg); other = msg->get_source(msg); + /* if this IKE_SA is virgin, we check for a config */ + if (this->ike_sa->get_ike_cfg(this->ike_sa) == NULL) + { + ike_sa_id_t *ike_sa_id; + ike_cfg_t *ike_cfg; + job_t *job; + ike_cfg = charon->backends->get_ike_cfg(charon->backends, me, other); + if (ike_cfg == NULL) + { + /* no config found for these hosts, destroy */ + DBG1(DBG_IKE, "no IKE config found for %H...%H", me, other); + return DESTROY_ME; + } + this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); + ike_cfg->destroy(ike_cfg); + /* add a timeout if peer does not establish it completely */ + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE); + lib->scheduler->schedule_job(lib->scheduler, job, + lib->settings->get_int(lib->settings, + "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); + } + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + + /* TODO-IKEv1: update hosts more selectively */ + mid = msg->get_message_id(msg); if ((mid && mid == this->initiating.mid) || (this->initiating.mid == 0 && this->active_tasks->get_count(this->active_tasks))) diff --git a/src/libcharon/sa/task_manager_v2.c b/src/libcharon/sa/task_manager_v2.c index 6148a814c..8b6a36214 100644 --- a/src/libcharon/sa/task_manager_v2.c +++ b/src/libcharon/sa/task_manager_v2.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2007-2011 Tobias Brunner * Copyright (C) 2007-2010 Martin Willi * Hochschule fuer Technik Rapperswil * @@ -35,7 +35,9 @@ #include #include #include +#include #include +#include #ifdef ME #include @@ -886,16 +888,194 @@ static status_t process_request(private_task_manager_t *this, return build_response(this, message); } +METHOD(task_manager_t, incr_mid, void, + private_task_manager_t *this, bool initiate) +{ + if (initiate) + { + this->initiating.mid++; + } + else + { + this->responding.mid++; + } +} + +/** + * Send a notify back to the sender + */ +static void send_notify_response(private_task_manager_t *this, + message_t *request, notify_type_t type, + chunk_t data) +{ + message_t *response; + packet_t *packet; + host_t *me, *other; + + response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); + response->set_exchange_type(response, request->get_exchange_type(request)); + response->set_request(response, FALSE); + response->set_message_id(response, request->get_message_id(request)); + response->add_notify(response, FALSE, type, data); + me = this->ike_sa->get_my_host(this->ike_sa); + if (me->is_anyaddr(me)) + { + me = request->get_destination(request); + this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); + } + other = this->ike_sa->get_other_host(this->ike_sa); + if (other->is_anyaddr(other)) + { + other = request->get_source(request); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + } + response->set_source(response, me->clone(me)); + response->set_destination(response, other->clone(other)); + if (this->ike_sa->generate_message(this->ike_sa, response, + &packet) == SUCCESS) + { + charon->sender->send(charon->sender, packet); + } + response->destroy(response); +} + +/** + * Parse the given message and verify that it is valid. + */ +static status_t parse_message(private_task_manager_t *this, message_t *msg) +{ + status_t status; + bool is_request; + u_int8_t type = 0; + + is_request = msg->get_request(msg); + status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); + + if (status == SUCCESS) + { /* check for unsupported critical payloads */ + enumerator_t *enumerator; + unknown_payload_t *unknown; + payload_t *payload; + + enumerator = msg->create_payload_enumerator(msg); + while (enumerator->enumerate(enumerator, &payload)) + { + unknown = (unknown_payload_t*)payload; + type = payload->get_type(payload); + if (!payload_is_known(type) && + unknown->is_critical(unknown)) + { + DBG1(DBG_ENC, "payload type %N is not supported, " + "but its critical!", payload_type_names, type); + status = NOT_SUPPORTED; + } + } + enumerator->destroy(enumerator); + } + + if (status != SUCCESS) + { + if (is_request) + { + switch (status) + { + case NOT_SUPPORTED: + DBG1(DBG_IKE, "critical unknown payloads found"); + if (is_request) + { + send_notify_response(this, msg, + UNSUPPORTED_CRITICAL_PAYLOAD, + chunk_from_thing(type)); + incr_mid(this, FALSE); + } + break; + case PARSE_ERROR: + DBG1(DBG_IKE, "message parsing failed"); + if (is_request) + { + send_notify_response(this, msg, + INVALID_SYNTAX, chunk_empty); + incr_mid(this, FALSE); + } + break; + case VERIFY_ERROR: + DBG1(DBG_IKE, "message verification failed"); + if (is_request) + { + send_notify_response(this, msg, + INVALID_SYNTAX, chunk_empty); + incr_mid(this, FALSE); + } + break; + case FAILED: + DBG1(DBG_IKE, "integrity check failed"); + /* ignored */ + break; + case INVALID_STATE: + DBG1(DBG_IKE, "found encrypted message, but no keys available"); + default: + break; + } + } + DBG1(DBG_IKE, "%N %s with message ID %d processing failed", + exchange_type_names, msg->get_exchange_type(msg), + is_request ? "request" : "response", + msg->get_message_id(msg)); + + if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED) + { /* invalid initiation attempt, close SA */ + return DESTROY_ME; + } + } + return status; +} + + METHOD(task_manager_t, process_message, status_t, private_task_manager_t *this, message_t *msg) { host_t *me, *other; + status_t status; u_int32_t mid; - mid = msg->get_message_id(msg); + status = parse_message(this, msg); + if (status != SUCCESS) + { + return status; + } + me = msg->get_destination(msg); other = msg->get_source(msg); + /* if this IKE_SA is virgin, we check for a config */ + if (this->ike_sa->get_ike_cfg(this->ike_sa) == NULL) + { + ike_sa_id_t *ike_sa_id; + ike_cfg_t *ike_cfg; + job_t *job; + ike_cfg = charon->backends->get_ike_cfg(charon->backends, me, other); + if (ike_cfg == NULL) + { + /* no config found for these hosts, destroy */ + DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", + me, other, notify_type_names, NO_PROPOSAL_CHOSEN); + send_notify_response(this, msg, + NO_PROPOSAL_CHOSEN, chunk_empty); + return DESTROY_ME; + } + this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); + ike_cfg->destroy(ike_cfg); + /* add a timeout if peer does not establish it completely */ + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE); + lib->scheduler->schedule_job(lib->scheduler, job, + lib->settings->get_int(lib->settings, + "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); + } + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + + mid = msg->get_message_id(msg); if (msg->get_request(msg)) { if (mid == this->responding.mid) @@ -1021,19 +1201,6 @@ METHOD(task_manager_t, busy, bool, return (this->active_tasks->get_count(this->active_tasks) > 0); } -METHOD(task_manager_t, incr_mid, void, - private_task_manager_t *this, bool initiate) -{ - if (initiate) - { - this->initiating.mid++; - } - else - { - this->responding.mid++; - } -} - METHOD(task_manager_t, reset, void, private_task_manager_t *this, u_int32_t initiate, u_int32_t respond) { From 1960312cfd65ff46f843632ce5d19bb3df6d54f9 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 16:05:00 +0100 Subject: [PATCH 163/534] Avoid parsing retransmits we already responded to. Decryption will fail as we already moved the IV when we sent the response. Without this change, encrypted retransmits would have been discarded during parsing already. --- src/libcharon/sa/task_manager_v1.c | 71 ++++++++++++++++-------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 9e94d96db..b9d2e2336 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -653,46 +653,22 @@ METHOD(task_manager_t, process_message, status_t, host_t *me, *other; status_t status; - status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); - if (status != SUCCESS) - { - return status; - } - + /* TODO-IKEv1: update hosts more selectively */ me = msg->get_destination(msg); other = msg->get_source(msg); - - /* if this IKE_SA is virgin, we check for a config */ - if (this->ike_sa->get_ike_cfg(this->ike_sa) == NULL) - { - ike_sa_id_t *ike_sa_id; - ike_cfg_t *ike_cfg; - job_t *job; - ike_cfg = charon->backends->get_ike_cfg(charon->backends, me, other); - if (ike_cfg == NULL) - { - /* no config found for these hosts, destroy */ - DBG1(DBG_IKE, "no IKE config found for %H...%H", me, other); - return DESTROY_ME; - } - this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); - ike_cfg->destroy(ike_cfg); - /* add a timeout if peer does not establish it completely */ - ike_sa_id = this->ike_sa->get_id(this->ike_sa); - job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE); - lib->scheduler->schedule_job(lib->scheduler, job, - lib->settings->get_int(lib->settings, - "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); - } - this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, - time_monotonic(NULL)); - - /* TODO-IKEv1: update hosts more selectively */ mid = msg->get_message_id(msg); + if ((mid && mid == this->initiating.mid) || (this->initiating.mid == 0 && this->active_tasks->get_count(this->active_tasks))) { + status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); + if (status != SUCCESS) + { + return status; + } + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); charon->bus->message(charon->bus, msg, FALSE); if (process_response(this, msg) != SUCCESS) @@ -712,6 +688,35 @@ METHOD(task_manager_t, process_message, status_t, this->responding.packet->clone(this->responding.packet)); return SUCCESS; } + status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); + if (status != SUCCESS) + { + return status; + } + /* if this IKE_SA is virgin, we check for a config */ + if (this->ike_sa->get_ike_cfg(this->ike_sa) == NULL) + { + ike_sa_id_t *ike_sa_id; + ike_cfg_t *ike_cfg; + job_t *job; + ike_cfg = charon->backends->get_ike_cfg(charon->backends, me, other); + if (ike_cfg == NULL) + { + /* no config found for these hosts, destroy */ + DBG1(DBG_IKE, "no IKE config found for %H...%H", me, other); + return DESTROY_ME; + } + this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); + ike_cfg->destroy(ike_cfg); + /* add a timeout if peer does not establish it completely */ + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE); + lib->scheduler->schedule_job(lib->scheduler, job, + lib->settings->get_int(lib->settings, + "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); + } + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); charon->bus->message(charon->bus, msg, TRUE); if (process_request(this, msg) != SUCCESS) From 7519106d0749d366f5a268777462700d57ab61f2 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 16:08:12 +0100 Subject: [PATCH 164/534] Set request flag to proper value for IKEv1 messages before parsing them. --- src/libcharon/sa/task_manager_v1.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index b9d2e2336..701bb068a 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -662,6 +662,7 @@ METHOD(task_manager_t, process_message, status_t, (this->initiating.mid == 0 && this->active_tasks->get_count(this->active_tasks))) { + msg->set_request(msg, FALSE); status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); if (status != SUCCESS) { @@ -688,6 +689,7 @@ METHOD(task_manager_t, process_message, status_t, this->responding.packet->clone(this->responding.packet)); return SUCCESS; } + msg->set_request(msg, TRUE); status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); if (status != SUCCESS) { From e6732003f471032779ce5a88004bcdc02b22f9a6 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 16:24:32 +0100 Subject: [PATCH 165/534] Error reporting for invalid IKEv2 responses fixed. --- src/libcharon/sa/task_manager_v2.c | 81 ++++++++++++++---------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/src/libcharon/sa/task_manager_v2.c b/src/libcharon/sa/task_manager_v2.c index 8b6a36214..57b485ac5 100644 --- a/src/libcharon/sa/task_manager_v2.c +++ b/src/libcharon/sa/task_manager_v2.c @@ -945,10 +945,8 @@ static void send_notify_response(private_task_manager_t *this, static status_t parse_message(private_task_manager_t *this, message_t *msg) { status_t status; - bool is_request; u_int8_t type = 0; - is_request = msg->get_request(msg); status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); if (status == SUCCESS) @@ -975,47 +973,46 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg) if (status != SUCCESS) { - if (is_request) + bool is_request = msg->get_request(msg); + + switch (status) { - switch (status) - { - case NOT_SUPPORTED: - DBG1(DBG_IKE, "critical unknown payloads found"); - if (is_request) - { - send_notify_response(this, msg, - UNSUPPORTED_CRITICAL_PAYLOAD, - chunk_from_thing(type)); - incr_mid(this, FALSE); - } - break; - case PARSE_ERROR: - DBG1(DBG_IKE, "message parsing failed"); - if (is_request) - { - send_notify_response(this, msg, - INVALID_SYNTAX, chunk_empty); - incr_mid(this, FALSE); - } - break; - case VERIFY_ERROR: - DBG1(DBG_IKE, "message verification failed"); - if (is_request) - { - send_notify_response(this, msg, - INVALID_SYNTAX, chunk_empty); - incr_mid(this, FALSE); - } - break; - case FAILED: - DBG1(DBG_IKE, "integrity check failed"); - /* ignored */ - break; - case INVALID_STATE: - DBG1(DBG_IKE, "found encrypted message, but no keys available"); - default: - break; - } + case NOT_SUPPORTED: + DBG1(DBG_IKE, "critical unknown payloads found"); + if (is_request) + { + send_notify_response(this, msg, + UNSUPPORTED_CRITICAL_PAYLOAD, + chunk_from_thing(type)); + incr_mid(this, FALSE); + } + break; + case PARSE_ERROR: + DBG1(DBG_IKE, "message parsing failed"); + if (is_request) + { + send_notify_response(this, msg, + INVALID_SYNTAX, chunk_empty); + incr_mid(this, FALSE); + } + break; + case VERIFY_ERROR: + DBG1(DBG_IKE, "message verification failed"); + if (is_request) + { + send_notify_response(this, msg, + INVALID_SYNTAX, chunk_empty); + incr_mid(this, FALSE); + } + break; + case FAILED: + DBG1(DBG_IKE, "integrity check failed"); + /* ignored */ + break; + case INVALID_STATE: + DBG1(DBG_IKE, "found encrypted message, but no keys available"); + default: + break; } DBG1(DBG_IKE, "%N %s with message ID %d processing failed", exchange_type_names, msg->get_exchange_type(msg), From 983e852af87ec33cb30a96fe09414cc1646f360a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 17:45:30 +0100 Subject: [PATCH 166/534] Handle INFORMATIONAL_V1 messages when no keys have been derived yet. This allows to gracefully process the INFORMATIONAL_V1 message rules which require the payloads to be encrypted and thus the exchange to be authenticated with a HASH payload. If such an exchange is now initiated before the ISAKMP_SA is established, the message is simply sent unencrypted and without HASH payload. --- src/libcharon/encoding/message.c | 5 +++-- src/libcharon/sa/keymat_v1.c | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index aa774e0c3..17adc5eb9 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1419,8 +1419,8 @@ METHOD(message_t, generate, status_t, chunk_free(&hash); } - /* if at least one payload requires encryption, encrypt the message */ - /* TODO-IKEV1: set is_encrypted externally instead of this check? */ + /* if at least one payload requires encryption, encrypt the message. + * if we have no key material available, the flag will be reset below */ enumerator = this->payloads->create_enumerator(this->payloads); while (enumerator->enumerate(enumerator, (void**)&payload)) { @@ -1447,6 +1447,7 @@ METHOD(message_t, generate, status_t, else { DBG2(DBG_ENC, "not encrypting payloads"); + this->is_encrypted = FALSE; } ike_header = ike_header_create_version(this->major_version, diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 392032369..41a02cc86 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -759,6 +759,11 @@ METHOD(keymat_v1_t, get_hash_phase2, chunk_t, bool add_message = TRUE; char *name = "Hash"; + if (!this->prf) + { /* no keys derived yet */ + return hash; + } + /* Hashes are simple for most exchanges in Phase 2: * Hash = prf(SKEYID_a, M-ID | Complete message after HASH payload) * For Quick Mode there are three hashes: From b235e69cde38ae71e8f567de9b6387922cb6a41a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 17:54:28 +0100 Subject: [PATCH 167/534] Send an INFORMATIONAL message on IKEv1 parse errors. --- src/libcharon/sa/task_manager_v1.c | 92 +++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 701bb068a..036de7cbb 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -646,6 +646,94 @@ static status_t process_response(private_task_manager_t *this, return initiate(this); } +/** + * Send a notify in a separate INFORMATIONAL exchange back to the sender. + */ +static void send_notify_response(private_task_manager_t *this, + message_t *request, notify_type_t type, + chunk_t data) +{ + message_t *response; + packet_t *packet; + host_t *me, *other; + u_int32_t mid; + + response = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); + response->set_exchange_type(response, INFORMATIONAL_V1); + response->set_request(response, TRUE); + this->rng->get_bytes(this->rng, sizeof(mid), (void*)&mid); + response->set_message_id(response, mid); + response->add_notify(response, FALSE, type, data); + me = this->ike_sa->get_my_host(this->ike_sa); + if (me->is_anyaddr(me)) + { + me = request->get_destination(request); + this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); + } + other = this->ike_sa->get_other_host(this->ike_sa); + if (other->is_anyaddr(other)) + { + other = request->get_source(request); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + } + response->set_source(response, me->clone(me)); + response->set_destination(response, other->clone(other)); + if (this->ike_sa->generate_message(this->ike_sa, response, + &packet) == SUCCESS) + { + charon->sender->send(charon->sender, packet); + } + response->destroy(response); +} + +/** + * Parse the given message and verify that it is valid. + */ +static status_t parse_message(private_task_manager_t *this, message_t *msg) +{ + status_t status; + + status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); + + if (status != SUCCESS) + { + switch (status) + { + case PARSE_ERROR: + DBG1(DBG_IKE, "message parsing failed"); + send_notify_response(this, msg, + PAYLOAD_MALFORMED, chunk_empty); + break; + case VERIFY_ERROR: + DBG1(DBG_IKE, "message verification failed"); + send_notify_response(this, msg, + PAYLOAD_MALFORMED, chunk_empty); + break; + case FAILED: + DBG1(DBG_IKE, "integrity check failed"); + send_notify_response(this, msg, + PAYLOAD_MALFORMED, chunk_empty); + break; + case INVALID_STATE: + DBG1(DBG_IKE, "found encrypted message, but no keys available"); + send_notify_response(this, msg, + PAYLOAD_MALFORMED, chunk_empty); + default: + break; + } + DBG1(DBG_IKE, "%N %s with message ID %d processing failed", + exchange_type_names, msg->get_exchange_type(msg), + msg->get_request(msg) ? "request" : "response", + msg->get_message_id(msg)); + + if (this->ike_sa->get_state(this->ike_sa) == IKE_CREATED) + { /* invalid initiation attempt, close SA */ + return DESTROY_ME; + } + } + return status; +} + METHOD(task_manager_t, process_message, status_t, private_task_manager_t *this, message_t *msg) { @@ -663,7 +751,7 @@ METHOD(task_manager_t, process_message, status_t, this->active_tasks->get_count(this->active_tasks))) { msg->set_request(msg, FALSE); - status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); + status = parse_message(this, msg); if (status != SUCCESS) { return status; @@ -690,7 +778,7 @@ METHOD(task_manager_t, process_message, status_t, return SUCCESS; } msg->set_request(msg, TRUE); - status = msg->parse_body(msg, this->ike_sa->get_keymat(this->ike_sa)); + status = parse_message(this, msg); if (status != SUCCESS) { return status; From 29a5e0707eb6cb1fd3f23b399af8f2fa0e7efe9b Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 17:58:37 +0100 Subject: [PATCH 168/534] Handle unsupported IKEv1 exchange types more specifically. --- src/libcharon/encoding/message.c | 2 +- src/libcharon/sa/task_manager_v1.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 17adc5eb9..3b45b7608 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1896,7 +1896,7 @@ METHOD(message_t, parse_body, status_t, DBG1(DBG_ENC, "no message rules specified for a %N %s", exchange_type_names, this->exchange_type, this->is_request ? "request" : "response"); - return PARSE_ERROR; + return NOT_SUPPORTED; } status = parse_payloads(this); diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 036de7cbb..c1868f224 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -699,6 +699,11 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg) { switch (status) { + case NOT_SUPPORTED: + DBG1(DBG_IKE, "unsupported exchange type"); + send_notify_response(this, msg, + INVALID_EXCHANGE_TYPE, chunk_empty); + break; case PARSE_ERROR: DBG1(DBG_IKE, "message parsing failed"); send_notify_response(this, msg, From 37639e94fba52dad26f8205ac3c263b34e697720 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 17:59:39 +0100 Subject: [PATCH 169/534] Handle invalid IKEv1 hashes more specifically. --- src/libcharon/encoding/message.c | 2 +- src/libcharon/encoding/payloads/notify_payload.h | 2 ++ src/libcharon/sa/task_manager_v1.c | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 3b45b7608..6c6004fac 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1942,7 +1942,7 @@ METHOD(message_t, parse_body, status_t, DBG1(DBG_ENC, "our hash does not match received %B", &other_hash); chunk_free(&hash); - return VERIFY_ERROR; + return FAILED; } DBG2(DBG_ENC, "verified IKEv1 message with hash %B", &hash); chunk_free(&hash); diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index 1fc310962..9539231ca 100644 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -51,6 +51,8 @@ enum notify_type_t { /* IKEv1 only */ PAYLOAD_MALFORMED = 16, INVALID_KE_PAYLOAD = 17, + /* IKEv1 only */ + INVALID_HASH_INFORMATION = 23, AUTHENTICATION_FAILED = 24, SINGLE_PAIR_REQUIRED = 34, NO_ADDITIONAL_SAS = 35, diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index c1868f224..5c9c926d8 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -717,7 +717,7 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg) case FAILED: DBG1(DBG_IKE, "integrity check failed"); send_notify_response(this, msg, - PAYLOAD_MALFORMED, chunk_empty); + INVALID_HASH_INFORMATION, chunk_empty); break; case INVALID_STATE: DBG1(DBG_IKE, "found encrypted message, but no keys available"); From 6be8d33daadede559f877adbfe5b21225e27911a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 18:00:06 +0100 Subject: [PATCH 170/534] Don't respond to malformed INFORMATIONAL_V1 messages with another INFORMATIONAL_V1 exchange. --- src/libcharon/sa/task_manager_v1.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 5c9c926d8..fe2f7c7ec 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -658,6 +658,12 @@ static void send_notify_response(private_task_manager_t *this, host_t *me, *other; u_int32_t mid; + if (request->get_exchange_type(request) == INFORMATIONAL_V1) + { /* don't respond to INFORMATIONAL requests to avoid a notify war */ + DBG1(DBG_IKE, "ignore malformed INFORMATIONAL request"); + return; + } + response = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); response->set_exchange_type(response, INFORMATIONAL_V1); response->set_request(response, TRUE); From 4cfd0db854f0308a824d62b6a030ba88233006e8 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 18:01:25 +0100 Subject: [PATCH 171/534] Respond with NO_PROPOSAL_CHOSEN, if we don't find an ike_cfg. --- src/libcharon/sa/task_manager_v1.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index fe2f7c7ec..442791881 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -804,7 +804,10 @@ METHOD(task_manager_t, process_message, status_t, if (ike_cfg == NULL) { /* no config found for these hosts, destroy */ - DBG1(DBG_IKE, "no IKE config found for %H...%H", me, other); + DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", + me, other, notify_type_names, NO_PROPOSAL_CHOSEN); + send_notify_response(this, msg, + NO_PROPOSAL_CHOSEN, chunk_empty); return DESTROY_ME; } this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); From 24ddf03f52839c9aa68df8cdebda37ac2c0162c0 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 18:57:03 +0100 Subject: [PATCH 172/534] Added an option to create a generator that does not log debug messages. --- src/libcharon/encoding/generator.c | 112 ++++++++++++++++++++++------- src/libcharon/encoding/generator.h | 8 +++ 2 files changed, 96 insertions(+), 24 deletions(-) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 43b157cc1..823a4ec10 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -108,6 +109,11 @@ struct private_generator_t { * to hold the length of the transform attribute in bytes. */ u_int16_t attribute_length; + + /** + * TRUE, if debug messages should be logged during generation. + */ + bool debug; }; /** @@ -155,8 +161,11 @@ static void make_space_available(private_generator_t *this, int bits) new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE; out_position_offset = this->out_position - this->buffer; - DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte", - old_buffer_size, new_buffer_size); + if (this->debug) + { + DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte", + old_buffer_size, new_buffer_size); + } this->buffer = realloc(this->buffer,new_buffer_size); this->out_position = (this->buffer + out_position_offset); @@ -244,7 +253,10 @@ static void generate_u_int_type(private_generator_t *this, low = *(this->out_position) & 0x0F; /* high is set, low_val is not changed */ *(this->out_position) = high | low; - DBG3(DBG_ENC, " => %d", *(this->out_position)); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *(this->out_position)); + } /* write position is not changed, just bit position is moved */ this->current_bit = 4; } @@ -255,7 +267,10 @@ static void generate_u_int_type(private_generator_t *this, /* low of current byte in buffer has to be set to the new value*/ low = *((u_int8_t *)(this->data_struct + offset)) & 0x0F; *(this->out_position) = high | low; - DBG3(DBG_ENC, " => %d", *(this->out_position)); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *(this->out_position)); + } this->out_position++; this->current_bit = 0; } @@ -274,7 +289,10 @@ static void generate_u_int_type(private_generator_t *this, { /* 8 bit values are written as they are */ *this->out_position = *((u_int8_t *)(this->data_struct + offset)); - DBG3(DBG_ENC, " => %d", *(this->out_position)); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *(this->out_position)); + } this->out_position++; break; } @@ -299,7 +317,10 @@ static void generate_u_int_type(private_generator_t *this, val |= 0x8000; } val = htons(val); - DBG3(DBG_ENC, " => %d", val); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", val); + } /* write bytes to buffer (set bit is overwritten) */ write_bytes_to_buffer(this, &val, sizeof(u_int16_t)); this->current_bit = 0; @@ -311,14 +332,20 @@ static void generate_u_int_type(private_generator_t *this, case CONFIGURATION_ATTRIBUTE_LENGTH: { u_int16_t val = htons(*((u_int16_t*)(this->data_struct + offset))); - DBG3(DBG_ENC, " %b", &val, sizeof(u_int16_t)); + if (this->debug) + { + DBG3(DBG_ENC, " %b", &val, sizeof(u_int16_t)); + } write_bytes_to_buffer(this, &val, sizeof(u_int16_t)); break; } case U_INT_32: { u_int32_t val = htonl(*((u_int32_t*)(this->data_struct + offset))); - DBG3(DBG_ENC, " %b", &val, sizeof(u_int32_t)); + if (this->debug) + { + DBG3(DBG_ENC, " %b", &val, sizeof(u_int32_t)); + } write_bytes_to_buffer(this, &val, sizeof(u_int32_t)); break; } @@ -327,8 +354,11 @@ static void generate_u_int_type(private_generator_t *this, /* 64 bit are written as-is, no host order conversion */ write_bytes_to_buffer(this, this->data_struct + offset, sizeof(u_int64_t)); - DBG3(DBG_ENC, " %b", this->data_struct + offset, - sizeof(u_int64_t)); + if (this->debug) + { + DBG3(DBG_ENC, " %b", this->data_struct + offset, + sizeof(u_int64_t)); + } break; } default: @@ -361,7 +391,10 @@ static void generate_flag(private_generator_t *this, u_int32_t offset) } *(this->out_position) = *(this->out_position) | flag; - DBG3(DBG_ENC, " => %d", *this->out_position); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *this->out_position); + } this->current_bit++; if (this->current_bit >= 8) @@ -380,12 +413,16 @@ static void generate_from_chunk(private_generator_t *this, u_int32_t offset) if (this->current_bit != 0) { - DBG1(DBG_ENC, "can not generate a chunk at Bitpos %d", this->current_bit); + DBG1(DBG_ENC, "can not generate a chunk at bitpos %d", + this->current_bit); return ; } value = (chunk_t *)(this->data_struct + offset); - DBG3(DBG_ENC, " %B", value); + if (this->debug) + { + DBG3(DBG_ENC, " %B", value); + } write_bytes_to_buffer(this, value->ptr, value->len); } @@ -397,7 +434,10 @@ METHOD(generator_t, get_chunk, chunk_t, *lenpos = (u_int32_t*)(this->buffer + this->header_length_offset); data = chunk_create(this->buffer, get_length(this)); - DBG3(DBG_ENC, "generated data of this generator %B", &data); + if (this->debug) + { + DBG3(DBG_ENC, "generated data of this generator %B", &data); + } return data; } @@ -413,16 +453,22 @@ METHOD(generator_t, generate_payload, void, offset_start = this->out_position - this->buffer; - DBG2(DBG_ENC, "generating payload of type %N", - payload_type_names, payload_type); + if (this->debug) + { + DBG2(DBG_ENC, "generating payload of type %N", + payload_type_names, payload_type); + } /* each payload has its own encoding rules */ rule_count = payload->get_encoding_rules(payload, &rules); for (i = 0; i < rule_count;i++) { - DBG2(DBG_ENC, " generating rule %d %N", - i, encoding_type_names, rules[i].type); + if (this->debug) + { + DBG2(DBG_ENC, " generating rule %d %N", + i, encoding_type_names, rules[i].type); + } switch ((int)rules[i].type) { case U_INT_4: @@ -499,7 +545,10 @@ METHOD(generator_t, generate_payload, void, { if (!this->attribute_format) { - DBG2(DBG_ENC, "attribute value has not fixed size"); + if (this->debug) + { + DBG2(DBG_ENC, "attribute value has not fixed size"); + } /* the attribute value is generated */ generate_from_chunk(this, rules[i].offset); } @@ -511,11 +560,14 @@ METHOD(generator_t, generate_payload, void, return; } } - DBG2(DBG_ENC, "generating %N payload finished", - payload_type_names, payload_type); - DBG3(DBG_ENC, "generated data for this payload %b", - this->buffer + offset_start, - this->out_position - this->buffer - offset_start); + if (this->debug) + { + DBG2(DBG_ENC, "generating %N payload finished", + payload_type_names, payload_type); + DBG3(DBG_ENC, "generated data for this payload %b", + this->buffer + offset_start, + this->out_position - this->buffer - offset_start); + } } METHOD(generator_t, destroy, void, @@ -539,6 +591,7 @@ generator_t *generator_create() .destroy = _destroy, }, .buffer = malloc(GENERATOR_DATA_BUFFER_SIZE), + .debug = TRUE, ); this->out_position = this->buffer; @@ -547,3 +600,14 @@ generator_t *generator_create() return &this->public; } +/* + * Described in header + */ +generator_t *generator_create_no_dbg() +{ + private_generator_t *this = (private_generator_t*)generator_create(); + + this->debug = FALSE; + + return &this->public; +} diff --git a/src/libcharon/encoding/generator.h b/src/libcharon/encoding/generator.h index fe561fdfd..c2c0aad2a 100644 --- a/src/libcharon/encoding/generator.h +++ b/src/libcharon/encoding/generator.h @@ -72,4 +72,12 @@ struct generator_t { */ generator_t *generator_create(void); +/** + * Constructor to create a generator that does not log any debug messages > 1. + * + * @return generator_t object. + */ +generator_t *generator_create_no_dbg(void); + + #endif /** GENERATOR_H_ @}*/ From 9eefb5f9b47eb9561cce988313564e6286c57348 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 25 Nov 2011 18:58:18 +0100 Subject: [PATCH 173/534] Use quiet generator when creating IKEv1 message hashes. This avoids cluttering the log with duplicate log messages when generating and especially confusing log messages when parsing authenticated messages. --- src/libcharon/sa/keymat_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 41a02cc86..98d12fb4f 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -820,7 +820,7 @@ METHOD(keymat_v1_t, get_hash_phase2, chunk_t, this->prf->set_key(this->prf, this->skeyid_a); if (add_message) { - generator_t *generator = generator_create(); + generator_t *generator = generator_create_no_dbg(); chunk_t msg = get_message_data(message, generator); this->prf->allocate_bytes(this->prf, data, NULL); this->prf->allocate_bytes(this->prf, msg, &hash); From 65359ccbbc0540d719d56d4d8de7e0d94c498145 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 29 Nov 2011 09:15:59 +0100 Subject: [PATCH 174/534] IKEv1 XAuth: Add "initiate xauth" method, which adds the xauth task into the queue for initiation. --- src/libcharon/sa/ike_sa.c | 9 +++++++++ src/libcharon/sa/ike_sa.h | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index a66d2a848..2de57d693 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1018,6 +1018,14 @@ METHOD(ike_sa_t, initiate_mediated, status_t, } #endif /* ME */ +METHOD(ike_sa_t, initiate_xauth, status_t, + private_ike_sa_t *this) +{ + xauth_request_t *task = xauth_request_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, (task_t*)task); + return this->task_manager->initiate(this->task_manager); +} + /** * Resolve DNS host in configuration */ @@ -2085,6 +2093,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .callback = _callback, .respond = _respond, #endif /* ME */ + .initiate_xauth = _initiate_xauth, }, .ike_sa_id = ike_sa_id->clone(ike_sa_id), .version = version, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 832f8f141..882de41b2 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -966,6 +966,11 @@ struct ike_sa_t { * Destroys a ike_sa_t object. */ void (*destroy) (ike_sa_t *this); + + /** + * Initiate an XAuth authentication exchange. + */ + status_t (*initiate_xauth) (ike_sa_t *this); }; /** From 2e210e3ef5e798dd194318c5a8a8a24271684dd3 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 29 Nov 2011 09:24:29 +0100 Subject: [PATCH 175/534] IKEv1 XAuth: Added a job to call the initiate_xauth method of ike_sa after the completion of the current set of tasks is complete. --- src/libcharon/Makefile.am | 1 + .../processing/jobs/initiate_xauth_job.c | 85 +++++++++++++++++++ .../processing/jobs/initiate_xauth_job.h | 49 +++++++++++ 3 files changed, 135 insertions(+) create mode 100644 src/libcharon/processing/jobs/initiate_xauth_job.c create mode 100644 src/libcharon/processing/jobs/initiate_xauth_job.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 6f3151ac5..538774928 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -57,6 +57,7 @@ processing/jobs/start_action_job.c processing/jobs/start_action_job.h \ processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \ +processing/jobs/initiate_xauth_job.c processing/jobs/initiate_xauth_job.h \ sa/authenticators/authenticator.c sa/authenticators/authenticator.h \ sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \ sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ diff --git a/src/libcharon/processing/jobs/initiate_xauth_job.c b/src/libcharon/processing/jobs/initiate_xauth_job.c new file mode 100644 index 000000000..0ec12dfdb --- /dev/null +++ b/src/libcharon/processing/jobs/initiate_xauth_job.c @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2007-2008 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 "initiate_xauth_job.h" + +#include +#include + + +typedef struct private_initiate_xauth_job_t private_initiate_xauth_job_t; + +/** + * Private data of an initiate_xauth_job_t Object + */ +struct private_initiate_xauth_job_t { + /** + * public initiate_xauth_job_t interface + */ + initiate_xauth_job_t public; + + /** + * ID of the IKE_SA of the mediated connection. + */ + ike_sa_id_t *ike_sa_id; +}; + +METHOD(job_t, destroy, void, + private_initiate_xauth_job_t *this) +{ + DESTROY_IF(this->ike_sa_id); + free(this); +} + +METHOD(job_t, initiate, void, + private_initiate_xauth_job_t *this) +{ + ike_sa_t *ike_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->ike_sa_id); + if (ike_sa) + { + DBG1(DBG_IKE, "INITIATING XAUTH!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); + ike_sa->initiate_xauth(ike_sa); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + destroy(this); +} + +METHOD(job_t, get_priority, job_priority_t, + private_initiate_xauth_job_t *this) +{ + return JOB_PRIO_MEDIUM; +} + +/** + * Creates an empty job + */ +initiate_xauth_job_t *initiate_xauth_job_create(ike_sa_id_t *ike_sa_id) +{ + private_initiate_xauth_job_t *this; + INIT(this, + .public = { + .job_interface = { + .get_priority = _get_priority, + .destroy = _destroy, + .execute = _initiate, + }, + }, + .ike_sa_id = ike_sa_id->clone(ike_sa_id), + ); + return &this->public; +} diff --git a/src/libcharon/processing/jobs/initiate_xauth_job.h b/src/libcharon/processing/jobs/initiate_xauth_job.h new file mode 100644 index 000000000..90271414d --- /dev/null +++ b/src/libcharon/processing/jobs/initiate_xauth_job.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2007-2008 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup initiate_xauth_job initiate_xauth_job + * @{ @ingroup cjobs + */ + +#ifndef INITIATE_XAUTH_JOB_H_ +#define INITIATE_XAUTH_JOB_H_ + +typedef struct initiate_xauth_job_t initiate_xauth_job_t; + +#include +#include + +/** + * Class representing a INITIATE_XAUTH Job. + * + * This job will an XAuth authentication exchange. + */ +struct initiate_xauth_job_t { + /** + * implements job_t interface + */ + job_t job_interface; +}; + +/** + * Creates a job of type INITIATE_XAUTH. + * + * @param ike_sa_id_t identification of the ike_sa as ike_sa_id_t object (gets cloned) + * @return job object + */ +initiate_xauth_job_t *initiate_xauth_job_create(ike_sa_id_t *ike_sa_id); + +#endif /** INITIATE_XAUTH_JOB_H_ @}*/ From 56fb0f0b3a27cd63a56651aa02d5b062dad0f471 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 29 Nov 2011 10:42:31 +0100 Subject: [PATCH 176/534] IKEv1 XAuth: Added XAuthResp authentication modes. --- src/libcharon/sa/authenticators/authenticator.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticators/authenticator.h index 81164772d..1161583c9 100644 --- a/src/libcharon/sa/authenticators/authenticator.h +++ b/src/libcharon/sa/authenticators/authenticator.h @@ -79,10 +79,20 @@ enum auth_method_t { */ AUTH_XAUTH_INIT_PSK = 256, + /** + * IKEv1 responder XAUTH with PSK, outside of IANA range + */ + AUTH_XAUTH_RESP_PSK, + /** * IKEv1 initiator XAUTH with RSA, outside of IANA range */ AUTH_XAUTH_INIT_RSA, + + /** + * IKEv1 responder XAUTH with RSA, outside of IANA range + */ + AUTH_XAUTH_RESP_RSA, }; /** From ef2eac7fb06001e715ced5b744b2b40fd992d134 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 29 Nov 2011 10:52:31 +0100 Subject: [PATCH 177/534] IKEv1 XAuth: Change the main_mode task to use the new initiate_xauth job instead of the old MIGRATE method. --- src/libcharon/sa/tasks/main_mode.c | 31 ++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 694c3f41e..3a051a6e7 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -28,6 +28,7 @@ #include #include #include +#include typedef struct private_main_mode_t private_main_mode_t; @@ -662,10 +663,18 @@ METHOD(task_t, build_r, status_t, this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - /* TODO-IKEv1: Check the proposal for XAuthInit* auth modes */ - /* TODO-IKEv1: check for XAUTH rounds, queue them */ - if(0) /* TODO-IKEv1: Change to 1 if XAUTH is desired. */ - return MIGRATE; + switch (this->auth_method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: /* There should be more INIT cases here once added */ + { + job_t *job = (job_t *) initiate_xauth_job_create(this->ike_sa->get_id(this->ike_sa)); + lib->processor->queue_job(lib->processor, job); + break; + } + default: + break; + } return SUCCESS; } default: @@ -767,6 +776,20 @@ METHOD(task_t, process_i, status_t, this->ike_sa->get_other_id(this->ike_sa)); this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + switch (this->auth_method) + { + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: /* There should be more RESP cases here once added */ + { + job_t *job = (job_t *) initiate_xauth_job_create(this->ike_sa->get_id(this->ike_sa)); + lib->processor->queue_job(lib->processor, job); + break; + } + default: + break; + } + return SUCCESS; } default: From c961d110abbb29df9898d97f2f3d5c849e1f96bb Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 29 Nov 2011 11:04:36 +0100 Subject: [PATCH 178/534] IKEv1 XAuth + CfgMode: Added ability to process CfgMode messages in the xauth task. Migrated away from using the MIGRATE method to switch queues. --- src/libcharon/sa/tasks/xauth_request.c | 649 +++++++++++++++++++++---- 1 file changed, 558 insertions(+), 91 deletions(-) diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c index 0a35889e1..1c9f115b2 100644 --- a/src/libcharon/sa/tasks/xauth_request.c +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -43,27 +43,53 @@ struct private_xauth_request_t { linked_list_t *requested; /** - * The user name - */ - chunk_t user_name; - - /** - * The user pass - */ - chunk_t user_pass; - - /** - * The current state of the task + * The current and next state of the task */ enum { TASK_XAUTH_INIT, - TASK_XAUTH_PASS_DONE, - } state; + TASK_XAUTH_PASS_VERIFY, + TASK_XAUTH_COMPLETE, + } state, next_state; /** * The status of the XAuth request */ status_t status; + + /** + * The current auth config + */ + auth_cfg_t *auth_cfg; + + /** + * The received XAuth Status + */ + u_int16_t xauth_status_data; + + /** + * The received XAuth user name + */ + chunk_t xauth_user_name; + + /** + * The received XAuth user pass + */ + chunk_t xauth_user_pass; + + /** + * Whether the user name attribute was received + */ + bool xauth_user_name_recv; + + /** + * Whether the user pass attribute was received + */ + bool xauth_user_pass_recv; + + /** + * Whether the XAuth status attribute was received + */ + bool xauth_status_recv; }; /** @@ -76,124 +102,560 @@ typedef struct { attribute_handler_t *handler; } entry_t; +/** + * Get the first authentcation config from peer config + */ +static auth_cfg_t *get_auth_cfg(private_xauth_request_t *this, bool local) +{ + enumerator_t *enumerator; + auth_cfg_t *cfg = NULL; + peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, + local); + enumerator->enumerate(enumerator, &cfg); + enumerator->destroy(enumerator); + return cfg; +} + +/** + * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip + */ +static configuration_attribute_t *build_vip(host_t *vip) +{ + configuration_attribute_type_t type; + chunk_t chunk, prefix; + + if (vip->get_family(vip) == AF_INET) + { + type = INTERNAL_IP4_ADDRESS; + if (vip->is_anyaddr(vip)) + { + chunk = chunk_empty; + } + else + { + chunk = vip->get_address(vip); + } + } + else + { + type = INTERNAL_IP6_ADDRESS; + if (vip->is_anyaddr(vip)) + { + chunk = chunk_empty; + } + else + { + prefix = chunk_alloca(1); + *prefix.ptr = 64; + chunk = vip->get_address(vip); + chunk = chunk_cata("cc", chunk, prefix); + } + } + return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE, + type, chunk); +} + +/** + * Handle a received attribute as initiator + */ +static void handle_attribute(private_xauth_request_t *this, + configuration_attribute_t *ca) +{ + attribute_handler_t *handler = NULL; + enumerator_t *enumerator; + entry_t *entry; + + /* find the handler which requested this attribute */ + enumerator = this->requested->create_enumerator(this->requested); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->type == ca->get_type(ca)) + { + handler = entry->handler; + this->requested->remove_at(this->requested, enumerator); + free(entry); + break; + } + } + enumerator->destroy(enumerator); + + /* and pass it to the handle function */ + handler = hydra->attributes->handle(hydra->attributes, + this->ike_sa->get_other_id(this->ike_sa), handler, + ca->get_type(ca), ca->get_chunk(ca)); + if (handler) + { + this->ike_sa->add_configuration_attribute(this->ike_sa, + handler, ca->get_type(ca), ca->get_chunk(ca)); + } +} + +/** + * process a single configuration attribute + */ +static void process_attribute(private_xauth_request_t *this, + configuration_attribute_t *ca) +{ + host_t *ip; + chunk_t addr; + int family = AF_INET6; + + switch (ca->get_type(ca)) + { + case XAUTH_USER_NAME: + this->xauth_user_name = ca->get_chunk(ca); + this->xauth_user_name_recv = TRUE; + break; + case XAUTH_USER_PASSWORD: + this->xauth_user_pass = ca->get_chunk(ca); + this->xauth_user_pass_recv = TRUE; + break; + case XAUTH_STATUS: + this->xauth_status_data = ca->get_value(ca); + this->xauth_status_recv = TRUE; + break; + case INTERNAL_IP4_ADDRESS: + family = AF_INET; + /* fall */ + case INTERNAL_IP6_ADDRESS: + { + addr = ca->get_chunk(ca); + if (addr.len == 0) + { + ip = host_create_any(family); + } + else + { + /* skip prefix byte in IPv6 payload*/ + if (family == AF_INET6) + { + addr.len--; + } + ip = host_create_from_chunk(family, addr, 0); + } + if (ip) + { + DESTROY_IF(this->virtual_ip); + this->virtual_ip = ip; + } + break; + } + case INTERNAL_IP4_SERVER: + case INTERNAL_IP6_SERVER: + /* assume it's a Windows client if we see proprietary attributes */ + this->ike_sa->enable_extension(this->ike_sa, EXT_MS_WINDOWS); + /* fall */ + default: + { + if (this->initiator) + { + handle_attribute(this, ca); + } + } + } +} + +/** + * Scan for configuration payloads and attributes + */ +static status_t process_payloads(private_xauth_request_t *this, message_t *message) +{ + enumerator_t *enumerator, *attributes; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch(payload->get_type(payload)) + { + case CONFIGURATION: + case CONFIGURATION_V1: + { + cp_payload_t *cp = (cp_payload_t*)payload; + configuration_attribute_t *ca; + + switch (cp->get_type(cp)) + { + case CFG_REQUEST: + case CFG_REPLY: + case CFG_SET: + case CFG_ACK: + { + attributes = cp->create_attribute_enumerator(cp); + while (attributes->enumerate(attributes, &ca)) + { + DBG2(DBG_IKE, "processing %N attribute", + configuration_attribute_type_names, ca->get_type(ca)); + process_attribute(this, ca); + } + attributes->destroy(attributes); + break; + } + default: + DBG1(DBG_IKE, "ignoring %N config payload", + config_type_names, cp->get_type(cp)); + break; + } + + switch(this->state) + { + case TASK_XAUTH_INIT: + if(((cp->get_type(cp) != CFG_REQUEST) && (cp->get_type(cp) != CFG_REPLY)) || + (this->xauth_user_name_recv != TRUE) || + (this->xauth_user_pass_recv != TRUE)) + { + /* Didn't get an XAuth message, assume we're a ConfigMode message, set state appropriately */ + this->state = TASK_XAUTH_COMPLETE; + this->next_state = TASK_XAUTH_COMPLETE; + this->status = SUCCESS; + break; + } + this->next_state = TASK_XAUTH_PASS_VERIFY; + break; + case TASK_XAUTH_PASS_VERIFY: + if(((cp->get_type(cp) != CFG_SET) && (cp->get_type(cp) != CFG_ACK)) || + (this->xauth_status_recv != TRUE)) + { + DBG1(DBG_IKE, "Didn't receive XAuth status."); + return FAILED; + } + /* Set the return status for the build call */ + if(cp->get_type(cp) != CFG_ACK) + { + this->status = (this->xauth_status_data == XAUTH_STATUS_OK ? SUCCESS : FAILED); + } + else + { + this->status = SUCCESS; + } + this->next_state = TASK_XAUTH_COMPLETE; + break; + default: + this->next_state = TASK_XAUTH_COMPLETE; + this->status = SUCCESS; + break; + } + } + default: + break; + } + } + enumerator->destroy(enumerator); + return NEED_MORE; +} + METHOD(task_t, build_i, status_t, private_xauth_request_t *this, message_t *message) { - cp_payload_t *cp; + cp_payload_t *cp = NULL; chunk_t chunk = chunk_empty; + ike_version_t version; + payload_type_t cp_type; + payload_type_t ca_type; + host_t *vip; + peer_cfg_t *config; + enumerator_t *enumerator; + attribute_handler_t *handler; + configuration_attribute_type_t type; + chunk_t data; + DBG1(DBG_IKE, "%s: state %d", __func__, this->state); + + version = this->ike_sa->get_version(this->ike_sa); + if(version == IKEV1) + { + if(this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { + DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!NEED_MORE!!!!!!!!!!!!!!!!!!!!!"); + return NEED_MORE; + } + + if(!this->auth_cfg) + { + this->auth_cfg = get_auth_cfg(this, TRUE); + } + switch((uintptr_t)this->auth_cfg->get(this->auth_cfg, AUTH_RULE_AUTH_CLASS)) + { + case AUTH_CLASS_XAUTH_PSK: + case AUTH_CLASS_XAUTH_PUBKEY: + break; + default: + /* We aren't XAuth, so do nothing */ + DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!SUCCESS!!!!!!!!!!!!!!!!!!!!!"); + return SUCCESS; + } + cp_type = CONFIGURATION_V1; + ca_type = CONFIGURATION_ATTRIBUTE_V1; + } + else /* IKEv2 */ + { + /* IKEv2 does not support XAuth, skip those states. */ + this->state = TASK_XAUTH_COMPLETE; + if (message->get_message_id(message) == 1) + { /* in first IKE_AUTH only */ + DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!NEED_MORE!!!!!!!!!!!!!!!!!!!!!"); + return NEED_MORE; + } + cp_type = CONFIGURATION; + ca_type = CONFIGURATION_ATTRIBUTE; + } switch(this->state) { case TASK_XAUTH_INIT: - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp = cp_payload_create_type(cp_type, CFG_REQUEST); cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk)); + ca_type, XAUTH_USER_NAME, chunk)); cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk)); + ca_type, XAUTH_USER_PASSWORD, chunk)); break; - case TASK_XAUTH_PASS_DONE: - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET); + case TASK_XAUTH_PASS_VERIFY: + cp = cp_payload_create_type(cp_type, CFG_SET); cp->add_attribute(cp, configuration_attribute_create_value( XAUTH_STATUS, (this->status == FAILED ? XAUTH_STATUS_FAIL : XAUTH_STATUS_OK))); break; + case TASK_XAUTH_COMPLETE: + /* ConfigMode stuff */ + /* reuse virtual IP if we already have one */ + vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (!vip) + { + config = this->ike_sa->get_peer_cfg(this->ike_sa); + vip = config->get_virtual_ip(config); + } + if (vip) + { + cp = cp_payload_create_type(cp_type, CFG_REQUEST); + cp->add_attribute(cp, build_vip(vip)); + } + + enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes, + this->ike_sa->get_other_id(this->ike_sa), vip); + while (enumerator->enumerate(enumerator, &handler, &type, &data)) + { + configuration_attribute_t *ca; + entry_t *entry; + + /* create configuration attribute */ + DBG2(DBG_IKE, "building %N attribute", + configuration_attribute_type_names, type); + ca = configuration_attribute_create_chunk(ca_type, + type, data); + if (!cp) + { + cp = cp_payload_create_type(cp_type, CFG_REQUEST); + } + cp->add_attribute(cp, ca); + + /* save handler along with requested type */ + entry = malloc_thing(entry_t); + entry->type = type; + entry->handler = handler; + + this->requested->insert_last(this->requested, entry); + } + enumerator->destroy(enumerator); + + break; default: + DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!FAILED!!!!!!!!!!!!!!!!!!!!!"); return FAILED; } /* Add the payloads into the message */ - message->add_payload(message, (payload_t *)cp); - + if(cp) + { + message->add_payload(message, (payload_t *)cp); + } + DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!NEED_MORE!!!!!!!!!!!!!!!!!!!!!"); return NEED_MORE; } METHOD(task_t, process_r, status_t, private_xauth_request_t *this, message_t *message) { - return NEED_MORE; + ike_version_t version; + payload_type_t cp_type; + DBG1(DBG_IKE, "%s: state %d", __func__, this->state); + + version = this->ike_sa->get_version(this->ike_sa); + if(version == IKEV1) + { + if(this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { + return NEED_MORE; + } + if(!this->auth_cfg) + { + this->auth_cfg = get_auth_cfg(this, TRUE); + } + switch((uintptr_t)this->auth_cfg->get(this->auth_cfg, AUTH_RULE_AUTH_CLASS)) + { + case AUTH_CLASS_XAUTH_PSK: + case AUTH_CLASS_XAUTH_PUBKEY: + break; + default: + /* We aren't XAuth, so do we should expect ConfigMode stuff */ + return SUCCESS; + } + cp_type = CONFIGURATION_V1; + } + else /* IKEv2 */ + { + /* IKEv2 does not support XAuth, skip those states. */ + this->state = TASK_XAUTH_COMPLETE; + if (message->get_message_id(message) == 1) + { /* in first IKE_AUTH only */ + return NEED_MORE; + } + cp_type = CONFIGURATION; + } + + return process_payloads(this, message); } METHOD(task_t, build_r, status_t, private_xauth_request_t *this, message_t *message) { - return NEED_MORE; + chunk_t user_name = chunk_from_chars('j', 'o', 's', 't'); + chunk_t user_pass = chunk_from_chars('j', 'o', 's', 't'); + status_t status; + cp_payload_t *cp = NULL; + payload_type_t cp_type = CONFIGURATION; + payload_type_t ca_type = CONFIGURATION_ATTRIBUTE; + ike_version_t version; + identification_t *id; + enumerator_t *enumerator; + configuration_attribute_type_t type; + chunk_t value; + host_t *vip = NULL; + peer_cfg_t *config; + + DBG1(DBG_IKE, "%s: state %d", __func__, this->state); + if(this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { + return NEED_MORE; + } + version = this->ike_sa->get_version(this->ike_sa); + if(version == IKEV1) + { + if(!this->auth_cfg) + { + this->auth_cfg = get_auth_cfg(this, TRUE); + } + switch((uintptr_t)this->auth_cfg->get(this->auth_cfg, AUTH_RULE_AUTH_CLASS)) + { + case AUTH_CLASS_XAUTH_PSK: + case AUTH_CLASS_XAUTH_PUBKEY: + break; + default: + this->state = TASK_XAUTH_COMPLETE; + return SUCCESS; + } + cp_type = CONFIGURATION_V1; + ca_type = CONFIGURATION_ATTRIBUTE_V1; + } + + switch(this->state) + { + case TASK_XAUTH_INIT: + /* TODO-IKEv1: Fetch the user/pass from an authenticator */ + cp = cp_payload_create_type(cp_type, CFG_REPLY); + cp->add_attribute(cp, configuration_attribute_create_chunk( + ca_type, XAUTH_USER_NAME, user_name)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + ca_type, XAUTH_USER_PASSWORD, user_pass)); + chunk_clear(&user_name); + chunk_clear(&user_pass); + + this->state = TASK_XAUTH_PASS_VERIFY; + status = NEED_MORE; + break; + case TASK_XAUTH_PASS_VERIFY: + cp = cp_payload_create_type(cp_type, CFG_ACK); + cp->add_attribute(cp, configuration_attribute_create_value( + XAUTH_STATUS, XAUTH_STATUS_OK)); + status = this->status; + this->state = TASK_XAUTH_COMPLETE; + break; + case TASK_XAUTH_COMPLETE: + id = this->ike_sa->get_other_eap_id(this->ike_sa); + + config = this->ike_sa->get_peer_cfg(this->ike_sa); + if (this->virtual_ip) + { + DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip); + if (config->get_pool(config)) + { + vip = hydra->attributes->acquire_address(hydra->attributes, + config->get_pool(config), id, this->virtual_ip); + } + if (vip == NULL) + { + DBG1(DBG_IKE, "no virtual IP found, sending %N", + notify_type_names, INTERNAL_ADDRESS_FAILURE); + message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE, + chunk_empty); + return SUCCESS; + } + DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id); + this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip); + + cp = cp_payload_create_type(cp_type, CFG_REPLY); + cp->add_attribute(cp, build_vip(vip)); + } + + /* query registered providers for additional attributes to include */ + enumerator = hydra->attributes->create_responder_enumerator( + hydra->attributes, config->get_pool(config), id, vip); + while (enumerator->enumerate(enumerator, &type, &value)) + { + if (!cp) + { + cp = cp_payload_create_type(cp_type, CFG_REPLY); + } + DBG2(DBG_IKE, "building %N attribute", + configuration_attribute_type_names, type); + cp->add_attribute(cp, + configuration_attribute_create_chunk(ca_type, + type, value)); + } + enumerator->destroy(enumerator); + status = SUCCESS; + break; + default: + return FAILED; + } + return status; } METHOD(task_t, process_i, status_t, private_xauth_request_t *this, message_t *message) { - cp_payload_t *cp_payload; - enumerator_t *enumerator; - configuration_attribute_t *ca; - chunk_t status_chunk = chunk_empty; + status_t status; + DBG1(DBG_IKE, "%s: state %d", __func__, this->state); + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { /* in last IKE_AUTH exchange */ - cp_payload = (cp_payload_t *)message->get_payload(message, CONFIGURATION_V1); - enumerator = cp_payload->create_attribute_enumerator(cp_payload); - while (enumerator->enumerate(enumerator, &ca)) - { - switch(ca->get_type(ca)) + status = process_payloads(this, message); + this->state = this->next_state; + + DBG1(DBG_IKE, "state %d, complete state %d", this->state, TASK_XAUTH_COMPLETE); + DBG1(DBG_IKE, "status %d SUCCESS %d", this->status, SUCCESS); + + if (this->virtual_ip) { - case XAUTH_USER_NAME: - this->user_name = ca->get_chunk(ca); - break; - case XAUTH_USER_PASSWORD: - this->user_pass = ca->get_chunk(ca); - break; - case XAUTH_STATUS: - status_chunk = ca->get_chunk(ca); - break; - default: - DBG3(DBG_IKE, "Unknown config attribute type %d, ignored", ca->get_type(ca)); + this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); } - } - enumerator->destroy(enumerator); - - switch(this->state) - { - case TASK_XAUTH_INIT: - - if(cp_payload->get_type(cp_payload) != CFG_REPLY) - { - DBG1(DBG_IKE, "ERROR: ConfigMode payload is not a reply"); - return FAILED; - } - - this->state = TASK_XAUTH_PASS_DONE; - if((this->user_name.len == 0) || (this->user_pass.len == 0)) - { - DBG1(DBG_IKE, "ERROR: Did not get user name or user pass, aborting"); - this->status = FAILED; - /* We should close out the XAuth negotiation cleanly by sending a "failed" message */ - return NEED_MORE; - } - - /* TODO-IKEv1: Do actual user/pass verification */ -// if(!chunk_compare(this->user_name, this->user_pass)) -// { -// this->status = FAILED; -// DBG1(DBG_IKE, "ERROR: user/pass verification failure"); - /* We should close out the XAuth negotiation cleanly by sending a "failed" message */ -// return NEED_MORE; -// } - - this->status = SUCCESS; - return NEED_MORE; - case TASK_XAUTH_PASS_DONE: - if(cp_payload->get_type(cp_payload) != CFG_ACK) - { - DBG1(DBG_IKE, "ERROR: ConfigMode payload is not a status ack"); - return FAILED; - } - if(status_chunk.len != 0) - { - DBG1(DBG_IKE, "Status payload of an ack had data, hmm...."); - } - - DBG1(DBG_IKE, "Done with XAUTH!!!"); + if(this->state == TASK_XAUTH_COMPLETE) return this->status; + return status; } - return FAILED; + return NEED_MORE; + } METHOD(task_t, get_type, task_type_t, @@ -257,9 +719,14 @@ xauth_request_t *xauth_request_create(ike_sa_t *ike_sa, bool initiator) .initiator = initiator, .ike_sa = ike_sa, .requested = linked_list_create(), - .user_name = chunk_empty, - .user_pass = chunk_empty, .state = TASK_XAUTH_INIT, + .next_state = TASK_XAUTH_INIT, + .xauth_status_data = XAUTH_STATUS_FAIL, + .xauth_user_name = chunk_empty, + .xauth_user_pass = chunk_empty, + .xauth_user_name_recv = FALSE, + .xauth_user_pass_recv = FALSE, + .xauth_status_recv = FALSE, ); if (initiator) From 0ea77083bb61acc775f7704540ce9f67a89bc78d Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 29 Nov 2011 11:21:54 +0100 Subject: [PATCH 179/534] Revert "IKEv1 XAuth: Added new MIGRATE status type to status_t." This reverts commit b57df8310a867a0a65abf17279bf1b6e6bb2f5d3. Conflicts: src/libcharon/sa/task_manager_v1.c --- src/libcharon/sa/task_manager_v1.c | 48 ------------------------------ src/libstrongswan/utils.h | 6 ---- 2 files changed, 54 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 442791881..86832f736 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -232,25 +232,6 @@ METHOD(task_manager_t, retransmit, status_t, return SUCCESS; } -void migrate_tasks(linked_list_t *from, linked_list_t *to) -{ - enumerator_t *enumerator; - task_t *task; - - enumerator = from->create_enumerator(from); - while(enumerator->enumerate(enumerator, (void**)&task)) - { - DBG4(DBG_IKE, " Migrating %N task to new queue", task_type_names, task->get_type(task)); - if(task->swap_initiator) - { - task->swap_initiator(task); - } - to->insert_last(to, task); - from->remove_at(from, enumerator); - } - enumerator->destroy(enumerator); -} - METHOD(task_manager_t, initiate, status_t, private_task_manager_t *this) { @@ -366,13 +347,6 @@ METHOD(task_manager_t, initiate, status_t, this->active_tasks->remove_at(this->active_tasks, enumerator); task->destroy(task); break; - case MIGRATE: - /* task completed, remove it */ - this->active_tasks->remove_at(this->active_tasks, enumerator); - task->destroy(task); - /* migrate the remaining active tasks to the passive queue */ - migrate_tasks(this->active_tasks, this->passive_tasks); - break; case NEED_MORE: /* processed, but task needs another exchange */ break; @@ -434,7 +408,6 @@ static status_t build_response(private_task_manager_t *this, message_t *request) host_t *me, *other; bool delete = FALSE; status_t status; - bool migrate = FALSE; me = request->get_destination(request); other = request->get_source(request); @@ -452,9 +425,6 @@ static status_t build_response(private_task_manager_t *this, message_t *request) { switch (task->build(task, message)) { - case MIGRATE: - migrate = TRUE; - /* FALL */ case SUCCESS: /* task completed, remove it */ this->passive_tasks->remove_at(this->passive_tasks, enumerator); @@ -501,14 +471,6 @@ static status_t build_response(private_task_manager_t *this, message_t *request) charon->sender->send(charon->sender, this->responding.packet->clone(this->responding.packet)); - - if (migrate) - { - migrate_tasks(this->passive_tasks, this->queued_tasks); - /* Kick off the newly installed tasks */ - initiate(this); - } - if (delete) { return DESTROY_ME; @@ -564,16 +526,6 @@ static status_t process_request(private_task_manager_t *this, task->destroy(task); enumerator->destroy(enumerator); return SUCCESS; - case MIGRATE: - /* task completed, remove it */ - this->passive_tasks->remove_at(this->passive_tasks, enumerator); - task->destroy(task); - enumerator->destroy(enumerator); - /* migrate the remaining tasks */ - migrate_tasks(this->passive_tasks, this->queued_tasks); - /* Kick off the newly installed tasks */ - initiate(this); - return SUCCESS; case NEED_MORE: /* processed, but task needs at least another call to build() */ break; diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h index f98de4139..0f06fec6a 100644 --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -299,12 +299,6 @@ enum status_t { * Another call to the method is required. */ NEED_MORE, - - /** - * For tasks only, same as SUCCESS, but also migrate all remaining tasks - * in the current queue to the opposite queue (passive->active or active->passive) - */ - MIGRATE, }; /** From 735fa3e5b9dc6d2c8badc4be4252ab9855f76afa Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 29 Nov 2011 11:36:53 +0100 Subject: [PATCH 180/534] IKEv1 XAuth: Remove XAuth task from the passive task list for ID_PROT. --- src/libcharon/sa/task_manager_v1.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 86832f736..915644bac 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -496,8 +496,6 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t *)xauth_request_create(this->ike_sa, FALSE); - this->passive_tasks->insert_last(this->passive_tasks, task); break; case AGGRESSIVE: /* TODO-IKEv1: agressive mode */ From 3fa8db8b59cb593ff42eeccd8afa23346efd6433 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 29 Nov 2011 11:41:56 +0100 Subject: [PATCH 181/534] IKEv1 XAuth: Clean up debug prints in xauth_request task. --- src/libcharon/sa/tasks/xauth_request.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c index 1c9f115b2..bf2a53433 100644 --- a/src/libcharon/sa/tasks/xauth_request.c +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -361,14 +361,11 @@ METHOD(task_t, build_i, status_t, configuration_attribute_type_t type; chunk_t data; - DBG1(DBG_IKE, "%s: state %d", __func__, this->state); - version = this->ike_sa->get_version(this->ike_sa); if(version == IKEV1) { if(this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) { - DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!NEED_MORE!!!!!!!!!!!!!!!!!!!!!"); return NEED_MORE; } @@ -383,7 +380,6 @@ METHOD(task_t, build_i, status_t, break; default: /* We aren't XAuth, so do nothing */ - DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!SUCCESS!!!!!!!!!!!!!!!!!!!!!"); return SUCCESS; } cp_type = CONFIGURATION_V1; @@ -395,7 +391,6 @@ METHOD(task_t, build_i, status_t, this->state = TASK_XAUTH_COMPLETE; if (message->get_message_id(message) == 1) { /* in first IKE_AUTH only */ - DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!NEED_MORE!!!!!!!!!!!!!!!!!!!!!"); return NEED_MORE; } cp_type = CONFIGURATION; @@ -460,7 +455,6 @@ METHOD(task_t, build_i, status_t, break; default: - DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!FAILED!!!!!!!!!!!!!!!!!!!!!"); return FAILED; } @@ -470,7 +464,6 @@ METHOD(task_t, build_i, status_t, message->add_payload(message, (payload_t *)cp); } - DBG1(DBG_IKE, "!!!!!!!!!!!!!!!!!!!!!!!!!NEED_MORE!!!!!!!!!!!!!!!!!!!!!"); return NEED_MORE; } @@ -479,7 +472,6 @@ METHOD(task_t, process_r, status_t, { ike_version_t version; payload_type_t cp_type; - DBG1(DBG_IKE, "%s: state %d", __func__, this->state); version = this->ike_sa->get_version(this->ike_sa); if(version == IKEV1) @@ -534,7 +526,6 @@ METHOD(task_t, build_r, status_t, host_t *vip = NULL; peer_cfg_t *config; - DBG1(DBG_IKE, "%s: state %d", __func__, this->state); if(this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) { return NEED_MORE; @@ -636,16 +627,12 @@ METHOD(task_t, process_i, status_t, private_xauth_request_t *this, message_t *message) { status_t status; - DBG1(DBG_IKE, "%s: state %d", __func__, this->state); if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) { /* in last IKE_AUTH exchange */ status = process_payloads(this, message); this->state = this->next_state; - DBG1(DBG_IKE, "state %d, complete state %d", this->state, TASK_XAUTH_COMPLETE); - DBG1(DBG_IKE, "status %d SUCCESS %d", this->status, SUCCESS); - if (this->virtual_ip) { this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); From 1e97783c993caec7f7556d6be5b7168701c31062 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 29 Nov 2011 11:14:25 +0100 Subject: [PATCH 182/534] Added payloads for IKEv1 NAT-Traversal negotiation. --- src/libcharon/encoding/message.c | 2 +- .../encoding/payloads/hash_payload.c | 8 ++++++- .../encoding/payloads/hash_payload.h | 3 ++- src/libcharon/encoding/payloads/id_payload.c | 22 ++++++++++++------- src/libcharon/encoding/payloads/id_payload.h | 4 ++-- src/libcharon/encoding/payloads/payload.c | 18 ++++++++++++--- src/libcharon/encoding/payloads/payload.h | 10 +++++++++ src/libcharon/sa/tasks/main_mode.c | 2 +- 8 files changed, 52 insertions(+), 17 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 6c6004fac..835073a5c 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1412,7 +1412,7 @@ METHOD(message_t, generate, status_t, chunk_t hash = keymat_v1->get_hash_phase2(keymat_v1, &this->public); if (hash.ptr) { /* insert a HASH payload as first payload */ - hash_payload_t *hash_payload = hash_payload_create(); + hash_payload_t *hash_payload = hash_payload_create(HASH_V1); hash_payload->set_hash(hash_payload, hash); this->payloads->insert_first(this->payloads, (payload_t*)hash_payload); diff --git a/src/libcharon/encoding/payloads/hash_payload.c b/src/libcharon/encoding/payloads/hash_payload.c index 9542b1c03..0cf63ba67 100644 --- a/src/libcharon/encoding/payloads/hash_payload.c +++ b/src/libcharon/encoding/payloads/hash_payload.c @@ -50,6 +50,11 @@ struct private_hash_payload_t { * The contained hash value. */ chunk_t hash; + + /** + * either HASH_V1 or NAT_D_V1 + */ + payload_type_t type; }; /** @@ -99,7 +104,7 @@ METHOD(payload_t, get_header_length, int, METHOD(payload_t, get_type, payload_type_t, private_hash_payload_t *this) { - return HASH_V1; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -166,6 +171,7 @@ hash_payload_t *hash_payload_create(payload_type_t type) }, .next_payload = NO_PAYLOAD, .payload_length = get_header_length(this), + .type = type, ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/hash_payload.h b/src/libcharon/encoding/payloads/hash_payload.h index 9f4b6e59b..cfe28460c 100644 --- a/src/libcharon/encoding/payloads/hash_payload.h +++ b/src/libcharon/encoding/payloads/hash_payload.h @@ -59,8 +59,9 @@ struct hash_payload_t { /** * Creates an empty hash_payload_t object. * + * @param type either HASH_V1 or NAT_D_V1 * @return hash_payload_t object */ -hash_payload_t *hash_payload_create(); +hash_payload_t *hash_payload_create(payload_type_t type); #endif /** HASH_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index 317cbd624..96d713e46 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -1,9 +1,8 @@ /* - * Copyright (C) 2005-2010 Martin Willi + * Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2010 revosec AG - * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2007-2011 Tobias Brunner * Copyright (C) 2005 Jan Hutter - * * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -82,7 +81,7 @@ struct private_id_payload_t { u_int16_t port; /** - * one of ID_INITIATOR, ID_RESPONDER and IDv1 + * one of ID_INITIATOR, ID_RESPONDER, IDv1 and NAT_OA_V1 */ payload_type_t type; }; @@ -92,9 +91,9 @@ struct private_id_payload_t { */ static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_id_payload_t, next_payload) }, + { U_INT_8, offsetof(private_id_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_id_payload_t, critical) }, + { FLAG, offsetof(private_id_payload_t, critical) }, /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[0]) }, { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[1]) }, @@ -104,7 +103,7 @@ static encoding_rule_t encodings_v2[] = { { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[5]) }, { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[6]) }, /* Length of the whole payload*/ - { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) }, + { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) }, /* 1 Byte ID type*/ { U_INT_8, offsetof(private_id_payload_t, id_type) }, /* 3 reserved bytes */ @@ -166,6 +165,13 @@ METHOD(payload_t, verify, status_t, { bool bad_length = FALSE; + if (this->type == NAT_OA_V1 && + this->id_type != ID_IPV4_ADDR && this->id_type != ID_IPV6_ADDR) + { + DBG1(DBG_ENC, "invalid ID type %N for %N payload", id_type_names, + this->id_type, payload_type_short_names, this->type); + return FAILED; + } switch (this->id_type) { case ID_IPV4_ADDR_RANGE: @@ -189,7 +195,7 @@ METHOD(payload_t, verify, status_t, METHOD(payload_t, get_encoding_rules, int, private_id_payload_t *this, encoding_rule_t **rules) { - if (this->type == ID_V1) + if (this->type == ID_V1 || this->type == NAT_OA_V1) { *rules = encodings_v1; return countof(encodings_v1); diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h index bc6920012..22016bc19 100644 --- a/src/libcharon/encoding/payloads/id_payload.h +++ b/src/libcharon/encoding/payloads/id_payload.h @@ -63,7 +63,7 @@ struct id_payload_t { /** * Creates an empty id_payload_t object. * - * @param type one of ID_INITIATOR, ID_RESPONDER and ID_V1 + * @param type one of ID_INITIATOR, ID_RESPONDER, ID_V1 and NAT_OA_V1 * @return id_payload_t object */ id_payload_t *id_payload_create(payload_type_t payload_type); @@ -71,7 +71,7 @@ id_payload_t *id_payload_create(payload_type_t payload_type); /** * Creates an id_payload_t from an existing identification_t object. * - * @param type one of ID_INITIATOR, ID_RESPONDER and ID_V1 + * @param type one of ID_INITIATOR, ID_RESPONDER, ID_V1 and NAT_OA_V1 * @param id identification_t object * @return id_payload_t object */ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 3a411606c..baa838715 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -55,7 +55,10 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, NO_PAYL "DELETE_V1", "VENDOR_ID_V1", "CONFIGURATION_V1"); -ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, CONFIGURATION_V1, +ENUM_NEXT(payload_type_names, NAT_D_V1, NAT_OA_V1, CONFIGURATION_V1, + "NAT_D_V1", + "NAT_OA_V1"); +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, NAT_OA_V1, "SECURITY_ASSOCIATION", "KEY_EXCHANGE", "ID_INITIATOR", @@ -121,7 +124,10 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, N "D", "V", "CP"); -ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, CONFIGURATION_V1, +ENUM_NEXT(payload_type_short_names, NAT_D_V1, NAT_OA_V1, CONFIGURATION_V1, + "NAT-D", + "NAT-OA"); +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, NAT_OA_V1, "SA", "KE", "IDi", @@ -196,6 +202,7 @@ payload_t *payload_create(payload_type_t type) case ID_INITIATOR: case ID_RESPONDER: case ID_V1: + case NAT_OA_V1: #ifdef ME case ID_PEER: #endif /* ME */ @@ -226,7 +233,8 @@ payload_t *payload_create(payload_type_t type) case VENDOR_ID_V1: return (payload_t*)vendor_id_payload_create(type); case HASH_V1: - return (payload_t*)hash_payload_create(); + case NAT_D_V1: + return (payload_t*)hash_payload_create(type); case CONFIGURATION: case CONFIGURATION_V1: return (payload_t*)cp_payload_create(type); @@ -260,6 +268,10 @@ bool payload_is_known(payload_type_t type) { return TRUE; } + if (type >= NAT_D_V1 && type <= NAT_OA_V1) + { + return TRUE; + } #ifdef ME if (type == ID_PEER) { diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index 6209b0822..ed839fc07 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -117,6 +117,16 @@ enum payload_type_t { */ CONFIGURATION_V1 = 14, + /** + * NAT discovery payload (NAT-D). + */ + NAT_D_V1 = 20, + + /** + * NAT original address payload (NAT-OA) + */ + NAT_OA_V1 = 21, + /** * The security association (SA) payload containing proposals. */ diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 3a051a6e7..4efcf0dd0 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -193,7 +193,7 @@ static void build_hash(private_main_mode_t *this, bool initiator, this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); free(dh.ptr); - hash_payload = hash_payload_create(); + hash_payload = hash_payload_create(HASH_V1); hash_payload->set_hash(hash_payload, hash); free(hash.ptr); From 06d29be7149e3da13b9d744d62c551cdcb0faf6f Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 29 Nov 2011 14:26:52 +0100 Subject: [PATCH 183/534] Handle IKEv1 NAT-T vendor ID payload (only RFC 3947 for now). --- src/libcharon/sa/ike_sa.h | 2 +- src/libcharon/sa/tasks/ike_vendor_v1.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 882de41b2..bc3544f92 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -69,7 +69,7 @@ typedef struct ike_sa_t ike_sa_t; enum ike_extension_t { /** - * peer supports NAT traversal as specified in RFC4306 + * peer supports NAT traversal as specified in RFC4306 or RFC3947 */ EXT_NATT = (1<<0), diff --git a/src/libcharon/sa/tasks/ike_vendor_v1.c b/src/libcharon/sa/tasks/ike_vendor_v1.c index bf857a314..450c5b287 100644 --- a/src/libcharon/sa/tasks/ike_vendor_v1.c +++ b/src/libcharon/sa/tasks/ike_vendor_v1.c @@ -41,10 +41,22 @@ struct private_ike_vendor_v1_t { bool initiator; }; +/** + * Indicate support for XAuth, MD5("draft-ietf-ipsra-isakmp-xauth-06.txt") + * Truncated to the first half. + */ static chunk_t xauth6_vid = chunk_from_chars( 0x09,0x00,0x26,0x89,0xdf,0xd6,0xb7,0x12 ); +/** + * Indicate support for NAT-Traversal, MD5("RFC 3947") + */ +static chunk_t natt_vid = chunk_from_chars( + 0x4a,0x13,0x1c,0x81,0x07,0x03,0x58,0x45, + 0x5c,0x57,0x28,0xf2,0x0e,0x95,0x45,0x2f +); + /** * strongSwan specific vendor ID without version, MD5("strongSwan") */ @@ -76,6 +88,7 @@ METHOD(task_t, build, status_t, } add_vendor_id(this, message, xauth6_vid); + add_vendor_id(this, message, natt_vid); return this->initiator ? NEED_MORE : SUCCESS; } @@ -107,6 +120,11 @@ METHOD(task_t, process, status_t, DBG1(DBG_IKE, "received XAuth vendor id"); this->ike_sa->enable_extension(this->ike_sa, EXT_XAUTH); } + else if (chunk_equals(data, natt_vid)) + { + DBG1(DBG_IKE, "received NAT-T vendor id"); + this->ike_sa->enable_extension(this->ike_sa, EXT_NATT); + } else { DBG1(DBG_ENC, "received unknown vendor id: %#B", &data); From 02c36eeb8683016bdb7c6a21a279f0c9105ded6c Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Wed, 30 Nov 2011 10:39:29 +0100 Subject: [PATCH 184/534] IKEv1 XAuth: Adding "initiate" flag parameter to the initiate_xauth method, signalling whether or not to call the task_manager->initiate method after queueing the task. --- src/libcharon/processing/jobs/initiate_xauth_job.c | 3 +-- src/libcharon/sa/ike_sa.c | 8 ++++++-- src/libcharon/sa/ike_sa.h | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libcharon/processing/jobs/initiate_xauth_job.c b/src/libcharon/processing/jobs/initiate_xauth_job.c index 0ec12dfdb..98fbac039 100644 --- a/src/libcharon/processing/jobs/initiate_xauth_job.c +++ b/src/libcharon/processing/jobs/initiate_xauth_job.c @@ -52,8 +52,7 @@ METHOD(job_t, initiate, void, this->ike_sa_id); if (ike_sa) { - DBG1(DBG_IKE, "INITIATING XAUTH!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); - ike_sa->initiate_xauth(ike_sa); + ike_sa->initiate_xauth(ike_sa, TRUE); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } destroy(this); diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 2de57d693..0990111bf 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1019,11 +1019,15 @@ METHOD(ike_sa_t, initiate_mediated, status_t, #endif /* ME */ METHOD(ike_sa_t, initiate_xauth, status_t, - private_ike_sa_t *this) + private_ike_sa_t *this, bool initiate) { xauth_request_t *task = xauth_request_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, (task_t*)task); - return this->task_manager->initiate(this->task_manager); + if(initiate) + { + return this->task_manager->initiate(this->task_manager); + } + return SUCCESS; } /** diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index bc3544f92..27eab5445 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -970,7 +970,7 @@ struct ike_sa_t { /** * Initiate an XAuth authentication exchange. */ - status_t (*initiate_xauth) (ike_sa_t *this); + status_t (*initiate_xauth) (ike_sa_t *this, bool initiate); }; /** From c5dc9d3383871e0e3b183bc2a166e45dec386ad6 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Wed, 30 Nov 2011 10:43:38 +0100 Subject: [PATCH 185/534] IKEv1 XAuth: Moving the state change to IKE_CONNECTED until after XAuth exchanges are complete. --- src/libcharon/sa/task_manager_v1.c | 17 +++++++++------ src/libcharon/sa/tasks/main_mode.c | 27 +++++++++++++++++------- src/libcharon/sa/tasks/xauth_request.c | 29 ++++++++++++++++---------- 3 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 915644bac..9008b607a 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -269,6 +269,13 @@ METHOD(task_manager_t, initiate, status_t, exchange = ID_PROT; } break; + case IKE_CONNECTING: + if (activate_task(this, TASK_XAUTH_REQUEST)) + { + exchange = TRANSACTION; + new_mid = TRUE; + } + break; case IKE_ESTABLISHED: if (activate_task(this, TASK_QUICK_MODE)) { @@ -276,12 +283,6 @@ METHOD(task_manager_t, initiate, status_t, new_mid = TRUE; break; } - if (activate_task(this, TASK_XAUTH_REQUEST)) - { - exchange = TRANSACTION; - new_mid = TRUE; - break; - } break; default: break; @@ -508,6 +509,10 @@ static status_t process_request(private_task_manager_t *this, case INFORMATIONAL_V1: /* TODO-IKEv1: informational */ return FAILED; + case TRANSACTION: + task = (task_t *)xauth_request_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + break; default: return FAILED; } diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 4efcf0dd0..a88f7a419 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -660,8 +660,6 @@ METHOD(task_t, build_r, status_t, this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); switch (this->auth_method) { @@ -672,8 +670,17 @@ METHOD(task_t, build_r, status_t, lib->processor->queue_job(lib->processor, job); break; } - default: + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: /* There should be more RESP cases here once added */ + { break; + } + default: + { + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + break; + } } return SUCCESS; } @@ -774,20 +781,26 @@ METHOD(task_t, process_i, status_t, this->ike_sa->get_my_id(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); switch (this->auth_method) { case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: /* There should be more RESP cases here once added */ { - job_t *job = (job_t *) initiate_xauth_job_create(this->ike_sa->get_id(this->ike_sa)); - lib->processor->queue_job(lib->processor, job); + this->ike_sa->initiate_xauth(this->ike_sa, FALSE); + break; + } + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: /* There should be more INIT cases here once added */ + { break; } default: + { + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); break; + } } return SUCCESS; diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c index bf2a53433..8e4489ed2 100644 --- a/src/libcharon/sa/tasks/xauth_request.c +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -364,11 +364,6 @@ METHOD(task_t, build_i, status_t, version = this->ike_sa->get_version(this->ike_sa); if(version == IKEV1) { - if(this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) - { - return NEED_MORE; - } - if(!this->auth_cfg) { this->auth_cfg = get_auth_cfg(this, TRUE); @@ -476,10 +471,6 @@ METHOD(task_t, process_r, status_t, version = this->ike_sa->get_version(this->ike_sa); if(version == IKEV1) { - if(this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) - { - return NEED_MORE; - } if(!this->auth_cfg) { this->auth_cfg = get_auth_cfg(this, TRUE); @@ -488,10 +479,11 @@ METHOD(task_t, process_r, status_t, { case AUTH_CLASS_XAUTH_PSK: case AUTH_CLASS_XAUTH_PUBKEY: + this->state = TASK_XAUTH_INIT; break; default: /* We aren't XAuth, so do we should expect ConfigMode stuff */ - return SUCCESS; + this->state = TASK_XAUTH_COMPLETE; } cp_type = CONFIGURATION_V1; } @@ -620,6 +612,11 @@ METHOD(task_t, build_r, status_t, default: return FAILED; } + if(status == SUCCESS) + { + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + } return status; } @@ -627,7 +624,9 @@ METHOD(task_t, process_i, status_t, private_xauth_request_t *this, message_t *message) { status_t status; - if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + if (((this->ike_sa->get_version(this->ike_sa) == IKEV2) && + (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)) || + (this->ike_sa->get_version(this->ike_sa) == IKEV1)) { /* in last IKE_AUTH exchange */ status = process_payloads(this, message); @@ -638,7 +637,15 @@ METHOD(task_t, process_i, status_t, this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); } if(this->state == TASK_XAUTH_COMPLETE) + { + if(this->status == SUCCESS) + { + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + } + return this->status; + } return status; } return NEED_MORE; From a0bea44a971baaa07704f34f94a09480af27b872 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 30 Nov 2011 16:55:24 +0100 Subject: [PATCH 186/534] Message rules for IKEv1 NAT-T payloads added. --- src/libcharon/encoding/message.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 835073a5c..b63264bf9 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -59,6 +59,11 @@ */ #define MAX_CERTREQ_PAYLOADS 5 +/** + * Max number of NAT-D payloads per IKEv1 message + */ +#define MAX_NAT_D_PAYLOADS 5 + /** * A payload rule defines the rules for a payload * in a specific message rule. It defines if and how @@ -431,6 +436,7 @@ static payload_rule_t id_prot_i_rules[] = { {NONCE_V1, 0, 1, FALSE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, TRUE, FALSE}, {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, {SIGNATURE_V1, 0, 1, TRUE, FALSE}, @@ -452,6 +458,7 @@ static payload_order_t id_prot_i_order[] = { {CERTIFICATE_REQUEST_V1, 0}, {NOTIFY_V1, 0}, {VENDOR_ID_V1, 0}, + {NAT_D_V1, 0}, }; /** @@ -465,6 +472,7 @@ static payload_rule_t id_prot_r_rules[] = { {NONCE_V1, 0, 1, FALSE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, TRUE, FALSE}, {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, {SIGNATURE_V1, 0, 1, TRUE, FALSE}, @@ -486,6 +494,7 @@ static payload_order_t id_prot_r_order[] = { {CERTIFICATE_REQUEST_V1, 0}, {NOTIFY_V1, 0}, {VENDOR_ID_V1, 0}, + {NAT_D_V1, 0}, }; /** @@ -499,6 +508,7 @@ static payload_rule_t aggressive_i_rules[] = { {NONCE_V1, 0, 1, FALSE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, FALSE, FALSE}, {CERTIFICATE_V1, 0, 1, FALSE, FALSE}, {SIGNATURE_V1, 0, 1, FALSE, FALSE}, @@ -515,6 +525,7 @@ static payload_order_t aggressive_i_order[] = { {NONCE_V1, 0}, {ID_V1, 0}, {CERTIFICATE_V1, 0}, + {NAT_D_V1, 0}, {SIGNATURE_V1, 0}, {HASH_V1, 0}, {CERTIFICATE_REQUEST_V1, 0}, @@ -533,6 +544,7 @@ static payload_rule_t aggressive_r_rules[] = { {NONCE_V1, 0, 1, FALSE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, FALSE, FALSE}, {CERTIFICATE_V1, 0, 1, FALSE, FALSE}, {SIGNATURE_V1, 0, 1, FALSE, FALSE}, @@ -549,6 +561,7 @@ static payload_order_t aggressive_r_order[] = { {NONCE_V1, 0}, {ID_V1, 0}, {CERTIFICATE_V1, 0}, + {NAT_D_V1, 0}, {SIGNATURE_V1, 0}, {HASH_V1, 0}, {CERTIFICATE_REQUEST_V1, 0}, @@ -588,6 +601,7 @@ static payload_rule_t quick_mode_i_rules[] = { {NONCE_V1, 0, 1, TRUE, FALSE}, {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE}, {ID_V1, 0, 2, TRUE, FALSE}, + {NAT_OA_V1, 0, 2, TRUE, FALSE}, }; /** @@ -602,6 +616,7 @@ static payload_order_t quick_mode_i_order[] = { {NONCE_V1, 0}, {KEY_EXCHANGE_V1, 0}, {ID_V1, 0}, + {NAT_OA_V1, 0}, }; /** @@ -616,6 +631,7 @@ static payload_rule_t quick_mode_r_rules[] = { {NONCE_V1, 0, 1, TRUE, FALSE}, {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE}, {ID_V1, 0, 2, TRUE, FALSE}, + {NAT_OA_V1, 0, 2, TRUE, FALSE}, }; /** @@ -630,6 +646,7 @@ static payload_order_t quick_mode_r_order[] = { {NONCE_V1, 0}, {KEY_EXCHANGE_V1, 0}, {ID_V1, 0}, + {NAT_OA_V1, 0}, }; /** From 4ace4daf0c40ac5be48b66f7bd755c7aff4d554e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 30 Nov 2011 17:03:01 +0100 Subject: [PATCH 187/534] Added a function to keymat_v1 to create the hasher earlier than during key derivation. The negotiated hasher is also used to generate NAT-D payloads. --- src/libcharon/sa/keymat_v1.c | 48 +++++++++++++++++++++++++----------- src/libcharon/sa/keymat_v1.h | 15 +++++++++++ 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 98d12fb4f..fc49a2030 100644 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -75,7 +75,7 @@ struct private_keymat_v1_t { aead_t *aead; /** - * Hasher used for IV generation + * Hasher used for IV generation (and other things like e.g. NAT-T) */ hasher_t *hasher; @@ -350,8 +350,8 @@ static void adjust_keylen(u_int16_t alg, chunk_t *key) { 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. */ + * not and therefore fixed key semantics apply to XCBC for key + * derivation. */ key->len = min(key->len, 16); break; default: @@ -470,19 +470,8 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, { return FALSE; } - - if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL) || - (alg = auth_to_hash(alg)) == HASH_UNKNOWN) + if (!this->hasher && !this->public.create_hasher(&this->public, proposal)) { - DBG1(DBG_IKE, "no %N selected", transform_type_names, HASH_ALGORITHM); - return FALSE; - } - this->hasher = lib->crypto->create_hasher(lib->crypto, alg); - if (!this->hasher) - { - DBG1(DBG_IKE, "%N %N not supported!", - transform_type_names, HASH_ALGORITHM, - hash_algorithm_names, alg); return FALSE; } @@ -619,6 +608,33 @@ METHOD(keymat_v1_t, derive_child_keys, bool, return TRUE; } +METHOD(keymat_v1_t, create_hasher, bool, + private_keymat_v1_t *this, proposal_t *proposal) +{ + u_int16_t alg; + if (!proposal->get_algorithm(proposal, INTEGRITY_ALGORITHM, &alg, NULL) || + (alg = auth_to_hash(alg)) == HASH_UNKNOWN) + { + DBG1(DBG_IKE, "no %N selected", transform_type_names, HASH_ALGORITHM); + return FALSE; + } + this->hasher = lib->crypto->create_hasher(lib->crypto, alg); + if (!this->hasher) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, HASH_ALGORITHM, + hash_algorithm_names, alg); + return FALSE; + } + return TRUE; +} + +METHOD(keymat_v1_t, get_hasher, hasher_t*, + private_keymat_v1_t *this) +{ + return this->hasher; +} + METHOD(keymat_v1_t, get_hash, chunk_t, private_keymat_v1_t *this, bool initiator, chunk_t dh, chunk_t dh_other, ike_sa_id_t *ike_sa_id, chunk_t sa_i, identification_t *id) @@ -973,6 +989,8 @@ keymat_v1_t *keymat_v1_create(bool initiator) }, .derive_ike_keys = _derive_ike_keys, .derive_child_keys = _derive_child_keys, + .create_hasher = _create_hasher, + .get_hasher = _get_hasher, .get_hash = _get_hash, .get_hash_phase2 = _get_hash_phase2, .get_iv = _get_iv, diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h index 28b9c1900..89314afb0 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/keymat_v1.h @@ -76,6 +76,21 @@ struct keymat_v1_t { chunk_t *encr_i, chunk_t *integ_i, chunk_t *encr_r, chunk_t *integ_r); + /** + * Create the negotiated hasher. + * + * @param proposal selected algorithms + * @return TRUE, if creation was successful + */ + bool (*create_hasher)(keymat_v1_t *this, proposal_t *proposal); + + /** + * Get the negotiated hasher. + * + * @return allocated hasher or NULL + */ + hasher_t *(*get_hasher)(keymat_v1_t *this); + /** * Get HASH data for authentication. * From 61e2a1ad8a6a3ea2d4a4c6f5298d685b9dcde60c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 30 Nov 2011 17:04:21 +0100 Subject: [PATCH 188/534] Create negotiated hasher earlier during Main Mode so it is available for building NAT-D payloads. --- src/libcharon/sa/tasks/main_mode.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index a88f7a419..4d4ca340a 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -376,6 +376,10 @@ METHOD(task_t, build_i, status_t, { u_int16_t group; + if (!this->keymat->create_hasher(this->keymat, this->proposal)) + { + return FAILED; + } if (!this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) { @@ -470,6 +474,10 @@ METHOD(task_t, process_r, status_t, { u_int16_t group; + if (!this->keymat->create_hasher(this->keymat, this->proposal)) + { + return FAILED; + } if (!this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) { From 1cc4ec46cfd9cf2209d6411d3605ea6835883c8a Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 30 Nov 2011 17:09:42 +0100 Subject: [PATCH 189/534] Task added for IKEv1 NAT detection. There is already support for both Main and Aggressive Mode. --- src/libcharon/Makefile.am | 6 +- src/libcharon/sa/ike_sa.c | 3 + src/libcharon/sa/task_manager_v1.c | 5 +- src/libcharon/sa/tasks/ike_natd_v1.c | 440 +++++++++++++++++++++++++++ src/libcharon/sa/tasks/ike_natd_v1.h | 50 +++ src/libcharon/sa/tasks/task.c | 2 + src/libcharon/sa/tasks/task.h | 4 +- 7 files changed, 506 insertions(+), 4 deletions(-) create mode 100644 src/libcharon/sa/tasks/ike_natd_v1.c create mode 100644 src/libcharon/sa/tasks/ike_natd_v1.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 538774928..aab293dd2 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -85,6 +85,7 @@ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ sa/tasks/ike_init.c sa/tasks/ike_init.h \ sa/tasks/ike_natd.c sa/tasks/ike_natd.h \ +sa/tasks/ike_natd_v1.c sa/tasks/ike_natd_v1.h \ sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \ sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ @@ -93,8 +94,9 @@ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ sa/tasks/ike_vendor_v1.c sa/tasks/ike_vendor_v1.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ -sa/tasks/task.c sa/tasks/task.h \ -sa/tasks/xauth_request.c sa/tasks/xauth_request.h +sa/tasks/xauth_request.c sa/tasks/xauth_request.h \ +sa/tasks/task.c sa/tasks/task.h + daemon.lo : $(top_builddir)/config.status diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 0990111bf..5a21a8870 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -1123,6 +1124,8 @@ METHOD(ike_sa_t, initiate, status_t, this->task_manager->queue_task(this->task_manager, task); task = (task_t*)main_mode_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_natd_v1_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); } else { diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 9008b607a..18decb678 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -19,10 +19,10 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -267,6 +267,7 @@ METHOD(task_manager_t, initiate, status_t, if (activate_task(this, TASK_MAIN_MODE)) { exchange = ID_PROT; + activate_task(this, TASK_IKE_NATD_V1); } break; case IKE_CONNECTING: @@ -497,6 +498,8 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t *)ike_natd_v1_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); break; case AGGRESSIVE: /* TODO-IKEv1: agressive mode */ diff --git a/src/libcharon/sa/tasks/ike_natd_v1.c b/src/libcharon/sa/tasks/ike_natd_v1.c new file mode 100644 index 000000000..d7f957d50 --- /dev/null +++ b/src/libcharon/sa/tasks/ike_natd_v1.c @@ -0,0 +1,440 @@ +/* + * Copyright (C) 2006-2011 Tobias Brunner, + * Copyright (C) 2006-2007 Martin Willi + * Copyright (C) 2006 Daniel Roethlisberger + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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_natd_v1.h" + +#include + +#include +#include +#include +#include +#include +#include + +typedef struct private_ike_natd_v1_t private_ike_natd_v1_t; + +/** + * Private members of a ike_natt_t task. + */ +struct private_ike_natd_v1_t { + + /** + * Public interface. + */ + ike_natd_v1_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Keymat derivation (from SA) + */ + keymat_v1_t *keymat; + + /** + * Did we process any NAT detection payloads for a source address? + */ + bool src_seen; + + /** + * Did we process any NAT detection payloads for a destination address? + */ + bool dst_seen; + + /** + * Have we found a matching source address NAT hash? + */ + bool src_matched; + + /** + * Have we found a matching destination address NAT hash? + */ + bool dst_matched; +}; + +/** + * Build NAT detection hash for a host. + */ +static chunk_t generate_natd_hash(private_ike_natd_v1_t *this, + ike_sa_id_t *ike_sa_id, host_t *host) +{ + hasher_t *hasher; + chunk_t natd_chunk, natd_hash; + u_int64_t spi_i, spi_r; + u_int16_t port; + + hasher = this->keymat->get_hasher(this->keymat); + if (!hasher) + { + DBG1(DBG_IKE, "no hasher available to build NAT-D payload"); + return chunk_empty; + } + + spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_r = ike_sa_id->get_responder_spi(ike_sa_id); + port = htons(host->get_port(host)); + + /* natd_hash = HASH(CKY-I | CKY-R | IP | Port) */ + natd_chunk = chunk_cata("cccc", chunk_from_thing(spi_i), + chunk_from_thing(spi_r), host->get_address(host), + chunk_from_thing(port)); + hasher->allocate_hash(hasher, natd_chunk, &natd_hash); + DBG3(DBG_IKE, "natd_chunk %B", &natd_chunk); + DBG3(DBG_IKE, "natd_hash %B", &natd_hash); + + return natd_hash; +} + +/** + * Build a faked NAT-D payload to enforce UDP encapsulation. + */ +static chunk_t generate_natd_hash_faked(private_ike_natd_v1_t *this) +{ + hasher_t *hasher; + chunk_t chunk; + rng_t *rng; + + hasher = this->keymat->get_hasher(this->keymat); + if (!hasher) + { + DBG1(DBG_IKE, "no hasher available to build NAT-D payload"); + return chunk_empty; + } + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "unable to get random bytes for NAT-D fake"); + return chunk_empty; + } + rng->allocate_bytes(rng, hasher->get_hash_size(hasher), &chunk); + rng->destroy(rng); + return chunk; +} + +/** + * Build a NAT-D payload. + */ +static hash_payload_t *build_natd_payload(private_ike_natd_v1_t *this, bool src, + host_t *host) +{ + hash_payload_t *payload; + ike_cfg_t *config; + chunk_t hash; + + config = this->ike_sa->get_ike_cfg(this->ike_sa); + if (src && config->force_encap(config)) + { + hash = generate_natd_hash_faked(this); + } + else + { + ike_sa_id_t *ike_sa_id = this->ike_sa->get_id(this->ike_sa); + hash = generate_natd_hash(this, ike_sa_id, host); + } + payload = hash_payload_create(NAT_D_V1); + payload->set_hash(payload, hash); + chunk_free(&hash); + return payload; +} + +/** + * Add NAT-D payloads to the message. + */ +static void add_natd_payloads(private_ike_natd_v1_t *this, message_t *message) +{ + hash_payload_t *payload; + host_t *host; + + /* destination has to be added first */ + host = message->get_destination(message); + payload = build_natd_payload(this, FALSE, host); + message->add_payload(message, (payload_t*)payload); + + /* source is added second, compared with IKEv2 we always know the source, + * as these payloads are added in the second Phase 1 exchange or the + * response to the first */ + host = message->get_source(message); + payload = build_natd_payload(this, TRUE, host); + message->add_payload(message, (payload_t*)payload); +} + +/** + * Read NAT-D payloads from message and evaluate them. + */ +static void process_payloads(private_ike_natd_v1_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + hash_payload_t *hash_payload; + chunk_t hash, src_hash, dst_hash; + ike_sa_id_t *ike_sa_id; + host_t *me, *other; + ike_cfg_t *config; + + /* precompute hashes for incoming NAT-D comparison */ + ike_sa_id = message->get_ike_sa_id(message); + me = message->get_destination(message); + other = message->get_source(message); + dst_hash = generate_natd_hash(this, ike_sa_id, me); + src_hash = generate_natd_hash(this, ike_sa_id, other); + + DBG3(DBG_IKE, "precalculated src_hash %B", &src_hash); + DBG3(DBG_IKE, "precalculated dst_hash %B", &dst_hash); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) != NAT_D_V1) + { + continue; + } + hash_payload = (hash_payload_t*)payload; + if (!this->dst_seen) + { /* the first NAT-D payload contains the destination hash */ + this->dst_seen = TRUE; + hash = hash_payload->get_hash(hash_payload); + DBG3(DBG_IKE, "received dst_hash %B", &hash); + if (chunk_equals(hash, dst_hash)) + { + this->dst_matched = TRUE; + } + continue; + } + /* the other NAT-D payloads contain source hashes */ + this->src_seen = TRUE; + if (!this->src_matched) + { + hash = hash_payload->get_hash(hash_payload); + DBG3(DBG_IKE, "received src_hash %B", &hash); + if (chunk_equals(hash, src_hash)) + { + this->src_matched = TRUE; + } + } + } + enumerator->destroy(enumerator); + + chunk_free(&src_hash); + chunk_free(&dst_hash); + + if (this->src_seen && this->dst_seen) + { + this->ike_sa->set_condition(this->ike_sa, COND_NAT_HERE, + !this->dst_matched); + this->ike_sa->set_condition(this->ike_sa, COND_NAT_THERE, + !this->src_matched); + config = this->ike_sa->get_ike_cfg(this->ike_sa); + if (this->dst_matched && this->src_matched && + config->force_encap(config)) + { + this->ike_sa->set_condition(this->ike_sa, COND_NAT_FAKE, TRUE); + } + } +} + +METHOD(task_t, build_i, status_t, + private_ike_natd_v1_t *this, message_t *message) +{ + status_t result = NEED_MORE; + + switch (message->get_exchange_type(message)) + { + case AGGRESSIVE: + { /* add NAT-D payloads to the second request, already processed + * those by the responder contained in the first response */ + result = SUCCESS; + /* fall */ + } + case ID_PROT: + { /* add NAT-D payloads to the second request, need to process + * those by the responder contained in the second response */ + if (message->get_payload(message, SECURITY_ASSOCIATION_V1)) + { /* wait for the second exchange */ + return NEED_MORE; + } + add_natd_payloads(this, message); + return result; + } + default: + break; + } + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_ike_natd_v1_t *this, message_t *message) +{ + status_t result = NEED_MORE; + + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT)) + { /* we didn't receive VIDs inidcating support for NAT-T */ + return SUCCESS; + } + + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { /* process NAT-D payloads in the second response, added them in the + * second request already, so we're done afterwards */ + if (message->get_payload(message, SECURITY_ASSOCIATION_V1)) + { /* wait for the second exchange */ + return NEED_MORE; + } + result = SUCCESS; + /* fall */ + } + case AGGRESSIVE: + { /* process NAT-D payloads in the first response, add them in the + * following second request */ + process_payloads(this, message); + + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + { + this->ike_sa->float_ports(this->ike_sa); + } + return result; + } + default: + break; + } + return SUCCESS; +} + +METHOD(task_t, process_r, status_t, + private_ike_natd_v1_t *this, message_t *message) +{ + status_t result = NEED_MORE; + + if (!this->ike_sa->supports_extension(this->ike_sa, EXT_NATT)) + { /* we didn't receive VIDs indicating NAT-T support */ + return SUCCESS; + } + + switch (message->get_exchange_type(message)) + { + case AGGRESSIVE: + { /* proccess NAT-D payloads in the second request, already added ours + * in the first response */ + result = SUCCESS; + /* fall */ + } + case ID_PROT: + { /* process NAT-D payloads in the second request, need to add ours + * to the second response */ + if (message->get_payload(message, SECURITY_ASSOCIATION_V1)) + { /* wait for the second exchange */ + return NEED_MORE; + } + process_payloads(this, message); + return result; + } + default: + break; + } + return SUCCESS; +} + +METHOD(task_t, build_r, status_t, + private_ike_natd_v1_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { /* add NAT-D payloads to second response, already processed those + * contained in the second request */ + if (message->get_payload(message, SECURITY_ASSOCIATION_V1)) + { /* wait for the second exchange */ + return NEED_MORE; + } + add_natd_payloads(this, message); + return SUCCESS; + } + case AGGRESSIVE: + { /* add NAT-D payloads to the first response, process those contained + * in the following second request */ + add_natd_payloads(this, message); + return NEED_MORE; + } + default: + break; + } + return SUCCESS; +} + +METHOD(task_t, get_type, task_type_t, + private_ike_natd_v1_t *this) +{ + return TASK_IKE_NATD_V1; +} + +METHOD(task_t, migrate, void, + private_ike_natd_v1_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; + this->src_seen = FALSE; + this->dst_seen = FALSE; + this->src_matched = FALSE; + this->dst_matched = FALSE; +} + +METHOD(task_t, destroy, void, + private_ike_natd_v1_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_natd_v1_t *ike_natd_v1_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_natd_v1_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa), + .initiator = initiator, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/tasks/ike_natd_v1.h b/src/libcharon/sa/tasks/ike_natd_v1.h new file mode 100644 index 000000000..a59054fb0 --- /dev/null +++ b/src/libcharon/sa/tasks/ike_natd_v1.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_natd_v1 ike_natd_v1 + * @{ @ingroup tasks + */ + +#ifndef IKE_NATD_V1_H_ +#define IKE_NATD_V1_H_ + +typedef struct ike_natd_v1_t ike_natd_v1_t; + +#include +#include +#include + +/** + * Task of type ike_natd_v1, detects NAT situation in IKEv1 Phase 1. + */ +struct ike_natd_v1_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_natd_v1 task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + * @return ike_natd_v1 task to handle by the task_manager + */ +ike_natd_v1_t *ike_natd_v1_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_NATD_V1_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index d0eed77e3..2f12ed574 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -38,6 +38,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, "MAIN_MODE", "QUICK_MODE", "VENDOR_V1", + "IKE_NATD_V1", "XAUTH_REQUEST", ); #else @@ -61,6 +62,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, "MAIN_MODE", "QUICK_MODE", "VENDOR_V1", + "IKE_NATD_V1", "XAUTH_REQUEST", ); #endif /* ME */ diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index e76ffcd8c..e4edb78e0 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -75,6 +75,8 @@ enum task_type_t { TASK_QUICK_MODE, /** IKEv1 vendor ID payload handling */ TASK_VENDOR_V1, + /** IKEv1 NAT detection */ + TASK_IKE_NATD_V1, /** Request the user/pass with XAUTH */ TASK_XAUTH_REQUEST, }; @@ -122,7 +124,7 @@ struct task_t { * * @param message message to read payloads from * @return - * - FAILED if a critical error occurred + * - FAILED if a critical error occurred * - DESTROY_ME if IKE_SA has been properly deleted * - NEED_MORE if another call to build/process needed * - SUCCESS if task completed From 29b0cb328a705db274d4c5ecb358094113cc9c02 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 30 Nov 2011 17:52:14 +0100 Subject: [PATCH 190/534] Negotiate UDP encapsulation during Quick Mode if NAT is detected. --- src/libcharon/sa/tasks/quick_mode.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 353a1dba2..3fd21aecb 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -457,6 +457,7 @@ METHOD(task_t, build_i, status_t, sa_payload_t *sa_payload; linked_list_t *list; proposal_t *proposal; + bool udp = FALSE; this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), @@ -478,10 +479,15 @@ METHOD(task_t, build_i, status_t, } enumerator->destroy(enumerator); + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + { + udp = TRUE; + } + get_lifetimes(this); sa_payload = sa_payload_create_from_proposals_v1(list, this->lifetime, this->lifebytes, AUTH_NONE, - this->config->get_mode(this->config), FALSE); + this->config->get_mode(this->config), udp); list->destroy_offset(list, offsetof(proposal_t, destroy)); message->add_payload(message, &sa_payload->payload_interface); @@ -603,6 +609,7 @@ METHOD(task_t, build_r, status_t, case QM_INIT: { sa_payload_t *sa_payload; + bool udp = FALSE; this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); if (!this->spi_r) @@ -612,9 +619,14 @@ METHOD(task_t, build_r, status_t, } this->proposal->set_spi(this->proposal, this->spi_r); + if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + { + udp = TRUE; + } + sa_payload = sa_payload_create_from_proposal_v1(this->proposal, this->lifetime, this->lifebytes, AUTH_NONE, - this->config->get_mode(this->config), FALSE); + this->config->get_mode(this->config), udp); message->add_payload(message, &sa_payload->payload_interface); if (!add_nonce(this, &this->nonce_r, message)) From 3bf0be6b0846f357f3d7ae7bd017f5716a293a71 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 30 Nov 2011 18:03:06 +0100 Subject: [PATCH 191/534] Add NAT-OA payloads during Quick Mode if transport mode is used. We don't parse them currently, as the Linux kernel does not need them to fix the IP header checksum. --- src/libcharon/sa/tasks/quick_mode.c | 46 +++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 3fd21aecb..472aad8c6 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -403,6 +403,34 @@ static bool get_ts(private_quick_mode_t *this, message_t *message) return TRUE; } +/** + * Add NAT-OA payloads + */ +static void add_nat_oa_payloads(private_quick_mode_t *this, message_t *message) +{ + identification_t *id; + id_payload_t *nat_oa; + host_t *src, *dst; + + src = message->get_source(message); + dst = message->get_destination(message); + + src = this->initiator ? src : dst; + dst = this->initiator ? dst : src; + + /* first NAT-OA is the initiator's address */ + id = identification_create_from_sockaddr(src->get_sockaddr(src)); + nat_oa = id_payload_create_from_identification(NAT_OA_V1, id); + message->add_payload(message, (payload_t*)nat_oa); + id->destroy(id); + + /* second NAT-OA is that of the responder */ + id = identification_create_from_sockaddr(dst->get_sockaddr(dst)); + nat_oa = id_payload_create_from_identification(NAT_OA_V1, id); + message->add_payload(message, (payload_t*)nat_oa); + id->destroy(id); +} + /** * Look up lifetimes */ @@ -457,6 +485,7 @@ METHOD(task_t, build_i, status_t, sa_payload_t *sa_payload; linked_list_t *list; proposal_t *proposal; + ipsec_mode_t mode; bool udp = FALSE; this->child_sa = child_sa_create( @@ -479,15 +508,21 @@ METHOD(task_t, build_i, status_t, } enumerator->destroy(enumerator); + mode = this->config->get_mode(this->config); if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) { udp = TRUE; + /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */ + if (mode == MODE_TRANSPORT) + { + add_nat_oa_payloads(this, message); + } } get_lifetimes(this); sa_payload = sa_payload_create_from_proposals_v1(list, this->lifetime, this->lifebytes, AUTH_NONE, - this->config->get_mode(this->config), udp); + mode, udp); list->destroy_offset(list, offsetof(proposal_t, destroy)); message->add_payload(message, &sa_payload->payload_interface); @@ -609,6 +644,7 @@ METHOD(task_t, build_r, status_t, case QM_INIT: { sa_payload_t *sa_payload; + ipsec_mode_t mode; bool udp = FALSE; this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); @@ -619,14 +655,20 @@ METHOD(task_t, build_r, status_t, } this->proposal->set_spi(this->proposal, this->spi_r); + mode = this->config->get_mode(this->config); if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) { udp = TRUE; + /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */ + if (mode == MODE_TRANSPORT) + { + add_nat_oa_payloads(this, message); + } } sa_payload = sa_payload_create_from_proposal_v1(this->proposal, this->lifetime, this->lifebytes, AUTH_NONE, - this->config->get_mode(this->config), udp); + mode, udp); message->add_payload(message, &sa_payload->payload_interface); if (!add_nonce(this, &this->nonce_r, message)) From 781f4c88988f23f5a6f155a59076b37164c954c9 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 1 Dec 2011 13:11:36 +0100 Subject: [PATCH 192/534] IKEv1 XAuth: Add XAuth defines for plugin types. --- src/libstrongswan/Makefile.am | 3 +- src/libstrongswan/xauth/xauth.c | 47 +++++++++++++++++++++++++++++ src/libstrongswan/xauth/xauth.h | 53 +++++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 src/libstrongswan/xauth/xauth.c create mode 100644 src/libstrongswan/xauth/xauth.h diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index 284decbd9..bfa440d03 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -70,7 +70,8 @@ utils/linked_list.c utils/linked_list.h \ utils/hashtable.c utils/hashtable.h \ utils/enumerator.c utils/enumerator.h \ utils/optionsfrom.c utils/optionsfrom.h \ -utils/backtrace.c utils/backtrace.h +utils/backtrace.c utils/backtrace.h \ +xauth/xauth.h xauth/xauth.c library.lo : $(top_builddir)/config.status diff --git a/src/libstrongswan/xauth/xauth.c b/src/libstrongswan/xauth/xauth.c new file mode 100644 index 000000000..8c0046337 --- /dev/null +++ b/src/libstrongswan/xauth/xauth.c @@ -0,0 +1,47 @@ +/* + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth.h" + +ENUM_BEGIN(xauth_method_type_names, XAUTH_RADIUS, XAUTH_RADIUS, + "XAUTH_RADIUS"); +ENUM_END(xauth_method_type_names, XAUTH_RADIUS); + +ENUM_BEGIN(xauth_method_type_short_names, XAUTH_RADIUS, XAUTH_RADIUS, + "RAD"); +ENUM_END(xauth_method_type_short_names, XAUTH_RADIUS); + +/* + * See header + */ +xauth_type_t xauth_type_from_string(char *name) +{ + int i; + static struct { + char *name; + xauth_type_t type; + } types[] = { + {"radius", XAUTH_RADIUS}, + }; + + for (i = 0; i < countof(types); i++) + { + if (strcaseeq(name, types[i].name)) + { + return types[i].type; + } + } + return 0; +} diff --git a/src/libstrongswan/xauth/xauth.h b/src/libstrongswan/xauth/xauth.h new file mode 100644 index 000000000..19274f2f1 --- /dev/null +++ b/src/libstrongswan/xauth/xauth.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 Martin Willi + * Copyright (C) 2010 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth xauth + * @{ @ingroup libstrongswan + */ + +#ifndef XAUTH_H_ +#define XAUTH_H_ + +typedef enum xauth_type_t xauth_type_t; + +#include + +/** + * XAuth types, defines the XAuth method implementation + */ +enum xauth_type_t { + XAUTH_RADIUS = 253, +}; + +/** + * enum names for xauth_type_t. + */ +extern enum_name_t *xauth_method_type_names; + +/** + * short string enum names for xauth_type_t. + */ +extern enum_name_t *xauth_method_type_short_names; + +/** + * Lookup the XAuth method type from a string. + * + * @param name XAuth method name (such as "md5", "aka") + * @return method type, 0 if unknown + */ +xauth_type_t xauth_type_from_string(char *name); + +#endif /** XAUTH_H_ @}*/ From 9c5366446a335ca5b53ca3b8813a971ba2b01080 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 1 Dec 2011 14:08:24 +0100 Subject: [PATCH 193/534] IKEv1 XAuth: Added plugin support for XAuth, which allows us to have plugins to talk to servers with different quirks for XAuth authentication. --- src/libcharon/Makefile.am | 3 + src/libcharon/daemon.c | 2 + src/libcharon/daemon.h | 6 + .../sa/authenticators/xauth/xauth_manager.c | 161 ++++++++++++++++ .../sa/authenticators/xauth/xauth_manager.h | 81 ++++++++ .../sa/authenticators/xauth/xauth_method.c | 42 +++++ .../sa/authenticators/xauth/xauth_method.h | 133 +++++++++++++ .../sa/authenticators/xauth_authenticator.c | 175 ++++++++++++++++++ .../sa/authenticators/xauth_authenticator.h | 55 ++++++ src/libstrongswan/plugins/plugin_feature.c | 11 ++ src/libstrongswan/plugins/plugin_feature.h | 9 + 11 files changed, 678 insertions(+) create mode 100644 src/libcharon/sa/authenticators/xauth/xauth_manager.c create mode 100644 src/libcharon/sa/authenticators/xauth/xauth_manager.h create mode 100644 src/libcharon/sa/authenticators/xauth/xauth_method.c create mode 100644 src/libcharon/sa/authenticators/xauth/xauth_method.h create mode 100644 src/libcharon/sa/authenticators/xauth_authenticator.c create mode 100644 src/libcharon/sa/authenticators/xauth_authenticator.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index aab293dd2..7192e3db7 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -64,6 +64,9 @@ sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ sa/authenticators/eap/eap_manager.c sa/authenticators/eap/eap_manager.h \ sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \ sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \ +sa/authenticators/xauth_authenticator.c sa/authenticators/xauth_authenticator.h \ +sa/authenticators/xauth/xauth_method.c sa/authenticators/xauth/xauth_method.h \ +sa/authenticators/xauth/xauth_manager.c sa/authenticators/xauth/xauth_manager.h \ sa/child_sa.c sa/child_sa.h \ sa/ike_sa.c sa/ike_sa.h \ sa/ike_sa_id.c sa/ike_sa_id.h \ diff --git a/src/libcharon/daemon.c b/src/libcharon/daemon.c index 9b6af22bb..343063be5 100644 --- a/src/libcharon/daemon.c +++ b/src/libcharon/daemon.c @@ -122,6 +122,7 @@ static void destroy(private_daemon_t *this) DESTROY_IF(this->public.ike_sa_manager); DESTROY_IF(this->public.controller); DESTROY_IF(this->public.eap); + DESTROY_IF(this->public.xauth); #ifdef ME DESTROY_IF(this->public.connect_manager); DESTROY_IF(this->public.mediation_manager); @@ -291,6 +292,7 @@ private_daemon_t *daemon_create() charon = &this->public; this->public.controller = controller_create(); this->public.eap = eap_manager_create(); + this->public.xauth = xauth_manager_create(); this->public.backends = backend_manager_create(); this->public.socket = socket_manager_create(); this->public.traps = trap_manager_create(); diff --git a/src/libcharon/daemon.h b/src/libcharon/daemon.h index 2e01c8d9b..a887eab79 100644 --- a/src/libcharon/daemon.h +++ b/src/libcharon/daemon.h @@ -149,6 +149,7 @@ typedef struct daemon_t daemon_t; #include #include #include +#include #ifdef ME #include @@ -235,6 +236,11 @@ struct daemon_t { */ eap_manager_t *eap; + /** + * XAuth manager to maintain registered XAuth methods + */ + xauth_manager_t *xauth; + #ifdef ME /** * Connect manager diff --git a/src/libcharon/sa/authenticators/xauth/xauth_manager.c b/src/libcharon/sa/authenticators/xauth/xauth_manager.c new file mode 100644 index 000000000..3cddf64bd --- /dev/null +++ b/src/libcharon/sa/authenticators/xauth/xauth_manager.c @@ -0,0 +1,161 @@ +/* + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_manager.h" + +#include +#include + +typedef struct private_xauth_manager_t private_xauth_manager_t; +typedef struct xauth_entry_t xauth_entry_t; + +/** + * XAuth constructor entry + */ +struct xauth_entry_t { + + /** + * XAuth method type, vendor specific if vendor is set + */ + xauth_type_t type; + + /** + * vendor ID, 0 for default XAuth methods + */ + u_int32_t vendor; + + /** + * Role of the method returned by the constructor, XAUTH_SERVER or XAUTH_PEER + */ + xauth_role_t role; + + /** + * constructor function to create instance + */ + xauth_constructor_t constructor; +}; + +/** + * private data of xauth_manager + */ +struct private_xauth_manager_t { + + /** + * public functions + */ + xauth_manager_t public; + + /** + * list of eap_entry_t's + */ + linked_list_t *methods; + + /** + * rwlock to lock methods + */ + rwlock_t *lock; +}; + +METHOD(xauth_manager_t, add_method, void, + private_xauth_manager_t *this, xauth_type_t type, u_int32_t vendor, + xauth_role_t role, xauth_constructor_t constructor) +{ + xauth_entry_t *entry = malloc_thing(xauth_entry_t); + + entry->type = type; + entry->vendor = vendor; + entry->role = role; + entry->constructor = constructor; + + this->lock->write_lock(this->lock); + this->methods->insert_last(this->methods, entry); + this->lock->unlock(this->lock); +} + +METHOD(xauth_manager_t, remove_method, void, + private_xauth_manager_t *this, xauth_constructor_t constructor) +{ + enumerator_t *enumerator; + xauth_entry_t *entry; + + this->lock->write_lock(this->lock); + 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); + this->lock->unlock(this->lock); +} + +METHOD(xauth_manager_t, create_instance, xauth_method_t*, + private_xauth_manager_t *this, xauth_type_t type, u_int32_t vendor, + xauth_role_t role, identification_t *server, identification_t *peer) +{ + enumerator_t *enumerator; + xauth_entry_t *entry; + xauth_method_t *method = NULL; + + this->lock->read_lock(this->lock); + 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); + this->lock->unlock(this->lock); + return method; +} + +METHOD(xauth_manager_t, destroy, void, + private_xauth_manager_t *this) +{ + this->methods->destroy_function(this->methods, free); + this->lock->destroy(this->lock); + free(this); +} + +/* + * See header + */ +xauth_manager_t *xauth_manager_create() +{ + private_xauth_manager_t *this; + + INIT(this, + .public = { + .add_method = _add_method, + .remove_method = _remove_method, + .create_instance = _create_instance, + .destroy = _destroy, + }, + .methods = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + ); + + return &this->public; +} diff --git a/src/libcharon/sa/authenticators/xauth/xauth_manager.h b/src/libcharon/sa/authenticators/xauth/xauth_manager.h new file mode 100644 index 000000000..401c13e99 --- /dev/null +++ b/src/libcharon/sa/authenticators/xauth/xauth_manager.h @@ -0,0 +1,81 @@ +/* + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_manager xauth_manager + * @{ @ingroup xauth + */ + +#ifndef XAUTH_MANAGER_H_ +#define XAUTH_MANAGER_H_ + +#include + +typedef struct xauth_manager_t xauth_manager_t; + +/** + * The XAuth manager manages all XAuth implementations and creates instances. + * + * A plugin registers it's implemented XAuth method at the manager by + * providing type and a contructor function. The manager then instanciates + * xauth_method_t instances through the provided constructor to handle + * XAuth authentication. + */ +struct xauth_manager_t { + + /** + * Register a XAuth method implementation. + * + * @param method vendor specific method, if vendor != 0 + * @param vendor vendor ID, 0 for non-vendor (default) XAuth methods + * @param role XAuth role of the registered method + * @param constructor constructor function, returns an xauth_method_t + */ + void (*add_method)(xauth_manager_t *this, xauth_type_t type, u_int32_t vendor, + xauth_role_t role, xauth_constructor_t constructor); + + /** + * Unregister a XAuth method implementation using it's constructor. + * + * @param constructor constructor function to remove, as added in add_method + */ + void (*remove_method)(xauth_manager_t *this, xauth_constructor_t constructor); + + /** + * Create a new XAuth method instance. + * + * @param vendor vendor ID, 0 for non-vendor (default) XAuth methods + * @param role role of XAuth method, either XAUTH_SERVER or XAUTH_PEER + * @param server identity of the server + * @param peer identity of the peer (client) + * @return XAUTH method instance, NULL if no constructor found + */ + xauth_method_t* (*create_instance)(xauth_manager_t *this, xauth_type_t type, + u_int32_t vendor, xauth_role_t role, + identification_t *server, + identification_t *peer); + + /** + * Destroy a eap_manager instance. + */ + void (*destroy)(xauth_manager_t *this); +}; + +/** + * Create a eap_manager instance. + */ +xauth_manager_t *xauth_manager_create(); + +#endif /** EAP_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/xauth/xauth_method.c b/src/libcharon/sa/authenticators/xauth/xauth_method.c new file mode 100644 index 000000000..14da7b9ba --- /dev/null +++ b/src/libcharon/sa/authenticators/xauth/xauth_method.c @@ -0,0 +1,42 @@ +/* + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_method.h" + +#include + +ENUM(xauth_role_names, XAUTH_SERVER, XAUTH_PEER, + "XAUTH_SERVER", + "XAUTH_PEER", +); + +/** + * See header + */ +bool xauth_method_register(plugin_t *plugin, plugin_feature_t *feature, + bool reg, void *data) +{ + if (reg) + { + charon->xauth->add_method(charon->xauth, feature->arg.xauth, 0, + feature->type == FEATURE_XAUTH_SERVER ? XAUTH_SERVER : XAUTH_PEER, + (xauth_constructor_t)data); + } + else + { + charon->xauth->remove_method(charon->xauth, (xauth_constructor_t)data); + } + return TRUE; +} diff --git a/src/libcharon/sa/authenticators/xauth/xauth_method.h b/src/libcharon/sa/authenticators/xauth/xauth_method.h new file mode 100644 index 000000000..fb289a247 --- /dev/null +++ b/src/libcharon/sa/authenticators/xauth/xauth_method.h @@ -0,0 +1,133 @@ +/* + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_method xauth_method + * @{ @ingroup xauth + */ + +#ifndef XAUTH_METHOD_H_ +#define XAUTH_METHOD_H_ + +typedef struct xauth_method_t xauth_method_t; +typedef enum xauth_role_t xauth_role_t; + +#include +#include +#include +#include +#include + +/** + * Role of an xauth_method, SERVER or PEER (client) + */ +enum xauth_role_t { + XAUTH_SERVER, + XAUTH_PEER, +}; +/** + * enum names for xauth_role_t. + */ +extern enum_name_t *xauth_role_names; + +/** + * Interface of an XAuth method for server and client side. + * + * An XAuth method initiates an XAuth exchange and processes requests and + * responses. An XAuth method may need multiple exchanges before succeeding, and + * the xauth_authentication may use multiple XAuth methods to authenticate a peer. + * To accomplish these requirements, all XAuth methods have their own + * implementation while the xauth_authenticatior uses one or more of these + * XAuth methods. Sending of XAUTH(STATUS) message is not the job + * of the method, the xauth_authenticator does this. + */ +struct xauth_method_t { + + /** + * Initiate the XAuth exchange. + * + * initiate() is only useable for server implementations, as clients only + * reply to server requests. + * A cp_payload is created in "out" if result is NEED_MORE. + * + * @param out cp_payload to send to the client + * @return + * - NEED_MORE, if an other exchange is required + * - FAILED, if unable to create XAuth request payload + */ + status_t (*initiate) (xauth_method_t *this, cp_payload_t **out); + + /** + * Process a received XAuth message. + * + * A cp_payload is created in "out" if result is NEED_MORE. + * + * @param in cp_payload response received + * @param out created cp_payload to send + * @return + * - NEED_MORE, if an other exchange is required + * - FAILED, if XAuth method failed + * - SUCCESS, if XAuth method succeeded + */ + status_t (*process) (xauth_method_t *this, cp_payload_t *in, + cp_payload_t **out); + + /** + * Get the XAuth type implemented in this method. + * + * @param vendor pointer receiving vendor identifier for type, 0 for none + * @return type of the XAuth method + */ + xauth_type_t (*get_type) (xauth_method_t *this, u_int32_t *vendor); + + /** + * Destroys a eap_method_t object. + */ + void (*destroy) (xauth_method_t *this); +}; + +/** + * Constructor definition for a pluggable XAuth method. + * + * Each XAuth module must define a constructor function which will return + * an initialized object with the methods defined in xauth_method_t. + * Constructors for server and peers are identical, to support both roles + * of a XAuth method, a plugin needs register two constructors in the + * xauth_manager_t. + * The passed identites are of type ID_EAP and valid only during the + * constructor invocation. + * + * @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 + */ +typedef xauth_method_t *(*xauth_constructor_t)(identification_t *server, + identification_t *peer); + +/** + * Helper function to (un-)register XAuth methods from plugin features. + * + * This function is a plugin_feature_callback_t and can be used with the + * PLUGIN_CALLBACK macro to register a XAuth method constructor. + * + * @param plugin plugin registering the XAuth method constructor + * @param feature associated plugin feature + * @param reg TRUE to register, FALSE to unregister. + * @param data data passed to callback, an xauth_constructor_t + */ +bool xauth_method_register(plugin_t *plugin, plugin_feature_t *feature, + bool reg, void *data); + +#endif /** XAUTH_METHOD_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/xauth_authenticator.c b/src/libcharon/sa/authenticators/xauth_authenticator.c new file mode 100644 index 000000000..3f0e591c6 --- /dev/null +++ b/src/libcharon/sa/authenticators/xauth_authenticator.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2005-2009 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_authenticator.h" + +#include +#include +#include + +typedef struct private_xauth_authenticator_t private_xauth_authenticator_t; + +/** + * Private data of an xauth_authenticator_t object. + */ +struct private_xauth_authenticator_t { + + /** + * Public authenticator_t interface. + */ + xauth_authenticator_t public; + + /** + * Assigned IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * The payload to send + */ + cp_payload_t *cp_payload; + + /** + * Whether the authenticator is for an XAUTH server or client + */ + xauth_role_t role; +}; + +/** + * load an XAuth method + */ +static xauth_method_t *load_method(private_xauth_authenticator_t *this, + xauth_type_t type, u_int32_t vendor) +{ + identification_t *server, *peer, *aaa; + auth_cfg_t *auth; + + if (this->role == XAUTH_SERVER) + { + server = this->ike_sa->get_my_id(this->ike_sa); + peer = this->ike_sa->get_other_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + } + else + { + server = this->ike_sa->get_other_id(this->ike_sa); + peer = this->ike_sa->get_my_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + } + aaa = auth->get(auth, AUTH_RULE_AAA_IDENTITY); + if (aaa) + { + server = aaa; + } + return charon->xauth->create_instance(charon->xauth, type, vendor, + this->role, server, peer); +} + +METHOD(authenticator_t, build, status_t, + private_xauth_authenticator_t *this, message_t *message) +{ + if(this->cp_payload != NULL) + { + message->add_payload(message, (payload_t *)this->cp_payload); + return NEED_MORE; + } + return SUCCESS; +} + +METHOD(authenticator_t, process, status_t, + private_xauth_authenticator_t *this, message_t *message) +{ + xauth_method_t *xauth_method = NULL; + cp_payload_t *cp_in, *cp_out; + status_t status = FAILED; + + cp_in = (cp_payload_t *)message->get_payload(message, CONFIGURATION_V1); + + xauth_method = load_method(this, XAUTH_RADIUS, 0); + + if(xauth_method != NULL) + { + status = xauth_method->process(xauth_method, cp_in, &cp_out); + if(status == NEED_MORE) + { + this->cp_payload = cp_out; + } + else + { + xauth_method->destroy(xauth_method); + } + } + else + { + DBG1(DBG_IKE, "Couldn't locate valid xauth method."); + } + + return status; +} + +METHOD(authenticator_t, destroy, void, + private_xauth_authenticator_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +xauth_authenticator_t *xauth_authenticator_create_builder(ike_sa_t *ike_sa) +{ + private_xauth_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .cp_payload = NULL, + .role = XAUTH_PEER, + ); + + return &this->public; +} + +/* + * Described in header. + */ +xauth_authenticator_t *xauth_authenticator_create_verifier(ike_sa_t *ike_sa) +{ + private_xauth_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .cp_payload = NULL, + .role = XAUTH_SERVER, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/authenticators/xauth_authenticator.h b/src/libcharon/sa/authenticators/xauth_authenticator.h new file mode 100644 index 000000000..d316b1672 --- /dev/null +++ b/src/libcharon/sa/authenticators/xauth_authenticator.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2006-2009 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_authenticator xauth_authenticator + * @{ @ingroup authenticators + */ + +#ifndef XAUTH_AUTHENTICATOR_H_ +#define XAUTH_AUTHENTICATOR_H_ + +typedef struct xauth_authenticator_t xauth_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using XAuth. + */ +struct xauth_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to build XAuth response payloads. + * + * @param ike_sa associated ike_sa + * @return PSK authenticator + */ +xauth_authenticator_t *xauth_authenticator_create_builder(ike_sa_t *ike_sa); + +/** + * Create an authenticator to verify using XAuth payloads. + * + * @param ike_sa associated ike_sa + * @return PSK authenticator + */ +xauth_authenticator_t *xauth_authenticator_create_verifier(ike_sa_t *ike_sa); + +#endif /** XAUTH_AUTHENTICATOR_H_ @}*/ diff --git a/src/libstrongswan/plugins/plugin_feature.c b/src/libstrongswan/plugins/plugin_feature.c index 2a97205bb..b2bf41946 100644 --- a/src/libstrongswan/plugins/plugin_feature.c +++ b/src/libstrongswan/plugins/plugin_feature.c @@ -96,6 +96,9 @@ bool plugin_feature_matches(plugin_feature_t *a, plugin_feature_t *b) streq(a->arg.fetcher, b->arg.fetcher); case FEATURE_CUSTOM: return streq(a->arg.custom, b->arg.custom); + case FEATURE_XAUTH_SERVER: + case FEATURE_XAUTH_PEER: + return a->arg.xauth == b->arg.xauth; } } return FALSE; @@ -229,6 +232,14 @@ char* plugin_feature_get_string(plugin_feature_t *feature) return str; } break; + case FEATURE_XAUTH_SERVER: + case FEATURE_XAUTH_PEER: + if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type, + xauth_method_type_short_names, feature->arg.xauth) > 0) + { + return str; + } + break; } if (!str) { diff --git a/src/libstrongswan/plugins/plugin_feature.h b/src/libstrongswan/plugins/plugin_feature.h index b1500feba..89c954471 100644 --- a/src/libstrongswan/plugins/plugin_feature.h +++ b/src/libstrongswan/plugins/plugin_feature.h @@ -25,6 +25,7 @@ typedef struct plugin_feature_t plugin_feature_t; #include #include +#include #include /** @@ -135,6 +136,10 @@ struct plugin_feature_t { FEATURE_FETCHER, /** custom feature, described with a string */ FEATURE_CUSTOM, + /** XAuth server implementation */ + FEATURE_XAUTH_SERVER, + /** XAuth peer implementation */ + FEATURE_XAUTH_PEER, } type; /** More specific data for each type */ union { @@ -182,6 +187,8 @@ struct plugin_feature_t { char *fetcher; /** FEATURE_CUSTOM */ char *custom; + /** FEATURE_XAUTH_SERVER/CLIENT */ + xauth_type_t xauth; /** FEATURE_REGISTER */ struct { @@ -266,6 +273,8 @@ struct plugin_feature_t { #define _PLUGIN_FEATURE_DATABASE(kind, type) __PLUGIN_FEATURE(kind, DATABASE, .database = type) #define _PLUGIN_FEATURE_FETCHER(kind, type) __PLUGIN_FEATURE(kind, FETCHER, .fetcher = type) #define _PLUGIN_FEATURE_CUSTOM(kind, name) __PLUGIN_FEATURE(kind, CUSTOM, .custom = name) +#define _PLUGIN_FEATURE_XAUTH_SERVER(kind, type) __PLUGIN_FEATURE(kind, XAUTH_SERVER, .xauth = type) +#define _PLUGIN_FEATURE_XAUTH_PEER(kind, type) __PLUGIN_FEATURE(kind, XAUTH_PEER, .xauth = type) #define __PLUGIN_FEATURE_REGISTER(type, _f) (plugin_feature_t){ FEATURE_REGISTER, FEATURE_##type, .arg.reg.f = _f } #define __PLUGIN_FEATURE_REGISTER_BUILDER(type, _f, _final) (plugin_feature_t){ FEATURE_REGISTER, FEATURE_##type, .arg.reg = {.f = _f, .final = _final, }} From 4394d96844343ea0429a0ea285140b146aeef62a Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 1 Dec 2011 16:34:30 +0100 Subject: [PATCH 194/534] IKEv1 XAuth: Added a "NULL" XAuth plugin which sends a hardcoded user/pass, and blindly accepts whatever user/pass is sent it. Changed the xauth_request task to use this new plugin. Add --enable-xauth-null to your configure line to build with the new plugin. --- configure.in | 4 + src/libcharon/plugins/xauth_null/Makefile.am | 16 +++ src/libcharon/plugins/xauth_null/xauth_null.c | 132 ++++++++++++++++++ src/libcharon/plugins/xauth_null/xauth_null.h | 59 ++++++++ .../plugins/xauth_null/xauth_null_plugin.c | 62 ++++++++ .../plugins/xauth_null/xauth_null_plugin.h | 42 ++++++ .../sa/authenticators/xauth_authenticator.c | 2 +- src/libcharon/sa/tasks/xauth_request.c | 53 ++++--- src/libstrongswan/xauth/xauth.c | 15 +- src/libstrongswan/xauth/xauth.h | 1 + 10 files changed, 363 insertions(+), 23 deletions(-) create mode 100644 src/libcharon/plugins/xauth_null/Makefile.am create mode 100644 src/libcharon/plugins/xauth_null/xauth_null.c create mode 100644 src/libcharon/plugins/xauth_null/xauth_null.h create mode 100644 src/libcharon/plugins/xauth_null/xauth_null_plugin.c create mode 100644 src/libcharon/plugins/xauth_null/xauth_null_plugin.h diff --git a/configure.in b/configure.in index 893914251..7385570b5 100755 --- a/configure.in +++ b/configure.in @@ -193,6 +193,7 @@ ARG_ENABL_SET([duplicheck], [advanced duplicate checking plugin using livene ARG_ENABL_SET([coupling], [enable IKEv2 plugin to couple peer certificates permanently to authentication.]) ARG_ENABL_SET([vstr], [enforce using the Vstr string library to replace glibc-like printf hooks.]) ARG_ENABL_SET([monolithic], [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.]) +ARG_ENABL_SET([xauth-null], [enable XAuth module which does no actual identity authentication (testing only).]) dnl ========================= dnl set up compiler and flags @@ -864,6 +865,7 @@ ADD_PLUGIN([maemo], [c libcharon]) ADD_PLUGIN([uci], [c libcharon]) ADD_PLUGIN([addrblock], [c libcharon]) ADD_PLUGIN([unit-tester], [c libcharon]) +ADD_PLUGIN([xauth-null], [c libcharon]) AC_SUBST(libcharon_plugins) AC_SUBST(pluto_plugins) @@ -979,6 +981,7 @@ AM_CONDITIONAL(USE_SOCKET_RAW, test x$socket_raw = xtrue) AM_CONDITIONAL(USE_SOCKET_DYNAMIC, test x$socket_dynamic = xtrue) AM_CONDITIONAL(USE_FARP, test x$farp = xtrue) AM_CONDITIONAL(USE_ADDRBLOCK, test x$addrblock = xtrue) +AM_CONDITIONAL(USE_XAUTH_NULL, test x$xauth_null = xtrue) dnl hydra plugins dnl ============= @@ -1170,6 +1173,7 @@ AC_OUTPUT( src/libcharon/plugins/dhcp/Makefile src/libcharon/plugins/unit_tester/Makefile src/libcharon/plugins/load_tester/Makefile + src/libcharon/plugins/xauth_null/Makefile src/stroke/Makefile src/ipsec/Makefile src/starter/Makefile diff --git a/src/libcharon/plugins/xauth_null/Makefile.am b/src/libcharon/plugins/xauth_null/Makefile.am new file mode 100644 index 000000000..f4ff03c47 --- /dev/null +++ b/src/libcharon/plugins/xauth_null/Makefile.am @@ -0,0 +1,16 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-xauth-null.la +else +plugin_LTLIBRARIES = libstrongswan-xauth-null.la +endif + +libstrongswan_xauth_null_la_SOURCES = \ + xauth_null_plugin.h xauth_null_plugin.c xauth_null.h xauth_null.c + +libstrongswan_xauth_null_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/xauth_null/xauth_null.c b/src/libcharon/plugins/xauth_null/xauth_null.c new file mode 100644 index 000000000..34ed4959a --- /dev/null +++ b/src/libcharon/plugins/xauth_null/xauth_null.c @@ -0,0 +1,132 @@ +/* + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_null.h" + +#include +#include + +typedef struct private_xauth_null_t private_xauth_null_t; + +/** + * Private data of an xauth_null_t object. + */ +struct private_xauth_null_t { + + /** + * Public authenticator_t interface. + */ + xauth_null_t public; + + /** + * ID of the peer + */ + identification_t *peer; +}; + +METHOD(xauth_method_t, process_peer, status_t, + private_xauth_null_t *this, cp_payload_t *in, cp_payload_t **out) +{ + chunk_t user_name = chunk_from_chars('j', 'o', 's', 't'); + chunk_t user_pass = chunk_from_chars('j', 'o', 's', 't'); + cp_payload_t *cp; + + /* TODO-IKEv1: Fetch the user/pass from an authenticator */ + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, user_name)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, user_pass)); + *out = cp; + return NEED_MORE; +} + +METHOD(xauth_method_t, initiate_peer, status_t, + private_xauth_null_t *this, cp_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +METHOD(xauth_method_t, process_server, status_t, + private_xauth_null_t *this, cp_payload_t *in, cp_payload_t **out) +{ + return SUCCESS; +} + +METHOD(xauth_method_t, initiate_server, status_t, + private_xauth_null_t *this, cp_payload_t **out) +{ + return NEED_MORE; +} + +METHOD(xauth_method_t, get_type, xauth_type_t, + private_xauth_null_t *this, u_int32_t *vendor) +{ + return XAUTH_NULL; +} + +METHOD(xauth_method_t, destroy, void, + private_xauth_null_t *this) +{ + this->peer->destroy(this->peer); + free(this); +} + +/* + * Described in header. + */ +xauth_null_t *xauth_null_create_peer(identification_t *server, + identification_t *peer) +{ + private_xauth_null_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate_peer, + .process = _process_peer, + .get_type = _get_type, + .destroy = _destroy, + }, + }, + .peer = peer->clone(peer), + ); + + return &this->public; +} + +/* + * Described in header. + */ +xauth_null_t *xauth_null_create_server(identification_t *server, + identification_t *peer) +{ + private_xauth_null_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate_server, + .process = _process_server, + .get_type = _get_type, + .destroy = _destroy, + }, + }, + .peer = peer->clone(peer), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/xauth_null/xauth_null.h b/src/libcharon/plugins/xauth_null/xauth_null.h new file mode 100644 index 000000000..e3ebaa128 --- /dev/null +++ b/src/libcharon/plugins/xauth_null/xauth_null.h @@ -0,0 +1,59 @@ +/* + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_null_i xauth_null + * @{ @ingroup xauth_null + */ + +#ifndef XAUTH_NULL_H_ +#define XAUTH_NULL_H_ + +typedef struct xauth_null_t xauth_null_t; + +#include + +/** + * Implementation of the xauth_method_t providing no actual identity verification. + */ +struct xauth_null_t { + + /** + * Implemented xauth_method_t interface. + */ + xauth_method_t xauth_method; +}; + +/** + * Creates the XAuth method XAuth NULL, acting as server. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_null_t object + */ +xauth_null_t *xauth_null_create_server(identification_t *server, + identification_t *peer); + +/** + * Creates the XAuth method XAuth NULL, acting as peer. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_null_t object + */ +xauth_null_t *xauth_null_create_peer(identification_t *server, + identification_t *peer); + +#endif /** XAUTH_NULL_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_null/xauth_null_plugin.c b/src/libcharon/plugins/xauth_null/xauth_null_plugin.c new file mode 100644 index 000000000..25b7b3841 --- /dev/null +++ b/src/libcharon/plugins/xauth_null/xauth_null_plugin.c @@ -0,0 +1,62 @@ +/* + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_null_plugin.h" +#include "xauth_null.h" + +#include + +METHOD(plugin_t, get_name, char*, + xauth_null_plugin_t *this) +{ + return "xauth-null"; +} + +METHOD(plugin_t, get_features, int, + xauth_null_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(xauth_method_register, xauth_null_create_server), + PLUGIN_PROVIDE(XAUTH_SERVER, XAUTH_NULL), + PLUGIN_CALLBACK(xauth_method_register, xauth_null_create_peer), + PLUGIN_PROVIDE(XAUTH_PEER, XAUTH_NULL), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + xauth_null_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *xauth_null_plugin_create() +{ + xauth_null_plugin_t *this; + + INIT(this, + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + ); + + return &this->plugin; +} diff --git a/src/libcharon/plugins/xauth_null/xauth_null_plugin.h b/src/libcharon/plugins/xauth_null/xauth_null_plugin.h new file mode 100644 index 000000000..55f4ae19b --- /dev/null +++ b/src/libcharon/plugins/xauth_null/xauth_null_plugin.h @@ -0,0 +1,42 @@ +/* + * 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 . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_null xauth_null + * @ingroup cplugins + * + * @defgroup xauth_null_plugin xauth_null_plugin + * @{ @ingroup xauth_null + */ + +#ifndef XAUTH_NULL_PLUGIN_H_ +#define XAUTH_NULL_PLUGIN_H_ + +#include + +typedef struct xauth_null_plugin_t xauth_null_plugin_t; + +/** + * XAUTH Null plugin. + */ +struct xauth_null_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** XAUTH_NULL_PLUGIN_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/xauth_authenticator.c b/src/libcharon/sa/authenticators/xauth_authenticator.c index 3f0e591c6..871817d70 100644 --- a/src/libcharon/sa/authenticators/xauth_authenticator.c +++ b/src/libcharon/sa/authenticators/xauth_authenticator.c @@ -98,7 +98,7 @@ METHOD(authenticator_t, process, status_t, cp_in = (cp_payload_t *)message->get_payload(message, CONFIGURATION_V1); - xauth_method = load_method(this, XAUTH_RADIUS, 0); + xauth_method = load_method(this, XAUTH_NULL, 0); if(xauth_method != NULL) { diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c index 8e4489ed2..7da5bf9e1 100644 --- a/src/libcharon/sa/tasks/xauth_request.c +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -4,6 +4,7 @@ #include #include #include +#include typedef struct private_xauth_request_t private_xauth_request_t; @@ -90,6 +91,11 @@ struct private_xauth_request_t { * Whether the XAuth status attribute was received */ bool xauth_status_recv; + + /** + * The XAuth authenticator_t object + */ + authenticator_t *xauth_authenticator; }; /** @@ -343,6 +349,11 @@ static status_t process_payloads(private_xauth_request_t *this, message_t *messa } } enumerator->destroy(enumerator); + + if(this->xauth_authenticator) + { + this->xauth_authenticator->process(this->xauth_authenticator, message); + } return NEED_MORE; } @@ -360,6 +371,7 @@ METHOD(task_t, build_i, status_t, attribute_handler_t *handler; configuration_attribute_type_t type; chunk_t data; + status_t status; version = this->ike_sa->get_version(this->ike_sa); if(version == IKEV1) @@ -401,10 +413,11 @@ METHOD(task_t, build_i, status_t, ca_type, XAUTH_USER_PASSWORD, chunk)); break; case TASK_XAUTH_PASS_VERIFY: + status = this->xauth_authenticator->build(this->xauth_authenticator, message); cp = cp_payload_create_type(cp_type, CFG_SET); cp->add_attribute(cp, configuration_attribute_create_value( XAUTH_STATUS, - (this->status == FAILED ? XAUTH_STATUS_FAIL : XAUTH_STATUS_OK))); + (status == FAILED ? XAUTH_STATUS_FAIL : XAUTH_STATUS_OK))); break; case TASK_XAUTH_COMPLETE: /* ConfigMode stuff */ @@ -467,6 +480,7 @@ METHOD(task_t, process_r, status_t, { ike_version_t version; payload_type_t cp_type; + status_t status; version = this->ike_sa->get_version(this->ike_sa); if(version == IKEV1) @@ -485,6 +499,10 @@ METHOD(task_t, process_r, status_t, /* We aren't XAuth, so do we should expect ConfigMode stuff */ this->state = TASK_XAUTH_COMPLETE; } + if((this->xauth_authenticator == NULL) && (this->state == TASK_XAUTH_INIT)) + { + this->xauth_authenticator = (authenticator_t *)xauth_authenticator_create_builder(this->ike_sa); + } cp_type = CONFIGURATION_V1; } else /* IKEv2 */ @@ -498,14 +516,17 @@ METHOD(task_t, process_r, status_t, cp_type = CONFIGURATION; } - return process_payloads(this, message); + status = process_payloads(this, message); + if(this->xauth_authenticator != NULL) + { + status = this->xauth_authenticator->process(this->xauth_authenticator, message); + } + return status; } METHOD(task_t, build_r, status_t, private_xauth_request_t *this, message_t *message) { - chunk_t user_name = chunk_from_chars('j', 'o', 's', 't'); - chunk_t user_pass = chunk_from_chars('j', 'o', 's', 't'); status_t status; cp_payload_t *cp = NULL; payload_type_t cp_type = CONFIGURATION; @@ -518,11 +539,11 @@ METHOD(task_t, build_r, status_t, host_t *vip = NULL; peer_cfg_t *config; - if(this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + version = this->ike_sa->get_version(this->ike_sa); + if ((version == IKEV2) && (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)) { return NEED_MORE; } - version = this->ike_sa->get_version(this->ike_sa); if(version == IKEV1) { if(!this->auth_cfg) @@ -545,17 +566,8 @@ METHOD(task_t, build_r, status_t, switch(this->state) { case TASK_XAUTH_INIT: - /* TODO-IKEv1: Fetch the user/pass from an authenticator */ - cp = cp_payload_create_type(cp_type, CFG_REPLY); - cp->add_attribute(cp, configuration_attribute_create_chunk( - ca_type, XAUTH_USER_NAME, user_name)); - cp->add_attribute(cp, configuration_attribute_create_chunk( - ca_type, XAUTH_USER_PASSWORD, user_pass)); - chunk_clear(&user_name); - chunk_clear(&user_pass); - + status = this->xauth_authenticator->build(this->xauth_authenticator, message); this->state = TASK_XAUTH_PASS_VERIFY; - status = NEED_MORE; break; case TASK_XAUTH_PASS_VERIFY: cp = cp_payload_create_type(cp_type, CFG_ACK); @@ -612,6 +624,10 @@ METHOD(task_t, build_r, status_t, default: return FAILED; } + if(cp != NULL) + { + message->add_payload(message, (payload_t *)cp); + } if(status == SUCCESS) { this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); @@ -629,6 +645,10 @@ METHOD(task_t, process_i, status_t, (this->ike_sa->get_version(this->ike_sa) == IKEV1)) { /* in last IKE_AUTH exchange */ + if(this->xauth_authenticator == NULL) + { + this->xauth_authenticator = (authenticator_t *)xauth_authenticator_create_verifier(this->ike_sa); + } status = process_payloads(this, message); this->state = this->next_state; @@ -674,6 +694,7 @@ METHOD(task_t, destroy, void, { DESTROY_IF(this->virtual_ip); this->requested->destroy_function(this->requested, free); + this->xauth_authenticator->destroy(this->xauth_authenticator); free(this); } diff --git a/src/libstrongswan/xauth/xauth.c b/src/libstrongswan/xauth/xauth.c index 8c0046337..b2caf374a 100644 --- a/src/libstrongswan/xauth/xauth.c +++ b/src/libstrongswan/xauth/xauth.c @@ -15,13 +15,15 @@ #include "xauth.h" -ENUM_BEGIN(xauth_method_type_names, XAUTH_RADIUS, XAUTH_RADIUS, - "XAUTH_RADIUS"); -ENUM_END(xauth_method_type_names, XAUTH_RADIUS); +ENUM_BEGIN(xauth_method_type_names, XAUTH_RADIUS, XAUTH_NULL, + "XAUTH_RADIUS", + "XAUTH_NULL"); +ENUM_END(xauth_method_type_names, XAUTH_NULL); -ENUM_BEGIN(xauth_method_type_short_names, XAUTH_RADIUS, XAUTH_RADIUS, - "RAD"); -ENUM_END(xauth_method_type_short_names, XAUTH_RADIUS); +ENUM_BEGIN(xauth_method_type_short_names, XAUTH_RADIUS, XAUTH_NULL, + "RAD", + "NULL"); +ENUM_END(xauth_method_type_short_names, XAUTH_NULL); /* * See header @@ -34,6 +36,7 @@ xauth_type_t xauth_type_from_string(char *name) xauth_type_t type; } types[] = { {"radius", XAUTH_RADIUS}, + {"null", XAUTH_NULL}, }; for (i = 0; i < countof(types); i++) diff --git a/src/libstrongswan/xauth/xauth.h b/src/libstrongswan/xauth/xauth.h index 19274f2f1..4554ee779 100644 --- a/src/libstrongswan/xauth/xauth.h +++ b/src/libstrongswan/xauth/xauth.h @@ -30,6 +30,7 @@ typedef enum xauth_type_t xauth_type_t; */ enum xauth_type_t { XAUTH_RADIUS = 253, + XAUTH_NULL = 254, }; /** From 8cb6f4f979be416e5b9021af282810d8e94ed106 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Fri, 2 Dec 2011 08:38:43 +0100 Subject: [PATCH 195/534] Don't stop processing tasks if one returns SUCCESS. Only send a response if at least one of the tasks requires it. --- src/libcharon/sa/task_manager_v1.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 18decb678..a2b172570 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -488,6 +488,7 @@ static status_t process_request(private_task_manager_t *this, { enumerator_t *enumerator; task_t *task = NULL; + bool send_response = FALSE; if (this->passive_tasks->get_count(this->passive_tasks) == 0) { /* create tasks depending on request type, if not already some queued */ @@ -530,10 +531,10 @@ static status_t process_request(private_task_manager_t *this, /* task completed, remove it */ this->passive_tasks->remove_at(this->passive_tasks, enumerator); task->destroy(task); - enumerator->destroy(enumerator); - return SUCCESS; + break; case NEED_MORE: /* processed, but task needs at least another call to build() */ + send_response = TRUE; break; case FAILED: default: @@ -549,7 +550,11 @@ static status_t process_request(private_task_manager_t *this, } enumerator->destroy(enumerator); - return build_response(this, message); + if (send_response) + { + return build_response(this, message); + } + return SUCCESS; } /** From f00ffe4dd2c3f2de9317f3ec13ac63e0191508bc Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 2 Dec 2011 15:39:09 +0100 Subject: [PATCH 196/534] IKEv1 XAuth: Added changes to Makefile.am to compile the xauth_null plugin. --- src/libcharon/Makefile.am | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 7192e3db7..4d3cc39c7 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -500,3 +500,9 @@ if MONOLITHIC endif endif +if USE_XAUTH_NULL + SUBDIRS += plugins/xauth_null +if MONOLITHIC + libcharon_la_LIBADD += plugins/xauth_null/libstrongswan-xauth-null.la +endif +endif From 07abb470c661cc2df1005b01ad17e1564f32384e Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 2 Dec 2011 16:22:42 +0100 Subject: [PATCH 197/534] IKEv1: Added basic support for INFORMATIONAL exchange types, and for NOTIFY_V1 messages in the 3rd message in quick_mode. --- src/libcharon/encoding/message.c | 22 ++++++---- .../encoding/payloads/notify_payload.c | 2 +- src/libcharon/sa/task_manager_v1.c | 42 ++++++++++++++++++- src/libcharon/sa/tasks/quick_mode.c | 29 +++++++++++++ 4 files changed, 83 insertions(+), 12 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index b63264bf9..0a808ac02 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -574,6 +574,7 @@ static payload_order_t aggressive_r_order[] = { */ static payload_rule_t informational_i_rules_v1[] = { /* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, @@ -1946,22 +1947,25 @@ METHOD(message_t, parse_body, status_t, { hash_payload_t *hash_payload; chunk_t other_hash; - if (this->first_payload != HASH_V1) + if ((this->first_payload != HASH_V1) && (this->public.get_exchange_type(&this->public) != INFORMATIONAL_V1)) { DBG1(DBG_ENC, "expected HASH payload as first payload"); chunk_free(&hash); return VERIFY_ERROR; } - hash_payload = (hash_payload_t*)get_payload(this, HASH_V1); - other_hash = hash_payload->get_hash(hash_payload); - if (!chunk_equals(hash, other_hash)) + if (this->first_payload == HASH_V1) { - DBG1(DBG_ENC, "our hash does not match received %B", - &other_hash); - chunk_free(&hash); - return FAILED; + hash_payload = (hash_payload_t*)get_payload(this, HASH_V1); + other_hash = hash_payload->get_hash(hash_payload); + if (!chunk_equals(hash, other_hash)) + { + DBG1(DBG_ENC, "our hash does not match received %B", + &other_hash); + chunk_free(&hash); + return FAILED; + } + DBG2(DBG_ENC, "verified IKEv1 message with hash %B", &hash); } - DBG2(DBG_ENC, "verified IKEv1 message with hash %B", &hash); chunk_free(&hash); } } diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index a5ffb0693..a72a0f37e 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -413,7 +413,7 @@ METHOD(payload_t, verify, status_t, case INVALID_MAJOR_VERSION: case NO_PROPOSAL_CHOSEN: { - if (this->notify_data.len != 0) + if ((this->notify_data.len != 0) && (this->type == NOTIFY)) { bad_length = TRUE; } diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index a2b172570..86b25e456 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -489,6 +489,8 @@ static status_t process_request(private_task_manager_t *this, enumerator_t *enumerator; task_t *task = NULL; bool send_response = FALSE; + payload_t *payload; + notify_payload_t *notify; if (this->passive_tasks->get_count(this->passive_tasks) == 0) { /* create tasks depending on request type, if not already some queued */ @@ -511,8 +513,44 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); break; case INFORMATIONAL_V1: - /* TODO-IKEv1: informational */ - return FAILED; + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case NOTIFY_V1: + { + notify = (notify_payload_t*)payload; + switch (notify->get_notify_type(notify)) + { + /* TODO-IKEv1: Add notification types here as needed */ + case INITIAL_CONTACT_IKEV1: + break; + default: + if(notify->get_notify_type(notify) < 16384) + { + DBG1(DBG_IKE, "Received %N error notification.", notify_type_names, notify->get_notify_type(notify)); + return FAILED; + } + break; + } + break; + } + case DELETE_V1: + { + /* TODO-IKEv1: Delete payload handling. */ + break; + } + default: + break; + } + if (task) + { + break; + } + } + enumerator->destroy(enumerator); + break; case TRANSACTION: task = (task_t *)xauth_request_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 472aad8c6..10e0c224c 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -22,6 +22,7 @@ #include #include #include +#include typedef struct private_quick_mode_t private_quick_mode_t; @@ -548,9 +549,24 @@ METHOD(task_t, build_i, status_t, } } +status_t process_notify(notify_payload_t *notify) +{ + if(notify->get_notify_type(notify) < 16384) + { + DBG1(DBG_IKE, "Received %N error notification.", notify_type_names, notify->get_notify_type(notify)); + return FAILED; + } + DBG1(DBG_IKE, "Received %N notification.", notify_type_names, notify->get_notify_type(notify)); + return SUCCESS; +} + METHOD(task_t, process_r, status_t, private_quick_mode_t *this, message_t *message) { + enumerator_t *enumerator; + payload_t *payload; + status_t status; + switch (this->state) { case QM_INIT: @@ -625,6 +641,19 @@ METHOD(task_t, process_r, status_t, } case QM_NEGOTIATED: { + enumerator = message->create_payload_enumerator(message); + while(enumerator->enumerate(enumerator, &payload)) + { + if(payload->get_type(payload) == NOTIFY_V1) + { + status = process_notify((notify_payload_t *)payload); + if(status != SUCCESS) + { + return status; + } + } + } + enumerator->destroy(enumerator); if (!install(this)) { return FAILED; From 8c583c110eab8e2ed5b8853e320173847e31992c Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Sat, 3 Dec 2011 15:12:14 +0100 Subject: [PATCH 198/534] version bump to 5.0.0dr1 --- configure.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 7385570b5..743500e28 100755 --- a/configure.in +++ b/configure.in @@ -16,7 +16,7 @@ dnl =========================== dnl initialize & set some vars dnl =========================== -AC_INIT(strongSwan,4.6.1) +AC_INIT(strongSwan,5.0.0dr1) AM_INIT_AUTOMAKE(tar-ustar) AC_CONFIG_MACRO_DIR([m4/config]) PKG_PROG_PKG_CONFIG From 8a9ab2035f40a9577dd551d6a1b5d967c3328e96 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Mon, 5 Dec 2011 12:48:14 +0100 Subject: [PATCH 199/534] ID_IPV4_ADDR and ID_IPV6_ADDR cases added to get_ts --- src/libcharon/encoding/payloads/id_payload.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) mode change 100644 => 100755 src/libcharon/encoding/payloads/id_payload.c diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c old mode 100644 new mode 100755 index 96d713e46..fe8918861 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -299,6 +299,24 @@ METHOD(id_payload_t, get_ts, traffic_selector_t*, return get_ts_from_range(this, TS_IPV6_ADDR_RANGE); } break; + case ID_IPV4_ADDR: + { + if (this->id_data.len == 4) + { + return traffic_selector_create_from_bytes(this->protocol_id, + TS_IPV4_ADDR_RANGE, this->id_data, this->port, + this->id_data, this->port ?: 65535); + } + } + case ID_IPV6_ADDR: + { + if (this->id_data.len == 16) + { + return traffic_selector_create_from_bytes(this->protocol_id, + TS_IPV4_ADDR_RANGE, this->id_data, this->port, + this->id_data, this->port ?: 65535); + } + } default: break; } From e102f86e88e6c2b2e689f8fbb39ec81c6212d32a Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Mon, 5 Dec 2011 13:44:22 +0100 Subject: [PATCH 200/534] Setting transform number in esp proposal. iPhone (racoon) fails quick mode when transform number is 0 --- src/libcharon/encoding/payloads/proposal_substructure.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 src/libcharon/encoding/payloads/proposal_substructure.c diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c old mode 100644 new mode 100755 index f758d1fbe..ca36206cb --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -1235,7 +1235,7 @@ proposal_substructure_t *proposal_substructure_create_from_proposal_v1( break; case PROTO_ESP: set_from_proposal_v1_esp(this, proposal, lifetime, - lifebytes, mode, udp, 0); + lifebytes, mode, udp, proposal->get_number(proposal)); break; default: break; From a846be311627f23e202bee65dae71d5731e53967 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Mon, 5 Dec 2011 13:54:54 +0100 Subject: [PATCH 201/534] keymat: derive_ike_keys updated with XAUTH RSA:s --- src/libcharon/sa/keymat_v1.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) mode change 100644 => 100755 src/libcharon/sa/keymat_v1.c diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c old mode 100644 new mode 100755 index fc49a2030..19d6a74ce --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -426,8 +426,14 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, this->prf->allocate_bytes(this->prf, nonces, &this->skeyid); break; } - case AUTH_RSA: case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + { + this->prf->set_key(this->prf, nonces); + this->prf->allocate_bytes(this->prf, g_xy, &this->skeyid); + break; + } + case AUTH_RSA: { /* signatures : SKEYID = prf(Ni_b | Nr_b, g^xy) * pubkey encr: SKEYID = prf(hash(Ni_b | Nr_b), CKY-I | CKY-R) */ From 7d9269bfce9ab02e614b41c12178174aad2d42de Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Mon, 5 Dec 2011 14:11:48 +0100 Subject: [PATCH 202/534] certificate handling for XAuth responder. --- src/libcharon/encoding/message.c | 4 +- .../encoding/payloads/certreq_payload.c | 46 ++- .../encoding/payloads/certreq_payload.h | 23 +- src/libcharon/encoding/payloads/payload.c | 4 +- src/libcharon/sa/tasks/ike_cert_post.c | 172 +++++++- src/libcharon/sa/tasks/ike_cert_pre.c | 377 ++++++++++++++++-- 6 files changed, 572 insertions(+), 54 deletions(-) mode change 100644 => 100755 src/libcharon/encoding/message.c mode change 100644 => 100755 src/libcharon/encoding/payloads/certreq_payload.c mode change 100644 => 100755 src/libcharon/encoding/payloads/certreq_payload.h mode change 100644 => 100755 src/libcharon/encoding/payloads/payload.c mode change 100644 => 100755 src/libcharon/sa/tasks/ike_cert_post.c mode change 100644 => 100755 src/libcharon/sa/tasks/ike_cert_pre.c diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c old mode 100644 new mode 100755 index 0a808ac02..5b79ac733 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -438,7 +438,7 @@ static payload_rule_t id_prot_i_rules[] = { {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, TRUE, FALSE}, - {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, + {CERTIFICATE_V1, 0, 2, TRUE, FALSE}, {SIGNATURE_V1, 0, 1, TRUE, FALSE}, {HASH_V1, 0, 1, TRUE, FALSE}, }; @@ -474,7 +474,7 @@ static payload_rule_t id_prot_r_rules[] = { {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, TRUE, FALSE}, - {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, + {CERTIFICATE_V1, 0, 2, TRUE, FALSE}, {SIGNATURE_V1, 0, 1, TRUE, FALSE}, {HASH_V1, 0, 1, TRUE, FALSE}, }; diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c old mode 100644 new mode 100755 index 69e80ad7e..dea1f40bd --- a/src/libcharon/encoding/payloads/certreq_payload.c +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -64,6 +64,11 @@ struct private_certreq_payload_t { * The contained certreq data value. */ chunk_t data; + + /** + * Payload type for certificate request. + */ + payload_type_t payload_type; }; /** @@ -122,6 +127,13 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } +METHOD(payload_t, verify_v1, status_t, + private_certreq_payload_t *this) +{ + /*TODO: */ + return SUCCESS; +} + METHOD(payload_t, get_encoding_rules, int, private_certreq_payload_t *this, encoding_rule_t **rules) { @@ -138,7 +150,7 @@ METHOD(payload_t, get_header_length, int, METHOD(payload_t, get_type, payload_type_t, private_certreq_payload_t *this) { - return CERTIFICATE_REQUEST; + return this->payload_type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -159,6 +171,23 @@ METHOD(payload_t, get_length, size_t, return this->payload_length; } +METHOD(certreq_payload_t, get_dn, chunk_t, + private_certreq_payload_t *this) +{ + return this->data; +} + +METHOD(certreq_payload_t, set_dn, void, + private_certreq_payload_t *this, chunk_t dn) +{ + if (this->data.ptr) + { + free(this->data.ptr); + } + this->data = chunk_clone(dn); + this->payload_length = get_header_length(this) + this->data.len; +} + METHOD(certreq_payload_t, add_keyid, void, private_certreq_payload_t *this, chunk_t keyid) { @@ -238,7 +267,7 @@ METHOD2(payload_t, certreq_payload_t, destroy, void, /* * Described in header */ -certreq_payload_t *certreq_payload_create() +certreq_payload_t *certreq_payload_create(payload_type_t payload_type) { private_certreq_payload_t *this; @@ -258,19 +287,28 @@ certreq_payload_t *certreq_payload_create() .get_cert_type = _get_cert_type, .add_keyid = _add_keyid, .destroy = _destroy, + .get_dn = _get_dn, + .set_dn = _set_dn, }, .next_payload = NO_PAYLOAD, .payload_length = get_header_length(this), + .payload_type = payload_type, ); + + if (payload_type == CERTIFICATE_REQUEST_V1) + { + this->public.payload_interface.verify = _verify_v1; + } + return &this->public; } /* * Described in header */ -certreq_payload_t *certreq_payload_create_type(certificate_type_t type) +certreq_payload_t *certreq_payload_create_type(payload_type_t payload_type, certificate_type_t type) { - private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create(); + private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create(payload_type); switch (type) { diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h old mode 100644 new mode 100755 index 421ad6d58..d426da711 --- a/src/libcharon/encoding/payloads/certreq_payload.h +++ b/src/libcharon/encoding/payloads/certreq_payload.h @@ -40,7 +40,7 @@ struct certreq_payload_t { payload_t payload_interface; /** - * Create an enumerator over contained keyids. + * Create an enumerator over contained keyids (IKEv2 only). * * @return enumerator over chunk_t's. */ @@ -54,13 +54,28 @@ struct certreq_payload_t { certificate_type_t (*get_cert_type)(certreq_payload_t *this); /** - * Add a certificates keyid to the payload. + * Add a certificates keyid to the payload (IKEv2 only). * * @param keyid keyid of the trusted certifcate * @return */ void (*add_keyid)(certreq_payload_t *this, chunk_t keyid); + /** + * Get certificate request data (IKEv1 only). + * + * @return certifcate request data + */ + chunk_t (*get_dn)(certreq_payload_t *this); + + /** + * Set certificate request data (IKEv1 only). + * + * @param dn certifcate request data to set + * @return + */ + void (*set_dn)(certreq_payload_t *this, chunk_t dn); + /** * Destroys an certreq_payload_t object. */ @@ -72,7 +87,7 @@ struct certreq_payload_t { * * @return certreq payload */ -certreq_payload_t *certreq_payload_create(void); +certreq_payload_t *certreq_payload_create(payload_type_t payload_type); /** * Creates an empty certreq_payload_t for a kind of certificates. @@ -80,6 +95,6 @@ certreq_payload_t *certreq_payload_create(void); * @param type type of the added keyids * @return certreq payload */ -certreq_payload_t *certreq_payload_create_type(certificate_type_t type); +certreq_payload_t *certreq_payload_create_type(payload_type_t payload_type, certificate_type_t type); #endif /** CERTREQ_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c old mode 100644 new mode 100755 index baa838715..257d53858 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -213,7 +213,8 @@ payload_t *payload_create(payload_type_t type) case CERTIFICATE_V1: return (payload_t*)cert_payload_create(type); case CERTIFICATE_REQUEST: - return (payload_t*)certreq_payload_create(); + case CERTIFICATE_REQUEST_V1: + return (payload_t*)certreq_payload_create(type); case TRAFFIC_SELECTOR_SUBSTRUCTURE: return (payload_t*)traffic_selector_substructure_create(); case TRAFFIC_SELECTOR_INITIATOR: @@ -233,6 +234,7 @@ payload_t *payload_create(payload_type_t type) case VENDOR_ID_V1: return (payload_t*)vendor_id_payload_create(type); case HASH_V1: + case SIGNATURE_V1: case NAT_D_V1: return (payload_t*)hash_payload_create(type); case CONFIGURATION: diff --git a/src/libcharon/sa/tasks/ike_cert_post.c b/src/libcharon/sa/tasks/ike_cert_post.c old mode 100644 new mode 100755 index ba5d76baa..358a067c9 --- a/src/libcharon/sa/tasks/ike_cert_post.c +++ b/src/libcharon/sa/tasks/ike_cert_post.c @@ -21,6 +21,7 @@ #include #include #include +#include #include @@ -45,6 +46,20 @@ struct private_ike_cert_post_t { * Are we the initiator? */ bool initiator; + + /** + * Certificate payload type that we are handling + */ + payload_type_t payload_type; + + /** + * States of ike cert pre + */ + enum { + CP_INIT, + CP_SA, + CP_SA_POST, + } state; }; /** @@ -62,14 +77,14 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL)) { - return cert_payload_create_from_cert(cert, CERTIFICATE); + return cert_payload_create_from_cert(cert, this->payload_type); } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!hasher) { DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported"); - return cert_payload_create_from_cert(cert, CERTIFICATE); + return cert_payload_create_from_cert(cert, this->payload_type); } if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded)) @@ -86,12 +101,12 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr, CERT_X509, id); if (enumerator->enumerate(enumerator, &url)) { - payload = cert_payload_create_from_hash_and_url(hash, url, CERTIFICATE); + payload = cert_payload_create_from_hash_and_url(hash, url, this->payload_type); DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url); } else { - payload = cert_payload_create_from_cert(cert, CERTIFICATE); + payload = cert_payload_create_from_cert(cert, this->payload_type); } enumerator->destroy(enumerator); chunk_free(&hash); @@ -99,21 +114,74 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, return payload; } +/** + * Checks for the auth_method to see if this task should handle certificates. + * (IKEv1 only) + */ +static status_t check_auth_method(private_ike_cert_post_t *this, + message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + status_t status = SUCCESS; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) + { + sa_payload_t *sa_payload = (sa_payload_t*)payload; + + switch (sa_payload->get_auth_method(sa_payload)) + { + case AUTH_RSA: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + DBG3(DBG_IKE, "handling certs method (%d)", + sa_payload->get_auth_method(sa_payload)); + status = NEED_MORE; + break; + default: + DBG3(DBG_IKE, "not handling certs method (%d)", + sa_payload->get_auth_method(sa_payload)); + status = SUCCESS; + break; + } + + this->state = CP_SA; + break; + } + } + enumerator->destroy(enumerator); + + return status; +} + /** * add certificates to message */ static void build_certs(private_ike_cert_post_t *this, message_t *message) { peer_cfg_t *peer_cfg; - auth_payload_t *payload; - payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (!peer_cfg || !payload || payload->get_auth_method(payload) == AUTH_PSK) - { /* no CERT payload for EAP/PSK */ + + if (!peer_cfg) + { return; } + if (this->payload_type == CERTIFICATE) + { + auth_payload_t *payload; + payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); + + if (!payload || payload->get_auth_method(payload) == AUTH_PSK) + { /* no CERT payload for EAP/PSK */ + return; + } + } + switch (peer_cfg->get_cert_policy(peer_cfg)) { case CERT_NEVER_SEND: @@ -154,7 +222,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) { if (type == AUTH_RULE_IM_CERT) { - payload = cert_payload_create_from_cert(cert, CERTIFICATE); + payload = cert_payload_create_from_cert(cert, this->payload_type); if (payload) { DBG1(DBG_IKE, "sending issuer cert \"%Y\"", @@ -166,6 +234,8 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) enumerator->destroy(enumerator); } } + + return; } METHOD(task_t, build_i, status_t, @@ -176,6 +246,14 @@ METHOD(task_t, build_i, status_t, return NEED_MORE; } +METHOD(task_t, build_i_v1, status_t, + private_ike_cert_post_t *this, message_t *message) +{ + /* TODO:*/ + + return FAILED; +} + METHOD(task_t, process_r, status_t, private_ike_cert_post_t *this, message_t *message) { @@ -194,6 +272,52 @@ METHOD(task_t, build_r, status_t, return SUCCESS; } +METHOD(task_t, build_r_v1, status_t, + private_ike_cert_post_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CP_INIT: + this->state = CP_SA; + return check_auth_method(this, message); + break; + + case CP_SA: + this->state = CP_SA_POST; + build_certs(this, message); + break; + + case CP_SA_POST: + build_certs(this, message); + return SUCCESS; + } + break; + } + case AGGRESSIVE: + { + if (check_auth_method(this, message) == NEED_MORE) + { + build_certs(this, message); + } + return SUCCESS; + break; + } + default: + break; + } + + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { + return NEED_MORE; + } + + return SUCCESS; +} + METHOD(task_t, process_i, status_t, private_ike_cert_post_t *this, message_t *message) { @@ -241,17 +365,43 @@ ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator) .initiator = initiator, ); + if (initiator) { - this->public.task.build = _build_i; this->public.task.process = _process_i; } else { - this->public.task.build = _build_r; this->public.task.process = _process_r; } + if (ike_sa->get_version(ike_sa) == IKEV2) + { + this->payload_type = CERTIFICATE; + + if (initiator) + { + this->public.task.build = _build_i; + } + else + { + this->public.task.build = _build_r; + } + } + else + { + this->payload_type = CERTIFICATE_V1; + + if (initiator) + { + this->public.task.build = _build_i_v1; + } + else + { + this->public.task.build = _build_r_v1; + } + } + return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_cert_pre.c b/src/libcharon/sa/tasks/ike_cert_pre.c old mode 100644 new mode 100755 index 0de2efd38..0bdbea5e1 --- a/src/libcharon/sa/tasks/ike_cert_pre.c +++ b/src/libcharon/sa/tasks/ike_cert_pre.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -54,8 +55,58 @@ struct private_ike_cert_pre_t { * wheter this is the final authentication round */ bool final; + + /** states of ike cert pre */ + enum { + CP_INIT, + CP_SA, + CP_SA_POST, + CP_REQ_SENT, + CP_NO_CERT, + } state; + + /** + * type of certicate request to send + */ + payload_type_t cert_req_payload_type; }; +/** + * add certificate to auth + */ +static bool add_certificate(auth_cfg_t *auth, chunk_t keyid, id_type_t id_type ) +{ + identification_t *id = NULL; + certificate_t *cert; + bool status = TRUE; + + id = identification_create_from_encoding(id_type, keyid); + + if (!id) + { + return FALSE; + } + + cert = lib->credmgr->get_cert(lib->credmgr, + CERT_X509, KEY_ANY, id, TRUE); + if (cert) + { + DBG1(DBG_IKE, "received cert request for \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_RULE_CA_CERT, cert); + } + else + { + DBG2(DBG_IKE, "received cert request for unknown ca " + "with keyid %Y", id); + status = FALSE; + } + + id->destroy(id); + + return status; +} + /** * read certificate requests */ @@ -73,6 +124,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) switch (payload->get_type(payload)) { case CERTIFICATE_REQUEST: + case CERTIFICATE_REQUEST_V1: { certreq_payload_t *certreq = (certreq_payload_t*)payload; enumerator_t *enumerator; @@ -87,30 +139,31 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) 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_KEY_ID, keyid); - cert = lib->credmgr->get_cert(lib->credmgr, - CERT_X509, KEY_ANY, id, TRUE); - if (cert) + if (payload->get_type(payload) == CERTIFICATE_REQUEST) + { + enumerator = certreq->create_keyid_enumerator(certreq); + while (enumerator->enumerate(enumerator, &keyid)) { - DBG1(DBG_IKE, "received cert request for \"%Y\"", - cert->get_subject(cert)); - auth->add(auth, AUTH_RULE_CA_CERT, cert); + if (!add_certificate(auth, keyid, ID_KEY_ID)) + { + unknown++; + } } - else + enumerator->destroy(enumerator); + } + else + { + keyid = certreq->get_dn(certreq); + + /* In case client (iPhone) is sending empty cert requests */ + if (!keyid.ptr || !keyid.len || + !add_certificate(auth, keyid, ID_DER_ASN1_DN)) { - DBG2(DBG_IKE, "received cert request for unknown ca " - "with keyid %Y", id); unknown++; } - id->destroy(id); } - enumerator->destroy(enumerator); + if (unknown) { DBG1(DBG_IKE, "received %u cert requests for an unknown ca", @@ -191,7 +244,8 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message) enumerator = message->create_payload_enumerator(message); while (enumerator->enumerate(enumerator, &payload)) { - if (payload->get_type(payload) == CERTIFICATE) + if (payload->get_type(payload) == CERTIFICATE || + payload->get_type(payload) == CERTIFICATE_V1) { cert_payload_t *cert_payload; cert_encoding_t encoding; @@ -291,7 +345,8 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message) /** * add the keyid of a certificate to the certificate request payload */ -static void add_certreq(certreq_payload_t **req, certificate_t *cert) +static void add_certreq(private_ike_cert_pre_t *this, + certreq_payload_t **req, certificate_t *cert) { switch (cert->get_type(cert)) { @@ -310,15 +365,30 @@ static void add_certreq(certreq_payload_t **req, certificate_t *cert) { break; } + if (*req == NULL) { - *req = certreq_payload_create_type(CERT_X509); + *req = certreq_payload_create_type(this->cert_req_payload_type, CERT_X509); } - if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) + + if (this->cert_req_payload_type == CERTIFICATE_REQUEST) { - (*req)->add_keyid(*req, keyid); + if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) + { + (*req)->add_keyid(*req, keyid); + DBG1(DBG_IKE, "sending cert request for \"%Y\"", + cert->get_subject(cert)); + } + } + else + { + identification_t *id; + id = cert->get_subject(cert); + + (*req)->set_dn(*req, id->get_encoding(id)); DBG1(DBG_IKE, "sending cert request for \"%Y\"", - cert->get_subject(cert)); + cert->get_subject(cert)); + } public->destroy(public); break; @@ -331,7 +401,8 @@ static void add_certreq(certreq_payload_t **req, certificate_t *cert) /** * add a auth_cfg's CA certificates to the certificate request */ -static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth) +static void add_certreqs(private_ike_cert_pre_t *this, + certreq_payload_t **req, auth_cfg_t *auth) { enumerator_t *enumerator; auth_rule_t type; @@ -343,7 +414,37 @@ static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth) switch (type) { case AUTH_RULE_CA_CERT: - add_certreq(req, (certificate_t*)value); + add_certreq(this, req, (certificate_t*)value); + break; + default: + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * add a auth_cfg's CA certificates to the certificate request + */ +static void add_certreqs_v1(private_ike_cert_pre_t *this, + certreq_payload_t **req, + auth_cfg_t *auth, message_t *message) +{ + enumerator_t *enumerator; + auth_rule_t type; + void *value; + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &value)) + { + switch (type) + { + case AUTH_RULE_CA_CERT: + add_certreq(this, req, (certificate_t*)value); + if (req) + { + message->add_payload(message,(payload_t*)req); + } break; default: break; @@ -377,7 +478,7 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); while (enumerator->enumerate(enumerator, &auth)) { - add_certreqs(&req, auth); + add_certreqs(this, &req, auth); } enumerator->destroy(enumerator); } @@ -389,7 +490,7 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) CERT_ANY, KEY_ANY, NULL, TRUE); while (enumerator->enumerate(enumerator, &cert)) { - add_certreq(&req, cert); + add_certreq(this, &req, cert); } enumerator->destroy(enumerator); } @@ -407,6 +508,58 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) } } +/** + * build certificate requests + */ +static void build_certreqs_v1(private_ike_cert_pre_t *this, message_t *message) +{ + enumerator_t *enumerator; + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + certificate_t *cert; + auth_cfg_t *auth; + certreq_payload_t *req = NULL; + + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + if (!ike_cfg->send_certreq(ike_cfg)) + { + return; + } + + /* check if we require a specific CA for that peer */ + /* Get the first authentcation config from peer config */ + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg) + { + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); + if (enumerator->enumerate(enumerator, &auth)) + { + add_certreqs_v1(this, &req, auth, message); + if (req) + { + message->add_payload(message, (payload_t*)req); + } + } + enumerator->destroy(enumerator); + } + + if (!req) + { + /* otherwise add all trusted CA certificates */ + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + CERT_ANY, KEY_ANY, NULL, TRUE); + while (enumerator->enumerate(enumerator, &cert)) + { + add_certreq(this, &req, cert); + if (req) + { + message->add_payload(message, (payload_t*)req); + } + } + enumerator->destroy(enumerator); + } +} + /** * Check if this is the final authentication round */ @@ -424,6 +577,55 @@ static bool final_auth(message_t *message) return TRUE; } +/** + * Checks for the auth_method to see if this task should handle certificates. + * (IKEv1 only) + */ +static status_t check_auth_method(private_ike_cert_pre_t *this, + message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + status_t status = SUCCESS; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) + { + sa_payload_t *sa_payload = (sa_payload_t*)payload; + + switch (sa_payload->get_auth_method(sa_payload)) + { + case AUTH_RSA: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + DBG3(DBG_IKE, "handling certs method (%d)", + sa_payload->get_auth_method(sa_payload)); + status = NEED_MORE; + break; + default: + DBG3(DBG_IKE, "not handling certs method (%d)", + sa_payload->get_auth_method(sa_payload)); + status = SUCCESS; + break; + } + + this->state = CP_SA; + break; + } + } + enumerator->destroy(enumerator); + + if (status != NEED_MORE) + { + this->state = CP_NO_CERT; + this->final = TRUE; + } + + return status; +} + METHOD(task_t, build_i, status_t, private_ike_cert_pre_t *this, message_t *message) { @@ -476,6 +678,97 @@ METHOD(task_t, process_i, status_t, return NEED_MORE; } +METHOD(task_t, process_r_v1, status_t, + private_ike_cert_pre_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CP_INIT: + check_auth_method(this, message); + break; + case CP_SA: + process_certreqs(this, message); + this->state = CP_SA_POST; + break; + case CP_SA_POST: + process_certreqs(this, message); + process_certs(this, message); + this->state = CP_REQ_SENT; + this->final = TRUE; + break; + default: + break; + } + break; + } + case AGGRESSIVE: + { + if (check_auth_method(this, message) == NEED_MORE) + { + process_certreqs(this, message); + process_certs(this, message); + } + this->final = TRUE; + break; + } + default: + break; + } + + return NEED_MORE; +} + +METHOD(task_t, process_i_v1, status_t, + private_ike_cert_pre_t *this, message_t *message) +{ + /* TODO: */ + return FAILED; +} + +METHOD(task_t, build_r_v1, status_t, + private_ike_cert_pre_t *this, message_t *message) +{ + + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + if (this->state == CP_SA_POST) + { + build_certreqs_v1(this, message); + } + break; + } + case AGGRESSIVE: + { + if (this->state != CP_NO_CERT) + { + build_certreqs_v1(this, message); + } + } + default: + break; + + } + + if (this->final) + { + return SUCCESS; + } + return NEED_MORE; +} + +METHOD(task_t, build_i_v1, status_t, + private_ike_cert_pre_t *this, message_t *message) +{ + /* TODO: */ + return FAILED; +} + METHOD(task_t, get_type, task_type_t, private_ike_cert_pre_t *this) { @@ -513,15 +806,35 @@ ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator) .initiator = initiator, ); - if (initiator) + if (ike_sa->get_version(ike_sa) == IKEV2) { - this->public.task.build = _build_i; - this->public.task.process = _process_i; + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + this->cert_req_payload_type = CERTIFICATE_REQUEST; } else { - this->public.task.build = _build_r; - this->public.task.process = _process_r; + this->state = CP_INIT; + if (initiator) + { + this->public.task.build = _build_i_v1; + this->public.task.process = _process_i_v1; + } + else + { + this->public.task.build = _build_r_v1; + this->public.task.process = _process_r_v1; + } + this->cert_req_payload_type = CERTIFICATE_REQUEST_V1; + } return &this->public; From 8ad5cd1f6cca7f7480398895dd2625f2c21ba029 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Mon, 5 Dec 2011 14:17:17 +0100 Subject: [PATCH 203/534] certificate tasks added to passive list for responder --- src/libcharon/sa/task_manager_v1.c | 6 ++++++ 1 file changed, 6 insertions(+) mode change 100644 => 100755 src/libcharon/sa/task_manager_v1.c diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c old mode 100644 new mode 100755 index 86b25e456..c08f70be8 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -499,10 +501,14 @@ static status_t process_request(private_task_manager_t *this, case ID_PROT: task = (task_t *)ike_vendor_v1_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)ike_natd_v1_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); break; case AGGRESSIVE: /* TODO-IKEv1: agressive mode */ From a874a1f50bc30c1e52c92d5534337b12f8cab477 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Mon, 5 Dec 2011 14:22:11 +0100 Subject: [PATCH 204/534] signature payload handling. --- src/libcharon/sa/tasks/main_mode.c | 198 +++++++++++++++++++++++++++-- 1 file changed, 188 insertions(+), 10 deletions(-) mode change 100644 => 100755 src/libcharon/sa/tasks/main_mode.c diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c old mode 100644 new mode 100755 index 4d4ca340a..f895117dc --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -180,9 +180,65 @@ static bool save_sa_payload(private_main_mode_t *this, message_t *message) } /** - * Build main mode hash payloads + * Add signature payload to message */ -static void build_hash(private_main_mode_t *this, bool initiator, +static bool add_signature(private_main_mode_t *this, + message_t *message, chunk_t hash) +{ + chunk_t auth_data; + bool status = FALSE; + private_key_t *private; + identification_t *id; + auth_cfg_t *auth; + hash_payload_t *signature_payload; + signature_scheme_t scheme; + + id = this->ike_sa->get_my_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, auth); + if (private == NULL) + { + DBG1(DBG_IKE, "no private key found for '%Y' type %d", id, id->get_type(id)); + free(hash.ptr); + return FALSE; + } + + switch (private->get_type(private)) + { + case KEY_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_NULL; + break; + + default: + DBG1(DBG_IKE, "private key of type %N not supported", + key_type_names, private->get_type(private)); + private->destroy(private); + free(hash.ptr); + return FALSE; + } + + if (private->sign(private, scheme, hash, &auth_data)) + { + signature_payload = hash_payload_create(SIGNATURE_V1); + signature_payload->set_hash(signature_payload, auth_data); + chunk_free(&auth_data); + message->add_payload(message, (payload_t*)signature_payload); + status = TRUE; + } + + DBG1(DBG_IKE, "authentication of '%Y' (myself) %s", id, + (status == TRUE)? "successful":"failed"); + + free(hash.ptr); + private->destroy(private); + return status; +} + + +/** + * Build main mode hash or signature payloads + */ +static bool build_hash(private_main_mode_t *this, bool initiator, message_t *message, identification_t *id) { hash_payload_t *hash_payload; @@ -193,11 +249,25 @@ static void build_hash(private_main_mode_t *this, bool initiator, this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); free(dh.ptr); - hash_payload = hash_payload_create(HASH_V1); - hash_payload->set_hash(hash_payload, hash); - free(hash.ptr); + switch (this->auth_method) + { + case AUTH_RSA: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + { + return add_signature(this, message, hash); + } + default: + { + hash_payload = hash_payload_create(HASH_V1); + hash_payload->set_hash(hash_payload, hash); + message->add_payload(message, &hash_payload->payload_interface); + free(hash.ptr); + break; + } + } - message->add_payload(message, &hash_payload->payload_interface); + return TRUE; } /** @@ -231,6 +301,84 @@ static bool verify_hash(private_main_mode_t *this, bool initiator, return equal; } +/** + * Verify main mode signature payload + */ +static bool verify_signature(private_main_mode_t *this, bool initiator, + message_t *message, identification_t *id) +{ + chunk_t hash, dh; + public_key_t *public; + hash_payload_t *signature_payload; + auth_method_t auth_method; + chunk_t auth_data; + auth_cfg_t *auth, *current_auth; + enumerator_t *enumerator; + key_type_t key_type = KEY_ECDSA; + signature_scheme_t scheme; + status_t status = NOT_FOUND; + + signature_payload = (hash_payload_t*)message->get_payload(message, SIGNATURE_V1); + if (!signature_payload) + { + DBG1(DBG_IKE, "no signature_payload found"); + return FALSE; + } + + auth_method = this->auth_method; + + switch (auth_method) + { + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + key_type = KEY_RSA; + scheme = SIGN_RSA_EMSA_PKCS1_NULL; + break; + + default: + DBG1(DBG_IKE, "unsupported auth_method (%d)",auth_method); + return FALSE; + } + + this->dh->get_my_public_value(this->dh, &dh); + hash = this->keymat->get_hash(this->keymat, initiator, this->dh_value, dh, + this->ike_sa->get_id(this->ike_sa), + this->sa_payload, id); + free(dh.ptr); + + auth_data = signature_payload->get_hash(signature_payload); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, + key_type, id, auth); + while (enumerator->enumerate(enumerator, &public, ¤t_auth)) + { + if (public->verify(public, scheme, hash, auth_data)) + { + DBG1(DBG_IKE, "authentication of '%Y' with %N successful", + id, auth_method_names, auth_method); + status = SUCCESS; + auth->merge(auth, current_auth, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + break; + } + else + { + status = NOT_FOUND; + DBG1(DBG_IKE, "signature validation failed, looking for another key"); + } + } + enumerator->destroy(enumerator); + if (status == NOT_FOUND) + { + DBG1(DBG_IKE, "no trusted %N public key found for '%Y'", + key_type_names, key_type, id); + } + + free(hash.ptr); + return status == SUCCESS; +} + + /** * Generate and add NONCE, KE payload */ @@ -417,7 +565,11 @@ METHOD(task_t, build_i, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - build_hash(this, TRUE, message, id); + if (!build_hash(this, TRUE, message, id)) + { + DBG1(DBG_CFG, "failed to build hash"); + return FAILED; + } this->state = MM_AUTH; return NEED_MORE; @@ -541,9 +693,31 @@ METHOD(task_t, process_r, status_t, return FAILED; } - if (!verify_hash(this, TRUE, message, id)) + switch (this->auth_method) { - return FAILED; + case AUTH_PSK: + case AUTH_XAUTH_INIT_PSK: + if (!verify_hash(this, TRUE, message, id)) + { + return FAILED; + } + break; + + case AUTH_XAUTH_RESP_RSA: + case AUTH_XAUTH_INIT_RSA: + case AUTH_RSA: + { + if (!verify_signature(this, TRUE, message, id)) + { + return FAILED; + } + break; + } + + default: + DBG1(DBG_IKE, "unknown auth_method:%d",get_auth_method(this)); + return FAILED; + break; } this->state = MM_AUTH; @@ -659,7 +833,11 @@ METHOD(task_t, build_r, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - build_hash(this, FALSE, message, id); + if (!build_hash(this, FALSE, message, id)) + { + DBG1(DBG_CFG, "failed to build hash"); + return FAILED; + } DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), From d82a68642dc3afae761d6da8a38f063b78a161f9 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Mon, 5 Dec 2011 14:27:53 +0100 Subject: [PATCH 205/534] XAUTH additions for certificates. --- src/libcharon/sa/tasks/xauth_request.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) mode change 100644 => 100755 src/libcharon/sa/tasks/xauth_request.c diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c old mode 100644 new mode 100755 index 7da5bf9e1..dbce6e514 --- a/src/libcharon/sa/tasks/xauth_request.c +++ b/src/libcharon/sa/tasks/xauth_request.c @@ -127,7 +127,7 @@ static auth_cfg_t *get_auth_cfg(private_xauth_request_t *this, bool local) /** * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip */ -static configuration_attribute_t *build_vip(host_t *vip) +static configuration_attribute_t *build_vip(payload_type_t ca_type, host_t *vip) { configuration_attribute_type_t type; chunk_t chunk, prefix; @@ -159,7 +159,7 @@ static configuration_attribute_t *build_vip(host_t *vip) chunk = chunk_cata("cc", chunk, prefix); } } - return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE, + return configuration_attribute_create_chunk(ca_type, type, chunk); } @@ -431,7 +431,7 @@ METHOD(task_t, build_i, status_t, if (vip) { cp = cp_payload_create_type(cp_type, CFG_REQUEST); - cp->add_attribute(cp, build_vip(vip)); + cp->add_attribute(cp, build_vip(ca_type, vip)); } enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes, @@ -489,16 +489,25 @@ METHOD(task_t, process_r, status_t, { this->auth_cfg = get_auth_cfg(this, TRUE); } + switch((uintptr_t)this->auth_cfg->get(this->auth_cfg, AUTH_RULE_AUTH_CLASS)) { case AUTH_CLASS_XAUTH_PSK: case AUTH_CLASS_XAUTH_PUBKEY: - this->state = TASK_XAUTH_INIT; + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + this->state = TASK_XAUTH_COMPLETE; + } + else + { + this->state = TASK_XAUTH_INIT; + } break; default: /* We aren't XAuth, so do we should expect ConfigMode stuff */ this->state = TASK_XAUTH_COMPLETE; } + if((this->xauth_authenticator == NULL) && (this->state == TASK_XAUTH_INIT)) { this->xauth_authenticator = (authenticator_t *)xauth_authenticator_create_builder(this->ike_sa); @@ -556,6 +565,7 @@ METHOD(task_t, build_r, status_t, case AUTH_CLASS_XAUTH_PUBKEY: break; default: + this->state = TASK_XAUTH_COMPLETE; return SUCCESS; } @@ -600,7 +610,7 @@ METHOD(task_t, build_r, status_t, this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip); cp = cp_payload_create_type(cp_type, CFG_REPLY); - cp->add_attribute(cp, build_vip(vip)); + cp->add_attribute(cp, build_vip(ca_type, vip)); } /* query registered providers for additional attributes to include */ @@ -640,6 +650,7 @@ METHOD(task_t, process_i, status_t, private_xauth_request_t *this, message_t *message) { status_t status; + if (((this->ike_sa->get_version(this->ike_sa) == IKEV2) && (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)) || (this->ike_sa->get_version(this->ike_sa) == IKEV1)) @@ -694,7 +705,7 @@ METHOD(task_t, destroy, void, { DESTROY_IF(this->virtual_ip); this->requested->destroy_function(this->requested, free); - this->xauth_authenticator->destroy(this->xauth_authenticator); + DESTROY_IF(this->xauth_authenticator); free(this); } From cd419ae4466b458681c2d2547e683cef02beb553 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Thu, 27 Oct 2011 00:37:24 +0200 Subject: [PATCH 206/534] extended bio_reader and bio_writer to handle u_int64_t --- src/libstrongswan/bio/bio_reader.c | 15 +++++++++++ src/libstrongswan/bio/bio_reader.h | 8 ++++++ src/libstrongswan/bio/bio_writer.c | 12 +++++++++ src/libstrongswan/bio/bio_writer.h | 7 +++++ src/libstrongswan/utils.h | 42 ++++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+) diff --git a/src/libstrongswan/bio/bio_reader.c b/src/libstrongswan/bio/bio_reader.c index d0478879f..fce0d1aef 100644 --- a/src/libstrongswan/bio/bio_reader.c +++ b/src/libstrongswan/bio/bio_reader.c @@ -103,6 +103,20 @@ METHOD(bio_reader_t, read_uint32, bool, return TRUE; } +METHOD(bio_reader_t, read_uint64, bool, + private_bio_reader_t *this, u_int64_t *res) +{ + if (this->buf.len < 8) + { + DBG1(DBG_LIB, "%d bytes insufficient to parse u_int64 data", + this->buf.len); + return FALSE; + } + *res = untoh64(this->buf.ptr); + this->buf = chunk_skip(this->buf, 8); + return TRUE; +} + METHOD(bio_reader_t, read_data, bool, private_bio_reader_t *this, u_int32_t len, chunk_t *res) { @@ -186,6 +200,7 @@ bio_reader_t *bio_reader_create(chunk_t data) .read_uint16 = _read_uint16, .read_uint24 = _read_uint24, .read_uint32 = _read_uint32, + .read_uint64 = _read_uint64, .read_data = _read_data, .read_data8 = _read_data8, .read_data16 = _read_data16, diff --git a/src/libstrongswan/bio/bio_reader.h b/src/libstrongswan/bio/bio_reader.h index c6eba36be..85434a784 100644 --- a/src/libstrongswan/bio/bio_reader.h +++ b/src/libstrongswan/bio/bio_reader.h @@ -76,6 +76,14 @@ struct bio_reader_t { */ bool (*read_uint32)(bio_reader_t *this, u_int32_t *res); + /** + * Read a 64-bit integer from the buffer, advance. + * + * @param res pointer to result + * @return TRUE if integer read successfully + */ + bool (*read_uint64)(bio_reader_t *this, u_int64_t *res); + /** * Read a chunk of len bytes, advance. * diff --git a/src/libstrongswan/bio/bio_writer.c b/src/libstrongswan/bio/bio_writer.c index a5df5ba0c..bf373d6ac 100644 --- a/src/libstrongswan/bio/bio_writer.c +++ b/src/libstrongswan/bio/bio_writer.c @@ -97,6 +97,17 @@ METHOD(bio_writer_t, write_uint32, void, this->used += 4; } +METHOD(bio_writer_t, write_uint64, void, + private_bio_writer_t *this, u_int64_t value) +{ + if (this->used + 8 > this->buf.len) + { + increase(this); + } + htoun64(this->buf.ptr + this->used, value); + this->used += 8; +} + METHOD(bio_writer_t, write_data, void, private_bio_writer_t *this, chunk_t value) { @@ -214,6 +225,7 @@ bio_writer_t *bio_writer_create(u_int32_t bufsize) .write_uint16 = _write_uint16, .write_uint24 = _write_uint24, .write_uint32 = _write_uint32, + .write_uint64 = _write_uint64, .write_data = _write_data, .write_data8 = _write_data8, .write_data16 = _write_data16, diff --git a/src/libstrongswan/bio/bio_writer.h b/src/libstrongswan/bio/bio_writer.h index 4789aaded..0b50f7882 100644 --- a/src/libstrongswan/bio/bio_writer.h +++ b/src/libstrongswan/bio/bio_writer.h @@ -58,6 +58,13 @@ struct bio_writer_t { */ void (*write_uint32)(bio_writer_t *this, u_int32_t value); + /** + * Append a 64-bit integer to the buffer. + * + * @param value value to append + */ + void (*write_uint64)(bio_writer_t *this, u_int64_t value); + /** * Append a chunk of data without a length header. * diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h index 0f06fec6a..5154a0f7f 100644 --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -482,6 +482,27 @@ static inline void htoun32(void *network, u_int32_t host) memcpy((char*)unaligned, &host, sizeof(host)); } +/** + * Write a 64-bit host order value in network order to an unaligned address. + * + * @param host host order 32-bit value + * @param network unaligned address to write network order value to + */ +static inline void htoun64(void *network, u_int64_t host) +{ + char *unaligned = (char*)network; + u_int32_t high_part, low_part; + + high_part = host >> 32; + high_part = htonl(high_part); + low_part = host & 0xFFFFFFFFLL; + low_part = htonl(low_part); + + memcpy(unaligned, &high_part, sizeof(high_part)); + unaligned += sizeof(high_part); + memcpy(unaligned, &low_part, sizeof(low_part)); +} + /** * Read a 16-bit value in network order from an unaligned address to host order. * @@ -512,6 +533,27 @@ static inline u_int32_t untoh32(void *network) return ntohl(tmp); } +/** + * Read a 64-bit value in network order from an unaligned address to host order. + * + * @param network unaligned address to read network order value from + * @return host order value + */ +static inline u_int64_t untoh64(void *network) +{ + char *unaligned = (char*)network; + u_int32_t high_part, low_part; + + memcpy(&high_part, unaligned, sizeof(high_part)); + unaligned += sizeof(high_part); + memcpy(&low_part, unaligned, sizeof(low_part)); + + high_part = ntohl(high_part); + low_part = ntohl(low_part); + + return (((u_int64_t)high_part) << 32) + low_part; +} + /** * Special type to count references */ From 65840cc4626673c477b9bdd198f06421b7137e98 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Sun, 4 Dec 2011 12:53:47 +0100 Subject: [PATCH 207/534] fixed copy-and-paste error --- src/libstrongswan/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h index 5154a0f7f..3014e2f60 100644 --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -485,7 +485,7 @@ static inline void htoun32(void *network, u_int32_t host) /** * Write a 64-bit host order value in network order to an unaligned address. * - * @param host host order 32-bit value + * @param host host order 64-bit value * @param network unaligned address to write network order value to */ static inline void htoun64(void *network, u_int64_t host) From f4e25e602b44a98d581f4da2daa61c13aa06ad9a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 5 Dec 2011 15:44:51 +0100 Subject: [PATCH 208/534] Implement htoun/untoh64 with potentially faster htobe64/be64toh macros, if available --- src/libstrongswan/utils.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h index 3014e2f60..e5e4a10c0 100644 --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -491,6 +491,11 @@ static inline void htoun32(void *network, u_int32_t host) static inline void htoun64(void *network, u_int64_t host) { char *unaligned = (char*)network; + +#ifdef be64toh + host = htobe64(host); + memcpy((char*)unaligned, &host, sizeof(host)); +#else u_int32_t high_part, low_part; high_part = host >> 32; @@ -501,6 +506,7 @@ static inline void htoun64(void *network, u_int64_t host) memcpy(unaligned, &high_part, sizeof(high_part)); unaligned += sizeof(high_part); memcpy(unaligned, &low_part, sizeof(low_part)); +#endif } /** @@ -542,6 +548,13 @@ static inline u_int32_t untoh32(void *network) static inline u_int64_t untoh64(void *network) { char *unaligned = (char*)network; + +#ifdef be64toh + u_int64_t tmp; + + memcpy(&tmp, unaligned, sizeof(tmp)); + return be64toh(tmp); +#else u_int32_t high_part, low_part; memcpy(&high_part, unaligned, sizeof(high_part)); @@ -552,6 +565,7 @@ static inline u_int64_t untoh64(void *network) low_part = ntohl(low_part); return (((u_int64_t)high_part) << 32) + low_part; +#endif } /** From bd8700f0553e23f9301e1d13e2a21166dde65a88 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 5 Dec 2011 15:45:01 +0100 Subject: [PATCH 209/534] Don't use unportable htobe64 macro directly --- src/libcharon/encoding/payloads/transform_attribute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 50b5b77cc..6a6451eb2 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -272,7 +272,7 @@ transform_attribute_t *transform_attribute_create_value(payload_type_t type, } else { - value = htobe64(value); + htoun64(&value, value); this->attribute_value = chunk_clone(chunk_from_thing(value)); this->attribute_length_or_value = sizeof(value); } From caa6f772c817cffce3ee5128a9e675bb873a5c73 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 5 Dec 2011 16:14:52 +0100 Subject: [PATCH 210/534] Added missing break;s when converting ID_IP_ADDRESS types to ts, extracted function --- src/libcharon/encoding/payloads/id_payload.c | 24 ++++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index fe8918861..2d27021a3 100755 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -270,6 +270,16 @@ static traffic_selector_t *get_ts_from_subnet(private_id_payload_t *this, net, this->port, netmask, this->port ?: 65535); } +/** + * Create a traffic selector from an IP ID + */ +static traffic_selector_t *get_ts_from_ip(private_id_payload_t *this, + ts_type_t type) +{ + return traffic_selector_create_from_bytes(this->protocol_id, type, + this->id_data, this->port, this->id_data, this->port ?: 65535); +} + METHOD(id_payload_t, get_ts, traffic_selector_t*, private_id_payload_t *this) { @@ -300,23 +310,17 @@ METHOD(id_payload_t, get_ts, traffic_selector_t*, } break; case ID_IPV4_ADDR: - { if (this->id_data.len == 4) { - return traffic_selector_create_from_bytes(this->protocol_id, - TS_IPV4_ADDR_RANGE, this->id_data, this->port, - this->id_data, this->port ?: 65535); + return get_ts_from_ip(this, TS_IPV4_ADDR_RANGE); } - } + break; case ID_IPV6_ADDR: - { if (this->id_data.len == 16) { - return traffic_selector_create_from_bytes(this->protocol_id, - TS_IPV4_ADDR_RANGE, this->id_data, this->port, - this->id_data, this->port ?: 65535); + return get_ts_from_ip(this, TS_IPV6_ADDR_RANGE); } - } + break; default: break; } From 695aff41f5680b4c892005ea501b645c08d2fb2e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 5 Dec 2011 16:20:56 +0100 Subject: [PATCH 211/534] Encode a single IP traffic selector as ID_IPV?_ADDRESS identity --- src/libcharon/encoding/payloads/id_payload.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index 2d27021a3..4d5cd05fe 100755 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -391,7 +391,19 @@ id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts) this = (private_id_payload_t*)id_payload_create(ID_V1); - if (ts->to_subnet(ts, &net, &mask)) + if (ts->is_host(ts, NULL)) + { + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) + { + this->id_type = ID_IPV4_ADDR; + } + else + { + this->id_type = ID_IPV6_ADDR; + } + this->id_data = chunk_clone(ts->get_from_address(ts)); + } + else if (ts->to_subnet(ts, &net, &mask)) { u_int8_t netmask[16], len, byte; @@ -418,6 +430,7 @@ id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts) } this->id_data = chunk_cat("cc", net->get_address(net), chunk_create(netmask, len)); + net->destroy(net); } else { @@ -431,12 +444,12 @@ id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts) } this->id_data = chunk_cat("cc", ts->get_from_address(ts), ts->get_to_address(ts)); + net->destroy(net); } this->port = ts->get_from_port(ts); this->protocol_id = ts->get_protocol(ts); this->payload_length += this->id_data.len; - net->destroy(net); - return &this->public; } + From a974700fc0e16d2817108abbd073c1d82c06f089 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 5 Dec 2011 17:07:48 +0100 Subject: [PATCH 212/534] Fix referencing of multiple CERTREQ payload with IKEv1, other cleanups --- src/libcharon/sa/tasks/ike_cert_pre.c | 115 ++++++++++++-------------- 1 file changed, 54 insertions(+), 61 deletions(-) diff --git a/src/libcharon/sa/tasks/ike_cert_pre.c b/src/libcharon/sa/tasks/ike_cert_pre.c index 0bdbea5e1..c5c026d53 100755 --- a/src/libcharon/sa/tasks/ike_cert_pre.c +++ b/src/libcharon/sa/tasks/ike_cert_pre.c @@ -74,21 +74,18 @@ struct private_ike_cert_pre_t { /** * add certificate to auth */ -static bool add_certificate(auth_cfg_t *auth, chunk_t keyid, id_type_t id_type ) +static bool add_certificate(auth_cfg_t *auth, id_type_t type, chunk_t data) { - identification_t *id = NULL; + identification_t *id; certificate_t *cert; bool status = TRUE; - id = identification_create_from_encoding(id_type, keyid); - - if (!id) + if (!data.len) { return FALSE; } - - cert = lib->credmgr->get_cert(lib->credmgr, - CERT_X509, KEY_ANY, id, TRUE); + id = identification_create_from_encoding(type, data); + cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE); if (cert) { DBG1(DBG_IKE, "received cert request for \"%Y\"", @@ -97,11 +94,9 @@ static bool add_certificate(auth_cfg_t *auth, chunk_t keyid, id_type_t id_type ) } else { - DBG2(DBG_IKE, "received cert request for unknown ca " - "with keyid %Y", id); + DBG2(DBG_IKE, "received cert request for unknown ca %Y", id); status = FALSE; } - id->destroy(id); return status; @@ -129,7 +124,7 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) certreq_payload_t *certreq = (certreq_payload_t*)payload; enumerator_t *enumerator; u_int unknown = 0; - chunk_t keyid; + chunk_t chunk; this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE); @@ -143,9 +138,9 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) if (payload->get_type(payload) == CERTIFICATE_REQUEST) { enumerator = certreq->create_keyid_enumerator(certreq); - while (enumerator->enumerate(enumerator, &keyid)) + while (enumerator->enumerate(enumerator, &chunk)) { - if (!add_certificate(auth, keyid, ID_KEY_ID)) + if (!add_certificate(auth, ID_KEY_ID, chunk)) { unknown++; } @@ -154,16 +149,12 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) } else { - keyid = certreq->get_dn(certreq); - - /* In case client (iPhone) is sending empty cert requests */ - if (!keyid.ptr || !keyid.len || - !add_certificate(auth, keyid, ID_DER_ASN1_DN)) + chunk = certreq->get_dn(certreq); + if (!add_certificate(auth, ID_DER_ASN1_DN, chunk)) { unknown++; } } - if (unknown) { DBG1(DBG_IKE, "received %u cert requests for an unknown ca", @@ -245,7 +236,7 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message) while (enumerator->enumerate(enumerator, &payload)) { if (payload->get_type(payload) == CERTIFICATE || - payload->get_type(payload) == CERTIFICATE_V1) + payload->get_type(payload) == CERTIFICATE_V1) { cert_payload_t *cert_payload; cert_encoding_t encoding; @@ -346,7 +337,7 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message) * add the keyid of a certificate to the certificate request payload */ static void add_certreq(private_ike_cert_pre_t *this, - certreq_payload_t **req, certificate_t *cert) + certreq_payload_t **req, certificate_t *cert) { switch (cert->get_type(cert)) { @@ -365,30 +356,15 @@ static void add_certreq(private_ike_cert_pre_t *this, { break; } - if (*req == NULL) { - *req = certreq_payload_create_type(this->cert_req_payload_type, CERT_X509); + *req = certreq_payload_create_type(CERTIFICATE_REQUEST, CERT_X509); } - - if (this->cert_req_payload_type == CERTIFICATE_REQUEST) + if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) { - if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) - { - (*req)->add_keyid(*req, keyid); - DBG1(DBG_IKE, "sending cert request for \"%Y\"", - cert->get_subject(cert)); - } - } - else - { - identification_t *id; - id = cert->get_subject(cert); - - (*req)->set_dn(*req, id->get_encoding(id)); + (*req)->add_keyid(*req, keyid); DBG1(DBG_IKE, "sending cert request for \"%Y\"", - cert->get_subject(cert)); - + cert->get_subject(cert)); } public->destroy(public); break; @@ -398,11 +374,42 @@ static void add_certreq(private_ike_cert_pre_t *this, } } +/** + * Add the subject of a CA certificate a message + */ +static void add_certreq_v1(private_ike_cert_pre_t *this, + message_t *message, certificate_t *cert) +{ + switch (cert->get_type(cert)) + { + case CERT_X509: + { + x509_t *x509 = (x509_t*)cert; + identification_t *id; + certreq_payload_t *req; + + if (!(x509->get_flags(x509) & X509_CA)) + { /* no CA cert, skip */ + break; + } + req = certreq_payload_create_type(CERTIFICATE_REQUEST_V1, CERT_X509); + id = cert->get_subject(cert); + req->set_dn(req, id->get_encoding(id)); + DBG1(DBG_IKE, "sending cert request for \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, &req->payload_interface); + break; + } + default: + break; + } +} + /** * add a auth_cfg's CA certificates to the certificate request */ static void add_certreqs(private_ike_cert_pre_t *this, - certreq_payload_t **req, auth_cfg_t *auth) + certreq_payload_t **req, auth_cfg_t *auth) { enumerator_t *enumerator; auth_rule_t type; @@ -427,8 +434,7 @@ static void add_certreqs(private_ike_cert_pre_t *this, * add a auth_cfg's CA certificates to the certificate request */ static void add_certreqs_v1(private_ike_cert_pre_t *this, - certreq_payload_t **req, - auth_cfg_t *auth, message_t *message) + auth_cfg_t *auth, message_t *message) { enumerator_t *enumerator; auth_rule_t type; @@ -440,11 +446,7 @@ static void add_certreqs_v1(private_ike_cert_pre_t *this, switch (type) { case AUTH_RULE_CA_CERT: - add_certreq(this, req, (certificate_t*)value); - if (req) - { - message->add_payload(message,(payload_t*)req); - } + add_certreq_v1(this, message, (certificate_t*)value); break; default: break; @@ -518,7 +520,6 @@ static void build_certreqs_v1(private_ike_cert_pre_t *this, message_t *message) peer_cfg_t *peer_cfg; certificate_t *cert; auth_cfg_t *auth; - certreq_payload_t *req = NULL; ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); if (!ike_cfg->send_certreq(ike_cfg)) @@ -534,27 +535,19 @@ static void build_certreqs_v1(private_ike_cert_pre_t *this, message_t *message) enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); if (enumerator->enumerate(enumerator, &auth)) { - add_certreqs_v1(this, &req, auth, message); - if (req) - { - message->add_payload(message, (payload_t*)req); - } + add_certreqs_v1(this, auth, message); } enumerator->destroy(enumerator); } - if (!req) + if (!message->get_payload(message, CERTIFICATE_REQUEST_V1)) { /* otherwise add all trusted CA certificates */ enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, CERT_ANY, KEY_ANY, NULL, TRUE); while (enumerator->enumerate(enumerator, &cert)) { - add_certreq(this, &req, cert); - if (req) - { - message->add_payload(message, (payload_t*)req); - } + add_certreq_v1(this, message, cert); } enumerator->destroy(enumerator); } From aaa8f88906d63351bc39b8529ebf0b14d47aa136 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 5 Dec 2011 17:24:17 +0100 Subject: [PATCH 213/534] Fix support for plain RSA authentication in IKEv1, both as initiator and responder --- src/libcharon/sa/keymat_v1.c | 9 +---- src/libcharon/sa/tasks/main_mode.c | 60 ++++++++++++++++++------------ 2 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 19d6a74ce..8cf10cdf8 100755 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -426,6 +426,7 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, this->prf->allocate_bytes(this->prf, nonces, &this->skeyid); break; } + case AUTH_RSA: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: { @@ -433,14 +434,8 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, this->prf->allocate_bytes(this->prf, g_xy, &this->skeyid); break; } - case AUTH_RSA: - { - /* signatures : SKEYID = prf(Ni_b | Nr_b, g^xy) - * pubkey encr: SKEYID = prf(hash(Ni_b | Nr_b), CKY-I | CKY-R) */ - /* TODO-IKEv1: implement key derivation for other schemes, - * fall for now */ - } default: + /* TODO-IKEv1: implement key derivation for other schemes */ /* authentication class not supported */ chunk_clear(&g_xy); return FALSE; diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index f895117dc..60ebdf21b 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -274,7 +274,7 @@ static bool build_hash(private_main_mode_t *this, bool initiator, * Verify main mode hash payload */ static bool verify_hash(private_main_mode_t *this, bool initiator, - message_t *message, identification_t *id) + message_t *message, identification_t *id) { hash_payload_t *hash_payload; chunk_t hash, dh; @@ -305,12 +305,11 @@ static bool verify_hash(private_main_mode_t *this, bool initiator, * Verify main mode signature payload */ static bool verify_signature(private_main_mode_t *this, bool initiator, - message_t *message, identification_t *id) + message_t *message, identification_t *id) { chunk_t hash, dh; public_key_t *public; hash_payload_t *signature_payload; - auth_method_t auth_method; chunk_t auth_data; auth_cfg_t *auth, *current_auth; enumerator_t *enumerator; @@ -325,25 +324,25 @@ static bool verify_signature(private_main_mode_t *this, bool initiator, return FALSE; } - auth_method = this->auth_method; - - switch (auth_method) + switch (this->auth_method) { + case AUTH_RSA: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: key_type = KEY_RSA; scheme = SIGN_RSA_EMSA_PKCS1_NULL; break; - default: - DBG1(DBG_IKE, "unsupported auth_method (%d)",auth_method); + /* TODO-IKEv1: other auth methods */ + DBG1(DBG_IKE, "unsupported auth method: %N", + auth_method_names, this->auth_method); return FALSE; } this->dh->get_my_public_value(this->dh, &dh); hash = this->keymat->get_hash(this->keymat, initiator, this->dh_value, dh, - this->ike_sa->get_id(this->ike_sa), - this->sa_payload, id); + this->ike_sa->get_id(this->ike_sa), + this->sa_payload, id); free(dh.ptr); auth_data = signature_payload->get_hash(signature_payload); @@ -355,7 +354,7 @@ static bool verify_signature(private_main_mode_t *this, bool initiator, if (public->verify(public, scheme, hash, auth_data)) { DBG1(DBG_IKE, "authentication of '%Y' with %N successful", - id, auth_method_names, auth_method); + id, auth_method_names, this->auth_method); status = SUCCESS; auth->merge(auth, current_auth, FALSE); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); @@ -378,7 +377,6 @@ static bool verify_signature(private_main_mode_t *this, bool initiator, return status == SUCCESS; } - /** * Generate and add NONCE, KE payload */ @@ -697,29 +695,25 @@ METHOD(task_t, process_r, status_t, { case AUTH_PSK: case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_RESP_PSK: if (!verify_hash(this, TRUE, message, id)) { return FAILED; } break; - - case AUTH_XAUTH_RESP_RSA: - case AUTH_XAUTH_INIT_RSA: case AUTH_RSA: - { + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: if (!verify_signature(this, TRUE, message, id)) { return FAILED; } break; - } - default: - DBG1(DBG_IKE, "unknown auth_method:%d",get_auth_method(this)); + DBG1(DBG_IKE, "unsupported auth method: %N", + auth_method_names, this->auth_method); return FAILED; - break; } - this->state = MM_AUTH; return NEED_MORE; } @@ -771,6 +765,7 @@ static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, { case AUTH_PSK: case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_RESP_PSK: shared_key = lookup_shared_key(this); break; default: @@ -954,9 +949,28 @@ METHOD(task_t, process_i, status_t, } this->ike_sa->set_other_id(this->ike_sa, id); - if (!verify_hash(this, FALSE, message, id)) + switch (this->auth_method) { - return FAILED; + case AUTH_PSK: + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_RESP_PSK: + if (!verify_hash(this, FALSE, message, id)) + { + return FAILED; + } + break; + case AUTH_RSA: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + if (!verify_signature(this, FALSE, message, id)) + { + return FAILED; + } + break; + default: + DBG1(DBG_IKE, "unsupported auth method: %N", + auth_method_names, this->auth_method); + return FAILED; } /* TODO-IKEv1: check for XAUTH rounds, queue them */ From 9f80110bc63f26a7e141e34736b2659567debaa5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 6 Dec 2011 10:33:10 +0100 Subject: [PATCH 214/534] Install SAs with UDP encapsulation during Quick Mode. --- src/libcharon/sa/tasks/quick_mode.c | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 10e0c224c..cfbfb1386 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -487,12 +487,12 @@ METHOD(task_t, build_i, status_t, linked_list_t *list; proposal_t *proposal; ipsec_mode_t mode; - bool udp = FALSE; + bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), - this->config, 0, FALSE); + this->config, 0, udp); list = this->config->get_proposals(this->config, TRUE); @@ -510,14 +510,10 @@ METHOD(task_t, build_i, status_t, enumerator->destroy(enumerator); mode = this->config->get_mode(this->config); - if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + if (udp && mode == MODE_TRANSPORT) { - udp = TRUE; /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */ - if (mode == MODE_TRANSPORT) - { - add_nat_oa_payloads(this, message); - } + add_nat_oa_payloads(this, message); } get_lifetimes(this); @@ -575,6 +571,7 @@ METHOD(task_t, process_r, status_t, linked_list_t *tsi, *tsr, *list; peer_cfg_t *peer_cfg; host_t *me, *other; + bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); if (!get_ts(this, message)) { @@ -636,7 +633,7 @@ METHOD(task_t, process_r, status_t, this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), - this->config, 0, FALSE); + this->config, 0, udp); return NEED_MORE; } case QM_NEGOTIATED: @@ -674,7 +671,7 @@ METHOD(task_t, build_r, status_t, { sa_payload_t *sa_payload; ipsec_mode_t mode; - bool udp = FALSE; + bool udp = this->child_sa->has_encap(this->child_sa); this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); if (!this->spi_r) @@ -685,14 +682,10 @@ METHOD(task_t, build_r, status_t, this->proposal->set_spi(this->proposal, this->spi_r); mode = this->config->get_mode(this->config); - if (this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY)) + if (udp && mode == MODE_TRANSPORT) { - udp = TRUE; /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */ - if (mode == MODE_TRANSPORT) - { - add_nat_oa_payloads(this, message); - } + add_nat_oa_payloads(this, message); } sa_payload = sa_payload_create_from_proposal_v1(this->proposal, From 6ccabe2561af854b20de79eb66ba735e5fffe782 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 6 Dec 2011 10:55:15 +0100 Subject: [PATCH 215/534] Reverted ike_cert tasks to IKEv2 only, we use dedicated IKEv1 tasks --- src/libcharon/sa/tasks/ike_cert_post.c | 172 +----------- src/libcharon/sa/tasks/ike_cert_pre.c | 366 ++----------------------- 2 files changed, 41 insertions(+), 497 deletions(-) mode change 100755 => 100644 src/libcharon/sa/tasks/ike_cert_post.c mode change 100755 => 100644 src/libcharon/sa/tasks/ike_cert_pre.c diff --git a/src/libcharon/sa/tasks/ike_cert_post.c b/src/libcharon/sa/tasks/ike_cert_post.c old mode 100755 new mode 100644 index 358a067c9..ba5d76baa --- a/src/libcharon/sa/tasks/ike_cert_post.c +++ b/src/libcharon/sa/tasks/ike_cert_post.c @@ -21,7 +21,6 @@ #include #include #include -#include #include @@ -46,20 +45,6 @@ struct private_ike_cert_post_t { * Are we the initiator? */ bool initiator; - - /** - * Certificate payload type that we are handling - */ - payload_type_t payload_type; - - /** - * States of ike cert pre - */ - enum { - CP_INIT, - CP_SA, - CP_SA_POST, - } state; }; /** @@ -77,14 +62,14 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL)) { - return cert_payload_create_from_cert(cert, this->payload_type); + return cert_payload_create_from_cert(cert, CERTIFICATE); } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!hasher) { DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported"); - return cert_payload_create_from_cert(cert, this->payload_type); + return cert_payload_create_from_cert(cert, CERTIFICATE); } if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded)) @@ -101,12 +86,12 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr, CERT_X509, id); if (enumerator->enumerate(enumerator, &url)) { - payload = cert_payload_create_from_hash_and_url(hash, url, this->payload_type); + payload = cert_payload_create_from_hash_and_url(hash, url, CERTIFICATE); DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url); } else { - payload = cert_payload_create_from_cert(cert, this->payload_type); + payload = cert_payload_create_from_cert(cert, CERTIFICATE); } enumerator->destroy(enumerator); chunk_free(&hash); @@ -114,74 +99,21 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, return payload; } -/** - * Checks for the auth_method to see if this task should handle certificates. - * (IKEv1 only) - */ -static status_t check_auth_method(private_ike_cert_post_t *this, - message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - status_t status = SUCCESS; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) - { - sa_payload_t *sa_payload = (sa_payload_t*)payload; - - switch (sa_payload->get_auth_method(sa_payload)) - { - case AUTH_RSA: - case AUTH_XAUTH_INIT_RSA: - case AUTH_XAUTH_RESP_RSA: - DBG3(DBG_IKE, "handling certs method (%d)", - sa_payload->get_auth_method(sa_payload)); - status = NEED_MORE; - break; - default: - DBG3(DBG_IKE, "not handling certs method (%d)", - sa_payload->get_auth_method(sa_payload)); - status = SUCCESS; - break; - } - - this->state = CP_SA; - break; - } - } - enumerator->destroy(enumerator); - - return status; -} - /** * add certificates to message */ static void build_certs(private_ike_cert_post_t *this, message_t *message) { peer_cfg_t *peer_cfg; + auth_payload_t *payload; + payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - - if (!peer_cfg) - { + if (!peer_cfg || !payload || payload->get_auth_method(payload) == AUTH_PSK) + { /* no CERT payload for EAP/PSK */ return; } - if (this->payload_type == CERTIFICATE) - { - auth_payload_t *payload; - payload = (auth_payload_t*)message->get_payload(message, AUTHENTICATION); - - if (!payload || payload->get_auth_method(payload) == AUTH_PSK) - { /* no CERT payload for EAP/PSK */ - return; - } - } - switch (peer_cfg->get_cert_policy(peer_cfg)) { case CERT_NEVER_SEND: @@ -222,7 +154,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) { if (type == AUTH_RULE_IM_CERT) { - payload = cert_payload_create_from_cert(cert, this->payload_type); + payload = cert_payload_create_from_cert(cert, CERTIFICATE); if (payload) { DBG1(DBG_IKE, "sending issuer cert \"%Y\"", @@ -234,8 +166,6 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) enumerator->destroy(enumerator); } } - - return; } METHOD(task_t, build_i, status_t, @@ -246,14 +176,6 @@ METHOD(task_t, build_i, status_t, return NEED_MORE; } -METHOD(task_t, build_i_v1, status_t, - private_ike_cert_post_t *this, message_t *message) -{ - /* TODO:*/ - - return FAILED; -} - METHOD(task_t, process_r, status_t, private_ike_cert_post_t *this, message_t *message) { @@ -272,52 +194,6 @@ METHOD(task_t, build_r, status_t, return SUCCESS; } -METHOD(task_t, build_r_v1, status_t, - private_ike_cert_post_t *this, message_t *message) -{ - switch (message->get_exchange_type(message)) - { - case ID_PROT: - { - switch (this->state) - { - case CP_INIT: - this->state = CP_SA; - return check_auth_method(this, message); - break; - - case CP_SA: - this->state = CP_SA_POST; - build_certs(this, message); - break; - - case CP_SA_POST: - build_certs(this, message); - return SUCCESS; - } - break; - } - case AGGRESSIVE: - { - if (check_auth_method(this, message) == NEED_MORE) - { - build_certs(this, message); - } - return SUCCESS; - break; - } - default: - break; - } - - if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) - { - return NEED_MORE; - } - - return SUCCESS; -} - METHOD(task_t, process_i, status_t, private_ike_cert_post_t *this, message_t *message) { @@ -365,43 +241,17 @@ ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator) .initiator = initiator, ); - if (initiator) { + this->public.task.build = _build_i; this->public.task.process = _process_i; } else { + this->public.task.build = _build_r; this->public.task.process = _process_r; } - if (ike_sa->get_version(ike_sa) == IKEV2) - { - this->payload_type = CERTIFICATE; - - if (initiator) - { - this->public.task.build = _build_i; - } - else - { - this->public.task.build = _build_r; - } - } - else - { - this->payload_type = CERTIFICATE_V1; - - if (initiator) - { - this->public.task.build = _build_i_v1; - } - else - { - this->public.task.build = _build_r_v1; - } - } - return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_cert_pre.c b/src/libcharon/sa/tasks/ike_cert_pre.c old mode 100755 new mode 100644 index c5c026d53..0de2efd38 --- a/src/libcharon/sa/tasks/ike_cert_pre.c +++ b/src/libcharon/sa/tasks/ike_cert_pre.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include @@ -55,53 +54,8 @@ struct private_ike_cert_pre_t { * wheter this is the final authentication round */ bool final; - - /** states of ike cert pre */ - enum { - CP_INIT, - CP_SA, - CP_SA_POST, - CP_REQ_SENT, - CP_NO_CERT, - } state; - - /** - * type of certicate request to send - */ - payload_type_t cert_req_payload_type; }; -/** - * add certificate to auth - */ -static bool add_certificate(auth_cfg_t *auth, id_type_t type, chunk_t data) -{ - identification_t *id; - certificate_t *cert; - bool status = TRUE; - - if (!data.len) - { - return FALSE; - } - id = identification_create_from_encoding(type, data); - cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE); - if (cert) - { - DBG1(DBG_IKE, "received cert request for \"%Y\"", - cert->get_subject(cert)); - auth->add(auth, AUTH_RULE_CA_CERT, cert); - } - else - { - DBG2(DBG_IKE, "received cert request for unknown ca %Y", id); - status = FALSE; - } - id->destroy(id); - - return status; -} - /** * read certificate requests */ @@ -119,12 +73,11 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) switch (payload->get_type(payload)) { case CERTIFICATE_REQUEST: - case CERTIFICATE_REQUEST_V1: { certreq_payload_t *certreq = (certreq_payload_t*)payload; enumerator_t *enumerator; u_int unknown = 0; - chunk_t chunk; + chunk_t keyid; this->ike_sa->set_condition(this->ike_sa, COND_CERTREQ_SEEN, TRUE); @@ -134,27 +87,30 @@ static void process_certreqs(private_ike_cert_pre_t *this, message_t *message) 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; - if (payload->get_type(payload) == CERTIFICATE_REQUEST) - { - enumerator = certreq->create_keyid_enumerator(certreq); - while (enumerator->enumerate(enumerator, &chunk)) + id = identification_create_from_encoding(ID_KEY_ID, keyid); + cert = lib->credmgr->get_cert(lib->credmgr, + CERT_X509, KEY_ANY, id, TRUE); + if (cert) { - if (!add_certificate(auth, ID_KEY_ID, chunk)) - { - unknown++; - } + DBG1(DBG_IKE, "received cert request for \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_RULE_CA_CERT, cert); } - enumerator->destroy(enumerator); - } - else - { - chunk = certreq->get_dn(certreq); - if (!add_certificate(auth, ID_DER_ASN1_DN, chunk)) + else { + DBG2(DBG_IKE, "received cert request for unknown ca " + "with keyid %Y", id); unknown++; } + id->destroy(id); } + enumerator->destroy(enumerator); if (unknown) { DBG1(DBG_IKE, "received %u cert requests for an unknown ca", @@ -235,8 +191,7 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message) enumerator = message->create_payload_enumerator(message); while (enumerator->enumerate(enumerator, &payload)) { - if (payload->get_type(payload) == CERTIFICATE || - payload->get_type(payload) == CERTIFICATE_V1) + if (payload->get_type(payload) == CERTIFICATE) { cert_payload_t *cert_payload; cert_encoding_t encoding; @@ -336,8 +291,7 @@ static void process_certs(private_ike_cert_pre_t *this, message_t *message) /** * add the keyid of a certificate to the certificate request payload */ -static void add_certreq(private_ike_cert_pre_t *this, - certreq_payload_t **req, certificate_t *cert) +static void add_certreq(certreq_payload_t **req, certificate_t *cert) { switch (cert->get_type(cert)) { @@ -358,7 +312,7 @@ static void add_certreq(private_ike_cert_pre_t *this, } if (*req == NULL) { - *req = certreq_payload_create_type(CERTIFICATE_REQUEST, CERT_X509); + *req = certreq_payload_create_type(CERT_X509); } if (public->get_fingerprint(public, KEYID_PUBKEY_INFO_SHA1, &keyid)) { @@ -374,42 +328,10 @@ static void add_certreq(private_ike_cert_pre_t *this, } } -/** - * Add the subject of a CA certificate a message - */ -static void add_certreq_v1(private_ike_cert_pre_t *this, - message_t *message, certificate_t *cert) -{ - switch (cert->get_type(cert)) - { - case CERT_X509: - { - x509_t *x509 = (x509_t*)cert; - identification_t *id; - certreq_payload_t *req; - - if (!(x509->get_flags(x509) & X509_CA)) - { /* no CA cert, skip */ - break; - } - req = certreq_payload_create_type(CERTIFICATE_REQUEST_V1, CERT_X509); - id = cert->get_subject(cert); - req->set_dn(req, id->get_encoding(id)); - DBG1(DBG_IKE, "sending cert request for \"%Y\"", - cert->get_subject(cert)); - message->add_payload(message, &req->payload_interface); - break; - } - default: - break; - } -} - /** * add a auth_cfg's CA certificates to the certificate request */ -static void add_certreqs(private_ike_cert_pre_t *this, - certreq_payload_t **req, auth_cfg_t *auth) +static void add_certreqs(certreq_payload_t **req, auth_cfg_t *auth) { enumerator_t *enumerator; auth_rule_t type; @@ -421,32 +343,7 @@ static void add_certreqs(private_ike_cert_pre_t *this, switch (type) { case AUTH_RULE_CA_CERT: - add_certreq(this, req, (certificate_t*)value); - break; - default: - break; - } - } - enumerator->destroy(enumerator); -} - -/** - * add a auth_cfg's CA certificates to the certificate request - */ -static void add_certreqs_v1(private_ike_cert_pre_t *this, - auth_cfg_t *auth, message_t *message) -{ - enumerator_t *enumerator; - auth_rule_t type; - void *value; - - enumerator = auth->create_enumerator(auth); - while (enumerator->enumerate(enumerator, &type, &value)) - { - switch (type) - { - case AUTH_RULE_CA_CERT: - add_certreq_v1(this, message, (certificate_t*)value); + add_certreq(req, (certificate_t*)value); break; default: break; @@ -480,7 +377,7 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); while (enumerator->enumerate(enumerator, &auth)) { - add_certreqs(this, &req, auth); + add_certreqs(&req, auth); } enumerator->destroy(enumerator); } @@ -492,7 +389,7 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) CERT_ANY, KEY_ANY, NULL, TRUE); while (enumerator->enumerate(enumerator, &cert)) { - add_certreq(this, &req, cert); + add_certreq(&req, cert); } enumerator->destroy(enumerator); } @@ -510,49 +407,6 @@ static void build_certreqs(private_ike_cert_pre_t *this, message_t *message) } } -/** - * build certificate requests - */ -static void build_certreqs_v1(private_ike_cert_pre_t *this, message_t *message) -{ - enumerator_t *enumerator; - ike_cfg_t *ike_cfg; - peer_cfg_t *peer_cfg; - certificate_t *cert; - auth_cfg_t *auth; - - ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - if (!ike_cfg->send_certreq(ike_cfg)) - { - return; - } - - /* check if we require a specific CA for that peer */ - /* Get the first authentcation config from peer config */ - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg) - { - enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); - if (enumerator->enumerate(enumerator, &auth)) - { - add_certreqs_v1(this, auth, message); - } - enumerator->destroy(enumerator); - } - - if (!message->get_payload(message, CERTIFICATE_REQUEST_V1)) - { - /* otherwise add all trusted CA certificates */ - enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, - CERT_ANY, KEY_ANY, NULL, TRUE); - while (enumerator->enumerate(enumerator, &cert)) - { - add_certreq_v1(this, message, cert); - } - enumerator->destroy(enumerator); - } -} - /** * Check if this is the final authentication round */ @@ -570,55 +424,6 @@ static bool final_auth(message_t *message) return TRUE; } -/** - * Checks for the auth_method to see if this task should handle certificates. - * (IKEv1 only) - */ -static status_t check_auth_method(private_ike_cert_pre_t *this, - message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload; - status_t status = SUCCESS; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) - { - sa_payload_t *sa_payload = (sa_payload_t*)payload; - - switch (sa_payload->get_auth_method(sa_payload)) - { - case AUTH_RSA: - case AUTH_XAUTH_INIT_RSA: - case AUTH_XAUTH_RESP_RSA: - DBG3(DBG_IKE, "handling certs method (%d)", - sa_payload->get_auth_method(sa_payload)); - status = NEED_MORE; - break; - default: - DBG3(DBG_IKE, "not handling certs method (%d)", - sa_payload->get_auth_method(sa_payload)); - status = SUCCESS; - break; - } - - this->state = CP_SA; - break; - } - } - enumerator->destroy(enumerator); - - if (status != NEED_MORE) - { - this->state = CP_NO_CERT; - this->final = TRUE; - } - - return status; -} - METHOD(task_t, build_i, status_t, private_ike_cert_pre_t *this, message_t *message) { @@ -671,97 +476,6 @@ METHOD(task_t, process_i, status_t, return NEED_MORE; } -METHOD(task_t, process_r_v1, status_t, - private_ike_cert_pre_t *this, message_t *message) -{ - switch (message->get_exchange_type(message)) - { - case ID_PROT: - { - switch (this->state) - { - case CP_INIT: - check_auth_method(this, message); - break; - case CP_SA: - process_certreqs(this, message); - this->state = CP_SA_POST; - break; - case CP_SA_POST: - process_certreqs(this, message); - process_certs(this, message); - this->state = CP_REQ_SENT; - this->final = TRUE; - break; - default: - break; - } - break; - } - case AGGRESSIVE: - { - if (check_auth_method(this, message) == NEED_MORE) - { - process_certreqs(this, message); - process_certs(this, message); - } - this->final = TRUE; - break; - } - default: - break; - } - - return NEED_MORE; -} - -METHOD(task_t, process_i_v1, status_t, - private_ike_cert_pre_t *this, message_t *message) -{ - /* TODO: */ - return FAILED; -} - -METHOD(task_t, build_r_v1, status_t, - private_ike_cert_pre_t *this, message_t *message) -{ - - switch (message->get_exchange_type(message)) - { - case ID_PROT: - { - if (this->state == CP_SA_POST) - { - build_certreqs_v1(this, message); - } - break; - } - case AGGRESSIVE: - { - if (this->state != CP_NO_CERT) - { - build_certreqs_v1(this, message); - } - } - default: - break; - - } - - if (this->final) - { - return SUCCESS; - } - return NEED_MORE; -} - -METHOD(task_t, build_i_v1, status_t, - private_ike_cert_pre_t *this, message_t *message) -{ - /* TODO: */ - return FAILED; -} - METHOD(task_t, get_type, task_type_t, private_ike_cert_pre_t *this) { @@ -799,35 +513,15 @@ ike_cert_pre_t *ike_cert_pre_create(ike_sa_t *ike_sa, bool initiator) .initiator = initiator, ); - if (ike_sa->get_version(ike_sa) == IKEV2) + if (initiator) { - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - this->cert_req_payload_type = CERTIFICATE_REQUEST; + this->public.task.build = _build_i; + this->public.task.process = _process_i; } else { - this->state = CP_INIT; - if (initiator) - { - this->public.task.build = _build_i_v1; - this->public.task.process = _process_i_v1; - } - else - { - this->public.task.build = _build_r_v1; - this->public.task.process = _process_r_v1; - } - this->cert_req_payload_type = CERTIFICATE_REQUEST_V1; - + this->public.task.build = _build_r; + this->public.task.process = _process_r; } return &this->public; From df06ef2098da33744295529872698b8d9defaa67 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 6 Dec 2011 10:56:39 +0100 Subject: [PATCH 216/534] Cleaned up certreq payload for IKEv2/IKEv1 use --- .../encoding/payloads/certreq_payload.c | 73 +++++++++---------- .../encoding/payloads/certreq_payload.h | 32 ++++---- 2 files changed, 52 insertions(+), 53 deletions(-) diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c index dea1f40bd..26d1f0a43 100755 --- a/src/libcharon/encoding/payloads/certreq_payload.c +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -66,16 +66,13 @@ struct private_certreq_payload_t { chunk_t data; /** - * Payload type for certificate request. + * Payload type CERTIFICATE_REQUEST or CERTIFICATE_REQUEST_V1 */ - payload_type_t payload_type; + payload_type_t type; }; /** - * Encoding rules to parse or generate a CERTREQ payload - * - * The defined offsets are the positions in a object of type - * private_certreq_payload_t. + * Encoding rules for CERTREQ payload. */ static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ @@ -114,7 +111,8 @@ static encoding_rule_t encodings[] = { METHOD(payload_t, verify, status_t, private_certreq_payload_t *this) { - if (this->encoding == ENC_X509_SIGNATURE) + if (this->type == CERTIFICATE_REQUEST && + this->encoding == ENC_X509_SIGNATURE) { if (this->data.len < HASH_SIZE_SHA1 || this->data.len % HASH_SIZE_SHA1) @@ -127,13 +125,6 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, verify_v1, status_t, - private_certreq_payload_t *this) -{ - /*TODO: */ - return SUCCESS; -} - METHOD(payload_t, get_encoding_rules, int, private_certreq_payload_t *this, encoding_rule_t **rules) { @@ -150,7 +141,7 @@ METHOD(payload_t, get_header_length, int, METHOD(payload_t, get_type, payload_type_t, private_certreq_payload_t *this) { - return this->payload_type; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -171,21 +162,14 @@ METHOD(payload_t, get_length, size_t, return this->payload_length; } -METHOD(certreq_payload_t, get_dn, chunk_t, +METHOD(certreq_payload_t, get_dn, identification_t*, private_certreq_payload_t *this) { - return this->data; -} - -METHOD(certreq_payload_t, set_dn, void, - private_certreq_payload_t *this, chunk_t dn) -{ - if (this->data.ptr) + if (this->data.len) { - free(this->data.ptr); + return identification_create_from_encoding(ID_DER_ASN1_DN, this->data); } - this->data = chunk_clone(dn); - this->payload_length = get_header_length(this) + this->data.len; + return NULL; } METHOD(certreq_payload_t, add_keyid, void, @@ -235,6 +219,10 @@ METHOD(certreq_payload_t, create_keyid_enumerator, enumerator_t*, { keyid_enumerator_t *enumerator; + if (this->type == CERTIFICATE_REQUEST_V1) + { + return enumerator_create_empty(); + } INIT(enumerator, .public = { .enumerate = (void*)_keyid_enumerate, @@ -267,7 +255,7 @@ METHOD2(payload_t, certreq_payload_t, destroy, void, /* * Described in header */ -certreq_payload_t *certreq_payload_create(payload_type_t payload_type) +certreq_payload_t *certreq_payload_create(payload_type_t type) { private_certreq_payload_t *this; @@ -288,28 +276,23 @@ certreq_payload_t *certreq_payload_create(payload_type_t payload_type) .add_keyid = _add_keyid, .destroy = _destroy, .get_dn = _get_dn, - .set_dn = _set_dn, }, .next_payload = NO_PAYLOAD, .payload_length = get_header_length(this), - .payload_type = payload_type, + .type = type, ); - - if (payload_type == CERTIFICATE_REQUEST_V1) - { - this->public.payload_interface.verify = _verify_v1; - } - return &this->public; } /* * Described in header */ -certreq_payload_t *certreq_payload_create_type(payload_type_t payload_type, certificate_type_t type) +certreq_payload_t *certreq_payload_create_type(certificate_type_t type) { - private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create(payload_type); + private_certreq_payload_t *this; + this = (private_certreq_payload_t*) + certreq_payload_create(CERTIFICATE_REQUEST); switch (type) { case CERT_X509: @@ -324,3 +307,19 @@ certreq_payload_t *certreq_payload_create_type(payload_type_t payload_type, cert return &this->public; } +/* + * Described in header + */ +certreq_payload_t *certreq_payload_create_dn(identification_t *id) +{ + private_certreq_payload_t *this; + + this = (private_certreq_payload_t*) + certreq_payload_create(CERTIFICATE_REQUEST_V1); + + this->encoding = ENC_X509_SIGNATURE; + this->data = chunk_clone(id->get_encoding(id)); + this->payload_length = get_header_length(this) + this->data.len; + + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h index d426da711..e234df5be 100755 --- a/src/libcharon/encoding/payloads/certreq_payload.h +++ b/src/libcharon/encoding/payloads/certreq_payload.h @@ -27,13 +27,13 @@ typedef struct certreq_payload_t certreq_payload_t; #include #include #include +#include /** - * Class representing an IKEv2 CERTREQ payload. - * - * The CERTREQ payload format is described in RFC section 3.7. + * Class representing an IKEv1/IKEv2 CERTREQ payload. */ struct certreq_payload_t { + /** * The payload_t interface. */ @@ -62,19 +62,11 @@ struct certreq_payload_t { void (*add_keyid)(certreq_payload_t *this, chunk_t keyid); /** - * Get certificate request data (IKEv1 only). + * Get the distinguished name of the payload (IKEv1 only). * - * @return certifcate request data + * @return DN as identity, must be destroyed */ - chunk_t (*get_dn)(certreq_payload_t *this); - - /** - * Set certificate request data (IKEv1 only). - * - * @param dn certifcate request data to set - * @return - */ - void (*set_dn)(certreq_payload_t *this, chunk_t dn); + identification_t* (*get_dn)(certreq_payload_t *this); /** * Destroys an certreq_payload_t object. @@ -90,11 +82,19 @@ struct certreq_payload_t { certreq_payload_t *certreq_payload_create(payload_type_t payload_type); /** - * Creates an empty certreq_payload_t for a kind of certificates. + * Creates an empty IKEv2 certreq_payload_t for a kind of certificates. * * @param type type of the added keyids * @return certreq payload */ -certreq_payload_t *certreq_payload_create_type(payload_type_t payload_type, certificate_type_t type); +certreq_payload_t *certreq_payload_create_type(certificate_type_t type); + +/** + * Creates a IKEv1 certreq_payload_t for a given distinguished name. + * + * @param dn distinguished name, does not get owned + * @return certreq payload + */ +certreq_payload_t *certreq_payload_create_dn(identification_t *id); #endif /** CERTREQ_PAYLOAD_H_ @}*/ From 8c33850615f0c69ea3229f3c297bb642c6c990f0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 6 Dec 2011 11:44:17 +0100 Subject: [PATCH 217/534] Added task types for IKEv1 certificate handling --- src/libcharon/sa/tasks/task.c | 4 ++++ src/libcharon/sa/tasks/task.h | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index 2f12ed574..145a4d6e7 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -39,6 +39,8 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, "QUICK_MODE", "VENDOR_V1", "IKE_NATD_V1", + "IKE_CERT_PRE_V1", + "IKE_CERT_POST_V1", "XAUTH_REQUEST", ); #else @@ -63,6 +65,8 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, "QUICK_MODE", "VENDOR_V1", "IKE_NATD_V1", + "IKE_CERT_PRE_V1", + "IKE_CERT_POST_V1", "XAUTH_REQUEST", ); #endif /* ME */ diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index e4edb78e0..6fb8144ec 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -77,6 +77,10 @@ enum task_type_t { TASK_VENDOR_V1, /** IKEv1 NAT detection */ TASK_IKE_NATD_V1, + /** IKEv1 pre-authentication certificate handling */ + TASK_IKE_CERT_PRE_V1, + /** IKEv1 post-authentication certificate handling */ + TASK_IKE_CERT_POST_V1, /** Request the user/pass with XAUTH */ TASK_XAUTH_REQUEST, }; From 0bcdb8e571d67d363a54ff2c2e3ecaf52bb93ebc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 6 Dec 2011 12:14:48 +0100 Subject: [PATCH 218/534] Implemented pre-authentication certificate handling for IKEv1 --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/ike_sa.c | 3 + src/libcharon/sa/task_manager_v1.c | 7 +- src/libcharon/sa/tasks/ike_cert_pre_v1.c | 517 +++++++++++++++++++++++ src/libcharon/sa/tasks/ike_cert_pre_v1.h | 53 +++ 5 files changed, 577 insertions(+), 4 deletions(-) create mode 100755 src/libcharon/sa/tasks/ike_cert_pre_v1.c create mode 100644 src/libcharon/sa/tasks/ike_cert_pre_v1.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 4d3cc39c7..d36b5a506 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -83,6 +83,7 @@ sa/tasks/child_rekey.c sa/tasks/child_rekey.h \ sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ +sa/tasks/ike_cert_pre_v1.c sa/tasks/ike_cert_pre_v1.h \ sa/tasks/ike_config.c sa/tasks/ike_config.h \ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 5a21a8870..96cbcf10a 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -1122,6 +1123,8 @@ METHOD(ike_sa_t, initiate, status_t, { task = (task_t*)ike_vendor_v1_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_cert_pre_v1_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); task = (task_t*)main_mode_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_natd_v1_create(&this->public, TRUE); diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index c08f70be8..0843db51e 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -266,6 +266,7 @@ METHOD(task_manager_t, initiate, status_t, { case IKE_CREATED: activate_task(this, TASK_VENDOR_V1); + activate_task(this, TASK_IKE_CERT_PRE_V1); if (activate_task(this, TASK_MAIN_MODE)) { exchange = ID_PROT; @@ -501,14 +502,12 @@ static status_t process_request(private_task_manager_t *this, case ID_PROT: task = (task_t *)ike_vendor_v1_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_cert_pre_create(this->ike_sa, FALSE); + task = (task_t*)ike_cert_pre_v1_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)ike_natd_v1_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); break; case AGGRESSIVE: /* TODO-IKEv1: agressive mode */ diff --git a/src/libcharon/sa/tasks/ike_cert_pre_v1.c b/src/libcharon/sa/tasks/ike_cert_pre_v1.c new file mode 100755 index 000000000..fab8d5bb3 --- /dev/null +++ b/src/libcharon/sa/tasks/ike_cert_pre_v1.c @@ -0,0 +1,517 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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_pre_v1.h" + +#include +#include +#include +#include +#include +#include + + +typedef struct private_ike_cert_pre_v1_t private_ike_cert_pre_v1_t; + +/** + * Private members of a ike_cert_pre_v1_t task. + */ +struct private_ike_cert_pre_v1_t { + + /** + * Public methods and task_t interface. + */ + ike_cert_pre_v1_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** next message we expect */ + enum { + CR_SA, + CR_KE, + CR_AUTH, + } state; +}; + +/** + * Find the CA certificate for a given certreq payload + */ +static certificate_t* find_certificate(private_ike_cert_pre_v1_t *this, + certreq_payload_t *certreq) +{ + identification_t *id; + certificate_t *cert; + + if (certreq->get_cert_type(certreq) != CERT_X509) + { + DBG1(DBG_IKE, "%N CERTREQ not supported - ignored", + certificate_type_names, certreq->get_cert_type(certreq)); + return NULL; + } + id = certreq->get_dn(certreq); + if (!id) + { + DBG1(DBG_IKE, "ignoring certificate request without data", + certificate_type_names, certreq->get_cert_type(certreq)); + return NULL; + } + cert = lib->credmgr->get_cert(lib->credmgr, CERT_X509, KEY_ANY, id, TRUE); + if (cert) + { + DBG1(DBG_IKE, "received cert request for '%Y'", + cert->get_subject(cert)); + } + else + { + DBG1(DBG_IKE, "received cert request for unknown ca '%Y'", id); + } + id->destroy(id); + + return cert; +} + +/** + * read certificate requests + */ +static void process_certreqs(private_ike_cert_pre_v1_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + auth_cfg_t *auth; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case CERTIFICATE_REQUEST_V1: + { + certificate_t *cert; + + this->ike_sa->set_condition(this->ike_sa, + COND_CERTREQ_SEEN, TRUE); + cert = find_certificate(this, (certreq_payload_t*)payload); + if (cert) + { + auth->add(auth, AUTH_RULE_CA_CERT, cert); + } + break; + } + default: + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Import receuved certificates + */ +static void process_certs(private_ike_cert_pre_v1_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + auth_cfg_t *auth; + bool first = TRUE; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == CERTIFICATE_V1) + { + cert_payload_t *cert_payload; + cert_encoding_t encoding; + certificate_t *cert; + + cert_payload = (cert_payload_t*)payload; + encoding = cert_payload->get_cert_encoding(cert_payload); + + switch (encoding) + { + case ENC_X509_SIGNATURE: + { + cert = cert_payload->get_cert(cert_payload); + if (cert) + { + if (first) + { /* the first is an end entity certificate */ + DBG1(DBG_IKE, "received end entity cert \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_SUBJECT_CERT, cert); + first = FALSE; + } + else + { + DBG1(DBG_IKE, "received issuer cert \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_IM_CERT, cert); + } + } + break; + } + case ENC_CRL: + cert = cert_payload->get_cert(cert_payload); + if (cert) + { + DBG1(DBG_IKE, "received CRL \"%Y\"", + cert->get_subject(cert)); + auth->add(auth, AUTH_HELPER_REVOCATION_CERT, cert); + } + break; + case ENC_PKCS7_WRAPPED_X509: + case ENC_PGP: + case ENC_DNS_SIGNED_KEY: + case ENC_KERBEROS_TOKEN: + case ENC_ARL: + case ENC_SPKI: + case ENC_X509_ATTRIBUTE: + case ENC_RAW_RSA_KEY: + case ENC_X509_HASH_AND_URL_BUNDLE: + case ENC_OCSP_CONTENT: + default: + DBG1(DBG_ENC, "certificate encoding %N not supported", + cert_encoding_names, encoding); + } + } + } + enumerator->destroy(enumerator); +} + +/** + * Add the subject of a CA certificate a message + */ +static void add_certreq(private_ike_cert_pre_v1_t *this, message_t *message, + certificate_t *cert) +{ + if (cert->get_type(cert) == CERT_X509) + { + x509_t *x509 = (x509_t*)cert; + + if (x509->get_flags(x509) & X509_CA) + { + DBG1(DBG_IKE, "sending cert request for \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*) + certreq_payload_create_dn(cert->get_subject(cert))); + } + } +} + +/** + * Add auth_cfg's CA certificates to the certificate request + */ +static void add_certreqs(private_ike_cert_pre_v1_t *this, + auth_cfg_t *auth, message_t *message) +{ + enumerator_t *enumerator; + auth_rule_t type; + void *value; + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &value)) + { + switch (type) + { + case AUTH_RULE_CA_CERT: + add_certreq(this, message, (certificate_t*)value); + break; + default: + break; + } + } + enumerator->destroy(enumerator); +} + +/** + * Build certificate requests + */ +static void build_certreqs(private_ike_cert_pre_v1_t *this, message_t *message) +{ + enumerator_t *enumerator; + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + certificate_t *cert; + auth_cfg_t *auth; + + ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + if (!ike_cfg->send_certreq(ike_cfg)) + { + return; + } + /* check if we require a specific CA for that peer */ + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg) + { + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, FALSE); + if (enumerator->enumerate(enumerator, &auth)) + { + add_certreqs(this, auth, message); + } + enumerator->destroy(enumerator); + } + if (!message->get_payload(message, CERTIFICATE_REQUEST_V1)) + { + /* otherwise add all trusted CA certificates */ + enumerator = lib->credmgr->create_cert_enumerator(lib->credmgr, + CERT_ANY, KEY_ANY, NULL, TRUE); + while (enumerator->enumerate(enumerator, &cert)) + { + add_certreq(this, message, cert); + } + enumerator->destroy(enumerator); + } +} + +/** + * Check if we actually use certificates for authentication + */ +static bool use_certs(private_ike_cert_pre_v1_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool use = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) + { + sa_payload_t *sa_payload = (sa_payload_t*)payload; + + switch (sa_payload->get_auth_method(sa_payload)) + { + case AUTH_RSA: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + use = TRUE; + break; + default: + break; + } + break; + } + } + enumerator->destroy(enumerator); + + return use; +} + +METHOD(task_t, build_i, status_t, + private_ike_cert_pre_v1_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + if (this->state == CR_AUTH) + { + build_certreqs(this, message); + } + return NEED_MORE; + case AGGRESSIVE: + if (this->state == CR_SA) + { + build_certreqs(this, message); + } + return NEED_MORE; + default: + return FAILED; + } +} + +METHOD(task_t, process_r, status_t, + private_ike_cert_pre_v1_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + return NEED_MORE; + case CR_KE: + process_certreqs(this, message); + return NEED_MORE; + case CR_AUTH: + process_certreqs(this, message); + process_certs(this, message); + return SUCCESS; + } + } + case AGGRESSIVE: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + process_certreqs(this, message); + return NEED_MORE; + case CR_AUTH: + process_certs(this, message); + return SUCCESS; + default: + return FAILED; + } + } + default: + return FAILED; + } +} + +METHOD(task_t, build_r, status_t, + private_ike_cert_pre_v1_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + switch (this->state) + { + case CR_SA: + this->state = CR_KE; + return NEED_MORE; + case CR_KE: + build_certreqs(this, message); + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + return NEED_MORE; + } + case AGGRESSIVE: + switch (this->state) + { + case CR_SA: + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + return SUCCESS; + default: + return FAILED; + } + default: + return FAILED; + } +} + +METHOD(task_t, process_i, status_t, + private_ike_cert_pre_v1_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + this->state = CR_KE; + return NEED_MORE; + case CR_KE: + process_certreqs(this, message); + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + process_certs(this, message); + return SUCCESS; + default: + return FAILED; + } + break; + } + case AGGRESSIVE: + { + if (!use_certs(this, message)) + { + return SUCCESS; + } + process_certreqs(this, message); + process_certs(this, message); + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, get_type, task_type_t, + private_ike_cert_pre_v1_t *this) +{ + return TASK_IKE_CERT_PRE_V1; +} + +METHOD(task_t, migrate, void, + private_ike_cert_pre_v1_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_ike_cert_pre_v1_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_cert_pre_v1_t *ike_cert_pre_v1_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_cert_pre_v1_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .state = CR_SA, + ); + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/tasks/ike_cert_pre_v1.h b/src/libcharon/sa/tasks/ike_cert_pre_v1.h new file mode 100644 index 000000000..38042ccf2 --- /dev/null +++ b/src/libcharon/sa/tasks/ike_cert_pre_v1.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_cert_pre_v1 ike_cert_pre_v1 + * @{ @ingroup tasks + */ + +#ifndef IKE_CERT_PRE_V1_H_ +#define IKE_CERT_PRE_V1_H_ + +typedef struct ike_cert_pre_v1_t ike_cert_pre_v1_t; + +#include +#include +#include + +/** + * IKE_CERT_PRE_V1 task, IKEv1 certificate processing before authentication. + */ +struct ike_cert_pre_v1_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new IKE_CERT_PRE_V1 task. + * + * The initiator parameter means the original initiator, not the initiator + * of the certificate request. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + * @return ike_cert_pre_v1 task to handle by the task_manager + */ +ike_cert_pre_v1_t *ike_cert_pre_v1_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IIKE_CERT_PRE_V1_H_ @}*/ From 9ad5b8fa951c294f3f79ffe701cac712a6cf18df Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 6 Dec 2011 13:37:57 +0100 Subject: [PATCH 219/534] Cleanup CERT payload constructors --- src/conftest/hooks/ike_auth_fill.c | 2 +- src/conftest/hooks/pretend_auth.c | 4 ++-- .../encoding/payloads/cert_payload.c | 23 ++++++++++++------- .../encoding/payloads/cert_payload.h | 16 ++++++------- src/libcharon/sa/tasks/ike_cert_post.c | 10 ++++---- 5 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/conftest/hooks/ike_auth_fill.c b/src/conftest/hooks/ike_auth_fill.c index ac26d1bfe..7362c19f4 100644 --- a/src/conftest/hooks/ike_auth_fill.c +++ b/src/conftest/hooks/ike_auth_fill.c @@ -108,7 +108,7 @@ METHOD(listener_t, message, bool, diff = this->bytes - size - CERT_PAYLOAD_HEADER_LENGTH; data = chunk_alloc(diff); memset(data.ptr, 0x12, data.len); - pld = cert_payload_create_custom(201, data, CERTIFICATE); + pld = cert_payload_create_custom(CERTIFICATE, 201, data); message->add_payload(message, &pld->payload_interface); DBG1(DBG_CFG, "inserting %d dummy bytes certificate payload", diff); } diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c index b8f961403..10b13c6ac 100644 --- a/src/conftest/hooks/pretend_auth.c +++ b/src/conftest/hooks/pretend_auth.c @@ -154,7 +154,7 @@ static void build_certs(private_pretend_auth_t *this, cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); if (cert) { - payload = cert_payload_create_from_cert(cert, CERTIFICATE); + payload = cert_payload_create_from_cert(CERTIFICATE, cert); if (payload) { DBG1(DBG_IKE, "pretending end entity cert \"%Y\"", @@ -167,7 +167,7 @@ static void build_certs(private_pretend_auth_t *this, { if (type == AUTH_RULE_IM_CERT) { - payload = cert_payload_create_from_cert(cert, CERTIFICATE); + payload = cert_payload_create_from_cert(CERTIFICATE, cert); if (payload) { DBG1(DBG_IKE, "pretending issuer cert \"%Y\"", diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c index af726ad62..3a230b91e 100644 --- a/src/libcharon/encoding/payloads/cert_payload.c +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -304,10 +304,12 @@ cert_payload_t *cert_payload_create(payload_type_t type) /* * Described in header */ -cert_payload_t *cert_payload_create_from_cert(certificate_t *cert, payload_type_t type) +cert_payload_t *cert_payload_create_from_cert(payload_type_t type, + certificate_t *cert) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(type); + private_cert_payload_t *this; + this = (private_cert_payload_t*)cert_payload_create(type); switch (cert->get_type(cert)) { case CERT_X509: @@ -326,33 +328,38 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert, payload_type_ return NULL; } this->payload_length = get_header_length(this) + this->data.len; + return &this->public; } /* * Described in header */ -cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url, - payload_type_t type) +cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(type); + private_cert_payload_t *this; + this = (private_cert_payload_t*)cert_payload_create(CERTIFICATE); this->encoding = ENC_X509_HASH_AND_URL; this->data = chunk_cat("cc", hash, chunk_create(url, strlen(url))); this->payload_length = get_header_length(this) + this->data.len; + return &this->public; } /* * Described in header */ -cert_payload_t *cert_payload_create_custom(cert_encoding_t encoding, - chunk_t data, payload_type_t type) +cert_payload_t *cert_payload_create_custom(payload_type_t type, + cert_encoding_t encoding, chunk_t data) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(type); + private_cert_payload_t *this; + this = (private_cert_payload_t*)cert_payload_create(type); this->encoding = encoding; this->data = data; this->payload_length = get_header_length(this) + this->data.len; + return &this->public; } + diff --git a/src/libcharon/encoding/payloads/cert_payload.h b/src/libcharon/encoding/payloads/cert_payload.h index c237d7dea..d85a463ca 100644 --- a/src/libcharon/encoding/payloads/cert_payload.h +++ b/src/libcharon/encoding/payloads/cert_payload.h @@ -55,9 +55,7 @@ enum cert_encoding_t { extern enum_name_t *cert_encoding_names; /** - * Class representing an IKEv2 CERT payload. - * - * The CERT payload format is described in RFC section 3.6. + * Class representing an IKEv1/IKEv2 CERT payload. */ struct cert_payload_t { @@ -121,17 +119,16 @@ cert_payload_t *cert_payload_create(payload_type_t type); * @param cert certificate to embed * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_from_cert(certificate_t *cert, payload_type_t type); +cert_payload_t *cert_payload_create_from_cert(payload_type_t type, + certificate_t *cert); /** - * Creates a certificate payload with hash and URL encoding of a certificate. + * Creates an IKEv2 certificate payload with hash and URL encoding. * - * @param type payload type (for IKEv1 or IKEv2) * @param hash hash of the DER encoded certificate (get's cloned) - * @param url the URL to locate the certificate (get's cloned) * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url, payload_type_t type); +cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url); /** * Creates a custom certificate payload using type and associated data. @@ -141,6 +138,7 @@ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url, p * @param data associated data (gets owned) * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_custom(cert_encoding_t encoding, chunk_t data, payload_type_t type); +cert_payload_t *cert_payload_create_custom(payload_type_t type, + cert_encoding_t encoding, chunk_t data); #endif /** CERT_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/sa/tasks/ike_cert_post.c b/src/libcharon/sa/tasks/ike_cert_post.c index ba5d76baa..bedf323ff 100644 --- a/src/libcharon/sa/tasks/ike_cert_post.c +++ b/src/libcharon/sa/tasks/ike_cert_post.c @@ -62,14 +62,14 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, if (!this->ike_sa->supports_extension(this->ike_sa, EXT_HASH_AND_URL)) { - return cert_payload_create_from_cert(cert, CERTIFICATE); + return cert_payload_create_from_cert(CERTIFICATE, cert); } hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); if (!hasher) { DBG1(DBG_IKE, "unable to use hash-and-url: sha1 not supported"); - return cert_payload_create_from_cert(cert, CERTIFICATE); + return cert_payload_create_from_cert(CERTIFICATE, cert); } if (!cert->get_encoding(cert, CERT_ASN1_DER, &encoded)) @@ -86,12 +86,12 @@ static cert_payload_t *build_cert_payload(private_ike_cert_post_t *this, enumerator = lib->credmgr->create_cdp_enumerator(lib->credmgr, CERT_X509, id); if (enumerator->enumerate(enumerator, &url)) { - payload = cert_payload_create_from_hash_and_url(hash, url, CERTIFICATE); + payload = cert_payload_create_from_hash_and_url(hash, url); DBG1(DBG_IKE, "sending hash-and-url \"%s\"", url); } else { - payload = cert_payload_create_from_cert(cert, CERTIFICATE); + payload = cert_payload_create_from_cert(CERTIFICATE, cert); } enumerator->destroy(enumerator); chunk_free(&hash); @@ -154,7 +154,7 @@ static void build_certs(private_ike_cert_post_t *this, message_t *message) { if (type == AUTH_RULE_IM_CERT) { - payload = cert_payload_create_from_cert(cert, CERTIFICATE); + payload = cert_payload_create_from_cert(CERTIFICATE, cert); if (payload) { DBG1(DBG_IKE, "sending issuer cert \"%Y\"", From c64a4b4f8e44cd02b6fae769ecea69b142fc141d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 6 Dec 2011 13:38:27 +0100 Subject: [PATCH 220/534] Implemented post-authentication certificate handling for IKEv1 --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/ike_sa.c | 3 + src/libcharon/sa/task_manager_v1.c | 5 +- src/libcharon/sa/tasks/ike_cert_post_v1.c | 346 ++++++++++++++++++++++ src/libcharon/sa/tasks/ike_cert_post_v1.h | 53 ++++ 5 files changed, 407 insertions(+), 1 deletion(-) create mode 100755 src/libcharon/sa/tasks/ike_cert_post_v1.c create mode 100644 src/libcharon/sa/tasks/ike_cert_post_v1.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index d36b5a506..d9e5a54b2 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -84,6 +84,7 @@ sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ sa/tasks/ike_cert_pre_v1.c sa/tasks/ike_cert_pre_v1.h \ +sa/tasks/ike_cert_post_v1.c sa/tasks/ike_cert_post_v1.h \ sa/tasks/ike_config.c sa/tasks/ike_config.h \ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 96cbcf10a..47aadc108 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -1127,6 +1128,8 @@ METHOD(ike_sa_t, initiate, status_t, this->task_manager->queue_task(this->task_manager, task); task = (task_t*)main_mode_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); + task = (task_t*)ike_cert_post_v1_create(&this->public, TRUE); + this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_natd_v1_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); } diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 0843db51e..3d8229c05 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include @@ -270,6 +270,7 @@ METHOD(task_manager_t, initiate, status_t, if (activate_task(this, TASK_MAIN_MODE)) { exchange = ID_PROT; + activate_task(this, TASK_IKE_CERT_POST_V1); activate_task(this, TASK_IKE_NATD_V1); } break; @@ -506,6 +507,8 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)ike_cert_post_v1_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)ike_natd_v1_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); break; diff --git a/src/libcharon/sa/tasks/ike_cert_post_v1.c b/src/libcharon/sa/tasks/ike_cert_post_v1.c new file mode 100755 index 000000000..517f8c1bf --- /dev/null +++ b/src/libcharon/sa/tasks/ike_cert_post_v1.c @@ -0,0 +1,346 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "ike_cert_post_v1.h" + +#include +#include +#include +#include +#include +#include +#include + + +typedef struct private_ike_cert_post_v1_t private_ike_cert_post_v1_t; + +/** + * Private members of a ike_cert_post_v1_t task. + */ +struct private_ike_cert_post_v1_t { + + /** + * Public methods and task_t interface. + */ + ike_cert_post_v1_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * States of ike cert pre + */ + enum { + CR_SA, + CR_KE, + CR_AUTH, + } state; +}; + +/** + * Check if we actually use certificates for authentication + */ +static bool use_certs(private_ike_cert_post_v1_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool use = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) + { + sa_payload_t *sa_payload = (sa_payload_t*)payload; + + switch (sa_payload->get_auth_method(sa_payload)) + { + case AUTH_RSA: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + use = TRUE; + break; + default: + break; + } + break; + } + } + enumerator->destroy(enumerator); + + return use; +} + +/** + * Add certificates to message + */ +static void build_certs(private_ike_cert_post_v1_t *this, message_t *message) +{ + peer_cfg_t *peer_cfg; + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (!peer_cfg) + { + return; + } + + switch (peer_cfg->get_cert_policy(peer_cfg)) + { + case CERT_NEVER_SEND: + break; + case CERT_SEND_IF_ASKED: + if (!this->ike_sa->has_condition(this->ike_sa, COND_CERTREQ_SEEN)) + { + break; + } + /* FALL */ + case CERT_ALWAYS_SEND: + { + cert_payload_t *payload; + enumerator_t *enumerator; + certificate_t *cert; + auth_rule_t type; + auth_cfg_t *auth; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (!cert) + { + break; + } + payload = cert_payload_create_from_cert(CERTIFICATE_V1, cert); + if (!payload) + { + break; + } + DBG1(DBG_IKE, "sending end entity cert \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + + enumerator = auth->create_enumerator(auth); + while (enumerator->enumerate(enumerator, &type, &cert)) + { + if (type == AUTH_RULE_IM_CERT) + { + payload = cert_payload_create_from_cert(CERTIFICATE_V1, cert); + if (payload) + { + DBG1(DBG_IKE, "sending issuer cert \"%Y\"", + cert->get_subject(cert)); + message->add_payload(message, (payload_t*)payload); + } + } + } + enumerator->destroy(enumerator); + } + } +} + +METHOD(task_t, build_i, status_t, + private_ike_cert_post_v1_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + if (this->state == CR_AUTH) + { + build_certs(this, message); + return SUCCESS; + } + return NEED_MORE; + case AGGRESSIVE: + if (this->state == CR_AUTH) + { + build_certs(this, message); + return SUCCESS; + } + return NEED_MORE; + default: + return FAILED; + } +} + +METHOD(task_t, process_r, status_t, + private_ike_cert_post_v1_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + return NEED_MORE; + case CR_KE: + return NEED_MORE; + case CR_AUTH: + return NEED_MORE; + } + } + case AGGRESSIVE: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + return NEED_MORE; + case CR_AUTH: + return SUCCESS; + default: + return FAILED; + } + } + default: + return FAILED; + } +} + +METHOD(task_t, build_r, status_t, + private_ike_cert_post_v1_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + switch (this->state) + { + case CR_SA: + this->state = CR_KE; + return NEED_MORE; + case CR_KE: + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + build_certs(this, message); + return SUCCESS; + } + case AGGRESSIVE: + switch (this->state) + { + case CR_SA: + build_certs(this, message); + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + return SUCCESS; + default: + return FAILED; + } + default: + return FAILED; + } +} + +METHOD(task_t, process_i, status_t, + private_ike_cert_post_v1_t *this, message_t *message) +{ + switch (message->get_exchange_type(message)) + { + case ID_PROT: + { + switch (this->state) + { + case CR_SA: + if (!use_certs(this, message)) + { + return SUCCESS; + } + this->state = CR_KE; + return NEED_MORE; + case CR_KE: + this->state = CR_AUTH; + return NEED_MORE; + case CR_AUTH: + return SUCCESS; + default: + return FAILED; + } + break; + } + case AGGRESSIVE: + { + if (!use_certs(this, message)) + { + return SUCCESS; + } + return SUCCESS; + } + default: + return FAILED; + } +} + +METHOD(task_t, get_type, task_type_t, + private_ike_cert_post_v1_t *this) +{ + return TASK_IKE_CERT_POST_V1; +} + +METHOD(task_t, migrate, void, + private_ike_cert_post_v1_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_ike_cert_post_v1_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +ike_cert_post_v1_t *ike_cert_post_v1_create(ike_sa_t *ike_sa, bool initiator) +{ + private_ike_cert_post_v1_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .state = CR_SA, + ); + if (initiator) + { + this->public.task.process = _process_i; + this->public.task.build = _build_i; + } + else + { + this->public.task.process = _process_r; + this->public.task.build = _build_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/tasks/ike_cert_post_v1.h b/src/libcharon/sa/tasks/ike_cert_post_v1.h new file mode 100644 index 000000000..58b7aa78f --- /dev/null +++ b/src/libcharon/sa/tasks/ike_cert_post_v1.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup ike_cert_post_v1 ike_cert_post_v1 + * @{ @ingroup tasks + */ + +#ifndef IKE_CERT_POST_V1_H_ +#define IKE_CERT_POST_V1_H_ + +typedef struct ike_cert_post_v1_t ike_cert_post_v1_t; + +#include +#include +#include + +/** + * IKE_CERT_POST_V1, IKEv1 certificate processing after authentication. + */ +struct ike_cert_post_v1_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new ike_cert_post_v1 task. + * + * The initiator parameter means the original initiator, not the initiator + * of the certificate request. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task is the original initiator + * @return ike_cert_post_v1 task to handle by the task_manager + */ +ike_cert_post_v1_t *ike_cert_post_v1_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** IKE_CERT_POST_V1_H_ @}*/ From 6f6380e670a6f078d673ad276baf67044dbbc8f0 Mon Sep 17 00:00:00 2001 From: Andreas Steffen Date: Tue, 6 Dec 2011 15:15:40 +0100 Subject: [PATCH 221/534] use untoh64 instead of non-portable be64toh --- src/libcharon/encoding/payloads/transform_attribute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 6a6451eb2..a11ee98a4 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -199,7 +199,7 @@ METHOD(transform_attribute_t, get_value, u_int64_t, } memcpy(((char*)&value) + sizeof(value) - this->attribute_value.len, this->attribute_value.ptr, this->attribute_value.len); - return be64toh(value); + return untoh64((char*)&value); } METHOD(transform_attribute_t, get_attribute_type, u_int16_t, From 5d1eeec297de5009056d71e65c336987ee0fe10f Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Wed, 7 Dec 2011 13:30:53 +0100 Subject: [PATCH 222/534] Handle incoming delete messages --- src/libcharon/encoding/message.c | 25 +++++++++++++++++++++++++ src/libcharon/sa/task_manager_v1.c | 19 +++++++++++++++++-- src/libcharon/sa/tasks/child_delete.c | 20 +++++++++++++++++--- src/libcharon/sa/tasks/ike_delete.c | 10 +++++++++- 4 files changed, 68 insertions(+), 6 deletions(-) mode change 100644 => 100755 src/libcharon/sa/tasks/child_delete.c mode change 100644 => 100755 src/libcharon/sa/tasks/ike_delete.c diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 5b79ac733..91131ad22 100755 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -590,6 +590,27 @@ static payload_order_t informational_i_order_v1[] = { {VENDOR_ID_V1, 0}, }; +/** + * Message rule for INFORMATIONAL_V1 from responder. + */ +static payload_rule_t informational_r_rules_v1[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL_V1 from responder. + */ +static payload_order_t informational_r_order_v1[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {DELETE_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + /** * Message rule for QUICK_MODE from initiator. */ @@ -737,6 +758,10 @@ static message_rule_t message_rules[] = { countof(informational_i_rules_v1), informational_i_rules_v1, countof(informational_i_order_v1), informational_i_order_v1, }, + {INFORMATIONAL_V1, FALSE, TRUE, + countof(informational_r_rules_v1), informational_r_rules_v1, + countof(informational_r_order_v1), informational_r_order_v1, + }, {QUICK_MODE, TRUE, TRUE, countof(quick_mode_i_rules), quick_mode_i_rules, countof(quick_mode_i_order), quick_mode_i_order, diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 3d8229c05..a196b2abc 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -19,13 +19,16 @@ #include #include +#include #include #include #include +#include #include #include #include #include +#include #include #include @@ -546,7 +549,19 @@ static status_t process_request(private_task_manager_t *this, } case DELETE_V1: { - /* TODO-IKEv1: Delete payload handling. */ + delete_payload_t *delete; + delete = (delete_payload_t*)payload; + + if (delete->get_protocol_id(delete) == PROTO_IKE) + { + task = (task_t*)ike_delete_create(this->ike_sa, + FALSE); + } + else + { + task = (task_t*)child_delete_create(this->ike_sa, + PROTO_NONE, 0); + } break; } default: @@ -554,7 +569,7 @@ static status_t process_request(private_task_manager_t *this, } if (task) { - break; + this->passive_tasks->insert_last(this->passive_tasks, task); } } enumerator->destroy(enumerator); diff --git a/src/libcharon/sa/tasks/child_delete.c b/src/libcharon/sa/tasks/child_delete.c old mode 100644 new mode 100755 index c5151abf1..455e06b7a --- a/src/libcharon/sa/tasks/child_delete.c +++ b/src/libcharon/sa/tasks/child_delete.c @@ -65,6 +65,11 @@ struct private_child_delete_t { * CHILD_SAs which get deleted */ linked_list_t *child_sas; + + /** + * CHILD_SAs which get deleted + */ + payload_type_t payload_type; }; /** @@ -87,7 +92,7 @@ static void build_payloads(private_child_delete_t *this, message_t *message) case PROTO_ESP: if (esp == NULL) { - esp = delete_payload_create(DELETE, PROTO_ESP); + esp = delete_payload_create(this->payload_type, PROTO_ESP); message->add_payload(message, (payload_t*)esp); } esp->add_spi(esp, spi); @@ -97,7 +102,7 @@ static void build_payloads(private_child_delete_t *this, message_t *message) case PROTO_AH: if (ah == NULL) { - ah = delete_payload_create(DELETE, PROTO_AH); + ah = delete_payload_create(this->payload_type, PROTO_AH); message->add_payload(message, (payload_t*)ah); } ah->add_spi(ah, spi); @@ -127,7 +132,7 @@ static void process_payloads(private_child_delete_t *this, message_t *message) payloads = message->create_payload_enumerator(message); while (payloads->enumerate(payloads, &payload)) { - if (payload->get_type(payload) == DELETE) + if (payload->get_type(payload) == this->payload_type) { delete_payload = (delete_payload_t*)payload; protocol = delete_payload->get_protocol_id(delete_payload); @@ -387,5 +392,14 @@ child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, this->public.task.process = _process_r; this->initiator = FALSE; } + + if (ike_sa->get_version(ike_sa) == IKEV2) + { + this->payload_type = DELETE; + } + else + { + this->payload_type = DELETE_V1; + } return &this->public; } diff --git a/src/libcharon/sa/tasks/ike_delete.c b/src/libcharon/sa/tasks/ike_delete.c old mode 100644 new mode 100755 index 29ac87258..dccd85892 --- a/src/libcharon/sa/tasks/ike_delete.c +++ b/src/libcharon/sa/tasks/ike_delete.c @@ -114,7 +114,15 @@ METHOD(task_t, process_r, status_t, case IKE_ESTABLISHED: this->ike_sa->set_state(this->ike_sa, IKE_DELETING); this->ike_sa->reestablish(this->ike_sa); - return NEED_MORE; + if (this->ike_sa->get_version(this->ike_sa) == IKEV2) + { + return NEED_MORE; + } + else + { + /* Dont send message to other side */ + return DESTROY_ME; + } case IKE_REKEYING: this->rekeyed = TRUE; break; From 279258787542652739e282e8dd2dec346c04fc99 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 7 Dec 2011 14:52:02 +0100 Subject: [PATCH 223/534] Implemented IKEv1 PSK HASH payload processing in separated authenticator --- src/libcharon/Makefile.am | 1 + .../sa/authenticators/psk_v1_authenticator.c | 145 ++++++++++++++++++ .../sa/authenticators/psk_v1_authenticator.h | 53 +++++++ 3 files changed, 199 insertions(+) create mode 100644 src/libcharon/sa/authenticators/psk_v1_authenticator.c create mode 100644 src/libcharon/sa/authenticators/psk_v1_authenticator.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index d9e5a54b2..eb58768f5 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -64,6 +64,7 @@ sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ sa/authenticators/eap/eap_manager.c sa/authenticators/eap/eap_manager.h \ sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \ sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \ +sa/authenticators/psk_v1_authenticator.c sa/authenticators/psk_v1_authenticator.h \ sa/authenticators/xauth_authenticator.c sa/authenticators/xauth_authenticator.h \ sa/authenticators/xauth/xauth_method.c sa/authenticators/xauth/xauth_method.h \ sa/authenticators/xauth/xauth_manager.c sa/authenticators/xauth/xauth_manager.h \ diff --git a/src/libcharon/sa/authenticators/psk_v1_authenticator.c b/src/libcharon/sa/authenticators/psk_v1_authenticator.c new file mode 100644 index 000000000..ecce92268 --- /dev/null +++ b/src/libcharon/sa/authenticators/psk_v1_authenticator.c @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "psk_v1_authenticator.h" + +#include +#include +#include + +typedef struct private_psk_v1_authenticator_t private_psk_v1_authenticator_t; + +/** + * Private data of an psk_v1_authenticator_t object. + */ +struct private_psk_v1_authenticator_t { + + /** + * Public authenticator_t interface. + */ + psk_v1_authenticator_t public; + + /** + * Assigned IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * TRUE if we are initiator + */ + bool initiator; + + /** + * DH key exchange + */ + diffie_hellman_t *dh; + + /** + * Others DH public value + */ + chunk_t dh_value; + + /** + * Encoded SA payload, without fixed header + */ + chunk_t sa_payload; +}; + +METHOD(authenticator_t, build, status_t, + private_psk_v1_authenticator_t *this, message_t *message) +{ + hash_payload_t *hash_payload; + keymat_v1_t *keymat; + chunk_t hash, dh; + + this->dh->get_my_public_value(this->dh, &dh); + keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); + hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, + this->ike_sa->get_my_id(this->ike_sa)); + free(dh.ptr); + + hash_payload = hash_payload_create(HASH_V1); + hash_payload->set_hash(hash_payload, hash); + message->add_payload(message, &hash_payload->payload_interface); + free(hash.ptr); + + return SUCCESS; +} + +METHOD(authenticator_t, process, status_t, + private_psk_v1_authenticator_t *this, message_t *message) +{ + hash_payload_t *hash_payload; + keymat_v1_t *keymat; + chunk_t hash, dh; + + hash_payload = (hash_payload_t*)message->get_payload(message, HASH_V1); + if (!hash_payload) + { + DBG1(DBG_IKE, "HASH payload missing in message"); + return FAILED; + } + + this->dh->get_my_public_value(this->dh, &dh); + keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); + hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, + this->ike_sa->get_other_id(this->ike_sa)); + free(dh.ptr); + + if (chunk_equals(hash, hash_payload->get_hash(hash_payload))) + { + free(hash.ptr); + return SUCCESS; + } + free(hash.ptr); + DBG1(DBG_IKE, "calculated HASH does not match HASH payload"); + return FAILED; +} + +METHOD(authenticator_t, destroy, void, + private_psk_v1_authenticator_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload) +{ + private_psk_v1_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .dh = dh, + .dh_value = dh_value, + .sa_payload = sa_payload, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/authenticators/psk_v1_authenticator.h b/src/libcharon/sa/authenticators/psk_v1_authenticator.h new file mode 100644 index 000000000..1103ee62f --- /dev/null +++ b/src/libcharon/sa/authenticators/psk_v1_authenticator.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup psk_v1_authenticator psk_v1_authenticator + * @{ @ingroup authenticators + */ + +#ifndef PSK_V1_AUTHENTICATOR_H_ +#define PSK_V1_AUTHENTICATOR_H_ + +typedef struct psk_v1_authenticator_t psk_v1_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using pre-shared keys for IKEv1. + */ +struct psk_v1_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to build PSK signatures. + * + * @param ike_sa associated IKE_SA + * @param initiator TRUE if we are the IKE_SA initiator + * @param dh diffie hellman key exchange + * @param dh_value others public diffie hellman value + * @param sa_payload generated SA payload data, without payload header + * @return PSK authenticator + */ +psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload); + +#endif /** PSK_V1_AUTHENTICATOR_H_ @}*/ From 7c27c914d4365e85830b8690fdfa912b848a9588 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 7 Dec 2011 14:08:06 +0000 Subject: [PATCH 224/534] Implemented IKEv1 pubkey SIG payload processing in an authenticator --- src/libcharon/Makefile.am | 1 + .../authenticators/pubkey_v1_authenticator.c | 207 ++++++++++++++++++ .../authenticators/pubkey_v1_authenticator.h | 52 +++++ 3 files changed, 260 insertions(+) create mode 100644 src/libcharon/sa/authenticators/pubkey_v1_authenticator.c create mode 100644 src/libcharon/sa/authenticators/pubkey_v1_authenticator.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index eb58768f5..bf409d26c 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -65,6 +65,7 @@ sa/authenticators/eap/eap_manager.c sa/authenticators/eap/eap_manager.h \ sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \ sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \ sa/authenticators/psk_v1_authenticator.c sa/authenticators/psk_v1_authenticator.h \ +sa/authenticators/pubkey_v1_authenticator.c sa/authenticators/pubkey_v1_authenticator.h \ sa/authenticators/xauth_authenticator.c sa/authenticators/xauth_authenticator.h \ sa/authenticators/xauth/xauth_method.c sa/authenticators/xauth/xauth_method.h \ sa/authenticators/xauth/xauth_manager.c sa/authenticators/xauth/xauth_manager.h \ diff --git a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c new file mode 100644 index 000000000..82fc8cf66 --- /dev/null +++ b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "pubkey_v1_authenticator.h" + +#include +#include +#include + +typedef struct private_pubkey_v1_authenticator_t private_pubkey_v1_authenticator_t; + +/** + * Private data of an pubkey_v1_authenticator_t object. + */ +struct private_pubkey_v1_authenticator_t { + + /** + * Public authenticator_t interface. + */ + pubkey_v1_authenticator_t public; + + /** + * Assigned IKE_SA + */ + ike_sa_t *ike_sa; + + /** + * TRUE if we are initiator + */ + bool initiator; + + /** + * DH key exchange + */ + diffie_hellman_t *dh; + + /** + * Others DH public value + */ + chunk_t dh_value; + + /** + * Encoded SA payload, without fixed header + */ + chunk_t sa_payload; +}; + +METHOD(authenticator_t, build, status_t, + private_pubkey_v1_authenticator_t *this, message_t *message) +{ + hash_payload_t *sig_payload; + chunk_t hash, sig, dh; + keymat_v1_t *keymat; + status_t status; + private_key_t *private; + identification_t *id; + auth_cfg_t *auth; + key_type_t type; + signature_scheme_t scheme; + + /* TODO-IKEv1: other key types */ + type = KEY_RSA; + scheme = SIGN_RSA_EMSA_PKCS1_NULL; + + id = this->ike_sa->get_my_id(this->ike_sa); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); + private = lib->credmgr->get_private(lib->credmgr, KEY_RSA, id, auth); + if (!private) + { + DBG1(DBG_IKE, "no private key found for '%Y'", id); + return NOT_FOUND; + } + + this->dh->get_my_public_value(this->dh, &dh); + keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); + hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); + free(dh.ptr); + + if (private->sign(private, scheme, hash, &sig)) + { + sig_payload = hash_payload_create(SIGNATURE_V1); + sig_payload->set_hash(sig_payload, sig); + free(sig.ptr); + message->add_payload(message, &sig_payload->payload_interface); + status = SUCCESS; + DBG1(DBG_IKE, "authentication of '%Y' (myself) successful", id); + } + else + { + DBG1(DBG_IKE, "authentication of '%Y' (myself) failed", id); + status = FAILED; + } + private->destroy(private); + free(hash.ptr); + + return status; +} + +METHOD(authenticator_t, process, status_t, + private_pubkey_v1_authenticator_t *this, message_t *message) +{ + chunk_t hash, sig, dh; + keymat_v1_t *keymat; + public_key_t *public; + hash_payload_t *sig_payload; + auth_cfg_t *auth, *current_auth; + enumerator_t *enumerator; + status_t status = NOT_FOUND; + key_type_t type; + signature_scheme_t scheme; + identification_t *id; + + /* TODO-IKEv1: currently RSA only */ + type = KEY_RSA; + scheme = SIGN_RSA_EMSA_PKCS1_NULL; + + sig_payload = (hash_payload_t*)message->get_payload(message, SIGNATURE_V1); + if (!sig_payload) + { + DBG1(DBG_IKE, "SIG payload missing in message"); + return FALSE; + } + + id = this->ike_sa->get_other_id(this->ike_sa); + this->dh->get_my_public_value(this->dh, &dh); + keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); + hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh, + this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); + free(dh.ptr); + + sig = sig_payload->get_hash(sig_payload); + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, type, + id, auth); + while (enumerator->enumerate(enumerator, &public, ¤t_auth)) + { + if (public->verify(public, scheme, hash, sig)) + { + DBG1(DBG_IKE, "authentication of '%Y' with %N successful", + id, key_type_names, type); + status = SUCCESS; + auth->merge(auth, current_auth, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); + break; + } + else + { + DBG1(DBG_IKE, "signature validation failed, looking for another key"); + status = FAILED; + } + } + enumerator->destroy(enumerator); + free(hash.ptr); + if (status != SUCCESS) + { + DBG1(DBG_IKE, "no trusted %N public key found for '%Y'", + key_type_names, type, id); + } + return status; +} + +METHOD(authenticator_t, destroy, void, + private_pubkey_v1_authenticator_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload) +{ + private_pubkey_v1_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .build = _build, + .process = _process, + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .dh = dh, + .dh_value = dh_value, + .sa_payload = sa_payload, + ); + + return &this->public; +} diff --git a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h new file mode 100644 index 000000000..ed6d77cc0 --- /dev/null +++ b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup pubkey_v1_authenticator pubkey_v1_authenticator + * @{ @ingroup authenticators + */ + +#ifndef PUBKEY_V1_AUTHENTICATOR_H_ +#define PUBKEY_V1_AUTHENTICATOR_H_ + +typedef struct pubkey_v1_authenticator_t pubkey_v1_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using public keys for IKEv1. + */ +struct pubkey_v1_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to build and verify public key signatures. + * + * @param ike_sa associated IKE_SA + * @param dh diffie hellman key exchange + * @param dh_value others public diffie hellman value + * @param sa_payload generated SA payload data, without payload header + * @return pubkey authenticator + */ +pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload); + +#endif /** PUBKEY_V1_AUTHENTICATOR_H_ @}*/ From 76fe7de3fd0b39e7161f6081920d1e2d5edb9317 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 7 Dec 2011 14:09:34 +0000 Subject: [PATCH 225/534] Added a factory function for IKEv1 authenticators --- .../sa/authenticators/authenticator.c | 25 +++++++++++++++++++ .../sa/authenticators/authenticator.h | 19 ++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/authenticators/authenticator.c b/src/libcharon/sa/authenticators/authenticator.c index 83f5fbaad..c69a5d92a 100644 --- a/src/libcharon/sa/authenticators/authenticator.c +++ b/src/libcharon/sa/authenticators/authenticator.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include @@ -95,3 +97,26 @@ authenticator_t *authenticator_create_verifier( } } +/** + * Described in header. + */ +authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, + auth_method_t auth_method, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload) +{ + switch (auth_method) + { + case AUTH_PSK: + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_RESP_PSK: + return (authenticator_t*)psk_v1_authenticator_create(ike_sa, + initiator, dh, dh_value, sa_payload); + case AUTH_RSA: + case AUTH_XAUTH_INIT_RSA: + case AUTH_XAUTH_RESP_RSA: + return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa, + initiator, dh, dh_value, sa_payload); + default: + return NULL; + } +} diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticators/authenticator.h index 1161583c9..3c1733388 100644 --- a/src/libcharon/sa/authenticators/authenticator.h +++ b/src/libcharon/sa/authenticators/authenticator.h @@ -148,7 +148,7 @@ struct authenticator_t { }; /** - * Create an authenticator to build signatures. + * Create an IKEv2 authenticator to build signatures. * * @param ike_sa associated ike_sa * @param cfg authentication configuration @@ -166,7 +166,7 @@ authenticator_t *authenticator_create_builder( char reserved[3]); /** - * Create an authenticator to verify signatures. + * Create an IKEv2 authenticator to verify signatures. * * @param ike_sa associated ike_sa * @param message message containing authentication data @@ -183,4 +183,19 @@ authenticator_t *authenticator_create_verifier( chunk_t received_init, chunk_t sent_init, char reserved[3]); +/** + * Create an IKEv1 authenticator to build and verify signatures or hash payloads. + * + * @param ike_sa associated IKE_SA + * @param initiator TRUE if we are the IKE_SA initiator + * @param auth_method negotiated authentication method to use + * @param dh diffie hellman key exchange + * @param dh_value others public diffie hellman value + * @param sa_payload generated SA payload data, without payload header + * @return authenticator, NULL if not supported + */ +authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, + auth_method_t auth_method, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload); + #endif /** AUTHENTICATOR_H_ @}*/ From fb8bc6a764473050cc742be91effac8c6d771c62 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 7 Dec 2011 14:10:05 +0000 Subject: [PATCH 226/534] Use authenticators in IKEv1 main mode --- src/libcharon/sa/tasks/main_mode.c | 275 +++-------------------------- 1 file changed, 28 insertions(+), 247 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 60ebdf21b..ab38ec29b 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -117,6 +117,11 @@ struct private_main_mode_t { */ auth_method_t auth_method; + /** + * Authenticator to use + */ + authenticator_t *authenticator; + /** states of main mode */ enum { MM_INIT, @@ -179,204 +184,6 @@ static bool save_sa_payload(private_main_mode_t *this, message_t *message) return FALSE; } -/** - * Add signature payload to message - */ -static bool add_signature(private_main_mode_t *this, - message_t *message, chunk_t hash) -{ - chunk_t auth_data; - bool status = FALSE; - private_key_t *private; - identification_t *id; - auth_cfg_t *auth; - hash_payload_t *signature_payload; - signature_scheme_t scheme; - - id = this->ike_sa->get_my_id(this->ike_sa); - auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, auth); - if (private == NULL) - { - DBG1(DBG_IKE, "no private key found for '%Y' type %d", id, id->get_type(id)); - free(hash.ptr); - return FALSE; - } - - switch (private->get_type(private)) - { - case KEY_RSA: - scheme = SIGN_RSA_EMSA_PKCS1_NULL; - break; - - default: - DBG1(DBG_IKE, "private key of type %N not supported", - key_type_names, private->get_type(private)); - private->destroy(private); - free(hash.ptr); - return FALSE; - } - - if (private->sign(private, scheme, hash, &auth_data)) - { - signature_payload = hash_payload_create(SIGNATURE_V1); - signature_payload->set_hash(signature_payload, auth_data); - chunk_free(&auth_data); - message->add_payload(message, (payload_t*)signature_payload); - status = TRUE; - } - - DBG1(DBG_IKE, "authentication of '%Y' (myself) %s", id, - (status == TRUE)? "successful":"failed"); - - free(hash.ptr); - private->destroy(private); - return status; -} - - -/** - * Build main mode hash or signature payloads - */ -static bool build_hash(private_main_mode_t *this, bool initiator, - message_t *message, identification_t *id) -{ - hash_payload_t *hash_payload; - chunk_t hash, dh; - - this->dh->get_my_public_value(this->dh, &dh); - hash = this->keymat->get_hash(this->keymat, initiator, dh, this->dh_value, - this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); - free(dh.ptr); - - switch (this->auth_method) - { - case AUTH_RSA: - case AUTH_XAUTH_INIT_RSA: - case AUTH_XAUTH_RESP_RSA: - { - return add_signature(this, message, hash); - } - default: - { - hash_payload = hash_payload_create(HASH_V1); - hash_payload->set_hash(hash_payload, hash); - message->add_payload(message, &hash_payload->payload_interface); - free(hash.ptr); - break; - } - } - - return TRUE; -} - -/** - * Verify main mode hash payload - */ -static bool verify_hash(private_main_mode_t *this, bool initiator, - message_t *message, identification_t *id) -{ - hash_payload_t *hash_payload; - chunk_t hash, dh; - bool equal; - - hash_payload = (hash_payload_t*)message->get_payload(message, - HASH_V1); - if (!hash_payload) - { - DBG1(DBG_IKE, "HASH payload missing in message"); - return FALSE; - } - hash = hash_payload->get_hash(hash_payload); - this->dh->get_my_public_value(this->dh, &dh); - hash = this->keymat->get_hash(this->keymat, initiator, this->dh_value, dh, - this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); - free(dh.ptr); - equal = chunk_equals(hash, hash_payload->get_hash(hash_payload)); - free(hash.ptr); - if (!equal) - { - DBG1(DBG_IKE, "calculated HASH does not match HASH payload"); - } - return equal; -} - -/** - * Verify main mode signature payload - */ -static bool verify_signature(private_main_mode_t *this, bool initiator, - message_t *message, identification_t *id) -{ - chunk_t hash, dh; - public_key_t *public; - hash_payload_t *signature_payload; - chunk_t auth_data; - auth_cfg_t *auth, *current_auth; - enumerator_t *enumerator; - key_type_t key_type = KEY_ECDSA; - signature_scheme_t scheme; - status_t status = NOT_FOUND; - - signature_payload = (hash_payload_t*)message->get_payload(message, SIGNATURE_V1); - if (!signature_payload) - { - DBG1(DBG_IKE, "no signature_payload found"); - return FALSE; - } - - switch (this->auth_method) - { - case AUTH_RSA: - case AUTH_XAUTH_INIT_RSA: - case AUTH_XAUTH_RESP_RSA: - key_type = KEY_RSA; - scheme = SIGN_RSA_EMSA_PKCS1_NULL; - break; - default: - /* TODO-IKEv1: other auth methods */ - DBG1(DBG_IKE, "unsupported auth method: %N", - auth_method_names, this->auth_method); - return FALSE; - } - - this->dh->get_my_public_value(this->dh, &dh); - hash = this->keymat->get_hash(this->keymat, initiator, this->dh_value, dh, - this->ike_sa->get_id(this->ike_sa), - this->sa_payload, id); - free(dh.ptr); - - auth_data = signature_payload->get_hash(signature_payload); - auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, - key_type, id, auth); - while (enumerator->enumerate(enumerator, &public, ¤t_auth)) - { - if (public->verify(public, scheme, hash, auth_data)) - { - DBG1(DBG_IKE, "authentication of '%Y' with %N successful", - id, auth_method_names, this->auth_method); - status = SUCCESS; - auth->merge(auth, current_auth, FALSE); - auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); - break; - } - else - { - status = NOT_FOUND; - DBG1(DBG_IKE, "signature validation failed, looking for another key"); - } - } - enumerator->destroy(enumerator); - if (status == NOT_FOUND) - { - DBG1(DBG_IKE, "no trusted %N public key found for '%Y'", - key_type_names, key_type, id); - } - - free(hash.ptr); - return status == SUCCESS; -} - /** * Generate and add NONCE, KE payload */ @@ -563,12 +370,11 @@ METHOD(task_t, build_i, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - if (!build_hash(this, TRUE, message, id)) + if (this->authenticator->build(this->authenticator, + message) != SUCCESS) { - DBG1(DBG_CFG, "failed to build hash"); return FAILED; } - this->state = MM_AUTH; return NEED_MORE; } @@ -691,28 +497,10 @@ METHOD(task_t, process_r, status_t, return FAILED; } - switch (this->auth_method) + if (this->authenticator->process(this->authenticator, + message) != SUCCESS) { - case AUTH_PSK: - case AUTH_XAUTH_INIT_PSK: - case AUTH_XAUTH_RESP_PSK: - if (!verify_hash(this, TRUE, message, id)) - { - return FAILED; - } - break; - case AUTH_RSA: - case AUTH_XAUTH_INIT_RSA: - case AUTH_XAUTH_RESP_RSA: - if (!verify_signature(this, TRUE, message, id)) - { - return FAILED; - } - break; - default: - DBG1(DBG_IKE, "unsupported auth method: %N", - auth_method_names, this->auth_method); - return FAILED; + return FAILED; } this->state = MM_AUTH; return NEED_MORE; @@ -775,11 +563,23 @@ static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, this->dh_value, nonce_i, nonce_r, id, this->auth_method, shared_key)) { DESTROY_IF(shared_key); + DBG1(DBG_IKE, "key derivation for %N failed", + auth_method_names, this->auth_method); return FALSE; } DESTROY_IF(shared_key); charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, nonce_i, nonce_r, NULL); + + this->authenticator = authenticator_create_v1(this->ike_sa, this->initiator, + this->auth_method, this->dh, + this->dh_value, this->sa_payload); + if (!this->authenticator) + { + DBG1(DBG_IKE, "negotiated authentication method %N not supported", + auth_method_names, this->auth_method); + return FALSE; + } return TRUE; } @@ -806,7 +606,6 @@ METHOD(task_t, build_r, status_t, } if (!derive_keys(this, this->nonce_i, this->nonce_r)) { - DBG1(DBG_IKE, "key derivation failed"); return FAILED; } return NEED_MORE; @@ -828,9 +627,9 @@ METHOD(task_t, build_r, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - if (!build_hash(this, FALSE, message, id)) + if (this->authenticator->build(this->authenticator, + message) != SUCCESS) { - DBG1(DBG_CFG, "failed to build hash"); return FAILED; } @@ -923,7 +722,6 @@ METHOD(task_t, process_i, status_t, } if (!derive_keys(this, this->nonce_i, this->nonce_r)) { - DBG1(DBG_IKE, "key derivation failed"); return FAILED; } return NEED_MORE; @@ -949,28 +747,10 @@ METHOD(task_t, process_i, status_t, } this->ike_sa->set_other_id(this->ike_sa, id); - switch (this->auth_method) + if (this->authenticator->process(this->authenticator, + message) != SUCCESS) { - case AUTH_PSK: - case AUTH_XAUTH_INIT_PSK: - case AUTH_XAUTH_RESP_PSK: - if (!verify_hash(this, FALSE, message, id)) - { - return FAILED; - } - break; - case AUTH_RSA: - case AUTH_XAUTH_INIT_RSA: - case AUTH_XAUTH_RESP_RSA: - if (!verify_signature(this, FALSE, message, id)) - { - return FAILED; - } - break; - default: - DBG1(DBG_IKE, "unsupported auth method: %N", - auth_method_names, this->auth_method); - return FAILED; + return FAILED; } /* TODO-IKEv1: check for XAUTH rounds, queue them */ @@ -1028,6 +808,7 @@ METHOD(task_t, destroy, void, DESTROY_IF(this->peer_cfg); DESTROY_IF(this->proposal); DESTROY_IF(this->dh); + DESTROY_IF(this->authenticator); free(this->dh_value.ptr); free(this->nonce_i.ptr); free(this->nonce_r.ptr); From 9bb4de1d83babe724d846ca5442cdc12da065f77 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 7 Dec 2011 17:41:16 +0100 Subject: [PATCH 227/534] En- and decode DH group attribute in quick mode SA payloads --- .../encoding/payloads/proposal_substructure.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index ca36206cb..d5778fab3 100755 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -684,6 +684,10 @@ static void add_to_proposal_v1_esp(proposal_t *proposal, proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, get_alg_from_ikev1(INTEGRITY_ALGORITHM, value), 0); break; + case TATTR_PH2_GROUP: + proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + value, 0); + break; default: /* TODO-IKEv1: lifetimes other attributes */ break; @@ -1076,6 +1080,15 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, } enumerator->destroy(enumerator); + enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_GROUP, alg)); + } + enumerator->destroy(enumerator); + transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp))); From 5adf855e3dd2484715082d3d612c051e6a5f78bb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 7 Dec 2011 17:43:58 +0100 Subject: [PATCH 228/534] Add support for KE payloads in IKEv1 quick mode (PFS) --- src/libcharon/sa/tasks/quick_mode.c | 87 +++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index cfbfb1386..dedcd66a2 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -96,6 +97,11 @@ struct private_quick_mode_t { */ keymat_v1_t *keymat; + /** + * DH exchange, when PFS is in use + */ + diffie_hellman_t *dh; + /** * Negotiated lifetime of new SA */ @@ -134,7 +140,7 @@ static bool install(private_quick_mode_t *this) tsr = linked_list_create(); tsi->insert_last(tsi, this->tsi); tsr->insert_last(tsr, this->tsr); - if (this->keymat->derive_child_keys(this->keymat, this->proposal, NULL, + if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh, this->spi_i, this->spi_r, this->nonce_i, this->nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) { @@ -186,7 +192,7 @@ static bool install(private_quick_mode_t *this) } charon->bus->child_keys(charon->bus, this->child_sa, this->initiator, - NULL, this->nonce_i, this->nonce_r); + this->dh, this->nonce_i, this->nonce_r); /* add to IKE_SA, and remove from task */ this->child_sa->set_state(this->child_sa, CHILD_INSTALLED); @@ -252,6 +258,35 @@ static bool get_nonce(private_quick_mode_t *this, chunk_t *nonce, return TRUE; } +/** + * Add KE payload to message + */ +static void add_ke(private_quick_mode_t *this, message_t *message) +{ + ke_payload_t *ke_payload; + + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, this->dh); + message->add_payload(message, &ke_payload->payload_interface); +} + +/** + * Get DH value from a KE payload + */ +static bool get_ke(private_quick_mode_t *this, message_t *message) +{ + ke_payload_t *ke_payload; + + ke_payload = (ke_payload_t*)message->get_payload(message, KEY_EXCHANGE_V1); + if (!ke_payload) + { + DBG1(DBG_IKE, "KE payload missing"); + return FALSE; + } + this->dh->set_other_public_value(this->dh, + ke_payload->get_key_exchange_data(ke_payload)); + return TRUE; +} + /** * Select a traffic selector from configuration */ @@ -487,6 +522,7 @@ METHOD(task_t, build_i, status_t, linked_list_t *list; proposal_t *proposal; ipsec_mode_t mode; + diffie_hellman_group_t group; bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); this->child_sa = child_sa_create( @@ -494,7 +530,7 @@ METHOD(task_t, build_i, status_t, this->ike_sa->get_other_host(this->ike_sa), this->config, 0, udp); - list = this->config->get_proposals(this->config, TRUE); + list = this->config->get_proposals(this->config, FALSE); this->spi_i = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); if (!this->spi_i) @@ -527,6 +563,20 @@ METHOD(task_t, build_i, status_t, { return FAILED; } + + group = this->config->get_dh_group(this->config); + if (group != MODP_NONE) + { + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + group); + if (!this->dh) + { + DBG1(DBG_IKE, "configured DH group %N not supported", + diffie_hellman_group_names, group); + return FAILED; + } + add_ke(this, message); + } this->tsi = select_ts(this, TRUE); this->tsr = select_ts(this, FALSE); if (!this->tsi || !this->tsr) @@ -571,6 +621,7 @@ METHOD(task_t, process_r, status_t, linked_list_t *tsi, *tsr, *list; peer_cfg_t *peer_cfg; host_t *me, *other; + u_int16_t group; bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); if (!get_ts(this, message)) @@ -611,7 +662,7 @@ METHOD(task_t, process_r, status_t, } list = sa_payload->get_proposals(sa_payload); this->proposal = this->config->select_proposal(this->config, - list, TRUE, FALSE); + list, FALSE, FALSE); list->destroy_offset(list, offsetof(proposal_t, destroy)); get_lifetimes(this); @@ -629,6 +680,22 @@ METHOD(task_t, process_r, status_t, return FAILED; } + if (this->proposal->get_algorithm(this->proposal, + DIFFIE_HELLMAN_GROUP, &group, NULL)) + { + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, + group); + if (!this->dh) + { + DBG1(DBG_IKE, "negotiated DH group %N not supported", + diffie_hellman_group_names, group); + return FAILED; + } + if (!get_ke(this, message)) + { + return FAILED; + } + } this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), @@ -697,6 +764,11 @@ METHOD(task_t, build_r, status_t, { return FAILED; } + if (this->dh) + { + add_ke(this, message); + } + add_ts(this, message); this->state = QM_NEGOTIATED; @@ -726,7 +798,7 @@ METHOD(task_t, process_i, status_t, } list = sa_payload->get_proposals(sa_payload); this->proposal = this->config->select_proposal(this->config, - list, TRUE, FALSE); + list, FALSE, FALSE); list->destroy_offset(list, offsetof(proposal_t, destroy)); if (!this->proposal) { @@ -741,6 +813,10 @@ METHOD(task_t, process_i, status_t, { return FAILED; } + if (this->dh && !get_ke(this, message)) + { + return FAILED; + } if (!get_ts(this, message)) { return FAILED; @@ -779,6 +855,7 @@ METHOD(task_t, destroy, void, DESTROY_IF(this->proposal); DESTROY_IF(this->child_sa); DESTROY_IF(this->config); + DESTROY_IF(this->dh); free(this); } From 1755ac0617b340f1ba10bc43e96f8bee874db539 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 7 Dec 2011 17:51:35 +0100 Subject: [PATCH 229/534] Cleaned up quick mode notify processing --- src/libcharon/sa/tasks/quick_mode.c | 54 ++++++++++++++++++----------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index dedcd66a2..6b6a93505 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -595,24 +595,45 @@ METHOD(task_t, build_i, status_t, } } -status_t process_notify(notify_payload_t *notify) +/** + * Check for notify errors, return TRUE if error found + */ +static bool has_notify_errors(private_quick_mode_t *this, message_t *message) { - if(notify->get_notify_type(notify) < 16384) + enumerator_t *enumerator; + payload_t *payload; + bool err = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) { - DBG1(DBG_IKE, "Received %N error notification.", notify_type_names, notify->get_notify_type(notify)); - return FAILED; + if (payload->get_type(payload) == NOTIFY_V1) + { + notify_payload_t *notify; + notify_type_t type; + + notify = (notify_payload_t*)payload; + type = notify->get_notify_type(notify); + if (type < 16384) + { + DBG1(DBG_IKE, "received %N error notify", + notify_type_names, type); + err = TRUE; + } + else + { + DBG1(DBG_IKE, "received %N notify", notify_type_names, type); + } + } } - DBG1(DBG_IKE, "Received %N notification.", notify_type_names, notify->get_notify_type(notify)); - return SUCCESS; + enumerator->destroy(enumerator); + + return err; } METHOD(task_t, process_r, status_t, private_quick_mode_t *this, message_t *message) { - enumerator_t *enumerator; - payload_t *payload; - status_t status; - switch (this->state) { case QM_INIT: @@ -705,19 +726,10 @@ METHOD(task_t, process_r, status_t, } case QM_NEGOTIATED: { - enumerator = message->create_payload_enumerator(message); - while(enumerator->enumerate(enumerator, &payload)) + if (has_notify_errors(this, message)) { - if(payload->get_type(payload) == NOTIFY_V1) - { - status = process_notify((notify_payload_t *)payload); - if(status != SUCCESS) - { - return status; - } - } + return FAILED; } - enumerator->destroy(enumerator); if (!install(this)) { return FAILED; From 751bd02e98a8802139755c58148f9e5da14ce143 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 8 Dec 2011 13:47:16 +0100 Subject: [PATCH 230/534] Added retransmissions for initiator. --- src/libcharon/sa/task_manager_v1.c | 33 +++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index a196b2abc..41cd8a7c6 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -103,9 +103,9 @@ struct private_task_manager_t { u_int32_t mid; /** - * Hash of a previously received message + * Sequence number of the last sent message */ - u_int32_t hash; + u_int32_t seqnr; /** * how many times we have retransmitted so far @@ -197,9 +197,10 @@ static bool activate_task(private_task_manager_t *this, task_type_t type) } METHOD(task_manager_t, retransmit, status_t, - private_task_manager_t *this, u_int32_t message_id) + private_task_manager_t *this, u_int32_t message_seqnr) { - if (message_id == this->initiating.mid) + /* this.initiating packet used as marker for received response */ + if (message_seqnr == this->initiating.seqnr && this->initiating.packet ) { u_int32_t timeout; packet_t *packet; @@ -223,14 +224,14 @@ METHOD(task_manager_t, retransmit, status_t, if (this->initiating.retransmitted) { - DBG1(DBG_IKE, "retransmit %d of request with message ID %d", - this->initiating.retransmitted, message_id); + DBG1(DBG_IKE, "retransmit %d of request with message ID %d seqnr (%d)", + this->initiating.retransmitted, this->initiating.mid, message_seqnr); } packet = this->initiating.packet->clone(this->initiating.packet); charon->sender->send(charon->sender, packet); this->initiating.retransmitted++; - job = (job_t*)retransmit_job_create(this->initiating.mid, + job = (job_t*)retransmit_job_create(this->initiating.seqnr, this->ike_sa->get_id(this->ike_sa)); lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout); } @@ -247,6 +248,7 @@ METHOD(task_manager_t, initiate, status_t, status_t status; exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED; bool new_mid = FALSE; + bool expect_response = FALSE; if (!this->rng) { @@ -357,6 +359,7 @@ METHOD(task_manager_t, initiate, status_t, task->destroy(task); break; case NEED_MORE: + expect_response = TRUE; /* processed, but task needs another exchange */ break; case FAILED: @@ -378,6 +381,7 @@ METHOD(task_manager_t, initiate, status_t, /* update exchange type if a task changed it */ this->initiating.type = message->get_exchange_type(message); + this->initiating.seqnr++; status = this->ike_sa->generate_message(this->ike_sa, message, &this->initiating.packet); @@ -392,10 +396,19 @@ METHOD(task_manager_t, initiate, status_t, } message->destroy(message); - charon->sender->send(charon->sender, - this->initiating.packet->clone(this->initiating.packet)); + if (expect_response) + { + return retransmit(this, this->initiating.seqnr); + } + else + { + charon->sender->send(charon->sender, + this->initiating.packet->clone(this->initiating.packet)); - return SUCCESS; + this->initiating.packet->destroy(this->initiating.packet); + this->initiating.packet = NULL; + return SUCCESS; + } } /** From a064eaa8a63a7ed2b3d8b5f0807d791d9ed89f5c Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 9 Dec 2011 11:41:26 +0100 Subject: [PATCH 231/534] Handling of initial contact --- src/libcharon/sa/ike_sa.h | 5 +++ src/libcharon/sa/ike_sa_manager.c | 11 +++++++ src/libcharon/sa/tasks/main_mode.c | 51 ++++++++++++++++++++++++++++++ 3 files changed, 67 insertions(+) mode change 100644 => 100755 src/libcharon/sa/ike_sa.h mode change 100644 => 100755 src/libcharon/sa/ike_sa_manager.c diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h old mode 100644 new mode 100755 index 27eab5445..15fd35c25 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -153,6 +153,11 @@ enum ike_condition_t { * IKE_SA is stale, the peer is currently unreachable (MOBIKE) */ COND_STALE = (1<<7), + + /** + * Initial contact received + */ + COND_INIT_CONTACT_SEEN = (1<<8), }; /** diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c old mode 100644 new mode 100755 index ffbc2ec3b..776b2b7ae --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1358,6 +1358,17 @@ METHOD(ike_sa_manager_t, checkin, void, if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && entry->my_id == NULL && entry->other_id == NULL) { + if (ike_sa->get_version(ike_sa) == IKEV1) + { + /* If authenticated and received INITIAL_CONTACT, + * delete any existing IKE_SAs with that peer. */ + if (ike_sa->has_condition(ike_sa, COND_INIT_CONTACT_SEEN)) + { + this->public.check_uniqueness(&this->public, ike_sa, TRUE); + ike_sa->set_condition(ike_sa, COND_INIT_CONTACT_SEEN, FALSE); + } + } + entry->my_id = my_id->clone(my_id); entry->other_id = other_id->clone(other_id); if (!entry->other) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index ab38ec29b..e1f583cb8 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -263,6 +263,52 @@ static auth_method_t get_auth_method(private_main_mode_t *this) return AUTH_RSA; } } +/** + * Check for notify errors, return TRUE if error found + */ +static bool has_notify_errors(private_main_mode_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool err = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY_V1) + { + notify_payload_t *notify; + notify_type_t type; + + notify = (notify_payload_t*)payload; + type = notify->get_notify_type(notify); + if (type < 16384) + { + DBG1(DBG_IKE, "received %N error notify", + notify_type_names, type); + err = TRUE; + } + else if (type == INITIAL_CONTACT_IKEV1) + { + if (!this->initiator && this->state == MM_AUTH) + { + /* If authenticated and received INITIAL_CONTACT, + * delete any existing IKE_SAs with that peer. + * The delete takes place when the SA is checked in due + * to other id not known until the 3rd message.*/ + this->ike_sa->set_condition(this->ike_sa, COND_INIT_CONTACT_SEEN, TRUE); + } + } + else + { + DBG1(DBG_IKE, "received %N notify", notify_type_names, type); + } + } + } + enumerator->destroy(enumerator); + + return err; +} METHOD(task_t, build_i, status_t, private_main_mode_t *this, message_t *message) @@ -503,6 +549,11 @@ METHOD(task_t, process_r, status_t, return FAILED; } this->state = MM_AUTH; + + if (has_notify_errors(this, message)) + { + return FAILED; + } return NEED_MORE; } default: From 9ce5d0c0e8af70ca2a88483b57e6aaa47d2f2961 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 9 Dec 2011 15:43:36 +0100 Subject: [PATCH 232/534] added functions for getting/setting ISAKMP SPI to notify payload --- .../encoding/payloads/notify_payload.c | 33 +++++++++++++++++++ .../encoding/payloads/notify_payload.h | 18 ++++++++++ 2 files changed, 51 insertions(+) mode change 100644 => 100755 src/libcharon/encoding/payloads/notify_payload.c mode change 100644 => 100755 src/libcharon/encoding/payloads/notify_payload.h diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c old mode 100644 new mode 100755 index a72a0f37e..6b6c28de1 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -600,6 +600,37 @@ METHOD(notify_payload_t, set_spi, void, compute_length(this); } +METHOD(notify_payload_t, get_spi_data, chunk_t, + private_notify_payload_t *this) +{ + switch (this->protocol_id) + { + case PROTO_IKE: + if (this->spi.len == 16) + { + return this->spi; + } + default: + break; + } + return chunk_empty; +} + +METHOD(notify_payload_t, set_spi_data, void, + private_notify_payload_t *this, chunk_t spi) +{ + chunk_free(&this->spi); + switch (this->protocol_id) + { + case PROTO_IKE: + this->spi = chunk_clone(spi); + default: + break; + } + this->spi_size = this->spi.len; + compute_length(this); +} + METHOD(notify_payload_t, get_notification_data, chunk_t, private_notify_payload_t *this) { @@ -647,6 +678,8 @@ notify_payload_t *notify_payload_create(payload_type_t type) .set_notify_type = _set_notify_type, .get_spi = _get_spi, .set_spi = _set_spi, + .get_spi_data = _get_spi_data, + .set_spi_data = _set_spi_data, .get_notification_data = _get_notification_data, .set_notification_data = _set_notification_data, .destroy = _destroy, diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h old mode 100644 new mode 100755 index 9539231ca..2f5294ee3 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -209,6 +209,24 @@ struct notify_payload_t { */ void (*set_spi) (notify_payload_t *this, u_int32_t spi); + /** + * Returns the currently set spi of this payload. + * + * This is only valid for notifys with protocol ISAKMP + * + * @return SPI value + */ + chunk_t (*get_spi_data) (notify_payload_t *this); + + /** + * Sets the spi of this payload. + * + * This is only valid for notifys with protocol ISAKMP + * + * @param spi SPI value + */ + void (*set_spi_data) (notify_payload_t *this, chunk_t spi); + /** * Returns the currently set notification data of payload. * From 1390daae15b58848b75d3d7f2d44fc054f3da882 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 9 Dec 2011 15:49:07 +0100 Subject: [PATCH 233/534] Added status code to status_t New status_t enum to allow packets to be sent to peer in task_manager->process --- src/libstrongswan/utils.h | 5 +++++ 1 file changed, 5 insertions(+) mode change 100644 => 100755 src/libstrongswan/utils.h diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h old mode 100644 new mode 100755 index e5e4a10c0..826477c7f --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -299,6 +299,11 @@ enum status_t { * Another call to the method is required. */ NEED_MORE, + + /** + * Call failed, send error to other side. + */ + FAILED_SEND_ERROR, }; /** From fbbd439bf9830c5ca8994f4b4549f91abddddbad Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 9 Dec 2011 16:03:37 +0100 Subject: [PATCH 234/534] Added possibility to send notification if task_manager->process fails --- src/libcharon/sa/task_manager_v1.c | 120 ++++++++++++++++------------- 1 file changed, 68 insertions(+), 52 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 41cd8a7c6..d557d970e 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -500,6 +500,66 @@ static status_t build_response(private_task_manager_t *this, message_t *request) return SUCCESS; } +/** + * Send a notify in a separate INFORMATIONAL exchange back to the sender. + */ +static void send_notify_response(private_task_manager_t *this, + message_t *request, notify_type_t type, + chunk_t data, task_t *task) +{ + message_t *response; + packet_t *packet; + host_t *me, *other; + u_int32_t mid; + + if (request && request->get_exchange_type(request) == INFORMATIONAL_V1) + { /* don't respond to INFORMATIONAL requests to avoid a notify war */ + DBG1(DBG_IKE, "ignore malformed INFORMATIONAL request"); + return; + } + + response = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); + response->set_exchange_type(response, INFORMATIONAL_V1); + response->set_request(response, TRUE); + this->rng->get_bytes(this->rng, sizeof(mid), (void*)&mid); + response->set_message_id(response, mid); + + if (task) + { + /* Let the task build the response */ + if (task->build(task,response) != SUCCESS) + { + response->destroy(response); + return; + } + } + else + { + response->add_notify(response, FALSE, type, data); + } + + me = this->ike_sa->get_my_host(this->ike_sa); + if (me->is_anyaddr(me)) + { + me = request->get_destination(request); + this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); + } + other = this->ike_sa->get_other_host(this->ike_sa); + if (other->is_anyaddr(other)) + { + other = request->get_source(request); + this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); + } + response->set_source(response, me->clone(me)); + response->set_destination(response, other->clone(other)); + if (this->ike_sa->generate_message(this->ike_sa, response, + &packet) == SUCCESS) + { + charon->sender->send(charon->sender, packet); + } + response->destroy(response); +} + /** * handle an incoming request message */ @@ -610,6 +670,8 @@ static status_t process_request(private_task_manager_t *this, /* processed, but task needs at least another call to build() */ send_response = TRUE; break; + case FAILED_SEND_ERROR: + send_notify_response(this, NULL, 0, chunk_empty, task); case FAILED: default: charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); @@ -683,52 +745,6 @@ static status_t process_response(private_task_manager_t *this, return initiate(this); } -/** - * Send a notify in a separate INFORMATIONAL exchange back to the sender. - */ -static void send_notify_response(private_task_manager_t *this, - message_t *request, notify_type_t type, - chunk_t data) -{ - message_t *response; - packet_t *packet; - host_t *me, *other; - u_int32_t mid; - - if (request->get_exchange_type(request) == INFORMATIONAL_V1) - { /* don't respond to INFORMATIONAL requests to avoid a notify war */ - DBG1(DBG_IKE, "ignore malformed INFORMATIONAL request"); - return; - } - - response = message_create(IKEV1_MAJOR_VERSION, IKEV1_MINOR_VERSION); - response->set_exchange_type(response, INFORMATIONAL_V1); - response->set_request(response, TRUE); - this->rng->get_bytes(this->rng, sizeof(mid), (void*)&mid); - response->set_message_id(response, mid); - response->add_notify(response, FALSE, type, data); - me = this->ike_sa->get_my_host(this->ike_sa); - if (me->is_anyaddr(me)) - { - me = request->get_destination(request); - this->ike_sa->set_my_host(this->ike_sa, me->clone(me)); - } - other = this->ike_sa->get_other_host(this->ike_sa); - if (other->is_anyaddr(other)) - { - other = request->get_source(request); - this->ike_sa->set_other_host(this->ike_sa, other->clone(other)); - } - response->set_source(response, me->clone(me)); - response->set_destination(response, other->clone(other)); - if (this->ike_sa->generate_message(this->ike_sa, response, - &packet) == SUCCESS) - { - charon->sender->send(charon->sender, packet); - } - response->destroy(response); -} - /** * Parse the given message and verify that it is valid. */ @@ -745,27 +761,27 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg) case NOT_SUPPORTED: DBG1(DBG_IKE, "unsupported exchange type"); send_notify_response(this, msg, - INVALID_EXCHANGE_TYPE, chunk_empty); + INVALID_EXCHANGE_TYPE, chunk_empty, NULL); break; case PARSE_ERROR: DBG1(DBG_IKE, "message parsing failed"); send_notify_response(this, msg, - PAYLOAD_MALFORMED, chunk_empty); + PAYLOAD_MALFORMED, chunk_empty, NULL); break; case VERIFY_ERROR: DBG1(DBG_IKE, "message verification failed"); send_notify_response(this, msg, - PAYLOAD_MALFORMED, chunk_empty); + PAYLOAD_MALFORMED, chunk_empty, NULL); break; case FAILED: DBG1(DBG_IKE, "integrity check failed"); send_notify_response(this, msg, - INVALID_HASH_INFORMATION, chunk_empty); + INVALID_HASH_INFORMATION, chunk_empty, NULL); break; case INVALID_STATE: DBG1(DBG_IKE, "found encrypted message, but no keys available"); send_notify_response(this, msg, - PAYLOAD_MALFORMED, chunk_empty); + PAYLOAD_MALFORMED, chunk_empty, NULL); default: break; } @@ -844,7 +860,7 @@ METHOD(task_manager_t, process_message, status_t, DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", me, other, notify_type_names, NO_PROPOSAL_CHOSEN); send_notify_response(this, msg, - NO_PROPOSAL_CHOSEN, chunk_empty); + NO_PROPOSAL_CHOSEN, chunk_empty, NULL); return DESTROY_ME; } this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); From b8383f1f2dd2202bf2dc8b7e78851a22ead6603a Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 9 Dec 2011 16:04:12 +0100 Subject: [PATCH 235/534] Encrypt INFORMATIONAL exchange if needed --- src/libcharon/encoding/message.c | 33 +++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 91131ad22..1296475d5 100755 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1459,24 +1459,35 @@ METHOD(message_t, generate, status_t, hash_payload->set_hash(hash_payload, hash); this->payloads->insert_first(this->payloads, (payload_t*)hash_payload); + + if (this->exchange_type == INFORMATIONAL_V1) + { + DBG3(DBG_ENC, "encrypting IKEv1 INFORMATIONAL exchange message"); + this->is_encrypted = TRUE; + encrypted = TRUE; + } + chunk_free(&hash); } - /* if at least one payload requires encryption, encrypt the message. - * if we have no key material available, the flag will be reset below */ - enumerator = this->payloads->create_enumerator(this->payloads); - while (enumerator->enumerate(enumerator, (void**)&payload)) + if (!encrypted) { - payload_rule_t *rule; - rule = get_payload_rule(this, payload->get_type(payload)); - if (rule && rule->encrypted) + /* if at least one payload requires encryption, encrypt the message. + * if we have no key material available, the flag will be reset below */ + enumerator = this->payloads->create_enumerator(this->payloads); + while (enumerator->enumerate(enumerator, (void**)&payload)) { - this->is_encrypted = TRUE; - encrypted = TRUE; - break; + payload_rule_t *rule; + rule = get_payload_rule(this, payload->get_type(payload)); + if (rule && rule->encrypted) + { + this->is_encrypted = TRUE; + encrypted = TRUE; + break; + } } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); } DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); From c29fba51aa0001bb7c50cf30e482cdff402058d5 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Fri, 9 Dec 2011 16:05:17 +0100 Subject: [PATCH 236/534] Some notification errors added to main_mode process_r --- src/libcharon/sa/tasks/main_mode.c | 62 ++++++++++++++++++++++++++++-- 1 file changed, 58 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index e1f583cb8..a5945a826 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -122,6 +122,16 @@ struct private_main_mode_t { */ authenticator_t *authenticator; + /** + * Notify type in case of error + */ + notify_type_t notify_type; + + /** + * Notify data in case of error + */ + chunk_t notify_data; + /** states of main mode */ enum { MM_INIT, @@ -263,6 +273,7 @@ static auth_method_t get_auth_method(private_main_mode_t *this) return AUTH_RSA; } } + /** * Check for notify errors, return TRUE if error found */ @@ -310,6 +321,49 @@ static bool has_notify_errors(private_main_mode_t *this, message_t *message) return err; } +METHOD(task_t, build_notify_error, status_t, + private_main_mode_t *this, message_t *message) +{ + notify_payload_t *notify; + ike_sa_id_t *ike_sa_id; + chunk_t spi; + u_int64_t spi_i, spi_r; + + notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_IKE, this->notify_type); + + if (this->notify_data.ptr) + { + notify->set_notification_data(notify, this->notify_data); + } + + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + + spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_r = ike_sa_id->get_responder_spi(ike_sa_id); + + spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r)); + + notify->set_spi_data(notify, spi); + + message->add_payload(message, (payload_t*)notify); + + return SUCCESS; +} + +/** + * Set the task ready to build notify error message + */ +static status_t set_notify_error(private_main_mode_t *this, + notify_type_t type, chunk_t data) +{ + this->notify_type = type; + this->notify_data = data; + /* The task will be destroyed after build */ + this->public.task.build = _build_notify_error; + return FAILED_SEND_ERROR; +} + METHOD(task_t, build_i, status_t, private_main_mode_t *this, message_t *message) { @@ -463,7 +517,7 @@ METHOD(task_t, process_r, status_t, if (!this->proposal) { DBG1(DBG_IKE, "no proposal found"); - return FAILED; + return set_notify_error(this, NO_PROPOSAL_CHOSEN, chunk_empty); } this->auth_method = sa_payload->get_auth_method(sa_payload); @@ -525,7 +579,7 @@ METHOD(task_t, process_r, status_t, id->destroy(id); any->destroy(any); enumerator->destroy(enumerator); - return FAILED; + return set_notify_error(this, AUTHENTICATION_FAILED, chunk_empty); } this->peer_cfg->get_ref(this->peer_cfg); enumerator->destroy(enumerator); @@ -540,13 +594,13 @@ METHOD(task_t, process_r, status_t, if (!this->my_auth || !this->other_auth) { DBG1(DBG_IKE, "auth config missing"); - return FAILED; + return set_notify_error(this, AUTHENTICATION_FAILED, chunk_empty); } if (this->authenticator->process(this->authenticator, message) != SUCCESS) { - return FAILED; + return set_notify_error(this, AUTHENTICATION_FAILED, chunk_empty); } this->state = MM_AUTH; From a0eea1a7ac3e9c76329c38dcab301664ef283ced Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 15:55:43 +0100 Subject: [PATCH 237/534] Defined hybrid IKEv1 authentication methods --- src/libcharon/sa/authenticators/authenticator.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticators/authenticator.h index 3c1733388..5a8d26d1e 100644 --- a/src/libcharon/sa/authenticators/authenticator.h +++ b/src/libcharon/sa/authenticators/authenticator.h @@ -93,6 +93,16 @@ enum auth_method_t { * IKEv1 responder XAUTH with RSA, outside of IANA range */ AUTH_XAUTH_RESP_RSA, + + /** + * IKEv1 initiator XAUTH, responder RSA, outside of IANA range + */ + AUTH_HYBRID_INIT_RSA, + + /** + * IKEv1 responder XAUTH, initiator RSA, outside of IANA range + */ + AUTH_HYBRID_RESP_RSA, }; /** From c6d0098c1b8ae90579458987b9a901178c897640 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 15:56:01 +0100 Subject: [PATCH 238/534] Added missing auth_method_t enum names --- src/libcharon/sa/authenticators/authenticator.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/authenticators/authenticator.c b/src/libcharon/sa/authenticators/authenticator.c index c69a5d92a..b052dd87b 100644 --- a/src/libcharon/sa/authenticators/authenticator.c +++ b/src/libcharon/sa/authenticators/authenticator.c @@ -34,7 +34,15 @@ ENUM_NEXT(auth_method_names, AUTH_ECDSA_256, AUTH_ECDSA_521, AUTH_DSS, "ECDSA-256 signature", "ECDSA-384 signature", "ECDSA-521 signature"); -ENUM_END(auth_method_names, AUTH_ECDSA_521); +ENUM_NEXT(auth_method_names, AUTH_XAUTH_INIT_PSK, AUTH_HYBRID_RESP_RSA, AUTH_ECDSA_521, + "XAuthInitPSK", + "XAuthRespPSK", + "XAuthInitRSA", + "XauthRespRSA", + "HybridInitRSA", + "HybridRespRSA", +); +ENUM_END(auth_method_names, AUTH_HYBRID_RESP_RSA); /** * Described in header. From 69adeb5bf25b9938a0aff34718ece9d2be4f32ef Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 16:19:54 +0100 Subject: [PATCH 239/534] Replace xauth_request task with a new stub where we reimplement it --- src/libcharon/Makefile.am | 3 +- src/libcharon/sa/ike_sa.c | 21 +- src/libcharon/sa/ike_sa.h | 13 +- src/libcharon/sa/task_manager_v1.c | 20 +- src/libcharon/sa/tasks/main_mode.c | 78 ++- src/libcharon/sa/tasks/task.c | 8 +- src/libcharon/sa/tasks/task.h | 4 +- src/libcharon/sa/tasks/xauth.c | 117 ++++ src/libcharon/sa/tasks/xauth.h | 50 ++ src/libcharon/sa/tasks/xauth_request.c | 770 ------------------------- src/libcharon/sa/tasks/xauth_request.h | 37 -- src/libstrongswan/xauth/xauth.h | 4 +- 12 files changed, 241 insertions(+), 884 deletions(-) create mode 100644 src/libcharon/sa/tasks/xauth.c create mode 100644 src/libcharon/sa/tasks/xauth.h delete mode 100755 src/libcharon/sa/tasks/xauth_request.c delete mode 100644 src/libcharon/sa/tasks/xauth_request.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index bf409d26c..3bddf0e61 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -57,7 +57,6 @@ processing/jobs/start_action_job.c processing/jobs/start_action_job.h \ processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \ -processing/jobs/initiate_xauth_job.c processing/jobs/initiate_xauth_job.h \ sa/authenticators/authenticator.c sa/authenticators/authenticator.h \ sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \ sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ @@ -100,8 +99,8 @@ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ sa/tasks/ike_vendor_v1.c sa/tasks/ike_vendor_v1.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ +sa/tasks/xauth.c sa/tasks/xauth.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ -sa/tasks/xauth_request.c sa/tasks/xauth_request.h \ sa/tasks/task.c sa/tasks/task.h diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 47aadc108..11e7b18d2 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -50,7 +50,6 @@ #include #include #include -#include #include #include #include @@ -1021,18 +1020,6 @@ METHOD(ike_sa_t, initiate_mediated, status_t, } #endif /* ME */ -METHOD(ike_sa_t, initiate_xauth, status_t, - private_ike_sa_t *this, bool initiate) -{ - xauth_request_t *task = xauth_request_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, (task_t*)task); - if(initiate) - { - return this->task_manager->initiate(this->task_manager); - } - return SUCCESS; -} - /** * Resolve DNS host in configuration */ @@ -1839,6 +1826,12 @@ METHOD(ike_sa_t, create_task_enumerator, enumerator_t*, return this->task_manager->create_task_enumerator(this->task_manager, queue); } +METHOD(ike_sa_t, queue_task, void, + private_ike_sa_t *this, task_t *task) +{ + this->task_manager->queue_task(this->task_manager, task); +} + METHOD(ike_sa_t, inherit, void, private_ike_sa_t *this, ike_sa_t *other_public) { @@ -2095,6 +2088,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .add_configuration_attribute = _add_configuration_attribute, .set_kmaddress = _set_kmaddress, .create_task_enumerator = _create_task_enumerator, + .queue_task = _queue_task, #ifdef ME .act_as_mediation_server = _act_as_mediation_server, .get_server_reflexive_host = _get_server_reflexive_host, @@ -2106,7 +2100,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .callback = _callback, .respond = _respond, #endif /* ME */ - .initiate_xauth = _initiate_xauth, }, .ike_sa_id = ike_sa_id->clone(ike_sa_id), .version = version, diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index 15fd35c25..cbb16ca4a 100755 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -37,6 +37,7 @@ typedef struct ike_sa_t ike_sa_t; #include #include #include +#include #include #include #include @@ -951,6 +952,13 @@ struct ike_sa_t { */ enumerator_t* (*create_task_enumerator)(ike_sa_t *this, task_queue_t queue); + /** + * Queue a task for initiaton to the task manager. + * + * @param task task to queue + */ + void (*queue_task)(ike_sa_t *this, task_t *task); + /** * Inherit all attributes of other to this after rekeying. * @@ -971,11 +979,6 @@ struct ike_sa_t { * Destroys a ike_sa_t object. */ void (*destroy) (ike_sa_t *this); - - /** - * Initiate an XAuth authentication exchange. - */ - status_t (*initiate_xauth) (ike_sa_t *this, bool initiate); }; /** diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index d557d970e..c01229564 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -280,7 +280,7 @@ METHOD(task_manager_t, initiate, status_t, } break; case IKE_CONNECTING: - if (activate_task(this, TASK_XAUTH_REQUEST)) + if (activate_task(this, TASK_XAUTH)) { exchange = TRANSACTION; new_mid = TRUE; @@ -313,7 +313,7 @@ METHOD(task_manager_t, initiate, status_t, case TASK_QUICK_MODE: exchange = QUICK_MODE; break; - case TASK_XAUTH_REQUEST: + case TASK_XAUTH: exchange = TRANSACTION; new_mid = TRUE; break; @@ -648,7 +648,7 @@ static status_t process_request(private_task_manager_t *this, enumerator->destroy(enumerator); break; case TRANSACTION: - task = (task_t *)xauth_request_create(this->ike_sa, FALSE); + task = (task_t *)xauth_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); break; default: @@ -688,7 +688,17 @@ static status_t process_request(private_task_manager_t *this, if (send_response) { - return build_response(this, message); + if (build_response(this, message) != SUCCESS) + { + return DESTROY_ME; + } + } + if (this->passive_tasks->get_count(this->passive_tasks) == 0 && + this->queued_tasks->get_count(this->queued_tasks) > 0) + { + /* passive tasks completed, check if an active task has been queued, + * such as XAUTH or modeconfig push */ + return initiate(this); } return SUCCESS; } diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index a5945a826..f54427cc8 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include typedef struct private_main_mode_t private_main_mode_t; @@ -738,6 +738,21 @@ METHOD(task_t, build_r, status_t, return FAILED; } + switch (this->auth_method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: + this->ike_sa->queue_task(this->ike_sa, + (task_t*)xauth_create(this->ike_sa, TRUE)); + return SUCCESS; + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: + /* TODO-IKEv1: not yet supported */ + return FAILED; + default: + break; + } + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa), @@ -746,27 +761,9 @@ METHOD(task_t, build_r, status_t, this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); - switch (this->auth_method) - { - case AUTH_XAUTH_INIT_PSK: - case AUTH_XAUTH_INIT_RSA: /* There should be more INIT cases here once added */ - { - job_t *job = (job_t *) initiate_xauth_job_create(this->ike_sa->get_id(this->ike_sa)); - lib->processor->queue_job(lib->processor, job); - break; - } - case AUTH_XAUTH_RESP_PSK: - case AUTH_XAUTH_RESP_RSA: /* There should be more RESP cases here once added */ - { - break; - } - default: - { - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - break; - } - } + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + return SUCCESS; } default: @@ -858,7 +855,20 @@ METHOD(task_t, process_i, status_t, return FAILED; } - /* TODO-IKEv1: check for XAUTH rounds, queue them */ + switch (this->auth_method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: + /* TODO-IKEv1: wait for XAUTH request */ + return SUCCESS; + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: + /* TODO-IKEv1: not yet */ + return FAILED; + default: + break; + } + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa), @@ -867,26 +877,8 @@ METHOD(task_t, process_i, status_t, this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); - switch (this->auth_method) - { - case AUTH_XAUTH_RESP_PSK: - case AUTH_XAUTH_RESP_RSA: /* There should be more RESP cases here once added */ - { - this->ike_sa->initiate_xauth(this->ike_sa, FALSE); - break; - } - case AUTH_XAUTH_INIT_PSK: - case AUTH_XAUTH_INIT_RSA: /* There should be more INIT cases here once added */ - { - break; - } - default: - { - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - break; - } - } + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); return SUCCESS; } diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index 145a4d6e7..dc4bf5e97 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -17,7 +17,7 @@ #include "task.h" #ifdef ME -ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, +ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", @@ -36,15 +36,15 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, "CHILD_DELETE", "CHILD_REKEY", "MAIN_MODE", + "XAUTH", "QUICK_MODE", "VENDOR_V1", "IKE_NATD_V1", "IKE_CERT_PRE_V1", "IKE_CERT_POST_V1", - "XAUTH_REQUEST", ); #else -ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, +ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", @@ -62,11 +62,11 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_XAUTH_REQUEST, "CHILD_DELETE", "CHILD_REKEY", "MAIN_MODE", + "XAUTH", "QUICK_MODE", "VENDOR_V1", "IKE_NATD_V1", "IKE_CERT_PRE_V1", "IKE_CERT_POST_V1", - "XAUTH_REQUEST", ); #endif /* ME */ diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 6fb8144ec..9a5cb7c53 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -71,6 +71,8 @@ enum task_type_t { TASK_CHILD_REKEY, /** IKEv1 main mode */ TASK_MAIN_MODE, + /** IKEv1 XAUTH authentication */ + TASK_XAUTH, /** IKEv1 quick mode */ TASK_QUICK_MODE, /** IKEv1 vendor ID payload handling */ @@ -81,8 +83,6 @@ enum task_type_t { TASK_IKE_CERT_PRE_V1, /** IKEv1 post-authentication certificate handling */ TASK_IKE_CERT_POST_V1, - /** Request the user/pass with XAUTH */ - TASK_XAUTH_REQUEST, }; /** diff --git a/src/libcharon/sa/tasks/xauth.c b/src/libcharon/sa/tasks/xauth.c new file mode 100644 index 000000000..4d12e16e6 --- /dev/null +++ b/src/libcharon/sa/tasks/xauth.c @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth.h" + +#include +#include +#include + +typedef struct private_xauth_t private_xauth_t; + +/** + * Private members of a xauth_t task. + */ +struct private_xauth_t { + + /** + * Public methods and task_t interface. + */ + xauth_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the XAUTH initiator? + */ + bool initiator; +}; + +METHOD(task_t, build_i, status_t, + private_xauth_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, process_r, status_t, + private_xauth_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, build_r, status_t, + private_xauth_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, process_i, status_t, + private_xauth_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_xauth_t *this) +{ + return TASK_XAUTH; +} + +METHOD(task_t, migrate, void, + private_xauth_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_xauth_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator) +{ + private_xauth_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/tasks/xauth.h b/src/libcharon/sa/tasks/xauth.h new file mode 100644 index 000000000..6633f9e55 --- /dev/null +++ b/src/libcharon/sa/tasks/xauth.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth xauth + * @{ @ingroup tasks + */ + +#ifndef XAUTH_H_ +#define XAUTH_H_ + +typedef struct xauth_t xauth_t; + +#include +#include +#include + +/** + * Task of type TASK_XAUTH, additional authentication after main/aggressive mode. + */ +struct xauth_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new xauth task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE for initiator + * @return xauth task to handle by the task_manager + */ +xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** XAUTH_H_ @}*/ diff --git a/src/libcharon/sa/tasks/xauth_request.c b/src/libcharon/sa/tasks/xauth_request.c deleted file mode 100755 index dbce6e514..000000000 --- a/src/libcharon/sa/tasks/xauth_request.c +++ /dev/null @@ -1,770 +0,0 @@ - -#include "xauth_request.h" - -#include -#include -#include -#include - -typedef struct private_xauth_request_t private_xauth_request_t; - -enum { - XAUTH_STATUS_FAIL = 0, - XAUTH_STATUS_OK = 1, -}; - -/** - * Private members of a xauth_request_t task. - */ -struct private_xauth_request_t { - - /** - * Public methods and task_t interface. - */ - xauth_request_t public; - - /** - * Assigned IKE_SA. - */ - ike_sa_t *ike_sa; - - /** - * Are we the initiator? - */ - bool initiator; - - /** - * virtual ip - */ - host_t *virtual_ip; - - /** - * list of attributes requested and its handler, entry_t - */ - linked_list_t *requested; - - /** - * The current and next state of the task - */ - enum { - TASK_XAUTH_INIT, - TASK_XAUTH_PASS_VERIFY, - TASK_XAUTH_COMPLETE, - } state, next_state; - - /** - * The status of the XAuth request - */ - status_t status; - - /** - * The current auth config - */ - auth_cfg_t *auth_cfg; - - /** - * The received XAuth Status - */ - u_int16_t xauth_status_data; - - /** - * The received XAuth user name - */ - chunk_t xauth_user_name; - - /** - * The received XAuth user pass - */ - chunk_t xauth_user_pass; - - /** - * Whether the user name attribute was received - */ - bool xauth_user_name_recv; - - /** - * Whether the user pass attribute was received - */ - bool xauth_user_pass_recv; - - /** - * Whether the XAuth status attribute was received - */ - bool xauth_status_recv; - - /** - * The XAuth authenticator_t object - */ - authenticator_t *xauth_authenticator; -}; - -/** - * Entry for a requested attribute and the requesting handler - */ -typedef struct { - /** attribute requested */ - configuration_attribute_type_t type; - /** handler requesting this attribute */ - attribute_handler_t *handler; -} entry_t; - -/** - * Get the first authentcation config from peer config - */ -static auth_cfg_t *get_auth_cfg(private_xauth_request_t *this, bool local) -{ - enumerator_t *enumerator; - auth_cfg_t *cfg = NULL; - peer_cfg_t *peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - - enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, - local); - enumerator->enumerate(enumerator, &cfg); - enumerator->destroy(enumerator); - return cfg; -} - -/** - * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip - */ -static configuration_attribute_t *build_vip(payload_type_t ca_type, host_t *vip) -{ - configuration_attribute_type_t type; - chunk_t chunk, prefix; - - if (vip->get_family(vip) == AF_INET) - { - type = INTERNAL_IP4_ADDRESS; - if (vip->is_anyaddr(vip)) - { - chunk = chunk_empty; - } - else - { - chunk = vip->get_address(vip); - } - } - else - { - type = INTERNAL_IP6_ADDRESS; - if (vip->is_anyaddr(vip)) - { - chunk = chunk_empty; - } - else - { - prefix = chunk_alloca(1); - *prefix.ptr = 64; - chunk = vip->get_address(vip); - chunk = chunk_cata("cc", chunk, prefix); - } - } - return configuration_attribute_create_chunk(ca_type, - type, chunk); -} - -/** - * Handle a received attribute as initiator - */ -static void handle_attribute(private_xauth_request_t *this, - configuration_attribute_t *ca) -{ - attribute_handler_t *handler = NULL; - enumerator_t *enumerator; - entry_t *entry; - - /* find the handler which requested this attribute */ - enumerator = this->requested->create_enumerator(this->requested); - while (enumerator->enumerate(enumerator, &entry)) - { - if (entry->type == ca->get_type(ca)) - { - handler = entry->handler; - this->requested->remove_at(this->requested, enumerator); - free(entry); - break; - } - } - enumerator->destroy(enumerator); - - /* and pass it to the handle function */ - handler = hydra->attributes->handle(hydra->attributes, - this->ike_sa->get_other_id(this->ike_sa), handler, - ca->get_type(ca), ca->get_chunk(ca)); - if (handler) - { - this->ike_sa->add_configuration_attribute(this->ike_sa, - handler, ca->get_type(ca), ca->get_chunk(ca)); - } -} - -/** - * process a single configuration attribute - */ -static void process_attribute(private_xauth_request_t *this, - configuration_attribute_t *ca) -{ - host_t *ip; - chunk_t addr; - int family = AF_INET6; - - switch (ca->get_type(ca)) - { - case XAUTH_USER_NAME: - this->xauth_user_name = ca->get_chunk(ca); - this->xauth_user_name_recv = TRUE; - break; - case XAUTH_USER_PASSWORD: - this->xauth_user_pass = ca->get_chunk(ca); - this->xauth_user_pass_recv = TRUE; - break; - case XAUTH_STATUS: - this->xauth_status_data = ca->get_value(ca); - this->xauth_status_recv = TRUE; - break; - case INTERNAL_IP4_ADDRESS: - family = AF_INET; - /* fall */ - case INTERNAL_IP6_ADDRESS: - { - addr = ca->get_chunk(ca); - if (addr.len == 0) - { - ip = host_create_any(family); - } - else - { - /* skip prefix byte in IPv6 payload*/ - if (family == AF_INET6) - { - addr.len--; - } - ip = host_create_from_chunk(family, addr, 0); - } - if (ip) - { - DESTROY_IF(this->virtual_ip); - this->virtual_ip = ip; - } - break; - } - case INTERNAL_IP4_SERVER: - case INTERNAL_IP6_SERVER: - /* assume it's a Windows client if we see proprietary attributes */ - this->ike_sa->enable_extension(this->ike_sa, EXT_MS_WINDOWS); - /* fall */ - default: - { - if (this->initiator) - { - handle_attribute(this, ca); - } - } - } -} - -/** - * Scan for configuration payloads and attributes - */ -static status_t process_payloads(private_xauth_request_t *this, message_t *message) -{ - enumerator_t *enumerator, *attributes; - payload_t *payload; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - switch(payload->get_type(payload)) - { - case CONFIGURATION: - case CONFIGURATION_V1: - { - cp_payload_t *cp = (cp_payload_t*)payload; - configuration_attribute_t *ca; - - switch (cp->get_type(cp)) - { - case CFG_REQUEST: - case CFG_REPLY: - case CFG_SET: - case CFG_ACK: - { - attributes = cp->create_attribute_enumerator(cp); - while (attributes->enumerate(attributes, &ca)) - { - DBG2(DBG_IKE, "processing %N attribute", - configuration_attribute_type_names, ca->get_type(ca)); - process_attribute(this, ca); - } - attributes->destroy(attributes); - break; - } - default: - DBG1(DBG_IKE, "ignoring %N config payload", - config_type_names, cp->get_type(cp)); - break; - } - - switch(this->state) - { - case TASK_XAUTH_INIT: - if(((cp->get_type(cp) != CFG_REQUEST) && (cp->get_type(cp) != CFG_REPLY)) || - (this->xauth_user_name_recv != TRUE) || - (this->xauth_user_pass_recv != TRUE)) - { - /* Didn't get an XAuth message, assume we're a ConfigMode message, set state appropriately */ - this->state = TASK_XAUTH_COMPLETE; - this->next_state = TASK_XAUTH_COMPLETE; - this->status = SUCCESS; - break; - } - this->next_state = TASK_XAUTH_PASS_VERIFY; - break; - case TASK_XAUTH_PASS_VERIFY: - if(((cp->get_type(cp) != CFG_SET) && (cp->get_type(cp) != CFG_ACK)) || - (this->xauth_status_recv != TRUE)) - { - DBG1(DBG_IKE, "Didn't receive XAuth status."); - return FAILED; - } - /* Set the return status for the build call */ - if(cp->get_type(cp) != CFG_ACK) - { - this->status = (this->xauth_status_data == XAUTH_STATUS_OK ? SUCCESS : FAILED); - } - else - { - this->status = SUCCESS; - } - this->next_state = TASK_XAUTH_COMPLETE; - break; - default: - this->next_state = TASK_XAUTH_COMPLETE; - this->status = SUCCESS; - break; - } - } - default: - break; - } - } - enumerator->destroy(enumerator); - - if(this->xauth_authenticator) - { - this->xauth_authenticator->process(this->xauth_authenticator, message); - } - return NEED_MORE; -} - -METHOD(task_t, build_i, status_t, - private_xauth_request_t *this, message_t *message) -{ - cp_payload_t *cp = NULL; - chunk_t chunk = chunk_empty; - ike_version_t version; - payload_type_t cp_type; - payload_type_t ca_type; - host_t *vip; - peer_cfg_t *config; - enumerator_t *enumerator; - attribute_handler_t *handler; - configuration_attribute_type_t type; - chunk_t data; - status_t status; - - version = this->ike_sa->get_version(this->ike_sa); - if(version == IKEV1) - { - if(!this->auth_cfg) - { - this->auth_cfg = get_auth_cfg(this, TRUE); - } - switch((uintptr_t)this->auth_cfg->get(this->auth_cfg, AUTH_RULE_AUTH_CLASS)) - { - case AUTH_CLASS_XAUTH_PSK: - case AUTH_CLASS_XAUTH_PUBKEY: - break; - default: - /* We aren't XAuth, so do nothing */ - return SUCCESS; - } - cp_type = CONFIGURATION_V1; - ca_type = CONFIGURATION_ATTRIBUTE_V1; - } - else /* IKEv2 */ - { - /* IKEv2 does not support XAuth, skip those states. */ - this->state = TASK_XAUTH_COMPLETE; - if (message->get_message_id(message) == 1) - { /* in first IKE_AUTH only */ - return NEED_MORE; - } - cp_type = CONFIGURATION; - ca_type = CONFIGURATION_ATTRIBUTE; - } - switch(this->state) - { - case TASK_XAUTH_INIT: - cp = cp_payload_create_type(cp_type, CFG_REQUEST); - cp->add_attribute(cp, configuration_attribute_create_chunk( - ca_type, XAUTH_USER_NAME, chunk)); - cp->add_attribute(cp, configuration_attribute_create_chunk( - ca_type, XAUTH_USER_PASSWORD, chunk)); - break; - case TASK_XAUTH_PASS_VERIFY: - status = this->xauth_authenticator->build(this->xauth_authenticator, message); - cp = cp_payload_create_type(cp_type, CFG_SET); - cp->add_attribute(cp, configuration_attribute_create_value( - XAUTH_STATUS, - (status == FAILED ? XAUTH_STATUS_FAIL : XAUTH_STATUS_OK))); - break; - case TASK_XAUTH_COMPLETE: - /* ConfigMode stuff */ - /* reuse virtual IP if we already have one */ - vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); - if (!vip) - { - config = this->ike_sa->get_peer_cfg(this->ike_sa); - vip = config->get_virtual_ip(config); - } - if (vip) - { - cp = cp_payload_create_type(cp_type, CFG_REQUEST); - cp->add_attribute(cp, build_vip(ca_type, vip)); - } - - enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes, - this->ike_sa->get_other_id(this->ike_sa), vip); - while (enumerator->enumerate(enumerator, &handler, &type, &data)) - { - configuration_attribute_t *ca; - entry_t *entry; - - /* create configuration attribute */ - DBG2(DBG_IKE, "building %N attribute", - configuration_attribute_type_names, type); - ca = configuration_attribute_create_chunk(ca_type, - type, data); - if (!cp) - { - cp = cp_payload_create_type(cp_type, CFG_REQUEST); - } - cp->add_attribute(cp, ca); - - /* save handler along with requested type */ - entry = malloc_thing(entry_t); - entry->type = type; - entry->handler = handler; - - this->requested->insert_last(this->requested, entry); - } - enumerator->destroy(enumerator); - - break; - default: - return FAILED; - - } - /* Add the payloads into the message */ - if(cp) - { - message->add_payload(message, (payload_t *)cp); - } - - return NEED_MORE; -} - -METHOD(task_t, process_r, status_t, - private_xauth_request_t *this, message_t *message) -{ - ike_version_t version; - payload_type_t cp_type; - status_t status; - - version = this->ike_sa->get_version(this->ike_sa); - if(version == IKEV1) - { - if(!this->auth_cfg) - { - this->auth_cfg = get_auth_cfg(this, TRUE); - } - - switch((uintptr_t)this->auth_cfg->get(this->auth_cfg, AUTH_RULE_AUTH_CLASS)) - { - case AUTH_CLASS_XAUTH_PSK: - case AUTH_CLASS_XAUTH_PUBKEY: - if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) - { - this->state = TASK_XAUTH_COMPLETE; - } - else - { - this->state = TASK_XAUTH_INIT; - } - break; - default: - /* We aren't XAuth, so do we should expect ConfigMode stuff */ - this->state = TASK_XAUTH_COMPLETE; - } - - if((this->xauth_authenticator == NULL) && (this->state == TASK_XAUTH_INIT)) - { - this->xauth_authenticator = (authenticator_t *)xauth_authenticator_create_builder(this->ike_sa); - } - cp_type = CONFIGURATION_V1; - } - else /* IKEv2 */ - { - /* IKEv2 does not support XAuth, skip those states. */ - this->state = TASK_XAUTH_COMPLETE; - if (message->get_message_id(message) == 1) - { /* in first IKE_AUTH only */ - return NEED_MORE; - } - cp_type = CONFIGURATION; - } - - status = process_payloads(this, message); - if(this->xauth_authenticator != NULL) - { - status = this->xauth_authenticator->process(this->xauth_authenticator, message); - } - return status; -} - -METHOD(task_t, build_r, status_t, - private_xauth_request_t *this, message_t *message) -{ - status_t status; - cp_payload_t *cp = NULL; - payload_type_t cp_type = CONFIGURATION; - payload_type_t ca_type = CONFIGURATION_ATTRIBUTE; - ike_version_t version; - identification_t *id; - enumerator_t *enumerator; - configuration_attribute_type_t type; - chunk_t value; - host_t *vip = NULL; - peer_cfg_t *config; - - version = this->ike_sa->get_version(this->ike_sa); - if ((version == IKEV2) && (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED)) - { - return NEED_MORE; - } - if(version == IKEV1) - { - if(!this->auth_cfg) - { - this->auth_cfg = get_auth_cfg(this, TRUE); - } - switch((uintptr_t)this->auth_cfg->get(this->auth_cfg, AUTH_RULE_AUTH_CLASS)) - { - case AUTH_CLASS_XAUTH_PSK: - case AUTH_CLASS_XAUTH_PUBKEY: - break; - default: - - this->state = TASK_XAUTH_COMPLETE; - return SUCCESS; - } - cp_type = CONFIGURATION_V1; - ca_type = CONFIGURATION_ATTRIBUTE_V1; - } - - switch(this->state) - { - case TASK_XAUTH_INIT: - status = this->xauth_authenticator->build(this->xauth_authenticator, message); - this->state = TASK_XAUTH_PASS_VERIFY; - break; - case TASK_XAUTH_PASS_VERIFY: - cp = cp_payload_create_type(cp_type, CFG_ACK); - cp->add_attribute(cp, configuration_attribute_create_value( - XAUTH_STATUS, XAUTH_STATUS_OK)); - status = this->status; - this->state = TASK_XAUTH_COMPLETE; - break; - case TASK_XAUTH_COMPLETE: - id = this->ike_sa->get_other_eap_id(this->ike_sa); - - config = this->ike_sa->get_peer_cfg(this->ike_sa); - if (this->virtual_ip) - { - DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip); - if (config->get_pool(config)) - { - vip = hydra->attributes->acquire_address(hydra->attributes, - config->get_pool(config), id, this->virtual_ip); - } - if (vip == NULL) - { - DBG1(DBG_IKE, "no virtual IP found, sending %N", - notify_type_names, INTERNAL_ADDRESS_FAILURE); - message->add_notify(message, FALSE, INTERNAL_ADDRESS_FAILURE, - chunk_empty); - return SUCCESS; - } - DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id); - this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip); - - cp = cp_payload_create_type(cp_type, CFG_REPLY); - cp->add_attribute(cp, build_vip(ca_type, vip)); - } - - /* query registered providers for additional attributes to include */ - enumerator = hydra->attributes->create_responder_enumerator( - hydra->attributes, config->get_pool(config), id, vip); - while (enumerator->enumerate(enumerator, &type, &value)) - { - if (!cp) - { - cp = cp_payload_create_type(cp_type, CFG_REPLY); - } - DBG2(DBG_IKE, "building %N attribute", - configuration_attribute_type_names, type); - cp->add_attribute(cp, - configuration_attribute_create_chunk(ca_type, - type, value)); - } - enumerator->destroy(enumerator); - status = SUCCESS; - break; - default: - return FAILED; - } - if(cp != NULL) - { - message->add_payload(message, (payload_t *)cp); - } - if(status == SUCCESS) - { - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - } - return status; -} - -METHOD(task_t, process_i, status_t, - private_xauth_request_t *this, message_t *message) -{ - status_t status; - - if (((this->ike_sa->get_version(this->ike_sa) == IKEV2) && - (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED)) || - (this->ike_sa->get_version(this->ike_sa) == IKEV1)) - { /* in last IKE_AUTH exchange */ - - if(this->xauth_authenticator == NULL) - { - this->xauth_authenticator = (authenticator_t *)xauth_authenticator_create_verifier(this->ike_sa); - } - status = process_payloads(this, message); - this->state = this->next_state; - - if (this->virtual_ip) - { - this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); - } - if(this->state == TASK_XAUTH_COMPLETE) - { - if(this->status == SUCCESS) - { - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - } - - return this->status; - } - return status; - } - return NEED_MORE; - -} - -METHOD(task_t, get_type, task_type_t, - private_xauth_request_t *this) -{ - return TASK_XAUTH_REQUEST; -} - -METHOD(task_t, migrate, void, - private_xauth_request_t *this, ike_sa_t *ike_sa) -{ - DESTROY_IF(this->virtual_ip); - - this->ike_sa = ike_sa; - this->virtual_ip = NULL; - this->requested->destroy_function(this->requested, free); - this->requested = linked_list_create(); -} - -METHOD(task_t, destroy, void, - private_xauth_request_t *this) -{ - DESTROY_IF(this->virtual_ip); - this->requested->destroy_function(this->requested, free); - DESTROY_IF(this->xauth_authenticator); - free(this); -} - -METHOD(task_t, swap_initiator, void, - private_xauth_request_t *this) -{ - if(this->initiator) - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - this->initiator = FALSE; - } - else - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - this->initiator = TRUE; - } -} - -/* - * Described in header. - */ -xauth_request_t *xauth_request_create(ike_sa_t *ike_sa, bool initiator) -{ - private_xauth_request_t *this; - - INIT(this, - .public = { - .task = { - .get_type = _get_type, - .migrate = _migrate, - .destroy = _destroy, - .swap_initiator = _swap_initiator, - }, - }, - .initiator = initiator, - .ike_sa = ike_sa, - .requested = linked_list_create(), - .state = TASK_XAUTH_INIT, - .next_state = TASK_XAUTH_INIT, - .xauth_status_data = XAUTH_STATUS_FAIL, - .xauth_user_name = chunk_empty, - .xauth_user_pass = chunk_empty, - .xauth_user_name_recv = FALSE, - .xauth_user_pass_recv = FALSE, - .xauth_status_recv = FALSE, - ); - - if (initiator) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - - return &this->public; -} diff --git a/src/libcharon/sa/tasks/xauth_request.h b/src/libcharon/sa/tasks/xauth_request.h deleted file mode 100644 index 6324ca0de..000000000 --- a/src/libcharon/sa/tasks/xauth_request.h +++ /dev/null @@ -1,37 +0,0 @@ - -/** - * @defgroup xauth_request xauth_request - * @{ @ingroup tasks - */ - -#ifndef XAUTH_REQUEST_H_ -#define XAUTH_REQUEST_H_ - -typedef struct xauth_request_t xauth_request_t; - -#include -#include -#include - -/** - * Task of type XAUTH_REQUEST, gets the username and password from the ISAKMP_SA - * initializer. - */ -struct xauth_request_t { - - /** - * Implements the task_t interface - */ - task_t task; -}; - -/** - * Create a new xauth_request task. - * - * @param ike_sa IKE_SA this task works for - * @param initiator TRUE for initiator - * @return ike_config task to handle by the task_manager - */ -xauth_request_t *xauth_request_create(ike_sa_t *ike_sa, bool initiator); - -#endif /** XAUTH_REQUEST_H_ @}*/ diff --git a/src/libstrongswan/xauth/xauth.h b/src/libstrongswan/xauth/xauth.h index 4554ee779..97008afcb 100644 --- a/src/libstrongswan/xauth/xauth.h +++ b/src/libstrongswan/xauth/xauth.h @@ -18,8 +18,8 @@ * @{ @ingroup libstrongswan */ -#ifndef XAUTH_H_ -#define XAUTH_H_ +#ifndef XAUTH_H__ +#define XAUTH_H__ typedef enum xauth_type_t xauth_type_t; From 96c9159d9601112b89a40b609035e7cf210a2050 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 16:20:46 +0100 Subject: [PATCH 240/534] Use a second authentication config to configure XAUTH authentication --- src/libcharon/plugins/stroke/stroke_config.c | 8 +- src/libcharon/sa/tasks/main_mode.c | 139 ++++++++++++++----- src/libstrongswan/credentials/auth_cfg.h | 6 +- 3 files changed, 108 insertions(+), 45 deletions(-) diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 0d612f10e..f1af65e11 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -469,13 +469,9 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, { cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); } - else if (streq(auth, "xauthpsk")) + else if (streq(auth, "xauth")) { - cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH_PSK); - } - else if (streq(auth, "xauthrsasig")) - { - cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH_PUBKEY); + cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH); } else if (strneq(auth, "eap", 3)) { diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index f54427cc8..adf9142e5 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -254,24 +254,103 @@ static bool get_nonce_ke(private_main_mode_t *this, chunk_t *nonce, } /** - * Get auth method to use + * Get the two auth classes from local or remote config */ -static auth_method_t get_auth_method(private_main_mode_t *this) +static void get_auth_class(peer_cfg_t *peer_cfg, bool local, + auth_class_t *c1, auth_class_t *c2) { - switch ((uintptr_t)this->my_auth->get(this->my_auth, AUTH_RULE_AUTH_CLASS)) + enumerator_t *enumerator; + auth_cfg_t *auth; + + *c1 = *c2 = AUTH_CLASS_ANY; + + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); + while (enumerator->enumerate(enumerator, &auth)) { - case AUTH_CLASS_PSK: - return AUTH_PSK; - case AUTH_CLASS_XAUTH_PSK: - return AUTH_XAUTH_INIT_PSK; - case AUTH_CLASS_XAUTH_PUBKEY: - return AUTH_XAUTH_INIT_RSA; - case AUTH_CLASS_PUBKEY: - /* TODO-IKEv1: look for a key, return RSA or ECDSA */ - default: - /* TODO-IKEv1: XAUTH methods */ - return AUTH_RSA; + if (*c1 == AUTH_CLASS_ANY) + { + *c1 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); + } + else + { + *c2 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); + break; + } } + enumerator->destroy(enumerator); +} + +/** + * Get auth method to use from a peer config + */ +static auth_method_t get_auth_method(private_main_mode_t *this, + peer_cfg_t *peer_cfg) +{ + auth_class_t i1, i2, r1, r2; + + get_auth_class(peer_cfg, this->initiator, &i1, &i2); + get_auth_class(peer_cfg, !this->initiator, &r1, &r2); + + if (i1 == AUTH_CLASS_PUBKEY && r1 == AUTH_CLASS_PUBKEY) + { + if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) + { + /* TODO-IKEv1: ECDSA? */ + return AUTH_RSA; + } + if (i2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_INIT_RSA; + } + if (r2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_RESP_RSA; + } + } + if (i1 == AUTH_CLASS_PSK && r2 == AUTH_CLASS_PSK) + { + if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) + { + return AUTH_PSK; + } + if (i2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_INIT_PSK; + } + if (r2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_RESP_PSK; + } + } + /* TODO-IKEv1: Hybrid methods? */ + return AUTH_NONE;; +} + +/** + * Select the best configuration as responder + */ +static peer_cfg_t *select_config(private_main_mode_t *this, identification_t *id) +{ + enumerator_t *enumerator; + identification_t *any; + peer_cfg_t *current, *found = NULL; + + any = identification_create_from_encoding(ID_ANY, chunk_empty); + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), any, id); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (get_auth_method(this, current) == this->auth_method) + { + found = current->get_ref(current); + break; + } + } + enumerator->destroy(enumerator); + any->destroy(any); + + return found; } /** @@ -392,9 +471,12 @@ METHOD(task_t, build_i, status_t, DBG1(DBG_CFG, "no auth config found"); return FAILED; } - - proposals = this->ike_cfg->get_proposals(this->ike_cfg); - this->auth_method = get_auth_method(this); + this->auth_method = get_auth_method(this, this->peer_cfg); + if (this->auth_method == AUTH_NONE) + { + DBG1(DBG_CFG, "configuration uses unsupported authentication"); + return FAILED; + } this->lifetime = this->peer_cfg->get_reauth_time(this->peer_cfg, FALSE); if (!this->lifetime) @@ -402,6 +484,7 @@ METHOD(task_t, build_i, status_t, this->lifetime = this->peer_cfg->get_rekey_time(this->peer_cfg, FALSE); } + proposals = this->ike_cfg->get_proposals(this->ike_cfg); sa_payload = sa_payload_create_from_proposals_v1(proposals, this->lifetime, 0, this->auth_method, MODE_NONE, FALSE); proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); @@ -555,9 +638,8 @@ METHOD(task_t, process_r, status_t, } case MM_KE: { - enumerator_t *enumerator; id_payload_t *id_payload; - identification_t *id, *any; + identification_t *id; id_payload = (id_payload_t*)message->get_payload(message, ID_V1); if (!id_payload) @@ -567,26 +649,13 @@ METHOD(task_t, process_r, status_t, } id = id_payload->get_identification(id_payload); - any = identification_create_from_encoding(ID_ANY, chunk_empty); - enumerator = charon->backends->create_peer_cfg_enumerator( - charon->backends, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - any, id); - if (!enumerator->enumerate(enumerator, &this->peer_cfg)) + this->ike_sa->set_other_id(this->ike_sa, id); + this->peer_cfg = select_config(this, id); + if (!this->peer_cfg) { DBG1(DBG_IKE, "no peer config found"); - id->destroy(id); - any->destroy(any); - enumerator->destroy(enumerator); return set_notify_error(this, AUTHENTICATION_FAILED, chunk_empty); } - this->peer_cfg->get_ref(this->peer_cfg); - enumerator->destroy(enumerator); - any->destroy(any); - - this->ike_sa->set_other_id(this->ike_sa, id); - this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); this->my_auth = get_auth_cfg(this, TRUE); diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index ea98470fe..fd8e4c06a 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -42,10 +42,8 @@ enum auth_class_t { AUTH_CLASS_PSK = 2, /** authentication using EAP */ AUTH_CLASS_EAP = 3, - /** authentication using pre-shared secrets in combination with XAuth */ - AUTH_CLASS_XAUTH_PSK = 4, - /** authentication using public keys in combination with XAuth */ - AUTH_CLASS_XAUTH_PUBKEY = 5, + /** authentication using IKEv1 XAUTH */ + AUTH_CLASS_XAUTH = 4, }; /** From 4e73f85b818c3abf48f5c5ae3db98cc6be7dd34f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 15:38:28 +0000 Subject: [PATCH 241/534] Remove xauth_authenticator, we handle it in the task --- src/libcharon/Makefile.am | 1 - .../sa/authenticators/xauth_authenticator.c | 175 ------------------ .../sa/authenticators/xauth_authenticator.h | 55 ------ 3 files changed, 231 deletions(-) delete mode 100644 src/libcharon/sa/authenticators/xauth_authenticator.c delete mode 100644 src/libcharon/sa/authenticators/xauth_authenticator.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 3bddf0e61..0ff9a35b1 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -65,7 +65,6 @@ sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \ sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \ sa/authenticators/psk_v1_authenticator.c sa/authenticators/psk_v1_authenticator.h \ sa/authenticators/pubkey_v1_authenticator.c sa/authenticators/pubkey_v1_authenticator.h \ -sa/authenticators/xauth_authenticator.c sa/authenticators/xauth_authenticator.h \ sa/authenticators/xauth/xauth_method.c sa/authenticators/xauth/xauth_method.h \ sa/authenticators/xauth/xauth_manager.c sa/authenticators/xauth/xauth_manager.h \ sa/child_sa.c sa/child_sa.h \ diff --git a/src/libcharon/sa/authenticators/xauth_authenticator.c b/src/libcharon/sa/authenticators/xauth_authenticator.c deleted file mode 100644 index 871817d70..000000000 --- a/src/libcharon/sa/authenticators/xauth_authenticator.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2005-2009 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 . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "xauth_authenticator.h" - -#include -#include -#include - -typedef struct private_xauth_authenticator_t private_xauth_authenticator_t; - -/** - * Private data of an xauth_authenticator_t object. - */ -struct private_xauth_authenticator_t { - - /** - * Public authenticator_t interface. - */ - xauth_authenticator_t public; - - /** - * Assigned IKE_SA - */ - ike_sa_t *ike_sa; - - /** - * The payload to send - */ - cp_payload_t *cp_payload; - - /** - * Whether the authenticator is for an XAUTH server or client - */ - xauth_role_t role; -}; - -/** - * load an XAuth method - */ -static xauth_method_t *load_method(private_xauth_authenticator_t *this, - xauth_type_t type, u_int32_t vendor) -{ - identification_t *server, *peer, *aaa; - auth_cfg_t *auth; - - if (this->role == XAUTH_SERVER) - { - server = this->ike_sa->get_my_id(this->ike_sa); - peer = this->ike_sa->get_other_id(this->ike_sa); - auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - } - else - { - server = this->ike_sa->get_other_id(this->ike_sa); - peer = this->ike_sa->get_my_id(this->ike_sa); - auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - } - aaa = auth->get(auth, AUTH_RULE_AAA_IDENTITY); - if (aaa) - { - server = aaa; - } - return charon->xauth->create_instance(charon->xauth, type, vendor, - this->role, server, peer); -} - -METHOD(authenticator_t, build, status_t, - private_xauth_authenticator_t *this, message_t *message) -{ - if(this->cp_payload != NULL) - { - message->add_payload(message, (payload_t *)this->cp_payload); - return NEED_MORE; - } - return SUCCESS; -} - -METHOD(authenticator_t, process, status_t, - private_xauth_authenticator_t *this, message_t *message) -{ - xauth_method_t *xauth_method = NULL; - cp_payload_t *cp_in, *cp_out; - status_t status = FAILED; - - cp_in = (cp_payload_t *)message->get_payload(message, CONFIGURATION_V1); - - xauth_method = load_method(this, XAUTH_NULL, 0); - - if(xauth_method != NULL) - { - status = xauth_method->process(xauth_method, cp_in, &cp_out); - if(status == NEED_MORE) - { - this->cp_payload = cp_out; - } - else - { - xauth_method->destroy(xauth_method); - } - } - else - { - DBG1(DBG_IKE, "Couldn't locate valid xauth method."); - } - - return status; -} - -METHOD(authenticator_t, destroy, void, - private_xauth_authenticator_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -xauth_authenticator_t *xauth_authenticator_create_builder(ike_sa_t *ike_sa) -{ - private_xauth_authenticator_t *this; - - INIT(this, - .public = { - .authenticator = { - .build = _build, - .process = _process, - .is_mutual = (void*)return_false, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .cp_payload = NULL, - .role = XAUTH_PEER, - ); - - return &this->public; -} - -/* - * Described in header. - */ -xauth_authenticator_t *xauth_authenticator_create_verifier(ike_sa_t *ike_sa) -{ - private_xauth_authenticator_t *this; - - INIT(this, - .public = { - .authenticator = { - .build = _build, - .process = _process, - .is_mutual = (void*)return_false, - .destroy = _destroy, - }, - }, - .ike_sa = ike_sa, - .cp_payload = NULL, - .role = XAUTH_SERVER, - ); - - return &this->public; -} diff --git a/src/libcharon/sa/authenticators/xauth_authenticator.h b/src/libcharon/sa/authenticators/xauth_authenticator.h deleted file mode 100644 index d316b1672..000000000 --- a/src/libcharon/sa/authenticators/xauth_authenticator.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2006-2009 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_authenticator xauth_authenticator - * @{ @ingroup authenticators - */ - -#ifndef XAUTH_AUTHENTICATOR_H_ -#define XAUTH_AUTHENTICATOR_H_ - -typedef struct xauth_authenticator_t xauth_authenticator_t; - -#include - -/** - * Implementation of authenticator_t using XAuth. - */ -struct xauth_authenticator_t { - - /** - * Implemented authenticator_t interface. - */ - authenticator_t authenticator; -}; - -/** - * Create an authenticator to build XAuth response payloads. - * - * @param ike_sa associated ike_sa - * @return PSK authenticator - */ -xauth_authenticator_t *xauth_authenticator_create_builder(ike_sa_t *ike_sa); - -/** - * Create an authenticator to verify using XAuth payloads. - * - * @param ike_sa associated ike_sa - * @return PSK authenticator - */ -xauth_authenticator_t *xauth_authenticator_create_verifier(ike_sa_t *ike_sa); - -#endif /** XAUTH_AUTHENTICATOR_H_ @}*/ From 1fe6cdfac2631434464a2a550414f45b60558369 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 16:42:11 +0100 Subject: [PATCH 242/534] Use a string to identify xauth backends, no need for integer types --- src/libcharon/plugins/xauth_null/xauth_null.c | 10 +--- src/libcharon/plugins/xauth_null/xauth_null.h | 4 +- .../plugins/xauth_null/xauth_null_plugin.c | 4 +- .../sa/authenticators/xauth/xauth_manager.c | 53 +++++++++--------- .../sa/authenticators/xauth/xauth_manager.h | 26 +++++---- .../sa/authenticators/xauth/xauth_method.c | 6 +-- .../sa/authenticators/xauth/xauth_method.h | 22 ++------ src/libstrongswan/Makefile.am | 3 +- src/libstrongswan/plugins/plugin_feature.h | 7 ++- src/libstrongswan/xauth/xauth.c | 50 ----------------- src/libstrongswan/xauth/xauth.h | 54 ------------------- 11 files changed, 52 insertions(+), 187 deletions(-) delete mode 100644 src/libstrongswan/xauth/xauth.c delete mode 100644 src/libstrongswan/xauth/xauth.h diff --git a/src/libcharon/plugins/xauth_null/xauth_null.c b/src/libcharon/plugins/xauth_null/xauth_null.c index 34ed4959a..5d2b02d24 100644 --- a/src/libcharon/plugins/xauth_null/xauth_null.c +++ b/src/libcharon/plugins/xauth_null/xauth_null.c @@ -72,12 +72,6 @@ METHOD(xauth_method_t, initiate_server, status_t, return NEED_MORE; } -METHOD(xauth_method_t, get_type, xauth_type_t, - private_xauth_null_t *this, u_int32_t *vendor) -{ - return XAUTH_NULL; -} - METHOD(xauth_method_t, destroy, void, private_xauth_null_t *this) { @@ -89,7 +83,7 @@ METHOD(xauth_method_t, destroy, void, * Described in header. */ xauth_null_t *xauth_null_create_peer(identification_t *server, - identification_t *peer) + identification_t *peer) { private_xauth_null_t *this; @@ -98,7 +92,6 @@ xauth_null_t *xauth_null_create_peer(identification_t *server, .xauth_method = { .initiate = _initiate_peer, .process = _process_peer, - .get_type = _get_type, .destroy = _destroy, }, }, @@ -121,7 +114,6 @@ xauth_null_t *xauth_null_create_server(identification_t *server, .xauth_method = { .initiate = _initiate_server, .process = _process_server, - .get_type = _get_type, .destroy = _destroy, }, }, diff --git a/src/libcharon/plugins/xauth_null/xauth_null.h b/src/libcharon/plugins/xauth_null/xauth_null.h index e3ebaa128..1d3c34002 100644 --- a/src/libcharon/plugins/xauth_null/xauth_null.h +++ b/src/libcharon/plugins/xauth_null/xauth_null.h @@ -44,7 +44,7 @@ struct xauth_null_t { * @return xauth_null_t object */ xauth_null_t *xauth_null_create_server(identification_t *server, - identification_t *peer); + identification_t *peer); /** * Creates the XAuth method XAuth NULL, acting as peer. @@ -54,6 +54,6 @@ xauth_null_t *xauth_null_create_server(identification_t *server, * @return xauth_null_t object */ xauth_null_t *xauth_null_create_peer(identification_t *server, - identification_t *peer); + identification_t *peer); #endif /** XAUTH_NULL_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_null/xauth_null_plugin.c b/src/libcharon/plugins/xauth_null/xauth_null_plugin.c index 25b7b3841..28ea7af8d 100644 --- a/src/libcharon/plugins/xauth_null/xauth_null_plugin.c +++ b/src/libcharon/plugins/xauth_null/xauth_null_plugin.c @@ -29,9 +29,9 @@ METHOD(plugin_t, get_features, int, { static plugin_feature_t f[] = { PLUGIN_CALLBACK(xauth_method_register, xauth_null_create_server), - PLUGIN_PROVIDE(XAUTH_SERVER, XAUTH_NULL), + PLUGIN_PROVIDE(XAUTH_SERVER, "null"), PLUGIN_CALLBACK(xauth_method_register, xauth_null_create_peer), - PLUGIN_PROVIDE(XAUTH_PEER, XAUTH_NULL), + PLUGIN_PROVIDE(XAUTH_PEER, "null"), }; *features = f; return countof(f); diff --git a/src/libcharon/sa/authenticators/xauth/xauth_manager.c b/src/libcharon/sa/authenticators/xauth/xauth_manager.c index 3cddf64bd..618a0bdac 100644 --- a/src/libcharon/sa/authenticators/xauth/xauth_manager.c +++ b/src/libcharon/sa/authenticators/xauth/xauth_manager.c @@ -1,6 +1,6 @@ /* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -27,17 +27,12 @@ typedef struct xauth_entry_t xauth_entry_t; struct xauth_entry_t { /** - * XAuth method type, vendor specific if vendor is set + * Xauth backend name */ - xauth_type_t type; + char *name; /** - * vendor ID, 0 for default XAuth methods - */ - u_int32_t vendor; - - /** - * Role of the method returned by the constructor, XAUTH_SERVER or XAUTH_PEER + * Role of the method, XAUTH_SERVER or XAUTH_PEER */ xauth_role_t role; @@ -69,15 +64,16 @@ struct private_xauth_manager_t { }; METHOD(xauth_manager_t, add_method, void, - private_xauth_manager_t *this, xauth_type_t type, u_int32_t vendor, - xauth_role_t role, xauth_constructor_t constructor) + private_xauth_manager_t *this, char *name, xauth_role_t role, + xauth_constructor_t constructor) { - xauth_entry_t *entry = malloc_thing(xauth_entry_t); + xauth_entry_t *entry; - entry->type = type; - entry->vendor = vendor; - entry->role = role; - entry->constructor = constructor; + INIT(entry, + .name = name, + .role = role, + .constructor = constructor, + ); this->lock->write_lock(this->lock); this->methods->insert_last(this->methods, entry); @@ -105,8 +101,8 @@ METHOD(xauth_manager_t, remove_method, void, } METHOD(xauth_manager_t, create_instance, xauth_method_t*, - private_xauth_manager_t *this, xauth_type_t type, u_int32_t vendor, - xauth_role_t role, identification_t *server, identification_t *peer) + private_xauth_manager_t *this, char *name, xauth_role_t role, + identification_t *server, identification_t *peer) { enumerator_t *enumerator; xauth_entry_t *entry; @@ -116,8 +112,7 @@ METHOD(xauth_manager_t, create_instance, xauth_method_t*, enumerator = this->methods->create_enumerator(this->methods); while (enumerator->enumerate(enumerator, &entry)) { - if (type == entry->type && vendor == entry->vendor && - role == entry->role) + if (streq(name, entry->name) && role == entry->role) { method = entry->constructor(server, peer); if (method) @@ -147,14 +142,14 @@ xauth_manager_t *xauth_manager_create() private_xauth_manager_t *this; INIT(this, - .public = { - .add_method = _add_method, - .remove_method = _remove_method, - .create_instance = _create_instance, - .destroy = _destroy, - }, - .methods = linked_list_create(), - .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), + .public = { + .add_method = _add_method, + .remove_method = _remove_method, + .create_instance = _create_instance, + .destroy = _destroy, + }, + .methods = linked_list_create(), + .lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); return &this->public; diff --git a/src/libcharon/sa/authenticators/xauth/xauth_manager.h b/src/libcharon/sa/authenticators/xauth/xauth_manager.h index 401c13e99..7f07cc22a 100644 --- a/src/libcharon/sa/authenticators/xauth/xauth_manager.h +++ b/src/libcharon/sa/authenticators/xauth/xauth_manager.h @@ -1,6 +1,6 @@ /* - * Copyright (C) 2008 Martin Willi - * Hochschule fuer Technik Rapperswil + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -38,34 +38,32 @@ struct xauth_manager_t { /** * Register a XAuth method implementation. * - * @param method vendor specific method, if vendor != 0 - * @param vendor vendor ID, 0 for non-vendor (default) XAuth methods - * @param role XAuth role of the registered method + * @param name backend name to register + * @param role XAUTH_SERVER or XAUTH_PEER * @param constructor constructor function, returns an xauth_method_t */ - void (*add_method)(xauth_manager_t *this, xauth_type_t type, u_int32_t vendor, + void (*add_method)(xauth_manager_t *this, char *name, xauth_role_t role, xauth_constructor_t constructor); /** * Unregister a XAuth method implementation using it's constructor. * - * @param constructor constructor function to remove, as added in add_method + * @param constructor constructor function, as added in add_method */ void (*remove_method)(xauth_manager_t *this, xauth_constructor_t constructor); /** * Create a new XAuth method instance. * - * @param vendor vendor ID, 0 for non-vendor (default) XAuth methods - * @param role role of XAuth method, either XAUTH_SERVER or XAUTH_PEER + * @param name backend name, as it was registered with + * @param role XAUTH_SERVER or XAUTH_PEER * @param server identity of the server * @param peer identity of the peer (client) * @return XAUTH method instance, NULL if no constructor found */ - xauth_method_t* (*create_instance)(xauth_manager_t *this, xauth_type_t type, - u_int32_t vendor, xauth_role_t role, - identification_t *server, - identification_t *peer); + xauth_method_t* (*create_instance)(xauth_manager_t *this, + char *name, xauth_role_t role, + identification_t *server, identification_t *peer); /** * Destroy a eap_manager instance. @@ -78,4 +76,4 @@ struct xauth_manager_t { */ xauth_manager_t *xauth_manager_create(); -#endif /** EAP_MANAGER_H_ @}*/ +#endif /** XAUTH_MANAGER_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/xauth/xauth_method.c b/src/libcharon/sa/authenticators/xauth/xauth_method.c index 14da7b9ba..838822d1e 100644 --- a/src/libcharon/sa/authenticators/xauth/xauth_method.c +++ b/src/libcharon/sa/authenticators/xauth/xauth_method.c @@ -30,9 +30,9 @@ bool xauth_method_register(plugin_t *plugin, plugin_feature_t *feature, { if (reg) { - charon->xauth->add_method(charon->xauth, feature->arg.xauth, 0, - feature->type == FEATURE_XAUTH_SERVER ? XAUTH_SERVER : XAUTH_PEER, - (xauth_constructor_t)data); + charon->xauth->add_method(charon->xauth, feature->arg.xauth, + feature->type == FEATURE_XAUTH_SERVER ? XAUTH_SERVER : XAUTH_PEER, + (xauth_constructor_t)data); } else { diff --git a/src/libcharon/sa/authenticators/xauth/xauth_method.h b/src/libcharon/sa/authenticators/xauth/xauth_method.h index fb289a247..cc3c77540 100644 --- a/src/libcharon/sa/authenticators/xauth/xauth_method.h +++ b/src/libcharon/sa/authenticators/xauth/xauth_method.h @@ -28,7 +28,6 @@ typedef enum xauth_role_t xauth_role_t; #include #include #include -#include /** * Role of an xauth_method, SERVER or PEER (client) @@ -37,6 +36,7 @@ enum xauth_role_t { XAUTH_SERVER, XAUTH_PEER, }; + /** * enum names for xauth_role_t. */ @@ -46,12 +46,8 @@ extern enum_name_t *xauth_role_names; * Interface of an XAuth method for server and client side. * * An XAuth method initiates an XAuth exchange and processes requests and - * responses. An XAuth method may need multiple exchanges before succeeding, and - * the xauth_authentication may use multiple XAuth methods to authenticate a peer. - * To accomplish these requirements, all XAuth methods have their own - * implementation while the xauth_authenticatior uses one or more of these - * XAuth methods. Sending of XAUTH(STATUS) message is not the job - * of the method, the xauth_authenticator does this. + * responses. An XAuth method may need multiple exchanges before succeeding. + * Sending of XAUTH(STATUS) message is done by the framework, not a method. */ struct xauth_method_t { @@ -84,14 +80,6 @@ struct xauth_method_t { status_t (*process) (xauth_method_t *this, cp_payload_t *in, cp_payload_t **out); - /** - * Get the XAuth type implemented in this method. - * - * @param vendor pointer receiving vendor identifier for type, 0 for none - * @return type of the XAuth method - */ - xauth_type_t (*get_type) (xauth_method_t *this, u_int32_t *vendor); - /** * Destroys a eap_method_t object. */ @@ -106,8 +94,6 @@ struct xauth_method_t { * Constructors for server and peers are identical, to support both roles * of a XAuth method, a plugin needs register two constructors in the * xauth_manager_t. - * The passed identites are of type ID_EAP and valid only during the - * constructor invocation. * * @param server ID of the server to use for credential lookup * @param peer ID of the peer to use for credential lookup @@ -128,6 +114,6 @@ typedef xauth_method_t *(*xauth_constructor_t)(identification_t *server, * @param data data passed to callback, an xauth_constructor_t */ bool xauth_method_register(plugin_t *plugin, plugin_feature_t *feature, - bool reg, void *data); + bool reg, void *data); #endif /** XAUTH_METHOD_H_ @}*/ diff --git a/src/libstrongswan/Makefile.am b/src/libstrongswan/Makefile.am index bfa440d03..284decbd9 100644 --- a/src/libstrongswan/Makefile.am +++ b/src/libstrongswan/Makefile.am @@ -70,8 +70,7 @@ utils/linked_list.c utils/linked_list.h \ utils/hashtable.c utils/hashtable.h \ utils/enumerator.c utils/enumerator.h \ utils/optionsfrom.c utils/optionsfrom.h \ -utils/backtrace.c utils/backtrace.h \ -xauth/xauth.h xauth/xauth.c +utils/backtrace.c utils/backtrace.h library.lo : $(top_builddir)/config.status diff --git a/src/libstrongswan/plugins/plugin_feature.h b/src/libstrongswan/plugins/plugin_feature.h index 89c954471..54fd2c67f 100644 --- a/src/libstrongswan/plugins/plugin_feature.h +++ b/src/libstrongswan/plugins/plugin_feature.h @@ -25,7 +25,6 @@ typedef struct plugin_feature_t plugin_feature_t; #include #include -#include #include /** @@ -188,7 +187,7 @@ struct plugin_feature_t { /** FEATURE_CUSTOM */ char *custom; /** FEATURE_XAUTH_SERVER/CLIENT */ - xauth_type_t xauth; + char *xauth; /** FEATURE_REGISTER */ struct { @@ -273,8 +272,8 @@ struct plugin_feature_t { #define _PLUGIN_FEATURE_DATABASE(kind, type) __PLUGIN_FEATURE(kind, DATABASE, .database = type) #define _PLUGIN_FEATURE_FETCHER(kind, type) __PLUGIN_FEATURE(kind, FETCHER, .fetcher = type) #define _PLUGIN_FEATURE_CUSTOM(kind, name) __PLUGIN_FEATURE(kind, CUSTOM, .custom = name) -#define _PLUGIN_FEATURE_XAUTH_SERVER(kind, type) __PLUGIN_FEATURE(kind, XAUTH_SERVER, .xauth = type) -#define _PLUGIN_FEATURE_XAUTH_PEER(kind, type) __PLUGIN_FEATURE(kind, XAUTH_PEER, .xauth = type) +#define _PLUGIN_FEATURE_XAUTH_SERVER(kind, name) __PLUGIN_FEATURE(kind, XAUTH_SERVER, .xauth = name) +#define _PLUGIN_FEATURE_XAUTH_PEER(kind, name) __PLUGIN_FEATURE(kind, XAUTH_PEER, .xauth = name) #define __PLUGIN_FEATURE_REGISTER(type, _f) (plugin_feature_t){ FEATURE_REGISTER, FEATURE_##type, .arg.reg.f = _f } #define __PLUGIN_FEATURE_REGISTER_BUILDER(type, _f, _final) (plugin_feature_t){ FEATURE_REGISTER, FEATURE_##type, .arg.reg = {.f = _f, .final = _final, }} diff --git a/src/libstrongswan/xauth/xauth.c b/src/libstrongswan/xauth/xauth.c deleted file mode 100644 index b2caf374a..000000000 --- a/src/libstrongswan/xauth/xauth.c +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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 . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "xauth.h" - -ENUM_BEGIN(xauth_method_type_names, XAUTH_RADIUS, XAUTH_NULL, - "XAUTH_RADIUS", - "XAUTH_NULL"); -ENUM_END(xauth_method_type_names, XAUTH_NULL); - -ENUM_BEGIN(xauth_method_type_short_names, XAUTH_RADIUS, XAUTH_NULL, - "RAD", - "NULL"); -ENUM_END(xauth_method_type_short_names, XAUTH_NULL); - -/* - * See header - */ -xauth_type_t xauth_type_from_string(char *name) -{ - int i; - static struct { - char *name; - xauth_type_t type; - } types[] = { - {"radius", XAUTH_RADIUS}, - {"null", XAUTH_NULL}, - }; - - for (i = 0; i < countof(types); i++) - { - if (strcaseeq(name, types[i].name)) - { - return types[i].type; - } - } - return 0; -} diff --git a/src/libstrongswan/xauth/xauth.h b/src/libstrongswan/xauth/xauth.h deleted file mode 100644 index 97008afcb..000000000 --- a/src/libstrongswan/xauth/xauth.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2010 Martin Willi - * Copyright (C) 2010 revosec AG - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth xauth - * @{ @ingroup libstrongswan - */ - -#ifndef XAUTH_H__ -#define XAUTH_H__ - -typedef enum xauth_type_t xauth_type_t; - -#include - -/** - * XAuth types, defines the XAuth method implementation - */ -enum xauth_type_t { - XAUTH_RADIUS = 253, - XAUTH_NULL = 254, -}; - -/** - * enum names for xauth_type_t. - */ -extern enum_name_t *xauth_method_type_names; - -/** - * short string enum names for xauth_type_t. - */ -extern enum_name_t *xauth_method_type_short_names; - -/** - * Lookup the XAuth method type from a string. - * - * @param name XAuth method name (such as "md5", "aka") - * @return method type, 0 if unknown - */ -xauth_type_t xauth_type_from_string(char *name); - -#endif /** XAUTH_H_ @}*/ From 89afbe58bb38b127efaed14a88c517486d9bf965 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 16:53:01 +0100 Subject: [PATCH 243/534] Remove unused task swap_initiator method --- src/libcharon/sa/tasks/task.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 9a5cb7c53..7647dedde 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -159,11 +159,6 @@ struct task_t { * Destroys a task_t object. */ void (*destroy) (task_t *this); - - /** - * Swaps the initiator flag in a task (if applicable, NULL OK) - */ - void (*swap_initiator) (task_t *this); }; #endif /** TASK_H_ @}*/ From 6ebcbc654c5940d11be857ebb4d233caaaf311fa Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 16:53:27 +0100 Subject: [PATCH 244/534] Added auth_cfg option to select XAUTH backend to use --- src/libstrongswan/credentials/auth_cfg.c | 10 ++++++++++ src/libstrongswan/credentials/auth_cfg.h | 2 ++ src/libstrongswan/plugins/plugin_feature.c | 4 ++-- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index 4b5dbbcf7..c9a8be61e 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -37,6 +37,7 @@ ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_REVOCATION_CERT, "RULE_EAP_IDENTITY", "RULE_EAP_TYPE", "RULE_EAP_VENDOR", + "RULE_XAUTH_BACKEND", "RULE_CA_CERT", "RULE_IM_CERT", "RULE_SUBJECT_CERT", @@ -159,6 +160,7 @@ static void destroy_entry_value(entry_t *entry) break; } case AUTH_RULE_CERT_POLICY: + case AUTH_RULE_XAUTH_BACKEND: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_SUBJECT_HASH_URL: { @@ -205,6 +207,7 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator, case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_BACKEND: case AUTH_RULE_GROUP: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: @@ -273,6 +276,7 @@ METHOD(auth_cfg_t, get, void*, case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_BACKEND: case AUTH_RULE_GROUP: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: @@ -313,6 +317,7 @@ static void add(private_auth_cfg_t *this, auth_rule_t type, ...) case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_BACKEND: case AUTH_RULE_GROUP: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: @@ -577,6 +582,8 @@ METHOD(auth_cfg_t, complies, bool, } break; } + case AUTH_RULE_XAUTH_BACKEND: + /* not enforced, just a hint for local authentication */ case AUTH_HELPER_IM_CERT: case AUTH_HELPER_SUBJECT_CERT: case AUTH_HELPER_IM_HASH_URL: @@ -656,6 +663,7 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy add(this, type, id->clone(id)); break; } + case AUTH_RULE_XAUTH_BACKEND: case AUTH_RULE_CERT_POLICY: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_SUBJECT_HASH_URL: @@ -755,6 +763,7 @@ static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other) } continue; } + case AUTH_RULE_XAUTH_BACKEND: case AUTH_RULE_CERT_POLICY: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_SUBJECT_HASH_URL: @@ -840,6 +849,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, clone->add(clone, entry->type, cert->get_ref(cert)); break; } + case AUTH_RULE_XAUTH_BACKEND: case AUTH_RULE_CERT_POLICY: case AUTH_HELPER_IM_HASH_URL: case AUTH_HELPER_SUBJECT_HASH_URL: diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index fd8e4c06a..3e0fc7376 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -78,6 +78,8 @@ enum auth_rule_t { AUTH_RULE_EAP_TYPE, /** EAP vendor for vendor specific type, u_int32_t */ AUTH_RULE_EAP_VENDOR, + /** XAUTH backend name to use, char* */ + AUTH_RULE_XAUTH_BACKEND, /** certificate authority, certificate_t* */ AUTH_RULE_CA_CERT, /** intermediate certificate in trustchain, certificate_t* */ diff --git a/src/libstrongswan/plugins/plugin_feature.c b/src/libstrongswan/plugins/plugin_feature.c index b2bf41946..6555e593b 100644 --- a/src/libstrongswan/plugins/plugin_feature.c +++ b/src/libstrongswan/plugins/plugin_feature.c @@ -234,8 +234,8 @@ char* plugin_feature_get_string(plugin_feature_t *feature) break; case FEATURE_XAUTH_SERVER: case FEATURE_XAUTH_PEER: - if (asprintf(&str, "%N:%N", plugin_feature_names, feature->type, - xauth_method_type_short_names, feature->arg.xauth) > 0) + if (asprintf(&str, "%N:%s", plugin_feature_names, feature->type, + feature->arg.xauth) > 0) { return str; } From cbda13f6fe63188b6372d693f916d84c992c223f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 16:57:38 +0100 Subject: [PATCH 245/534] Accept a xauth backend name appended to left/rightauth --- src/libcharon/plugins/stroke/stroke_config.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index f1af65e11..fec28c1ef 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -469,8 +469,15 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, { cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); } - else if (streq(auth, "xauth")) + else if (strneq(auth, "xauth", 5)) { + char *pos; + + pos = strchr(auth, '-'); + if (pos) + { + cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos)); + } cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH); } else if (strneq(auth, "eap", 3)) From 59ee898326c7e54b01d02ed15bb707ff7a7a6b22 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 17:19:10 +0100 Subject: [PATCH 246/534] Get first XAuth backend if none configured --- src/libcharon/sa/authenticators/xauth/xauth_manager.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/authenticators/xauth/xauth_manager.c b/src/libcharon/sa/authenticators/xauth/xauth_manager.c index 618a0bdac..432c9c0ab 100644 --- a/src/libcharon/sa/authenticators/xauth/xauth_manager.c +++ b/src/libcharon/sa/authenticators/xauth/xauth_manager.c @@ -112,7 +112,8 @@ METHOD(xauth_manager_t, create_instance, xauth_method_t*, enumerator = this->methods->create_enumerator(this->methods); while (enumerator->enumerate(enumerator, &entry)) { - if (streq(name, entry->name) && role == entry->role) + if (role == entry->role && + (!name || streq(name, entry->name))) { method = entry->constructor(server, peer); if (method) From 081b6dd3edba78ce6abe5da549e1595e90dd6755 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 18:08:13 +0100 Subject: [PATCH 247/534] Ask for a username/password in xauth-null as XAUTH initiator --- src/libcharon/plugins/xauth_null/xauth_null.c | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/libcharon/plugins/xauth_null/xauth_null.c b/src/libcharon/plugins/xauth_null/xauth_null.c index 5d2b02d24..86edc14e7 100644 --- a/src/libcharon/plugins/xauth_null/xauth_null.c +++ b/src/libcharon/plugins/xauth_null/xauth_null.c @@ -29,21 +29,15 @@ struct private_xauth_null_t { * Public authenticator_t interface. */ xauth_null_t public; - - /** - * ID of the peer - */ - identification_t *peer; }; METHOD(xauth_method_t, process_peer, status_t, private_xauth_null_t *this, cp_payload_t *in, cp_payload_t **out) { - chunk_t user_name = chunk_from_chars('j', 'o', 's', 't'); - chunk_t user_pass = chunk_from_chars('j', 'o', 's', 't'); + chunk_t user_name = chunk_from_chars('t', 'e', 's', 't'); + chunk_t user_pass = chunk_from_chars('t', 'e', 's', 't'); cp_payload_t *cp; - /* TODO-IKEv1: Fetch the user/pass from an authenticator */ cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); cp->add_attribute(cp, configuration_attribute_create_chunk( CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, user_name)); @@ -63,19 +57,28 @@ METHOD(xauth_method_t, initiate_peer, status_t, METHOD(xauth_method_t, process_server, status_t, private_xauth_null_t *this, cp_payload_t *in, cp_payload_t **out) { + /* always successful */ return SUCCESS; } METHOD(xauth_method_t, initiate_server, status_t, private_xauth_null_t *this, cp_payload_t **out) { + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + + *out = cp; return NEED_MORE; } METHOD(xauth_method_t, destroy, void, private_xauth_null_t *this) { - this->peer->destroy(this->peer); free(this); } @@ -95,7 +98,6 @@ xauth_null_t *xauth_null_create_peer(identification_t *server, .destroy = _destroy, }, }, - .peer = peer->clone(peer), ); return &this->public; @@ -117,7 +119,6 @@ xauth_null_t *xauth_null_create_server(identification_t *server, .destroy = _destroy, }, }, - .peer = peer->clone(peer), ); return &this->public; From d192cc9dc8c0d844a922ee3a1f8c95c9dc7a1f4e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 18:08:54 +0100 Subject: [PATCH 248/534] Implemented initiator part of xauth task --- src/libcharon/sa/tasks/xauth.c | 168 ++++++++++++++++++++++++++++++++- 1 file changed, 167 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/xauth.c b/src/libcharon/sa/tasks/xauth.c index 4d12e16e6..4fcb569a1 100644 --- a/src/libcharon/sa/tasks/xauth.c +++ b/src/libcharon/sa/tasks/xauth.c @@ -21,6 +21,14 @@ typedef struct private_xauth_t private_xauth_t; +/** + * Status types exchanged + */ +typedef enum { + XAUTH_FAILED = 0, + XAUTH_OK = 1, +} xauth_status_t; + /** * Private members of a xauth_t task. */ @@ -40,11 +48,116 @@ struct private_xauth_t { * Are we the XAUTH initiator? */ bool initiator; + + /** + * XAuth backend to use + */ + xauth_method_t *xauth; + + /** + * Generated configuration payload + */ + cp_payload_t *cp; + + /** + * status of Xauth exchange + */ + xauth_status_t status; }; +/** + * Load XAuth backend + */ +static xauth_method_t *load_method(ike_sa_t *ike_sa, bool initiator) +{ + identification_t *server, *peer; + enumerator_t *enumerator; + xauth_method_t *xauth; + xauth_role_t role; + peer_cfg_t *peer_cfg; + auth_cfg_t *auth; + char *name; + + if (initiator) + { + server = ike_sa->get_my_id(ike_sa); + peer = ike_sa->get_other_id(ike_sa); + role = XAUTH_SERVER; + } + else + { + peer = ike_sa->get_my_id(ike_sa); + server = ike_sa->get_other_id(ike_sa); + role = XAUTH_PEER; + } + peer_cfg = ike_sa->get_peer_cfg(ike_sa); + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !initiator); + if (!enumerator->enumerate(enumerator, &auth) || + !enumerator->enumerate(enumerator, &auth)) + { + DBG1(DBG_CFG, "no second authentication round found for XAuth"); + enumerator->destroy(enumerator); + return NULL; + } + name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND); + enumerator->destroy(enumerator); + + xauth = charon->xauth->create_instance(charon->xauth, name, role, + server, peer); + if (!xauth) + { + if (name) + { + DBG1(DBG_CFG, "no XAuth method found named '%s'"); + } + else + { + DBG1(DBG_CFG, "no XAuth method found"); + } + } + return xauth; +} + +METHOD(task_t, build_i_status, status_t, + private_xauth_t *this, message_t *message) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_SET); + cp->add_attribute(cp, + configuration_attribute_create_value(XAUTH_STATUS, this->status)); + + message->add_payload(message, (payload_t *)cp); + + return NEED_MORE; +} + METHOD(task_t, build_i, status_t, private_xauth_t *this, message_t *message) { + if (!this->xauth) + { + cp_payload_t *cp; + + this->xauth = load_method(this->ike_sa, this->initiator); + if (!this->xauth) + { + return FAILED; + } + if (this->xauth->initiate(this->xauth, &cp) != NEED_MORE) + { + return FAILED; + } + message->add_payload(message, (payload_t *)cp); + return NEED_MORE; + } + + if (this->cp) + { /* send previously generated payload */ + message->add_payload(message, (payload_t *)this->cp); + this->cp = NULL; + return NEED_MORE; + } return FAILED; } @@ -60,10 +173,60 @@ METHOD(task_t, build_r, status_t, return FAILED; } +METHOD(task_t, process_i_status, status_t, + private_xauth_t *this, message_t *message) +{ + cp_payload_t *cp; + + cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1); + if (!cp || cp->get_type(cp) != CFG_ACK) + { + DBG1(DBG_IKE, "received invalid XAUTH status response"); + return FAILED; + } + + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + return SUCCESS; +} + METHOD(task_t, process_i, status_t, private_xauth_t *this, message_t *message) { - return FAILED; + cp_payload_t *cp; + + cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1); + if (!cp) + { + DBG1(DBG_IKE, "configuration payload missing in XAuth response"); + return FAILED; + } + switch (this->xauth->process(this->xauth, cp, &this->cp)) + { + case NEED_MORE: + return NEED_MORE; + case SUCCESS: + DBG1(DBG_IKE, "XAuth authentication successful"); + this->status = XAUTH_OK; + break; + case FAILED: + DBG1(DBG_IKE, "XAuth authentication failed"); + break; + default: + return FAILED; + } + this->public.task.build = _build_i_status; + this->public.task.process = _process_i_status; + return NEED_MORE; } METHOD(task_t, get_type, task_type_t, @@ -81,6 +244,8 @@ METHOD(task_t, migrate, void, METHOD(task_t, destroy, void, private_xauth_t *this) { + DESTROY_IF(this->xauth); + DESTROY_IF(this->cp); free(this); } @@ -101,6 +266,7 @@ xauth_t *xauth_create(ike_sa_t *ike_sa, bool initiator) }, .initiator = initiator, .ike_sa = ike_sa, + .status = XAUTH_FAILED, ); if (initiator) From 9f43868a014189f7bd6d15bf8ed6cbd17673a6a1 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 8 Dec 2011 18:30:47 +0100 Subject: [PATCH 249/534] Implemented responder part of XAUTH task --- src/libcharon/sa/tasks/xauth.c | 108 +++++++++++++++++++++++++++++---- 1 file changed, 96 insertions(+), 12 deletions(-) diff --git a/src/libcharon/sa/tasks/xauth.c b/src/libcharon/sa/tasks/xauth.c index 4fcb569a1..de93935a9 100644 --- a/src/libcharon/sa/tasks/xauth.c +++ b/src/libcharon/sa/tasks/xauth.c @@ -118,6 +118,23 @@ static xauth_method_t *load_method(ike_sa_t *ike_sa, bool initiator) return xauth; } +/** + * Set IKE_SA to established state + */ +static void establish(private_xauth_t *this) +{ + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); +} + METHOD(task_t, build_i_status, status_t, private_xauth_t *this, message_t *message) { @@ -161,16 +178,92 @@ METHOD(task_t, build_i, status_t, return FAILED; } +METHOD(task_t, build_r_ack, status_t, + private_xauth_t *this, message_t *message) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK); + cp->add_attribute(cp, + configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty)); + + message->add_payload(message, (payload_t *)cp); + + if (this->status == XAUTH_OK) + { + establish(this); + return SUCCESS; + } + return FAILED; +} + METHOD(task_t, process_r, status_t, private_xauth_t *this, message_t *message) { - return FAILED; + cp_payload_t *cp; + + if (!this->xauth) + { + this->xauth = load_method(this->ike_sa, this->initiator); + if (!this->xauth) + { /* send empty reply */ + return NEED_MORE; + } + } + cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1); + if (!cp) + { + DBG1(DBG_IKE, "configuration payload missing in XAuth request"); + return FAILED; + } + if (cp->get_type(cp) == CFG_REQUEST) + { + switch (this->xauth->process(this->xauth, cp, &this->cp)) + { + case NEED_MORE: + return NEED_MORE; + case SUCCESS: + DBG1(DBG_IKE, "XAuth authentication successful"); + establish(this); + break; + case FAILED: + default: + DBG1(DBG_IKE, "XAuth authentication failed"); + break; + } + this->cp = NULL; + return NEED_MORE; + } + if (cp->get_type(cp) == CFG_SET) + { + configuration_attribute_t *attribute; + enumerator_t *enumerator; + + enumerator = cp->create_attribute_enumerator(cp); + while (enumerator->enumerate(enumerator, &attribute)) + { + if (attribute->get_type(attribute) == XAUTH_STATUS) + { + this->status = attribute->get_value(attribute); + } + } + enumerator->destroy(enumerator); + } + this->public.task.build = _build_r_ack; + return NEED_MORE; } METHOD(task_t, build_r, status_t, private_xauth_t *this, message_t *message) { - return FAILED; + if (!this->cp) + { /* send empty reply if building data failed */ + this->cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + } + message->add_payload(message, (payload_t *)this->cp); + this->cp = NULL; + return NEED_MORE; } METHOD(task_t, process_i_status, status_t, @@ -185,16 +278,7 @@ METHOD(task_t, process_i_status, status_t, return FAILED; } - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + establish(this); return SUCCESS; } From c9e5998d7f3583e9b2282c716c5c7f8a2dd26e25 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 9 Dec 2011 14:54:23 +0100 Subject: [PATCH 250/534] Interpret attribute format correctly in IKEv1 configuration format --- src/libcharon/encoding/payloads/configuration_attribute.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index fe2e42bc4..bcb89c515 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -97,9 +97,9 @@ static encoding_rule_t encodings_v2[] = { */ static encoding_rule_t encodings_v1[] = { /* AF Flag */ - { FLAG, offsetof(private_configuration_attribute_t, af_flag) }, + { ATTRIBUTE_FORMAT, offsetof(private_configuration_attribute_t, af_flag) }, /* type of the attribute as 15 bit unsigned integer */ - { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, /* Length of attribute value */ { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_configuration_attribute_t, length_or_value)}, /* Value of attribute if attribute format flag is zero */ From 9626164e9aa042bb74907577c861ddc8aa36191b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 9 Dec 2011 14:57:51 +0100 Subject: [PATCH 251/534] Don't complain when receiving XAuth or Unity configuration attributes --- .../payloads/configuration_attribute.c | 53 +++++++++++++------ 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index bcb89c515..db2e447a9 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -126,48 +126,71 @@ METHOD(payload_t, verify, status_t, switch (this->attr_type) { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_NETMASK: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case INTERNAL_ADDRESS_EXPIRY: - case INTERNAL_IP4_DHCP: + case INTERNAL_IP4_ADDRESS: + case INTERNAL_IP4_NETMASK: + case INTERNAL_IP4_DNS: + case INTERNAL_IP4_NBNS: + case INTERNAL_ADDRESS_EXPIRY: + case INTERNAL_IP4_DHCP: if (this->length_or_value != 0 && this->length_or_value != 4) { failed = TRUE; } break; - case INTERNAL_IP4_SUBNET: + case INTERNAL_IP4_SUBNET: if (this->length_or_value != 0 && this->length_or_value != 8) { failed = TRUE; } break; - case INTERNAL_IP6_ADDRESS: - case INTERNAL_IP6_SUBNET: + case INTERNAL_IP6_ADDRESS: + case INTERNAL_IP6_SUBNET: if (this->length_or_value != 0 && this->length_or_value != 17) { failed = TRUE; } break; - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: - case INTERNAL_IP6_DHCP: + case INTERNAL_IP6_DNS: + case INTERNAL_IP6_NBNS: + case INTERNAL_IP6_DHCP: if (this->length_or_value != 0 && this->length_or_value != 16) { failed = TRUE; } break; - case SUPPORTED_ATTRIBUTES: + case SUPPORTED_ATTRIBUTES: if (this->length_or_value % 2) { failed = TRUE; } break; - case APPLICATION_VERSION: + case APPLICATION_VERSION: + case INTERNAL_IP4_SERVER: + case INTERNAL_IP6_SERVER: + case XAUTH_TYPE: + case XAUTH_USER_NAME: + case XAUTH_USER_PASSWORD: + case XAUTH_PASSCODE: + case XAUTH_MESSAGE: + case XAUTH_CHALLENGE: + case XAUTH_DOMAIN: + case XAUTH_STATUS: + case XAUTH_NEXT_PIN: + case XAUTH_ANSWER: + case UNITY_BANNER: + case UNITY_SAVE_PASSWD: + case UNITY_DEF_DOMAIN: + case UNITY_SPLITDNS_NAME: + case UNITY_SPLIT_INCLUDE: + case UNITY_NATT_PORT: + case UNITY_LOCAL_LAN: + case UNITY_PFS: + case UNITY_FW_TYPE: + case UNITY_BACKUP_SERVERS: + case UNITY_DDNS_HOSTNAME: /* any length acceptable */ break; - default: + default: DBG1(DBG_ENC, "unknown attribute type %N", configuration_attribute_type_names, this->attr_type); break; From f223a28ae71d5c9c883450bacabf51b62dcbabaa Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 7 Dec 2011 13:40:38 +0100 Subject: [PATCH 252/534] Be less verbose if plugin dependecy not satisfied --- src/libstrongswan/plugins/plugin_loader.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/plugins/plugin_loader.c b/src/libstrongswan/plugins/plugin_loader.c index a8f7a64fd..4d26a77f8 100644 --- a/src/libstrongswan/plugins/plugin_loader.c +++ b/src/libstrongswan/plugins/plugin_loader.c @@ -292,7 +292,7 @@ static bool dependencies_satisfied(private_plugin_loader_t *this, name = entry->plugin->get_name(entry->plugin); provide = plugin_feature_get_string(&features[0]); depend = plugin_feature_get_string(&features[i]); - DBG1(DBG_LIB, "feature %s in '%s' plugin has unsatisfied " + DBG2(DBG_LIB, "feature %s in '%s' plugin has unsatisfied " "dependency: %s", provide, name, depend); free(provide); free(depend); From 67a753b95c703d0d32a87362db8e3a4b8c5f4986 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 9 Dec 2011 15:10:38 +0100 Subject: [PATCH 253/534] Use a common function to set IKE_SA to established --- src/libcharon/sa/tasks/main_mode.c | 51 +++++++++++++----------------- 1 file changed, 22 insertions(+), 29 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index adf9142e5..d31458b07 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -757,6 +757,23 @@ static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, return TRUE; } +/** + * Set IKE_SA to established state + */ +static void establish(private_main_mode_t *this) +{ + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); +} + METHOD(task_t, build_r, status_t, private_main_mode_t *this, message_t *message) { @@ -819,21 +836,9 @@ METHOD(task_t, build_r, status_t, /* TODO-IKEv1: not yet supported */ return FAILED; default: - break; + establish(this); + return SUCCESS; } - - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - - return SUCCESS; } default: return FAILED; @@ -928,28 +933,16 @@ METHOD(task_t, process_i, status_t, { case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_INIT_RSA: - /* TODO-IKEv1: wait for XAUTH request */ + /* wait for XAUTH request */ return SUCCESS; case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: /* TODO-IKEv1: not yet */ return FAILED; default: - break; + establish(this); + return SUCCESS; } - - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); - - return SUCCESS; } default: return FAILED; From a22b9e4f3385072edc2faa8ae28fb1c935d95266 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 9 Dec 2011 15:18:23 +0100 Subject: [PATCH 254/534] Reject quick modes if IKE_SA not yet established --- src/libcharon/sa/task_manager_v1.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index c01229564..7fda51eeb 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -592,6 +592,12 @@ static status_t process_request(private_task_manager_t *this, /* TODO-IKEv1: agressive mode */ return FAILED; case QUICK_MODE: + if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) + { + DBG1(DBG_IKE, "received quick mode request for " + "unestablished IKE_SA, ignored"); + return FAILED; + } task = (task_t *)quick_mode_create(this->ike_sa, NULL, NULL, NULL); this->passive_tasks->insert_last(this->passive_tasks, task); From 21c916886df44c5f3bd829239b9431f422c754e0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 9 Dec 2011 15:22:30 +0100 Subject: [PATCH 255/534] Added missing XAuth auth_class enum name --- src/libstrongswan/credentials/auth_cfg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index c9a8be61e..3420e3157 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -23,11 +23,12 @@ #include #include -ENUM(auth_class_names, AUTH_CLASS_ANY, AUTH_CLASS_EAP, +ENUM(auth_class_names, AUTH_CLASS_ANY, AUTH_CLASS_XAUTH, "any", "public key", "pre-shared key", "EAP", + "XAuth", ); ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_REVOCATION_CERT, From b155084c42277a4a72f2b90997b6c5d32708aef3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 9 Dec 2011 16:18:22 +0100 Subject: [PATCH 256/534] Added IKEv1 Mode Config task based on IKEv2 ike_config --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/tasks/mode_config.c | 417 +++++++++++++++++++++++++++ src/libcharon/sa/tasks/mode_config.h | 50 ++++ src/libcharon/sa/tasks/task.c | 2 + src/libcharon/sa/tasks/task.h | 2 + 5 files changed, 472 insertions(+) create mode 100644 src/libcharon/sa/tasks/mode_config.c create mode 100644 src/libcharon/sa/tasks/mode_config.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 0ff9a35b1..1b4469649 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -100,6 +100,7 @@ sa/tasks/ike_vendor_v1.c sa/tasks/ike_vendor_v1.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/xauth.c sa/tasks/xauth.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ +sa/tasks/mode_config.c sa/tasks/mode_config.h \ sa/tasks/task.c sa/tasks/task.h diff --git a/src/libcharon/sa/tasks/mode_config.c b/src/libcharon/sa/tasks/mode_config.c new file mode 100644 index 000000000..e99d07428 --- /dev/null +++ b/src/libcharon/sa/tasks/mode_config.c @@ -0,0 +1,417 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "mode_config.h" + +#include +#include +#include + +typedef struct private_mode_config_t private_mode_config_t; + +/** + * Private members of a mode_config_t task. + */ +struct private_mode_config_t { + + /** + * Public methods and task_t interface. + */ + mode_config_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * virtual ip + */ + host_t *virtual_ip; + + /** + * list of attributes requested and its handler, entry_t + */ + linked_list_t *requested; +}; + +/** + * Entry for a requested attribute and the requesting handler + */ +typedef struct { + /** attribute requested */ + configuration_attribute_type_t type; + /** handler requesting this attribute */ + attribute_handler_t *handler; +} entry_t; + +/** + * build INTERNAL_IPV4/6_ADDRESS attribute from virtual ip + */ +static configuration_attribute_t *build_vip(host_t *vip) +{ + configuration_attribute_type_t type; + chunk_t chunk, prefix; + + if (vip->get_family(vip) == AF_INET) + { + type = INTERNAL_IP4_ADDRESS; + if (vip->is_anyaddr(vip)) + { + chunk = chunk_empty; + } + else + { + chunk = vip->get_address(vip); + } + } + else + { + type = INTERNAL_IP6_ADDRESS; + if (vip->is_anyaddr(vip)) + { + chunk = chunk_empty; + } + else + { + prefix = chunk_alloca(1); + *prefix.ptr = 64; + chunk = vip->get_address(vip); + chunk = chunk_cata("cc", chunk, prefix); + } + } + return configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, + type, chunk); +} + +/** + * Handle a received attribute as initiator + */ +static void handle_attribute(private_mode_config_t *this, + configuration_attribute_t *ca) +{ + attribute_handler_t *handler = NULL; + enumerator_t *enumerator; + entry_t *entry; + + /* find the handler which requested this attribute */ + enumerator = this->requested->create_enumerator(this->requested); + while (enumerator->enumerate(enumerator, &entry)) + { + if (entry->type == ca->get_type(ca)) + { + handler = entry->handler; + this->requested->remove_at(this->requested, enumerator); + free(entry); + break; + } + } + enumerator->destroy(enumerator); + + /* and pass it to the handle function */ + handler = hydra->attributes->handle(hydra->attributes, + this->ike_sa->get_other_id(this->ike_sa), handler, + ca->get_type(ca), ca->get_chunk(ca)); + if (handler) + { + this->ike_sa->add_configuration_attribute(this->ike_sa, + handler, ca->get_type(ca), ca->get_chunk(ca)); + } +} + +/** + * process a single configuration attribute + */ +static void process_attribute(private_mode_config_t *this, + configuration_attribute_t *ca) +{ + host_t *ip; + chunk_t addr; + int family = AF_INET6; + + switch (ca->get_type(ca)) + { + case INTERNAL_IP4_ADDRESS: + family = AF_INET; + /* fall */ + case INTERNAL_IP6_ADDRESS: + { + addr = ca->get_chunk(ca); + if (addr.len == 0) + { + ip = host_create_any(family); + } + else + { + /* skip prefix byte in IPv6 payload*/ + if (family == AF_INET6) + { + addr.len--; + } + ip = host_create_from_chunk(family, addr, 0); + } + if (ip) + { + DESTROY_IF(this->virtual_ip); + this->virtual_ip = ip; + } + break; + } + default: + { + if (this->initiator) + { + handle_attribute(this, ca); + } + } + } +} + +/** + * Scan for configuration payloads and attributes + */ +static void process_payloads(private_mode_config_t *this, message_t *message) +{ + enumerator_t *enumerator, *attributes; + payload_t *payload; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == CONFIGURATION_V1) + { + cp_payload_t *cp = (cp_payload_t*)payload; + configuration_attribute_t *ca; + + switch (cp->get_type(cp)) + { + case CFG_REQUEST: + case CFG_REPLY: + attributes = cp->create_attribute_enumerator(cp); + while (attributes->enumerate(attributes, &ca)) + { + DBG2(DBG_IKE, "processing %N attribute", + configuration_attribute_type_names, ca->get_type(ca)); + process_attribute(this, ca); + } + attributes->destroy(attributes); + break; + default: + DBG1(DBG_IKE, "ignoring %N config payload", + config_type_names, cp->get_type(cp)); + break; + } + } + } + enumerator->destroy(enumerator); +} + +METHOD(task_t, build_i, status_t, + private_mode_config_t *this, message_t *message) +{ + cp_payload_t *cp = NULL; + enumerator_t *enumerator; + attribute_handler_t *handler; + peer_cfg_t *config; + configuration_attribute_type_t type; + chunk_t data; + host_t *vip; + + /* reuse virtual IP if we already have one */ + vip = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (!vip) + { + config = this->ike_sa->get_peer_cfg(this->ike_sa); + vip = config->get_virtual_ip(config); + } + if (vip) + { + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, build_vip(vip)); + } + + enumerator = hydra->attributes->create_initiator_enumerator(hydra->attributes, + this->ike_sa->get_other_id(this->ike_sa), vip); + while (enumerator->enumerate(enumerator, &handler, &type, &data)) + { + configuration_attribute_t *ca; + entry_t *entry; + + DBG2(DBG_IKE, "building %N attribute", + configuration_attribute_type_names, type); + ca = configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, + type, data); + if (!cp) + { + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + } + cp->add_attribute(cp, ca); + + INIT(entry, + .type = type, + .handler = handler, + ); + this->requested->insert_last(this->requested, entry); + } + enumerator->destroy(enumerator); + + if (cp) + { + message->add_payload(message, (payload_t*)cp); + } + return NEED_MORE; +} + +METHOD(task_t, process_r, status_t, + private_mode_config_t *this, message_t *message) +{ + process_payloads(this, message); + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_mode_config_t *this, message_t *message) +{ + enumerator_t *enumerator; + configuration_attribute_type_t type; + chunk_t value; + host_t *vip = NULL; + cp_payload_t *cp = NULL; + peer_cfg_t *config; + identification_t *id; + + id = this->ike_sa->get_other_eap_id(this->ike_sa); + + config = this->ike_sa->get_peer_cfg(this->ike_sa); + if (this->virtual_ip) + { + DBG1(DBG_IKE, "peer requested virtual IP %H", this->virtual_ip); + if (config->get_pool(config)) + { + vip = hydra->attributes->acquire_address(hydra->attributes, + config->get_pool(config), id, this->virtual_ip); + } + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + if (vip) + { + DBG1(DBG_IKE, "assigning virtual IP %H to peer '%Y'", vip, id); + this->ike_sa->set_virtual_ip(this->ike_sa, FALSE, vip); + cp->add_attribute(cp, build_vip(vip)); + } + else + { + DBG1(DBG_IKE, "no virtual IP found, sending empty config payload"); + } + } + /* query registered providers for additional attributes to include */ + enumerator = hydra->attributes->create_responder_enumerator( + hydra->attributes, config->get_pool(config), id, vip); + while (enumerator->enumerate(enumerator, &type, &value)) + { + if (!cp) + { + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + } + DBG2(DBG_IKE, "building %N attribute", + configuration_attribute_type_names, type); + cp->add_attribute(cp, + configuration_attribute_create_chunk(CONFIGURATION_ATTRIBUTE_V1, + type, value)); + } + enumerator->destroy(enumerator); + + if (cp) + { + message->add_payload(message, (payload_t*)cp); + } + DESTROY_IF(vip); + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_mode_config_t *this, message_t *message) +{ + process_payloads(this, message); + + if (this->virtual_ip) + { + this->ike_sa->set_virtual_ip(this->ike_sa, TRUE, this->virtual_ip); + } + return SUCCESS; +} + +METHOD(task_t, get_type, task_type_t, + private_mode_config_t *this) +{ + return TASK_MODE_CONFIG; +} + +METHOD(task_t, migrate, void, + private_mode_config_t *this, ike_sa_t *ike_sa) +{ + DESTROY_IF(this->virtual_ip); + + this->ike_sa = ike_sa; + this->virtual_ip = NULL; + this->requested->destroy_function(this->requested, free); + this->requested = linked_list_create(); +} + +METHOD(task_t, destroy, void, + private_mode_config_t *this) +{ + DESTROY_IF(this->virtual_ip); + this->requested->destroy_function(this->requested, free); + free(this); +} + +/* + * Described in header. + */ +mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator) +{ + private_mode_config_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .initiator = initiator, + .ike_sa = ike_sa, + .requested = linked_list_create(), + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/tasks/mode_config.h b/src/libcharon/sa/tasks/mode_config.h new file mode 100644 index 000000000..34b744d10 --- /dev/null +++ b/src/libcharon/sa/tasks/mode_config.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup mode_config mode_config + * @{ @ingroup tasks + */ + +#ifndef MODE_CONFIG_H_ +#define MODE_CONFIG_H_ + +typedef struct mode_config_t mode_config_t; + +#include +#include +#include + +/** + * Task of type TASK_MODE_COFNIG, IKEv1 configuration attribute exchange. + */ +struct mode_config_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new mode_config task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE for initiator + * @return mode_config task to handle by the task_manager + */ +mode_config_t *mode_config_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** MODE_CONFIG_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index dc4bf5e97..ca5ecca73 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -37,6 +37,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, "CHILD_REKEY", "MAIN_MODE", "XAUTH", + "MODE_CONFIG", "QUICK_MODE", "VENDOR_V1", "IKE_NATD_V1", @@ -63,6 +64,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, "CHILD_REKEY", "MAIN_MODE", "XAUTH", + "MODE_CONFIG", "QUICK_MODE", "VENDOR_V1", "IKE_NATD_V1", diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 7647dedde..d368a6810 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -73,6 +73,8 @@ enum task_type_t { TASK_MAIN_MODE, /** IKEv1 XAUTH authentication */ TASK_XAUTH, + /** IKEv1 Mode Config */ + TASK_MODE_CONFIG, /** IKEv1 quick mode */ TASK_QUICK_MODE, /** IKEv1 vendor ID payload handling */ From 156b8662a64a4e251470de1e42213bc66f8e772e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 9 Dec 2011 16:19:37 +0100 Subject: [PATCH 257/534] Queue Mode Config tasks when required --- src/libcharon/sa/task_manager_v1.c | 30 ++++++++++++++++++++---------- src/libcharon/sa/tasks/main_mode.c | 7 +++++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 7fda51eeb..e899b0687 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -287,6 +288,12 @@ METHOD(task_manager_t, initiate, status_t, } break; case IKE_ESTABLISHED: + if (activate_task(this, TASK_MODE_CONFIG)) + { + exchange = TRANSACTION; + new_mid = TRUE; + break; + } if (activate_task(this, TASK_QUICK_MODE)) { exchange = QUICK_MODE; @@ -400,15 +407,11 @@ METHOD(task_manager_t, initiate, status_t, { return retransmit(this, this->initiating.seqnr); } - else - { - charon->sender->send(charon->sender, - this->initiating.packet->clone(this->initiating.packet)); - - this->initiating.packet->destroy(this->initiating.packet); - this->initiating.packet = NULL; - return SUCCESS; - } + charon->sender->send(charon->sender, + this->initiating.packet->clone(this->initiating.packet)); + this->initiating.packet->destroy(this->initiating.packet); + this->initiating.packet = NULL; + return SUCCESS; } /** @@ -654,7 +657,14 @@ static status_t process_request(private_task_manager_t *this, enumerator->destroy(enumerator); break; case TRANSACTION: - task = (task_t *)xauth_create(this->ike_sa, FALSE); + if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) + { + task = (task_t *)mode_config_create(this->ike_sa, FALSE); + } + else + { + task = (task_t *)xauth_create(this->ike_sa, FALSE); + } this->passive_tasks->insert_last(this->passive_tasks, task); break; default: diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index d31458b07..cea0631fe 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -29,6 +29,7 @@ #include #include #include +#include typedef struct private_main_mode_t private_main_mode_t; @@ -824,6 +825,12 @@ METHOD(task_t, build_r, status_t, return FAILED; } + if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE)); + } + switch (this->auth_method) { case AUTH_XAUTH_INIT_PSK: From ea9e047bc5324880650021e865dd06f158b5c607 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 9 Dec 2011 16:19:54 +0100 Subject: [PATCH 258/534] Use virtual IP to substitute dynamic traffic selectors in quick mode --- src/libcharon/sa/tasks/quick_mode.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 6b6a93505..0a625c31b 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -296,13 +296,17 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator) linked_list_t *list; host_t *host; - if (initiator) + host = this->ike_sa->get_virtual_ip(this->ike_sa, initiator); + if (!host) { - host = this->ike_sa->get_my_host(this->ike_sa); - } - else - { - host = this->ike_sa->get_other_host(this->ike_sa); + if (initiator) + { + host = this->ike_sa->get_my_host(this->ike_sa); + } + else + { + host = this->ike_sa->get_other_host(this->ike_sa); + } } list = this->config->get_traffic_selectors(this->config, initiator, NULL, host); From 0e2cc3fed93ac54e8acd1f4702dedc1a5a16cce3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 11:28:24 +0100 Subject: [PATCH 259/534] Fixed authentication method selection for main mode PSK authentication --- src/libcharon/sa/tasks/main_mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index cea0631fe..e674381fa 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -308,7 +308,7 @@ static auth_method_t get_auth_method(private_main_mode_t *this, return AUTH_XAUTH_RESP_RSA; } } - if (i1 == AUTH_CLASS_PSK && r2 == AUTH_CLASS_PSK) + if (i1 == AUTH_CLASS_PSK && r1 == AUTH_CLASS_PSK) { if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) { From d7376e2ab43316e0e5a4b93aa19f8a85644d94b6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 12:17:13 +0100 Subject: [PATCH 260/534] Accept NULL identities passed to peer config enumeration --- src/libcharon/config/backend_manager.c | 18 +++++++++--------- src/libcharon/sa/tasks/main_mode.c | 5 +---- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c index a93457ea4..c84da2504 100644 --- a/src/libcharon/config/backend_manager.c +++ b/src/libcharon/config/backend_manager.c @@ -160,7 +160,7 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, while (enumerator->enumerate(enumerator, (void**)¤t)) { match = get_ike_match(current, me, other); - + DBG3(DBG_CFG, "ike config match: %d (%H %H)", match, me, other); if (match) { DBG2(DBG_CFG, " candidate: %s...%s, prio %d", @@ -195,9 +195,12 @@ static id_match_t get_peer_match(identification_t *id, auth_cfg_t *auth; identification_t *candidate; id_match_t match = ID_MATCH_NONE; + chunk_t data; if (!id) { + DBG3(DBG_CFG, "peer config match %s: %d (%N)", + local ? "local" : "remote", ID_MATCH_ANY, id_type_names, ID_ANY); return ID_MATCH_ANY; } @@ -221,6 +224,10 @@ static id_match_t get_peer_match(identification_t *id, } } enumerator->destroy(enumerator); + + data = id->get_encoding(id); + DBG3(DBG_CFG, "peer config match %s: %d (%N -> %#B)", + match, id_type_names, id->get_type(id), &data); return match; } @@ -351,18 +358,11 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, id_match_t match_peer_me, match_peer_other; ike_cfg_match_t match_ike; match_entry_t *entry; - chunk_t data; match_peer_me = get_peer_match(my_id, cfg, TRUE); - data = my_id->get_encoding(my_id); - DBG3(DBG_CFG, "match_peer_me: %d (%N -> %#B)", match_peer_me, - id_type_names, my_id->get_type(my_id), &data); match_peer_other = get_peer_match(other_id, cfg, FALSE); - data = other_id->get_encoding(other_id); - DBG3(DBG_CFG, "match_peer_other: %d (%N -> %#B)", match_peer_other, - id_type_names, other_id->get_type(other_id), &data); match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other); - DBG3(DBG_CFG, "match_ike: %d (%H %H)", match_ike, me, other); + DBG3(DBG_CFG, "ike config match: %d (%H %H)", match_ike, me, other); if (match_peer_me && match_peer_other && match_ike) { diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index e674381fa..dbdc0c07e 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -333,13 +333,11 @@ static auth_method_t get_auth_method(private_main_mode_t *this, static peer_cfg_t *select_config(private_main_mode_t *this, identification_t *id) { enumerator_t *enumerator; - identification_t *any; peer_cfg_t *current, *found = NULL; - any = identification_create_from_encoding(ID_ANY, chunk_empty); enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), any, id); + this->ike_sa->get_other_host(this->ike_sa), NULL, id); while (enumerator->enumerate(enumerator, ¤t)) { if (get_auth_method(this, current) == this->auth_method) @@ -349,7 +347,6 @@ static peer_cfg_t *select_config(private_main_mode_t *this, identification_t *id } } enumerator->destroy(enumerator); - any->destroy(any); return found; } From 033dfba01febe6e0c3310496f8d8a8c74fd3e626 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 12:30:47 +0100 Subject: [PATCH 261/534] Log peer cfg enumeration externally for flexibility --- src/libcharon/config/backend_manager.c | 3 --- src/libcharon/sa/tasks/ike_auth.c | 2 ++ src/libcharon/sa/tasks/main_mode.c | 7 +++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c index c84da2504..5fe137ed5 100644 --- a/src/libcharon/config/backend_manager.c +++ b/src/libcharon/config/backend_manager.c @@ -347,9 +347,6 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, return enumerator; } - DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]", - me, my_id, other, other_id); - configs = linked_list_create(); /* only once allocated helper list for sorting */ helper = linked_list_create(); diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/tasks/ike_auth.c index 4a92385ee..39d865c9f 100644 --- a/src/libcharon/sa/tasks/ike_auth.c +++ b/src/libcharon/sa/tasks/ike_auth.c @@ -269,6 +269,8 @@ static bool load_cfg_candidates(private_ike_auth_t *this) my_id = this->ike_sa->get_my_id(this->ike_sa); other_id = this->ike_sa->get_other_id(this->ike_sa); + DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]", + me, my_id, other, other_id); enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, me, other, my_id, other_id); while (enumerator->enumerate(enumerator, &peer_cfg)) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index dbdc0c07e..240f7f383 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -334,10 +334,13 @@ static peer_cfg_t *select_config(private_main_mode_t *this, identification_t *id { enumerator_t *enumerator; peer_cfg_t *current, *found = NULL; + host_t *me, *other; + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + DBG1(DBG_CFG, "looking for peer configs matching %H...%H[%Y]", me, other, id); enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), NULL, id); + me, other, NULL, id); while (enumerator->enumerate(enumerator, ¤t)) { if (get_auth_method(this, current) == this->auth_method) From cc6b03bb5a4dbdf74568d6966159380861c71c79 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 12:33:31 +0100 Subject: [PATCH 262/534] If no IKEv1 shared key found for hosts, try to find one based on config identities --- src/libcharon/sa/tasks/main_mode.c | 85 ++++++++++++++++++++++++------ 1 file changed, 68 insertions(+), 17 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 240f7f383..94d9f877d 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -145,13 +145,12 @@ struct private_main_mode_t { /** * Get the first authentcation config from peer config */ -static auth_cfg_t *get_auth_cfg(private_main_mode_t *this, bool local) +static auth_cfg_t *get_auth_cfg(peer_cfg_t *peer_cfg, bool local) { enumerator_t *enumerator; auth_cfg_t *cfg = NULL; - enumerator = this->peer_cfg->create_auth_cfg_enumerator(this->peer_cfg, - local); + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); enumerator->enumerate(enumerator, &cfg); enumerator->destroy(enumerator); return cfg; @@ -465,8 +464,8 @@ METHOD(task_t, build_i, status_t, this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); this->peer_cfg->get_ref(this->peer_cfg); - this->my_auth = get_auth_cfg(this, TRUE); - this->other_auth = get_auth_cfg(this, FALSE); + this->my_auth = get_auth_cfg(this->peer_cfg, TRUE); + this->other_auth = get_auth_cfg(this->peer_cfg, FALSE); if (!this->my_auth || !this->other_auth) { DBG1(DBG_CFG, "no auth config found"); @@ -659,8 +658,8 @@ METHOD(task_t, process_r, status_t, } this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); - this->my_auth = get_auth_cfg(this, TRUE); - this->other_auth = get_auth_cfg(this, FALSE); + this->my_auth = get_auth_cfg(this->peer_cfg, TRUE); + this->other_auth = get_auth_cfg(this->peer_cfg, FALSE); if (!this->my_auth || !this->other_auth) { DBG1(DBG_IKE, "auth config missing"); @@ -694,24 +693,76 @@ static shared_key_t *lookup_shared_key(private_main_mode_t *this) identification_t *my_id, *other_id; shared_key_t *shared_key; + /* try to get a PSK for IP addresses */ me = this->ike_sa->get_my_host(this->ike_sa); other = this->ike_sa->get_other_host(this->ike_sa); my_id = identification_create_from_sockaddr(me->get_sockaddr(me)); other_id = identification_create_from_sockaddr(other->get_sockaddr(other)); - if (!my_id || !other_id) + if (my_id && other_id) { - DESTROY_IF(my_id); - DESTROY_IF(other_id); - return NULL; + shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, + my_id, other_id); } - shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, my_id, - other_id); - if (!shared_key) + DESTROY_IF(my_id); + DESTROY_IF(other_id); + if (shared_key) { - DBG1(DBG_IKE, "no shared key found for %H - %H", me, other); + return shared_key; + } + + if (this->my_auth && this->other_auth) + { /* as initiator, use identities from configuraiton */ + my_id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY); + other_id = this->other_auth->get(this->other_auth, AUTH_RULE_IDENTITY); + if (my_id && other_id) + { + shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, + my_id, other_id); + } + else + { + DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]", + my_id, me, other_id, other); + } + } + else + { /* as responder, we try to find a config by IP */ + enumerator_t *enumerator; + auth_cfg_t *my_auth, *other_auth; + peer_cfg_t *peer_cfg = NULL; + + enumerator = charon->backends->create_peer_cfg_enumerator( + charon->backends, me, other, NULL, NULL); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + my_auth = get_auth_cfg(peer_cfg, TRUE); + other_auth = get_auth_cfg(peer_cfg, FALSE); + if (my_auth && other_auth) + { + my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY); + other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY); + if (my_id && other_id) + { + shared_key = lib->credmgr->get_shared(lib->credmgr, + SHARED_IKE, my_id, other_id); + if (shared_key) + { + break; + } + else + { + DBG1(DBG_IKE, "no shared key found for " + "'%Y'[%H] - '%Y'[%H]", my_id, me, other_id, other); + } + } + } + } + enumerator->destroy(enumerator); + if (!peer_cfg) + { + DBG1(DBG_IKE, "no shared key found for %H - %H", me, other); + } } - my_id->destroy(my_id); - other_id->destroy(other_id); return shared_key; } From e647c98a139c4421e1160f2383e3fb68ddd45aeb Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Mon, 12 Dec 2011 14:35:34 +0100 Subject: [PATCH 263/534] Setting Protocol ID of notifys sent from task manager to ISAKMP --- src/libcharon/sa/task_manager_v1.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index e899b0687..65cce8e46 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -505,6 +505,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) /** * Send a notify in a separate INFORMATIONAL exchange back to the sender. + * The notify protocol_id is set to ISAKMP */ static void send_notify_response(private_task_manager_t *this, message_t *request, notify_type_t type, @@ -538,7 +539,17 @@ static void send_notify_response(private_task_manager_t *this, } else { - response->add_notify(response, FALSE, type, data); + notify_payload_t *notify; + + notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_IKE, type); + + if (data.ptr) + { + notify->set_notification_data(notify, data); + } + + response->add_payload(response, (payload_t*)notify); } me = this->ike_sa->get_my_host(this->ike_sa); From 5c6abd2865059599124d96082c05241c682d43c3 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Mon, 12 Dec 2011 15:54:27 +0100 Subject: [PATCH 264/534] Added possibility to send notifications from the Quick Mode task --- src/libcharon/sa/tasks/quick_mode.c | 34 ++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) mode change 100644 => 100755 src/libcharon/sa/tasks/quick_mode.c diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c old mode 100644 new mode 100755 index 0a625c31b..18895db09 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -112,6 +112,11 @@ struct private_quick_mode_t { */ u_int64_t lifebytes; + /** + * Notify type in case of error + */ + notify_type_t notify_type; + /** states of quick mode */ enum { QM_INIT, @@ -514,6 +519,33 @@ static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload } } +METHOD(task_t, build_notify_error, status_t, + private_quick_mode_t *this, message_t *message) +{ + notify_payload_t *notify; + + notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_ESP, this->notify_type); + + notify->set_spi(notify, this->spi_i); + + message->add_payload(message, (payload_t*)notify); + + return SUCCESS; +} + +/** + * Set the task ready to build notify error message + */ +static status_t set_notify_error(private_quick_mode_t *this, + notify_type_t type) +{ + this->notify_type = type; + /* The task will be destroyed after build */ + this->public.task.build = _build_notify_error; + return FAILED_SEND_ERROR; +} + METHOD(task_t, build_i, status_t, private_quick_mode_t *this, message_t *message) { @@ -696,7 +728,7 @@ METHOD(task_t, process_r, status_t, if (!this->proposal) { DBG1(DBG_IKE, "no matching proposal found"); - return FAILED; + return set_notify_error(this, NO_PROPOSAL_CHOSEN); } this->spi_i = this->proposal->get_spi(this->proposal); From 41e1e435d9c70c28c3e38074d34c43e639ae79e6 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 12 Dec 2011 14:25:15 +0100 Subject: [PATCH 265/534] Removed xauth-null dummy plugin. --- configure.in | 4 - src/libcharon/Makefile.am | 7 +- src/libcharon/plugins/xauth_null/Makefile.am | 16 --- src/libcharon/plugins/xauth_null/xauth_null.c | 125 ------------------ src/libcharon/plugins/xauth_null/xauth_null.h | 59 --------- .../plugins/xauth_null/xauth_null_plugin.c | 62 --------- .../plugins/xauth_null/xauth_null_plugin.h | 42 ------ 7 files changed, 1 insertion(+), 314 deletions(-) delete mode 100644 src/libcharon/plugins/xauth_null/Makefile.am delete mode 100644 src/libcharon/plugins/xauth_null/xauth_null.c delete mode 100644 src/libcharon/plugins/xauth_null/xauth_null.h delete mode 100644 src/libcharon/plugins/xauth_null/xauth_null_plugin.c delete mode 100644 src/libcharon/plugins/xauth_null/xauth_null_plugin.h diff --git a/configure.in b/configure.in index 743500e28..5ab5417a8 100755 --- a/configure.in +++ b/configure.in @@ -193,7 +193,6 @@ ARG_ENABL_SET([duplicheck], [advanced duplicate checking plugin using livene ARG_ENABL_SET([coupling], [enable IKEv2 plugin to couple peer certificates permanently to authentication.]) ARG_ENABL_SET([vstr], [enforce using the Vstr string library to replace glibc-like printf hooks.]) ARG_ENABL_SET([monolithic], [build monolithic version of libstrongswan that includes all enabled plugins. Similarly, the plugins of charon are assembled in libcharon.]) -ARG_ENABL_SET([xauth-null], [enable XAuth module which does no actual identity authentication (testing only).]) dnl ========================= dnl set up compiler and flags @@ -865,7 +864,6 @@ ADD_PLUGIN([maemo], [c libcharon]) ADD_PLUGIN([uci], [c libcharon]) ADD_PLUGIN([addrblock], [c libcharon]) ADD_PLUGIN([unit-tester], [c libcharon]) -ADD_PLUGIN([xauth-null], [c libcharon]) AC_SUBST(libcharon_plugins) AC_SUBST(pluto_plugins) @@ -981,7 +979,6 @@ AM_CONDITIONAL(USE_SOCKET_RAW, test x$socket_raw = xtrue) AM_CONDITIONAL(USE_SOCKET_DYNAMIC, test x$socket_dynamic = xtrue) AM_CONDITIONAL(USE_FARP, test x$farp = xtrue) AM_CONDITIONAL(USE_ADDRBLOCK, test x$addrblock = xtrue) -AM_CONDITIONAL(USE_XAUTH_NULL, test x$xauth_null = xtrue) dnl hydra plugins dnl ============= @@ -1173,7 +1170,6 @@ AC_OUTPUT( src/libcharon/plugins/dhcp/Makefile src/libcharon/plugins/unit_tester/Makefile src/libcharon/plugins/load_tester/Makefile - src/libcharon/plugins/xauth_null/Makefile src/stroke/Makefile src/ipsec/Makefile src/starter/Makefile diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 1b4469649..4c6718340 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -503,9 +503,4 @@ if MONOLITHIC endif endif -if USE_XAUTH_NULL - SUBDIRS += plugins/xauth_null -if MONOLITHIC - libcharon_la_LIBADD += plugins/xauth_null/libstrongswan-xauth-null.la -endif -endif + diff --git a/src/libcharon/plugins/xauth_null/Makefile.am b/src/libcharon/plugins/xauth_null/Makefile.am deleted file mode 100644 index f4ff03c47..000000000 --- a/src/libcharon/plugins/xauth_null/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ - -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ - -I$(top_srcdir)/src/libcharon - -AM_CFLAGS = -rdynamic - -if MONOLITHIC -noinst_LTLIBRARIES = libstrongswan-xauth-null.la -else -plugin_LTLIBRARIES = libstrongswan-xauth-null.la -endif - -libstrongswan_xauth_null_la_SOURCES = \ - xauth_null_plugin.h xauth_null_plugin.c xauth_null.h xauth_null.c - -libstrongswan_xauth_null_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/xauth_null/xauth_null.c b/src/libcharon/plugins/xauth_null/xauth_null.c deleted file mode 100644 index 86edc14e7..000000000 --- a/src/libcharon/plugins/xauth_null/xauth_null.c +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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 . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "xauth_null.h" - -#include -#include - -typedef struct private_xauth_null_t private_xauth_null_t; - -/** - * Private data of an xauth_null_t object. - */ -struct private_xauth_null_t { - - /** - * Public authenticator_t interface. - */ - xauth_null_t public; -}; - -METHOD(xauth_method_t, process_peer, status_t, - private_xauth_null_t *this, cp_payload_t *in, cp_payload_t **out) -{ - chunk_t user_name = chunk_from_chars('t', 'e', 's', 't'); - chunk_t user_pass = chunk_from_chars('t', 'e', 's', 't'); - cp_payload_t *cp; - - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); - cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, user_name)); - cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, user_pass)); - *out = cp; - return NEED_MORE; -} - -METHOD(xauth_method_t, initiate_peer, status_t, - private_xauth_null_t *this, cp_payload_t **out) -{ - /* peer never initiates */ - return FAILED; -} - -METHOD(xauth_method_t, process_server, status_t, - private_xauth_null_t *this, cp_payload_t *in, cp_payload_t **out) -{ - /* always successful */ - return SUCCESS; -} - -METHOD(xauth_method_t, initiate_server, status_t, - private_xauth_null_t *this, cp_payload_t **out) -{ - cp_payload_t *cp; - - cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); - cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); - cp->add_attribute(cp, configuration_attribute_create_chunk( - CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); - - *out = cp; - return NEED_MORE; -} - -METHOD(xauth_method_t, destroy, void, - private_xauth_null_t *this) -{ - free(this); -} - -/* - * Described in header. - */ -xauth_null_t *xauth_null_create_peer(identification_t *server, - identification_t *peer) -{ - private_xauth_null_t *this; - - INIT(this, - .public = { - .xauth_method = { - .initiate = _initiate_peer, - .process = _process_peer, - .destroy = _destroy, - }, - }, - ); - - return &this->public; -} - -/* - * Described in header. - */ -xauth_null_t *xauth_null_create_server(identification_t *server, - identification_t *peer) -{ - private_xauth_null_t *this; - - INIT(this, - .public = { - .xauth_method = { - .initiate = _initiate_server, - .process = _process_server, - .destroy = _destroy, - }, - }, - ); - - return &this->public; -} diff --git a/src/libcharon/plugins/xauth_null/xauth_null.h b/src/libcharon/plugins/xauth_null/xauth_null.h deleted file mode 100644 index 1d3c34002..000000000 --- a/src/libcharon/plugins/xauth_null/xauth_null.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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 . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_null_i xauth_null - * @{ @ingroup xauth_null - */ - -#ifndef XAUTH_NULL_H_ -#define XAUTH_NULL_H_ - -typedef struct xauth_null_t xauth_null_t; - -#include - -/** - * Implementation of the xauth_method_t providing no actual identity verification. - */ -struct xauth_null_t { - - /** - * Implemented xauth_method_t interface. - */ - xauth_method_t xauth_method; -}; - -/** - * Creates the XAuth method XAuth NULL, acting as server. - * - * @param server ID of the XAuth server - * @param peer ID of the XAuth client - * @return xauth_null_t object - */ -xauth_null_t *xauth_null_create_server(identification_t *server, - identification_t *peer); - -/** - * Creates the XAuth method XAuth NULL, acting as peer. - * - * @param server ID of the XAuth server - * @param peer ID of the XAuth client - * @return xauth_null_t object - */ -xauth_null_t *xauth_null_create_peer(identification_t *server, - identification_t *peer); - -#endif /** XAUTH_NULL_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_null/xauth_null_plugin.c b/src/libcharon/plugins/xauth_null/xauth_null_plugin.c deleted file mode 100644 index 28ea7af8d..000000000 --- a/src/libcharon/plugins/xauth_null/xauth_null_plugin.c +++ /dev/null @@ -1,62 +0,0 @@ -/* - * 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 . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -#include "xauth_null_plugin.h" -#include "xauth_null.h" - -#include - -METHOD(plugin_t, get_name, char*, - xauth_null_plugin_t *this) -{ - return "xauth-null"; -} - -METHOD(plugin_t, get_features, int, - xauth_null_plugin_t *this, plugin_feature_t *features[]) -{ - static plugin_feature_t f[] = { - PLUGIN_CALLBACK(xauth_method_register, xauth_null_create_server), - PLUGIN_PROVIDE(XAUTH_SERVER, "null"), - PLUGIN_CALLBACK(xauth_method_register, xauth_null_create_peer), - PLUGIN_PROVIDE(XAUTH_PEER, "null"), - }; - *features = f; - return countof(f); -} - -METHOD(plugin_t, destroy, void, - xauth_null_plugin_t *this) -{ - free(this); -} - -/* - * see header file - */ -plugin_t *xauth_null_plugin_create() -{ - xauth_null_plugin_t *this; - - INIT(this, - .plugin = { - .get_name = _get_name, - .get_features = _get_features, - .destroy = _destroy, - }, - ); - - return &this->plugin; -} diff --git a/src/libcharon/plugins/xauth_null/xauth_null_plugin.h b/src/libcharon/plugins/xauth_null/xauth_null_plugin.h deleted file mode 100644 index 55f4ae19b..000000000 --- a/src/libcharon/plugins/xauth_null/xauth_null_plugin.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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 . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup xauth_null xauth_null - * @ingroup cplugins - * - * @defgroup xauth_null_plugin xauth_null_plugin - * @{ @ingroup xauth_null - */ - -#ifndef XAUTH_NULL_PLUGIN_H_ -#define XAUTH_NULL_PLUGIN_H_ - -#include - -typedef struct xauth_null_plugin_t xauth_null_plugin_t; - -/** - * XAUTH Null plugin. - */ -struct xauth_null_plugin_t { - - /** - * implements plugin interface - */ - plugin_t plugin; -}; - -#endif /** XAUTH_NULL_PLUGIN_H_ @}*/ From 3d44d735c649559b9768ae635a6bee7fec932902 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 12 Dec 2011 18:26:26 +0100 Subject: [PATCH 266/534] Added generic XAuth backend, using secrets provided by credential sets. --- configure.in | 4 + src/libcharon/Makefile.am | 6 + .../plugins/xauth_generic/Makefile.am | 17 ++ .../plugins/xauth_generic/xauth_generic.c | 210 ++++++++++++++++++ .../plugins/xauth_generic/xauth_generic.h | 60 +++++ .../xauth_generic/xauth_generic_plugin.c | 62 ++++++ .../xauth_generic/xauth_generic_plugin.h | 42 ++++ .../sa/authenticators/xauth/xauth_method.h | 2 +- 8 files changed, 402 insertions(+), 1 deletion(-) create mode 100644 src/libcharon/plugins/xauth_generic/Makefile.am create mode 100644 src/libcharon/plugins/xauth_generic/xauth_generic.c create mode 100644 src/libcharon/plugins/xauth_generic/xauth_generic.h create mode 100644 src/libcharon/plugins/xauth_generic/xauth_generic_plugin.c create mode 100644 src/libcharon/plugins/xauth_generic/xauth_generic_plugin.h diff --git a/configure.in b/configure.in index 5ab5417a8..0be86058a 100755 --- a/configure.in +++ b/configure.in @@ -129,6 +129,7 @@ ARG_ENABL_SET([eap-ttls], [enable EAP TTLS authentication module.]) ARG_ENABL_SET([eap-peap], [enable EAP PEAP authentication module.]) ARG_ENABL_SET([eap-tnc], [enable EAP TNC trusted network connect module.]) ARG_ENABL_SET([eap-radius], [enable RADIUS proxy authentication module.]) +ARG_ENABL_SET([xauth-generic], [enable generic XAuth backend.]) ARG_ENABL_SET([tnc-ifmap], [enable TNC IF-MAP module.]) ARG_ENABL_SET([tnc-imc], [enable TNC IMC module.]) ARG_ENABL_SET([tnc-imv], [enable TNC IMV module.]) @@ -842,6 +843,7 @@ ADD_PLUGIN([eap-tls], [c libcharon]) ADD_PLUGIN([eap-ttls], [c libcharon]) ADD_PLUGIN([eap-peap], [c libcharon]) ADD_PLUGIN([eap-tnc], [c libcharon]) +ADD_PLUGIN([xauth-generic], [c libcharon]) ADD_PLUGIN([tnc-ifmap], [c libcharon]) ADD_PLUGIN([tnc-imc], [c libcharon]) ADD_PLUGIN([tnc-imv], [c libcharon]) @@ -961,6 +963,7 @@ AM_CONDITIONAL(USE_EAP_TTLS, test x$eap_ttls = xtrue) AM_CONDITIONAL(USE_EAP_PEAP, test x$eap_peap = xtrue) AM_CONDITIONAL(USE_EAP_TNC, test x$eap_tnc = xtrue) AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue) +AM_CONDITIONAL(USE_XAUTH_GENERIC, test x$xauth_generic = xtrue) AM_CONDITIONAL(USE_TNC_IFMAP, test x$tnc_ifmap = xtrue) AM_CONDITIONAL(USE_TNC_IMC, test x$tnc_imc = xtrue) AM_CONDITIONAL(USE_TNC_IMV, test x$tnc_imv = xtrue) @@ -1139,6 +1142,7 @@ AC_OUTPUT( src/libcharon/plugins/eap_peap/Makefile src/libcharon/plugins/eap_tnc/Makefile src/libcharon/plugins/eap_radius/Makefile + src/libcharon/plugins/xauth_generic/Makefile src/libcharon/plugins/tnc_ifmap/Makefile src/libcharon/plugins/tnc_imc/Makefile src/libcharon/plugins/tnc_imv/Makefile diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 4c6718340..4e77b4f4f 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -503,4 +503,10 @@ if MONOLITHIC endif endif +if USE_XAUTH_GENERIC + SUBDIRS += plugins/xauth_generic +if MONOLITHIC + libcharon_la_LIBADD += plugins/xauth_generic/libstrongswan-xauth-generic.la +endif +endif diff --git a/src/libcharon/plugins/xauth_generic/Makefile.am b/src/libcharon/plugins/xauth_generic/Makefile.am new file mode 100644 index 000000000..0f25e74a2 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-xauth-generic.la +else +plugin_LTLIBRARIES = libstrongswan-xauth-generic.la +endif + +libstrongswan_xauth_generic_la_SOURCES = \ + xauth_generic_plugin.h xauth_generic_plugin.c \ + xauth_generic.h xauth_generic.c + +libstrongswan_xauth_generic_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.c b/src/libcharon/plugins/xauth_generic/xauth_generic.c new file mode 100644 index 000000000..cac740a34 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_generic.h" + +#include +#include + +typedef struct private_xauth_generic_t private_xauth_generic_t; + +/** + * Private data of an xauth_generic_t object. + */ +struct private_xauth_generic_t { + + /** + * Public interface. + */ + xauth_generic_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + +}; + +METHOD(xauth_method_t, initiate_peer, status_t, + private_xauth_generic_t *this, cp_payload_t **out) +{ + /* peer never initiates */ + return FAILED; +} + +METHOD(xauth_method_t, process_peer, status_t, + private_xauth_generic_t *this, cp_payload_t *in, cp_payload_t **out) +{ + shared_key_t *shared; + cp_payload_t *cp; + chunk_t user, pass; + + shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, this->peer, + this->server); + if (!shared) + { + DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'", this->peer, + this->server); + return FAILED; + } + + user = this->peer->get_encoding(this->peer); + pass = shared->get_key(shared); + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REPLY); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, user)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, pass)); + *out = cp; + return NEED_MORE; +} + +METHOD(xauth_method_t, initiate_server, status_t, + private_xauth_generic_t *this, cp_payload_t **out) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + *out = cp; + return NEED_MORE; +} + +METHOD(xauth_method_t, process_server, status_t, + private_xauth_generic_t *this, cp_payload_t *in, cp_payload_t **out) +{ + configuration_attribute_t *attr; + enumerator_t *enumerator; + shared_key_t *shared; + identification_t *id = NULL, *peer; + chunk_t user = chunk_empty, pass = chunk_empty; + status_t status = SUCCESS; + + enumerator = in->create_attribute_enumerator(in); + while (enumerator->enumerate(enumerator, &attr)) + { + switch (attr->get_type(attr)) + { + case XAUTH_USER_NAME: + user = attr->get_chunk(attr); + break; + case XAUTH_USER_PASSWORD: + pass = attr->get_chunk(attr); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (!user.ptr || !pass.ptr) + { + DBG1(DBG_IKE, "peer did not respond to our XAuth request"); + return FAILED; + } + if (user.len) + { + id = identification_create_from_data(user); + if (!id) + { + DBG1(DBG_IKE, "failed to parse provided XAuth username"); + return FAILED; + } + } + + peer = id ?: this->peer; + shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, this->server, + peer); + if (!shared) + { + DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'", this->server, + peer); + status = FAILED; + } + else if (!chunk_equals(shared->get_key(shared), pass)) + { + DBG1(DBG_IKE, "failed to authenticate '%Y' with XAuth", peer); + status = FAILED; + } + else + { + DBG2(DBG_IKE, "authentication of '%Y' with XAuth successful", peer); + } + DESTROY_IF(id); + return status; +} + +METHOD(xauth_method_t, destroy, void, + private_xauth_generic_t *this) +{ + this->server->destroy(this->server); + this->peer->destroy(this->peer); + free(this); +} + +/* + * Described in header. + */ +xauth_generic_t *xauth_generic_create_peer(identification_t *server, + identification_t *peer) +{ + private_xauth_generic_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate_peer, + .process = _process_peer, + .destroy = _destroy, + }, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + ); + + return &this->public; +} + +/* + * Described in header. + */ +xauth_generic_t *xauth_generic_create_server(identification_t *server, + identification_t *peer) +{ + private_xauth_generic_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate_server, + .process = _process_server, + .destroy = _destroy, + }, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + ); + + return &this->public; +} diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.h b/src/libcharon/plugins/xauth_generic/xauth_generic.h new file mode 100644 index 000000000..dfb759b82 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_generic_i xauth_generic + * @{ @ingroup xauth_generic + */ + +#ifndef XAUTH_GENERIC_H_ +#define XAUTH_GENERIC_H_ + +typedef struct xauth_generic_t xauth_generic_t; + +#include + +/** + * Implementation of the xauth_method_t interface using cleartext secrets + * from any credential set. + */ +struct xauth_generic_t { + + /** + * Implemented xauth_method_t interface. + */ + xauth_method_t xauth_method; +}; + +/** + * Creates the generic XAuth method, acting as server. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_generic_t object + */ +xauth_generic_t *xauth_generic_create_server(identification_t *server, + identification_t *peer); + +/** + * Creates the generic XAuth method, acting as peer. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_generic_t object + */ +xauth_generic_t *xauth_generic_create_peer(identification_t *server, + identification_t *peer); + +#endif /** XAUTH_GENERIC_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.c b/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.c new file mode 100644 index 000000000..a87084e20 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_generic_plugin.h" +#include "xauth_generic.h" + +#include + +METHOD(plugin_t, get_name, char*, + xauth_generic_plugin_t *this) +{ + return "xauth-generic"; +} + +METHOD(plugin_t, get_features, int, + xauth_generic_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(xauth_method_register, xauth_generic_create_server), + PLUGIN_PROVIDE(XAUTH_SERVER, "generic"), + PLUGIN_CALLBACK(xauth_method_register, xauth_generic_create_peer), + PLUGIN_PROVIDE(XAUTH_PEER, "generic"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + xauth_generic_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *xauth_generic_plugin_create() +{ + xauth_generic_plugin_t *this; + + INIT(this, + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + ); + + return &this->plugin; +} diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.h b/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.h new file mode 100644 index 000000000..426f806a7 --- /dev/null +++ b/src/libcharon/plugins/xauth_generic/xauth_generic_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_generic xauth_generic + * @ingroup cplugins + * + * @defgroup xauth_generic_plugin xauth_generic_plugin + * @{ @ingroup xauth_generic + */ + +#ifndef XAUTH_GENERIC_PLUGIN_H_ +#define XAUTH_GENERIC_PLUGIN_H_ + +#include + +typedef struct xauth_generic_plugin_t xauth_generic_plugin_t; + +/** + * XAuth generic plugin using secrets defined in ipsec.secrets. + */ +struct xauth_generic_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** XAUTH_GENERIC_PLUGIN_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/xauth/xauth_method.h b/src/libcharon/sa/authenticators/xauth/xauth_method.h index cc3c77540..c544724b8 100644 --- a/src/libcharon/sa/authenticators/xauth/xauth_method.h +++ b/src/libcharon/sa/authenticators/xauth/xauth_method.h @@ -100,7 +100,7 @@ struct xauth_method_t { * @return implementation of the eap_method_t interface */ typedef xauth_method_t *(*xauth_constructor_t)(identification_t *server, - identification_t *peer); + identification_t *peer); /** * Helper function to (un-)register XAuth methods from plugin features. From 4dbd81c66959dbb78485941e3ab9705c5b05776c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 12 Dec 2011 18:38:32 +0100 Subject: [PATCH 267/534] Destroy IKE_SA after failed XAuth authentication. --- src/libcharon/sa/tasks/xauth.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/tasks/xauth.c b/src/libcharon/sa/tasks/xauth.c index de93935a9..4fd896e3c 100644 --- a/src/libcharon/sa/tasks/xauth.c +++ b/src/libcharon/sa/tasks/xauth.c @@ -277,9 +277,12 @@ METHOD(task_t, process_i_status, status_t, DBG1(DBG_IKE, "received invalid XAUTH status response"); return FAILED; } - + if (this->status != XAUTH_OK) + { + DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication"); + return FAILED; + } establish(this); - return SUCCESS; } From 0793ac497ac49bf21443736f03fd2effc73af2d5 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Mon, 12 Dec 2011 18:37:49 +0100 Subject: [PATCH 268/534] Fixed memory leak when handling IKEv1 error notifications. --- src/libcharon/sa/task_manager_v1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 65cce8e46..b20a9ac36 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -634,6 +634,7 @@ static status_t process_request(private_task_manager_t *this, if(notify->get_notify_type(notify) < 16384) { DBG1(DBG_IKE, "Received %N error notification.", notify_type_names, notify->get_notify_type(notify)); + enumerator->destroy(enumerator); return FAILED; } break; From 9862852823373eea1a41a5b7b74f59973b342ab0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 15:43:12 +0100 Subject: [PATCH 269/534] Double check if we have a packet before retransmitting it --- src/libcharon/sa/task_manager_v1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index b20a9ac36..2af0ba2ac 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -871,12 +871,12 @@ METHOD(task_manager_t, process_message, status_t, else { hash = chunk_hash(msg->get_packet_data(msg)); - if (hash == this->responding.hash) + if (hash == this->responding.hash && this->responding.packet) { DBG1(DBG_IKE, "received retransmit of request with ID %d, " "retransmitting response", mid); charon->sender->send(charon->sender, - this->responding.packet->clone(this->responding.packet)); + this->responding.packet->clone(this->responding.packet)); return SUCCESS; } msg->set_request(msg, TRUE); From 0f61964ed75ded8c40dce8413943f343146bc840 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 18:01:21 +0100 Subject: [PATCH 270/534] Support flushing of single tasks queues in IKEv1 task manager --- src/libcharon/sa/task_manager_v1.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 2af0ba2ac..cfa67b079 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -156,20 +156,27 @@ struct private_task_manager_t { double retransmit_base; }; +/** + * Flush a single task queue + */ +static void flush_queue(private_task_manager_t *this, linked_list_t *list) +{ + task_t *task; + + while (list->remove_last(list, (void**)&task) == SUCCESS) + { + task->destroy(task); + } +} + /** * flush all tasks in the task manager */ static void flush(private_task_manager_t *this) { - this->queued_tasks->destroy_offset(this->queued_tasks, - offsetof(task_t, destroy)); - this->queued_tasks = linked_list_create(); - this->passive_tasks->destroy_offset(this->passive_tasks, - offsetof(task_t, destroy)); - this->passive_tasks = linked_list_create(); - this->active_tasks->destroy_offset(this->active_tasks, - offsetof(task_t, destroy)); - this->active_tasks = linked_list_create(); + flush_queue(this, this->queued_tasks); + flush_queue(this, this->passive_tasks); + flush_queue(this, this->active_tasks); } /** From 590ca1d482e2817558e8e4029e203d1cef749eb7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 15:16:15 +0100 Subject: [PATCH 271/534] Allow IKEv1 tasks to return ALREADY_DONE to flush all active or passive tasks --- src/libcharon/sa/task_manager_v1.c | 31 ++++++++++++++++++++---------- src/libcharon/sa/tasks/task.h | 2 ++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index cfa67b079..93c02278e 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -371,10 +371,13 @@ METHOD(task_manager_t, initiate, status_t, /* task completed, remove it */ this->active_tasks->remove_at(this->active_tasks, enumerator); task->destroy(task); - break; + continue; case NEED_MORE: expect_response = TRUE; /* processed, but task needs another exchange */ + continue; + case ALREADY_DONE: + flush_queue(this, this->active_tasks); break; case FAILED: default: @@ -390,6 +393,7 @@ METHOD(task_manager_t, initiate, status_t, flush(this); return DESTROY_ME; } + break; } enumerator->destroy(enumerator); @@ -464,7 +468,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) { task->destroy(task); } - break; + continue; case NEED_MORE: /* processed, but task needs another exchange */ if (handle_collisions(this, task)) @@ -472,6 +476,9 @@ static status_t build_response(private_task_manager_t *this, message_t *request) this->passive_tasks->remove_at(this->passive_tasks, enumerator); } + continue; + case ALREADY_DONE: + flush_queue(this, this->passive_tasks); break; case FAILED: default: @@ -482,10 +489,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) delete = TRUE; break; } - if (delete) - { - break; - } + break; } enumerator->destroy(enumerator); @@ -700,13 +704,15 @@ static status_t process_request(private_task_manager_t *this, /* task completed, remove it */ this->passive_tasks->remove_at(this->passive_tasks, enumerator); task->destroy(task); - break; + continue; case NEED_MORE: /* processed, but task needs at least another call to build() */ send_response = TRUE; + continue; + case ALREADY_DONE: + send_response = FALSE; + flush_queue(this, this->passive_tasks); break; - case FAILED_SEND_ERROR: - send_notify_response(this, NULL, 0, chunk_empty, task); case FAILED: default: charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); @@ -718,6 +724,7 @@ static status_t process_request(private_task_manager_t *this, task->destroy(task); return DESTROY_ME; } + break; } enumerator->destroy(enumerator); @@ -765,9 +772,12 @@ static status_t process_response(private_task_manager_t *this, /* task completed, remove it */ this->active_tasks->remove_at(this->active_tasks, enumerator); task->destroy(task); - break; + continue; case NEED_MORE: /* processed, but task needs another exchange */ + continue; + case ALREADY_DONE: + flush_queue(this, this->active_tasks); break; case FAILED: default: @@ -780,6 +790,7 @@ static status_t process_response(private_task_manager_t *this, task->destroy(task); return DESTROY_ME; } + break; } enumerator->destroy(enumerator); diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index d368a6810..7c725944e 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -121,6 +121,7 @@ struct task_t { * - FAILED if a critical error occurred * - DESTROY_ME if IKE_SA has been properly deleted * - NEED_MORE if another call to build/process needed + * - ALREADY_DONE to cancel all active or passive tasks * - SUCCESS if task completed */ status_t (*build) (task_t *this, message_t *message); @@ -133,6 +134,7 @@ struct task_t { * - FAILED if a critical error occurred * - DESTROY_ME if IKE_SA has been properly deleted * - NEED_MORE if another call to build/process needed + * - ALREADY_DONE to cancel all active or passive tasks * - SUCCESS if task completed */ status_t (*process) (task_t *this, message_t *message); From f4929076674ee05b7dd8bc9873fd0a9ff256f32c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 15:38:20 +0100 Subject: [PATCH 272/534] Added a task stub to create and process IKEv1 informational exchanges --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/tasks/informational.c | 119 +++++++++++++++++++++++++ src/libcharon/sa/tasks/informational.h | 50 +++++++++++ src/libcharon/sa/tasks/task.c | 2 + src/libcharon/sa/tasks/task.h | 2 + 5 files changed, 174 insertions(+) create mode 100644 src/libcharon/sa/tasks/informational.c create mode 100644 src/libcharon/sa/tasks/informational.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 4e77b4f4f..47c52abaa 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -98,6 +98,7 @@ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ sa/tasks/ike_vendor_v1.c sa/tasks/ike_vendor_v1.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ +sa/tasks/informational.c sa/tasks/informational.h \ sa/tasks/xauth.c sa/tasks/xauth.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ sa/tasks/mode_config.c sa/tasks/mode_config.h \ diff --git a/src/libcharon/sa/tasks/informational.c b/src/libcharon/sa/tasks/informational.c new file mode 100644 index 000000000..8cbe10ebd --- /dev/null +++ b/src/libcharon/sa/tasks/informational.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "informational.h" + +#include + +typedef struct private_informational_t private_informational_t; + +/** + * Private members of a informational_t task. + */ +struct private_informational_t { + + /** + * Public methods and task_t interface. + */ + informational_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Notify payload to send + */ + notify_payload_t *notify; +}; + +METHOD(task_t, build_i, status_t, + private_informational_t *this, message_t *message) +{ + message->add_payload(message, &this->notify->payload_interface); + this->notify = NULL; + return SUCCESS; +} + +METHOD(task_t, process_r, status_t, + private_informational_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, build_r, status_t, + private_informational_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, process_i, status_t, + private_informational_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_informational_t *this) +{ + return TASK_INFORMATIONAL; +} + +METHOD(task_t, migrate, void, + private_informational_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_informational_t *this) +{ + DESTROY_IF(this->notify); + free(this); +} + +/* + * Described in header. + */ +informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify) +{ + private_informational_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .notify = notify, + ); + + if (notify) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/tasks/informational.h b/src/libcharon/sa/tasks/informational.h new file mode 100644 index 000000000..e9c32f647 --- /dev/null +++ b/src/libcharon/sa/tasks/informational.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup informational informational + * @{ @ingroup tasks + */ + +#ifndef INFORMATIONAL_H_ +#define informational_H_ + +typedef struct informational_t informational_t; + +#include +#include +#include +#include + +/** + * IKEv1 informational exchange, negotiates errors. + */ +struct informational_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new informational task. + * + * @param notify notify to send as initiator, NULL if responder + * @return task to handle by the task_manager + */ +informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify); + +#endif /** INFORMATIONAL_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index ca5ecca73..f8ff56571 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -36,6 +36,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, "CHILD_DELETE", "CHILD_REKEY", "MAIN_MODE", + "INFORMATIONAL", "XAUTH", "MODE_CONFIG", "QUICK_MODE", @@ -63,6 +64,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, "CHILD_DELETE", "CHILD_REKEY", "MAIN_MODE", + "INFORMATIONAL", "XAUTH", "MODE_CONFIG", "QUICK_MODE", diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 7c725944e..7fa99251f 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -71,6 +71,8 @@ enum task_type_t { TASK_CHILD_REKEY, /** IKEv1 main mode */ TASK_MAIN_MODE, + /** IKEv1 informational exchange */ + TASK_INFORMATIONAL, /** IKEv1 XAUTH authentication */ TASK_XAUTH, /** IKEv1 Mode Config */ From accf46129a3e9bedf245729b6c9d929906f575cb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 15:44:58 +0100 Subject: [PATCH 273/534] Use informational taks to send notify errors --- src/libcharon/sa/task_manager_v1.c | 10 +++++ src/libcharon/sa/tasks/main_mode.c | 63 +++++++++--------------------- 2 files changed, 29 insertions(+), 44 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 93c02278e..99189f89d 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -293,6 +293,11 @@ METHOD(task_manager_t, initiate, status_t, exchange = TRANSACTION; new_mid = TRUE; } + if (activate_task(this, TASK_INFORMATIONAL)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + } break; case IKE_ESTABLISHED: if (activate_task(this, TASK_MODE_CONFIG)) @@ -307,6 +312,11 @@ METHOD(task_manager_t, initiate, status_t, new_mid = TRUE; break; } + if (activate_task(this, TASK_INFORMATIONAL)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + } break; default: break; diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 94d9f877d..1390f1b50 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -30,6 +30,7 @@ #include #include #include +#include typedef struct private_main_mode_t private_main_mode_t; @@ -123,16 +124,6 @@ struct private_main_mode_t { */ authenticator_t *authenticator; - /** - * Notify type in case of error - */ - notify_type_t notify_type; - - /** - * Notify data in case of error - */ - chunk_t notify_data; - /** states of main mode */ enum { MM_INIT, @@ -386,7 +377,8 @@ static bool has_notify_errors(private_main_mode_t *this, message_t *message) * delete any existing IKE_SAs with that peer. * The delete takes place when the SA is checked in due * to other id not known until the 3rd message.*/ - this->ike_sa->set_condition(this->ike_sa, COND_INIT_CONTACT_SEEN, TRUE); + this->ike_sa->set_condition(this->ike_sa, + COND_INIT_CONTACT_SEEN, TRUE); } } else @@ -400,47 +392,30 @@ static bool has_notify_errors(private_main_mode_t *this, message_t *message) return err; } -METHOD(task_t, build_notify_error, status_t, - private_main_mode_t *this, message_t *message) +/** + * Queue a task sending a notify in an INFORMATIONAL exchange + */ +static status_t send_notify(private_main_mode_t *this, + notify_type_t type, chunk_t data) { notify_payload_t *notify; ike_sa_id_t *ike_sa_id; - chunk_t spi; u_int64_t spi_i, spi_r; + chunk_t spi; notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, - PROTO_IKE, this->notify_type); - - if (this->notify_data.ptr) - { - notify->set_notification_data(notify, this->notify_data); - } - + PROTO_IKE, type); + notify->set_notification_data(notify, data); ike_sa_id = this->ike_sa->get_id(this->ike_sa); - spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); spi_r = ike_sa_id->get_responder_spi(ike_sa_id); - spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r)); - notify->set_spi_data(notify, spi); - message->add_payload(message, (payload_t*)notify); - - return SUCCESS; -} - -/** - * Set the task ready to build notify error message - */ -static status_t set_notify_error(private_main_mode_t *this, - notify_type_t type, chunk_t data) -{ - this->notify_type = type; - this->notify_data = data; - /* The task will be destroyed after build */ - this->public.task.build = _build_notify_error; - return FAILED_SEND_ERROR; + this->ike_sa->queue_task(this->ike_sa, + (task_t*)informational_create(this->ike_sa, notify)); + /* cancel all active/passive tasks in favour of informational */ + return ALREADY_DONE; } METHOD(task_t, build_i, status_t, @@ -600,7 +575,7 @@ METHOD(task_t, process_r, status_t, if (!this->proposal) { DBG1(DBG_IKE, "no proposal found"); - return set_notify_error(this, NO_PROPOSAL_CHOSEN, chunk_empty); + return send_notify(this, NO_PROPOSAL_CHOSEN, chunk_empty); } this->auth_method = sa_payload->get_auth_method(sa_payload); @@ -654,7 +629,7 @@ METHOD(task_t, process_r, status_t, if (!this->peer_cfg) { DBG1(DBG_IKE, "no peer config found"); - return set_notify_error(this, AUTHENTICATION_FAILED, chunk_empty); + return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); } this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); @@ -663,13 +638,13 @@ METHOD(task_t, process_r, status_t, if (!this->my_auth || !this->other_auth) { DBG1(DBG_IKE, "auth config missing"); - return set_notify_error(this, AUTHENTICATION_FAILED, chunk_empty); + return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); } if (this->authenticator->process(this->authenticator, message) != SUCCESS) { - return set_notify_error(this, AUTHENTICATION_FAILED, chunk_empty); + return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); } this->state = MM_AUTH; From b47052694fc336dbef5b73a073d9274fc33d8741 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 15:45:45 +0100 Subject: [PATCH 274/534] Cleaned up notification sending in IKEv1 task manager --- src/libcharon/sa/task_manager_v1.c | 50 +++++++----------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 99189f89d..c5b3748d7 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -528,9 +528,8 @@ static status_t build_response(private_task_manager_t *this, message_t *request) * Send a notify in a separate INFORMATIONAL exchange back to the sender. * The notify protocol_id is set to ISAKMP */ -static void send_notify_response(private_task_manager_t *this, - message_t *request, notify_type_t type, - chunk_t data, task_t *task) +static void send_notify(private_task_manager_t *this, message_t *request, + notify_type_t type) { message_t *response; packet_t *packet; @@ -548,30 +547,9 @@ static void send_notify_response(private_task_manager_t *this, response->set_request(response, TRUE); this->rng->get_bytes(this->rng, sizeof(mid), (void*)&mid); response->set_message_id(response, mid); - - if (task) - { - /* Let the task build the response */ - if (task->build(task,response) != SUCCESS) - { - response->destroy(response); - return; - } - } - else - { - notify_payload_t *notify; - - notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, - PROTO_IKE, type); - - if (data.ptr) - { - notify->set_notification_data(notify, data); - } - - response->add_payload(response, (payload_t*)notify); - } + response->add_payload(response, (payload_t*) + notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_IKE, type)); me = this->ike_sa->get_my_host(this->ike_sa); if (me->is_anyaddr(me)) @@ -826,28 +804,23 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg) { case NOT_SUPPORTED: DBG1(DBG_IKE, "unsupported exchange type"); - send_notify_response(this, msg, - INVALID_EXCHANGE_TYPE, chunk_empty, NULL); + send_notify(this, msg, INVALID_EXCHANGE_TYPE); break; case PARSE_ERROR: DBG1(DBG_IKE, "message parsing failed"); - send_notify_response(this, msg, - PAYLOAD_MALFORMED, chunk_empty, NULL); + send_notify(this, msg, PAYLOAD_MALFORMED); break; case VERIFY_ERROR: DBG1(DBG_IKE, "message verification failed"); - send_notify_response(this, msg, - PAYLOAD_MALFORMED, chunk_empty, NULL); + send_notify(this, msg, PAYLOAD_MALFORMED); break; case FAILED: DBG1(DBG_IKE, "integrity check failed"); - send_notify_response(this, msg, - INVALID_HASH_INFORMATION, chunk_empty, NULL); + send_notify(this, msg, INVALID_HASH_INFORMATION); break; case INVALID_STATE: DBG1(DBG_IKE, "found encrypted message, but no keys available"); - send_notify_response(this, msg, - PAYLOAD_MALFORMED, chunk_empty, NULL); + send_notify(this, msg, PAYLOAD_MALFORMED); default: break; } @@ -925,8 +898,7 @@ METHOD(task_manager_t, process_message, status_t, /* no config found for these hosts, destroy */ DBG1(DBG_IKE, "no IKE config found for %H...%H, sending %N", me, other, notify_type_names, NO_PROPOSAL_CHOSEN); - send_notify_response(this, msg, - NO_PROPOSAL_CHOSEN, chunk_empty, NULL); + send_notify(this, msg, NO_PROPOSAL_CHOSEN); return DESTROY_ME; } this->ike_sa->set_ike_cfg(this->ike_sa, ike_cfg); From e7ae90c1943c78fbb87e466e0b9022a31666ee58 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 12 Dec 2011 18:13:10 +0100 Subject: [PATCH 275/534] Use informational task in quick mode to send notifies --- src/libcharon/sa/tasks/quick_mode.c | 34 +++++++++++------------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 18895db09..92a526e21 100755 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -24,6 +24,7 @@ #include #include #include +#include typedef struct private_quick_mode_t private_quick_mode_t; @@ -519,31 +520,21 @@ static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload } } -METHOD(task_t, build_notify_error, status_t, - private_quick_mode_t *this, message_t *message) +/** + * Set the task ready to build notify error message + */ +static status_t send_notify(private_quick_mode_t *this, notify_type_t type) { notify_payload_t *notify; notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, - PROTO_ESP, this->notify_type); - + PROTO_ESP, type); notify->set_spi(notify, this->spi_i); - message->add_payload(message, (payload_t*)notify); - - return SUCCESS; -} - -/** - * Set the task ready to build notify error message - */ -static status_t set_notify_error(private_quick_mode_t *this, - notify_type_t type) -{ - this->notify_type = type; - /* The task will be destroyed after build */ - this->public.task.build = _build_notify_error; - return FAILED_SEND_ERROR; + this->ike_sa->queue_task(this->ike_sa, + (task_t*)informational_create(this->ike_sa, notify)); + /* cancel all active/passive tasks in favour of informational */ + return ALREADY_DONE; } METHOD(task_t, build_i, status_t, @@ -727,8 +718,9 @@ METHOD(task_t, process_r, status_t, if (!this->proposal) { - DBG1(DBG_IKE, "no matching proposal found"); - return set_notify_error(this, NO_PROPOSAL_CHOSEN); + DBG1(DBG_IKE, "no matching proposal found, sending %N", + notify_type_names, NO_PROPOSAL_CHOSEN); + return send_notify(this, NO_PROPOSAL_CHOSEN); } this->spi_i = this->proposal->get_spi(this->proposal); From 1cc3e92ccc485f1078b606480553e0a1705926d1 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 09:40:26 +0100 Subject: [PATCH 276/534] Check if IKEv1 exchange type matches before handling it as response --- src/libcharon/sa/task_manager_v1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index c5b3748d7..21b3baefe 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -851,6 +851,7 @@ METHOD(task_manager_t, process_message, status_t, if ((mid && mid == this->initiating.mid) || (this->initiating.mid == 0 && + msg->get_exchange_type(msg) == this->initiating.type && this->active_tasks->get_count(this->active_tasks))) { msg->set_request(msg, FALSE); From 1477ab157c3305c1f8abef0fa93f30196a765e24 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 09:42:16 +0100 Subject: [PATCH 277/534] Remove unused status type --- src/libstrongswan/utils.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h index 826477c7f..e5e4a10c0 100755 --- a/src/libstrongswan/utils.h +++ b/src/libstrongswan/utils.h @@ -299,11 +299,6 @@ enum status_t { * Another call to the method is required. */ NEED_MORE, - - /** - * Call failed, send error to other side. - */ - FAILED_SEND_ERROR, }; /** From 97933967a04bfdb8056528f793f5dd2e2d5dd56a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 09:50:31 +0100 Subject: [PATCH 278/534] Moved responder informational handling to task --- src/libcharon/sa/task_manager_v1.c | 56 ++------------------------ src/libcharon/sa/tasks/informational.c | 44 +++++++++++++++++++- 2 files changed, 46 insertions(+), 54 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 21b3baefe..48218a809 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -582,8 +582,6 @@ static status_t process_request(private_task_manager_t *this, enumerator_t *enumerator; task_t *task = NULL; bool send_response = FALSE; - payload_t *payload; - notify_payload_t *notify; if (this->passive_tasks->get_count(this->passive_tasks) == 0) { /* create tasks depending on request type, if not already some queued */ @@ -616,56 +614,8 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); break; case INFORMATIONAL_V1: - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - switch (payload->get_type(payload)) - { - case NOTIFY_V1: - { - notify = (notify_payload_t*)payload; - switch (notify->get_notify_type(notify)) - { - /* TODO-IKEv1: Add notification types here as needed */ - case INITIAL_CONTACT_IKEV1: - break; - default: - if(notify->get_notify_type(notify) < 16384) - { - DBG1(DBG_IKE, "Received %N error notification.", notify_type_names, notify->get_notify_type(notify)); - enumerator->destroy(enumerator); - return FAILED; - } - break; - } - break; - } - case DELETE_V1: - { - delete_payload_t *delete; - delete = (delete_payload_t*)payload; - - if (delete->get_protocol_id(delete) == PROTO_IKE) - { - task = (task_t*)ike_delete_create(this->ike_sa, - FALSE); - } - else - { - task = (task_t*)child_delete_create(this->ike_sa, - PROTO_NONE, 0); - } - break; - } - default: - break; - } - if (task) - { - this->passive_tasks->insert_last(this->passive_tasks, task); - } - } - enumerator->destroy(enumerator); + task = (task_t *)informational_create(this->ike_sa, NULL); + this->passive_tasks->insert_last(this->passive_tasks, task); break; case TRANSACTION: if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) diff --git a/src/libcharon/sa/tasks/informational.c b/src/libcharon/sa/tasks/informational.c index 8cbe10ebd..08e5a7eb2 100644 --- a/src/libcharon/sa/tasks/informational.c +++ b/src/libcharon/sa/tasks/informational.c @@ -51,7 +51,49 @@ METHOD(task_t, build_i, status_t, METHOD(task_t, process_r, status_t, private_informational_t *this, message_t *message) { - return FAILED; + enumerator_t *enumerator; + notify_payload_t *notify; + notify_type_t type; + payload_t *payload; + status_t status = SUCCESS; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case NOTIFY_V1: + notify = (notify_payload_t*)payload; + type = notify->get_notify_type(notify); + + if (type == INITIAL_CONTACT_IKEV1) + { + this->ike_sa->set_condition(this->ike_sa, + COND_INIT_CONTACT_SEEN, TRUE); + } + else if (type < 16384) + { + DBG1(DBG_IKE, "received %N error notify", + notify_type_names, notify->get_notify_type(notify)); + status = FAILED; + break; + } + else + { + DBG1(DBG_IKE, "received %N notify", + notify_type_names, notify->get_notify_type(notify)); + } + continue; + case DELETE_V1: + /* TODO-IKEv1: handle delete */ + default: + continue; + } + break; + } + enumerator->destroy(enumerator); + + return status; } METHOD(task_t, build_r, status_t, From 46505067c761072c1567a134814c9d7852d066b3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 09:55:37 +0100 Subject: [PATCH 279/534] Close SA immediately after sending an INFORMATIONAL error --- src/libcharon/sa/task_manager_v1.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 48218a809..89c664c8f 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -432,6 +432,13 @@ METHOD(task_manager_t, initiate, status_t, this->initiating.packet->clone(this->initiating.packet)); this->initiating.packet->destroy(this->initiating.packet); this->initiating.packet = NULL; + + /* close after sending an INFORMATIONAL error but not yet established */ + if (this->initiating.type == INFORMATIONAL_V1 && + this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING) + { + return FAILED; + } return SUCCESS; } From 10e18713f17f3528667c7124d17174e55a1137c9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 10:22:49 +0100 Subject: [PATCH 280/534] Handle DELETE as responder as INFORMATIONAL subtask --- src/libcharon/sa/task_manager_v1.c | 2 -- src/libcharon/sa/tasks/informational.c | 30 +++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 89c664c8f..f9df2564e 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -19,7 +19,6 @@ #include #include -#include #include #include #include @@ -29,7 +28,6 @@ #include #include #include -#include #include #include diff --git a/src/libcharon/sa/tasks/informational.c b/src/libcharon/sa/tasks/informational.c index 08e5a7eb2..c1a30e4ee 100644 --- a/src/libcharon/sa/tasks/informational.c +++ b/src/libcharon/sa/tasks/informational.c @@ -16,6 +16,9 @@ #include "informational.h" #include +#include +#include +#include typedef struct private_informational_t private_informational_t; @@ -38,6 +41,11 @@ struct private_informational_t { * Notify payload to send */ notify_payload_t *notify; + + /** + * Delete subtask + */ + task_t *del; }; METHOD(task_t, build_i, status_t, @@ -52,6 +60,7 @@ METHOD(task_t, process_r, status_t, private_informational_t *this, message_t *message) { enumerator_t *enumerator; + delete_payload_t *delete; notify_payload_t *notify; notify_type_t type; payload_t *payload; @@ -85,7 +94,17 @@ METHOD(task_t, process_r, status_t, } continue; case DELETE_V1: - /* TODO-IKEv1: handle delete */ + delete = (delete_payload_t*)payload; + if (delete->get_protocol_id(delete) == PROTO_IKE) + { + this->del = (task_t*)ike_delete_create(this->ike_sa, FALSE); + } + else + { + this->del = (task_t*)child_delete_create(this->ike_sa, + PROTO_NONE, 0); + } + break; default: continue; } @@ -93,12 +112,20 @@ METHOD(task_t, process_r, status_t, } enumerator->destroy(enumerator); + if (status == SUCCESS) + { + return this->del->process(this->del, message); + } return status; } METHOD(task_t, build_r, status_t, private_informational_t *this, message_t *message) { + if (this->del) + { + return this->del->build(this->del, message); + } return FAILED; } @@ -124,6 +151,7 @@ METHOD(task_t, destroy, void, private_informational_t *this) { DESTROY_IF(this->notify); + DESTROY_IF(this->del); free(this); } From 5dec456b69af65170c44ecf8c724ea7d62e39d16 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 10:35:18 +0100 Subject: [PATCH 281/534] Fix IKEv1 DELETE subtask creation and processing --- src/libcharon/sa/tasks/informational.c | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/libcharon/sa/tasks/informational.c b/src/libcharon/sa/tasks/informational.c index c1a30e4ee..c2c6aa5fa 100644 --- a/src/libcharon/sa/tasks/informational.c +++ b/src/libcharon/sa/tasks/informational.c @@ -94,15 +94,19 @@ METHOD(task_t, process_r, status_t, } continue; case DELETE_V1: - delete = (delete_payload_t*)payload; - if (delete->get_protocol_id(delete) == PROTO_IKE) + if (!this->del) { - this->del = (task_t*)ike_delete_create(this->ike_sa, FALSE); - } - else - { - this->del = (task_t*)child_delete_create(this->ike_sa, - PROTO_NONE, 0); + delete = (delete_payload_t*)payload; + if (delete->get_protocol_id(delete) == PROTO_IKE) + { + this->del = (task_t*)ike_delete_create(this->ike_sa, + FALSE); + } + else + { + this->del = (task_t*)child_delete_create(this->ike_sa, + PROTO_NONE, 0); + } } break; default: @@ -112,7 +116,7 @@ METHOD(task_t, process_r, status_t, } enumerator->destroy(enumerator); - if (status == SUCCESS) + if (this->del && status == SUCCESS) { return this->del->process(this->del, message); } From 8ef2bae4dbaa702ba14e0bf9c78195facec1ed85 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 10:36:02 +0100 Subject: [PATCH 282/534] Activate DELETE tasks when queued --- src/libcharon/sa/task_manager_v1.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index f9df2564e..6a9592fe5 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -315,6 +315,16 @@ METHOD(task_manager_t, initiate, status_t, exchange = INFORMATIONAL_V1; new_mid = TRUE; } + if (activate_task(this, TASK_IKE_DELETE)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + } + if (activate_task(this, TASK_CHILD_DELETE)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + } break; default: break; From c9fc577a8ae8e9f8b0c454fb4cf0133077d390c8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 10:36:42 +0100 Subject: [PATCH 283/534] Use version specific DELETE payload identifier in ike_delete task --- src/libcharon/sa/tasks/ike_delete.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/ike_delete.c b/src/libcharon/sa/tasks/ike_delete.c index dccd85892..0318b9c18 100755 --- a/src/libcharon/sa/tasks/ike_delete.c +++ b/src/libcharon/sa/tasks/ike_delete.c @@ -65,7 +65,14 @@ METHOD(task_t, build_i, status_t, this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); - delete_payload = delete_payload_create(DELETE, PROTO_IKE); + if (this->ike_sa->get_version(this->ike_sa) == IKEV1) + { + delete_payload = delete_payload_create(DELETE_V1, PROTO_IKE); + } + else + { + delete_payload = delete_payload_create(DELETE, PROTO_IKE); + } message->add_payload(message, (payload_t*)delete_payload); if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING) From 5383b50d88bc716c7279af3143af8cc7b72fef9c Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 13 Dec 2011 10:39:36 +0100 Subject: [PATCH 284/534] Fixed missing shared_key initialization in main_mode task. --- src/libcharon/sa/tasks/main_mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 1390f1b50..5e18bb7c6 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -666,7 +666,7 @@ static shared_key_t *lookup_shared_key(private_main_mode_t *this) { host_t *me, *other; identification_t *my_id, *other_id; - shared_key_t *shared_key; + shared_key_t *shared_key = NULL; /* try to get a PSK for IP addresses */ me = this->ike_sa->get_my_host(this->ike_sa); From 0acb5207588c095b34031e9114d4ed4cc637a9e7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 11:08:53 +0100 Subject: [PATCH 285/534] Support IKEv1 SPIs in IKEv1 delete payload --- .../encoding/payloads/delete_payload.c | 25 +++++++++++++++++-- .../encoding/payloads/delete_payload.h | 8 ++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index 79070a79f..3222e9fbe 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -272,6 +272,16 @@ METHOD(delete_payload_t, add_spi, void, } } +METHOD(delete_payload_t, set_ike_spi, void, + private_delete_payload_t *this, u_int64_t spi_i, u_int64_t spi_r) +{ + free(this->spis.ptr); + this->spis = chunk_cat("cc", chunk_from_thing(spi_i), + chunk_from_thing(spi_r)); + this->spi_count = 1; + this->payload_length = get_header_length(this) + this->spi_size; +} + /** * SPI enumerator implementation */ @@ -342,16 +352,27 @@ delete_payload_t *delete_payload_create(payload_type_t type, }, .get_protocol_id = _get_protocol_id, .add_spi = _add_spi, + .set_ike_spi = _set_ike_spi, .create_spi_enumerator = _create_spi_enumerator, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .doi = IKEV1_DOI_IPSEC, .protocol_id = protocol_id, - .spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0, .type = type, ); this->payload_length = get_header_length(this); + if (type == DELETE_V1) + { + if (protocol_id == PROTO_IKE) + { + this->spi_size = 16; + } + else + { + this->doi = IKEV1_DOI_IPSEC, + this->spi_size = 4; + } + } return &this->public; } diff --git a/src/libcharon/encoding/payloads/delete_payload.h b/src/libcharon/encoding/payloads/delete_payload.h index 0ee0d4f7a..afce1ecf1 100644 --- a/src/libcharon/encoding/payloads/delete_payload.h +++ b/src/libcharon/encoding/payloads/delete_payload.h @@ -52,6 +52,14 @@ struct delete_payload_t { */ void (*add_spi) (delete_payload_t *this, u_int32_t spi); + /** + * Set the IKE SPIs for an IKEv1 delete. + * + * @param spi_i initiator SPI + * @param spi_r responder SPI + */ + void (*set_ike_spi)(delete_payload_t *this, u_int64_t spi_i, u_int64_t spi_r); + /** * Get an enumerator over the SPIs in network order. * From 92aa6e0255aeb5951d73a405db662fe9fdc78700 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 11:10:48 +0100 Subject: [PATCH 286/534] Include COOKIES in IKEv1 delete payloads --- src/libcharon/sa/tasks/ike_delete.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcharon/sa/tasks/ike_delete.c b/src/libcharon/sa/tasks/ike_delete.c index 0318b9c18..56d423117 100755 --- a/src/libcharon/sa/tasks/ike_delete.c +++ b/src/libcharon/sa/tasks/ike_delete.c @@ -56,6 +56,7 @@ METHOD(task_t, build_i, status_t, private_ike_delete_t *this, message_t *message) { delete_payload_t *delete_payload; + ike_sa_id_t *id; DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), @@ -68,6 +69,9 @@ METHOD(task_t, build_i, status_t, if (this->ike_sa->get_version(this->ike_sa) == IKEV1) { delete_payload = delete_payload_create(DELETE_V1, PROTO_IKE); + id = this->ike_sa->get_id(this->ike_sa); + delete_payload->set_ike_spi(delete_payload, id->get_initiator_spi(id), + id->get_responder_spi(id)); } else { From 41fbde45442f2e33beebb4e0b6075a1d6a9ad948 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 11:19:08 +0100 Subject: [PATCH 287/534] Reset task manager state when build() completes an exchange (quick mode) --- src/libcharon/sa/task_manager_v1.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 6a9592fe5..b292934bc 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -415,8 +415,10 @@ METHOD(task_manager_t, initiate, status_t, } enumerator->destroy(enumerator); - /* update exchange type if a task changed it */ - this->initiating.type = message->get_exchange_type(message); + if (this->active_tasks->get_count(this->active_tasks) == 0) + { /* tasks completed, no exchange active anymore */ + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + } this->initiating.seqnr++; status = this->ike_sa->generate_message(this->ike_sa, message, @@ -442,7 +444,7 @@ METHOD(task_manager_t, initiate, status_t, this->initiating.packet = NULL; /* close after sending an INFORMATIONAL error but not yet established */ - if (this->initiating.type == INFORMATIONAL_V1 && + if (exchange == INFORMATIONAL_V1 && this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING) { return FAILED; From 226b0f36c74f7739dbf498ad0093e9e208a7db6f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 11:30:35 +0100 Subject: [PATCH 288/534] Fixed SPI size calculation in DELETE payload --- src/libcharon/encoding/payloads/delete_payload.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index 3222e9fbe..dec1ba72a 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -264,7 +264,6 @@ METHOD(delete_payload_t, add_spi, void, case PROTO_ESP: this->spi_count++; this->payload_length += sizeof(spi); - this->spi_size += sizeof(spi); this->spis = chunk_cat("mc", this->spis, chunk_from_thing(spi)); break; default: @@ -362,17 +361,17 @@ delete_payload_t *delete_payload_create(payload_type_t type, ); this->payload_length = get_header_length(this); - if (type == DELETE_V1) + if (protocol_id == PROTO_IKE) { - if (protocol_id == PROTO_IKE) + if (type == DELETE_V1) { this->spi_size = 16; } - else - { - this->doi = IKEV1_DOI_IPSEC, - this->spi_size = 4; - } + } + else + { + this->doi = IKEV1_DOI_IPSEC, + this->spi_size = 4; } return &this->public; } From 45956d15ea6d53ff7d1917a8a063e98535987dfe Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 11:37:02 +0100 Subject: [PATCH 289/534] Free list after removing the last local credential set, fixes a leak report --- src/libstrongswan/credentials/credential_manager.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index 27b97eab3..4c310406e 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -393,6 +393,11 @@ METHOD(credential_manager_t, remove_local_set, void, sets = this->local_sets->get(this->local_sets); sets->remove(sets, set, NULL); + if (sets->get_count(sets) == 0) + { + this->local_sets->set(this->local_sets, NULL); + sets->destroy(sets); + } } METHOD(credential_manager_t, cache_cert, void, From e33510f8a32ffe72f6c239919058e6eb120ef070 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 11:39:54 +0100 Subject: [PATCH 290/534] Fixed leak of shared keys in xauth-generic plugin --- src/libcharon/plugins/xauth_generic/xauth_generic.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.c b/src/libcharon/plugins/xauth_generic/xauth_generic.c index cac740a34..981ab77d0 100644 --- a/src/libcharon/plugins/xauth_generic/xauth_generic.c +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.c @@ -73,6 +73,7 @@ METHOD(xauth_method_t, process_peer, status_t, CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, user)); cp->add_attribute(cp, configuration_attribute_create_chunk( CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, pass)); + shared->destroy(shared); *out = cp; return NEED_MORE; } @@ -151,6 +152,7 @@ METHOD(xauth_method_t, process_server, status_t, { DBG2(DBG_IKE, "authentication of '%Y' with XAuth successful", peer); } + DESTROY_IF(shared); DESTROY_IF(id); return status; } From f91b6ac77ae444c92078539b5db477594a6f4a10 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 12:17:35 +0100 Subject: [PATCH 291/534] Queue a TRANSACTION message for later processing if Main Mode not yet completed --- src/libcharon/sa/task_manager_v1.c | 36 ++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index b292934bc..e50737063 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -138,6 +138,11 @@ struct private_task_manager_t { */ linked_list_t *passive_tasks; + /** + * Queued messages not yet ready to process + */ + message_t *queued; + /** * Number of times we retransmit messages before giving up */ @@ -707,6 +712,7 @@ static status_t process_response(private_task_manager_t *this, message_t *message) { enumerator_t *enumerator; + status_t status; task_t *task; if (message->get_exchange_type(message) != this->initiating.type) @@ -753,6 +759,18 @@ static status_t process_response(private_task_manager_t *this, this->initiating.packet->destroy(this->initiating.packet); this->initiating.packet = NULL; + if (this->queued && this->active_tasks->get_count(this->active_tasks) == 0) + { + status = this->public.task_manager.process_message( + &this->public.task_manager, this->queued); + this->queued->destroy(this->queued); + this->queued = NULL; + if (status == DESTROY_ME) + { + return status; + } + } + return initiate(this); } @@ -848,6 +866,23 @@ METHOD(task_manager_t, process_message, status_t, this->responding.packet->clone(this->responding.packet)); return SUCCESS; } + + if (msg->get_exchange_type(msg) == TRANSACTION && + this->active_tasks->get_count(this->active_tasks) && + !this->queued) + { /* main mode not yet complete, queue XAuth/Mode config tasks */ + this->queued = message_create_from_packet(msg->get_packet(msg)); + if (this->queued->parse_header(this->queued) != SUCCESS) + { + this->queued->destroy(this->queued); + this->queued = NULL; + return FAILED; + } + DBG1(DBG_IKE, "queueing %N request as tasks still active", + exchange_type_names, TRANSACTION); + return SUCCESS; + } + msg->set_request(msg, TRUE); status = parse_message(this, msg); if (status != SUCCESS) @@ -958,6 +993,7 @@ METHOD(task_manager_t, destroy, void, this->queued_tasks->destroy(this->queued_tasks); this->passive_tasks->destroy(this->passive_tasks); + DESTROY_IF(this->queued); DESTROY_IF(this->responding.packet); DESTROY_IF(this->initiating.packet); DESTROY_IF(this->rng); From 360c3394cfe25d9a531a3e0633683abc7169c1be Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 13:42:41 +0100 Subject: [PATCH 292/534] Fixed compiler warning (set but unused variable) --- src/libcharon/sa/authenticators/pubkey_v1_authenticator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c index 82fc8cf66..e3e7a8073 100644 --- a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c +++ b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c @@ -76,7 +76,7 @@ METHOD(authenticator_t, build, status_t, id = this->ike_sa->get_my_id(this->ike_sa); auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - private = lib->credmgr->get_private(lib->credmgr, KEY_RSA, id, auth); + private = lib->credmgr->get_private(lib->credmgr, type, id, auth); if (!private) { DBG1(DBG_IKE, "no private key found for '%Y'", id); From 156cd8827fe2320f745610ecdb40f37b767b3d58 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 14:26:31 +0100 Subject: [PATCH 293/534] Use a generic IKEv1 vendor ID database to send and receive vendor IDs --- src/libcharon/sa/tasks/ike_vendor_v1.c | 102 ++++++++++++------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/libcharon/sa/tasks/ike_vendor_v1.c b/src/libcharon/sa/tasks/ike_vendor_v1.c index 450c5b287..68ee8512e 100644 --- a/src/libcharon/sa/tasks/ike_vendor_v1.c +++ b/src/libcharon/sa/tasks/ike_vendor_v1.c @@ -42,54 +42,53 @@ struct private_ike_vendor_v1_t { }; /** - * Indicate support for XAuth, MD5("draft-ietf-ipsra-isakmp-xauth-06.txt") - * Truncated to the first half. + * IKEv1 Vendor ID database */ -static chunk_t xauth6_vid = chunk_from_chars( - 0x09,0x00,0x26,0x89,0xdf,0xd6,0xb7,0x12 -); +static struct { + /* Description */ + char *desc; + /* extension flag negotiated with vendor ID, if any */ + ike_extension_t extension; + /* send yourself? */ + bool send; + /* length of vendor ID string */ + int len; + /* vendor ID string */ + char *id; +} vendor_ids[] = { -/** - * Indicate support for NAT-Traversal, MD5("RFC 3947") - */ -static chunk_t natt_vid = chunk_from_chars( - 0x4a,0x13,0x1c,0x81,0x07,0x03,0x58,0x45, - 0x5c,0x57,0x28,0xf2,0x0e,0x95,0x45,0x2f -); + /* strongSwan MD5("strongSwan") */ + { "strongSwan", EXT_STRONGSWAN, FALSE, 16, + "\x88\x2f\xe5\x6d\x6f\xd2\x0d\xbc\x22\x51\x61\x3b\x2e\xbe\x5b\xeb"}, -/** - * strongSwan specific vendor ID without version, MD5("strongSwan") - */ -static chunk_t strongswan_vid = chunk_from_chars( - 0x88,0x2f,0xe5,0x6d,0x6f,0xd2,0x0d,0xbc, - 0x22,0x51,0x61,0x3b,0x2e,0xbe,0x5b,0xeb -); + /* XAuth, MD5("draft-ietf-ipsra-isakmp-xauth-06.txt") */ + { "XAuth", EXT_XAUTH, TRUE, 8, + "\x09\x00\x26\x89\xdf\xd6\xb7\x12"}, -/** - * Add a vendor ID to message - */ -static void add_vendor_id(private_ike_vendor_v1_t *this, message_t *message, - chunk_t vid) -{ - vendor_id_payload_t *vid_payload; - - vid_payload = vendor_id_payload_create_data(VENDOR_ID_V1, chunk_clone(vid)); - message->add_payload(message, &vid_payload->payload_interface); -} + /* NAT-Traversal, MD5("RFC 3947") */ + { "NAT-T (RFC 3947)", EXT_NATT, TRUE, 16, + "\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"}, +}; METHOD(task_t, build, status_t, private_ike_vendor_v1_t *this, message_t *message) { + vendor_id_payload_t *vid_payload; + bool strongswan; + int i; - if (lib->settings->get_bool(lib->settings, - "charon.send_vendor_id", FALSE)) + strongswan = lib->settings->get_bool(lib->settings, + "charon.send_vendor_id", FALSE); + for (i = 0; i < countof(vendor_ids); i++) { - add_vendor_id(this, message, strongswan_vid); + if (vendor_ids[i].send || + (vendor_ids[i].extension == EXT_STRONGSWAN && strongswan)) + { + vid_payload = vendor_id_payload_create_data(VENDOR_ID_V1, + chunk_clone(chunk_create(vendor_ids[i].id, vendor_ids[i].len))); + message->add_payload(message, &vid_payload->payload_interface); + } } - - add_vendor_id(this, message, xauth6_vid); - add_vendor_id(this, message, natt_vid); - return this->initiator ? NEED_MORE : SUCCESS; } @@ -98,6 +97,7 @@ METHOD(task_t, process, status_t, { enumerator_t *enumerator; payload_t *payload; + int i; enumerator = message->create_payload_enumerator(message); while (enumerator->enumerate(enumerator, &payload)) @@ -105,27 +105,27 @@ METHOD(task_t, process, status_t, if (payload->get_type(payload) == VENDOR_ID_V1) { vendor_id_payload_t *vid; + bool found = FALSE; chunk_t data; vid = (vendor_id_payload_t*)payload; data = vid->get_data(vid); - if (chunk_equals(data, strongswan_vid)) + for (i = 0; i < countof(vendor_ids); i++) { - DBG1(DBG_IKE, "received strongSwan vendor id"); - this->ike_sa->enable_extension(this->ike_sa, EXT_STRONGSWAN); + if (chunk_equals(data, chunk_create(vendor_ids[i].id, + vendor_ids[i].len))) + { + DBG1(DBG_IKE, "received %s vendor id", vendor_ids[i].desc); + if (vendor_ids[i].extension) + { + this->ike_sa->enable_extension(this->ike_sa, + vendor_ids[i].extension); + } + found = TRUE; + } } - else if (chunk_equals(data, xauth6_vid)) - { - DBG1(DBG_IKE, "received XAuth vendor id"); - this->ike_sa->enable_extension(this->ike_sa, EXT_XAUTH); - } - else if (chunk_equals(data, natt_vid)) - { - DBG1(DBG_IKE, "received NAT-T vendor id"); - this->ike_sa->enable_extension(this->ike_sa, EXT_NATT); - } - else + if (!found) { DBG1(DBG_ENC, "received unknown vendor id: %#B", &data); } From 9f10b95a3b223492930097d46a8f781a4aef88f4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 14:39:24 +0100 Subject: [PATCH 294/534] Added a bunch of well known IKEv1 vendor IDs to database --- src/libcharon/sa/tasks/ike_vendor_v1.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/libcharon/sa/tasks/ike_vendor_v1.c b/src/libcharon/sa/tasks/ike_vendor_v1.c index 68ee8512e..8a756312f 100644 --- a/src/libcharon/sa/tasks/ike_vendor_v1.c +++ b/src/libcharon/sa/tasks/ike_vendor_v1.c @@ -68,6 +68,31 @@ static struct { /* NAT-Traversal, MD5("RFC 3947") */ { "NAT-T (RFC 3947)", EXT_NATT, TRUE, 16, "\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"}, + + /* draft-ietf-ipsec-dpd-00 */ + { "DPD", 0, FALSE, 16, + "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"}, + + { "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16, + "\x27\xba\xb5\xdc\x01\xea\x07\x60\xea\x4e\x31\x90\xac\x27\xc0\xd0"}, + + { "draft-stenberg-ipsec-nat-traversal-02", 0, FALSE, 16, + "\x61\x05\xc4\x22\xe7\x68\x47\xe4\x3f\x96\x84\x80\x12\x92\xae\xcd"}, + + { "draft-ietf-ipsec-nat-t-ike-00", 0, FALSE, 16, + "\x44\x85\x15\x2d\x18\xb6\xbb\xcd\x0b\xe8\xa8\x46\x95\x79\xdd\xcc"}, + + { "draft-ietf-ipsec-nat-t-ike-02", 0, FALSE, 16, + "\xcd\x60\x46\x43\x35\xdf\x21\xf8\x7c\xfd\xb2\xfc\x68\xb6\xa4\x48"}, + + { "draft-ietf-ipsec-nat-t-ike-02", 0, FALSE, 16, + "\x90\xcb\x80\x91\x3e\xbb\x69\x6e\x08\x63\x81\xb5\xec\x42\x7b\x1f"}, + + { "draft-ietf-ipsec-nat-t-ike-03", 0, FALSE, 16, + "\x7d\x94\x19\xa6\x53\x10\xca\x6f\x2c\x17\x9d\x92\x15\x52\x9d\x56"}, + + { "Cisco Unity", 0, FALSE, 16, + "\x12\xf5\xf2\x8c\x45\x71\x68\xa9\x70\x2d\x9f\xe2\x74\xcc\x01\x00"}, }; METHOD(task_t, build, status_t, From e6503db2cf3e922f4efbcae113cf9f9fe8e31390 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 13 Dec 2011 13:08:54 +0100 Subject: [PATCH 295/534] Fixed SIGSEGV when logging peer config matches. --- src/libcharon/config/backend_manager.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c index 5fe137ed5..e7e7a9055 100644 --- a/src/libcharon/config/backend_manager.c +++ b/src/libcharon/config/backend_manager.c @@ -195,12 +195,13 @@ static id_match_t get_peer_match(identification_t *id, auth_cfg_t *auth; identification_t *candidate; id_match_t match = ID_MATCH_NONE; + char *where = local ? "local" : "remote"; chunk_t data; if (!id) { DBG3(DBG_CFG, "peer config match %s: %d (%N)", - local ? "local" : "remote", ID_MATCH_ANY, id_type_names, ID_ANY); + where, ID_MATCH_ANY, id_type_names, ID_ANY); return ID_MATCH_ANY; } @@ -227,7 +228,7 @@ static id_match_t get_peer_match(identification_t *id, data = id->get_encoding(id); DBG3(DBG_CFG, "peer config match %s: %d (%N -> %#B)", - match, id_type_names, id->get_type(id), &data); + where, match, id_type_names, id->get_type(id), &data); return match; } From 0a43f4b6c4602f7ead88f2eb15bb672287608b77 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 13 Dec 2011 13:09:37 +0100 Subject: [PATCH 296/534] Log configured IKE version in stroke plugin. --- src/libcharon/plugins/stroke/stroke_socket.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 808906f00..0f7a6040f 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -195,6 +195,7 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); DBG2(DBG_CFG, " mediated_by=%s", msg->add_conn.ikeme.mediated_by); DBG2(DBG_CFG, " me_peerid=%s", msg->add_conn.ikeme.peerid); + DBG2(DBG_CFG, " keyexchange=%s", msg->add_conn.ikev2 ? "ikev2" : "ikev1"); this->config->add(this->config, msg); this->attribute->add_pool(this->attribute, msg); From 6a6e000134129156f1cfc8ff35bc3ac780c1dd2e Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 13 Dec 2011 13:09:56 +0100 Subject: [PATCH 297/534] Log selected peer config during Main Mode. --- src/libcharon/sa/tasks/main_mode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 5e18bb7c6..b15ed3307 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -341,6 +341,10 @@ static peer_cfg_t *select_config(private_main_mode_t *this, identification_t *id } enumerator->destroy(enumerator); + if (found) + { + DBG2(DBG_CFG, "selected peer config \"%s\"", found->get_name(found)); + } return found; } From f5ef357791d946ecb313825512adc97ab2319188 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 14:52:50 +0100 Subject: [PATCH 298/534] Print unsigned IKEv1 message IDs --- src/libcharon/sa/task_manager_v1.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index e50737063..348bea40f 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -235,7 +235,7 @@ METHOD(task_manager_t, retransmit, status_t, if (this->initiating.retransmitted) { - DBG1(DBG_IKE, "retransmit %d of request with message ID %d seqnr (%d)", + DBG1(DBG_IKE, "retransmit %d of request with message ID %u seqnr (%d)", this->initiating.retransmitted, this->initiating.mid, message_seqnr); } packet = this->initiating.packet->clone(this->initiating.packet); @@ -809,7 +809,7 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg) default: break; } - DBG1(DBG_IKE, "%N %s with message ID %d processing failed", + DBG1(DBG_IKE, "%N %s with message ID %u processing failed", exchange_type_names, msg->get_exchange_type(msg), msg->get_request(msg) ? "request" : "response", msg->get_message_id(msg)); @@ -860,7 +860,7 @@ METHOD(task_manager_t, process_message, status_t, hash = chunk_hash(msg->get_packet_data(msg)); if (hash == this->responding.hash && this->responding.packet) { - DBG1(DBG_IKE, "received retransmit of request with ID %d, " + DBG1(DBG_IKE, "received retransmit of request with ID %u, " "retransmitting response", mid); charon->sender->send(charon->sender, this->responding.packet->clone(this->responding.packet)); From 7b34de45c3499d13374fd234a50511305cc9857e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 15:10:26 +0100 Subject: [PATCH 299/534] Don't send a retransmit for a request we never have sent a response --- src/libcharon/sa/task_manager_v1.c | 31 ++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 348bea40f..1dc2bc3cd 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -75,11 +75,6 @@ struct private_task_manager_t { * Exchange we are currently handling as responder */ struct { - /** - * Message ID of the exchange - */ - u_int32_t mid; - /** * Hash of a previously received message */ @@ -695,6 +690,12 @@ static status_t process_request(private_task_manager_t *this, return DESTROY_ME; } } + else + { /* We don't send a response, so don't retransmit one if we get + * the same message again. */ + DESTROY_IF(this->responding.packet); + this->responding.packet = NULL; + } if (this->passive_tasks->get_count(this->passive_tasks) == 0 && this->queued_tasks->get_count(this->queued_tasks) > 0) { @@ -858,12 +859,20 @@ METHOD(task_manager_t, process_message, status_t, else { hash = chunk_hash(msg->get_packet_data(msg)); - if (hash == this->responding.hash && this->responding.packet) + if (hash == this->responding.hash) { - DBG1(DBG_IKE, "received retransmit of request with ID %u, " - "retransmitting response", mid); - charon->sender->send(charon->sender, - this->responding.packet->clone(this->responding.packet)); + if (this->responding.packet) + { + DBG1(DBG_IKE, "received retransmit of request with ID %u, " + "retransmitting response", mid); + charon->sender->send(charon->sender, + this->responding.packet->clone(this->responding.packet)); + } + else + { + DBG1(DBG_IKE, "received retransmit of request with ID %u, " + "but no response to retransmit", mid); + } return SUCCESS; } @@ -922,8 +931,6 @@ METHOD(task_manager_t, process_message, status_t, flush(this); return DESTROY_ME; } - - this->responding.mid = mid; this->responding.hash = hash; } return SUCCESS; From 3643179535a2abf5d39c2c18e8a986940ebef44f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 15:32:53 +0100 Subject: [PATCH 300/534] Narrow down received and configured traffic selector to a common subset --- src/libcharon/sa/tasks/quick_mode.c | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 92a526e21..3858c0a69 100755 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -296,16 +296,17 @@ static bool get_ke(private_quick_mode_t *this, message_t *message) /** * Select a traffic selector from configuration */ -static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator) +static traffic_selector_t* select_ts(private_quick_mode_t *this, bool local, + linked_list_t *supplied) { traffic_selector_t *ts; linked_list_t *list; host_t *host; - host = this->ike_sa->get_virtual_ip(this->ike_sa, initiator); + host = this->ike_sa->get_virtual_ip(this->ike_sa, local); if (!host) { - if (initiator) + if (local) { host = this->ike_sa->get_my_host(this->ike_sa); } @@ -314,21 +315,21 @@ static traffic_selector_t* select_ts(private_quick_mode_t *this, bool initiator) host = this->ike_sa->get_other_host(this->ike_sa); } } - list = this->config->get_traffic_selectors(this->config, initiator, - NULL, host); + list = this->config->get_traffic_selectors(this->config, local, + supplied, host); if (list->get_first(list, (void**)&ts) == SUCCESS) { if (list->get_count(list) > 1) { DBG1(DBG_IKE, "configuration has more than one %s traffic selector," - " using first only", initiator ? "initiator" : "responder"); + " using first only", local ? "local" : "remote"); } ts = ts->clone(ts); } else { DBG1(DBG_IKE, "%s traffic selector missing in configuration", - initiator ? "initiator" : "responder"); + local ? "local" : "local"); ts = NULL; } list->destroy_offset(list, offsetof(traffic_selector_t, destroy)); @@ -604,8 +605,8 @@ METHOD(task_t, build_i, status_t, } add_ke(this, message); } - this->tsi = select_ts(this, TRUE); - this->tsr = select_ts(this, FALSE); + this->tsi = select_ts(this, TRUE, NULL); + this->tsr = select_ts(this, FALSE, NULL); if (!this->tsi || !this->tsr) { return FAILED; @@ -691,10 +692,13 @@ METHOD(task_t, process_r, status_t, tsr = linked_list_create(); tsi->insert_last(tsi, this->tsi); tsr->insert_last(tsr, this->tsr); + this->tsi = this->tsr = NULL; this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi, me, other); - tsi->destroy(tsi); - tsr->destroy(tsr); + this->tsi = select_ts(this, FALSE, tsi); + this->tsr = select_ts(this, TRUE, tsr); + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); if (!this->config) { DBG1(DBG_IKE, "no child config found"); From fce566a87662988eab6e6f8dcabb08922e489ede Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 16:14:17 +0100 Subject: [PATCH 301/534] Keep a history of received response hashes to detect late retransmissions If we receive an old response and we already sent out the next request, we must be able to identify that it is not the response to the new request. --- src/libcharon/sa/task_manager_v1.c | 37 ++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 1dc2bc3cd..e44e4ac33 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -31,6 +31,15 @@ #include #include +/** + * Number of old messages hashes we keep for retransmission. + * + * In Main Mode, we must ignore messages from a previous message pair if + * we already continued to the next. Otherwise a late retransmission + * could be considered as a reply to the newer request. + */ +#define MAX_OLD_HASHES 2 + typedef struct exchange_t exchange_t; /** @@ -96,6 +105,16 @@ struct private_task_manager_t { */ u_int32_t mid; + /** + * Hashes of old responses we can ignore + */ + u_int32_t old_hashes[MAX_OLD_HASHES]; + + /** + * Position in old hash array + */ + int old_hash_pos; + /** * Sequence number of the last sent message */ @@ -826,7 +845,7 @@ static status_t parse_message(private_task_manager_t *this, message_t *msg) METHOD(task_manager_t, process_message, status_t, private_task_manager_t *this, message_t *msg) { - u_int32_t hash, mid; + u_int32_t hash, mid, i; host_t *me, *other; status_t status; @@ -834,11 +853,21 @@ METHOD(task_manager_t, process_message, status_t, me = msg->get_destination(msg); other = msg->get_source(msg); mid = msg->get_message_id(msg); + hash = chunk_hash(msg->get_packet_data(msg)); + for (i = 0; i < MAX_OLD_HASHES; i++) + { + if (this->initiating.old_hashes[i] == hash) + { + DBG1(DBG_IKE, "received retransmit of response with ID %u, " + "but next request already sent", mid); + return SUCCESS; + } + } if ((mid && mid == this->initiating.mid) || (this->initiating.mid == 0 && msg->get_exchange_type(msg) == this->initiating.type && - this->active_tasks->get_count(this->active_tasks))) + this->active_tasks->get_count(this->active_tasks))) { msg->set_request(msg, FALSE); status = parse_message(this, msg); @@ -855,10 +884,11 @@ METHOD(task_manager_t, process_message, status_t, flush(this); return DESTROY_ME; } + this->initiating.old_hashes[(this->initiating.old_hash_pos++) % + MAX_OLD_HASHES] = hash; } else { - hash = chunk_hash(msg->get_packet_data(msg)); if (hash == this->responding.hash) { if (this->responding.packet) @@ -875,7 +905,6 @@ METHOD(task_manager_t, process_message, status_t, } return SUCCESS; } - if (msg->get_exchange_type(msg) == TRANSACTION && this->active_tasks->get_count(this->active_tasks) && !this->queued) From 0b0191e143b1c3b6ecef62c702aed16ebdd7c5d3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 13 Dec 2011 16:21:47 +0100 Subject: [PATCH 302/534] Ignore additional TRANSACTION request if we already queued one --- src/libcharon/sa/task_manager_v1.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index e44e4ac33..baf7bb437 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -906,9 +906,14 @@ METHOD(task_manager_t, process_message, status_t, return SUCCESS; } if (msg->get_exchange_type(msg) == TRANSACTION && - this->active_tasks->get_count(this->active_tasks) && - !this->queued) + this->active_tasks->get_count(this->active_tasks)) { /* main mode not yet complete, queue XAuth/Mode config tasks */ + if (this->queued) + { + DBG1(DBG_IKE, "ignoring additional %N request, queue full", + exchange_type_names, TRANSACTION); + return SUCCESS; + } this->queued = message_create_from_packet(msg->get_packet(msg)); if (this->queued->parse_header(this->queued) != SUCCESS) { From 33493a5253ef541b519cb9391ab9f7493fd9b262 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 13 Dec 2011 17:12:23 +0100 Subject: [PATCH 303/534] Added method to get encoded version if ID_V1 payload. --- src/libcharon/encoding/payloads/id_payload.c | 10 ++++++++++ src/libcharon/encoding/payloads/id_payload.h | 7 +++++++ 2 files changed, 17 insertions(+) diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index 4d5cd05fe..02b07d691 100755 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -327,6 +327,15 @@ METHOD(id_payload_t, get_ts, traffic_selector_t*, return NULL; } +METHOD(id_payload_t, get_encoded, chunk_t, + private_id_payload_t *this) +{ + u_int16_t port = htons(this->port); + return chunk_cat("cccc", chunk_from_thing(this->id_type), + chunk_from_thing(this->protocol_id), + chunk_from_thing(port), this->id_data); +} + METHOD2(payload_t, id_payload_t, destroy, void, private_id_payload_t *this) { @@ -354,6 +363,7 @@ id_payload_t *id_payload_create(payload_type_t type) .destroy = _destroy, }, .get_identification = _get_identification, + .get_encoded = _get_encoded, .get_ts = _get_ts, .destroy = _destroy, }, diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h index 22016bc19..94ed1cb38 100644 --- a/src/libcharon/encoding/payloads/id_payload.h +++ b/src/libcharon/encoding/payloads/id_payload.h @@ -54,6 +54,13 @@ struct id_payload_t { */ traffic_selector_t* (*get_ts)(id_payload_t *this); + /** + * Get encoded payload without fixed payload header (used for IKEv1). + * + * @return encoded payload (gets allocated) + */ + chunk_t (*get_encoded)(id_payload_t *this); + /** * Destroys an id_payload_t object. */ From 19965ffe560d6f6393e58baa77b58de7270a64ce Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 13 Dec 2011 18:53:44 +0100 Subject: [PATCH 304/534] Create authenticators right when they are used during Main Mode. --- src/libcharon/sa/tasks/main_mode.c | 67 +++++++++++++++++++----------- 1 file changed, 43 insertions(+), 24 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index b15ed3307..dffd5e45b 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -119,11 +119,6 @@ struct private_main_mode_t { */ auth_method_t auth_method; - /** - * Authenticator to use - */ - authenticator_t *authenticator; - /** states of main mode */ enum { MM_INIT, @@ -147,6 +142,23 @@ static auth_cfg_t *get_auth_cfg(peer_cfg_t *peer_cfg, bool local) return cfg; } +/** + * Create an authenticator, if supported + */ +static authenticator_t *create_authenticator(private_main_mode_t *this) +{ + authenticator_t *authenticator; + authenticator = authenticator_create_v1(this->ike_sa, this->initiator, + this->auth_method, this->dh, + this->dh_value, this->sa_payload); + if (!authenticator) + { + DBG1(DBG_IKE, "negotiated authentication method %N not supported", + auth_method_names, this->auth_method); + } + return authenticator; +} + /** * Save the encoded SA payload of a message */ @@ -517,6 +529,7 @@ METHOD(task_t, build_i, status_t, } case MM_KE: { + authenticator_t *authenticator; id_payload_t *id_payload; identification_t *id; @@ -532,11 +545,15 @@ METHOD(task_t, build_i, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - if (this->authenticator->build(this->authenticator, - message) != SUCCESS) + authenticator = create_authenticator(this); + if (!authenticator || authenticator->build(authenticator, + message) != SUCCESS) { + DESTROY_IF(authenticator); return FAILED; } + authenticator->destroy(authenticator); + this->state = MM_AUTH; return NEED_MORE; } @@ -617,6 +634,7 @@ METHOD(task_t, process_r, status_t, } case MM_KE: { + authenticator_t *authenticator; id_payload_t *id_payload; identification_t *id; @@ -645,13 +663,16 @@ METHOD(task_t, process_r, status_t, return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); } - if (this->authenticator->process(this->authenticator, - message) != SUCCESS) + authenticator = create_authenticator(this); + if (!authenticator || authenticator->process(authenticator, + message) != SUCCESS) { + DESTROY_IF(authenticator); return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); } - this->state = MM_AUTH; + authenticator->destroy(authenticator); + this->state = MM_AUTH; if (has_notify_errors(this, message)) { return FAILED; @@ -776,15 +797,6 @@ static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, nonce_i, nonce_r, NULL); - this->authenticator = authenticator_create_v1(this->ike_sa, this->initiator, - this->auth_method, this->dh, - this->dh_value, this->sa_payload); - if (!this->authenticator) - { - DBG1(DBG_IKE, "negotiated authentication method %N not supported", - auth_method_names, this->auth_method); - return FALSE; - } return TRUE; } @@ -834,6 +846,7 @@ METHOD(task_t, build_r, status_t, } case MM_AUTH: { + authenticator_t *authenticator; id_payload_t *id_payload; identification_t *id; @@ -849,11 +862,14 @@ METHOD(task_t, build_r, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - if (this->authenticator->build(this->authenticator, - message) != SUCCESS) + authenticator = create_authenticator(this); + if (!authenticator || authenticator->build(authenticator, + message) != SUCCESS) { + DESTROY_IF(authenticator); return FAILED; } + authenticator->destroy(authenticator); if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) { @@ -941,6 +957,7 @@ METHOD(task_t, process_i, status_t, } case MM_AUTH: { + authenticator_t *authenticator; id_payload_t *id_payload; identification_t *id; @@ -960,11 +977,14 @@ METHOD(task_t, process_i, status_t, } this->ike_sa->set_other_id(this->ike_sa, id); - if (this->authenticator->process(this->authenticator, - message) != SUCCESS) + authenticator = create_authenticator(this); + if (!authenticator || authenticator->process(authenticator, + message) != SUCCESS) { + DESTROY_IF(authenticator); return FAILED; } + authenticator->destroy(authenticator); switch (this->auth_method) { @@ -1004,7 +1024,6 @@ METHOD(task_t, destroy, void, DESTROY_IF(this->peer_cfg); DESTROY_IF(this->proposal); DESTROY_IF(this->dh); - DESTROY_IF(this->authenticator); free(this->dh_value.ptr); free(this->nonce_i.ptr); free(this->nonce_r.ptr); From a6c328a6e9b865f51fb6a7129646552142157317 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 13 Dec 2011 18:56:06 +0100 Subject: [PATCH 305/534] Use real ID payload to build HASH_I|R for Main Mode authentication. This is required for clients like the iPhone which set the protocol and/or port fields of the ID payload. --- src/libcharon/sa/authenticators/authenticator.c | 9 ++++++--- src/libcharon/sa/authenticators/authenticator.h | 11 +++++++++-- .../sa/authenticators/psk_v1_authenticator.c | 15 +++++++++++---- .../sa/authenticators/psk_v1_authenticator.h | 5 ++++- .../sa/authenticators/pubkey_v1_authenticator.c | 16 +++++++++++++--- .../sa/authenticators/pubkey_v1_authenticator.h | 5 ++++- src/libcharon/sa/keymat_v1.c | 8 +++----- src/libcharon/sa/keymat_v1.h | 4 ++-- src/libcharon/sa/tasks/main_mode.c | 14 ++++++++------ 9 files changed, 60 insertions(+), 27 deletions(-) diff --git a/src/libcharon/sa/authenticators/authenticator.c b/src/libcharon/sa/authenticators/authenticator.c index b052dd87b..f2319a420 100644 --- a/src/libcharon/sa/authenticators/authenticator.c +++ b/src/libcharon/sa/authenticators/authenticator.c @@ -110,7 +110,8 @@ authenticator_t *authenticator_create_verifier( */ authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, auth_method_t auth_method, diffie_hellman_t *dh, - chunk_t dh_value, chunk_t sa_payload) + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload) { switch (auth_method) { @@ -118,12 +119,14 @@ authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_RESP_PSK: return (authenticator_t*)psk_v1_authenticator_create(ike_sa, - initiator, dh, dh_value, sa_payload); + initiator, dh, dh_value, sa_payload, + id_payload); case AUTH_RSA: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa, - initiator, dh, dh_value, sa_payload); + initiator, dh, dh_value, sa_payload, + id_payload); default: return NULL; } diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticators/authenticator.h index 5a8d26d1e..3af939160 100644 --- a/src/libcharon/sa/authenticators/authenticator.h +++ b/src/libcharon/sa/authenticators/authenticator.h @@ -194,7 +194,11 @@ authenticator_t *authenticator_create_verifier( char reserved[3]); /** - * Create an IKEv1 authenticator to build and verify signatures or hash payloads. + * Create an IKEv1 authenticator to build and verify signatures or hash + * payloads. + * + * @note Due to the fixed ID, these authenticators can only be used in one + * direction at a time. * * @param ike_sa associated IKE_SA * @param initiator TRUE if we are the IKE_SA initiator @@ -202,10 +206,13 @@ authenticator_t *authenticator_create_verifier( * @param dh diffie hellman key exchange * @param dh_value others public diffie hellman value * @param sa_payload generated SA payload data, without payload header + * @param id_payload encoded ID payload of peer to authenticate or verify + * without payload header (gets owned) * @return authenticator, NULL if not supported */ authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, auth_method_t auth_method, diffie_hellman_t *dh, - chunk_t dh_value, chunk_t sa_payload); + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload); #endif /** AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/psk_v1_authenticator.c b/src/libcharon/sa/authenticators/psk_v1_authenticator.c index ecce92268..11fd8118d 100644 --- a/src/libcharon/sa/authenticators/psk_v1_authenticator.c +++ b/src/libcharon/sa/authenticators/psk_v1_authenticator.c @@ -55,6 +55,11 @@ struct private_psk_v1_authenticator_t { * Encoded SA payload, without fixed header */ chunk_t sa_payload; + + /** + * Encoded ID payload, without fixed header + */ + chunk_t id_payload; }; METHOD(authenticator_t, build, status_t, @@ -68,7 +73,7 @@ METHOD(authenticator_t, build, status_t, keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value, this->ike_sa->get_id(this->ike_sa), this->sa_payload, - this->ike_sa->get_my_id(this->ike_sa)); + this->id_payload); free(dh.ptr); hash_payload = hash_payload_create(HASH_V1); @@ -97,9 +102,8 @@ METHOD(authenticator_t, process, status_t, keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh, this->ike_sa->get_id(this->ike_sa), this->sa_payload, - this->ike_sa->get_other_id(this->ike_sa)); + this->id_payload); free(dh.ptr); - if (chunk_equals(hash, hash_payload->get_hash(hash_payload))) { free(hash.ptr); @@ -113,6 +117,7 @@ METHOD(authenticator_t, process, status_t, METHOD(authenticator_t, destroy, void, private_psk_v1_authenticator_t *this) { + chunk_free(&this->id_payload); free(this); } @@ -121,7 +126,8 @@ METHOD(authenticator_t, destroy, void, */ psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, bool initiator, diffie_hellman_t *dh, - chunk_t dh_value, chunk_t sa_payload) + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload) { private_psk_v1_authenticator_t *this; @@ -139,6 +145,7 @@ psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, .dh = dh, .dh_value = dh_value, .sa_payload = sa_payload, + .id_payload = id_payload, ); return &this->public; diff --git a/src/libcharon/sa/authenticators/psk_v1_authenticator.h b/src/libcharon/sa/authenticators/psk_v1_authenticator.h index 1103ee62f..e01d49c95 100644 --- a/src/libcharon/sa/authenticators/psk_v1_authenticator.h +++ b/src/libcharon/sa/authenticators/psk_v1_authenticator.h @@ -44,10 +44,13 @@ struct psk_v1_authenticator_t { * @param dh diffie hellman key exchange * @param dh_value others public diffie hellman value * @param sa_payload generated SA payload data, without payload header + * @param id_payload encoded ID payload of peer to authenticate or verify + * without payload header (gets owned) * @return PSK authenticator */ psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, bool initiator, diffie_hellman_t *dh, - chunk_t dh_value, chunk_t sa_payload); + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload); #endif /** PSK_V1_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c index e3e7a8073..a947349c9 100644 --- a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c +++ b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c @@ -55,6 +55,11 @@ struct private_pubkey_v1_authenticator_t { * Encoded SA payload, without fixed header */ chunk_t sa_payload; + + /** + * Encoded ID payload, without fixed header + */ + chunk_t id_payload; }; METHOD(authenticator_t, build, status_t, @@ -86,7 +91,8 @@ METHOD(authenticator_t, build, status_t, this->dh->get_my_public_value(this->dh, &dh); keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); hash = keymat->get_hash(keymat, this->initiator, dh, this->dh_value, - this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); + this->ike_sa->get_id(this->ike_sa), this->sa_payload, + this->id_payload); free(dh.ptr); if (private->sign(private, scheme, hash, &sig)) @@ -138,7 +144,8 @@ METHOD(authenticator_t, process, status_t, this->dh->get_my_public_value(this->dh, &dh); keymat = (keymat_v1_t*)this->ike_sa->get_keymat(this->ike_sa); hash = keymat->get_hash(keymat, !this->initiator, this->dh_value, dh, - this->ike_sa->get_id(this->ike_sa), this->sa_payload, id); + this->ike_sa->get_id(this->ike_sa), this->sa_payload, + this->id_payload); free(dh.ptr); sig = sig_payload->get_hash(sig_payload); @@ -175,6 +182,7 @@ METHOD(authenticator_t, process, status_t, METHOD(authenticator_t, destroy, void, private_pubkey_v1_authenticator_t *this) { + chunk_free(&this->id_payload); free(this); } @@ -183,7 +191,8 @@ METHOD(authenticator_t, destroy, void, */ pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, bool initiator, diffie_hellman_t *dh, - chunk_t dh_value, chunk_t sa_payload) + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload) { private_pubkey_v1_authenticator_t *this; @@ -201,6 +210,7 @@ pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, .dh = dh, .dh_value = dh_value, .sa_payload = sa_payload, + .id_payload = id_payload, ); return &this->public; diff --git a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h index ed6d77cc0..48968d6a1 100644 --- a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h +++ b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h @@ -43,10 +43,13 @@ struct pubkey_v1_authenticator_t { * @param dh diffie hellman key exchange * @param dh_value others public diffie hellman value * @param sa_payload generated SA payload data, without payload header + * @param id_payload encoded ID payload of peer to authenticate or verify + * without payload header (gets owned) * @return pubkey authenticator */ pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, bool initiator, diffie_hellman_t *dh, - chunk_t dh_value, chunk_t sa_payload); + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload); #endif /** PUBKEY_V1_AUTHENTICATOR_H_ @}*/ diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 8cf10cdf8..8d384143c 100755 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -638,12 +638,10 @@ METHOD(keymat_v1_t, get_hasher, hasher_t*, METHOD(keymat_v1_t, get_hash, chunk_t, private_keymat_v1_t *this, bool initiator, chunk_t dh, chunk_t dh_other, - ike_sa_id_t *ike_sa_id, chunk_t sa_i, identification_t *id) + ike_sa_id_t *ike_sa_id, chunk_t sa_i, chunk_t id) { chunk_t hash, data; u_int64_t spi, spi_other; - /* TODO-IKEv1: get real bytes from ID header? */ - u_int8_t id_header[4] = { id->get_type(id), 0, 0, 0 }; /* HASH_I = prf(SKEYID, g^xi | g^xr | CKY-I | CKY-R | SAi_b | IDii_b ) * HASH_R = prf(SKEYID, g^xr | g^xi | CKY-R | CKY-I | SAi_b | IDir_b ) @@ -658,9 +656,9 @@ METHOD(keymat_v1_t, get_hash, chunk_t, spi_other = ike_sa_id->get_initiator_spi(ike_sa_id); spi = ike_sa_id->get_responder_spi(ike_sa_id); } - data = chunk_cat("ccccccc", dh, dh_other, + data = chunk_cat("cccccc", dh, dh_other, chunk_from_thing(spi), chunk_from_thing(spi_other), - sa_i, chunk_from_thing(id_header), id->get_encoding(id)); + sa_i, id); DBG3(DBG_IKE, "HASH_%c data %B", initiator ? 'I' : 'R', &data); diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/keymat_v1.h index 89314afb0..875ad9d30 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/keymat_v1.h @@ -99,12 +99,12 @@ struct keymat_v1_t { * @param dh_other others public DH value * @param ike_sa_id IKE_SA identifier * @param sa_i encoded SA payload of initiator - * @param id ID of peer to create hash for + * @param id encoded IDii payload for HASH_I (IDir for HASH_R) * @return allocated HASH data */ chunk_t (*get_hash)(keymat_v1_t *this, bool initiator, chunk_t dh, chunk_t dh_other, ike_sa_id_t *ike_sa_id, - chunk_t sa_i, identification_t *id); + chunk_t sa_i, chunk_t id); /** * Get HASH data for integrity/authentication in Phase 2 exchanges. diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index dffd5e45b..0e936209f 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -145,12 +145,14 @@ static auth_cfg_t *get_auth_cfg(peer_cfg_t *peer_cfg, bool local) /** * Create an authenticator, if supported */ -static authenticator_t *create_authenticator(private_main_mode_t *this) +static authenticator_t *create_authenticator(private_main_mode_t *this, + id_payload_t *id) { authenticator_t *authenticator; authenticator = authenticator_create_v1(this->ike_sa, this->initiator, this->auth_method, this->dh, - this->dh_value, this->sa_payload); + this->dh_value, this->sa_payload, + id->get_encoded(id)); if (!authenticator) { DBG1(DBG_IKE, "negotiated authentication method %N not supported", @@ -545,7 +547,7 @@ METHOD(task_t, build_i, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - authenticator = create_authenticator(this); + authenticator = create_authenticator(this, id_payload); if (!authenticator || authenticator->build(authenticator, message) != SUCCESS) { @@ -663,7 +665,7 @@ METHOD(task_t, process_r, status_t, return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); } - authenticator = create_authenticator(this); + authenticator = create_authenticator(this, id_payload); if (!authenticator || authenticator->process(authenticator, message) != SUCCESS) { @@ -862,7 +864,7 @@ METHOD(task_t, build_r, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - authenticator = create_authenticator(this); + authenticator = create_authenticator(this, id_payload); if (!authenticator || authenticator->build(authenticator, message) != SUCCESS) { @@ -977,7 +979,7 @@ METHOD(task_t, process_i, status_t, } this->ike_sa->set_other_id(this->ike_sa, id); - authenticator = create_authenticator(this); + authenticator = create_authenticator(this, id_payload); if (!authenticator || authenticator->process(authenticator, message) != SUCCESS) { From 29101ce97817c8c4a2cac82cfd15a1ad47e8a282 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 09:40:43 +0100 Subject: [PATCH 306/534] Added a IKEv1 hybrid authenticator based on Pubkey/PSK authenticators --- src/libcharon/Makefile.am | 1 + .../sa/authenticators/authenticator.c | 6 + .../sa/authenticators/hybrid_authenticator.c | 113 ++++++++++++++++++ .../sa/authenticators/hybrid_authenticator.h | 56 +++++++++ 4 files changed, 176 insertions(+) create mode 100644 src/libcharon/sa/authenticators/hybrid_authenticator.c create mode 100644 src/libcharon/sa/authenticators/hybrid_authenticator.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 47c52abaa..19b55486e 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -65,6 +65,7 @@ sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \ sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \ sa/authenticators/psk_v1_authenticator.c sa/authenticators/psk_v1_authenticator.h \ sa/authenticators/pubkey_v1_authenticator.c sa/authenticators/pubkey_v1_authenticator.h \ +sa/authenticators/hybrid_authenticator.c sa/authenticators/hybrid_authenticator.h \ sa/authenticators/xauth/xauth_method.c sa/authenticators/xauth/xauth_method.h \ sa/authenticators/xauth/xauth_manager.c sa/authenticators/xauth/xauth_manager.h \ sa/child_sa.c sa/child_sa.h \ diff --git a/src/libcharon/sa/authenticators/authenticator.c b/src/libcharon/sa/authenticators/authenticator.c index f2319a420..73029b9e1 100644 --- a/src/libcharon/sa/authenticators/authenticator.c +++ b/src/libcharon/sa/authenticators/authenticator.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -127,6 +128,11 @@ authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa, initiator, dh, dh_value, sa_payload, id_payload); + case AUTH_HYBRID_INIT_RSA: + case AUTH_HYBRID_RESP_RSA: + return (authenticator_t*)hybrid_authenticator_create(ike_sa, + initiator, dh, dh_value, sa_payload, + id_payload); default: return NULL; } diff --git a/src/libcharon/sa/authenticators/hybrid_authenticator.c b/src/libcharon/sa/authenticators/hybrid_authenticator.c new file mode 100644 index 000000000..f1bc1ecc2 --- /dev/null +++ b/src/libcharon/sa/authenticators/hybrid_authenticator.c @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "hybrid_authenticator.h" + +#include + +typedef struct private_hybrid_authenticator_t private_hybrid_authenticator_t; + +/** + * Private data of an hybrid_authenticator_t object. + */ +struct private_hybrid_authenticator_t { + + /** + * Public authenticator_t interface. + */ + hybrid_authenticator_t public; + + /** + * Public key authenticator + */ + authenticator_t *sig; + + /** + * HASH payload authenticator without credentials + */ + authenticator_t *hash; +}; + +METHOD(authenticator_t, build_i, status_t, + private_hybrid_authenticator_t *this, message_t *message) +{ + return this->hash->build(this->hash, message); +} + +METHOD(authenticator_t, process_r, status_t, + private_hybrid_authenticator_t *this, message_t *message) +{ + return this->hash->process(this->hash, message); +} + +METHOD(authenticator_t, build_r, status_t, + private_hybrid_authenticator_t *this, message_t *message) +{ + return this->sig->build(this->sig, message); +} + +METHOD(authenticator_t, process_i, status_t, + private_hybrid_authenticator_t *this, message_t *message) +{ + return this->sig->process(this->sig, message); +} + +METHOD(authenticator_t, destroy, void, + private_hybrid_authenticator_t *this) +{ + DESTROY_IF(this->hash); + DESTROY_IF(this->sig); + free(this); +} + +/* + * Described in header. + */ +hybrid_authenticator_t *hybrid_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload) +{ + private_hybrid_authenticator_t *this; + + INIT(this, + .public = { + .authenticator = { + .is_mutual = (void*)return_false, + .destroy = _destroy, + }, + }, + .sig = authenticator_create_v1(ike_sa, initiator, AUTH_RSA, dh, + dh_value, sa_payload, id_payload), + .hash = authenticator_create_v1(ike_sa, initiator, AUTH_PSK, + dh, dh_value, sa_payload, chunk_clone(id_payload)), + ); + if (!this->sig || !this->hash) + { + destroy(this); + return NULL; + } + if (initiator) + { + this->public.authenticator.build = _build_i; + this->public.authenticator.process = _process_i; + } + else + { + this->public.authenticator.build = _build_r; + this->public.authenticator.process = _process_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/authenticators/hybrid_authenticator.h b/src/libcharon/sa/authenticators/hybrid_authenticator.h new file mode 100644 index 000000000..37057470b --- /dev/null +++ b/src/libcharon/sa/authenticators/hybrid_authenticator.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup hybrid_authenticator hybrid_authenticator + * @{ @ingroup authenticators + */ + +#ifndef HYBRID_AUTHENTICATOR_H_ +#define HYBRID_AUTHENTICATOR_H_ + +typedef struct hybrid_authenticator_t hybrid_authenticator_t; + +#include + +/** + * Implementation of authenticator_t using IKEv1 hybrid authentication. + */ +struct hybrid_authenticator_t { + + /** + * Implemented authenticator_t interface. + */ + authenticator_t authenticator; +}; + +/** + * Create an authenticator to build hybrid signatures. + * + * @param ike_sa associated IKE_SA + * @param initiator TRUE if we are the IKE_SA initiator + * @param dh diffie hellman key exchange + * @param dh_value others public diffie hellman value + * @param sa_payload generated SA payload data, without payload header + * @param id_payload encoded ID payload of peer to authenticate or verify + * without payload header (gets owned) + * @return hybrid authenticator + */ +hybrid_authenticator_t *hybrid_authenticator_create(ike_sa_t *ike_sa, + bool initiator, diffie_hellman_t *dh, + chunk_t dh_value, chunk_t sa_payload, + chunk_t id_payload); + +#endif /** HYBRID_AUTHENTICATOR_H_ @}*/ From 51da01a7220933cd2da0041f6dafb2dc13684b5d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 09:43:44 +0100 Subject: [PATCH 307/534] Support encoding of Hybrid initiator authentication method --- src/libcharon/encoding/payloads/proposal_substructure.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index d5778fab3..57b948145 100755 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -247,6 +247,11 @@ typedef enum { IKEV1_AUTH_XAUTH_RESP_RSA_ENC = 65008, IKEV1_AUTH_XAUTH_INIT_RSA_ENC_REV = 65009, IKEV1_AUTH_XAUTH_RESP_RSA_ENC_REV = 65010, + IKEV1_AUTH_HYBRID_INIT_RSA = 64221, + IKEV1_AUTH_HYBRID_RESP_RSA = 64222, + IKEV1_AUTH_HYBRID_INIT_DSS = 64223, + IKEV1_AUTH_HYBRID_RESP_DSS = 64224, + } ikev1_auth_method_t; METHOD(payload_t, verify, status_t, @@ -587,6 +592,8 @@ static u_int16_t get_ikev1_auth(auth_method_t method) return IKEV1_AUTH_XAUTH_INIT_PSK; case AUTH_XAUTH_INIT_RSA: return IKEV1_AUTH_XAUTH_INIT_RSA; + case AUTH_HYBRID_INIT_RSA: + return IKEV1_AUTH_HYBRID_INIT_RSA; default: /* TODO-IKEv1: Handle other XAUTH methods */ /* TODO-IKEv1: Handle ECDSA methods */ @@ -889,6 +896,8 @@ METHOD(proposal_substructure_t, get_auth_method, auth_method_t, return AUTH_XAUTH_INIT_PSK; case IKEV1_AUTH_XAUTH_INIT_RSA: return AUTH_XAUTH_INIT_RSA; + case IKEV1_AUTH_HYBRID_INIT_RSA: + return AUTH_HYBRID_INIT_RSA; default: /* TODO-IKEv1: other XAUTH, ECDSA sigs */ return AUTH_NONE; From d548435a02f26cb7d3624349107f8b062d48556e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 09:44:39 +0100 Subject: [PATCH 308/534] Added hybrid authentication support to Main Mode --- src/libcharon/sa/keymat_v1.c | 2 ++ src/libcharon/sa/tasks/main_mode.c | 10 +++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c index 8d384143c..100c9526a 100755 --- a/src/libcharon/sa/keymat_v1.c +++ b/src/libcharon/sa/keymat_v1.c @@ -429,6 +429,8 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, case AUTH_RSA: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_INIT_RSA: + case AUTH_HYBRID_RESP_RSA: { this->prf->set_key(this->prf, nonces); this->prf->allocate_bytes(this->prf, g_xy, &this->skeyid); diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 0e936209f..f60bda768 100755 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -327,7 +327,11 @@ static auth_method_t get_auth_method(private_main_mode_t *this, return AUTH_XAUTH_RESP_PSK; } } - /* TODO-IKEv1: Hybrid methods? */ + if (i1 == AUTH_CLASS_XAUTH && r1 == AUTH_CLASS_PUBKEY && + i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) + { + return AUTH_HYBRID_INIT_RSA; + } return AUTH_NONE;; } @@ -883,11 +887,13 @@ METHOD(task_t, build_r, status_t, { case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_INIT_RSA: + case AUTH_HYBRID_INIT_RSA: this->ike_sa->queue_task(this->ike_sa, (task_t*)xauth_create(this->ike_sa, TRUE)); return SUCCESS; case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_RESP_RSA: /* TODO-IKEv1: not yet supported */ return FAILED; default: @@ -992,10 +998,12 @@ METHOD(task_t, process_i, status_t, { case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_INIT_RSA: + case AUTH_HYBRID_INIT_RSA: /* wait for XAUTH request */ return SUCCESS; case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_RESP_RSA: /* TODO-IKEv1: not yet */ return FAILED; default: From d1b986eb4825ea93a9bade30c2c42b76a38e6a0d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 09:44:59 +0100 Subject: [PATCH 309/534] Look for an XAuth authentication config both in the first and the second round --- src/libcharon/sa/tasks/xauth.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/tasks/xauth.c b/src/libcharon/sa/tasks/xauth.c index 4fd896e3c..58e127aa9 100644 --- a/src/libcharon/sa/tasks/xauth.c +++ b/src/libcharon/sa/tasks/xauth.c @@ -93,11 +93,15 @@ static xauth_method_t *load_method(ike_sa_t *ike_sa, bool initiator) peer_cfg = ike_sa->get_peer_cfg(ike_sa); enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !initiator); if (!enumerator->enumerate(enumerator, &auth) || - !enumerator->enumerate(enumerator, &auth)) + (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH) { - DBG1(DBG_CFG, "no second authentication round found for XAuth"); - enumerator->destroy(enumerator); - return NULL; + if (!enumerator->enumerate(enumerator, &auth) || + (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH) + { + DBG1(DBG_CFG, "no XAuth authentication round found"); + enumerator->destroy(enumerator); + return NULL; + } } name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND); enumerator->destroy(enumerator); From 7b25135ecfac553deb384a8f90bdbc80c8db67bb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 10:56:23 +0100 Subject: [PATCH 310/534] Send certificates and requests when using Hybrid authentication --- src/libcharon/sa/tasks/ike_cert_post_v1.c | 2 ++ src/libcharon/sa/tasks/ike_cert_pre_v1.c | 18 +++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/ike_cert_post_v1.c b/src/libcharon/sa/tasks/ike_cert_post_v1.c index 517f8c1bf..2c1c8750f 100755 --- a/src/libcharon/sa/tasks/ike_cert_post_v1.c +++ b/src/libcharon/sa/tasks/ike_cert_post_v1.c @@ -77,6 +77,8 @@ static bool use_certs(private_ike_cert_post_v1_t *this, message_t *message) case AUTH_RSA: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_INIT_RSA: + case AUTH_HYBRID_RESP_RSA: use = TRUE; break; default: diff --git a/src/libcharon/sa/tasks/ike_cert_pre_v1.c b/src/libcharon/sa/tasks/ike_cert_pre_v1.c index fab8d5bb3..0220650b2 100755 --- a/src/libcharon/sa/tasks/ike_cert_pre_v1.c +++ b/src/libcharon/sa/tasks/ike_cert_pre_v1.c @@ -45,6 +45,11 @@ struct private_ike_cert_pre_v1_t { */ bool initiator; + /** + * Send certificate requests? + */ + bool send_req; + /** next message we expect */ enum { CR_SA, @@ -304,6 +309,13 @@ static bool use_certs(private_ike_cert_pre_v1_t *this, message_t *message) switch (sa_payload->get_auth_method(sa_payload)) { + case AUTH_HYBRID_INIT_RSA: + case AUTH_HYBRID_RESP_RSA: + if (!this->initiator) + { + this->send_req = FALSE; + } + /* FALL */ case AUTH_RSA: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: @@ -401,7 +413,10 @@ METHOD(task_t, build_r, status_t, this->state = CR_KE; return NEED_MORE; case CR_KE: - build_certreqs(this, message); + if (this->send_req) + { + build_certreqs(this, message); + } this->state = CR_AUTH; return NEED_MORE; case CR_AUTH: @@ -502,6 +517,7 @@ ike_cert_pre_v1_t *ike_cert_pre_v1_create(ike_sa_t *ike_sa, bool initiator) .ike_sa = ike_sa, .initiator = initiator, .state = CR_SA, + .send_req = TRUE, ); if (initiator) { From 137c06babfc2b4830206dd536ffdf0a95bf99841 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 15:21:35 +0100 Subject: [PATCH 311/534] Use a single task_type_t enum name for ME and non-ME variant --- src/libcharon/sa/tasks/task.c | 82 ++++++++++++----------------------- 1 file changed, 27 insertions(+), 55 deletions(-) diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index f8ff56571..77c0af96a 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -16,61 +16,33 @@ #include "task.h" +ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, + "IKE_INIT", + "IKE_NATD", + "IKE_MOBIKE", + "IKE_AUTH", + "IKE_AUTH_LIFETIME", + "IKE_CERT_PRE", + "IKE_CERT_POST", + "IKE_CONFIG", + "IKE_REKEY", + "IKE_REAUTH", + "IKE_DELETE", + "IKE_DPD", + "IKE_VENDOR", #ifdef ME -ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, - "IKE_INIT", - "IKE_NATD", - "IKE_MOBIKE", - "IKE_AUTH", - "IKE_AUTH_LIFETIME", - "IKE_CERT_PRE", - "IKE_CERT_POST", - "IKE_CONFIG", - "IKE_REKEY", - "IKE_REAUTH", - "IKE_DELETE", - "IKE_DPD", - "IKE_VENDOR", "IKE_ME", - "CHILD_CREATE", - "CHILD_DELETE", - "CHILD_REKEY", - "MAIN_MODE", - "INFORMATIONAL", - "XAUTH", - "MODE_CONFIG", - "QUICK_MODE", - "VENDOR_V1", - "IKE_NATD_V1", - "IKE_CERT_PRE_V1", - "IKE_CERT_POST_V1", -); -#else -ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, - "IKE_INIT", - "IKE_NATD", - "IKE_MOBIKE", - "IKE_AUTH", - "IKE_AUTH_LIFETIME", - "IKE_CERT_PRE", - "IKE_CERT_POST", - "IKE_CONFIG", - "IKE_REKEY", - "IKE_REAUTH", - "IKE_DELETE", - "IKE_DPD", - "IKE_VENDOR", - "CHILD_CREATE", - "CHILD_DELETE", - "CHILD_REKEY", - "MAIN_MODE", - "INFORMATIONAL", - "XAUTH", - "MODE_CONFIG", - "QUICK_MODE", - "VENDOR_V1", - "IKE_NATD_V1", - "IKE_CERT_PRE_V1", - "IKE_CERT_POST_V1", -); #endif /* ME */ + "CHILD_CREATE", + "CHILD_DELETE", + "CHILD_REKEY", + "MAIN_MODE", + "INFORMATIONAL", + "XAUTH", + "MODE_CONFIG", + "QUICK_MODE", + "VENDOR_V1", + "IKE_NATD_V1", + "IKE_CERT_PRE_V1", + "IKE_CERT_POST_V1", +); From 8db202f1b0d774e9f9b8d7d3047bb3bd282dbbb4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 15:22:39 +0100 Subject: [PATCH 312/534] Added a dedicated delete task for IKEv1 IKE_SAs --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/tasks/isakmp_delete.c | 147 +++++++++++++++++++++++++ src/libcharon/sa/tasks/isakmp_delete.h | 50 +++++++++ src/libcharon/sa/tasks/task.c | 1 + src/libcharon/sa/tasks/task.h | 2 + 5 files changed, 201 insertions(+) create mode 100755 src/libcharon/sa/tasks/isakmp_delete.c create mode 100644 src/libcharon/sa/tasks/isakmp_delete.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 19b55486e..4c5e62855 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -100,6 +100,7 @@ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ sa/tasks/ike_vendor_v1.c sa/tasks/ike_vendor_v1.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/informational.c sa/tasks/informational.h \ +sa/tasks/isakmp_delete.c sa/tasks/isakmp_delete.h \ sa/tasks/xauth.c sa/tasks/xauth.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ sa/tasks/mode_config.c sa/tasks/mode_config.h \ diff --git a/src/libcharon/sa/tasks/isakmp_delete.c b/src/libcharon/sa/tasks/isakmp_delete.c new file mode 100755 index 000000000..0640d13b1 --- /dev/null +++ b/src/libcharon/sa/tasks/isakmp_delete.c @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "isakmp_delete.h" + +#include +#include + +typedef struct private_isakmp_delete_t private_isakmp_delete_t; + +/** + * Private members of a isakmp_delete_t task. + */ +struct private_isakmp_delete_t { + + /** + * Public methods and task_t interface. + */ + isakmp_delete_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; +}; + +METHOD(task_t, build_i, status_t, + private_isakmp_delete_t *this, message_t *message) +{ + delete_payload_t *delete_payload; + ike_sa_id_t *id; + + DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + delete_payload = delete_payload_create(DELETE_V1, PROTO_IKE); + id = this->ike_sa->get_id(this->ike_sa); + delete_payload->set_ike_spi(delete_payload, id->get_initiator_spi(id), + id->get_responder_spi(id)); + message->add_payload(message, (payload_t*)delete_payload); + + DBG1(DBG_IKE, "sending DELETE for IKE_SA %s[%d]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_DELETING); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_isakmp_delete_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, process_r, status_t, + private_isakmp_delete_t *this, message_t *message) +{ + DBG1(DBG_IKE, "received DELETE for IKE_SA %s[%d]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa)); + DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_DELETING); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); + return DESTROY_ME; +} + +METHOD(task_t, build_r, status_t, + private_isakmp_delete_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_isakmp_delete_t *this) +{ + return TASK_ISAKMP_DELETE; +} + +METHOD(task_t, migrate, void, + private_isakmp_delete_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_isakmp_delete_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +isakmp_delete_t *isakmp_delete_create(ike_sa_t *ike_sa, bool initiator) +{ + private_isakmp_delete_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/tasks/isakmp_delete.h b/src/libcharon/sa/tasks/isakmp_delete.h new file mode 100644 index 000000000..49e49fab9 --- /dev/null +++ b/src/libcharon/sa/tasks/isakmp_delete.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup isakmp_delete isakmp_delete + * @{ @ingroup tasks + */ + +#ifndef ISAKMP_DELETE_H_ +#define ISAKMP_DELETE_H_ + +typedef struct isakmp_delete_t isakmp_delete_t; + +#include +#include +#include + +/** + * Task of type ISAKMP_DELETE, delete an IKEv1 IKE_SA. + */ +struct isakmp_delete_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new isakmp_delete task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if we initiate the delete + * @return isakmp_delete task to handle by the task_manager + */ +isakmp_delete_t *isakmp_delete_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** ISAKMP_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index 77c0af96a..72819d853 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -38,6 +38,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, "CHILD_REKEY", "MAIN_MODE", "INFORMATIONAL", + "ISAKMP_DELETE", "XAUTH", "MODE_CONFIG", "QUICK_MODE", diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 7fa99251f..8f43b3ff8 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -73,6 +73,8 @@ enum task_type_t { TASK_MAIN_MODE, /** IKEv1 informational exchange */ TASK_INFORMATIONAL, + /** IKEv1 delete using an informational */ + TASK_ISAKMP_DELETE, /** IKEv1 XAUTH authentication */ TASK_XAUTH, /** IKEv1 Mode Config */ From 5f23be840bd90c874ca14a8a036cf8de647edc68 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 15:27:12 +0100 Subject: [PATCH 313/534] Use the IKEv1 specific delete in IKEv1 SAs --- src/libcharon/sa/ike_sa.c | 14 +++++++++++--- src/libcharon/sa/task_manager_v1.c | 2 +- src/libcharon/sa/tasks/informational.c | 6 +++--- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 11e7b18d2..fa07f5876 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include #include @@ -1373,14 +1374,21 @@ METHOD(ike_sa_t, destroy_child_sa, status_t, METHOD(ike_sa_t, delete_, status_t, private_ike_sa_t *this) { - ike_delete_t *ike_delete; + task_t *task; switch (this->state) { case IKE_ESTABLISHED: case IKE_REKEYING: - ike_delete = ike_delete_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, &ike_delete->task); + if (this->version == IKEV1) + { + task = (task_t*)isakmp_delete_create(&this->public, TRUE); + } + else + { + task = (task_t*)ike_delete_create(&this->public, TRUE); + } + this->task_manager->queue_task(this->task_manager, task); return this->task_manager->initiate(this->task_manager); case IKE_CREATED: DBG1(DBG_IKE, "deleting unestablished IKE_SA"); diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index baf7bb437..bdb55a07e 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -334,7 +334,7 @@ METHOD(task_manager_t, initiate, status_t, exchange = INFORMATIONAL_V1; new_mid = TRUE; } - if (activate_task(this, TASK_IKE_DELETE)) + if (activate_task(this, TASK_ISAKMP_DELETE)) { exchange = INFORMATIONAL_V1; new_mid = TRUE; diff --git a/src/libcharon/sa/tasks/informational.c b/src/libcharon/sa/tasks/informational.c index c2c6aa5fa..5391dd32f 100644 --- a/src/libcharon/sa/tasks/informational.c +++ b/src/libcharon/sa/tasks/informational.c @@ -16,7 +16,7 @@ #include "informational.h" #include -#include +#include #include #include @@ -99,8 +99,8 @@ METHOD(task_t, process_r, status_t, delete = (delete_payload_t*)payload; if (delete->get_protocol_id(delete) == PROTO_IKE) { - this->del = (task_t*)ike_delete_create(this->ike_sa, - FALSE); + this->del = (task_t*)isakmp_delete_create(this->ike_sa, + FALSE); } else { From 0f5b6c6831e85d31fc75dece62fed3a14858a857 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 15:28:43 +0100 Subject: [PATCH 314/534] Removed IKEv1 specific code from ike_delete task --- src/libcharon/sa/tasks/ike_delete.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) mode change 100755 => 100644 src/libcharon/sa/tasks/ike_delete.c diff --git a/src/libcharon/sa/tasks/ike_delete.c b/src/libcharon/sa/tasks/ike_delete.c old mode 100755 new mode 100644 index 56d423117..29ac87258 --- a/src/libcharon/sa/tasks/ike_delete.c +++ b/src/libcharon/sa/tasks/ike_delete.c @@ -56,7 +56,6 @@ METHOD(task_t, build_i, status_t, private_ike_delete_t *this, message_t *message) { delete_payload_t *delete_payload; - ike_sa_id_t *id; DBG0(DBG_IKE, "deleting IKE_SA %s[%d] between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), @@ -66,17 +65,7 @@ METHOD(task_t, build_i, status_t, this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); - if (this->ike_sa->get_version(this->ike_sa) == IKEV1) - { - delete_payload = delete_payload_create(DELETE_V1, PROTO_IKE); - id = this->ike_sa->get_id(this->ike_sa); - delete_payload->set_ike_spi(delete_payload, id->get_initiator_spi(id), - id->get_responder_spi(id)); - } - else - { - delete_payload = delete_payload_create(DELETE, PROTO_IKE); - } + delete_payload = delete_payload_create(DELETE, PROTO_IKE); message->add_payload(message, (payload_t*)delete_payload); if (this->ike_sa->get_state(this->ike_sa) == IKE_REKEYING) @@ -125,15 +114,7 @@ METHOD(task_t, process_r, status_t, case IKE_ESTABLISHED: this->ike_sa->set_state(this->ike_sa, IKE_DELETING); this->ike_sa->reestablish(this->ike_sa); - if (this->ike_sa->get_version(this->ike_sa) == IKEV2) - { - return NEED_MORE; - } - else - { - /* Dont send message to other side */ - return DESTROY_ME; - } + return NEED_MORE; case IKE_REKEYING: this->rekeyed = TRUE; break; From 07095794a1ecee5b084c5b69f7d5a9fefd737c9e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 15:33:06 +0100 Subject: [PATCH 315/534] Close IKE_SA directly after sending the delete --- src/libcharon/sa/task_manager_v1.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index bdb55a07e..494fe84c3 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -462,11 +462,19 @@ METHOD(task_manager_t, initiate, status_t, this->initiating.packet->destroy(this->initiating.packet); this->initiating.packet = NULL; - /* close after sending an INFORMATIONAL error but not yet established */ - if (exchange == INFORMATIONAL_V1 && - this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING) + if (exchange == INFORMATIONAL_V1) { - return FAILED; + switch (this->ike_sa->get_state(this->ike_sa)) + { + case IKE_CONNECTING: + /* close after sending an INFORMATIONAL when unestablished */ + return FAILED; + case IKE_DELETING: + /* close after sending a DELETE */ + return DESTROY_ME; + default: + break; + } } return SUCCESS; } From 5f109385924f529a88951c0a6ae11f854bbddf1c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 16:33:39 +0100 Subject: [PATCH 316/534] Added a dedicated IKEv1 task to delete CHILD_SAs --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/tasks/quick_delete.c | 216 ++++++++++++++++++++++++++ src/libcharon/sa/tasks/quick_delete.h | 53 +++++++ src/libcharon/sa/tasks/task.c | 1 + src/libcharon/sa/tasks/task.h | 2 + 5 files changed, 273 insertions(+) create mode 100755 src/libcharon/sa/tasks/quick_delete.c create mode 100644 src/libcharon/sa/tasks/quick_delete.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 4c5e62855..94ada5ae9 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -103,6 +103,7 @@ sa/tasks/informational.c sa/tasks/informational.h \ sa/tasks/isakmp_delete.c sa/tasks/isakmp_delete.h \ sa/tasks/xauth.c sa/tasks/xauth.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ +sa/tasks/quick_delete.c sa/tasks/quick_delete.h \ sa/tasks/mode_config.c sa/tasks/mode_config.h \ sa/tasks/task.c sa/tasks/task.h diff --git a/src/libcharon/sa/tasks/quick_delete.c b/src/libcharon/sa/tasks/quick_delete.c new file mode 100755 index 000000000..61fa2ef1f --- /dev/null +++ b/src/libcharon/sa/tasks/quick_delete.c @@ -0,0 +1,216 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "quick_delete.h" + +#include +#include + +typedef struct private_quick_delete_t private_quick_delete_t; + +/** + * Private members of a quick_delete_t task. + */ +struct private_quick_delete_t { + + /** + * Public methods and task_t interface. + */ + quick_delete_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Protocol of CHILD_SA to delete + */ + protocol_id_t protocol; + + /** + * Inbound SPI of CHILD_SA to delete + */ + u_int32_t spi; +}; + +/** + * Delete the specified CHILD_SA, if found + */ +static bool delete_child(private_quick_delete_t *this, + protocol_id_t protocol, u_int32_t spi) +{ + u_int64_t bytes_in, bytes_out; + child_sa_t *child_sa; + + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE); + if (!child_sa) + { /* fallback and check for outbound SA */ + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE); + if (!child_sa) + { + return FALSE; + } + this->spi = spi = child_sa->get_spi(child_sa, TRUE); + } + + child_sa->set_state(child_sa, CHILD_DELETING); + + child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in); + child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out); + + DBG0(DBG_IKE, "closing CHILD_SA %s{%d} " + "with SPIs %.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, + ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + + charon->bus->child_updown(charon->bus, child_sa, FALSE); + + this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi); + + /* TODO-IKEv1: handle close action? */ + + return TRUE; +} + +METHOD(task_t, build_i, status_t, + private_quick_delete_t *this, message_t *message) +{ + if (delete_child(this, this->protocol, this->spi)) + { + delete_payload_t *delete_payload; + + DBG1(DBG_IKE, "sending DELETE for %N CHILD_SA with SPI %.8x", + protocol_id_names, this->protocol, ntohl(this->spi)); + + delete_payload = delete_payload_create(DELETE_V1, PROTO_ESP); + delete_payload->add_spi(delete_payload, this->spi); + message->add_payload(message, &delete_payload->payload_interface); + + return SUCCESS; + } + return FAILED; +} + +METHOD(task_t, process_i, status_t, + private_quick_delete_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, process_r, status_t, + private_quick_delete_t *this, message_t *message) +{ + enumerator_t *payloads, *spis; + payload_t *payload; + delete_payload_t *delete_payload; + protocol_id_t protocol; + u_int32_t spi; + + payloads = message->create_payload_enumerator(message); + while (payloads->enumerate(payloads, &payload)) + { + if (payload->get_type(payload) == DELETE_V1) + { + delete_payload = (delete_payload_t*)payload; + protocol = delete_payload->get_protocol_id(delete_payload); + if (protocol != PROTO_ESP && protocol != PROTO_AH) + { + continue; + } + spis = delete_payload->create_spi_enumerator(delete_payload); + while (spis->enumerate(spis, &spi)) + { + DBG1(DBG_IKE, "received DELETE for %N CHILD_SA with SPI %.8x", + protocol_id_names, protocol, ntohl(spi)); + if (!delete_child(this, protocol, spi)) + { + DBG1(DBG_IKE, "CHILD_SA not found, ignored"); + continue; + } + } + spis->destroy(spis); + } + } + payloads->destroy(payloads); + + return SUCCESS; +} + +METHOD(task_t, build_r, status_t, + private_quick_delete_t *this, message_t *message) +{ + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_quick_delete_t *this) +{ + return TASK_QUICK_DELETE; +} + +METHOD(task_t, migrate, void, + private_quick_delete_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; +} + +METHOD(task_t, destroy, void, + private_quick_delete_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, + u_int32_t spi) +{ + private_quick_delete_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .protocol = protocol, + .spi = spi, + ); + + if (protocol != PROTO_NONE) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + return &this->public; +} diff --git a/src/libcharon/sa/tasks/quick_delete.h b/src/libcharon/sa/tasks/quick_delete.h new file mode 100644 index 000000000..a0dbd0bc7 --- /dev/null +++ b/src/libcharon/sa/tasks/quick_delete.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup quick_delete quick_delete + * @{ @ingroup tasks + */ + +#ifndef QUICK_DELETE_H_ +#define QUICK_DELETE_H_ + +typedef struct quick_delete_t quick_delete_t; + +#include +#include +#include +#include + +/** + * Task of type QUICK_DELETE, delete an IKEv1 quick mode SA. + */ +struct quick_delete_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new quick_delete task. + * + * @param ike_sa IKE_SA this task works for + * @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder + * @param spi inbound SPI of CHILD_SA to delete + * @return quick_delete task to handle by the task_manager + */ +quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, + u_int32_t spi); + +#endif /** QUICK_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index 72819d853..5a7035287 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -42,6 +42,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, "XAUTH", "MODE_CONFIG", "QUICK_MODE", + "QUICK_DELETE", "VENDOR_V1", "IKE_NATD_V1", "IKE_CERT_PRE_V1", diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 8f43b3ff8..55c8b728c 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -81,6 +81,8 @@ enum task_type_t { TASK_MODE_CONFIG, /** IKEv1 quick mode */ TASK_QUICK_MODE, + /** IKEv1 delete of a quick mode SA */ + TASK_QUICK_DELETE, /** IKEv1 vendor ID payload handling */ TASK_VENDOR_V1, /** IKEv1 NAT detection */ From c459dae556f3d858dbde30a3b96924f747c8e6a8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 16:39:44 +0100 Subject: [PATCH 317/534] Use IKEv1 specific tasks to close Quick Mode SAs --- src/libcharon/sa/ike_sa.c | 14 +++++++++++--- src/libcharon/sa/task_manager_v1.c | 2 +- src/libcharon/sa/tasks/informational.c | 4 ++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index fa07f5876..7b4d16c70 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include #include @@ -1341,10 +1342,17 @@ METHOD(ike_sa_t, rekey_child_sa, status_t, METHOD(ike_sa_t, delete_child_sa, status_t, private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) { - child_delete_t *child_delete; + task_t *task; - child_delete = child_delete_create(&this->public, protocol, spi); - this->task_manager->queue_task(this->task_manager, &child_delete->task); + if (this->version == IKEV1) + { + task = (task_t*)quick_delete_create(&this->public, protocol, spi); + } + else + { + task = (task_t*)child_delete_create(&this->public, protocol, spi); + } + this->task_manager->queue_task(this->task_manager, task); return this->task_manager->initiate(this->task_manager); } diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 494fe84c3..2f905516d 100755 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -339,7 +339,7 @@ METHOD(task_manager_t, initiate, status_t, exchange = INFORMATIONAL_V1; new_mid = TRUE; } - if (activate_task(this, TASK_CHILD_DELETE)) + if (activate_task(this, TASK_QUICK_DELETE)) { exchange = INFORMATIONAL_V1; new_mid = TRUE; diff --git a/src/libcharon/sa/tasks/informational.c b/src/libcharon/sa/tasks/informational.c index 5391dd32f..f0ddad021 100644 --- a/src/libcharon/sa/tasks/informational.c +++ b/src/libcharon/sa/tasks/informational.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include typedef struct private_informational_t private_informational_t; @@ -104,7 +104,7 @@ METHOD(task_t, process_r, status_t, } else { - this->del = (task_t*)child_delete_create(this->ike_sa, + this->del = (task_t*)quick_delete_create(this->ike_sa, PROTO_NONE, 0); } } From 91ca35a2d225957e05f102a84c9d4bb41417e111 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 16:41:32 +0100 Subject: [PATCH 318/534] Removed IKEv1 specific code from child_delete task --- src/libcharon/sa/tasks/child_delete.c | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) mode change 100755 => 100644 src/libcharon/sa/tasks/child_delete.c diff --git a/src/libcharon/sa/tasks/child_delete.c b/src/libcharon/sa/tasks/child_delete.c old mode 100755 new mode 100644 index 455e06b7a..c5151abf1 --- a/src/libcharon/sa/tasks/child_delete.c +++ b/src/libcharon/sa/tasks/child_delete.c @@ -65,11 +65,6 @@ struct private_child_delete_t { * CHILD_SAs which get deleted */ linked_list_t *child_sas; - - /** - * CHILD_SAs which get deleted - */ - payload_type_t payload_type; }; /** @@ -92,7 +87,7 @@ static void build_payloads(private_child_delete_t *this, message_t *message) case PROTO_ESP: if (esp == NULL) { - esp = delete_payload_create(this->payload_type, PROTO_ESP); + esp = delete_payload_create(DELETE, PROTO_ESP); message->add_payload(message, (payload_t*)esp); } esp->add_spi(esp, spi); @@ -102,7 +97,7 @@ static void build_payloads(private_child_delete_t *this, message_t *message) case PROTO_AH: if (ah == NULL) { - ah = delete_payload_create(this->payload_type, PROTO_AH); + ah = delete_payload_create(DELETE, PROTO_AH); message->add_payload(message, (payload_t*)ah); } ah->add_spi(ah, spi); @@ -132,7 +127,7 @@ static void process_payloads(private_child_delete_t *this, message_t *message) payloads = message->create_payload_enumerator(message); while (payloads->enumerate(payloads, &payload)) { - if (payload->get_type(payload) == this->payload_type) + if (payload->get_type(payload) == DELETE) { delete_payload = (delete_payload_t*)payload; protocol = delete_payload->get_protocol_id(delete_payload); @@ -392,14 +387,5 @@ child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, this->public.task.process = _process_r; this->initiator = FALSE; } - - if (ike_sa->get_version(ike_sa) == IKEV2) - { - this->payload_type = DELETE; - } - else - { - this->payload_type = DELETE_V1; - } return &this->public; } From 3ba15819edb44d00f5c9f8ad06ea7e78a48515c4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 16:46:29 +0100 Subject: [PATCH 319/534] Remove executable flag from source code files --- src/libcharon/encoding/message.c | 0 src/libcharon/encoding/payloads/certreq_payload.c | 0 src/libcharon/encoding/payloads/certreq_payload.h | 0 src/libcharon/encoding/payloads/id_payload.c | 0 src/libcharon/encoding/payloads/notify_payload.c | 0 src/libcharon/encoding/payloads/notify_payload.h | 0 src/libcharon/encoding/payloads/payload.c | 0 src/libcharon/encoding/payloads/proposal_substructure.c | 0 src/libcharon/sa/ike_sa.h | 0 src/libcharon/sa/ike_sa_manager.c | 0 src/libcharon/sa/keymat_v1.c | 0 src/libcharon/sa/task_manager_v1.c | 0 src/libcharon/sa/tasks/ike_cert_post_v1.c | 0 src/libcharon/sa/tasks/ike_cert_pre_v1.c | 0 src/libcharon/sa/tasks/isakmp_delete.c | 0 src/libcharon/sa/tasks/main_mode.c | 0 src/libcharon/sa/tasks/quick_delete.c | 0 src/libcharon/sa/tasks/quick_mode.c | 0 src/libstrongswan/utils.h | 0 19 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 src/libcharon/encoding/message.c mode change 100755 => 100644 src/libcharon/encoding/payloads/certreq_payload.c mode change 100755 => 100644 src/libcharon/encoding/payloads/certreq_payload.h mode change 100755 => 100644 src/libcharon/encoding/payloads/id_payload.c mode change 100755 => 100644 src/libcharon/encoding/payloads/notify_payload.c mode change 100755 => 100644 src/libcharon/encoding/payloads/notify_payload.h mode change 100755 => 100644 src/libcharon/encoding/payloads/payload.c mode change 100755 => 100644 src/libcharon/encoding/payloads/proposal_substructure.c mode change 100755 => 100644 src/libcharon/sa/ike_sa.h mode change 100755 => 100644 src/libcharon/sa/ike_sa_manager.c mode change 100755 => 100644 src/libcharon/sa/keymat_v1.c mode change 100755 => 100644 src/libcharon/sa/task_manager_v1.c mode change 100755 => 100644 src/libcharon/sa/tasks/ike_cert_post_v1.c mode change 100755 => 100644 src/libcharon/sa/tasks/ike_cert_pre_v1.c mode change 100755 => 100644 src/libcharon/sa/tasks/isakmp_delete.c mode change 100755 => 100644 src/libcharon/sa/tasks/main_mode.c mode change 100755 => 100644 src/libcharon/sa/tasks/quick_delete.c mode change 100755 => 100644 src/libcharon/sa/tasks/quick_mode.c mode change 100755 => 100644 src/libstrongswan/utils.h diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c old mode 100755 new mode 100644 diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c old mode 100755 new mode 100644 diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h old mode 100755 new mode 100644 diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c old mode 100755 new mode 100644 diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c old mode 100755 new mode 100644 diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h old mode 100755 new mode 100644 diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c old mode 100755 new mode 100644 diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/keymat_v1.c old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/tasks/ike_cert_post_v1.c b/src/libcharon/sa/tasks/ike_cert_post_v1.c old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/tasks/ike_cert_pre_v1.c b/src/libcharon/sa/tasks/ike_cert_pre_v1.c old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/tasks/isakmp_delete.c b/src/libcharon/sa/tasks/isakmp_delete.c old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/tasks/quick_delete.c b/src/libcharon/sa/tasks/quick_delete.c old mode 100755 new mode 100644 diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c old mode 100755 new mode 100644 diff --git a/src/libstrongswan/utils.h b/src/libstrongswan/utils.h old mode 100755 new mode 100644 From 7b1e15ac4e45ce4d6989f7be859f7337fa4a44ca Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 17:34:57 +0100 Subject: [PATCH 320/534] Fixed IKEv1 prf+ keymat expansion beyond 320 bits --- src/libstrongswan/crypto/prf_plus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/crypto/prf_plus.c b/src/libstrongswan/crypto/prf_plus.c index 29f61197d..0f06ede83 100644 --- a/src/libstrongswan/crypto/prf_plus.c +++ b/src/libstrongswan/crypto/prf_plus.c @@ -72,12 +72,12 @@ METHOD(prf_plus_t, get_bytes, void, this->prf->get_bytes(this->prf, this->seed, NULL); this->prf->get_bytes(this->prf, chunk_from_thing(this->counter), this->buffer.ptr); + this->counter++; } else { this->prf->get_bytes(this->prf, this->seed, this->buffer.ptr); } - this->counter++; this->used = 0; } round = min(length, this->buffer.len - this->used); From 00d88232428c1b9eb06ef7abee030b7bd6abddb2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 14 Dec 2011 19:45:30 +0100 Subject: [PATCH 321/534] Show auth method of config we are looking for in main mode --- src/libcharon/sa/tasks/main_mode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index f60bda768..f2b16b1fd 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -346,7 +346,8 @@ static peer_cfg_t *select_config(private_main_mode_t *this, identification_t *id me = this->ike_sa->get_my_host(this->ike_sa); other = this->ike_sa->get_other_host(this->ike_sa); - DBG1(DBG_CFG, "looking for peer configs matching %H...%H[%Y]", me, other, id); + DBG1(DBG_CFG, "looking for %N peer configs matching %H...%H[%Y]", + auth_method_names, this->auth_method, me, other, id); enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, me, other, NULL, id); while (enumerator->enumerate(enumerator, ¤t)) From 4ac137135a53b9b924a55a261886d28cb2577b05 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 10:01:35 +0100 Subject: [PATCH 322/534] Fixed return value if SIG payload missing --- src/libcharon/sa/authenticators/pubkey_v1_authenticator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c index a947349c9..7da1953af 100644 --- a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c +++ b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c @@ -137,7 +137,7 @@ METHOD(authenticator_t, process, status_t, if (!sig_payload) { DBG1(DBG_IKE, "SIG payload missing in message"); - return FALSE; + return FAILED; } id = this->ike_sa->get_other_id(this->ike_sa); From b24b73b7f33483185a514fe1ebd049369e55e44b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 11:01:06 +0100 Subject: [PATCH 323/534] Flush auth configs, if enabled, for both IKEv1 and IKEv2 --- src/libcharon/sa/ike_sa.c | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 7b4d16c70..223901cad 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -257,6 +257,11 @@ struct private_ike_sa_t { * remote host address to be used for IKE, set via MIGRATE kernel message */ host_t *remote_host; + + /** + * Flush auth configs once established? + */ + bool flush_auth_cfg; }; /** @@ -420,6 +425,9 @@ static void flush_auth_cfgs(private_ike_sa_t *this) { auth_cfg_t *cfg; + this->my_auth->purge(this->my_auth, FALSE); + this->other_auth->purge(this->other_auth, FALSE); + while (this->my_auths->remove_last(this->my_auths, (void**)&cfg) == SUCCESS) { @@ -1203,16 +1211,16 @@ METHOD(ike_sa_t, process_message, status_t, private_ike_sa_t *this, message_t *message) { status_t status; + if (this->state == IKE_PASSIVE) { /* do not handle messages in passive state */ return FAILED; } status = this->task_manager->process_message(this->task_manager, message); - if (message->get_exchange_type(message) == IKE_AUTH && - this->state == IKE_ESTABLISHED && - lib->settings->get_bool(lib->settings, - "charon.flush_auth_cfg", FALSE)) - { /* authentication completed */ + if (this->flush_auth_cfg && this->state == IKE_ESTABLISHED) + { + /* authentication completed */ + this->flush_auth_cfg = FALSE; flush_auth_cfgs(this); } return status; @@ -2137,6 +2145,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, .attributes = linked_list_create(), .keepalive_interval = lib->settings->get_time(lib->settings, "charon.keep_alive", KEEPALIVE_INTERVAL), + .flush_auth_cfg = lib->settings->get_bool(lib->settings, + "charon.flush_auth_cfg", FALSE), ); this->task_manager = task_manager_create(&this->public); From ac3bc42e639ad70fe650257b3926b57e08b0f696 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 11:01:35 +0100 Subject: [PATCH 324/534] Save authentication info collected during main mode authentication --- src/libcharon/sa/tasks/main_mode.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index f2b16b1fd..89f63b789 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -332,7 +332,28 @@ static auth_method_t get_auth_method(private_main_mode_t *this, { return AUTH_HYBRID_INIT_RSA; } - return AUTH_NONE;; + return AUTH_NONE; +} + +/** + * Save authentication information after authentication succeeded + */ +static void save_auth_cfg(private_main_mode_t *this, bool local) +{ + auth_cfg_t *auth; + bool initiator; + + initiator = local == this->initiator; + if ((initiator && this->auth_method == AUTH_HYBRID_INIT_RSA) || + (!initiator && this->auth_method == AUTH_HYBRID_RESP_RSA)) + { /* peer not authenticated in main mode with hybrid methods */ + return; + } + auth = auth_cfg_create(); + /* for local config, we _copy_ entires from the config, as it contains + * certificates we must send later. */ + auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), local); + this->ike_sa->add_auth_cfg(this->ike_sa, local, auth); } /** @@ -560,6 +581,7 @@ METHOD(task_t, build_i, status_t, return FAILED; } authenticator->destroy(authenticator); + save_auth_cfg(this, TRUE); this->state = MM_AUTH; return NEED_MORE; @@ -678,6 +700,7 @@ METHOD(task_t, process_r, status_t, return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); } authenticator->destroy(authenticator); + save_auth_cfg(this, FALSE); this->state = MM_AUTH; if (has_notify_errors(this, message)) @@ -877,6 +900,7 @@ METHOD(task_t, build_r, status_t, return FAILED; } authenticator->destroy(authenticator); + save_auth_cfg(this, TRUE); if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) { @@ -994,6 +1018,7 @@ METHOD(task_t, process_i, status_t, return FAILED; } authenticator->destroy(authenticator); + save_auth_cfg(this, FALSE); switch (this->auth_method) { From fd2a491b31c505c4ab4cb6e9d2f36c6407fbe03d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 11:30:22 +0100 Subject: [PATCH 325/534] Stop checking once a key size constraint is not fulfilled --- src/libstrongswan/credentials/auth_cfg.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index 3420e3157..e2cea0741 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -537,6 +537,7 @@ METHOD(auth_cfg_t, complies, bool, "public keys, but %d bit key used", (uintptr_t)value, strength); } + break; } } else if (t2 == AUTH_RULE_RSA_STRENGTH) @@ -547,6 +548,7 @@ METHOD(auth_cfg_t, complies, bool, DBG1(DBG_CFG, "constraint requires %d bit ECDSA, " "but RSA used", (uintptr_t)value); } + break; } else if (t2 == AUTH_RULE_ECDSA_STRENGTH) { @@ -556,6 +558,7 @@ METHOD(auth_cfg_t, complies, bool, DBG1(DBG_CFG, "constraint requires %d bit RSA, " "but ECDSA used", (uintptr_t)value); } + break; } } e2->destroy(e2); From bdadc5aee2b64f8e9a795151fd0a43c16c8a4bda Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 11:31:02 +0100 Subject: [PATCH 326/534] Check authorization constraints after main mode completed --- src/libcharon/sa/tasks/main_mode.c | 53 +++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 89f63b789..42290d427 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -335,18 +335,53 @@ static auth_method_t get_auth_method(private_main_mode_t *this, return AUTH_NONE; } +/** + * Check if a peer skipped authentication by using Hybrid authentication + */ +static bool skipped_auth(private_main_mode_t *this, bool local) +{ + bool initiator; + + initiator = local == this->initiator; + if (initiator && this->auth_method == AUTH_HYBRID_INIT_RSA) + { + return TRUE; + } + if (!initiator && this->auth_method == AUTH_HYBRID_RESP_RSA) + { + return TRUE; + } + return FALSE; +} + +/** + * Check if remote authentication constraints fulfilled + */ +static bool check_constraints(private_main_mode_t *this) +{ + identification_t *id; + auth_cfg_t *auth; + + if (skipped_auth(this, FALSE)) + { + return TRUE; + } + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + /* auth identity to comply */ + id = this->ike_sa->get_other_id(this->ike_sa); + auth->add(auth, AUTH_RULE_IDENTITY, id->clone(id)); + return auth->complies(auth, this->other_auth, TRUE); +} + /** * Save authentication information after authentication succeeded */ static void save_auth_cfg(private_main_mode_t *this, bool local) { auth_cfg_t *auth; - bool initiator; - initiator = local == this->initiator; - if ((initiator && this->auth_method == AUTH_HYBRID_INIT_RSA) || - (!initiator && this->auth_method == AUTH_HYBRID_RESP_RSA)) - { /* peer not authenticated in main mode with hybrid methods */ + if (skipped_auth(this, local)) + { return; } auth = auth_cfg_create(); @@ -700,6 +735,10 @@ METHOD(task_t, process_r, status_t, return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); } authenticator->destroy(authenticator); + if (!check_constraints(this)) + { + return FAILED; + } save_auth_cfg(this, FALSE); this->state = MM_AUTH; @@ -1018,6 +1057,10 @@ METHOD(task_t, process_i, status_t, return FAILED; } authenticator->destroy(authenticator); + if (!check_constraints(this)) + { + return FAILED; + } save_auth_cfg(this, FALSE); switch (this->auth_method) From f5e5c5edbd029e146bd25ceae052ca915bc68b5b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 11:58:26 +0100 Subject: [PATCH 327/534] Added an XAUTH identity to use or require for XAuth authentication --- src/libstrongswan/credentials/auth_cfg.c | 9 +++++++++ src/libstrongswan/credentials/auth_cfg.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/libstrongswan/credentials/auth_cfg.c b/src/libstrongswan/credentials/auth_cfg.c index e2cea0741..0646b0e2c 100644 --- a/src/libstrongswan/credentials/auth_cfg.c +++ b/src/libstrongswan/credentials/auth_cfg.c @@ -39,6 +39,7 @@ ENUM(auth_rule_names, AUTH_RULE_IDENTITY, AUTH_HELPER_REVOCATION_CERT, "RULE_EAP_TYPE", "RULE_EAP_VENDOR", "RULE_XAUTH_BACKEND", + "RULE_XAUTH_IDENTITY", "RULE_CA_CERT", "RULE_IM_CERT", "RULE_SUBJECT_CERT", @@ -144,6 +145,7 @@ static void destroy_entry_value(entry_t *entry) case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_GROUP: + case AUTH_RULE_XAUTH_IDENTITY: { identification_t *id = (identification_t*)entry->value; id->destroy(id); @@ -209,6 +211,7 @@ static void replace(private_auth_cfg_t *this, entry_enumerator_t *enumerator, case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_XAUTH_BACKEND: + case AUTH_RULE_XAUTH_IDENTITY: case AUTH_RULE_GROUP: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: @@ -278,6 +281,7 @@ METHOD(auth_cfg_t, get, void*, case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_XAUTH_BACKEND: + case AUTH_RULE_XAUTH_IDENTITY: case AUTH_RULE_GROUP: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: @@ -319,6 +323,7 @@ static void add(private_auth_cfg_t *this, auth_rule_t type, ...) case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_XAUTH_BACKEND: + case AUTH_RULE_XAUTH_IDENTITY: case AUTH_RULE_GROUP: case AUTH_RULE_CA_CERT: case AUTH_RULE_IM_CERT: @@ -440,6 +445,7 @@ METHOD(auth_cfg_t, complies, bool, case AUTH_RULE_IDENTITY: case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: + case AUTH_RULE_XAUTH_IDENTITY: { identification_t *id1, *id2; @@ -661,6 +667,7 @@ static void merge(private_auth_cfg_t *this, private_auth_cfg_t *other, bool copy case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_GROUP: + case AUTH_RULE_XAUTH_IDENTITY: { identification_t *id = (identification_t*)value; @@ -754,6 +761,7 @@ static bool equals(private_auth_cfg_t *this, private_auth_cfg_t *other) case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_GROUP: + case AUTH_RULE_XAUTH_IDENTITY: { identification_t *id1, *id2; @@ -837,6 +845,7 @@ METHOD(auth_cfg_t, clone_, auth_cfg_t*, case AUTH_RULE_EAP_IDENTITY: case AUTH_RULE_AAA_IDENTITY: case AUTH_RULE_GROUP: + case AUTH_RULE_XAUTH_IDENTITY: { identification_t *id = (identification_t*)entry->value; clone->add(clone, entry->type, id->clone(id)); diff --git a/src/libstrongswan/credentials/auth_cfg.h b/src/libstrongswan/credentials/auth_cfg.h index 3e0fc7376..fbc4b6eda 100644 --- a/src/libstrongswan/credentials/auth_cfg.h +++ b/src/libstrongswan/credentials/auth_cfg.h @@ -80,6 +80,8 @@ enum auth_rule_t { AUTH_RULE_EAP_VENDOR, /** XAUTH backend name to use, char* */ AUTH_RULE_XAUTH_BACKEND, + /** XAuth identity to use or require, identification_t* */ + AUTH_RULE_XAUTH_IDENTITY, /** certificate authority, certificate_t* */ AUTH_RULE_CA_CERT, /** intermediate certificate in trustchain, certificate_t* */ From 10a6a5acff4a1237be0d33e9a483585e01c5e652 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 12:28:43 +0100 Subject: [PATCH 328/534] Store Main Mode identity even if XAuth-only is used for authentication --- src/libcharon/sa/tasks/main_mode.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 42290d427..0582c33d5 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -362,14 +362,14 @@ static bool check_constraints(private_main_mode_t *this) identification_t *id; auth_cfg_t *auth; - if (skipped_auth(this, FALSE)) - { - return TRUE; - } auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); /* auth identity to comply */ id = this->ike_sa->get_other_id(this->ike_sa); auth->add(auth, AUTH_RULE_IDENTITY, id->clone(id)); + if (skipped_auth(this, FALSE)) + { + return TRUE; + } return auth->complies(auth, this->other_auth, TRUE); } From 21a4fc832ea64a6abb194a14ee64ff42ca214a44 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 13:12:42 +0100 Subject: [PATCH 329/534] Pass ipsec.conf xauth_identity option via stroke to charon configurations --- src/libcharon/plugins/stroke/stroke_config.c | 5 +++++ src/libcharon/plugins/stroke/stroke_socket.c | 2 ++ src/starter/starterstroke.c | 1 + src/stroke/stroke_msg.h | 1 + 4 files changed, 9 insertions(+) diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index fec28c1ef..c4b218d1b 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -479,6 +479,11 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, cfg->add(cfg, AUTH_RULE_XAUTH_BACKEND, strdup(++pos)); } cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_XAUTH); + if (msg->add_conn.xauth_identity) + { + cfg->add(cfg, AUTH_RULE_XAUTH_IDENTITY, + identification_create_from_string(msg->add_conn.xauth_identity)); + } } else if (strneq(auth, "eap", 3)) { diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 0f7a6040f..7a14be0cf 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -181,12 +181,14 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) pop_end(msg, "right", &msg->add_conn.other); pop_string(msg, &msg->add_conn.eap_identity); pop_string(msg, &msg->add_conn.aaa_identity); + pop_string(msg, &msg->add_conn.xauth_identity); pop_string(msg, &msg->add_conn.algorithms.ike); pop_string(msg, &msg->add_conn.algorithms.esp); pop_string(msg, &msg->add_conn.ikeme.mediated_by); pop_string(msg, &msg->add_conn.ikeme.peerid); DBG2(DBG_CFG, " eap_identity=%s", msg->add_conn.eap_identity); DBG2(DBG_CFG, " aaa_identity=%s", msg->add_conn.aaa_identity); + DBG2(DBG_CFG, " xauth_identity=%s", msg->add_conn.xauth_identity); DBG2(DBG_CFG, " ike=%s", msg->add_conn.algorithms.ike); DBG2(DBG_CFG, " esp=%s", msg->add_conn.algorithms.esp); DBG2(DBG_CFG, " dpddelay=%d", msg->add_conn.dpd.delay); diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index e399b1c04..628d63214 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -220,6 +220,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) msg.add_conn.eap_vendor = conn->eap_vendor; msg.add_conn.eap_identity = push_string(&msg, conn->eap_identity); msg.add_conn.aaa_identity = push_string(&msg, conn->aaa_identity); + msg.add_conn.xauth_identity = push_string(&msg, conn->xauth_identity); if (conn->policy & POLICY_TUNNEL) { diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index f3c525ba7..3350d7603 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -246,6 +246,7 @@ struct stroke_msg_t { u_int32_t eap_vendor; char *eap_identity; char *aaa_identity; + char *xauth_identity; int mode; int mobike; int force_encap; From 5f6a37eb9b439751f7e0825a740cc32e500061f2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 13:13:30 +0100 Subject: [PATCH 330/534] Be a little more verbose about XAuth configs in ipsec statusall --- src/libcharon/plugins/stroke/stroke_list.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index 2246e748d..d2fda1b3c 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -319,11 +319,7 @@ static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local) auth->get(auth, AUTH_RULE_IDENTITY)); auth_class = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); - if (auth_class != AUTH_CLASS_EAP) - { - fprintf(out, "%N authentication\n", auth_class_names, auth_class); - } - else + if (auth_class == AUTH_CLASS_EAP) { if ((uintptr_t)auth->get(auth, AUTH_RULE_EAP_TYPE) == EAP_NAK) { @@ -350,6 +346,21 @@ static void log_auth_cfgs(FILE *out, peer_cfg_t *peer_cfg, bool local) } fprintf(out, "\n"); } + else if (auth_class == AUTH_CLASS_XAUTH) + { + fprintf(out, "%N authentication: %s", auth_class_names, auth_class, + auth->get(auth, AUTH_RULE_XAUTH_BACKEND) ?: "any"); + id = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY); + if (id) + { + fprintf(out, " with XAuth identity '%Y'", id); + } + fprintf(out, "\n"); + } + else + { + fprintf(out, "%N authentication\n", auth_class_names, auth_class); + } cert = auth->get(auth, AUTH_RULE_CA_CERT); if (cert) From 7a7efbf9d88346609ee4c246936e4fa2a6c72723 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 13:14:33 +0100 Subject: [PATCH 331/534] Added an identity getter to XAuth methods to query the actually used identity --- .../plugins/xauth_generic/xauth_generic.c | 28 +++++++++++-------- .../sa/authenticators/xauth/xauth_method.h | 7 +++++ 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.c b/src/libcharon/plugins/xauth_generic/xauth_generic.c index 981ab77d0..6350a130f 100644 --- a/src/libcharon/plugins/xauth_generic/xauth_generic.c +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.c @@ -98,7 +98,7 @@ METHOD(xauth_method_t, process_server, status_t, configuration_attribute_t *attr; enumerator_t *enumerator; shared_key_t *shared; - identification_t *id = NULL, *peer; + identification_t *id; chunk_t user = chunk_empty, pass = chunk_empty; status_t status = SUCCESS; @@ -132,31 +132,33 @@ METHOD(xauth_method_t, process_server, status_t, DBG1(DBG_IKE, "failed to parse provided XAuth username"); return FAILED; } + this->peer->destroy(this->peer); + this->peer = id; } - peer = id ?: this->peer; - shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, this->server, - peer); + shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, + this->server, this->peer); if (!shared) { - DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'", this->server, - peer); + DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'", + this->server, this->peer); status = FAILED; } else if (!chunk_equals(shared->get_key(shared), pass)) { - DBG1(DBG_IKE, "failed to authenticate '%Y' with XAuth", peer); + DBG1(DBG_IKE, "failed to authenticate '%Y' with XAuth", this->peer); status = FAILED; } - else - { - DBG2(DBG_IKE, "authentication of '%Y' with XAuth successful", peer); - } DESTROY_IF(shared); - DESTROY_IF(id); return status; } +METHOD(xauth_method_t, get_identity, identification_t*, + private_xauth_generic_t *this) +{ + return this->peer; +} + METHOD(xauth_method_t, destroy, void, private_xauth_generic_t *this) { @@ -178,6 +180,7 @@ xauth_generic_t *xauth_generic_create_peer(identification_t *server, .xauth_method = { .initiate = _initiate_peer, .process = _process_peer, + .get_identity = _get_identity, .destroy = _destroy, }, }, @@ -201,6 +204,7 @@ xauth_generic_t *xauth_generic_create_server(identification_t *server, .xauth_method = { .initiate = _initiate_server, .process = _process_server, + .get_identity = _get_identity, .destroy = _destroy, }, }, diff --git a/src/libcharon/sa/authenticators/xauth/xauth_method.h b/src/libcharon/sa/authenticators/xauth/xauth_method.h index c544724b8..9f6067dbf 100644 --- a/src/libcharon/sa/authenticators/xauth/xauth_method.h +++ b/src/libcharon/sa/authenticators/xauth/xauth_method.h @@ -80,6 +80,13 @@ struct xauth_method_t { status_t (*process) (xauth_method_t *this, cp_payload_t *in, cp_payload_t **out); + /** + * Get the XAuth username received as XAuth initiator. + * + * @return used XAuth username, pointer to internal data + */ + identification_t* (*get_identity)(xauth_method_t *this); + /** * Destroys a eap_method_t object. */ From daf7e6bc3619a2572fa61b4871d853a6c6cf9482 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 13:15:34 +0100 Subject: [PATCH 332/534] Use (as client) and verify (as server) configured XAuth identities --- src/libcharon/sa/tasks/xauth.c | 59 ++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/src/libcharon/sa/tasks/xauth.c b/src/libcharon/sa/tasks/xauth.c index 58e127aa9..b4d690094 100644 --- a/src/libcharon/sa/tasks/xauth.c +++ b/src/libcharon/sa/tasks/xauth.c @@ -54,6 +54,11 @@ struct private_xauth_t { */ xauth_method_t *xauth; + /** + * XAuth username + */ + identification_t *user; + /** * Generated configuration payload */ @@ -68,7 +73,7 @@ struct private_xauth_t { /** * Load XAuth backend */ -static xauth_method_t *load_method(ike_sa_t *ike_sa, bool initiator) +static xauth_method_t *load_method(private_xauth_t* this) { identification_t *server, *peer; enumerator_t *enumerator; @@ -78,20 +83,20 @@ static xauth_method_t *load_method(ike_sa_t *ike_sa, bool initiator) auth_cfg_t *auth; char *name; - if (initiator) + if (this->initiator) { - server = ike_sa->get_my_id(ike_sa); - peer = ike_sa->get_other_id(ike_sa); + server = this->ike_sa->get_my_id(this->ike_sa); + peer = this->ike_sa->get_other_id(this->ike_sa); role = XAUTH_SERVER; } else { - peer = ike_sa->get_my_id(ike_sa); - server = ike_sa->get_other_id(ike_sa); + peer = this->ike_sa->get_my_id(this->ike_sa); + server = this->ike_sa->get_other_id(this->ike_sa); role = XAUTH_PEER; } - peer_cfg = ike_sa->get_peer_cfg(ike_sa); - enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !initiator); + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, !this->initiator); if (!enumerator->enumerate(enumerator, &auth) || (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS) != AUTH_CLASS_XAUTH) { @@ -104,8 +109,12 @@ static xauth_method_t *load_method(ike_sa_t *ike_sa, bool initiator) } } name = auth->get(auth, AUTH_RULE_XAUTH_BACKEND); + this->user = auth->get(auth, AUTH_RULE_XAUTH_IDENTITY); + if (!this->initiator && this->user) + { /* use XAUTH username, if configured */ + peer = this->user; + } enumerator->destroy(enumerator); - xauth = charon->xauth->create_instance(charon->xauth, name, role, server, peer); if (!xauth) @@ -160,7 +169,7 @@ METHOD(task_t, build_i, status_t, { cp_payload_t *cp; - this->xauth = load_method(this->ike_sa, this->initiator); + this->xauth = load_method(this); if (!this->xauth) { return FAILED; @@ -209,7 +218,7 @@ METHOD(task_t, process_r, status_t, if (!this->xauth) { - this->xauth = load_method(this->ike_sa, this->initiator); + this->xauth = load_method(this); if (!this->xauth) { /* send empty reply */ return NEED_MORE; @@ -228,12 +237,8 @@ METHOD(task_t, process_r, status_t, case NEED_MORE: return NEED_MORE; case SUCCESS: - DBG1(DBG_IKE, "XAuth authentication successful"); - establish(this); - break; case FAILED: default: - DBG1(DBG_IKE, "XAuth authentication failed"); break; } this->cp = NULL; @@ -253,6 +258,17 @@ METHOD(task_t, process_r, status_t, } } enumerator->destroy(enumerator); + if (this->status == XAUTH_OK) + { + DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful", + this->xauth->get_identity(this->xauth)); + establish(this); + } + else + { + DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) failed", + this->xauth->get_identity(this->xauth)); + } } this->public.task.build = _build_r_ack; return NEED_MORE; @@ -293,6 +309,7 @@ METHOD(task_t, process_i_status, status_t, METHOD(task_t, process_i, status_t, private_xauth_t *this, message_t *message) { + identification_t *id; cp_payload_t *cp; cp = (cp_payload_t*)message->get_payload(message, CONFIGURATION_V1); @@ -306,11 +323,19 @@ METHOD(task_t, process_i, status_t, case NEED_MORE: return NEED_MORE; case SUCCESS: - DBG1(DBG_IKE, "XAuth authentication successful"); + id = this->xauth->get_identity(this->xauth); + if (this->user && !id->matches(id, this->user)) + { + DBG1(DBG_IKE, "XAuth username '%Y' does not match to " + "configured username '%Y'", id, this->user); + break; + } + DBG1(DBG_IKE, "XAuth authentication of '%Y' successful", id); this->status = XAUTH_OK; break; case FAILED: - DBG1(DBG_IKE, "XAuth authentication failed"); + DBG1(DBG_IKE, "XAuth authentication of '%Y' failed", + this->xauth->get_identity(this->xauth)); break; default: return FAILED; From a4cc07136481f1ce9960d7d366b942f40ae5b451 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 16:23:47 +0100 Subject: [PATCH 333/534] Do not trust unprotected INFORMATIONALS, just print that we got one --- src/libcharon/encoding/message.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 1296475d5..1c6e6943c 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1983,25 +1983,30 @@ METHOD(message_t, parse_body, status_t, { hash_payload_t *hash_payload; chunk_t other_hash; - if ((this->first_payload != HASH_V1) && (this->public.get_exchange_type(&this->public) != INFORMATIONAL_V1)) + if (this->first_payload != HASH_V1) { - DBG1(DBG_ENC, "expected HASH payload as first payload"); + if (this->exchange_type == INFORMATIONAL_V1) + { /* TODO-IKEv1: Parse and log contents? */ + DBG1(DBG_ENC, "ignoring unprotected INFORMATIONAL from %H", + this->packet->get_source(this->packet)); + } + else + { + DBG1(DBG_ENC, "expected HASH payload as first payload"); + } chunk_free(&hash); return VERIFY_ERROR; } - if (this->first_payload == HASH_V1) + hash_payload = (hash_payload_t*)get_payload(this, HASH_V1); + other_hash = hash_payload->get_hash(hash_payload); + if (!chunk_equals(hash, other_hash)) { - hash_payload = (hash_payload_t*)get_payload(this, HASH_V1); - other_hash = hash_payload->get_hash(hash_payload); - if (!chunk_equals(hash, other_hash)) - { - DBG1(DBG_ENC, "our hash does not match received %B", - &other_hash); - chunk_free(&hash); - return FAILED; - } - DBG2(DBG_ENC, "verified IKEv1 message with hash %B", &hash); + DBG1(DBG_ENC, "our hash does not match received %B", + &other_hash); + chunk_free(&hash); + return FAILED; } + DBG2(DBG_ENC, "verified IKEv1 message with hash %B", &hash); chunk_free(&hash); } } From ca2606574566beca1c0905c7c8fcb8d7d2cde442 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 17:04:29 +0100 Subject: [PATCH 334/534] Add some additional IKEv1 notify types --- .../encoding/payloads/notify_payload.c | 20 +++++++++++++------ .../encoding/payloads/notify_payload.h | 7 +++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index 6b6c28de1..c3d1deb20 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -38,10 +38,14 @@ ENUM_NEXT(notify_type_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVALID_SPI"); ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, "NO_PROPOSAL_CHOSEN"); -ENUM_NEXT(notify_type_names, PAYLOAD_MALFORMED, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, +ENUM_NEXT(notify_type_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN, "PAYLOAD_MALFORMED", - "INVALID_KE_PAYLOAD"); -ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, + "INVALID_KE_PAYLOAD" + "INVALID_ID_INFORMATION", + "INVALID_CERT_ENCODING", + "INVALID_CERTIFICATE", + "CERT_TYPE_UNSUPPORTED", + "INVALID_CERT_AUTHORITY", "AUTHENTICATION_FAILED"); ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED, "SINGLE_PAIR_REQUIRED", @@ -128,10 +132,14 @@ ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVAL_SPI"); ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, "NO_PROP"); -ENUM_NEXT(notify_type_short_names, PAYLOAD_MALFORMED, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, +ENUM_NEXT(notify_type_short_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN, "PLD_MAL", - "INVAL_KE"); -ENUM_NEXT(notify_type_short_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, + "INVAL_KE", + "INVAL_ID", + "INVAL_CERTEN", + "INVAL_CERT", + "CERT_UNSUP", + "INVAL_CA", "AUTH_FAILED"); ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED, "SINGLE_PAIR", diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index 2f5294ee3..214a6b795 100644 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -51,7 +51,14 @@ enum notify_type_t { /* IKEv1 only */ PAYLOAD_MALFORMED = 16, INVALID_KE_PAYLOAD = 17, + /* IKEv1 alias */ + INVALID_KEY_INFORMATION = 17, /* IKEv1 only */ + INVALID_ID_INFORMATION = 18, + INVALID_CERT_ENCODING = 19, + INVALID_CERTIFICATE = 20, + CERT_TYPE_UNSUPPORTED = 21, + INVALID_CERT_AUTHORITY = 22, INVALID_HASH_INFORMATION = 23, AUTHENTICATION_FAILED = 24, SINGLE_PAIR_REQUIRED = 34, From 5762c0efebc31b88ae2e50a3fc7def71be7b3363 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 17:04:45 +0100 Subject: [PATCH 335/534] Send notifies in all error cases of Main Mode --- src/libcharon/sa/tasks/main_mode.c | 63 ++++++++++++++---------------- 1 file changed, 30 insertions(+), 33 deletions(-) diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 0582c33d5..525484f6f 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -474,8 +474,7 @@ static bool has_notify_errors(private_main_mode_t *this, message_t *message) /** * Queue a task sending a notify in an INFORMATIONAL exchange */ -static status_t send_notify(private_main_mode_t *this, - notify_type_t type, chunk_t data) +static status_t send_notify(private_main_mode_t *this, notify_type_t type) { notify_payload_t *notify; ike_sa_id_t *ike_sa_id; @@ -484,7 +483,6 @@ static status_t send_notify(private_main_mode_t *this, notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, PROTO_IKE, type); - notify->set_notification_data(notify, data); ike_sa_id = this->ike_sa->get_id(this->ike_sa); spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); spi_r = ike_sa_id->get_responder_spi(ike_sa_id); @@ -568,24 +566,24 @@ METHOD(task_t, build_i, status_t, if (!this->keymat->create_hasher(this->keymat, this->proposal)) { - return FAILED; + return send_notify(this, NO_PROPOSAL_CHOSEN); } if (!this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) { DBG1(DBG_IKE, "DH group selection failed"); - return FAILED; + return send_notify(this, NO_PROPOSAL_CHOSEN); } this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, group); if (!this->dh) { DBG1(DBG_IKE, "negotiated DH group not supported"); - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } if (!add_nonce_ke(this, &this->nonce_i, message)) { - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } this->state = MM_KE; return NEED_MORE; @@ -600,7 +598,7 @@ METHOD(task_t, build_i, status_t, if (!id) { DBG1(DBG_CFG, "own identity not known"); - return FAILED; + return send_notify(this, INVALID_ID_INFORMATION); } this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); @@ -613,7 +611,7 @@ METHOD(task_t, build_i, status_t, message) != SUCCESS) { DESTROY_IF(authenticator); - return FAILED; + return send_notify(this, AUTHENTICATION_FAILED); } authenticator->destroy(authenticator); save_auth_cfg(this, TRUE); @@ -650,7 +648,7 @@ METHOD(task_t, process_r, status_t, if (!sa_payload || !save_sa_payload(this, message)) { DBG1(DBG_IKE, "SA payload missing or invalid"); - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } list = sa_payload->get_proposals(sa_payload); @@ -660,7 +658,7 @@ METHOD(task_t, process_r, status_t, if (!this->proposal) { DBG1(DBG_IKE, "no proposal found"); - return send_notify(this, NO_PROPOSAL_CHOSEN, chunk_empty); + return send_notify(this, NO_PROPOSAL_CHOSEN); } this->auth_method = sa_payload->get_auth_method(sa_payload); @@ -675,23 +673,23 @@ METHOD(task_t, process_r, status_t, if (!this->keymat->create_hasher(this->keymat, this->proposal)) { - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } if (!this->proposal->get_algorithm(this->proposal, DIFFIE_HELLMAN_GROUP, &group, NULL)) { DBG1(DBG_IKE, "DH group selection failed"); - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } this->dh = lib->crypto->create_dh(lib->crypto, group); if (!this->dh) { DBG1(DBG_IKE, "negotiated DH group not supported"); - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } if (!get_nonce_ke(this, &this->nonce_i, message)) { - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } this->state = MM_KE; return NEED_MORE; @@ -706,7 +704,7 @@ METHOD(task_t, process_r, status_t, if (!id_payload) { DBG1(DBG_IKE, "IDii payload missing"); - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } id = id_payload->get_identification(id_payload); @@ -715,7 +713,7 @@ METHOD(task_t, process_r, status_t, if (!this->peer_cfg) { DBG1(DBG_IKE, "no peer config found"); - return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); + return send_notify(this, AUTHENTICATION_FAILED); } this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); @@ -724,7 +722,7 @@ METHOD(task_t, process_r, status_t, if (!this->my_auth || !this->other_auth) { DBG1(DBG_IKE, "auth config missing"); - return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); + return send_notify(this, AUTHENTICATION_FAILED); } authenticator = create_authenticator(this, id_payload); @@ -732,12 +730,12 @@ METHOD(task_t, process_r, status_t, message) != SUCCESS) { DESTROY_IF(authenticator); - return send_notify(this, AUTHENTICATION_FAILED, chunk_empty); + return send_notify(this, AUTHENTICATION_FAILED); } authenticator->destroy(authenticator); if (!check_constraints(this)) { - return FAILED; + return send_notify(this, AUTHENTICATION_FAILED); } save_auth_cfg(this, FALSE); @@ -905,11 +903,11 @@ METHOD(task_t, build_r, status_t, { if (!add_nonce_ke(this, &this->nonce_r, message)) { - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } if (!derive_keys(this, this->nonce_i, this->nonce_r)) { - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } return NEED_MORE; } @@ -923,9 +921,8 @@ METHOD(task_t, build_r, status_t, if (!id) { DBG1(DBG_CFG, "own identity not known"); - return FAILED; + return send_notify(this, INVALID_ID_INFORMATION); } - this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); id_payload = id_payload_create_from_identification(ID_V1, id); @@ -936,7 +933,7 @@ METHOD(task_t, build_r, status_t, message) != SUCCESS) { DESTROY_IF(authenticator); - return FAILED; + return send_notify(this, AUTHENTICATION_FAILED); } authenticator->destroy(authenticator); save_auth_cfg(this, TRUE); @@ -987,7 +984,7 @@ METHOD(task_t, process_i, status_t, if (!sa_payload) { DBG1(DBG_IKE, "SA payload missing"); - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } list = sa_payload->get_proposals(sa_payload); this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, @@ -996,7 +993,7 @@ METHOD(task_t, process_i, status_t, if (!this->proposal) { DBG1(DBG_IKE, "no proposal found"); - return FAILED; + return send_notify(this, NO_PROPOSAL_CHOSEN); } lifetime = sa_payload->get_lifetime(sa_payload); @@ -1019,11 +1016,11 @@ METHOD(task_t, process_i, status_t, { if (!get_nonce_ke(this, &this->nonce_r, message)) { - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } if (!derive_keys(this, this->nonce_i, this->nonce_r)) { - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } return NEED_MORE; } @@ -1037,7 +1034,7 @@ METHOD(task_t, process_i, status_t, if (!id_payload) { DBG1(DBG_IKE, "IDir payload missing"); - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } id = id_payload->get_identification(id_payload); if (!id->matches(id, this->other_auth->get(this->other_auth, @@ -1045,7 +1042,7 @@ METHOD(task_t, process_i, status_t, { DBG1(DBG_IKE, "IDir does not match"); id->destroy(id); - return FAILED; + return send_notify(this, INVALID_ID_INFORMATION); } this->ike_sa->set_other_id(this->ike_sa, id); @@ -1054,12 +1051,12 @@ METHOD(task_t, process_i, status_t, message) != SUCCESS) { DESTROY_IF(authenticator); - return FAILED; + return send_notify(this, AUTHENTICATION_FAILED); } authenticator->destroy(authenticator); if (!check_constraints(this)) { - return FAILED; + return send_notify(this, AUTHENTICATION_FAILED); } save_auth_cfg(this, FALSE); From 429d95fef265e1c24da09d4559d7858a9d03467f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 17:28:58 +0100 Subject: [PATCH 336/534] Send delete if Main Mode authentication fails as initiator --- src/libcharon/sa/task_manager_v1.c | 16 ++++++++++++++++ src/libcharon/sa/tasks/main_mode.c | 20 ++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 2f905516d..c10f63d0f 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -180,6 +180,11 @@ static void flush_queue(private_task_manager_t *this, linked_list_t *list) { task_t *task; + if (this->queued) + { + this->queued->destroy(this->queued); + this->queued = NULL; + } while (list->remove_last(list, (void**)&task) == SUCCESS) { task->destroy(task); @@ -305,15 +310,23 @@ METHOD(task_manager_t, initiate, status_t, } break; case IKE_CONNECTING: + if (activate_task(this, TASK_ISAKMP_DELETE)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } if (activate_task(this, TASK_XAUTH)) { exchange = TRANSACTION; new_mid = TRUE; + break; } if (activate_task(this, TASK_INFORMATIONAL)) { exchange = INFORMATIONAL_V1; new_mid = TRUE; + break; } break; case IKE_ESTABLISHED: @@ -333,16 +346,19 @@ METHOD(task_manager_t, initiate, status_t, { exchange = INFORMATIONAL_V1; new_mid = TRUE; + break; } if (activate_task(this, TASK_ISAKMP_DELETE)) { exchange = INFORMATIONAL_V1; new_mid = TRUE; + break; } if (activate_task(this, TASK_QUICK_DELETE)) { exchange = INFORMATIONAL_V1; new_mid = TRUE; + break; } break; default: diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 525484f6f..5b2cdf77e 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -31,6 +31,7 @@ #include #include #include +#include typedef struct private_main_mode_t private_main_mode_t; @@ -495,6 +496,17 @@ static status_t send_notify(private_main_mode_t *this, notify_type_t type) return ALREADY_DONE; } +/** + * Queue a delete task if authentication failed as initiator + */ +static status_t send_delete(private_main_mode_t *this) +{ + this->ike_sa->queue_task(this->ike_sa, + (task_t*)isakmp_delete_create(this->ike_sa, TRUE)); + /* cancel all active tasks in favour of informational */ + return ALREADY_DONE; +} + METHOD(task_t, build_i, status_t, private_main_mode_t *this, message_t *message) { @@ -1034,7 +1046,7 @@ METHOD(task_t, process_i, status_t, if (!id_payload) { DBG1(DBG_IKE, "IDir payload missing"); - return send_notify(this, INVALID_PAYLOAD_TYPE); + return send_delete(this); } id = id_payload->get_identification(id_payload); if (!id->matches(id, this->other_auth->get(this->other_auth, @@ -1042,7 +1054,7 @@ METHOD(task_t, process_i, status_t, { DBG1(DBG_IKE, "IDir does not match"); id->destroy(id); - return send_notify(this, INVALID_ID_INFORMATION); + return send_delete(this); } this->ike_sa->set_other_id(this->ike_sa, id); @@ -1051,12 +1063,12 @@ METHOD(task_t, process_i, status_t, message) != SUCCESS) { DESTROY_IF(authenticator); - return send_notify(this, AUTHENTICATION_FAILED); + return send_delete(this); } authenticator->destroy(authenticator); if (!check_constraints(this)) { - return send_notify(this, AUTHENTICATION_FAILED); + return send_delete(this); } save_auth_cfg(this, FALSE); From 53816600ffae1d16e4566a144536712d2b7fb9e2 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 18:03:14 +0100 Subject: [PATCH 337/534] Added a quick_delete task flag to enforce delete, even if CHILD_SA not found --- src/libcharon/sa/ike_sa.c | 2 +- src/libcharon/sa/tasks/informational.c | 2 +- src/libcharon/sa/tasks/quick_delete.c | 10 ++++++++-- src/libcharon/sa/tasks/quick_delete.h | 3 ++- 4 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 223901cad..cb560cd85 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1354,7 +1354,7 @@ METHOD(ike_sa_t, delete_child_sa, status_t, if (this->version == IKEV1) { - task = (task_t*)quick_delete_create(&this->public, protocol, spi); + task = (task_t*)quick_delete_create(&this->public, protocol, spi, FALSE); } else { diff --git a/src/libcharon/sa/tasks/informational.c b/src/libcharon/sa/tasks/informational.c index f0ddad021..60e1cfcb8 100644 --- a/src/libcharon/sa/tasks/informational.c +++ b/src/libcharon/sa/tasks/informational.c @@ -105,7 +105,7 @@ METHOD(task_t, process_r, status_t, else { this->del = (task_t*)quick_delete_create(this->ike_sa, - PROTO_NONE, 0); + PROTO_NONE, 0, FALSE); } } break; diff --git a/src/libcharon/sa/tasks/quick_delete.c b/src/libcharon/sa/tasks/quick_delete.c index 61fa2ef1f..a5f27c5e0 100644 --- a/src/libcharon/sa/tasks/quick_delete.c +++ b/src/libcharon/sa/tasks/quick_delete.c @@ -49,6 +49,11 @@ struct private_quick_delete_t { * Inbound SPI of CHILD_SA to delete */ u_int32_t spi; + + /** + * Send delete even if SA does not exist + */ + bool force; }; /** @@ -96,7 +101,7 @@ static bool delete_child(private_quick_delete_t *this, METHOD(task_t, build_i, status_t, private_quick_delete_t *this, message_t *message) { - if (delete_child(this, this->protocol, this->spi)) + if (delete_child(this, this->protocol, this->spi) || this->force) { delete_payload_t *delete_payload; @@ -185,7 +190,7 @@ METHOD(task_t, destroy, void, * Described in header. */ quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi) + u_int32_t spi, bool force) { private_quick_delete_t *this; @@ -200,6 +205,7 @@ quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, .ike_sa = ike_sa, .protocol = protocol, .spi = spi, + .force = force, ); if (protocol != PROTO_NONE) diff --git a/src/libcharon/sa/tasks/quick_delete.h b/src/libcharon/sa/tasks/quick_delete.h index a0dbd0bc7..80aae8273 100644 --- a/src/libcharon/sa/tasks/quick_delete.h +++ b/src/libcharon/sa/tasks/quick_delete.h @@ -45,9 +45,10 @@ struct quick_delete_t { * @param ike_sa IKE_SA this task works for * @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder * @param spi inbound SPI of CHILD_SA to delete + * @param force send delete even if SA does not exist * @return quick_delete task to handle by the task_manager */ quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi); + u_int32_t spi, bool force); #endif /** QUICK_DELETE_H_ @}*/ From 767966e70bd25221362a597544be034ae85444b7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 18:04:39 +0100 Subject: [PATCH 338/534] Delete CHILD_SA if installing SA in third message fails --- src/libcharon/sa/tasks/quick_mode.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 3858c0a69..3e20c36a4 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -25,6 +25,7 @@ #include #include #include +#include typedef struct private_quick_mode_t private_quick_mode_t; @@ -764,7 +765,11 @@ METHOD(task_t, process_r, status_t, } if (!install(this)) { - return FAILED; + this->ike_sa->queue_task(this->ike_sa, + (task_t*)quick_delete_create(this->ike_sa, + this->proposal->get_protocol(this->proposal), + this->spi_i, TRUE)); + return ALREADY_DONE; } return SUCCESS; } From fceb20f390789554e537ff606416cac2b4991ae6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 18:11:00 +0100 Subject: [PATCH 339/534] Consider notify errors fatal only during main mode --- src/libcharon/sa/tasks/informational.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/tasks/informational.c b/src/libcharon/sa/tasks/informational.c index 60e1cfcb8..5b2ceca84 100644 --- a/src/libcharon/sa/tasks/informational.c +++ b/src/libcharon/sa/tasks/informational.c @@ -84,7 +84,10 @@ METHOD(task_t, process_r, status_t, { DBG1(DBG_IKE, "received %N error notify", notify_type_names, notify->get_notify_type(notify)); - status = FAILED; + if (this->ike_sa->get_state(this->ike_sa) == IKE_CONNECTING) + { /* only critical during main mode */ + status = FAILED; + } break; } else From b64d6423b17e9f63a7dc05d2ca59eda007dc97d8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 18:23:28 +0100 Subject: [PATCH 340/534] Support flushing of task queue after building message in task fails --- src/libcharon/sa/task_manager_v1.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index c10f63d0f..e18a070bf 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -277,8 +277,7 @@ METHOD(task_manager_t, initiate, status_t, host_t *me, *other; status_t status; exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED; - bool new_mid = FALSE; - bool expect_response = FALSE; + bool new_mid = FALSE, expect_response = FALSE, flushed = FALSE; if (!this->rng) { @@ -431,6 +430,7 @@ METHOD(task_manager_t, initiate, status_t, continue; case ALREADY_DONE: flush_queue(this, this->active_tasks); + flushed = TRUE; break; case FAILED: default: @@ -454,6 +454,11 @@ METHOD(task_manager_t, initiate, status_t, { /* tasks completed, no exchange active anymore */ this->initiating.type = EXCHANGE_TYPE_UNDEFINED; } + if (flushed) + { + message->destroy(message); + return initiate(this); + } this->initiating.seqnr++; status = this->ike_sa->generate_message(this->ike_sa, message, @@ -512,7 +517,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) task_t *task; message_t *message; host_t *me, *other; - bool delete = FALSE; + bool delete = FALSE, flushed = FALSE; status_t status; me = request->get_destination(request); @@ -549,6 +554,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) continue; case ALREADY_DONE: flush_queue(this, this->passive_tasks); + flushed = TRUE; break; case FAILED: default: @@ -563,9 +569,13 @@ static status_t build_response(private_task_manager_t *this, message_t *request) } enumerator->destroy(enumerator); - /* message complete, send it */ DESTROY_IF(this->responding.packet); this->responding.packet = NULL; + if (flushed) + { + message->destroy(message); + return initiate(this); + } status = this->ike_sa->generate_message(this->ike_sa, message, &this->responding.packet); message->destroy(message); From bf5b1d9e73fc9afe934f66bdb78c19dcc33b3b2e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 15 Dec 2011 18:35:55 +0100 Subject: [PATCH 341/534] Send different notifies if quick mode fails --- src/libcharon/sa/tasks/quick_mode.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/tasks/quick_mode.c index 3e20c36a4..9d9b5e958 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/tasks/quick_mode.c @@ -645,6 +645,7 @@ static bool has_notify_errors(private_quick_mode_t *this, message_t *message) type = notify->get_notify_type(notify); if (type < 16384) { + DBG1(DBG_IKE, "received %N error notify", notify_type_names, type); err = TRUE; @@ -703,7 +704,7 @@ METHOD(task_t, process_r, status_t, if (!this->config) { DBG1(DBG_IKE, "no child config found"); - return FAILED; + return send_notify(this, NO_PROPOSAL_CHOSEN); } sa_payload = (sa_payload_t*)message->get_payload(message, @@ -711,7 +712,7 @@ METHOD(task_t, process_r, status_t, if (!sa_payload) { DBG1(DBG_IKE, "sa payload missing"); - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } list = sa_payload->get_proposals(sa_payload); this->proposal = this->config->select_proposal(this->config, @@ -731,7 +732,7 @@ METHOD(task_t, process_r, status_t, if (!get_nonce(this, &this->nonce_i, message)) { - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } if (this->proposal->get_algorithm(this->proposal, @@ -743,11 +744,11 @@ METHOD(task_t, process_r, status_t, { DBG1(DBG_IKE, "negotiated DH group %N not supported", diffie_hellman_group_names, group); - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } if (!get_ke(this, message)) { - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } } @@ -761,7 +762,7 @@ METHOD(task_t, process_r, status_t, { if (has_notify_errors(this, message)) { - return FAILED; + return SUCCESS; } if (!install(this)) { @@ -793,7 +794,7 @@ METHOD(task_t, build_r, status_t, if (!this->spi_r) { DBG1(DBG_IKE, "allocating SPI from kernel failed"); - return FAILED; + return send_notify(this, NO_PROPOSAL_CHOSEN); } this->proposal->set_spi(this->proposal, this->spi_r); @@ -843,7 +844,7 @@ METHOD(task_t, process_i, status_t, if (!sa_payload) { DBG1(DBG_IKE, "sa payload missing"); - return FAILED; + return send_notify(this, NO_PROPOSAL_CHOSEN); } list = sa_payload->get_proposals(sa_payload); this->proposal = this->config->select_proposal(this->config, @@ -852,7 +853,7 @@ METHOD(task_t, process_i, status_t, if (!this->proposal) { DBG1(DBG_IKE, "no matching proposal found"); - return FAILED; + return send_notify(this, NO_PROPOSAL_CHOSEN); } this->spi_r = this->proposal->get_spi(this->proposal); @@ -860,19 +861,19 @@ METHOD(task_t, process_i, status_t, if (!get_nonce(this, &this->nonce_r, message)) { - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } if (this->dh && !get_ke(this, message)) { - return FAILED; + return send_notify(this, INVALID_KEY_INFORMATION); } if (!get_ts(this, message)) { - return FAILED; + return send_notify(this, INVALID_PAYLOAD_TYPE); } if (!install(this)) { - return FAILED; + return send_notify(this, NO_PROPOSAL_CHOSEN); } this->state = QM_NEGOTIATED; return NEED_MORE; From b46b56fac1a1435ff33e0a9ccb3240db5150fe13 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 15 Dec 2011 11:22:31 +0100 Subject: [PATCH 342/534] Log parsed unsigned ints with proper format strings. --- src/libcharon/encoding/parser.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 14e2cc7a0..8f1d667fc 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -137,7 +137,7 @@ static bool parse_uint4(private_parser_t *this, int rule_number, } if (output_pos) { - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hhu", *output_pos); } return TRUE; } @@ -159,7 +159,7 @@ static bool parse_uint8(private_parser_t *this, int rule_number, if (output_pos) { *output_pos = *(this->byte_pos); - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hhu", *output_pos); } this->byte_pos++; return TRUE; @@ -183,7 +183,7 @@ static bool parse_uint15(private_parser_t *this, int rule_number, { memcpy(output_pos, this->byte_pos, sizeof(u_int16_t)); *output_pos = ntohs(*output_pos) & ~0x8000; - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hu", *output_pos); } this->byte_pos += sizeof(u_int16_t); this->bit_pos = 0; @@ -208,7 +208,7 @@ static bool parse_uint16(private_parser_t *this, int rule_number, { memcpy(output_pos, this->byte_pos, sizeof(u_int16_t)); *output_pos = ntohs(*output_pos); - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hu", *output_pos); } this->byte_pos += sizeof(u_int16_t); return TRUE; @@ -231,7 +231,7 @@ static bool parse_uint32(private_parser_t *this, int rule_number, { memcpy(output_pos, this->byte_pos, sizeof(u_int32_t)); *output_pos = ntohl(*output_pos); - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %u", *output_pos); } this->byte_pos += sizeof(u_int32_t); return TRUE; From 00cc2188d47b2b31fe6c06c9ab86da6cc672d516 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 15 Dec 2011 16:51:19 +0100 Subject: [PATCH 343/534] Some whitespace fixes. --- .../credentials/certificates/x509.h | 8 ++-- src/libstrongswan/plugins/x509/x509_cert.c | 44 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h index fec02dbad..ba3766b1f 100644 --- a/src/libstrongswan/credentials/certificates/x509.h +++ b/src/libstrongswan/credentials/certificates/x509.h @@ -41,13 +41,13 @@ enum x509_flag_t { /** cert has no constraints */ X509_NONE = 0, /** cert has CA constraint */ - X509_CA = (1<<0), + X509_CA = (1<<0), /** cert has AA constraint */ - X509_AA = (1<<1), + X509_AA = (1<<1), /** cert has OCSP signer constraint */ - X509_OCSP_SIGNER = (1<<2), + X509_OCSP_SIGNER = (1<<2), /** cert has serverAuth key usage */ - X509_SERVER_AUTH = (1<<3), + X509_SERVER_AUTH = (1<<3), /** cert has clientAuth key usage */ X509_CLIENT_AUTH = (1<<4), /** cert is self-signed */ diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index 8b228a2b6..6db2e6869 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -275,8 +275,8 @@ static const asn1Object_t basicConstraintsObjects[] = { { 0, "basicConstraints", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ { 1, "CA", ASN1_BOOLEAN, ASN1_DEF|ASN1_BODY }, /* 1 */ { 1, "pathLenConstraint", ASN1_INTEGER, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; #define BASIC_CONSTRAINTS_CA 1 #define BASIC_CONSTRAINTS_PATH_LEN 2 @@ -394,7 +394,7 @@ static const asn1Object_t generalNameObjects[] = { { 0, "otherName", ASN1_CONTEXT_C_0, ASN1_OPT|ASN1_BODY }, /* 0 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 1 */ { 0, "rfc822Name", ASN1_CONTEXT_S_1, ASN1_OPT|ASN1_BODY }, /* 2 */ - { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ + { 0, "end choice", ASN1_EOC, ASN1_END }, /* 3 */ { 0, "dnsName", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 4 */ { 0, "end choice", ASN1_EOC, ASN1_END }, /* 5 */ { 0, "x400Address", ASN1_CONTEXT_S_3, ASN1_OPT|ASN1_BODY }, /* 6 */ @@ -536,14 +536,14 @@ void x509_parse_generalNames(chunk_t blob, int level0, bool implicit, linked_lis * ASN.1 definition of a authorityKeyIdentifier extension */ static const asn1Object_t authKeyIdentifierObjects[] = { - { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ + { 0, "authorityKeyIdentifier", ASN1_SEQUENCE, ASN1_NONE }, /* 0 */ { 1, "keyIdentifier", ASN1_CONTEXT_S_0, ASN1_OPT|ASN1_BODY }, /* 1 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 2 */ { 1, "authorityCertIssuer", ASN1_CONTEXT_C_1, ASN1_OPT|ASN1_OBJ }, /* 3 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 4 */ { 1, "authorityCertSerialNumber", ASN1_CONTEXT_S_2, ASN1_OPT|ASN1_BODY }, /* 5 */ - { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */ - { 0, "exit", ASN1_EOC, ASN1_EXIT } + { 1, "end opt", ASN1_EOC, ASN1_END }, /* 6 */ + { 0, "exit", ASN1_EOC, ASN1_EXIT } }; #define AUTH_KEY_ID_KEY_ID 1 #define AUTH_KEY_ID_CERT_ISSUER 3 @@ -1105,19 +1105,19 @@ static void parse_policyConstraints(chunk_t blob, int level0, * ASN.1 definition of ipAddrBlocks according to RFC 3779 */ static const asn1Object_t ipAddrBlocksObjects[] = { - { 0, "ipAddrBlocks", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ + { 0, "ipAddrBlocks", ASN1_SEQUENCE, ASN1_LOOP }, /* 0 */ { 1, "ipAddressFamily", ASN1_SEQUENCE, ASN1_NONE }, /* 1 */ - { 2, "addressFamily", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ - { 2, "inherit", ASN1_NULL, ASN1_OPT|ASN1_NONE }, /* 3 */ - { 2, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ - { 2, "addressesOrRanges", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 5 */ - { 3, "addressPrefix", ASN1_BIT_STRING, ASN1_OPT|ASN1_BODY }, /* 6 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ - { 3, "addressRange", ASN1_SEQUENCE, ASN1_OPT|ASN1_NONE }, /* 8 */ - { 4, "min", ASN1_BIT_STRING, ASN1_BODY }, /* 9 */ - { 4, "max", ASN1_BIT_STRING, ASN1_BODY }, /* 10 */ - { 3, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ - { 2, "end opt/loop", ASN1_EOC, ASN1_END }, /* 12 */ + { 2, "addressFamily", ASN1_OCTET_STRING, ASN1_BODY }, /* 2 */ + { 2, "inherit", ASN1_NULL, ASN1_OPT|ASN1_NONE }, /* 3 */ + { 2, "end choice", ASN1_EOC, ASN1_END }, /* 4 */ + { 2, "addressesOrRanges", ASN1_SEQUENCE, ASN1_OPT|ASN1_LOOP }, /* 5 */ + { 3, "addressPrefix", ASN1_BIT_STRING, ASN1_OPT|ASN1_BODY }, /* 6 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 7 */ + { 3, "addressRange", ASN1_SEQUENCE, ASN1_OPT|ASN1_NONE }, /* 8 */ + { 4, "min", ASN1_BIT_STRING, ASN1_BODY }, /* 9 */ + { 4, "max", ASN1_BIT_STRING, ASN1_BODY }, /* 10 */ + { 3, "end choice", ASN1_EOC, ASN1_END }, /* 11 */ + { 2, "end opt/loop", ASN1_EOC, ASN1_END }, /* 12 */ { 0, "end loop", ASN1_EOC, ASN1_END }, /* 13 */ { 0, "exit", ASN1_EOC, ASN1_EXIT } }; @@ -1280,7 +1280,7 @@ static const asn1Object_t certObjects[] = { #define X509_OBJ_VERSION 3 #define X509_OBJ_SERIAL_NUMBER 4 #define X509_OBJ_SIG_ALG 5 -#define X509_OBJ_ISSUER 6 +#define X509_OBJ_ISSUER 6 #define X509_OBJ_NOT_BEFORE 8 #define X509_OBJ_NOT_AFTER 9 #define X509_OBJ_SUBJECT 10 @@ -1706,7 +1706,7 @@ METHOD(x509_t, get_subjectKeyIdentifier, chunk_t, chunk_t fingerprint; if (this->public_key->get_fingerprint(this->public_key, - KEYID_PUBKEY_SHA1, &fingerprint)) + KEYID_PUBKEY_SHA1, &fingerprint)) { return fingerprint; } From f29a4f1c647151abc4a74d3ec4f029272ec0ec53 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 15 Dec 2011 16:54:49 +0100 Subject: [PATCH 344/534] Added support for iKEIntermediate X.509 extended key usage flag. Mac OS X requires server certificates to have this flag set. --- src/libcharon/plugins/stroke/stroke_list.c | 4 ++-- src/libstrongswan/asn1/oid.txt | 3 +++ .../credentials/certificates/x509.h | 2 ++ src/libstrongswan/plugins/x509/x509_cert.c | 20 +++++++++++++------ 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index d2fda1b3c..eb160471e 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -799,8 +799,8 @@ static void stroke_list_certs(linked_list_t *list, char *label, x509_flag_t flag_mask; /* mask all auxiliary flags */ - flag_mask = ~(X509_SERVER_AUTH | X509_CLIENT_AUTH | - X509_SELF_SIGNED | X509_IP_ADDR_BLOCKS ); + flag_mask = ~(X509_SERVER_AUTH | X509_CLIENT_AUTH | X509_IKE_INTERMEDIATE | + X509_SELF_SIGNED | X509_IP_ADDR_BLOCKS); enumerator = list->create_enumerator(list); while (enumerator->enumerate(enumerator, (void**)&cert)) diff --git a/src/libstrongswan/asn1/oid.txt b/src/libstrongswan/asn1/oid.txt index f16287cb2..73c068851 100644 --- a/src/libstrongswan/asn1/oid.txt +++ b/src/libstrongswan/asn1/oid.txt @@ -226,6 +226,9 @@ 0x02 "caIssuers" OID_CA_ISSUERS 0x03 "timeStamping" 0x05 "caRepository" + 0x08 "ipsec" + 0x02 "certificate" + 0x02 "iKEIntermediate" OID_IKE_INTERMEDIATE 0x0E "oiw" 0x03 "secsig" 0x02 "algorithms" diff --git a/src/libstrongswan/credentials/certificates/x509.h b/src/libstrongswan/credentials/certificates/x509.h index ba3766b1f..8bd2a6a83 100644 --- a/src/libstrongswan/credentials/certificates/x509.h +++ b/src/libstrongswan/credentials/certificates/x509.h @@ -56,6 +56,8 @@ enum x509_flag_t { X509_IP_ADDR_BLOCKS = (1<<6), /** cert has CRL sign key usage */ X509_CRL_SIGN = (1<<7), + /** cert has iKEIntermediate key usage */ + X509_IKE_INTERMEDIATE = (1<<8), }; /** diff --git a/src/libstrongswan/plugins/x509/x509_cert.c b/src/libstrongswan/plugins/x509/x509_cert.c index 6db2e6869..cba1a4610 100644 --- a/src/libstrongswan/plugins/x509/x509_cert.c +++ b/src/libstrongswan/plugins/x509/x509_cert.c @@ -752,6 +752,9 @@ static void parse_extendedKeyUsage(chunk_t blob, int level0, case OID_CLIENT_AUTH: this->flags |= X509_CLIENT_AUTH; break; + case OID_IKE_INTERMEDIATE: + this->flags |= X509_IKE_INTERMEDIATE; + break; case OID_OCSP_SIGNING: this->flags |= X509_OCSP_SIGNER; break; @@ -1994,6 +1997,7 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, chunk_t subjectKeyIdentifier = chunk_empty, authKeyIdentifier = chunk_empty; chunk_t crlDistributionPoints = chunk_empty, authorityInfoAccess = chunk_empty; chunk_t policyConstraints = chunk_empty, inhibitAnyPolicy = chunk_empty; + chunk_t ikeIntermediate = chunk_empty; identification_t *issuer, *subject; chunk_t key_info; signature_scheme_t scheme; @@ -2107,7 +2111,7 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, asn1_wrap(ASN1_BIT_STRING, "c", keyUsageBits))); } - /* add serverAuth extendedKeyUsage flag */ + /* add extendedKeyUsage flags */ if (cert->flags & X509_SERVER_AUTH) { serverAuth = asn1_build_known_oid(OID_SERVER_AUTH); @@ -2116,20 +2120,24 @@ static bool generate(private_x509_cert_t *cert, certificate_t *sign_cert, { clientAuth = asn1_build_known_oid(OID_CLIENT_AUTH); } - - /* add ocspSigning extendedKeyUsage flag */ + if (cert->flags & X509_IKE_INTERMEDIATE) + { + ikeIntermediate = asn1_build_known_oid(OID_IKE_INTERMEDIATE); + } if (cert->flags & X509_OCSP_SIGNER) { ocspSigning = asn1_build_known_oid(OID_OCSP_SIGNING); } - if (serverAuth.ptr || clientAuth.ptr || ocspSigning.ptr) + if (serverAuth.ptr || clientAuth.ptr || ikeIntermediate.ptr || + ocspSigning.ptr) { extendedKeyUsage = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_build_known_oid(OID_EXTENDED_KEY_USAGE), asn1_wrap(ASN1_OCTET_STRING, "m", - asn1_wrap(ASN1_SEQUENCE, "mmm", - serverAuth, clientAuth, ocspSigning))); + asn1_wrap(ASN1_SEQUENCE, "mmmm", + serverAuth, clientAuth, ikeIntermediate, + ocspSigning))); } /* add subjectKeyIdentifier to CA and OCSP signer certificates */ From 4bc4e8e17b5f6c00bc060376bfbd5dbd34e47d48 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Thu, 15 Dec 2011 16:56:07 +0100 Subject: [PATCH 345/534] Added support for iKEIntermediate flag to ipsec pki. --- src/pki/commands/issue.c | 4 ++++ src/pki/commands/print.c | 4 ++++ src/pki/commands/self.c | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/pki/commands/issue.c b/src/pki/commands/issue.c index 6a5686d92..97769fca6 100644 --- a/src/pki/commands/issue.c +++ b/src/pki/commands/issue.c @@ -229,6 +229,10 @@ static int issue() { flags |= X509_CLIENT_AUTH; } + else if (streq(arg, "ikeIntermediate")) + { + flags |= X509_IKE_INTERMEDIATE; + } else if (streq(arg, "crlSign")) { flags |= X509_CRL_SIGN; diff --git a/src/pki/commands/print.c b/src/pki/commands/print.c index ee6f30c98..2bc80f96b 100644 --- a/src/pki/commands/print.c +++ b/src/pki/commands/print.c @@ -133,6 +133,10 @@ static void print_x509(x509_t *x509) { printf("clientAuth "); } + if (flags & X509_IKE_INTERMEDIATE) + { + printf("iKEIntermediate "); + } if (flags & X509_SELF_SIGNED) { printf("self-signed "); diff --git a/src/pki/commands/self.c b/src/pki/commands/self.c index c7788ff62..7852d8594 100644 --- a/src/pki/commands/self.c +++ b/src/pki/commands/self.c @@ -212,6 +212,10 @@ static int self() { flags |= X509_CLIENT_AUTH; } + else if (streq(arg, "ikeIntermediate")) + { + flags |= X509_IKE_INTERMEDIATE; + } else if (streq(arg, "crlSign")) { flags |= X509_CRL_SIGN; From 2f58f6cba136ae2b7c67b3781422d690de1bb1dd Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 17 Dec 2011 12:19:30 +0100 Subject: [PATCH 346/534] Fixed notify enum names --- src/libcharon/encoding/payloads/notify_payload.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index c3d1deb20..d5de611e7 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -40,12 +40,13 @@ ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI "NO_PROPOSAL_CHOSEN"); ENUM_NEXT(notify_type_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN, "PAYLOAD_MALFORMED", - "INVALID_KE_PAYLOAD" + "INVALID_KE_PAYLOAD", "INVALID_ID_INFORMATION", "INVALID_CERT_ENCODING", "INVALID_CERTIFICATE", "CERT_TYPE_UNSUPPORTED", "INVALID_CERT_AUTHORITY", + "INVALID_HASH_INFORMATION", "AUTHENTICATION_FAILED"); ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED, "SINGLE_PAIR_REQUIRED", @@ -140,6 +141,7 @@ ENUM_NEXT(notify_type_short_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_ "INVAL_CERT", "CERT_UNSUP", "INVAL_CA", + "INVAL_HASH", "AUTH_FAILED"); ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED, "SINGLE_PAIR", From b9a707e696148fad420df508462abbaf734bc646 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 17 Dec 2011 12:47:44 +0100 Subject: [PATCH 347/534] Some coding style cleanups --- src/libcharon/encoding/message.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 1c6e6943c..532b00a5c 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1825,8 +1825,9 @@ static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) { /* instead of associated data we provide the IV, we also update * the IV with the last encrypted block */ keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; - chunk_t last_block = chunk_create(chunk.ptr + chunk.len - bs, - bs); + chunk_t last_block; + + last_block = chunk_create(chunk.ptr + chunk.len - bs, bs); chunk = keymat_v1->get_iv(keymat_v1, this->message_id); keymat_v1->update_iv(keymat_v1, this->message_id, last_block); } @@ -1978,15 +1979,17 @@ METHOD(message_t, parse_body, status_t, { keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; chunk_t hash; + hash = keymat_v1->get_hash_phase2(keymat_v1, &this->public); if (hash.ptr) { hash_payload_t *hash_payload; chunk_t other_hash; + if (this->first_payload != HASH_V1) { if (this->exchange_type == INFORMATIONAL_V1) - { /* TODO-IKEv1: Parse and log contents? */ + { DBG1(DBG_ENC, "ignoring unprotected INFORMATIONAL from %H", this->packet->get_source(this->packet)); } From d94c923648a506f9abae431592ef4bfd6609a030 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 17 Dec 2011 12:48:14 +0100 Subject: [PATCH 348/534] Support an "any" IKE version for both IKEv1 or IKEv2 --- src/libcharon/config/peer_cfg.h | 2 ++ src/libcharon/plugins/stroke/stroke_config.c | 2 +- src/libcharon/plugins/stroke/stroke_socket.c | 2 +- src/libcharon/sa/keymat.c | 3 ++- src/libcharon/sa/task_manager.c | 4 +++- src/starter/confread.h | 7 ++++--- src/starter/starterstroke.c | 2 +- src/stroke/stroke.c | 2 +- src/stroke/stroke_msg.h | 2 +- 9 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index 33309d116..f1915614a 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -43,6 +43,8 @@ typedef struct peer_cfg_t peer_cfg_t; * IKE version. */ enum ike_version_t { + /** any version */ + IKE_ANY = 0, /** IKE version 1 */ IKEV1 = 1, /** IKE version 2 */ diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index c4b218d1b..08339a475 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -686,7 +686,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, * the pool name as the connection name, which the attribute provider * uses to serve pool addresses. */ peer_cfg = peer_cfg_create(msg->add_conn.name, - msg->add_conn.ikev2 ? IKEV2 : IKEV1, ike_cfg, + msg->add_conn.version, ike_cfg, msg->add_conn.me.sendcert, unique, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, msg->add_conn.mobike, msg->add_conn.dpd.delay, diff --git a/src/libcharon/plugins/stroke/stroke_socket.c b/src/libcharon/plugins/stroke/stroke_socket.c index 7a14be0cf..21d15afe6 100644 --- a/src/libcharon/plugins/stroke/stroke_socket.c +++ b/src/libcharon/plugins/stroke/stroke_socket.c @@ -197,7 +197,7 @@ static void stroke_add_conn(private_stroke_socket_t *this, stroke_msg_t *msg) DBG2(DBG_CFG, " mediation=%s", msg->add_conn.ikeme.mediation ? "yes" : "no"); DBG2(DBG_CFG, " mediated_by=%s", msg->add_conn.ikeme.mediated_by); DBG2(DBG_CFG, " me_peerid=%s", msg->add_conn.ikeme.peerid); - DBG2(DBG_CFG, " keyexchange=%s", msg->add_conn.ikev2 ? "ikev2" : "ikev1"); + DBG2(DBG_CFG, " keyexchange=ikev%u", msg->add_conn.version); this->config->add(this->config, msg); this->attribute->add_pool(this->attribute, msg); diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c index 2fa4423e1..f132822b7 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat.c @@ -28,8 +28,9 @@ keymat_t *keymat_create(ike_version_t version, bool initiator) return &keymat_v1_create(initiator)->keymat; case IKEV2: return &keymat_v2_create(initiator)->keymat; + default: + return NULL; } - return NULL; } /** diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c index eea2320e0..3538087bc 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager.c @@ -28,6 +28,8 @@ task_manager_t *task_manager_create(ike_sa_t *ike_sa) return &task_manager_v1_create(ike_sa)->task_manager; case IKEV2: return &task_manager_v2_create(ike_sa)->task_manager; + default: + return NULL; } - return NULL; } + diff --git a/src/starter/confread.h b/src/starter/confread.h index 988b8ed48..47bd84603 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -39,9 +39,10 @@ typedef enum { } starter_state_t; typedef enum { - KEY_EXCHANGE_IKE, - KEY_EXCHANGE_IKEV1, - KEY_EXCHANGE_IKEV2 + /* shared with ike_version_t */ + KEY_EXCHANGE_IKE = 0, + KEY_EXCHANGE_IKEV1 = 1, + KEY_EXCHANGE_IKEV2 = 2, } keyexchange_t; typedef enum { diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 628d63214..c4d9fa2e9 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -196,7 +196,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) memset(&msg, 0, sizeof(msg)); msg.type = STR_ADD_CONN; msg.length = offsetof(stroke_msg_t, buffer); - msg.add_conn.ikev2 = conn->keyexchange != KEY_EXCHANGE_IKEV1; + msg.add_conn.version = conn->keyexchange; msg.add_conn.name = push_string(&msg, connection_name(conn)); /* PUBKEY is preferred to PSK and EAP */ diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c index a27c374c7..697115a84 100644 --- a/src/stroke/stroke.c +++ b/src/stroke/stroke.c @@ -138,7 +138,7 @@ static int add_connection(char *name, msg.type = STR_ADD_CONN; msg.add_conn.name = push_string(&msg, name); - msg.add_conn.ikev2 = 1; + msg.add_conn.version = 2; msg.add_conn.auth_method = 2; msg.add_conn.mode = 1; msg.add_conn.mobike = 1; diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index 3350d7603..af566b952 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -239,7 +239,7 @@ struct stroke_msg_t { /* data for STR_ADD_CONN */ struct { char *name; - int ikev2; + int version; /* next three are deprecated, use stroke_end_t.auth instead */ int auth_method; u_int32_t eap_type; From ac009df132e9b7a66962e1cf860cd2e2f40be60e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 17 Dec 2011 13:31:27 +0100 Subject: [PATCH 349/534] Pass IKE version to peer config enumerator, filter configs --- src/libcharon/config/backend_manager.c | 54 +++++++++++++------ src/libcharon/config/backend_manager.h | 4 +- src/libcharon/config/peer_cfg.c | 3 +- src/libcharon/plugins/smp/smp.c | 2 +- src/libcharon/plugins/stroke/stroke_control.c | 8 +-- src/libcharon/plugins/stroke/stroke_list.c | 7 +-- src/libcharon/plugins/uci/uci_control.c | 2 +- .../processing/jobs/start_action_job.c | 2 +- src/libcharon/sa/tasks/ike_auth.c | 2 +- src/libcharon/sa/tasks/main_mode.c | 4 +- 10 files changed, 57 insertions(+), 31 deletions(-) diff --git a/src/libcharon/config/backend_manager.c b/src/libcharon/config/backend_manager.c index e7e7a9055..507f26d2f 100644 --- a/src/libcharon/config/backend_manager.c +++ b/src/libcharon/config/backend_manager.c @@ -146,10 +146,11 @@ METHOD(backend_manager_t, get_ike_cfg, ike_cfg_t*, ike_cfg_match_t match, best = MATCH_ANY; ike_data_t *data; - data = malloc_thing(ike_data_t); - data->this = this; - data->me = me; - data->other = other; + INIT(data, + .this = this, + .me = me, + .other = other, + ); DBG2(DBG_CFG, "looking for an ike config for %H...%H", me, other); @@ -232,6 +233,22 @@ static id_match_t get_peer_match(identification_t *id, return match; } +/** + * Get match quality of IKE version + */ +static int get_version_match(ike_version_t cfg, ike_version_t req) +{ + if (req == IKE_ANY || cfg == IKE_ANY) + { + return 1; + } + if (req == cfg) + { + return 2; + } + return 0; +} + /** * data to pass nested peer enumerator */ @@ -325,17 +342,18 @@ static void insert_sorted(match_entry_t *entry, linked_list_t *list, METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, private_backend_manager_t *this, host_t *me, host_t *other, - identification_t *my_id, identification_t *other_id) + identification_t *my_id, identification_t *other_id, ike_version_t version) { enumerator_t *enumerator; peer_data_t *data; peer_cfg_t *cfg; linked_list_t *configs, *helper; - data = malloc_thing(peer_data_t); - data->lock = this->lock; - data->me = my_id; - data->other = other_id; + INIT(data, + .lock = this->lock, + .me = my_id, + .other = other_id, + ); /* create a sorted list with all matches */ this->lock->read_lock(this->lock); @@ -355,22 +373,26 @@ METHOD(backend_manager_t, create_peer_cfg_enumerator, enumerator_t*, { id_match_t match_peer_me, match_peer_other; ike_cfg_match_t match_ike; + int match_version; match_entry_t *entry; match_peer_me = get_peer_match(my_id, cfg, TRUE); match_peer_other = get_peer_match(other_id, cfg, FALSE); match_ike = get_ike_match(cfg->get_ike_cfg(cfg), me, other); + match_version = get_version_match(cfg->get_ike_version(cfg), version); DBG3(DBG_CFG, "ike config match: %d (%H %H)", match_ike, me, other); - if (match_peer_me && match_peer_other && match_ike) + if (match_peer_me && match_peer_other && match_ike && match_version) { - DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d (me/other/ike)", - cfg->get_name(cfg), match_peer_me, match_peer_other, match_ike); + DBG2(DBG_CFG, " candidate \"%s\", match: %d/%d/%d/%d " + "(me/other/ike/version)", cfg->get_name(cfg), + match_peer_me, match_peer_other, match_ike, match_version); - entry = malloc_thing(match_entry_t); - entry->match_peer = match_peer_me + match_peer_other; - entry->match_ike = match_ike; - entry->cfg = cfg->get_ref(cfg); + INIT(entry, + .match_peer = match_peer_me + match_peer_other, + .match_ike = match_ike, + .cfg = cfg->get_ref(cfg), + ); insert_sorted(entry, configs, helper); } } diff --git a/src/libcharon/config/backend_manager.h b/src/libcharon/config/backend_manager.h index 5b394f791..de263365b 100644 --- a/src/libcharon/config/backend_manager.h +++ b/src/libcharon/config/backend_manager.h @@ -56,6 +56,7 @@ struct backend_manager_t { * * @param my_host address of own host * @param other_host address of remote host + * @param version IKE version to get a config for * @return matching ike_config, or NULL if none found */ ike_cfg_t* (*get_ike_cfg)(backend_manager_t *this, @@ -79,11 +80,12 @@ struct backend_manager_t { * @param other remote address * @param my_id IDr in first authentication round * @param other_id IDi in first authentication round + * @param version IKE version to get a config for * @return enumerator over peer_cfg_t */ enumerator_t* (*create_peer_cfg_enumerator)(backend_manager_t *this, host_t *me, host_t *other, identification_t *my_id, - identification_t *other_id); + identification_t *other_id, ike_version_t version); /** * Register a backend on the manager. * diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index fbdfa25e2..b58bdce55 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -25,7 +25,8 @@ #include #include -ENUM(ike_version_names, IKEV1, IKEV2, +ENUM(ike_version_names, IKE_ANY, IKEV2, + "IKEv1/2" "IKEv1", "IKEv2", ); diff --git a/src/libcharon/plugins/smp/smp.c b/src/libcharon/plugins/smp/smp.c index 0db287480..c2fe11f74 100644 --- a/src/libcharon/plugins/smp/smp.c +++ b/src/libcharon/plugins/smp/smp.c @@ -294,7 +294,7 @@ static void request_query_config(xmlTextReaderPtr reader, xmlTextWriterPtr write xmlTextWriterStartElement(writer, "configlist"); enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { enumerator_t *children; diff --git a/src/libcharon/plugins/stroke/stroke_control.c b/src/libcharon/plugins/stroke/stroke_control.c index 98f57b56c..3264cb802 100644 --- a/src/libcharon/plugins/stroke/stroke_control.c +++ b/src/libcharon/plugins/stroke/stroke_control.c @@ -149,8 +149,8 @@ METHOD(stroke_control_t, initiate, void, } else { - enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + enumerator = charon->backends->create_peer_cfg_enumerator( + charon->backends, NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { child_cfg = get_child_from_peer(peer_cfg, msg->initiate.name); @@ -579,8 +579,8 @@ METHOD(stroke_control_t, route, void, } else { - enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + enumerator = charon->backends->create_peer_cfg_enumerator( + charon->backends, NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { child_cfg = get_child_from_peer(peer_cfg, msg->route.name); diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index eb160471e..19fc46418 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -497,7 +497,7 @@ METHOD(stroke_list_t, status, void, fprintf(out, "Connections:\n"); enumerator = charon->backends->create_peer_cfg_enumerator( - charon->backends, NULL, NULL, NULL, NULL); + charon->backends, NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { if (name && !streq(name, peer_cfg->get_name(peer_cfg))) @@ -506,8 +506,9 @@ METHOD(stroke_list_t, status, void, } ike_cfg = peer_cfg->get_ike_cfg(peer_cfg); - fprintf(out, "%12s: %s...%s", peer_cfg->get_name(peer_cfg), - ike_cfg->get_my_addr(ike_cfg), ike_cfg->get_other_addr(ike_cfg)); + fprintf(out, "%12s: %s...%s (%N)", peer_cfg->get_name(peer_cfg), + ike_cfg->get_my_addr(ike_cfg), ike_cfg->get_other_addr(ike_cfg), + ike_version_names, peer_cfg->get_ike_version(peer_cfg)); dpd = peer_cfg->get_dpd(peer_cfg); if (dpd) diff --git a/src/libcharon/plugins/uci/uci_control.c b/src/libcharon/plugins/uci/uci_control.c index af4a6a711..87d0f8603 100644 --- a/src/libcharon/plugins/uci/uci_control.c +++ b/src/libcharon/plugins/uci/uci_control.c @@ -84,7 +84,7 @@ static void status(private_uci_control_t *this, char *name) FILE *out = NULL; configs = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, IKE_ANY); while (configs->enumerate(configs, &peer_cfg)) { if (name && !streq(name, peer_cfg->get_name(peer_cfg))) diff --git a/src/libcharon/processing/jobs/start_action_job.c b/src/libcharon/processing/jobs/start_action_job.c index efb53acea..294ac154a 100644 --- a/src/libcharon/processing/jobs/start_action_job.c +++ b/src/libcharon/processing/jobs/start_action_job.c @@ -46,7 +46,7 @@ METHOD(job_t, execute, void, char *name; enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, IKE_ANY); while (enumerator->enumerate(enumerator, &peer_cfg)) { children = peer_cfg->create_child_cfg_enumerator(peer_cfg); diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/tasks/ike_auth.c index 39d865c9f..f9cf5c613 100644 --- a/src/libcharon/sa/tasks/ike_auth.c +++ b/src/libcharon/sa/tasks/ike_auth.c @@ -272,7 +272,7 @@ static bool load_cfg_candidates(private_ike_auth_t *this) DBG1(DBG_CFG, "looking for peer configs matching %H[%Y]...%H[%Y]", me, my_id, other, other_id); enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - me, other, my_id, other_id); + me, other, my_id, other_id, IKEV2); while (enumerator->enumerate(enumerator, &peer_cfg)) { peer_cfg->get_ref(peer_cfg); diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/tasks/main_mode.c index 5b2cdf77e..08bb29124 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/tasks/main_mode.c @@ -406,7 +406,7 @@ static peer_cfg_t *select_config(private_main_mode_t *this, identification_t *id DBG1(DBG_CFG, "looking for %N peer configs matching %H...%H[%Y]", auth_method_names, this->auth_method, me, other, id); enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - me, other, NULL, id); + me, other, NULL, id, IKEV1); while (enumerator->enumerate(enumerator, ¤t)) { if (get_auth_method(this, current) == this->auth_method) @@ -811,7 +811,7 @@ static shared_key_t *lookup_shared_key(private_main_mode_t *this) peer_cfg_t *peer_cfg = NULL; enumerator = charon->backends->create_peer_cfg_enumerator( - charon->backends, me, other, NULL, NULL); + charon->backends, me, other, NULL, NULL, IKEV1); while (enumerator->enumerate(enumerator, &peer_cfg)) { my_auth = get_auth_cfg(peer_cfg, TRUE); From ef175c92d9e4f2006e8a4e48aff0e49f47e3a989 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Sat, 17 Dec 2011 14:26:04 +0100 Subject: [PATCH 350/534] Initiate IKE_ANY configurations with IKEv2 --- src/libcharon/sa/ike_sa.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index cb560cd85..04524b371 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -2042,6 +2042,11 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, private_ike_sa_t *this; static u_int32_t unique_id = 0; + if (version != IKEV1) + { + version = IKEV2; + } + INIT(this, .public = { .get_version = _get_version, From 2ee83c277898f5098cc761c7685953185872f4ca Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 10:10:57 +0100 Subject: [PATCH 351/534] Fix XAuth plugin feature matching --- src/libstrongswan/plugins/plugin_feature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/plugins/plugin_feature.c b/src/libstrongswan/plugins/plugin_feature.c index 6555e593b..8b27c73c3 100644 --- a/src/libstrongswan/plugins/plugin_feature.c +++ b/src/libstrongswan/plugins/plugin_feature.c @@ -98,7 +98,7 @@ bool plugin_feature_matches(plugin_feature_t *a, plugin_feature_t *b) return streq(a->arg.custom, b->arg.custom); case FEATURE_XAUTH_SERVER: case FEATURE_XAUTH_PEER: - return a->arg.xauth == b->arg.xauth; + return streq(a->arg.xauth == b->arg.xauth); } } return FALSE; From 5d0458af0aef7b3161957bec95016e728efc3c2d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 10:12:33 +0100 Subject: [PATCH 352/534] Another set of cleanups in message.c --- src/libcharon/encoding/message.c | 37 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 532b00a5c..708e3fb97 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1351,8 +1351,7 @@ static void order_payloads(private_message_t *this) /** * Wrap payloads in an encryption payload */ -static encryption_payload_t* wrap_payloads(private_message_t *this, - payload_type_t encryption_type) +static encryption_payload_t* wrap_payloads(private_message_t *this) { encryption_payload_t *encryption; linked_list_t *payloads; @@ -1366,7 +1365,14 @@ static encryption_payload_t* wrap_payloads(private_message_t *this, payloads->insert_last(payloads, current); } - encryption = encryption_payload_create(encryption_type); + if (this->is_encrypted) + { + encryption = encryption_payload_create(ENCRYPTED_V1); + } + else + { + encryption = encryption_payload_create(ENCRYPTED); + } while (payloads->remove_first(payloads, (void**)¤t) == SUCCESS) { payload_rule_t *rule; @@ -1455,34 +1461,30 @@ METHOD(message_t, generate, status_t, chunk_t hash = keymat_v1->get_hash_phase2(keymat_v1, &this->public); if (hash.ptr) { /* insert a HASH payload as first payload */ - hash_payload_t *hash_payload = hash_payload_create(HASH_V1); - hash_payload->set_hash(hash_payload, hash); - this->payloads->insert_first(this->payloads, - (payload_t*)hash_payload); + hash_payload_t *hash_payload; + hash_payload = hash_payload_create(HASH_V1); + hash_payload->set_hash(hash_payload, hash); + this->payloads->insert_first(this->payloads, hash_payload); if (this->exchange_type == INFORMATIONAL_V1) { - DBG3(DBG_ENC, "encrypting IKEv1 INFORMATIONAL exchange message"); - this->is_encrypted = TRUE; - encrypted = TRUE; + this->is_encrypted = encrypted = TRUE; } - chunk_free(&hash); } - if (!encrypted) { - /* if at least one payload requires encryption, encrypt the message. - * if we have no key material available, the flag will be reset below */ + /* If at least one payload requires encryption, encrypt the message. + * If no key material is available, the flag will be reset below. */ enumerator = this->payloads->create_enumerator(this->payloads); while (enumerator->enumerate(enumerator, (void**)&payload)) { payload_rule_t *rule; + rule = get_payload_rule(this, payload->get_type(payload)); if (rule && rule->encrypted) { - this->is_encrypted = TRUE; - encrypted = TRUE; + this->is_encrypted = encrypted = TRUE; break; } } @@ -1495,8 +1497,7 @@ METHOD(message_t, generate, status_t, aead = keymat->get_aead(keymat, FALSE); if (aead && encrypted) { - encryption = wrap_payloads(this, this->is_encrypted ? ENCRYPTED_V1 - : ENCRYPTED); + encryption = wrap_payloads(this); } else { From 26b02f50f4fb53195ccfa4830abf30ae763b9183 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 10:12:52 +0100 Subject: [PATCH 353/534] Always use a transform number of 1 when encoding a single transform --- src/libcharon/encoding/payloads/proposal_substructure.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 57b948145..77a4fe434 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -1243,7 +1243,7 @@ proposal_substructure_t *proposal_substructure_create_from_proposal_v2( * See header. */ proposal_substructure_t *proposal_substructure_create_from_proposal_v1( - proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, auth_method_t auth, ipsec_mode_t mode, bool udp) { private_proposal_substructure_t *this; @@ -1253,11 +1253,11 @@ proposal_substructure_t *proposal_substructure_create_from_proposal_v1( switch (proposal->get_protocol(proposal)) { case PROTO_IKE: - set_from_proposal_v1_ike(this, proposal, lifetime, auth, 0); + set_from_proposal_v1_ike(this, proposal, lifetime, auth, 1); break; case PROTO_ESP: set_from_proposal_v1_esp(this, proposal, lifetime, - lifebytes, mode, udp, proposal->get_number(proposal)); + lifebytes, mode, udp, 1); break; default: break; From ef32c6866e306fe7c33d3c951c34a5616c81696f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 10:22:47 +0100 Subject: [PATCH 354/534] Removed obsolete XAuth job --- .../processing/jobs/initiate_xauth_job.c | 84 ------------------- .../processing/jobs/initiate_xauth_job.h | 49 ----------- 2 files changed, 133 deletions(-) delete mode 100644 src/libcharon/processing/jobs/initiate_xauth_job.c delete mode 100644 src/libcharon/processing/jobs/initiate_xauth_job.h diff --git a/src/libcharon/processing/jobs/initiate_xauth_job.c b/src/libcharon/processing/jobs/initiate_xauth_job.c deleted file mode 100644 index 98fbac039..000000000 --- a/src/libcharon/processing/jobs/initiate_xauth_job.c +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2007-2008 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * 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 "initiate_xauth_job.h" - -#include -#include - - -typedef struct private_initiate_xauth_job_t private_initiate_xauth_job_t; - -/** - * Private data of an initiate_xauth_job_t Object - */ -struct private_initiate_xauth_job_t { - /** - * public initiate_xauth_job_t interface - */ - initiate_xauth_job_t public; - - /** - * ID of the IKE_SA of the mediated connection. - */ - ike_sa_id_t *ike_sa_id; -}; - -METHOD(job_t, destroy, void, - private_initiate_xauth_job_t *this) -{ - DESTROY_IF(this->ike_sa_id); - free(this); -} - -METHOD(job_t, initiate, void, - private_initiate_xauth_job_t *this) -{ - ike_sa_t *ike_sa; - - ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, - this->ike_sa_id); - if (ike_sa) - { - ike_sa->initiate_xauth(ike_sa, TRUE); - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - } - destroy(this); -} - -METHOD(job_t, get_priority, job_priority_t, - private_initiate_xauth_job_t *this) -{ - return JOB_PRIO_MEDIUM; -} - -/** - * Creates an empty job - */ -initiate_xauth_job_t *initiate_xauth_job_create(ike_sa_id_t *ike_sa_id) -{ - private_initiate_xauth_job_t *this; - INIT(this, - .public = { - .job_interface = { - .get_priority = _get_priority, - .destroy = _destroy, - .execute = _initiate, - }, - }, - .ike_sa_id = ike_sa_id->clone(ike_sa_id), - ); - return &this->public; -} diff --git a/src/libcharon/processing/jobs/initiate_xauth_job.h b/src/libcharon/processing/jobs/initiate_xauth_job.h deleted file mode 100644 index 90271414d..000000000 --- a/src/libcharon/processing/jobs/initiate_xauth_job.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright (C) 2007-2008 Tobias Brunner - * Hochschule fuer Technik Rapperswil - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. See . - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ - -/** - * @defgroup initiate_xauth_job initiate_xauth_job - * @{ @ingroup cjobs - */ - -#ifndef INITIATE_XAUTH_JOB_H_ -#define INITIATE_XAUTH_JOB_H_ - -typedef struct initiate_xauth_job_t initiate_xauth_job_t; - -#include -#include - -/** - * Class representing a INITIATE_XAUTH Job. - * - * This job will an XAuth authentication exchange. - */ -struct initiate_xauth_job_t { - /** - * implements job_t interface - */ - job_t job_interface; -}; - -/** - * Creates a job of type INITIATE_XAUTH. - * - * @param ike_sa_id_t identification of the ike_sa as ike_sa_id_t object (gets cloned) - * @return job object - */ -initiate_xauth_job_t *initiate_xauth_job_create(ike_sa_id_t *ike_sa_id); - -#endif /** INITIATE_XAUTH_JOB_H_ @}*/ From 883306887710987a39a1367e153e7351eef225a5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 10:27:40 +0100 Subject: [PATCH 355/534] Doxygen fixes --- src/libcharon/encoding/payloads/cert_payload.h | 3 +-- src/libcharon/encoding/payloads/certreq_payload.h | 2 +- src/libcharon/encoding/payloads/id_payload.h | 2 +- src/libcharon/encoding/payloads/notify_payload.h | 2 +- src/libcharon/sa/authenticators/pubkey_v1_authenticator.h | 1 + src/libcharon/sa/tasks/informational.h | 1 + src/libcharon/sa/tasks/main_mode.h | 1 + src/libcharon/sa/tasks/quick_mode.h | 1 + 8 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libcharon/encoding/payloads/cert_payload.h b/src/libcharon/encoding/payloads/cert_payload.h index d85a463ca..19ed2ccd2 100644 --- a/src/libcharon/encoding/payloads/cert_payload.h +++ b/src/libcharon/encoding/payloads/cert_payload.h @@ -96,7 +96,6 @@ struct cert_payload_t { */ char *(*get_url)(cert_payload_t *this); - /** * Destroys the cert_payload object. */ @@ -107,7 +106,6 @@ struct cert_payload_t { * Creates an empty certificate payload. * * @param type payload type (for IKEv1 or IKEv2) - * @param cert certificate to embed * @return cert_payload_t object */ cert_payload_t *cert_payload_create(payload_type_t type); @@ -126,6 +124,7 @@ cert_payload_t *cert_payload_create_from_cert(payload_type_t type, * Creates an IKEv2 certificate payload with hash and URL encoding. * * @param hash hash of the DER encoded certificate (get's cloned) + * @param url URL to the certificate * @return cert_payload_t object */ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url); diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h index e234df5be..cce71c0ad 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.h +++ b/src/libcharon/encoding/payloads/certreq_payload.h @@ -92,7 +92,7 @@ certreq_payload_t *certreq_payload_create_type(certificate_type_t type); /** * Creates a IKEv1 certreq_payload_t for a given distinguished name. * - * @param dn distinguished name, does not get owned + * @param id distinguished name, does not get owned * @return certreq payload */ certreq_payload_t *certreq_payload_create_dn(identification_t *id); diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h index 94ed1cb38..9a6249429 100644 --- a/src/libcharon/encoding/payloads/id_payload.h +++ b/src/libcharon/encoding/payloads/id_payload.h @@ -73,7 +73,7 @@ struct id_payload_t { * @param type one of ID_INITIATOR, ID_RESPONDER, ID_V1 and NAT_OA_V1 * @return id_payload_t object */ -id_payload_t *id_payload_create(payload_type_t payload_type); +id_payload_t *id_payload_create(payload_type_t type); /** * Creates an id_payload_t from an existing identification_t object. diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index 214a6b795..c6d09daa7 100644 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -272,7 +272,7 @@ notify_payload_t *notify_payload_create(payload_type_t type); * * @param type payload type, NOTIFY or NOTIFY_V1 * @param protocol protocol id (IKE, AH or ESP) - * @param type notify type (see notify_type_t) + * @param notify type of notify * @return notify_payload_t object */ notify_payload_t *notify_payload_create_from_protocol_and_type( diff --git a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h index 48968d6a1..e71a81f18 100644 --- a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h +++ b/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h @@ -40,6 +40,7 @@ struct pubkey_v1_authenticator_t { * Create an authenticator to build and verify public key signatures. * * @param ike_sa associated IKE_SA + * @param initiator TRUE if we are IKE_SA initiator * @param dh diffie hellman key exchange * @param dh_value others public diffie hellman value * @param sa_payload generated SA payload data, without payload header diff --git a/src/libcharon/sa/tasks/informational.h b/src/libcharon/sa/tasks/informational.h index e9c32f647..2aec7abd8 100644 --- a/src/libcharon/sa/tasks/informational.h +++ b/src/libcharon/sa/tasks/informational.h @@ -42,6 +42,7 @@ struct informational_t { /** * Create a new informational task. * + * @param ike_sa IKE_SA this task works for * @param notify notify to send as initiator, NULL if responder * @return task to handle by the task_manager */ diff --git a/src/libcharon/sa/tasks/main_mode.h b/src/libcharon/sa/tasks/main_mode.h index d62501180..9ff253096 100644 --- a/src/libcharon/sa/tasks/main_mode.h +++ b/src/libcharon/sa/tasks/main_mode.h @@ -41,6 +41,7 @@ struct main_mode_t { /** * Create a new main_mode task. * + * @param ike_sa IKE_SA this task works for * @param initiator TRUE if task initiated locally * @return task to handle by the task_manager */ diff --git a/src/libcharon/sa/tasks/quick_mode.h b/src/libcharon/sa/tasks/quick_mode.h index 358296c2e..e50c1a97e 100644 --- a/src/libcharon/sa/tasks/quick_mode.h +++ b/src/libcharon/sa/tasks/quick_mode.h @@ -41,6 +41,7 @@ struct quick_mode_t { /** * Create a new quick_mode task. * + * @param ike_sa IKE_SA this task works for * @param config child_cfg if task initiator, NULL if responder * @param tsi source of triggering packet, or NULL * @param tsr destination of triggering packet, or NULL From 26a758ffcb378a10483d6a086b671e7cfeec3d14 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 11:33:06 +0100 Subject: [PATCH 356/534] Fixed fix for XAuth plugin feature matching --- src/libstrongswan/plugins/plugin_feature.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/plugins/plugin_feature.c b/src/libstrongswan/plugins/plugin_feature.c index 8b27c73c3..385e77b8b 100644 --- a/src/libstrongswan/plugins/plugin_feature.c +++ b/src/libstrongswan/plugins/plugin_feature.c @@ -98,7 +98,7 @@ bool plugin_feature_matches(plugin_feature_t *a, plugin_feature_t *b) return streq(a->arg.custom, b->arg.custom); case FEATURE_XAUTH_SERVER: case FEATURE_XAUTH_PEER: - return streq(a->arg.xauth == b->arg.xauth); + return streq(a->arg.xauth, b->arg.xauth); } } return FALSE; From 0aa2af5efc950cb205822b31947d143e8bdf5b31 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 11:12:27 +0100 Subject: [PATCH 357/534] Renamed ike_cert_post_v1 to isakmp_cert_post --- src/libcharon/Makefile.am | 2 +- src/libcharon/sa/ike_sa.c | 4 +-- src/libcharon/sa/task_manager_v1.c | 6 ++-- ...{ike_cert_post_v1.c => isakmp_cert_post.c} | 34 +++++++++---------- ...{ike_cert_post_v1.h => isakmp_cert_post.h} | 20 +++++------ src/libcharon/sa/tasks/task.c | 4 +-- src/libcharon/sa/tasks/task.h | 2 +- 7 files changed, 36 insertions(+), 36 deletions(-) rename src/libcharon/sa/tasks/{ike_cert_post_v1.c => isakmp_cert_post.c} (88%) rename src/libcharon/sa/tasks/{ike_cert_post_v1.h => isakmp_cert_post.h} (69%) diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 94ada5ae9..a58db1de0 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -85,7 +85,6 @@ sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ sa/tasks/ike_cert_pre_v1.c sa/tasks/ike_cert_pre_v1.h \ -sa/tasks/ike_cert_post_v1.c sa/tasks/ike_cert_post_v1.h \ sa/tasks/ike_config.c sa/tasks/ike_config.h \ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ @@ -100,6 +99,7 @@ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ sa/tasks/ike_vendor_v1.c sa/tasks/ike_vendor_v1.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/informational.c sa/tasks/informational.h \ +sa/tasks/isakmp_cert_post.c sa/tasks/isakmp_cert_post.h \ sa/tasks/isakmp_delete.c sa/tasks/isakmp_delete.h \ sa/tasks/xauth.c sa/tasks/xauth.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 04524b371..0a0f94df5 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -47,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -1125,7 +1125,7 @@ METHOD(ike_sa_t, initiate, status_t, this->task_manager->queue_task(this->task_manager, task); task = (task_t*)main_mode_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_post_v1_create(&this->public, TRUE); + task = (task_t*)isakmp_cert_post_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); task = (task_t*)ike_natd_v1_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index e18a070bf..7f6aa9f3c 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -304,7 +304,7 @@ METHOD(task_manager_t, initiate, status_t, if (activate_task(this, TASK_MAIN_MODE)) { exchange = ID_PROT; - activate_task(this, TASK_IKE_CERT_POST_V1); + activate_task(this, TASK_ISAKMP_CERT_POST); activate_task(this, TASK_IKE_NATD_V1); } break; @@ -664,7 +664,7 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_cert_post_v1_create(this->ike_sa, FALSE); + task = (task_t*)isakmp_cert_post_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)ike_natd_v1_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); diff --git a/src/libcharon/sa/tasks/ike_cert_post_v1.c b/src/libcharon/sa/tasks/isakmp_cert_post.c similarity index 88% rename from src/libcharon/sa/tasks/ike_cert_post_v1.c rename to src/libcharon/sa/tasks/isakmp_cert_post.c index 2c1c8750f..30e1c6d84 100644 --- a/src/libcharon/sa/tasks/ike_cert_post_v1.c +++ b/src/libcharon/sa/tasks/isakmp_cert_post.c @@ -13,7 +13,7 @@ * for more details. */ -#include "ike_cert_post_v1.h" +#include "isakmp_cert_post.h" #include #include @@ -24,17 +24,17 @@ #include -typedef struct private_ike_cert_post_v1_t private_ike_cert_post_v1_t; +typedef struct private_isakmp_cert_post_t private_isakmp_cert_post_t; /** - * Private members of a ike_cert_post_v1_t task. + * Private members of a isakmp_cert_post_t task. */ -struct private_ike_cert_post_v1_t { +struct private_isakmp_cert_post_t { /** * Public methods and task_t interface. */ - ike_cert_post_v1_t public; + isakmp_cert_post_t public; /** * Assigned IKE_SA. @@ -59,7 +59,7 @@ struct private_ike_cert_post_v1_t { /** * Check if we actually use certificates for authentication */ -static bool use_certs(private_ike_cert_post_v1_t *this, message_t *message) +static bool use_certs(private_isakmp_cert_post_t *this, message_t *message) { enumerator_t *enumerator; payload_t *payload; @@ -95,7 +95,7 @@ static bool use_certs(private_ike_cert_post_v1_t *this, message_t *message) /** * Add certificates to message */ -static void build_certs(private_ike_cert_post_v1_t *this, message_t *message) +static void build_certs(private_isakmp_cert_post_t *this, message_t *message) { peer_cfg_t *peer_cfg; @@ -158,7 +158,7 @@ static void build_certs(private_ike_cert_post_v1_t *this, message_t *message) } METHOD(task_t, build_i, status_t, - private_ike_cert_post_v1_t *this, message_t *message) + private_isakmp_cert_post_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -182,7 +182,7 @@ METHOD(task_t, build_i, status_t, } METHOD(task_t, process_r, status_t, - private_ike_cert_post_v1_t *this, message_t *message) + private_isakmp_cert_post_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -224,7 +224,7 @@ METHOD(task_t, process_r, status_t, } METHOD(task_t, build_r, status_t, - private_ike_cert_post_v1_t *this, message_t *message) + private_isakmp_cert_post_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -259,7 +259,7 @@ METHOD(task_t, build_r, status_t, } METHOD(task_t, process_i, status_t, - private_ike_cert_post_v1_t *this, message_t *message) + private_isakmp_cert_post_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -298,19 +298,19 @@ METHOD(task_t, process_i, status_t, } METHOD(task_t, get_type, task_type_t, - private_ike_cert_post_v1_t *this) + private_isakmp_cert_post_t *this) { - return TASK_IKE_CERT_POST_V1; + return TASK_ISAKMP_CERT_POST; } METHOD(task_t, migrate, void, - private_ike_cert_post_v1_t *this, ike_sa_t *ike_sa) + private_isakmp_cert_post_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; } METHOD(task_t, destroy, void, - private_ike_cert_post_v1_t *this) + private_isakmp_cert_post_t *this) { free(this); } @@ -318,9 +318,9 @@ METHOD(task_t, destroy, void, /* * Described in header. */ -ike_cert_post_v1_t *ike_cert_post_v1_create(ike_sa_t *ike_sa, bool initiator) +isakmp_cert_post_t *isakmp_cert_post_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_cert_post_v1_t *this; + private_isakmp_cert_post_t *this; INIT(this, .public = { diff --git a/src/libcharon/sa/tasks/ike_cert_post_v1.h b/src/libcharon/sa/tasks/isakmp_cert_post.h similarity index 69% rename from src/libcharon/sa/tasks/ike_cert_post_v1.h rename to src/libcharon/sa/tasks/isakmp_cert_post.h index 58b7aa78f..6720c54e0 100644 --- a/src/libcharon/sa/tasks/ike_cert_post_v1.h +++ b/src/libcharon/sa/tasks/isakmp_cert_post.h @@ -14,23 +14,23 @@ */ /** - * @defgroup ike_cert_post_v1 ike_cert_post_v1 + * @defgroup isakmp_cert_post isakmp_cert_post * @{ @ingroup tasks */ -#ifndef IKE_CERT_POST_V1_H_ -#define IKE_CERT_POST_V1_H_ +#ifndef ISAKMP_CERT_POST_H_ +#define ISAKMP_CERT_POST_H_ -typedef struct ike_cert_post_v1_t ike_cert_post_v1_t; +typedef struct isakmp_cert_post_t isakmp_cert_post_t; #include #include #include /** - * IKE_CERT_POST_V1, IKEv1 certificate processing after authentication. + * ISAKMP_CERT_POST, IKEv1 certificate processing after authentication. */ -struct ike_cert_post_v1_t { +struct isakmp_cert_post_t { /** * Implements the task_t interface @@ -39,15 +39,15 @@ struct ike_cert_post_v1_t { }; /** - * Create a new ike_cert_post_v1 task. + * Create a new isakmp_cert_post task. * * The initiator parameter means the original initiator, not the initiator * of the certificate request. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if task is the original initiator - * @return ike_cert_post_v1 task to handle by the task_manager + * @return isakmp_cert_post task to handle by the task_manager */ -ike_cert_post_v1_t *ike_cert_post_v1_create(ike_sa_t *ike_sa, bool initiator); +isakmp_cert_post_t *isakmp_cert_post_create(ike_sa_t *ike_sa, bool initiator); -#endif /** IKE_CERT_POST_V1_H_ @}*/ +#endif /** ISAKMP_CERT_POST_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index 5a7035287..a3a848995 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -16,7 +16,7 @@ #include "task.h" -ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, +ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST, "IKE_INIT", "IKE_NATD", "IKE_MOBIKE", @@ -46,5 +46,5 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_IKE_CERT_POST_V1, "VENDOR_V1", "IKE_NATD_V1", "IKE_CERT_PRE_V1", - "IKE_CERT_POST_V1", + "ISAKMP_CERT_POST", ); diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 55c8b728c..0af8ea7ec 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -90,7 +90,7 @@ enum task_type_t { /** IKEv1 pre-authentication certificate handling */ TASK_IKE_CERT_PRE_V1, /** IKEv1 post-authentication certificate handling */ - TASK_IKE_CERT_POST_V1, + TASK_ISAKMP_CERT_POST, }; /** From 824dc0adad5f5dca52129079a81699c482afecc9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 11:17:31 +0100 Subject: [PATCH 358/534] Renamed ike_cert_pre_v1 to isakmp_cert_pre --- src/libcharon/Makefile.am | 2 +- src/libcharon/sa/ike_sa.c | 4 +- src/libcharon/sa/task_manager_v1.c | 6 +-- .../{ike_cert_pre_v1.c => isakmp_cert_pre.c} | 44 +++++++++---------- .../{ike_cert_pre_v1.h => isakmp_cert_pre.h} | 20 ++++----- src/libcharon/sa/tasks/task.c | 2 +- src/libcharon/sa/tasks/task.h | 2 +- 7 files changed, 40 insertions(+), 40 deletions(-) rename src/libcharon/sa/tasks/{ike_cert_pre_v1.c => isakmp_cert_pre.c} (90%) rename src/libcharon/sa/tasks/{ike_cert_pre_v1.h => isakmp_cert_pre.h} (70%) diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index a58db1de0..10992d703 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -84,7 +84,6 @@ sa/tasks/child_rekey.c sa/tasks/child_rekey.h \ sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ -sa/tasks/ike_cert_pre_v1.c sa/tasks/ike_cert_pre_v1.h \ sa/tasks/ike_config.c sa/tasks/ike_config.h \ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ @@ -99,6 +98,7 @@ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ sa/tasks/ike_vendor_v1.c sa/tasks/ike_vendor_v1.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/informational.c sa/tasks/informational.h \ +sa/tasks/isakmp_cert_pre.c sa/tasks/isakmp_cert_pre.h \ sa/tasks/isakmp_cert_post.c sa/tasks/isakmp_cert_post.h \ sa/tasks/isakmp_delete.c sa/tasks/isakmp_delete.h \ sa/tasks/xauth.c sa/tasks/xauth.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 0a0f94df5..fe4e91dfc 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -46,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -1121,7 +1121,7 @@ METHOD(ike_sa_t, initiate, status_t, { task = (task_t*)ike_vendor_v1_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_pre_v1_create(&this->public, TRUE); + task = (task_t*)isakmp_cert_pre_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); task = (task_t*)main_mode_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 7f6aa9f3c..03c68fc5b 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include @@ -300,7 +300,7 @@ METHOD(task_manager_t, initiate, status_t, { case IKE_CREATED: activate_task(this, TASK_VENDOR_V1); - activate_task(this, TASK_IKE_CERT_PRE_V1); + activate_task(this, TASK_ISAKMP_CERT_PRE); if (activate_task(this, TASK_MAIN_MODE)) { exchange = ID_PROT; @@ -660,7 +660,7 @@ static status_t process_request(private_task_manager_t *this, case ID_PROT: task = (task_t *)ike_vendor_v1_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t*)ike_cert_pre_v1_create(this->ike_sa, FALSE); + task = (task_t*)isakmp_cert_pre_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t *)main_mode_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); diff --git a/src/libcharon/sa/tasks/ike_cert_pre_v1.c b/src/libcharon/sa/tasks/isakmp_cert_pre.c similarity index 90% rename from src/libcharon/sa/tasks/ike_cert_pre_v1.c rename to src/libcharon/sa/tasks/isakmp_cert_pre.c index 0220650b2..db25bf3a3 100644 --- a/src/libcharon/sa/tasks/ike_cert_pre_v1.c +++ b/src/libcharon/sa/tasks/isakmp_cert_pre.c @@ -13,7 +13,7 @@ * for more details. */ -#include "ike_cert_pre_v1.h" +#include "isakmp_cert_pre.h" #include #include @@ -23,17 +23,17 @@ #include -typedef struct private_ike_cert_pre_v1_t private_ike_cert_pre_v1_t; +typedef struct private_isakmp_cert_pre_t private_isakmp_cert_pre_t; /** - * Private members of a ike_cert_pre_v1_t task. + * Private members of a isakmp_cert_pre_t task. */ -struct private_ike_cert_pre_v1_t { +struct private_isakmp_cert_pre_t { /** * Public methods and task_t interface. */ - ike_cert_pre_v1_t public; + isakmp_cert_pre_t public; /** * Assigned IKE_SA. @@ -61,7 +61,7 @@ struct private_ike_cert_pre_v1_t { /** * Find the CA certificate for a given certreq payload */ -static certificate_t* find_certificate(private_ike_cert_pre_v1_t *this, +static certificate_t* find_certificate(private_isakmp_cert_pre_t *this, certreq_payload_t *certreq) { identification_t *id; @@ -98,7 +98,7 @@ static certificate_t* find_certificate(private_ike_cert_pre_v1_t *this, /** * read certificate requests */ -static void process_certreqs(private_ike_cert_pre_v1_t *this, message_t *message) +static void process_certreqs(private_isakmp_cert_pre_t *this, message_t *message) { enumerator_t *enumerator; payload_t *payload; @@ -134,7 +134,7 @@ static void process_certreqs(private_ike_cert_pre_v1_t *this, message_t *message /** * Import receuved certificates */ -static void process_certs(private_ike_cert_pre_v1_t *this, message_t *message) +static void process_certs(private_isakmp_cert_pre_t *this, message_t *message) { enumerator_t *enumerator; payload_t *payload; @@ -209,7 +209,7 @@ static void process_certs(private_ike_cert_pre_v1_t *this, message_t *message) /** * Add the subject of a CA certificate a message */ -static void add_certreq(private_ike_cert_pre_v1_t *this, message_t *message, +static void add_certreq(private_isakmp_cert_pre_t *this, message_t *message, certificate_t *cert) { if (cert->get_type(cert) == CERT_X509) @@ -229,7 +229,7 @@ static void add_certreq(private_ike_cert_pre_v1_t *this, message_t *message, /** * Add auth_cfg's CA certificates to the certificate request */ -static void add_certreqs(private_ike_cert_pre_v1_t *this, +static void add_certreqs(private_isakmp_cert_pre_t *this, auth_cfg_t *auth, message_t *message) { enumerator_t *enumerator; @@ -254,7 +254,7 @@ static void add_certreqs(private_ike_cert_pre_v1_t *this, /** * Build certificate requests */ -static void build_certreqs(private_ike_cert_pre_v1_t *this, message_t *message) +static void build_certreqs(private_isakmp_cert_pre_t *this, message_t *message) { enumerator_t *enumerator; ike_cfg_t *ike_cfg; @@ -294,7 +294,7 @@ static void build_certreqs(private_ike_cert_pre_v1_t *this, message_t *message) /** * Check if we actually use certificates for authentication */ -static bool use_certs(private_ike_cert_pre_v1_t *this, message_t *message) +static bool use_certs(private_isakmp_cert_pre_t *this, message_t *message) { enumerator_t *enumerator; payload_t *payload; @@ -333,7 +333,7 @@ static bool use_certs(private_ike_cert_pre_v1_t *this, message_t *message) } METHOD(task_t, build_i, status_t, - private_ike_cert_pre_v1_t *this, message_t *message) + private_isakmp_cert_pre_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -355,7 +355,7 @@ METHOD(task_t, build_i, status_t, } METHOD(task_t, process_r, status_t, - private_ike_cert_pre_v1_t *this, message_t *message) + private_isakmp_cert_pre_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -402,7 +402,7 @@ METHOD(task_t, process_r, status_t, } METHOD(task_t, build_r, status_t, - private_ike_cert_pre_v1_t *this, message_t *message) + private_isakmp_cert_pre_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -439,7 +439,7 @@ METHOD(task_t, build_r, status_t, } METHOD(task_t, process_i, status_t, - private_ike_cert_pre_v1_t *this, message_t *message) + private_isakmp_cert_pre_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -482,19 +482,19 @@ METHOD(task_t, process_i, status_t, } METHOD(task_t, get_type, task_type_t, - private_ike_cert_pre_v1_t *this) + private_isakmp_cert_pre_t *this) { - return TASK_IKE_CERT_PRE_V1; + return TASK_ISAKMP_CERT_PRE; } METHOD(task_t, migrate, void, - private_ike_cert_pre_v1_t *this, ike_sa_t *ike_sa) + private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; } METHOD(task_t, destroy, void, - private_ike_cert_pre_v1_t *this) + private_isakmp_cert_pre_t *this) { free(this); } @@ -502,9 +502,9 @@ METHOD(task_t, destroy, void, /* * Described in header. */ -ike_cert_pre_v1_t *ike_cert_pre_v1_create(ike_sa_t *ike_sa, bool initiator) +isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_cert_pre_v1_t *this; + private_isakmp_cert_pre_t *this; INIT(this, .public = { diff --git a/src/libcharon/sa/tasks/ike_cert_pre_v1.h b/src/libcharon/sa/tasks/isakmp_cert_pre.h similarity index 70% rename from src/libcharon/sa/tasks/ike_cert_pre_v1.h rename to src/libcharon/sa/tasks/isakmp_cert_pre.h index 38042ccf2..c6dc98ac5 100644 --- a/src/libcharon/sa/tasks/ike_cert_pre_v1.h +++ b/src/libcharon/sa/tasks/isakmp_cert_pre.h @@ -14,23 +14,23 @@ */ /** - * @defgroup ike_cert_pre_v1 ike_cert_pre_v1 + * @defgroup isakmp_cert_pre isakmp_cert_pre * @{ @ingroup tasks */ -#ifndef IKE_CERT_PRE_V1_H_ -#define IKE_CERT_PRE_V1_H_ +#ifndef ISAKMP_CERT_PRE_H_ +#define ISAKMP_CERT_PRE_H_ -typedef struct ike_cert_pre_v1_t ike_cert_pre_v1_t; +typedef struct isakmp_cert_pre_t isakmp_cert_pre_t; #include #include #include /** - * IKE_CERT_PRE_V1 task, IKEv1 certificate processing before authentication. + * ISAKMP_CERT_PRE task, IKEv1 certificate processing before authentication. */ -struct ike_cert_pre_v1_t { +struct isakmp_cert_pre_t { /** * Implements the task_t interface @@ -39,15 +39,15 @@ struct ike_cert_pre_v1_t { }; /** - * Create a new IKE_CERT_PRE_V1 task. + * Create a new ISAKMP_CERT_PRE task. * * The initiator parameter means the original initiator, not the initiator * of the certificate request. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if task is the original initiator - * @return ike_cert_pre_v1 task to handle by the task_manager + * @return isakmp_cert_pre task to handle by the task_manager */ -ike_cert_pre_v1_t *ike_cert_pre_v1_create(ike_sa_t *ike_sa, bool initiator); +isakmp_cert_pre_t *isakmp_cert_pre_create(ike_sa_t *ike_sa, bool initiator); -#endif /** IIKE_CERT_PRE_V1_H_ @}*/ +#endif /** ISAKMP_CERT_PRE_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index a3a848995..e635d539e 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -45,6 +45,6 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST, "QUICK_DELETE", "VENDOR_V1", "IKE_NATD_V1", - "IKE_CERT_PRE_V1", + "ISAKMP_CERT_PRE", "ISAKMP_CERT_POST", ); diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 0af8ea7ec..503377550 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -88,7 +88,7 @@ enum task_type_t { /** IKEv1 NAT detection */ TASK_IKE_NATD_V1, /** IKEv1 pre-authentication certificate handling */ - TASK_IKE_CERT_PRE_V1, + TASK_ISAKMP_CERT_PRE, /** IKEv1 post-authentication certificate handling */ TASK_ISAKMP_CERT_POST, }; From 79d6fc7f720cedfd6483b880425288ae0616266d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 11:24:03 +0100 Subject: [PATCH 359/534] Renamed ike_natd_v1 to isakmp_natd --- src/libcharon/Makefile.am | 2 +- src/libcharon/sa/ike_sa.c | 4 +- src/libcharon/sa/task_manager_v1.c | 6 +-- .../sa/tasks/{ike_natd_v1.c => isakmp_natd.c} | 38 +++++++++---------- .../sa/tasks/{ike_natd_v1.h => isakmp_natd.h} | 20 +++++----- src/libcharon/sa/tasks/task.c | 2 +- src/libcharon/sa/tasks/task.h | 2 +- 7 files changed, 37 insertions(+), 37 deletions(-) rename src/libcharon/sa/tasks/{ike_natd_v1.c => isakmp_natd.c} (91%) rename src/libcharon/sa/tasks/{ike_natd_v1.h => isakmp_natd.h} (69%) diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 10992d703..0edb674ed 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -89,7 +89,6 @@ sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ sa/tasks/ike_init.c sa/tasks/ike_init.h \ sa/tasks/ike_natd.c sa/tasks/ike_natd.h \ -sa/tasks/ike_natd_v1.c sa/tasks/ike_natd_v1.h \ sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \ sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ @@ -100,6 +99,7 @@ sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/informational.c sa/tasks/informational.h \ sa/tasks/isakmp_cert_pre.c sa/tasks/isakmp_cert_pre.h \ sa/tasks/isakmp_cert_post.c sa/tasks/isakmp_cert_post.h \ +sa/tasks/isakmp_natd.c sa/tasks/isakmp_natd.h \ sa/tasks/isakmp_delete.c sa/tasks/isakmp_delete.h \ sa/tasks/xauth.c sa/tasks/xauth.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index fe4e91dfc..b1ef154ad 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -47,9 +47,9 @@ #include #include #include +#include #include #include -#include #include #include #include @@ -1127,7 +1127,7 @@ METHOD(ike_sa_t, initiate, status_t, this->task_manager->queue_task(this->task_manager, task); task = (task_t*)isakmp_cert_post_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_natd_v1_create(&this->public, TRUE); + task = (task_t*)isakmp_natd_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); } else diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index 03c68fc5b..ab029bdcb 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -24,7 +24,7 @@ #include #include #include -#include +#include #include #include #include @@ -305,7 +305,7 @@ METHOD(task_manager_t, initiate, status_t, { exchange = ID_PROT; activate_task(this, TASK_ISAKMP_CERT_POST); - activate_task(this, TASK_IKE_NATD_V1); + activate_task(this, TASK_ISAKMP_NATD); } break; case IKE_CONNECTING: @@ -666,7 +666,7 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)isakmp_cert_post_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); - task = (task_t *)ike_natd_v1_create(this->ike_sa, FALSE); + task = (task_t *)isakmp_natd_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); break; case AGGRESSIVE: diff --git a/src/libcharon/sa/tasks/ike_natd_v1.c b/src/libcharon/sa/tasks/isakmp_natd.c similarity index 91% rename from src/libcharon/sa/tasks/ike_natd_v1.c rename to src/libcharon/sa/tasks/isakmp_natd.c index d7f957d50..b956ff66f 100644 --- a/src/libcharon/sa/tasks/ike_natd_v1.c +++ b/src/libcharon/sa/tasks/isakmp_natd.c @@ -15,7 +15,7 @@ * for more details. */ -#include "ike_natd_v1.h" +#include "isakmp_natd.h" #include @@ -26,17 +26,17 @@ #include #include -typedef struct private_ike_natd_v1_t private_ike_natd_v1_t; +typedef struct private_isakmp_natd_t private_isakmp_natd_t; /** * Private members of a ike_natt_t task. */ -struct private_ike_natd_v1_t { +struct private_isakmp_natd_t { /** * Public interface. */ - ike_natd_v1_t public; + isakmp_natd_t public; /** * Assigned IKE_SA. @@ -77,7 +77,7 @@ struct private_ike_natd_v1_t { /** * Build NAT detection hash for a host. */ -static chunk_t generate_natd_hash(private_ike_natd_v1_t *this, +static chunk_t generate_natd_hash(private_isakmp_natd_t *this, ike_sa_id_t *ike_sa_id, host_t *host) { hasher_t *hasher; @@ -110,7 +110,7 @@ static chunk_t generate_natd_hash(private_ike_natd_v1_t *this, /** * Build a faked NAT-D payload to enforce UDP encapsulation. */ -static chunk_t generate_natd_hash_faked(private_ike_natd_v1_t *this) +static chunk_t generate_natd_hash_faked(private_isakmp_natd_t *this) { hasher_t *hasher; chunk_t chunk; @@ -136,7 +136,7 @@ static chunk_t generate_natd_hash_faked(private_ike_natd_v1_t *this) /** * Build a NAT-D payload. */ -static hash_payload_t *build_natd_payload(private_ike_natd_v1_t *this, bool src, +static hash_payload_t *build_natd_payload(private_isakmp_natd_t *this, bool src, host_t *host) { hash_payload_t *payload; @@ -162,7 +162,7 @@ static hash_payload_t *build_natd_payload(private_ike_natd_v1_t *this, bool src, /** * Add NAT-D payloads to the message. */ -static void add_natd_payloads(private_ike_natd_v1_t *this, message_t *message) +static void add_natd_payloads(private_isakmp_natd_t *this, message_t *message) { hash_payload_t *payload; host_t *host; @@ -183,7 +183,7 @@ static void add_natd_payloads(private_ike_natd_v1_t *this, message_t *message) /** * Read NAT-D payloads from message and evaluate them. */ -static void process_payloads(private_ike_natd_v1_t *this, message_t *message) +static void process_payloads(private_isakmp_natd_t *this, message_t *message) { enumerator_t *enumerator; payload_t *payload; @@ -255,7 +255,7 @@ static void process_payloads(private_ike_natd_v1_t *this, message_t *message) } METHOD(task_t, build_i, status_t, - private_ike_natd_v1_t *this, message_t *message) + private_isakmp_natd_t *this, message_t *message) { status_t result = NEED_MORE; @@ -284,7 +284,7 @@ METHOD(task_t, build_i, status_t, } METHOD(task_t, process_i, status_t, - private_ike_natd_v1_t *this, message_t *message) + private_isakmp_natd_t *this, message_t *message) { status_t result = NEED_MORE; @@ -323,7 +323,7 @@ METHOD(task_t, process_i, status_t, } METHOD(task_t, process_r, status_t, - private_ike_natd_v1_t *this, message_t *message) + private_isakmp_natd_t *this, message_t *message) { status_t result = NEED_MORE; @@ -357,7 +357,7 @@ METHOD(task_t, process_r, status_t, } METHOD(task_t, build_r, status_t, - private_ike_natd_v1_t *this, message_t *message) + private_isakmp_natd_t *this, message_t *message) { switch (message->get_exchange_type(message)) { @@ -384,13 +384,13 @@ METHOD(task_t, build_r, status_t, } METHOD(task_t, get_type, task_type_t, - private_ike_natd_v1_t *this) + private_isakmp_natd_t *this) { - return TASK_IKE_NATD_V1; + return TASK_ISAKMP_NATD; } METHOD(task_t, migrate, void, - private_ike_natd_v1_t *this, ike_sa_t *ike_sa) + private_isakmp_natd_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; this->src_seen = FALSE; @@ -400,7 +400,7 @@ METHOD(task_t, migrate, void, } METHOD(task_t, destroy, void, - private_ike_natd_v1_t *this) + private_isakmp_natd_t *this) { free(this); } @@ -408,9 +408,9 @@ METHOD(task_t, destroy, void, /* * Described in header. */ -ike_natd_v1_t *ike_natd_v1_create(ike_sa_t *ike_sa, bool initiator) +isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_natd_v1_t *this; + private_isakmp_natd_t *this; INIT(this, .public = { diff --git a/src/libcharon/sa/tasks/ike_natd_v1.h b/src/libcharon/sa/tasks/isakmp_natd.h similarity index 69% rename from src/libcharon/sa/tasks/ike_natd_v1.h rename to src/libcharon/sa/tasks/isakmp_natd.h index a59054fb0..3d5df7e5a 100644 --- a/src/libcharon/sa/tasks/ike_natd_v1.h +++ b/src/libcharon/sa/tasks/isakmp_natd.h @@ -14,23 +14,23 @@ */ /** - * @defgroup ike_natd_v1 ike_natd_v1 + * @defgroup isakmp_natd isakmp_natd * @{ @ingroup tasks */ -#ifndef IKE_NATD_V1_H_ -#define IKE_NATD_V1_H_ +#ifndef ISAKMP_NATD_H_ +#define ISAKMP_NATD_H_ -typedef struct ike_natd_v1_t ike_natd_v1_t; +typedef struct isakmp_natd_t isakmp_natd_t; #include #include #include /** - * Task of type ike_natd_v1, detects NAT situation in IKEv1 Phase 1. + * Task of type ISAKMP_NATD, detects NAT situation in IKEv1 Phase 1. */ -struct ike_natd_v1_t { +struct isakmp_natd_t { /** * Implements the task_t interface @@ -39,12 +39,12 @@ struct ike_natd_v1_t { }; /** - * Create a new ike_natd_v1 task. + * Create a new ISAKMP_NATD task. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if task is the original initiator - * @return ike_natd_v1 task to handle by the task_manager + * @return isakmp_natd task to handle by the task_manager */ -ike_natd_v1_t *ike_natd_v1_create(ike_sa_t *ike_sa, bool initiator); +isakmp_natd_t *isakmp_natd_create(ike_sa_t *ike_sa, bool initiator); -#endif /** IKE_NATD_V1_H_ @}*/ +#endif /** ISAKMP_NATD_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index e635d539e..c3e67e3f4 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -44,7 +44,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST, "QUICK_MODE", "QUICK_DELETE", "VENDOR_V1", - "IKE_NATD_V1", + "ISAKMP_NATD", "ISAKMP_CERT_PRE", "ISAKMP_CERT_POST", ); diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index 503377550..a45cff9cc 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -86,7 +86,7 @@ enum task_type_t { /** IKEv1 vendor ID payload handling */ TASK_VENDOR_V1, /** IKEv1 NAT detection */ - TASK_IKE_NATD_V1, + TASK_ISAKMP_NATD, /** IKEv1 pre-authentication certificate handling */ TASK_ISAKMP_CERT_PRE, /** IKEv1 post-authentication certificate handling */ From 2e3c9f879906dea18d1745d7dfd1d21dd4499160 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 11:28:54 +0100 Subject: [PATCH 360/534] Renamed ike_vendor_v1 to isakmp_vendor --- src/libcharon/Makefile.am | 2 +- src/libcharon/sa/ike_sa.c | 4 +-- src/libcharon/sa/task_manager_v1.c | 6 ++-- .../{ike_vendor_v1.c => isakmp_vendor.c} | 28 +++++++++---------- .../{ike_vendor_v1.h => isakmp_vendor.h} | 16 +++++------ src/libcharon/sa/tasks/task.c | 2 +- src/libcharon/sa/tasks/task.h | 2 +- 7 files changed, 30 insertions(+), 30 deletions(-) rename src/libcharon/sa/tasks/{ike_vendor_v1.c => isakmp_vendor.c} (88%) rename src/libcharon/sa/tasks/{ike_vendor_v1.h => isakmp_vendor.h} (76%) diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 0edb674ed..95bec0966 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -94,12 +94,12 @@ sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ -sa/tasks/ike_vendor_v1.c sa/tasks/ike_vendor_v1.h \ sa/tasks/main_mode.c sa/tasks/main_mode.h \ sa/tasks/informational.c sa/tasks/informational.h \ sa/tasks/isakmp_cert_pre.c sa/tasks/isakmp_cert_pre.h \ sa/tasks/isakmp_cert_post.c sa/tasks/isakmp_cert_post.h \ sa/tasks/isakmp_natd.c sa/tasks/isakmp_natd.h \ +sa/tasks/isakmp_vendor.c sa/tasks/isakmp_vendor.h \ sa/tasks/isakmp_delete.c sa/tasks/isakmp_delete.h \ sa/tasks/xauth.c sa/tasks/xauth.h \ sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index b1ef154ad..331b001bf 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -50,7 +50,7 @@ #include #include #include -#include +#include #include #include #include @@ -1119,7 +1119,7 @@ METHOD(ike_sa_t, initiate, status_t, if (this->version == IKEV1) { - task = (task_t*)ike_vendor_v1_create(&this->public, TRUE); + task = (task_t*)isakmp_vendor_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); task = (task_t*)isakmp_cert_pre_create(&this->public, TRUE); this->task_manager->queue_task(this->task_manager, task); diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/task_manager_v1.c index ab029bdcb..dea4dcb87 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/task_manager_v1.c @@ -25,7 +25,7 @@ #include #include #include -#include +#include #include #include #include @@ -299,7 +299,7 @@ METHOD(task_manager_t, initiate, status_t, switch (this->ike_sa->get_state(this->ike_sa)) { case IKE_CREATED: - activate_task(this, TASK_VENDOR_V1); + activate_task(this, TASK_ISAKMP_VENDOR); activate_task(this, TASK_ISAKMP_CERT_PRE); if (activate_task(this, TASK_MAIN_MODE)) { @@ -658,7 +658,7 @@ static status_t process_request(private_task_manager_t *this, switch (message->get_exchange_type(message)) { case ID_PROT: - task = (task_t *)ike_vendor_v1_create(this->ike_sa, FALSE); + task = (task_t *)isakmp_vendor_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); task = (task_t*)isakmp_cert_pre_create(this->ike_sa, FALSE); this->passive_tasks->insert_last(this->passive_tasks, task); diff --git a/src/libcharon/sa/tasks/ike_vendor_v1.c b/src/libcharon/sa/tasks/isakmp_vendor.c similarity index 88% rename from src/libcharon/sa/tasks/ike_vendor_v1.c rename to src/libcharon/sa/tasks/isakmp_vendor.c index 8a756312f..a1d64863c 100644 --- a/src/libcharon/sa/tasks/ike_vendor_v1.c +++ b/src/libcharon/sa/tasks/isakmp_vendor.c @@ -13,22 +13,22 @@ * for more details. */ -#include "ike_vendor_v1.h" +#include "isakmp_vendor.h" #include #include -typedef struct private_ike_vendor_v1_t private_ike_vendor_v1_t; +typedef struct private_isakmp_vendor_t private_isakmp_vendor_t; /** - * Private data of an ike_vendor_v1_t object. + * Private data of an isakmp_vendor_t object. */ -struct private_ike_vendor_v1_t { +struct private_isakmp_vendor_t { /** - * Public ike_vendor_v1_t interface. + * Public isakmp_vendor_t interface. */ - ike_vendor_v1_t public; + isakmp_vendor_t public; /** * Associated IKE_SA @@ -96,7 +96,7 @@ static struct { }; METHOD(task_t, build, status_t, - private_ike_vendor_v1_t *this, message_t *message) + private_isakmp_vendor_t *this, message_t *message) { vendor_id_payload_t *vid_payload; bool strongswan; @@ -118,7 +118,7 @@ METHOD(task_t, build, status_t, } METHOD(task_t, process, status_t, - private_ike_vendor_v1_t *this, message_t *message) + private_isakmp_vendor_t *this, message_t *message) { enumerator_t *enumerator; payload_t *payload; @@ -162,19 +162,19 @@ METHOD(task_t, process, status_t, } METHOD(task_t, migrate, void, - private_ike_vendor_v1_t *this, ike_sa_t *ike_sa) + private_isakmp_vendor_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; } METHOD(task_t, get_type, task_type_t, - private_ike_vendor_v1_t *this) + private_isakmp_vendor_t *this) { - return TASK_VENDOR_V1; + return TASK_ISAKMP_VENDOR; } METHOD(task_t, destroy, void, - private_ike_vendor_v1_t *this) + private_isakmp_vendor_t *this) { free(this); } @@ -182,9 +182,9 @@ METHOD(task_t, destroy, void, /** * See header */ -ike_vendor_v1_t *ike_vendor_v1_create(ike_sa_t *ike_sa, bool initiator) +isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator) { - private_ike_vendor_v1_t *this; + private_isakmp_vendor_t *this; INIT(this, .public = { diff --git a/src/libcharon/sa/tasks/ike_vendor_v1.h b/src/libcharon/sa/tasks/isakmp_vendor.h similarity index 76% rename from src/libcharon/sa/tasks/ike_vendor_v1.h rename to src/libcharon/sa/tasks/isakmp_vendor.h index 60e96ebdc..e6ceb2e6d 100644 --- a/src/libcharon/sa/tasks/ike_vendor_v1.h +++ b/src/libcharon/sa/tasks/isakmp_vendor.h @@ -14,14 +14,14 @@ */ /** - * @defgroup ike_vendor_v1 ike_vendor_v1 + * @defgroup isakmp_vendor isakmp_vendor * @{ @ingroup tasks */ -#ifndef IKE_VENDOR_V1_H_ -#define IKE_VENDOR_V1_H_ +#ifndef ISAKMP_VENDOR_H_ +#define ISAKMP_VENDOR_H_ -typedef struct ike_vendor_v1_t ike_vendor_v1_t; +typedef struct isakmp_vendor_t isakmp_vendor_t; #include #include @@ -30,7 +30,7 @@ typedef struct ike_vendor_v1_t ike_vendor_v1_t; /** * Vendor ID processing task for IKEv1. */ -struct ike_vendor_v1_t { +struct isakmp_vendor_t { /** * Implements task interface. @@ -39,11 +39,11 @@ struct ike_vendor_v1_t { }; /** - * Create a ike_vendor_v1 instance. + * Create a isakmp_vendor instance. * * @param ike_sa IKE_SA this task works for * @param initiator TRUE if task is the original initiator */ -ike_vendor_v1_t *ike_vendor_v1_create(ike_sa_t *ike_sa, bool initiator); +isakmp_vendor_t *isakmp_vendor_create(ike_sa_t *ike_sa, bool initiator); -#endif /** ike_vendor_v1_H_ @}*/ +#endif /** ISAKMP_VENDOR_H_ @}*/ diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/tasks/task.c index c3e67e3f4..ce61c4088 100644 --- a/src/libcharon/sa/tasks/task.c +++ b/src/libcharon/sa/tasks/task.c @@ -43,7 +43,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST, "MODE_CONFIG", "QUICK_MODE", "QUICK_DELETE", - "VENDOR_V1", + "ISAKMP_VENDOR", "ISAKMP_NATD", "ISAKMP_CERT_PRE", "ISAKMP_CERT_POST", diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/tasks/task.h index a45cff9cc..0afdf4351 100644 --- a/src/libcharon/sa/tasks/task.h +++ b/src/libcharon/sa/tasks/task.h @@ -84,7 +84,7 @@ enum task_type_t { /** IKEv1 delete of a quick mode SA */ TASK_QUICK_DELETE, /** IKEv1 vendor ID payload handling */ - TASK_VENDOR_V1, + TASK_ISAKMP_VENDOR, /** IKEv1 NAT detection */ TASK_ISAKMP_NATD, /** IKEv1 pre-authentication certificate handling */ From 15a682f4c23d0b8340b31077698e6f6d924c2861 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 13:10:29 +0100 Subject: [PATCH 361/534] Separated libcharon/sa directory with ikev1 and ikev2 subfolders --- src/conftest/hooks/pretend_auth.c | 2 +- src/conftest/hooks/rebuild_auth.c | 2 +- src/libcharon/Makefile.am | 94 ++++++++++--------- src/libcharon/config/peer_cfg.h | 2 - src/libcharon/daemon.h | 8 +- src/libcharon/encoding/message.c | 2 +- .../encoding/payloads/auth_payload.h | 2 +- src/libcharon/encoding/payloads/eap_payload.c | 1 + src/libcharon/encoding/payloads/eap_payload.h | 2 +- .../encoding/payloads/proposal_substructure.h | 2 +- src/libcharon/encoding/payloads/sa_payload.h | 2 +- src/libcharon/plugins/eap_aka/eap_aka_peer.h | 2 +- .../plugins/eap_aka/eap_aka_server.h | 2 +- src/libcharon/plugins/eap_gtc/eap_gtc.h | 2 +- .../plugins/eap_identity/eap_identity.h | 2 +- src/libcharon/plugins/eap_md5/eap_md5.h | 2 +- .../plugins/eap_mschapv2/eap_mschapv2.h | 2 +- src/libcharon/plugins/eap_peap/eap_peap.h | 2 +- .../plugins/eap_peap/eap_peap_peer.h | 2 +- .../plugins/eap_peap/eap_peap_server.h | 2 +- src/libcharon/plugins/eap_radius/eap_radius.h | 2 +- src/libcharon/plugins/eap_sim/eap_sim_peer.h | 2 +- .../plugins/eap_sim/eap_sim_server.h | 2 +- src/libcharon/plugins/eap_tls/eap_tls.h | 2 +- src/libcharon/plugins/eap_tnc/eap_tnc.h | 2 +- src/libcharon/plugins/eap_ttls/eap_ttls.h | 2 +- .../plugins/eap_ttls/eap_ttls_peer.c | 2 +- .../plugins/eap_ttls/eap_ttls_server.c | 2 +- .../plugins/xauth_generic/xauth_generic.h | 2 +- .../sa/{authenticators => }/authenticator.c | 12 +-- .../sa/{authenticators => }/authenticator.h | 0 src/libcharon/sa/ike_sa.c | 50 +++++----- src/libcharon/sa/ike_sa.h | 2 +- .../authenticators/hybrid_authenticator.c | 0 .../authenticators/hybrid_authenticator.h | 2 +- .../authenticators/psk_v1_authenticator.c | 2 +- .../authenticators/psk_v1_authenticator.h | 2 +- .../authenticators/pubkey_v1_authenticator.c | 2 +- .../authenticators/pubkey_v1_authenticator.h | 2 +- .../authenticators/xauth/xauth_manager.c | 0 .../authenticators/xauth/xauth_manager.h | 2 +- .../authenticators/xauth/xauth_method.c | 0 .../authenticators/xauth/xauth_method.h | 0 src/libcharon/sa/{ => ikev1}/keymat_v1.c | 0 src/libcharon/sa/{ => ikev1}/keymat_v1.h | 1 + .../sa/{ => ikev1}/task_manager_v1.c | 18 ++-- .../sa/{ => ikev1}/task_manager_v1.h | 0 .../sa/{ => ikev1}/tasks/informational.c | 4 +- .../sa/{ => ikev1}/tasks/informational.h | 2 +- .../sa/{ => ikev1}/tasks/isakmp_cert_post.c | 0 .../sa/{ => ikev1}/tasks/isakmp_cert_post.h | 2 +- .../sa/{ => ikev1}/tasks/isakmp_cert_pre.c | 0 .../sa/{ => ikev1}/tasks/isakmp_cert_pre.h | 2 +- .../sa/{ => ikev1}/tasks/isakmp_delete.c | 0 .../sa/{ => ikev1}/tasks/isakmp_delete.h | 2 +- .../sa/{ => ikev1}/tasks/isakmp_natd.c | 2 +- .../sa/{ => ikev1}/tasks/isakmp_natd.h | 2 +- .../sa/{ => ikev1}/tasks/isakmp_vendor.c | 0 .../sa/{ => ikev1}/tasks/isakmp_vendor.h | 2 +- .../sa/{ => ikev1}/tasks/main_mode.c | 10 +- .../sa/{ => ikev1}/tasks/main_mode.h | 2 +- .../sa/{ => ikev1}/tasks/mode_config.c | 0 .../sa/{ => ikev1}/tasks/mode_config.h | 2 +- .../sa/{ => ikev1}/tasks/quick_delete.c | 0 .../sa/{ => ikev1}/tasks/quick_delete.h | 2 +- .../sa/{ => ikev1}/tasks/quick_mode.c | 6 +- .../sa/{ => ikev1}/tasks/quick_mode.h | 2 +- src/libcharon/sa/{ => ikev1}/tasks/xauth.c | 0 src/libcharon/sa/{ => ikev1}/tasks/xauth.h | 2 +- .../authenticators/eap/eap_manager.c | 1 - .../authenticators/eap/eap_manager.h | 2 +- .../authenticators/eap/eap_method.c | 0 .../authenticators/eap/eap_method.h | 0 .../authenticators/eap_authenticator.c | 5 +- .../authenticators/eap_authenticator.h | 2 +- .../authenticators/psk_authenticator.c | 3 +- .../authenticators/psk_authenticator.h | 2 +- .../authenticators/pubkey_authenticator.c | 2 +- .../authenticators/pubkey_authenticator.h | 2 +- .../sa/{ => ikev2}/connect_manager.c | 0 .../sa/{ => ikev2}/connect_manager.h | 0 src/libcharon/sa/{ => ikev2}/keymat_v2.c | 0 src/libcharon/sa/{ => ikev2}/keymat_v2.h | 0 .../sa/{ => ikev2}/mediation_manager.c | 0 .../sa/{ => ikev2}/mediation_manager.h | 0 .../sa/{ => ikev2}/task_manager_v2.c | 32 +++---- .../sa/{ => ikev2}/task_manager_v2.h | 0 .../sa/{ => ikev2}/tasks/child_create.c | 2 +- .../sa/{ => ikev2}/tasks/child_create.h | 2 +- .../sa/{ => ikev2}/tasks/child_delete.c | 0 .../sa/{ => ikev2}/tasks/child_delete.h | 2 +- .../sa/{ => ikev2}/tasks/child_rekey.c | 4 +- .../sa/{ => ikev2}/tasks/child_rekey.h | 2 +- src/libcharon/sa/{ => ikev2}/tasks/ike_auth.c | 3 +- src/libcharon/sa/{ => ikev2}/tasks/ike_auth.h | 2 +- .../sa/{ => ikev2}/tasks/ike_auth_lifetime.c | 1 - .../sa/{ => ikev2}/tasks/ike_auth_lifetime.h | 2 +- .../sa/{ => ikev2}/tasks/ike_cert_post.c | 1 - .../sa/{ => ikev2}/tasks/ike_cert_post.h | 2 +- .../sa/{ => ikev2}/tasks/ike_cert_pre.c | 0 .../sa/{ => ikev2}/tasks/ike_cert_pre.h | 2 +- .../sa/{ => ikev2}/tasks/ike_config.c | 1 - .../sa/{ => ikev2}/tasks/ike_config.h | 2 +- .../sa/{ => ikev2}/tasks/ike_delete.c | 0 .../sa/{ => ikev2}/tasks/ike_delete.h | 2 +- src/libcharon/sa/{ => ikev2}/tasks/ike_dpd.c | 0 src/libcharon/sa/{ => ikev2}/tasks/ike_dpd.h | 2 +- src/libcharon/sa/{ => ikev2}/tasks/ike_init.c | 2 +- src/libcharon/sa/{ => ikev2}/tasks/ike_init.h | 2 +- src/libcharon/sa/{ => ikev2}/tasks/ike_me.c | 0 src/libcharon/sa/{ => ikev2}/tasks/ike_me.h | 2 +- .../sa/{ => ikev2}/tasks/ike_mobike.c | 3 +- .../sa/{ => ikev2}/tasks/ike_mobike.h | 2 +- src/libcharon/sa/{ => ikev2}/tasks/ike_natd.c | 0 src/libcharon/sa/{ => ikev2}/tasks/ike_natd.h | 2 +- .../sa/{ => ikev2}/tasks/ike_reauth.c | 3 +- .../sa/{ => ikev2}/tasks/ike_reauth.h | 2 +- .../sa/{ => ikev2}/tasks/ike_rekey.c | 4 +- .../sa/{ => ikev2}/tasks/ike_rekey.h | 2 +- .../sa/{ => ikev2}/tasks/ike_vendor.c | 1 - .../sa/{ => ikev2}/tasks/ike_vendor.h | 2 +- src/libcharon/sa/keymat.c | 5 +- src/libcharon/sa/keymat.h | 2 +- src/libcharon/sa/{tasks => }/task.c | 0 src/libcharon/sa/{tasks => }/task.h | 0 src/libcharon/sa/task_manager.c | 5 +- src/libcharon/sa/task_manager.h | 2 +- 127 files changed, 206 insertions(+), 212 deletions(-) rename src/libcharon/sa/{authenticators => }/authenticator.c (92%) rename src/libcharon/sa/{authenticators => }/authenticator.h (100%) rename src/libcharon/sa/{ => ikev1}/authenticators/hybrid_authenticator.c (100%) rename src/libcharon/sa/{ => ikev1}/authenticators/hybrid_authenticator.h (97%) rename src/libcharon/sa/{ => ikev1}/authenticators/psk_v1_authenticator.c (99%) rename src/libcharon/sa/{ => ikev1}/authenticators/psk_v1_authenticator.h (97%) rename src/libcharon/sa/{ => ikev1}/authenticators/pubkey_v1_authenticator.c (99%) rename src/libcharon/sa/{ => ikev1}/authenticators/pubkey_v1_authenticator.h (97%) rename src/libcharon/sa/{ => ikev1}/authenticators/xauth/xauth_manager.c (100%) rename src/libcharon/sa/{ => ikev1}/authenticators/xauth/xauth_manager.h (97%) rename src/libcharon/sa/{ => ikev1}/authenticators/xauth/xauth_method.c (100%) rename src/libcharon/sa/{ => ikev1}/authenticators/xauth/xauth_method.h (100%) rename src/libcharon/sa/{ => ikev1}/keymat_v1.c (100%) rename src/libcharon/sa/{ => ikev1}/keymat_v1.h (99%) rename src/libcharon/sa/{ => ikev1}/task_manager_v1.c (98%) rename src/libcharon/sa/{ => ikev1}/task_manager_v1.h (100%) rename src/libcharon/sa/{ => ikev1}/tasks/informational.c (98%) rename src/libcharon/sa/{ => ikev1}/tasks/informational.h (98%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_cert_post.c (100%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_cert_post.h (98%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_cert_pre.c (100%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_cert_pre.h (98%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_delete.c (100%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_delete.h (97%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_natd.c (99%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_natd.h (97%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_vendor.c (100%) rename src/libcharon/sa/{ => ikev1}/tasks/isakmp_vendor.h (97%) rename src/libcharon/sa/{ => ikev1}/tasks/main_mode.c (99%) rename src/libcharon/sa/{ => ikev1}/tasks/main_mode.h (97%) rename src/libcharon/sa/{ => ikev1}/tasks/mode_config.c (100%) rename src/libcharon/sa/{ => ikev1}/tasks/mode_config.h (97%) rename src/libcharon/sa/{ => ikev1}/tasks/quick_delete.c (100%) rename src/libcharon/sa/{ => ikev1}/tasks/quick_delete.h (98%) rename src/libcharon/sa/{ => ikev1}/tasks/quick_mode.c (99%) rename src/libcharon/sa/{ => ikev1}/tasks/quick_mode.h (98%) rename src/libcharon/sa/{ => ikev1}/tasks/xauth.c (100%) rename src/libcharon/sa/{ => ikev1}/tasks/xauth.h (97%) rename src/libcharon/sa/{ => ikev2}/authenticators/eap/eap_manager.c (99%) rename src/libcharon/sa/{ => ikev2}/authenticators/eap/eap_manager.h (98%) rename src/libcharon/sa/{ => ikev2}/authenticators/eap/eap_method.c (100%) rename src/libcharon/sa/{ => ikev2}/authenticators/eap/eap_method.h (100%) rename src/libcharon/sa/{ => ikev2}/authenticators/eap_authenticator.c (99%) rename src/libcharon/sa/{ => ikev2}/authenticators/eap_authenticator.h (98%) rename src/libcharon/sa/{ => ikev2}/authenticators/psk_authenticator.c (99%) rename src/libcharon/sa/{ => ikev2}/authenticators/psk_authenticator.h (97%) rename src/libcharon/sa/{ => ikev2}/authenticators/pubkey_authenticator.c (99%) rename src/libcharon/sa/{ => ikev2}/authenticators/pubkey_authenticator.h (97%) rename src/libcharon/sa/{ => ikev2}/connect_manager.c (100%) rename src/libcharon/sa/{ => ikev2}/connect_manager.h (100%) rename src/libcharon/sa/{ => ikev2}/keymat_v2.c (100%) rename src/libcharon/sa/{ => ikev2}/keymat_v2.h (100%) rename src/libcharon/sa/{ => ikev2}/mediation_manager.c (100%) rename src/libcharon/sa/{ => ikev2}/mediation_manager.h (100%) rename src/libcharon/sa/{ => ikev2}/task_manager_v2.c (98%) rename src/libcharon/sa/{ => ikev2}/task_manager_v2.h (100%) rename src/libcharon/sa/{ => ikev2}/tasks/child_create.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/child_create.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/child_delete.c (100%) rename src/libcharon/sa/{ => ikev2}/tasks/child_delete.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/child_rekey.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/child_rekey.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_auth.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_auth.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_auth_lifetime.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_auth_lifetime.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_cert_post.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_cert_post.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_cert_pre.c (100%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_cert_pre.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_config.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_config.h (97%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_delete.c (100%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_delete.h (97%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_dpd.c (100%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_dpd.h (97%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_init.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_init.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_me.c (100%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_me.h (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_mobike.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_mobike.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_natd.c (100%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_natd.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_reauth.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_reauth.h (97%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_rekey.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_rekey.h (98%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_vendor.c (99%) rename src/libcharon/sa/{ => ikev2}/tasks/ike_vendor.h (97%) rename src/libcharon/sa/{tasks => }/task.c (100%) rename src/libcharon/sa/{tasks => }/task.h (100%) diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c index 10b13c6ac..3a7bb4f6b 100644 --- a/src/conftest/hooks/pretend_auth.c +++ b/src/conftest/hooks/pretend_auth.c @@ -15,7 +15,7 @@ #include "hook.h" -#include +#include #include #include #include diff --git a/src/conftest/hooks/rebuild_auth.c b/src/conftest/hooks/rebuild_auth.c index cf9b113cc..1197eb2dc 100644 --- a/src/conftest/hooks/rebuild_auth.c +++ b/src/conftest/hooks/rebuild_auth.c @@ -15,7 +15,7 @@ #include "hook.h" -#include +#include #include #include #include diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 95bec0966..474b20521 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -57,55 +57,57 @@ processing/jobs/start_action_job.c processing/jobs/start_action_job.h \ processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \ -sa/authenticators/authenticator.c sa/authenticators/authenticator.h \ -sa/authenticators/eap_authenticator.c sa/authenticators/eap_authenticator.h \ -sa/authenticators/eap/eap_method.c sa/authenticators/eap/eap_method.h \ -sa/authenticators/eap/eap_manager.c sa/authenticators/eap/eap_manager.h \ -sa/authenticators/psk_authenticator.c sa/authenticators/psk_authenticator.h \ -sa/authenticators/pubkey_authenticator.c sa/authenticators/pubkey_authenticator.h \ -sa/authenticators/psk_v1_authenticator.c sa/authenticators/psk_v1_authenticator.h \ -sa/authenticators/pubkey_v1_authenticator.c sa/authenticators/pubkey_v1_authenticator.h \ -sa/authenticators/hybrid_authenticator.c sa/authenticators/hybrid_authenticator.h \ -sa/authenticators/xauth/xauth_method.c sa/authenticators/xauth/xauth_method.h \ -sa/authenticators/xauth/xauth_manager.c sa/authenticators/xauth/xauth_manager.h \ +sa/authenticator.c sa/authenticator.h \ sa/child_sa.c sa/child_sa.h \ sa/ike_sa.c sa/ike_sa.h \ sa/ike_sa_id.c sa/ike_sa_id.h \ +sa/keymat.h sa/keymat.c \ sa/ike_sa_manager.c sa/ike_sa_manager.h \ -sa/task_manager.h sa/task_manager.c sa/task_manager_v2.c sa/task_manager_v2.h \ -sa/task_manager_v1.c sa/task_manager_v1.h \ -sa/keymat.h sa/keymat.c sa/keymat_v2.c sa/keymat_v2.h \ -sa/keymat_v1.c sa/keymat_v1.h \ +sa/task_manager.h sa/task_manager.c \ sa/shunt_manager.c sa/shunt_manager.h \ sa/trap_manager.c sa/trap_manager.h \ -sa/tasks/child_create.c sa/tasks/child_create.h \ -sa/tasks/child_delete.c sa/tasks/child_delete.h \ -sa/tasks/child_rekey.c sa/tasks/child_rekey.h \ -sa/tasks/ike_auth.c sa/tasks/ike_auth.h \ -sa/tasks/ike_cert_pre.c sa/tasks/ike_cert_pre.h \ -sa/tasks/ike_cert_post.c sa/tasks/ike_cert_post.h \ -sa/tasks/ike_config.c sa/tasks/ike_config.h \ -sa/tasks/ike_delete.c sa/tasks/ike_delete.h \ -sa/tasks/ike_dpd.c sa/tasks/ike_dpd.h \ -sa/tasks/ike_init.c sa/tasks/ike_init.h \ -sa/tasks/ike_natd.c sa/tasks/ike_natd.h \ -sa/tasks/ike_mobike.c sa/tasks/ike_mobike.h \ -sa/tasks/ike_rekey.c sa/tasks/ike_rekey.h \ -sa/tasks/ike_reauth.c sa/tasks/ike_reauth.h \ -sa/tasks/ike_auth_lifetime.c sa/tasks/ike_auth_lifetime.h \ -sa/tasks/ike_vendor.c sa/tasks/ike_vendor.h \ -sa/tasks/main_mode.c sa/tasks/main_mode.h \ -sa/tasks/informational.c sa/tasks/informational.h \ -sa/tasks/isakmp_cert_pre.c sa/tasks/isakmp_cert_pre.h \ -sa/tasks/isakmp_cert_post.c sa/tasks/isakmp_cert_post.h \ -sa/tasks/isakmp_natd.c sa/tasks/isakmp_natd.h \ -sa/tasks/isakmp_vendor.c sa/tasks/isakmp_vendor.h \ -sa/tasks/isakmp_delete.c sa/tasks/isakmp_delete.h \ -sa/tasks/xauth.c sa/tasks/xauth.h \ -sa/tasks/quick_mode.c sa/tasks/quick_mode.h \ -sa/tasks/quick_delete.c sa/tasks/quick_delete.h \ -sa/tasks/mode_config.c sa/tasks/mode_config.h \ -sa/tasks/task.c sa/tasks/task.h +sa/task.c sa/task.h \ +sa/ikev2/keymat_v2.c sa/ikev2/keymat_v2.h \ +sa/ikev2/task_manager_v2.c sa/ikev2/task_manager_v2.h \ +sa/ikev2/authenticators/eap_authenticator.c sa/ikev2/authenticators/eap_authenticator.h \ +sa/ikev2/authenticators/eap/eap_method.c sa/ikev2/authenticators/eap/eap_method.h \ +sa/ikev2/authenticators/eap/eap_manager.c sa/ikev2/authenticators/eap/eap_manager.h \ +sa/ikev2/authenticators/psk_authenticator.c sa/ikev2/authenticators/psk_authenticator.h \ +sa/ikev2/authenticators/pubkey_authenticator.c sa/ikev2/authenticators/pubkey_authenticator.h \ +sa/ikev2/tasks/child_create.c sa/ikev2/tasks/child_create.h \ +sa/ikev2/tasks/child_delete.c sa/ikev2/tasks/child_delete.h \ +sa/ikev2/tasks/child_rekey.c sa/ikev2/tasks/child_rekey.h \ +sa/ikev2/tasks/ike_auth.c sa/ikev2/tasks/ike_auth.h \ +sa/ikev2/tasks/ike_cert_pre.c sa/ikev2/tasks/ike_cert_pre.h \ +sa/ikev2/tasks/ike_cert_post.c sa/ikev2/tasks/ike_cert_post.h \ +sa/ikev2/tasks/ike_config.c sa/ikev2/tasks/ike_config.h \ +sa/ikev2/tasks/ike_delete.c sa/ikev2/tasks/ike_delete.h \ +sa/ikev2/tasks/ike_dpd.c sa/ikev2/tasks/ike_dpd.h \ +sa/ikev2/tasks/ike_init.c sa/ikev2/tasks/ike_init.h \ +sa/ikev2/tasks/ike_natd.c sa/ikev2/tasks/ike_natd.h \ +sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \ +sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \ +sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \ +sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \ +sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h \ +sa/ikev1/keymat_v1.c sa/ikev1/keymat_v1.h \ +sa/ikev1/task_manager_v1.c sa/ikev1/task_manager_v1.h \ +sa/ikev1/authenticators/psk_v1_authenticator.c sa/ikev1/authenticators/psk_v1_authenticator.h \ +sa/ikev1/authenticators/pubkey_v1_authenticator.c sa/ikev1/authenticators/pubkey_v1_authenticator.h \ +sa/ikev1/authenticators/hybrid_authenticator.c sa/ikev1/authenticators/hybrid_authenticator.h \ +sa/ikev1/authenticators/xauth/xauth_method.c sa/ikev1/authenticators/xauth/xauth_method.h \ +sa/ikev1/authenticators/xauth/xauth_manager.c sa/ikev1/authenticators/xauth/xauth_manager.h \ +sa/ikev1/tasks/main_mode.c sa/ikev1/tasks/main_mode.h \ +sa/ikev1/tasks/informational.c sa/ikev1/tasks/informational.h \ +sa/ikev1/tasks/isakmp_cert_pre.c sa/ikev1/tasks/isakmp_cert_pre.h \ +sa/ikev1/tasks/isakmp_cert_post.c sa/ikev1/tasks/isakmp_cert_post.h \ +sa/ikev1/tasks/isakmp_natd.c sa/ikev1/tasks/isakmp_natd.h \ +sa/ikev1/tasks/isakmp_vendor.c sa/ikev1/tasks/isakmp_vendor.h \ +sa/ikev1/tasks/isakmp_delete.c sa/ikev1/tasks/isakmp_delete.h \ +sa/ikev1/tasks/xauth.c sa/ikev1/tasks/xauth.h \ +sa/ikev1/tasks/quick_mode.c sa/ikev1/tasks/quick_mode.h \ +sa/ikev1/tasks/quick_delete.c sa/ikev1/tasks/quick_delete.h \ +sa/ikev1/tasks/mode_config.c sa/ikev1/tasks/mode_config.h daemon.lo : $(top_builddir)/config.status @@ -132,9 +134,9 @@ if USE_ME libcharon_la_SOURCES += encoding/payloads/endpoint_notify.c encoding/payloads/endpoint_notify.h \ processing/jobs/initiate_mediation_job.c processing/jobs/initiate_mediation_job.h \ processing/jobs/mediation_job.c processing/jobs/mediation_job.h \ - sa/connect_manager.c sa/connect_manager.h \ - sa/mediation_manager.c sa/mediation_manager.h \ - sa/tasks/ike_me.c sa/tasks/ike_me.h + sa/ikev2/connect_manager.c sa/ikev2/connect_manager.h \ + sa/ikev2/mediation_manager.c sa/ikev2/mediation_manager.h \ + sa/ikev2/tasks/ike_me.c sa/ikev2/tasks/ike_me.h endif if USE_LIBCAP diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index f1915614a..dcbe6aa9e 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -35,8 +35,6 @@ typedef struct peer_cfg_t peer_cfg_t; #include #include #include -#include -#include #include /** diff --git a/src/libcharon/daemon.h b/src/libcharon/daemon.h index a887eab79..785ad23bf 100644 --- a/src/libcharon/daemon.h +++ b/src/libcharon/daemon.h @@ -148,12 +148,12 @@ typedef struct daemon_t daemon_t; #include #include #include -#include -#include +#include +#include #ifdef ME -#include -#include +#include +#include #endif /* ME */ /** diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 708e3fb97..cf2a66efa 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/libcharon/encoding/payloads/auth_payload.h b/src/libcharon/encoding/payloads/auth_payload.h index 521fe1d19..b922d12c8 100644 --- a/src/libcharon/encoding/payloads/auth_payload.h +++ b/src/libcharon/encoding/payloads/auth_payload.h @@ -26,7 +26,7 @@ typedef struct auth_payload_t auth_payload_t; #include #include -#include +#include /** * Class representing an IKEv2 AUTH payload. diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index 9982f05a1..1b9a5c802 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -19,6 +19,7 @@ #include "eap_payload.h" #include +#include typedef struct private_eap_payload_t private_eap_payload_t; diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h index e63db7d88..52bc7ac5e 100644 --- a/src/libcharon/encoding/payloads/eap_payload.h +++ b/src/libcharon/encoding/payloads/eap_payload.h @@ -25,8 +25,8 @@ typedef struct eap_payload_t eap_payload_t; #include +#include #include -#include /** * Class representing an IKEv2 EAP payload. diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index 03b26e127..aefdf2f27 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -30,7 +30,7 @@ typedef struct proposal_substructure_t proposal_substructure_t; #include #include #include -#include +#include /** * Class representing an IKEv1/IKEv2 proposal substructure. diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h index dfba47749..6dfbd5180 100644 --- a/src/libcharon/encoding/payloads/sa_payload.h +++ b/src/libcharon/encoding/payloads/sa_payload.h @@ -29,7 +29,7 @@ typedef struct sa_payload_t sa_payload_t; #include #include #include -#include +#include /** * Class representing an IKEv1 or IKEv2 SA Payload. diff --git a/src/libcharon/plugins/eap_aka/eap_aka_peer.h b/src/libcharon/plugins/eap_aka/eap_aka_peer.h index 974ba2721..4fc1821c4 100644 --- a/src/libcharon/plugins/eap_aka/eap_aka_peer.h +++ b/src/libcharon/plugins/eap_aka/eap_aka_peer.h @@ -23,7 +23,7 @@ typedef struct eap_aka_peer_t eap_aka_peer_t; -#include +#include /** * EAP-AKA peer implementation. diff --git a/src/libcharon/plugins/eap_aka/eap_aka_server.h b/src/libcharon/plugins/eap_aka/eap_aka_server.h index 5ab1c4dfd..4819021d2 100644 --- a/src/libcharon/plugins/eap_aka/eap_aka_server.h +++ b/src/libcharon/plugins/eap_aka/eap_aka_server.h @@ -23,7 +23,7 @@ typedef struct eap_aka_server_t eap_aka_server_t; -#include +#include /** * EAP-AKA server implementation. diff --git a/src/libcharon/plugins/eap_gtc/eap_gtc.h b/src/libcharon/plugins/eap_gtc/eap_gtc.h index 2eb8482f8..0ce46b303 100644 --- a/src/libcharon/plugins/eap_gtc/eap_gtc.h +++ b/src/libcharon/plugins/eap_gtc/eap_gtc.h @@ -23,7 +23,7 @@ typedef struct eap_gtc_t eap_gtc_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-GTC. diff --git a/src/libcharon/plugins/eap_identity/eap_identity.h b/src/libcharon/plugins/eap_identity/eap_identity.h index 9a7f28574..811b19b5b 100644 --- a/src/libcharon/plugins/eap_identity/eap_identity.h +++ b/src/libcharon/plugins/eap_identity/eap_identity.h @@ -23,7 +23,7 @@ typedef struct eap_identity_t eap_identity_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP Identity. diff --git a/src/libcharon/plugins/eap_md5/eap_md5.h b/src/libcharon/plugins/eap_md5/eap_md5.h index c6687149a..302abc4e6 100644 --- a/src/libcharon/plugins/eap_md5/eap_md5.h +++ b/src/libcharon/plugins/eap_md5/eap_md5.h @@ -23,7 +23,7 @@ typedef struct eap_md5_t eap_md5_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-MD5 (CHAP). diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h index 34cc1141e..44050d0da 100644 --- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h +++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h @@ -23,7 +23,7 @@ typedef struct eap_mschapv2_t eap_mschapv2_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-MS-CHAPv2. diff --git a/src/libcharon/plugins/eap_peap/eap_peap.h b/src/libcharon/plugins/eap_peap/eap_peap.h index f47bad561..7bf7b1d70 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap.h +++ b/src/libcharon/plugins/eap_peap/eap_peap.h @@ -23,7 +23,7 @@ typedef struct eap_peap_t eap_peap_t; -#include +#include /** * Implementation of eap_method_t using EAP-PEAP. diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.h b/src/libcharon/plugins/eap_peap/eap_peap_peer.h index a87544209..61586b16c 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_peer.h +++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.h @@ -26,7 +26,7 @@ typedef struct eap_peap_peer_t eap_peap_peer_t; #include "tls_application.h" #include -#include +#include /** * TLS application data handler as peer. diff --git a/src/libcharon/plugins/eap_peap/eap_peap_server.h b/src/libcharon/plugins/eap_peap/eap_peap_server.h index 93141d62b..cc03d4ba9 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_server.h +++ b/src/libcharon/plugins/eap_peap/eap_peap_server.h @@ -26,7 +26,7 @@ typedef struct eap_peap_server_t eap_peap_server_t; #include "tls_application.h" #include -#include +#include /** * TLS application data handler as server. diff --git a/src/libcharon/plugins/eap_radius/eap_radius.h b/src/libcharon/plugins/eap_radius/eap_radius.h index e98cb06e3..9cfdbb95d 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius.h +++ b/src/libcharon/plugins/eap_radius/eap_radius.h @@ -23,7 +23,7 @@ typedef struct eap_radius_t eap_radius_t; -#include +#include /** * Implementation of the eap_method_t interface using a RADIUS server. diff --git a/src/libcharon/plugins/eap_sim/eap_sim_peer.h b/src/libcharon/plugins/eap_sim/eap_sim_peer.h index ba72ce484..c32cb3120 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_peer.h +++ b/src/libcharon/plugins/eap_sim/eap_sim_peer.h @@ -21,7 +21,7 @@ #ifndef EAP_SIM_PEER_H_ #define EAP_SIM_PEER_H_ -#include +#include typedef struct eap_sim_peer_t eap_sim_peer_t; diff --git a/src/libcharon/plugins/eap_sim/eap_sim_server.h b/src/libcharon/plugins/eap_sim/eap_sim_server.h index c0ed64ff2..a4a0eea63 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_server.h +++ b/src/libcharon/plugins/eap_sim/eap_sim_server.h @@ -21,7 +21,7 @@ #ifndef EAP_SIM_SERVER_H_ #define EAP_SIM_SERVER_H_ -#include +#include typedef struct eap_sim_server_t eap_sim_server_t; diff --git a/src/libcharon/plugins/eap_tls/eap_tls.h b/src/libcharon/plugins/eap_tls/eap_tls.h index 7e080230a..4227c9db3 100644 --- a/src/libcharon/plugins/eap_tls/eap_tls.h +++ b/src/libcharon/plugins/eap_tls/eap_tls.h @@ -23,7 +23,7 @@ typedef struct eap_tls_t eap_tls_t; -#include +#include /** * Implementation of eap_method_t using EAP-TLS. diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc.h b/src/libcharon/plugins/eap_tnc/eap_tnc.h index 7e166fb60..1c7e1b6fa 100644 --- a/src/libcharon/plugins/eap_tnc/eap_tnc.h +++ b/src/libcharon/plugins/eap_tnc/eap_tnc.h @@ -23,7 +23,7 @@ typedef struct eap_tnc_t eap_tnc_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-TNC. diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.h b/src/libcharon/plugins/eap_ttls/eap_ttls.h index 6e3bf2ceb..ca2b82477 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls.h +++ b/src/libcharon/plugins/eap_ttls/eap_ttls.h @@ -23,7 +23,7 @@ typedef struct eap_ttls_t eap_ttls_t; -#include +#include /** * Implementation of eap_method_t using EAP-TTLS. diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c index d2feb7774..aa10c7d3d 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -19,7 +19,7 @@ #include #include -#include +#include typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t; diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c index 3c46993b7..2a2aee12f 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c @@ -19,7 +19,7 @@ #include #include -#include +#include typedef struct private_eap_ttls_server_t private_eap_ttls_server_t; diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.h b/src/libcharon/plugins/xauth_generic/xauth_generic.h index dfb759b82..04e3d47bb 100644 --- a/src/libcharon/plugins/xauth_generic/xauth_generic.h +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.h @@ -23,7 +23,7 @@ typedef struct xauth_generic_t xauth_generic_t; -#include +#include /** * Implementation of the xauth_method_t interface using cleartext secrets diff --git a/src/libcharon/sa/authenticators/authenticator.c b/src/libcharon/sa/authenticator.c similarity index 92% rename from src/libcharon/sa/authenticators/authenticator.c rename to src/libcharon/sa/authenticator.c index 73029b9e1..d7a4b3eef 100644 --- a/src/libcharon/sa/authenticators/authenticator.c +++ b/src/libcharon/sa/authenticator.c @@ -18,12 +18,12 @@ #include "authenticator.h" -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include diff --git a/src/libcharon/sa/authenticators/authenticator.h b/src/libcharon/sa/authenticator.h similarity index 100% rename from src/libcharon/sa/authenticators/authenticator.h rename to src/libcharon/sa/authenticator.h diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 331b001bf..0ee4324bf 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -28,30 +28,30 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -59,7 +59,7 @@ #include #ifdef ME -#include +#include #include #endif diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index cbb16ca4a..e50356451 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -37,7 +37,7 @@ typedef struct ike_sa_t ike_sa_t; #include #include #include -#include +#include #include #include #include diff --git a/src/libcharon/sa/authenticators/hybrid_authenticator.c b/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c similarity index 100% rename from src/libcharon/sa/authenticators/hybrid_authenticator.c rename to src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c diff --git a/src/libcharon/sa/authenticators/hybrid_authenticator.h b/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.h similarity index 97% rename from src/libcharon/sa/authenticators/hybrid_authenticator.h rename to src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.h index 37057470b..6a0bb1e59 100644 --- a/src/libcharon/sa/authenticators/hybrid_authenticator.h +++ b/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.h @@ -23,7 +23,7 @@ typedef struct hybrid_authenticator_t hybrid_authenticator_t; -#include +#include /** * Implementation of authenticator_t using IKEv1 hybrid authentication. diff --git a/src/libcharon/sa/authenticators/psk_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c similarity index 99% rename from src/libcharon/sa/authenticators/psk_v1_authenticator.c rename to src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c index 11fd8118d..ce794a286 100644 --- a/src/libcharon/sa/authenticators/psk_v1_authenticator.c +++ b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c @@ -16,7 +16,7 @@ #include "psk_v1_authenticator.h" #include -#include +#include #include typedef struct private_psk_v1_authenticator_t private_psk_v1_authenticator_t; diff --git a/src/libcharon/sa/authenticators/psk_v1_authenticator.h b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h similarity index 97% rename from src/libcharon/sa/authenticators/psk_v1_authenticator.h rename to src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h index e01d49c95..194b96456 100644 --- a/src/libcharon/sa/authenticators/psk_v1_authenticator.h +++ b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h @@ -23,7 +23,7 @@ typedef struct psk_v1_authenticator_t psk_v1_authenticator_t; -#include +#include /** * Implementation of authenticator_t using pre-shared keys for IKEv1. diff --git a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c similarity index 99% rename from src/libcharon/sa/authenticators/pubkey_v1_authenticator.c rename to src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c index 7da1953af..56fcf2c9d 100644 --- a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.c +++ b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c @@ -16,7 +16,7 @@ #include "pubkey_v1_authenticator.h" #include -#include +#include #include typedef struct private_pubkey_v1_authenticator_t private_pubkey_v1_authenticator_t; diff --git a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h similarity index 97% rename from src/libcharon/sa/authenticators/pubkey_v1_authenticator.h rename to src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h index e71a81f18..bafc3a2b2 100644 --- a/src/libcharon/sa/authenticators/pubkey_v1_authenticator.h +++ b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h @@ -23,7 +23,7 @@ typedef struct pubkey_v1_authenticator_t pubkey_v1_authenticator_t; -#include +#include /** * Implementation of authenticator_t using public keys for IKEv1. diff --git a/src/libcharon/sa/authenticators/xauth/xauth_manager.c b/src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.c similarity index 100% rename from src/libcharon/sa/authenticators/xauth/xauth_manager.c rename to src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.c diff --git a/src/libcharon/sa/authenticators/xauth/xauth_manager.h b/src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.h similarity index 97% rename from src/libcharon/sa/authenticators/xauth/xauth_manager.h rename to src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.h index 7f07cc22a..e7e84d06b 100644 --- a/src/libcharon/sa/authenticators/xauth/xauth_manager.h +++ b/src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.h @@ -21,7 +21,7 @@ #ifndef XAUTH_MANAGER_H_ #define XAUTH_MANAGER_H_ -#include +#include typedef struct xauth_manager_t xauth_manager_t; diff --git a/src/libcharon/sa/authenticators/xauth/xauth_method.c b/src/libcharon/sa/ikev1/authenticators/xauth/xauth_method.c similarity index 100% rename from src/libcharon/sa/authenticators/xauth/xauth_method.c rename to src/libcharon/sa/ikev1/authenticators/xauth/xauth_method.c diff --git a/src/libcharon/sa/authenticators/xauth/xauth_method.h b/src/libcharon/sa/ikev1/authenticators/xauth/xauth_method.h similarity index 100% rename from src/libcharon/sa/authenticators/xauth/xauth_method.h rename to src/libcharon/sa/ikev1/authenticators/xauth/xauth_method.h diff --git a/src/libcharon/sa/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c similarity index 100% rename from src/libcharon/sa/keymat_v1.c rename to src/libcharon/sa/ikev1/keymat_v1.c diff --git a/src/libcharon/sa/keymat_v1.h b/src/libcharon/sa/ikev1/keymat_v1.h similarity index 99% rename from src/libcharon/sa/keymat_v1.h rename to src/libcharon/sa/ikev1/keymat_v1.h index 875ad9d30..bb1022b5e 100644 --- a/src/libcharon/sa/keymat_v1.h +++ b/src/libcharon/sa/ikev1/keymat_v1.h @@ -22,6 +22,7 @@ #define KEYMAT_V1_H_ #include +#include typedef struct keymat_v1_t keymat_v1_t; diff --git a/src/libcharon/sa/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c similarity index 98% rename from src/libcharon/sa/task_manager_v1.c rename to src/libcharon/sa/ikev1/task_manager_v1.c index dea4dcb87..8e4aa7496 100644 --- a/src/libcharon/sa/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -19,15 +19,15 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include diff --git a/src/libcharon/sa/task_manager_v1.h b/src/libcharon/sa/ikev1/task_manager_v1.h similarity index 100% rename from src/libcharon/sa/task_manager_v1.h rename to src/libcharon/sa/ikev1/task_manager_v1.h diff --git a/src/libcharon/sa/tasks/informational.c b/src/libcharon/sa/ikev1/tasks/informational.c similarity index 98% rename from src/libcharon/sa/tasks/informational.c rename to src/libcharon/sa/ikev1/tasks/informational.c index 5b2ceca84..9de5c2e71 100644 --- a/src/libcharon/sa/tasks/informational.c +++ b/src/libcharon/sa/ikev1/tasks/informational.c @@ -16,8 +16,8 @@ #include "informational.h" #include -#include -#include +#include +#include #include typedef struct private_informational_t private_informational_t; diff --git a/src/libcharon/sa/tasks/informational.h b/src/libcharon/sa/ikev1/tasks/informational.h similarity index 98% rename from src/libcharon/sa/tasks/informational.h rename to src/libcharon/sa/ikev1/tasks/informational.h index 2aec7abd8..f1543dc58 100644 --- a/src/libcharon/sa/tasks/informational.h +++ b/src/libcharon/sa/ikev1/tasks/informational.h @@ -25,7 +25,7 @@ typedef struct informational_t informational_t; #include #include -#include +#include #include /** diff --git a/src/libcharon/sa/tasks/isakmp_cert_post.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c similarity index 100% rename from src/libcharon/sa/tasks/isakmp_cert_post.c rename to src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c diff --git a/src/libcharon/sa/tasks/isakmp_cert_post.h b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.h similarity index 98% rename from src/libcharon/sa/tasks/isakmp_cert_post.h rename to src/libcharon/sa/ikev1/tasks/isakmp_cert_post.h index 6720c54e0..2e38df89f 100644 --- a/src/libcharon/sa/tasks/isakmp_cert_post.h +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.h @@ -25,7 +25,7 @@ typedef struct isakmp_cert_post_t isakmp_cert_post_t; #include #include -#include +#include /** * ISAKMP_CERT_POST, IKEv1 certificate processing after authentication. diff --git a/src/libcharon/sa/tasks/isakmp_cert_pre.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c similarity index 100% rename from src/libcharon/sa/tasks/isakmp_cert_pre.c rename to src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c diff --git a/src/libcharon/sa/tasks/isakmp_cert_pre.h b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.h similarity index 98% rename from src/libcharon/sa/tasks/isakmp_cert_pre.h rename to src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.h index c6dc98ac5..908cff020 100644 --- a/src/libcharon/sa/tasks/isakmp_cert_pre.h +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.h @@ -25,7 +25,7 @@ typedef struct isakmp_cert_pre_t isakmp_cert_pre_t; #include #include -#include +#include /** * ISAKMP_CERT_PRE task, IKEv1 certificate processing before authentication. diff --git a/src/libcharon/sa/tasks/isakmp_delete.c b/src/libcharon/sa/ikev1/tasks/isakmp_delete.c similarity index 100% rename from src/libcharon/sa/tasks/isakmp_delete.c rename to src/libcharon/sa/ikev1/tasks/isakmp_delete.c diff --git a/src/libcharon/sa/tasks/isakmp_delete.h b/src/libcharon/sa/ikev1/tasks/isakmp_delete.h similarity index 97% rename from src/libcharon/sa/tasks/isakmp_delete.h rename to src/libcharon/sa/ikev1/tasks/isakmp_delete.h index 49e49fab9..3b7b40c11 100644 --- a/src/libcharon/sa/tasks/isakmp_delete.h +++ b/src/libcharon/sa/ikev1/tasks/isakmp_delete.h @@ -25,7 +25,7 @@ typedef struct isakmp_delete_t isakmp_delete_t; #include #include -#include +#include /** * Task of type ISAKMP_DELETE, delete an IKEv1 IKE_SA. diff --git a/src/libcharon/sa/tasks/isakmp_natd.c b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c similarity index 99% rename from src/libcharon/sa/tasks/isakmp_natd.c rename to src/libcharon/sa/ikev1/tasks/isakmp_natd.c index b956ff66f..88ee327ba 100644 --- a/src/libcharon/sa/tasks/isakmp_natd.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/libcharon/sa/tasks/isakmp_natd.h b/src/libcharon/sa/ikev1/tasks/isakmp_natd.h similarity index 97% rename from src/libcharon/sa/tasks/isakmp_natd.h rename to src/libcharon/sa/ikev1/tasks/isakmp_natd.h index 3d5df7e5a..b83b07805 100644 --- a/src/libcharon/sa/tasks/isakmp_natd.h +++ b/src/libcharon/sa/ikev1/tasks/isakmp_natd.h @@ -25,7 +25,7 @@ typedef struct isakmp_natd_t isakmp_natd_t; #include #include -#include +#include /** * Task of type ISAKMP_NATD, detects NAT situation in IKEv1 Phase 1. diff --git a/src/libcharon/sa/tasks/isakmp_vendor.c b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c similarity index 100% rename from src/libcharon/sa/tasks/isakmp_vendor.c rename to src/libcharon/sa/ikev1/tasks/isakmp_vendor.c diff --git a/src/libcharon/sa/tasks/isakmp_vendor.h b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.h similarity index 97% rename from src/libcharon/sa/tasks/isakmp_vendor.h rename to src/libcharon/sa/ikev1/tasks/isakmp_vendor.h index e6ceb2e6d..b81d79034 100644 --- a/src/libcharon/sa/tasks/isakmp_vendor.h +++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.h @@ -25,7 +25,7 @@ typedef struct isakmp_vendor_t isakmp_vendor_t; #include #include -#include +#include /** * Vendor ID processing task for IKEv1. diff --git a/src/libcharon/sa/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c similarity index 99% rename from src/libcharon/sa/tasks/main_mode.c rename to src/libcharon/sa/ikev1/tasks/main_mode.c index 08bb29124..7f263260c 100644 --- a/src/libcharon/sa/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -21,17 +21,17 @@ #include #include -#include +#include #include #include #include #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include typedef struct private_main_mode_t private_main_mode_t; diff --git a/src/libcharon/sa/tasks/main_mode.h b/src/libcharon/sa/ikev1/tasks/main_mode.h similarity index 97% rename from src/libcharon/sa/tasks/main_mode.h rename to src/libcharon/sa/ikev1/tasks/main_mode.h index 9ff253096..d266b6e63 100644 --- a/src/libcharon/sa/tasks/main_mode.h +++ b/src/libcharon/sa/ikev1/tasks/main_mode.h @@ -25,7 +25,7 @@ typedef struct main_mode_t main_mode_t; #include #include -#include +#include /** * IKEv1 main mode, establishes a mainmode including authentication. diff --git a/src/libcharon/sa/tasks/mode_config.c b/src/libcharon/sa/ikev1/tasks/mode_config.c similarity index 100% rename from src/libcharon/sa/tasks/mode_config.c rename to src/libcharon/sa/ikev1/tasks/mode_config.c diff --git a/src/libcharon/sa/tasks/mode_config.h b/src/libcharon/sa/ikev1/tasks/mode_config.h similarity index 97% rename from src/libcharon/sa/tasks/mode_config.h rename to src/libcharon/sa/ikev1/tasks/mode_config.h index 34b744d10..026545eba 100644 --- a/src/libcharon/sa/tasks/mode_config.h +++ b/src/libcharon/sa/ikev1/tasks/mode_config.h @@ -25,7 +25,7 @@ typedef struct mode_config_t mode_config_t; #include #include -#include +#include /** * Task of type TASK_MODE_COFNIG, IKEv1 configuration attribute exchange. diff --git a/src/libcharon/sa/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c similarity index 100% rename from src/libcharon/sa/tasks/quick_delete.c rename to src/libcharon/sa/ikev1/tasks/quick_delete.c diff --git a/src/libcharon/sa/tasks/quick_delete.h b/src/libcharon/sa/ikev1/tasks/quick_delete.h similarity index 98% rename from src/libcharon/sa/tasks/quick_delete.h rename to src/libcharon/sa/ikev1/tasks/quick_delete.h index 80aae8273..1cdf07c48 100644 --- a/src/libcharon/sa/tasks/quick_delete.h +++ b/src/libcharon/sa/ikev1/tasks/quick_delete.h @@ -25,7 +25,7 @@ typedef struct quick_delete_t quick_delete_t; #include #include -#include +#include #include /** diff --git a/src/libcharon/sa/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c similarity index 99% rename from src/libcharon/sa/tasks/quick_mode.c rename to src/libcharon/sa/ikev1/tasks/quick_mode.c index 9d9b5e958..9e71642af 100644 --- a/src/libcharon/sa/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -18,14 +18,14 @@ #include #include -#include +#include #include #include #include #include #include -#include -#include +#include +#include typedef struct private_quick_mode_t private_quick_mode_t; diff --git a/src/libcharon/sa/tasks/quick_mode.h b/src/libcharon/sa/ikev1/tasks/quick_mode.h similarity index 98% rename from src/libcharon/sa/tasks/quick_mode.h rename to src/libcharon/sa/ikev1/tasks/quick_mode.h index e50c1a97e..82790c768 100644 --- a/src/libcharon/sa/tasks/quick_mode.h +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.h @@ -25,7 +25,7 @@ typedef struct quick_mode_t quick_mode_t; #include #include -#include +#include /** * IKEv1 quick mode, establishes a CHILD_SA in IKEv1. diff --git a/src/libcharon/sa/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c similarity index 100% rename from src/libcharon/sa/tasks/xauth.c rename to src/libcharon/sa/ikev1/tasks/xauth.c diff --git a/src/libcharon/sa/tasks/xauth.h b/src/libcharon/sa/ikev1/tasks/xauth.h similarity index 97% rename from src/libcharon/sa/tasks/xauth.h rename to src/libcharon/sa/ikev1/tasks/xauth.h index 6633f9e55..c1528ccbe 100644 --- a/src/libcharon/sa/tasks/xauth.h +++ b/src/libcharon/sa/ikev1/tasks/xauth.h @@ -25,7 +25,7 @@ typedef struct xauth_t xauth_t; #include #include -#include +#include /** * Task of type TASK_XAUTH, additional authentication after main/aggressive mode. diff --git a/src/libcharon/sa/authenticators/eap/eap_manager.c b/src/libcharon/sa/ikev2/authenticators/eap/eap_manager.c similarity index 99% rename from src/libcharon/sa/authenticators/eap/eap_manager.c rename to src/libcharon/sa/ikev2/authenticators/eap/eap_manager.c index bc2c4a617..d38754e01 100644 --- a/src/libcharon/sa/authenticators/eap/eap_manager.c +++ b/src/libcharon/sa/ikev2/authenticators/eap/eap_manager.c @@ -159,4 +159,3 @@ eap_manager_t *eap_manager_create() return &this->public; } - diff --git a/src/libcharon/sa/authenticators/eap/eap_manager.h b/src/libcharon/sa/ikev2/authenticators/eap/eap_manager.h similarity index 98% rename from src/libcharon/sa/authenticators/eap/eap_manager.h rename to src/libcharon/sa/ikev2/authenticators/eap/eap_manager.h index 0333fb6da..6b8754634 100644 --- a/src/libcharon/sa/authenticators/eap/eap_manager.h +++ b/src/libcharon/sa/ikev2/authenticators/eap/eap_manager.h @@ -21,7 +21,7 @@ #ifndef EAP_MANAGER_H_ #define EAP_MANAGER_H_ -#include +#include typedef struct eap_manager_t eap_manager_t; diff --git a/src/libcharon/sa/authenticators/eap/eap_method.c b/src/libcharon/sa/ikev2/authenticators/eap/eap_method.c similarity index 100% rename from src/libcharon/sa/authenticators/eap/eap_method.c rename to src/libcharon/sa/ikev2/authenticators/eap/eap_method.c diff --git a/src/libcharon/sa/authenticators/eap/eap_method.h b/src/libcharon/sa/ikev2/authenticators/eap/eap_method.h similarity index 100% rename from src/libcharon/sa/authenticators/eap/eap_method.h rename to src/libcharon/sa/ikev2/authenticators/eap/eap_method.h diff --git a/src/libcharon/sa/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c similarity index 99% rename from src/libcharon/sa/authenticators/eap_authenticator.c rename to src/libcharon/sa/ikev2/authenticators/eap_authenticator.c index d36d544e8..462436d80 100644 --- a/src/libcharon/sa/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c @@ -16,8 +16,8 @@ #include "eap_authenticator.h" #include -#include -#include +#include +#include #include #include @@ -707,4 +707,3 @@ eap_authenticator_t *eap_authenticator_create_verifier(ike_sa_t *ike_sa, return &this->public; } - diff --git a/src/libcharon/sa/authenticators/eap_authenticator.h b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.h similarity index 98% rename from src/libcharon/sa/authenticators/eap_authenticator.h rename to src/libcharon/sa/ikev2/authenticators/eap_authenticator.h index 726411a18..15d7cb88d 100644 --- a/src/libcharon/sa/authenticators/eap_authenticator.h +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.h @@ -23,7 +23,7 @@ typedef struct eap_authenticator_t eap_authenticator_t; -#include +#include /** * Implementation of authenticator_t using EAP authentication. diff --git a/src/libcharon/sa/authenticators/psk_authenticator.c b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c similarity index 99% rename from src/libcharon/sa/authenticators/psk_authenticator.c rename to src/libcharon/sa/ikev2/authenticators/psk_authenticator.c index 26c722530..2d3434cdf 100644 --- a/src/libcharon/sa/authenticators/psk_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.c @@ -18,7 +18,7 @@ #include #include -#include +#include typedef struct private_psk_authenticator_t private_psk_authenticator_t; @@ -202,4 +202,3 @@ psk_authenticator_t *psk_authenticator_create_verifier(ike_sa_t *ike_sa, return &this->public; } - diff --git a/src/libcharon/sa/authenticators/psk_authenticator.h b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.h similarity index 97% rename from src/libcharon/sa/authenticators/psk_authenticator.h rename to src/libcharon/sa/ikev2/authenticators/psk_authenticator.h index 8cf1a0f98..ffd06f1bc 100644 --- a/src/libcharon/sa/authenticators/psk_authenticator.h +++ b/src/libcharon/sa/ikev2/authenticators/psk_authenticator.h @@ -23,7 +23,7 @@ typedef struct psk_authenticator_t psk_authenticator_t; -#include +#include /** * Implementation of authenticator_t using pre-shared keys. diff --git a/src/libcharon/sa/authenticators/pubkey_authenticator.c b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c similarity index 99% rename from src/libcharon/sa/authenticators/pubkey_authenticator.c rename to src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c index df5b06ae6..179be3977 100644 --- a/src/libcharon/sa/authenticators/pubkey_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.c @@ -19,7 +19,7 @@ #include #include -#include +#include typedef struct private_pubkey_authenticator_t private_pubkey_authenticator_t; diff --git a/src/libcharon/sa/authenticators/pubkey_authenticator.h b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.h similarity index 97% rename from src/libcharon/sa/authenticators/pubkey_authenticator.h rename to src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.h index 4c3937ecc..bf95d6efd 100644 --- a/src/libcharon/sa/authenticators/pubkey_authenticator.h +++ b/src/libcharon/sa/ikev2/authenticators/pubkey_authenticator.h @@ -24,7 +24,7 @@ typedef struct pubkey_authenticator_t pubkey_authenticator_t; -#include +#include /** * Implementation of authenticator_t using public key authenitcation. diff --git a/src/libcharon/sa/connect_manager.c b/src/libcharon/sa/ikev2/connect_manager.c similarity index 100% rename from src/libcharon/sa/connect_manager.c rename to src/libcharon/sa/ikev2/connect_manager.c diff --git a/src/libcharon/sa/connect_manager.h b/src/libcharon/sa/ikev2/connect_manager.h similarity index 100% rename from src/libcharon/sa/connect_manager.h rename to src/libcharon/sa/ikev2/connect_manager.h diff --git a/src/libcharon/sa/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c similarity index 100% rename from src/libcharon/sa/keymat_v2.c rename to src/libcharon/sa/ikev2/keymat_v2.c diff --git a/src/libcharon/sa/keymat_v2.h b/src/libcharon/sa/ikev2/keymat_v2.h similarity index 100% rename from src/libcharon/sa/keymat_v2.h rename to src/libcharon/sa/ikev2/keymat_v2.h diff --git a/src/libcharon/sa/mediation_manager.c b/src/libcharon/sa/ikev2/mediation_manager.c similarity index 100% rename from src/libcharon/sa/mediation_manager.c rename to src/libcharon/sa/ikev2/mediation_manager.c diff --git a/src/libcharon/sa/mediation_manager.h b/src/libcharon/sa/ikev2/mediation_manager.h similarity index 100% rename from src/libcharon/sa/mediation_manager.h rename to src/libcharon/sa/ikev2/mediation_manager.h diff --git a/src/libcharon/sa/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c similarity index 98% rename from src/libcharon/sa/task_manager_v2.c rename to src/libcharon/sa/ikev2/task_manager_v2.c index 57b485ac5..cce9551d5 100644 --- a/src/libcharon/sa/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -19,28 +19,28 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include #ifdef ME -#include +#include #endif typedef struct exchange_t exchange_t; diff --git a/src/libcharon/sa/task_manager_v2.h b/src/libcharon/sa/ikev2/task_manager_v2.h similarity index 100% rename from src/libcharon/sa/task_manager_v2.h rename to src/libcharon/sa/ikev2/task_manager_v2.h diff --git a/src/libcharon/sa/tasks/child_create.c b/src/libcharon/sa/ikev2/tasks/child_create.c similarity index 99% rename from src/libcharon/sa/tasks/child_create.c rename to src/libcharon/sa/ikev2/tasks/child_create.c index 79d082138..023334bd4 100644 --- a/src/libcharon/sa/tasks/child_create.c +++ b/src/libcharon/sa/ikev2/tasks/child_create.c @@ -18,7 +18,7 @@ #include "child_create.h" #include -#include +#include #include #include #include diff --git a/src/libcharon/sa/tasks/child_create.h b/src/libcharon/sa/ikev2/tasks/child_create.h similarity index 98% rename from src/libcharon/sa/tasks/child_create.h rename to src/libcharon/sa/ikev2/tasks/child_create.h index fdec3bbb9..938b84398 100644 --- a/src/libcharon/sa/tasks/child_create.h +++ b/src/libcharon/sa/ikev2/tasks/child_create.h @@ -25,7 +25,7 @@ typedef struct child_create_t child_create_t; #include #include -#include +#include #include /** diff --git a/src/libcharon/sa/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c similarity index 100% rename from src/libcharon/sa/tasks/child_delete.c rename to src/libcharon/sa/ikev2/tasks/child_delete.c diff --git a/src/libcharon/sa/tasks/child_delete.h b/src/libcharon/sa/ikev2/tasks/child_delete.h similarity index 98% rename from src/libcharon/sa/tasks/child_delete.h rename to src/libcharon/sa/ikev2/tasks/child_delete.h index 365807c68..34d399ce3 100644 --- a/src/libcharon/sa/tasks/child_delete.h +++ b/src/libcharon/sa/ikev2/tasks/child_delete.h @@ -25,7 +25,7 @@ typedef struct child_delete_t child_delete_t; #include #include -#include +#include #include /** diff --git a/src/libcharon/sa/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c similarity index 99% rename from src/libcharon/sa/tasks/child_rekey.c rename to src/libcharon/sa/ikev2/tasks/child_rekey.c index fa916c4e5..50a8aad95 100644 --- a/src/libcharon/sa/tasks/child_rekey.c +++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c @@ -18,8 +18,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/libcharon/sa/tasks/child_rekey.h b/src/libcharon/sa/ikev2/tasks/child_rekey.h similarity index 98% rename from src/libcharon/sa/tasks/child_rekey.h rename to src/libcharon/sa/ikev2/tasks/child_rekey.h index 3ba417611..78314b0f9 100644 --- a/src/libcharon/sa/tasks/child_rekey.h +++ b/src/libcharon/sa/ikev2/tasks/child_rekey.h @@ -26,7 +26,7 @@ typedef struct child_rekey_t child_rekey_t; #include #include #include -#include +#include /** * Task of type TASK_CHILD_REKEY, rekey an established CHILD_SA. diff --git a/src/libcharon/sa/tasks/ike_auth.c b/src/libcharon/sa/ikev2/tasks/ike_auth.c similarity index 99% rename from src/libcharon/sa/tasks/ike_auth.c rename to src/libcharon/sa/ikev2/tasks/ike_auth.c index f9cf5c613..183ca3440 100644 --- a/src/libcharon/sa/tasks/ike_auth.c +++ b/src/libcharon/sa/ikev2/tasks/ike_auth.c @@ -23,7 +23,7 @@ #include #include #include -#include +#include typedef struct private_ike_auth_t private_ike_auth_t; @@ -1096,4 +1096,3 @@ ike_auth_t *ike_auth_create(ike_sa_t *ike_sa, bool initiator) } return &this->public; } - diff --git a/src/libcharon/sa/tasks/ike_auth.h b/src/libcharon/sa/ikev2/tasks/ike_auth.h similarity index 98% rename from src/libcharon/sa/tasks/ike_auth.h rename to src/libcharon/sa/ikev2/tasks/ike_auth.h index c6c0100b0..cf507f8e6 100644 --- a/src/libcharon/sa/tasks/ike_auth.h +++ b/src/libcharon/sa/ikev2/tasks/ike_auth.h @@ -25,7 +25,7 @@ typedef struct ike_auth_t ike_auth_t; #include #include -#include +#include /** * Task of type ike_auth, authenticates an IKE_SA using authenticators. diff --git a/src/libcharon/sa/tasks/ike_auth_lifetime.c b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.c similarity index 99% rename from src/libcharon/sa/tasks/ike_auth_lifetime.c rename to src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.c index 31e3bffca..a7d162e68 100644 --- a/src/libcharon/sa/tasks/ike_auth_lifetime.c +++ b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.c @@ -170,4 +170,3 @@ ike_auth_lifetime_t *ike_auth_lifetime_create(ike_sa_t *ike_sa, bool initiator) return &this->public; } - diff --git a/src/libcharon/sa/tasks/ike_auth_lifetime.h b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h similarity index 98% rename from src/libcharon/sa/tasks/ike_auth_lifetime.h rename to src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h index 9052f4274..5259beb2a 100644 --- a/src/libcharon/sa/tasks/ike_auth_lifetime.h +++ b/src/libcharon/sa/ikev2/tasks/ike_auth_lifetime.h @@ -25,7 +25,7 @@ typedef struct ike_auth_lifetime_t ike_auth_lifetime_t; #include #include -#include +#include /** * Task of type TASK_IKE_AUTH_LIFETIME, implements RFC4478. diff --git a/src/libcharon/sa/tasks/ike_cert_post.c b/src/libcharon/sa/ikev2/tasks/ike_cert_post.c similarity index 99% rename from src/libcharon/sa/tasks/ike_cert_post.c rename to src/libcharon/sa/ikev2/tasks/ike_cert_post.c index bedf323ff..10bb4d19b 100644 --- a/src/libcharon/sa/tasks/ike_cert_post.c +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_post.c @@ -254,4 +254,3 @@ ike_cert_post_t *ike_cert_post_create(ike_sa_t *ike_sa, bool initiator) return &this->public; } - diff --git a/src/libcharon/sa/tasks/ike_cert_post.h b/src/libcharon/sa/ikev2/tasks/ike_cert_post.h similarity index 98% rename from src/libcharon/sa/tasks/ike_cert_post.h rename to src/libcharon/sa/ikev2/tasks/ike_cert_post.h index b3881a01a..61d4c2d82 100644 --- a/src/libcharon/sa/tasks/ike_cert_post.h +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_post.h @@ -25,7 +25,7 @@ typedef struct ike_cert_post_t ike_cert_post_t; #include #include -#include +#include /** * Task of type ike_cert_post, certificate processing after authentication. diff --git a/src/libcharon/sa/tasks/ike_cert_pre.c b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.c similarity index 100% rename from src/libcharon/sa/tasks/ike_cert_pre.c rename to src/libcharon/sa/ikev2/tasks/ike_cert_pre.c diff --git a/src/libcharon/sa/tasks/ike_cert_pre.h b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h similarity index 98% rename from src/libcharon/sa/tasks/ike_cert_pre.h rename to src/libcharon/sa/ikev2/tasks/ike_cert_pre.h index 4b2d0d470..7de1f3271 100644 --- a/src/libcharon/sa/tasks/ike_cert_pre.h +++ b/src/libcharon/sa/ikev2/tasks/ike_cert_pre.h @@ -25,7 +25,7 @@ typedef struct ike_cert_pre_t ike_cert_pre_t; #include #include -#include +#include /** * Task of type ike_cert_post, certificate processing before authentication. diff --git a/src/libcharon/sa/tasks/ike_config.c b/src/libcharon/sa/ikev2/tasks/ike_config.c similarity index 99% rename from src/libcharon/sa/tasks/ike_config.c rename to src/libcharon/sa/ikev2/tasks/ike_config.c index 332af465b..da530a007 100644 --- a/src/libcharon/sa/tasks/ike_config.c +++ b/src/libcharon/sa/ikev2/tasks/ike_config.c @@ -443,4 +443,3 @@ ike_config_t *ike_config_create(ike_sa_t *ike_sa, bool initiator) return &this->public; } - diff --git a/src/libcharon/sa/tasks/ike_config.h b/src/libcharon/sa/ikev2/tasks/ike_config.h similarity index 97% rename from src/libcharon/sa/tasks/ike_config.h rename to src/libcharon/sa/ikev2/tasks/ike_config.h index d343761c1..239e35c43 100644 --- a/src/libcharon/sa/tasks/ike_config.h +++ b/src/libcharon/sa/ikev2/tasks/ike_config.h @@ -25,7 +25,7 @@ typedef struct ike_config_t ike_config_t; #include #include -#include +#include /** * Task of type TASK_IKE_CONFIG, sets up a virtual IP and other diff --git a/src/libcharon/sa/tasks/ike_delete.c b/src/libcharon/sa/ikev2/tasks/ike_delete.c similarity index 100% rename from src/libcharon/sa/tasks/ike_delete.c rename to src/libcharon/sa/ikev2/tasks/ike_delete.c diff --git a/src/libcharon/sa/tasks/ike_delete.h b/src/libcharon/sa/ikev2/tasks/ike_delete.h similarity index 97% rename from src/libcharon/sa/tasks/ike_delete.h rename to src/libcharon/sa/ikev2/tasks/ike_delete.h index 82782f393..039e068e6 100644 --- a/src/libcharon/sa/tasks/ike_delete.h +++ b/src/libcharon/sa/ikev2/tasks/ike_delete.h @@ -25,7 +25,7 @@ typedef struct ike_delete_t ike_delete_t; #include #include -#include +#include /** * Task of type ike_delete, delete an IKE_SA. diff --git a/src/libcharon/sa/tasks/ike_dpd.c b/src/libcharon/sa/ikev2/tasks/ike_dpd.c similarity index 100% rename from src/libcharon/sa/tasks/ike_dpd.c rename to src/libcharon/sa/ikev2/tasks/ike_dpd.c diff --git a/src/libcharon/sa/tasks/ike_dpd.h b/src/libcharon/sa/ikev2/tasks/ike_dpd.h similarity index 97% rename from src/libcharon/sa/tasks/ike_dpd.h rename to src/libcharon/sa/ikev2/tasks/ike_dpd.h index a9f68c31c..586557232 100644 --- a/src/libcharon/sa/tasks/ike_dpd.h +++ b/src/libcharon/sa/ikev2/tasks/ike_dpd.h @@ -25,7 +25,7 @@ typedef struct ike_dpd_t ike_dpd_t; #include #include -#include +#include /** * Task of type ike_dpd, detects dead peers. diff --git a/src/libcharon/sa/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c similarity index 99% rename from src/libcharon/sa/tasks/ike_init.c rename to src/libcharon/sa/ikev2/tasks/ike_init.c index 3b0c4e8f8..ceae484d0 100644 --- a/src/libcharon/sa/tasks/ike_init.c +++ b/src/libcharon/sa/ikev2/tasks/ike_init.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include #include diff --git a/src/libcharon/sa/tasks/ike_init.h b/src/libcharon/sa/ikev2/tasks/ike_init.h similarity index 98% rename from src/libcharon/sa/tasks/ike_init.h rename to src/libcharon/sa/ikev2/tasks/ike_init.h index 6855ac839..aa3cfa8a9 100644 --- a/src/libcharon/sa/tasks/ike_init.h +++ b/src/libcharon/sa/ikev2/tasks/ike_init.h @@ -25,7 +25,7 @@ typedef struct ike_init_t ike_init_t; #include #include -#include +#include /** * Task of type TASK_IKE_INIT, creates an IKE_SA without authentication. diff --git a/src/libcharon/sa/tasks/ike_me.c b/src/libcharon/sa/ikev2/tasks/ike_me.c similarity index 100% rename from src/libcharon/sa/tasks/ike_me.c rename to src/libcharon/sa/ikev2/tasks/ike_me.c diff --git a/src/libcharon/sa/tasks/ike_me.h b/src/libcharon/sa/ikev2/tasks/ike_me.h similarity index 99% rename from src/libcharon/sa/tasks/ike_me.h rename to src/libcharon/sa/ikev2/tasks/ike_me.h index 74dd1dedf..a7fe0c588 100644 --- a/src/libcharon/sa/tasks/ike_me.h +++ b/src/libcharon/sa/ikev2/tasks/ike_me.h @@ -25,7 +25,7 @@ typedef struct ike_me_t ike_me_t; #include #include -#include +#include /** * Task of type TASK_IKE_ME, detects and handles IKE-ME extensions. diff --git a/src/libcharon/sa/tasks/ike_mobike.c b/src/libcharon/sa/ikev2/tasks/ike_mobike.c similarity index 99% rename from src/libcharon/sa/tasks/ike_mobike.c rename to src/libcharon/sa/ikev2/tasks/ike_mobike.c index 6719bddd6..c533506bb 100644 --- a/src/libcharon/sa/tasks/ike_mobike.c +++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.c @@ -19,7 +19,7 @@ #include #include -#include +#include #include #define COOKIE2_SIZE 16 @@ -649,4 +649,3 @@ ike_mobike_t *ike_mobike_create(ike_sa_t *ike_sa, bool initiator) return &this->public; } - diff --git a/src/libcharon/sa/tasks/ike_mobike.h b/src/libcharon/sa/ikev2/tasks/ike_mobike.h similarity index 98% rename from src/libcharon/sa/tasks/ike_mobike.h rename to src/libcharon/sa/ikev2/tasks/ike_mobike.h index 16611939e..04cd33f51 100644 --- a/src/libcharon/sa/tasks/ike_mobike.h +++ b/src/libcharon/sa/ikev2/tasks/ike_mobike.h @@ -25,7 +25,7 @@ typedef struct ike_mobike_t ike_mobike_t; #include #include -#include +#include #include /** diff --git a/src/libcharon/sa/tasks/ike_natd.c b/src/libcharon/sa/ikev2/tasks/ike_natd.c similarity index 100% rename from src/libcharon/sa/tasks/ike_natd.c rename to src/libcharon/sa/ikev2/tasks/ike_natd.c diff --git a/src/libcharon/sa/tasks/ike_natd.h b/src/libcharon/sa/ikev2/tasks/ike_natd.h similarity index 98% rename from src/libcharon/sa/tasks/ike_natd.h rename to src/libcharon/sa/ikev2/tasks/ike_natd.h index 68114af42..33ebfcae7 100644 --- a/src/libcharon/sa/tasks/ike_natd.h +++ b/src/libcharon/sa/ikev2/tasks/ike_natd.h @@ -25,7 +25,7 @@ typedef struct ike_natd_t ike_natd_t; #include #include -#include +#include /** * Task of type ike_natd, detects NAT situation in IKE_SA_INIT exchange. diff --git a/src/libcharon/sa/tasks/ike_reauth.c b/src/libcharon/sa/ikev2/tasks/ike_reauth.c similarity index 99% rename from src/libcharon/sa/tasks/ike_reauth.c rename to src/libcharon/sa/ikev2/tasks/ike_reauth.c index 38c7a4272..d9f3fe8de 100644 --- a/src/libcharon/sa/tasks/ike_reauth.c +++ b/src/libcharon/sa/ikev2/tasks/ike_reauth.c @@ -16,7 +16,7 @@ #include "ike_reauth.h" #include -#include +#include typedef struct private_ike_reauth_t private_ike_reauth_t; @@ -190,4 +190,3 @@ ike_reauth_t *ike_reauth_create(ike_sa_t *ike_sa) return &this->public; } - diff --git a/src/libcharon/sa/tasks/ike_reauth.h b/src/libcharon/sa/ikev2/tasks/ike_reauth.h similarity index 97% rename from src/libcharon/sa/tasks/ike_reauth.h rename to src/libcharon/sa/ikev2/tasks/ike_reauth.h index 5e97b719c..52c507ede 100644 --- a/src/libcharon/sa/tasks/ike_reauth.h +++ b/src/libcharon/sa/ikev2/tasks/ike_reauth.h @@ -25,7 +25,7 @@ typedef struct ike_reauth_t ike_reauth_t; #include #include -#include +#include /** * Task of type ike_reauth, reestablishes an IKE_SA. diff --git a/src/libcharon/sa/tasks/ike_rekey.c b/src/libcharon/sa/ikev2/tasks/ike_rekey.c similarity index 99% rename from src/libcharon/sa/tasks/ike_rekey.c rename to src/libcharon/sa/ikev2/tasks/ike_rekey.c index a0d346040..2cfcdc1fc 100644 --- a/src/libcharon/sa/tasks/ike_rekey.c +++ b/src/libcharon/sa/ikev2/tasks/ike_rekey.c @@ -18,8 +18,8 @@ #include #include -#include -#include +#include +#include #include #include diff --git a/src/libcharon/sa/tasks/ike_rekey.h b/src/libcharon/sa/ikev2/tasks/ike_rekey.h similarity index 98% rename from src/libcharon/sa/tasks/ike_rekey.h rename to src/libcharon/sa/ikev2/tasks/ike_rekey.h index 6a9d59b0e..20fcd80ed 100644 --- a/src/libcharon/sa/tasks/ike_rekey.h +++ b/src/libcharon/sa/ikev2/tasks/ike_rekey.h @@ -25,7 +25,7 @@ typedef struct ike_rekey_t ike_rekey_t; #include #include -#include +#include /** * Task of type TASK_IKE_REKEY, rekey an established IKE_SA. diff --git a/src/libcharon/sa/tasks/ike_vendor.c b/src/libcharon/sa/ikev2/tasks/ike_vendor.c similarity index 99% rename from src/libcharon/sa/tasks/ike_vendor.c rename to src/libcharon/sa/ikev2/tasks/ike_vendor.c index 7b3cc6e91..b2b965a57 100644 --- a/src/libcharon/sa/tasks/ike_vendor.c +++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.c @@ -139,4 +139,3 @@ ike_vendor_t *ike_vendor_create(ike_sa_t *ike_sa, bool initiator) return &this->public; } - diff --git a/src/libcharon/sa/tasks/ike_vendor.h b/src/libcharon/sa/ikev2/tasks/ike_vendor.h similarity index 97% rename from src/libcharon/sa/tasks/ike_vendor.h rename to src/libcharon/sa/ikev2/tasks/ike_vendor.h index 6c353c447..54aad9541 100644 --- a/src/libcharon/sa/tasks/ike_vendor.h +++ b/src/libcharon/sa/ikev2/tasks/ike_vendor.h @@ -25,7 +25,7 @@ typedef struct ike_vendor_t ike_vendor_t; #include #include -#include +#include /** * Vendor ID processing task. diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c index f132822b7..bcf131fd0 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat.c @@ -14,8 +14,9 @@ */ #include "keymat.h" -#include "keymat_v1.h" -#include "keymat_v2.h" + +#include +#include /** * See header diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index 5395c3776..4a551a8f5 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -28,7 +28,7 @@ typedef struct keymat_t keymat_t; #include #include #include -#include /* for ike_version_t */ +#include #include /** diff --git a/src/libcharon/sa/tasks/task.c b/src/libcharon/sa/task.c similarity index 100% rename from src/libcharon/sa/tasks/task.c rename to src/libcharon/sa/task.c diff --git a/src/libcharon/sa/tasks/task.h b/src/libcharon/sa/task.h similarity index 100% rename from src/libcharon/sa/tasks/task.h rename to src/libcharon/sa/task.h diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c index 3538087bc..70f732fab 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager.c @@ -14,8 +14,9 @@ */ #include "task_manager.h" -#include "task_manager_v1.h" -#include "task_manager_v2.h" + +#include +#include /** * See header diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 42a04fb64..47b39a68a 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -29,7 +29,7 @@ typedef enum task_queue_t task_queue_t; #include #include #include -#include +#include /** * First retransmit timeout in seconds. From e51a28fda8761f67494bf0a8d996f5f8f53dc302 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 13:13:45 +0100 Subject: [PATCH 362/534] Added a --disable-ikev2 option to disable IKEv2 support in charon --- configure.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/configure.in b/configure.in index 0be86058a..417e33794 100755 --- a/configure.in +++ b/configure.in @@ -161,10 +161,11 @@ ARG_ENABL_SET([integrity-test], [enable integrity testing of libstrongswan and p ARG_DISBL_SET([load-warning], [disable the charon/pluto plugin load option warning in starter.]) ARG_ENABL_SET([pluto], [enable the IKEv1 keying daemon pluto.]) ARG_DISBL_SET([ikev1], [disable IKEv1 protocol support in charon.]) +ARG_DISBL_SET([ikev2], [disable IKEv2 protocol support in charon.]) ARG_DISBL_SET([xauth], [disable xauth plugin.]) ARG_DISBL_SET([threads], [disable the use of threads in pluto. Charon always uses threads.]) ARG_DISBL_SET([adns], [disable the use of adns in pluto (disables opportunistic encryption).]) -ARG_DISBL_SET([charon], [disable the IKEv2 keying daemon charon.]) +ARG_DISBL_SET([charon], [disable the IKEv1/IKEv2 keying daemon charon.]) ARG_DISBL_SET([tools], [disable additional utilities (openac, scepclient and pki).]) ARG_DISBL_SET([scripts], [disable additional utilities (found in directory scripts).]) ARG_ENABL_SET([conftest], [enforce Suite B conformance test framework.]) @@ -1014,6 +1015,7 @@ AM_CONDITIONAL(USE_INTEGRITY_TEST, test x$integrity_test = xtrue) AM_CONDITIONAL(USE_LOAD_WARNING, test x$load_warning = xtrue) AM_CONDITIONAL(USE_PLUTO, test x$pluto = xtrue) AM_CONDITIONAL(USE_IKEV1, test x$ikev1 = xtrue) +AM_CONDITIONAL(USE_IKEV2, test x$ikev2 = xtrue) AM_CONDITIONAL(USE_THREADS, test x$threads = xtrue) AM_CONDITIONAL(USE_ADNS, test x$adns = xtrue) AM_CONDITIONAL(USE_CHARON, test x$charon = xtrue) @@ -1051,6 +1053,9 @@ fi if test x$ikev1 = xtrue; then AC_DEFINE(USE_IKEV1) fi +if test x$ikev2 = xtrue; then + AC_DEFINE(USE_IKEV2) +fi dnl ============================== dnl build Makefiles From 7d0a3a427d6ce15e4d410fde53d97a4336b5a2a7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 13:32:41 +0100 Subject: [PATCH 363/534] Factories honor charon IKEv1/IKEv2 protocol support flags --- src/libcharon/sa/authenticator.c | 8 ++++++++ src/libcharon/sa/keymat.c | 9 ++++++++- src/libcharon/sa/task_manager.c | 9 ++++++++- 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/authenticator.c b/src/libcharon/sa/authenticator.c index d7a4b3eef..ea1889a61 100644 --- a/src/libcharon/sa/authenticator.c +++ b/src/libcharon/sa/authenticator.c @@ -45,6 +45,8 @@ ENUM_NEXT(auth_method_names, AUTH_XAUTH_INIT_PSK, AUTH_HYBRID_RESP_RSA, AUTH_ECD ); ENUM_END(auth_method_names, AUTH_HYBRID_RESP_RSA); +#ifdef USE_IKEV2 + /** * Described in header. */ @@ -106,6 +108,10 @@ authenticator_t *authenticator_create_verifier( } } +#endif /* USE_IKEV2 */ + +#ifdef USE_IKEV1 + /** * Described in header. */ @@ -137,3 +143,5 @@ authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, return NULL; } } + +#endif /* USE_IKEV1 */ diff --git a/src/libcharon/sa/keymat.c b/src/libcharon/sa/keymat.c index bcf131fd0..d04d966ad 100644 --- a/src/libcharon/sa/keymat.c +++ b/src/libcharon/sa/keymat.c @@ -26,12 +26,19 @@ keymat_t *keymat_create(ike_version_t version, bool initiator) switch (version) { case IKEV1: +#ifdef USE_IKEV1 return &keymat_v1_create(initiator)->keymat; +#endif + break; case IKEV2: +#ifdef USE_IKEV2 return &keymat_v2_create(initiator)->keymat; +#endif + break; default: - return NULL; + break; } + return NULL; } /** diff --git a/src/libcharon/sa/task_manager.c b/src/libcharon/sa/task_manager.c index 70f732fab..c42008ba9 100644 --- a/src/libcharon/sa/task_manager.c +++ b/src/libcharon/sa/task_manager.c @@ -26,11 +26,18 @@ task_manager_t *task_manager_create(ike_sa_t *ike_sa) switch (ike_sa->get_version(ike_sa)) { case IKEV1: +#ifdef USE_IKEV1 return &task_manager_v1_create(ike_sa)->task_manager; +#endif + break; case IKEV2: +#ifdef USE_IKEV2 return &task_manager_v2_create(ike_sa)->task_manager; +#endif + break; default: - return NULL; + break; } + return NULL; } From 244d715de5c0a5eddede2cde26fd300c548ab526 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 13:49:09 +0100 Subject: [PATCH 364/534] Moved liveness checking task creation to protocol specific task manager --- src/libcharon/sa/ike_sa.c | 23 +++-------------------- src/libcharon/sa/ikev1/task_manager_v1.c | 7 +++++++ src/libcharon/sa/ikev2/task_manager_v2.c | 21 +++++++++++++++++++++ src/libcharon/sa/task_manager.h | 5 +++++ 4 files changed, 36 insertions(+), 20 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 0ee4324bf..da7ff43ed 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -603,26 +603,9 @@ METHOD(ike_sa_t, send_dpd, status_t, if (!delay || diff >= delay) { /* to long ago, initiate dead peer detection */ - task_t *task; - ike_mobike_t *mobike; - - if (supports_extension(this, EXT_MOBIKE) && - has_condition(this, COND_NAT_HERE)) - { - /* use mobike enabled DPD to detect NAT mapping changes */ - mobike = ike_mobike_create(&this->public, TRUE); - mobike->dpd(mobike); - task = &mobike->task; - } - else - { - task = (task_t*)ike_dpd_create(TRUE); - } - diff = 0; DBG1(DBG_IKE, "sending DPD request"); - - this->task_manager->queue_task(this->task_manager, task); - this->task_manager->initiate(this->task_manager); + this->task_manager->queue_dpd(this->task_manager); + diff = 0; } } /* recheck in "interval" seconds */ @@ -631,7 +614,7 @@ METHOD(ike_sa_t, send_dpd, status_t, job = (job_t*)send_dpd_job_create(this->ike_sa_id); lib->scheduler->schedule_job(lib->scheduler, job, delay - diff); } - return SUCCESS; + return this->task_manager->initiate(this->task_manager); } METHOD(ike_sa_t, get_state, ike_sa_state_t, diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 8e4aa7496..5c1c72777 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1011,6 +1011,12 @@ METHOD(task_manager_t, queue_task, void, this->queued_tasks->insert_last(this->queued_tasks, task); } +METHOD(task_manager_t, queue_dpd, void, + private_task_manager_t *this) +{ + /* TODO-IKEv1: DPD checking */ +} + METHOD(task_manager_t, adopt_tasks, void, private_task_manager_t *this, task_manager_t *other_public) { @@ -1087,6 +1093,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .task_manager = { .process_message = _process_message, .queue_task = _queue_task, + .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, .incr_mid = _incr_mid, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index cce9551d5..aa0fb4276 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1176,6 +1176,26 @@ METHOD(task_manager_t, queue_task, void, this->queued_tasks->insert_last(this->queued_tasks, task); } +METHOD(task_manager_t, queue_dpd, void, + private_task_manager_t *this) +{ + ike_mobike_t *mobike; + + if (this->ike_sa->supports_extension(this->ike_sa, EXT_MOBIKE) && + this->ike_sa->has_condition(this->ike_sa, COND_NAT_HERE)) + { + /* use mobike enabled DPD to detect NAT mapping changes */ + mobike = ike_mobike_create(this->ike_sa, TRUE); + mobike->dpd(mobike); + queue_task(this, &mobike->task); + } + else + { + queue_task(this, (task_t*)ike_dpd_create(TRUE)); + } +} + + METHOD(task_manager_t, adopt_tasks, void, private_task_manager_t *this, task_manager_t *other_public) { @@ -1280,6 +1300,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .task_manager = { .process_message = _process_message, .queue_task = _queue_task, + .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, .incr_mid = _incr_mid, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 47b39a68a..2ef904104 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -124,6 +124,11 @@ struct task_manager_t { */ void (*queue_task) (task_manager_t *this, task_t *task); + /** + * Queue liveness checking tasks. + */ + void (*queue_dpd)(task_manager_t *this); + /** * Retransmit a request if it hasn't been acknowledged yet. * From a60daa07f6fc0445ab5bc25b3471af6180b04c91 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 14:15:02 +0100 Subject: [PATCH 365/534] Moved IKE_SA initiate task creation to protocol specific task manager --- src/libcharon/sa/ike_sa.c | 43 +----------------------- src/libcharon/sa/ikev1/task_manager_v1.c | 11 ++++++ src/libcharon/sa/ikev2/task_manager_v2.c | 25 ++++++++++++++ src/libcharon/sa/task_manager.h | 5 +++ 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index da7ff43ed..8d52fdcac 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1099,48 +1099,7 @@ METHOD(ike_sa_t, initiate, status_t, } set_condition(this, COND_ORIGINAL_INITIATOR, TRUE); - - if (this->version == IKEV1) - { - task = (task_t*)isakmp_vendor_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)isakmp_cert_pre_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)main_mode_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)isakmp_cert_post_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)isakmp_natd_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - } - else - { - task = (task_t*)ike_vendor_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_init_create(&this->public, TRUE, NULL); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_natd_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_pre_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_auth_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_cert_post_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_config_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_auth_lifetime_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - if (this->peer_cfg->use_mobike(this->peer_cfg)) - { - task = (task_t*)ike_mobike_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - } -#ifdef ME - task = (task_t*)ike_me_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); -#endif /* ME */ - } + this->task_manager->queue_ike(this->task_manager); } #ifdef ME diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 5c1c72777..e8399e418 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1011,6 +1011,16 @@ METHOD(task_manager_t, queue_task, void, this->queued_tasks->insert_last(this->queued_tasks, task); } +METHOD(task_manager_t, queue_ike, void, + private_task_manager_t *this) +{ + queue_task(this, (task_t*)isakmp_vendor_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)isakmp_cert_pre_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)main_mode_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)isakmp_cert_post_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)isakmp_natd_create(this->ike_sa, TRUE)); +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { @@ -1093,6 +1103,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .task_manager = { .process_message = _process_message, .queue_task = _queue_task, + .queue_ike = _queue_ike, .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index aa0fb4276..d28562b70 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1176,6 +1176,30 @@ METHOD(task_manager_t, queue_task, void, this->queued_tasks->insert_last(this->queued_tasks, task); } +METHOD(task_manager_t, queue_ike, void, + private_task_manager_t *this) +{ + peer_cfg_t *peer_cfg; + + queue_task(this, (task_t*)ike_vendor_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_init_create(this->ike_sa, TRUE, NULL)); + queue_task(this, (task_t*)ike_natd_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_cert_pre_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_auth_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_cert_post_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_config_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_auth_lifetime_create(this->ike_sa, TRUE)); + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg->use_mobike(peer_cfg)) + { + queue_task(this, (task_t*)ike_mobike_create(this->ike_sa, TRUE)); + } +#ifdef ME + queue_task(this, (task_t*)ike_me_create(this->ike_sa, TRUE)); +#endif /* ME */ +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { @@ -1300,6 +1324,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .task_manager = { .process_message = _process_message, .queue_task = _queue_task, + .queue_ike = _queue_ike, .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 2ef904104..6a388e411 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -124,6 +124,11 @@ struct task_manager_t { */ void (*queue_task) (task_manager_t *this, task_t *task); + /** + * Queue IKE_SA establishing tasks. + */ + void (*queue_ike)(task_manager_t *this); + /** * Queue liveness checking tasks. */ From fe43d9a237a531d5b4bfc7cc1ff307817162508b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 14:15:21 +0100 Subject: [PATCH 366/534] Moved CHILD_SA initiate task creation to protocol specific task manager --- src/libcharon/sa/ike_sa.c | 21 ++------------------- src/libcharon/sa/ikev1/task_manager_v1.c | 8 ++++++++ src/libcharon/sa/ikev2/task_manager_v2.c | 15 +++++++++++++++ src/libcharon/sa/task_manager.h | 11 +++++++++++ 4 files changed, 36 insertions(+), 19 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 8d52fdcac..c177a7dcb 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1080,8 +1080,6 @@ METHOD(ike_sa_t, initiate, status_t, private_ike_sa_t *this, child_cfg_t *child_cfg, u_int32_t reqid, traffic_selector_t *tsi, traffic_selector_t *tsr) { - task_t *task; - if (this->state == IKE_CREATED) { resolve_hosts(this); @@ -1118,23 +1116,8 @@ METHOD(ike_sa_t, initiate, status_t, #endif /* ME */ { /* normal IKE_SA with CHILD_SA */ - if (this->version == IKEV2) - { - task = (task_t*)child_create_create(&this->public, child_cfg, FALSE, - tsi, tsr); - if (reqid) - { - child_create_t *child_create = (child_create_t*)task; - child_create->use_reqid(child_create, reqid); - } - } - else - { - task = (task_t*)quick_mode_create(&this->public, child_cfg, - tsi, tsr); - } - this->task_manager->queue_task(this->task_manager, task); - + this->task_manager->queue_child(this->task_manager, child_cfg, reqid, + tsi, tsr); #ifdef ME if (this->peer_cfg->get_mediated_by(this->peer_cfg)) { diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index e8399e418..d42f63f01 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1021,6 +1021,13 @@ METHOD(task_manager_t, queue_ike, void, queue_task(this, (task_t*)isakmp_natd_create(this->ike_sa, TRUE)); } +METHOD(task_manager_t, queue_child, void, + private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, + traffic_selector_t *tsi, traffic_selector_t *tsr) +{ + queue_task(this, (task_t*)quick_mode_create(this->ike_sa, cfg, tsi, tsr)); +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { @@ -1104,6 +1111,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .process_message = _process_message, .queue_task = _queue_task, .queue_ike = _queue_ike, + .queue_child = _queue_child, .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index d28562b70..cfc545491 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1200,6 +1200,20 @@ METHOD(task_manager_t, queue_ike, void, #endif /* ME */ } +METHOD(task_manager_t, queue_child, void, + private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, + traffic_selector_t *tsi, traffic_selector_t *tsr) +{ + child_create_t *task; + + task = child_create_create(this->ike_sa, cfg, FALSE, tsi, tsr); + if (reqid) + { + task->use_reqid(task, reqid); + } + queue_task(this, &task->task); +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { @@ -1325,6 +1339,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .process_message = _process_message, .queue_task = _queue_task, .queue_ike = _queue_ike, + .queue_child = _queue_child, .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 6a388e411..d4a8eebf8 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -129,6 +129,17 @@ struct task_manager_t { */ void (*queue_ike)(task_manager_t *this); + /** + * Queue CHILD_SA establishing tasks. + * + * @param cfg CHILD_SA config to establish + * @param reqid reqid to use for CHILD_SA + * @param tsi initiator traffic selector, if packet-triggered + * @param tsr responder traffic selector, if packet-triggered + */ + void (*queue_child)(task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, + traffic_selector_t *tsi, traffic_selector_t *tsr); + /** * Queue liveness checking tasks. */ From 463a73cc0f152d5abcf1855826fdaf06441f273e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 14:20:33 +0100 Subject: [PATCH 367/534] Moved CHILD_SA rekey task creation to protocol specific task manager --- src/libcharon/sa/ike_sa.c | 5 +---- src/libcharon/sa/ikev1/task_manager_v1.c | 7 +++++++ src/libcharon/sa/ikev2/task_manager_v2.c | 7 +++++++ src/libcharon/sa/task_manager.h | 9 +++++++++ 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index c177a7dcb..7026608f0 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1265,10 +1265,7 @@ METHOD(ike_sa_t, remove_child_sa, void, METHOD(ike_sa_t, rekey_child_sa, status_t, private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) { - child_rekey_t *child_rekey; - - child_rekey = child_rekey_create(&this->public, protocol, spi); - this->task_manager->queue_task(this->task_manager, &child_rekey->task); + this->task_manager->queue_child_rekey(this->task_manager, protocol, spi); return this->task_manager->initiate(this->task_manager); } diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index d42f63f01..a4509e69c 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1028,6 +1028,12 @@ METHOD(task_manager_t, queue_child, void, queue_task(this, (task_t*)quick_mode_create(this->ike_sa, cfg, tsi, tsr)); } +METHOD(task_manager_t, queue_child_rekey, void, + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) +{ + /* TODO-IKEv1: CHILD rekeying */ +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { @@ -1112,6 +1118,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .queue_task = _queue_task, .queue_ike = _queue_ike, .queue_child = _queue_child, + .queue_child_rekey = _queue_child_rekey, .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index cfc545491..d8dc9b8c3 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1214,6 +1214,12 @@ METHOD(task_manager_t, queue_child, void, queue_task(this, &task->task); } +METHOD(task_manager_t, queue_child_rekey, void, + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) +{ + queue_task(this, (task_t*)child_rekey_create(this->ike_sa, protocol, spi)); +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { @@ -1340,6 +1346,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .queue_task = _queue_task, .queue_ike = _queue_ike, .queue_child = _queue_child, + .queue_child_rekey = _queue_child_rekey, .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index d4a8eebf8..e2e797c3f 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -140,6 +140,15 @@ struct task_manager_t { void (*queue_child)(task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, traffic_selector_t *tsi, traffic_selector_t *tsr); + /** + * Queue CHILD_SA rekeying tasks. + * + * @param protocol CHILD_SA protocol, AH|ESP + * @param spi CHILD_SA SPI to rekey + */ + void (*queue_child_rekey)(task_manager_t *this, protocol_id_t protocol, + u_int32_t spi); + /** * Queue liveness checking tasks. */ From 83c5fda053005668a35c675fd9f458a8b54d4bc8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 14:25:14 +0100 Subject: [PATCH 368/534] Moved CHILD_SA delete task creation to protocol specific task manager --- src/libcharon/sa/ike_sa.c | 12 +----------- src/libcharon/sa/ikev1/task_manager_v1.c | 9 +++++++++ src/libcharon/sa/ikev2/task_manager_v2.c | 7 +++++++ src/libcharon/sa/task_manager.h | 9 +++++++++ 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 7026608f0..d3465acef 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1272,17 +1272,7 @@ METHOD(ike_sa_t, rekey_child_sa, status_t, METHOD(ike_sa_t, delete_child_sa, status_t, private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) { - task_t *task; - - if (this->version == IKEV1) - { - task = (task_t*)quick_delete_create(&this->public, protocol, spi, FALSE); - } - else - { - task = (task_t*)child_delete_create(&this->public, protocol, spi); - } - this->task_manager->queue_task(this->task_manager, task); + this->task_manager->queue_child_delete(this->task_manager, protocol, spi); return this->task_manager->initiate(this->task_manager); } diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index a4509e69c..82c5c31bc 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -1034,6 +1035,13 @@ METHOD(task_manager_t, queue_child_rekey, void, /* TODO-IKEv1: CHILD rekeying */ } +METHOD(task_manager_t, queue_child_delete, void, + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) +{ + queue_task(this, (task_t*)quick_delete_create(this->ike_sa, protocol, + spi, FALSE)); +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { @@ -1119,6 +1127,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .queue_ike = _queue_ike, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, + .queue_child_delete = _queue_child_delete, .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index d8dc9b8c3..ee2d536fe 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1220,6 +1220,12 @@ METHOD(task_manager_t, queue_child_rekey, void, queue_task(this, (task_t*)child_rekey_create(this->ike_sa, protocol, spi)); } +METHOD(task_manager_t, queue_child_delete, void, + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) +{ + queue_task(this, (task_t*)child_delete_create(this->ike_sa, protocol, spi)); +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { @@ -1347,6 +1353,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .queue_ike = _queue_ike, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, + .queue_child_delete = _queue_child_delete, .queue_dpd = _queue_dpd, .initiate = _initiate, .retransmit = _retransmit, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index e2e797c3f..cfec427e4 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -149,6 +149,15 @@ struct task_manager_t { void (*queue_child_rekey)(task_manager_t *this, protocol_id_t protocol, u_int32_t spi); + /** + * Queue CHILD_SA delete tasks. + * + * @param protocol CHILD_SA protocol, AH|ESP + * @param spi CHILD_SA SPI to rekey + */ + void (*queue_child_delete)(task_manager_t *this, protocol_id_t protocol, + u_int32_t spi); + /** * Queue liveness checking tasks. */ From 3ed148b37e0159fd93a75fa033a699c8e0f09f0f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 14:29:57 +0100 Subject: [PATCH 369/534] Moved IKE_SA delete task creation to protocol specific task manager --- src/libcharon/sa/ike_sa.c | 12 +----------- src/libcharon/sa/ikev1/task_manager_v1.c | 8 ++++++++ src/libcharon/sa/ikev2/task_manager_v2.c | 7 +++++++ src/libcharon/sa/task_manager.h | 5 +++++ 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index d3465acef..474703056 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1302,21 +1302,11 @@ METHOD(ike_sa_t, destroy_child_sa, status_t, METHOD(ike_sa_t, delete_, status_t, private_ike_sa_t *this) { - task_t *task; - switch (this->state) { case IKE_ESTABLISHED: case IKE_REKEYING: - if (this->version == IKEV1) - { - task = (task_t*)isakmp_delete_create(&this->public, TRUE); - } - else - { - task = (task_t*)ike_delete_create(&this->public, TRUE); - } - this->task_manager->queue_task(this->task_manager, task); + this->task_manager->queue_ike_delete(this->task_manager); return this->task_manager->initiate(this->task_manager); case IKE_CREATED: DBG1(DBG_IKE, "deleting unestablished IKE_SA"); diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 82c5c31bc..012890afa 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -1022,6 +1023,12 @@ METHOD(task_manager_t, queue_ike, void, queue_task(this, (task_t*)isakmp_natd_create(this->ike_sa, TRUE)); } +METHOD(task_manager_t, queue_ike_delete, void, + private_task_manager_t *this) +{ + queue_task(this, (task_t*)isakmp_delete_create(this->ike_sa, TRUE)); +} + METHOD(task_manager_t, queue_child, void, private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, traffic_selector_t *tsi, traffic_selector_t *tsr) @@ -1125,6 +1132,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .process_message = _process_message, .queue_task = _queue_task, .queue_ike = _queue_ike, + .queue_ike_delete = _queue_ike_delete, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, .queue_child_delete = _queue_child_delete, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index ee2d536fe..5aa96cc4e 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1200,6 +1200,12 @@ METHOD(task_manager_t, queue_ike, void, #endif /* ME */ } +METHOD(task_manager_t, queue_ike_delete, void, + private_task_manager_t *this) +{ + queue_task(this, (task_t*)ike_delete_create(this->ike_sa, TRUE)); +} + METHOD(task_manager_t, queue_child, void, private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, traffic_selector_t *tsi, traffic_selector_t *tsr) @@ -1351,6 +1357,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .process_message = _process_message, .queue_task = _queue_task, .queue_ike = _queue_ike, + .queue_ike_delete = _queue_ike_delete, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, .queue_child_delete = _queue_child_delete, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index cfec427e4..eeccb1aab 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -129,6 +129,11 @@ struct task_manager_t { */ void (*queue_ike)(task_manager_t *this); + /** + * Queue IKE_SA delete tasks. + */ + void (*queue_ike_delete)(task_manager_t *this); + /** * Queue CHILD_SA establishing tasks. * From dab60d6411ad97299cd9271232ecbc929e38315c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 14:35:14 +0100 Subject: [PATCH 370/534] Moved IKE_SA rekey task creation to protocol specific task manager --- src/libcharon/sa/ike_sa.c | 6 +----- src/libcharon/sa/ikev1/task_manager_v1.c | 7 +++++++ src/libcharon/sa/ikev2/task_manager_v2.c | 7 +++++++ src/libcharon/sa/task_manager.h | 5 +++++ 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 474703056..7e2fccdb3 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1325,11 +1325,7 @@ METHOD(ike_sa_t, delete_, status_t, METHOD(ike_sa_t, rekey, status_t, private_ike_sa_t *this) { - ike_rekey_t *ike_rekey; - - ike_rekey = ike_rekey_create(&this->public, TRUE); - - this->task_manager->queue_task(this->task_manager, &ike_rekey->task); + this->task_manager->queue_ike_rekey(this->task_manager); return this->task_manager->initiate(this->task_manager); } diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 012890afa..f135d0262 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1023,6 +1023,12 @@ METHOD(task_manager_t, queue_ike, void, queue_task(this, (task_t*)isakmp_natd_create(this->ike_sa, TRUE)); } +METHOD(task_manager_t, queue_ike_rekey, void, + private_task_manager_t *this) +{ + /* TODO-IKEv1: IKE_SA rekeying */ +} + METHOD(task_manager_t, queue_ike_delete, void, private_task_manager_t *this) { @@ -1132,6 +1138,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .process_message = _process_message, .queue_task = _queue_task, .queue_ike = _queue_ike, + .queue_ike_rekey = _queue_ike_rekey, .queue_ike_delete = _queue_ike_delete, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 5aa96cc4e..fd9572d92 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1200,6 +1200,12 @@ METHOD(task_manager_t, queue_ike, void, #endif /* ME */ } +METHOD(task_manager_t, queue_ike_rekey, void, + private_task_manager_t *this) +{ + queue_task(this, (task_t*)ike_rekey_create(this->ike_sa, TRUE)); +} + METHOD(task_manager_t, queue_ike_delete, void, private_task_manager_t *this) { @@ -1357,6 +1363,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .process_message = _process_message, .queue_task = _queue_task, .queue_ike = _queue_ike, + .queue_ike_rekey = _queue_ike_rekey, .queue_ike_delete = _queue_ike_delete, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index eeccb1aab..6ea48fa1c 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -129,6 +129,11 @@ struct task_manager_t { */ void (*queue_ike)(task_manager_t *this); + /** + * Queue IKE_SA rekey tasks. + */ + void (*queue_ike_rekey)(task_manager_t *this); + /** * Queue IKE_SA delete tasks. */ From cedb412e5a823907b9f3ea2ac0821cecb41f9699 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 14:39:05 +0100 Subject: [PATCH 371/534] Moved IKE_SA reauth task creation to protocol specific task manager --- src/libcharon/sa/ike_sa.c | 6 +----- src/libcharon/sa/ikev1/task_manager_v1.c | 7 +++++++ src/libcharon/sa/ikev2/task_manager_v2.c | 8 ++++++++ src/libcharon/sa/task_manager.h | 5 +++++ 4 files changed, 21 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 7e2fccdb3..d3aad94df 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1332,8 +1332,6 @@ METHOD(ike_sa_t, rekey, status_t, METHOD(ike_sa_t, reauth, status_t, private_ike_sa_t *this) { - task_t *task; - /* we can't reauthenticate as responder when we use EAP or virtual IPs. * If the peer does not support RFC4478, there is no way to keep the * IKE_SA up. */ @@ -1359,9 +1357,7 @@ METHOD(ike_sa_t, reauth, status_t, DBG1(DBG_IKE, "reauthenticating actively"); } } - task = (task_t*)ike_reauth_create(&this->public); - this->task_manager->queue_task(this->task_manager, task); - + this->task_manager->queue_ike_reauth(this->task_manager); return this->task_manager->initiate(this->task_manager); } diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index f135d0262..d23b237fa 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1029,6 +1029,12 @@ METHOD(task_manager_t, queue_ike_rekey, void, /* TODO-IKEv1: IKE_SA rekeying */ } +METHOD(task_manager_t, queue_ike_reauth, void, + private_task_manager_t *this) +{ + /* TODO-IKEv1: IKE_SA reauth */ +} + METHOD(task_manager_t, queue_ike_delete, void, private_task_manager_t *this) { @@ -1139,6 +1145,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .queue_task = _queue_task, .queue_ike = _queue_ike, .queue_ike_rekey = _queue_ike_rekey, + .queue_ike_reauth = _queue_ike_reauth, .queue_ike_delete = _queue_ike_delete, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index fd9572d92..f2cfad2a1 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -1206,6 +1207,12 @@ METHOD(task_manager_t, queue_ike_rekey, void, queue_task(this, (task_t*)ike_rekey_create(this->ike_sa, TRUE)); } +METHOD(task_manager_t, queue_ike_reauth, void, + private_task_manager_t *this) +{ + queue_task(this, (task_t*)ike_reauth_create(this->ike_sa)); +} + METHOD(task_manager_t, queue_ike_delete, void, private_task_manager_t *this) { @@ -1364,6 +1371,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .queue_task = _queue_task, .queue_ike = _queue_ike, .queue_ike_rekey = _queue_ike_rekey, + .queue_ike_reauth = _queue_ike_reauth, .queue_ike_delete = _queue_ike_delete, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 6ea48fa1c..4087265c7 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -134,6 +134,11 @@ struct task_manager_t { */ void (*queue_ike_rekey)(task_manager_t *this); + /** + * Queue IKE_SA reauth tasks. + */ + void (*queue_ike_reauth)(task_manager_t *this); + /** * Queue IKE_SA delete tasks. */ From 26eee421b4d38f49d153e6cad111daf11a3630ce Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 14:46:56 +0100 Subject: [PATCH 372/534] Check in task manager if we have to requeue IKE tasks in a non-first keyingtry --- src/libcharon/sa/ike_sa.c | 36 +--------------- src/libcharon/sa/ikev2/task_manager_v2.c | 53 ++++++++++++++++++------ 2 files changed, 42 insertions(+), 47 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index d3aad94df..43e61ef74 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1491,40 +1491,6 @@ METHOD(ike_sa_t, reestablish, status_t, return status; } -/** - * Requeue the IKE_SA_INIT tasks for initiation, if required - */ -static void requeue_init_tasks(private_ike_sa_t *this) -{ - enumerator_t *enumerator; - bool has_init = FALSE; - task_t *task; - - /* if we have advanced to IKE_AUTH, the IKE_INIT and related tasks - * have already completed. Recreate them if necessary. */ - enumerator = this->task_manager->create_task_enumerator( - this->task_manager, TASK_QUEUE_QUEUED); - while (enumerator->enumerate(enumerator, &task)) - { - if (task->get_type(task) == TASK_IKE_INIT) - { - has_init = TRUE; - break; - } - } - enumerator->destroy(enumerator); - - if (!has_init) - { - task = (task_t*)ike_vendor_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_natd_create(&this->public, TRUE); - this->task_manager->queue_task(this->task_manager, task); - task = (task_t*)ike_init_create(&this->public, TRUE, NULL); - this->task_manager->queue_task(this->task_manager, task); - } -} - METHOD(ike_sa_t, retransmit, status_t, private_ike_sa_t *this, u_int32_t message_id) { @@ -1544,7 +1510,7 @@ METHOD(ike_sa_t, retransmit, status_t, DBG1(DBG_IKE, "peer not responding, trying again (%d/%d)", this->keyingtry + 1, tries); reset(this); - requeue_init_tasks(this); + this->task_manager->queue_ike(this->task_manager); return this->task_manager->initiate(this->task_manager); } DBG1(DBG_IKE, "establishing IKE_SA failed, peer not responding"); diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index f2cfad2a1..91589b15c 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1182,23 +1182,52 @@ METHOD(task_manager_t, queue_ike, void, { peer_cfg_t *peer_cfg; - queue_task(this, (task_t*)ike_vendor_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)ike_init_create(this->ike_sa, TRUE, NULL)); - queue_task(this, (task_t*)ike_natd_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)ike_cert_pre_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)ike_auth_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)ike_cert_post_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)ike_config_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)ike_auth_lifetime_create(this->ike_sa, TRUE)); + enumerator_t *enumerator; + bool has_init = FALSE, has_auth = FALSE; + task_t *task; - peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); - if (peer_cfg->use_mobike(peer_cfg)) + /* when initiating with a non-first keying try, IKE_AUTH is still queued, + * but IKE_INIT is not */ + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + while (enumerator->enumerate(enumerator, &task)) { - queue_task(this, (task_t*)ike_mobike_create(this->ike_sa, TRUE)); + switch (task->get_type(task)) + { + case TASK_IKE_INIT: + has_init = TRUE; + break; + case TASK_IKE_AUTH: + has_auth = TRUE; + break; + default: + break; + } } + enumerator->destroy(enumerator); + + if (!has_init) + { + queue_task(this, (task_t*)ike_vendor_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_init_create(this->ike_sa, TRUE, NULL)); + queue_task(this, (task_t*)ike_natd_create(this->ike_sa, TRUE)); + } + if (!has_auth) + { + queue_task(this, (task_t*)ike_cert_pre_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_auth_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_cert_post_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_config_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_auth_lifetime_create(this->ike_sa, TRUE)); + + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg->use_mobike(peer_cfg)) + { + queue_task(this, (task_t*)ike_mobike_create(this->ike_sa, TRUE)); + } #ifdef ME - queue_task(this, (task_t*)ike_me_create(this->ike_sa, TRUE)); + queue_task(this, (task_t*)ike_me_create(this->ike_sa, TRUE)); #endif /* ME */ + } } METHOD(task_manager_t, queue_ike_rekey, void, From 873df908cc2c840410df9085861a64c482f259aa Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 15:04:28 +0100 Subject: [PATCH 373/534] Moved MOBIKE task creation to protocol specific task manager --- src/libcharon/sa/ike_sa.c | 11 ++--------- src/libcharon/sa/ikev1/task_manager_v1.c | 7 +++++++ src/libcharon/sa/ikev2/task_manager_v2.c | 19 ++++++++++++++++++- src/libcharon/sa/task_manager.h | 8 ++++++++ 4 files changed, 35 insertions(+), 10 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 43e61ef74..83d072c2a 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1621,8 +1621,6 @@ static bool is_any_path_valid(private_ike_sa_t *this) METHOD(ike_sa_t, roam, status_t, private_ike_sa_t *this, bool address) { - ike_mobike_t *mobike; - switch (this->state) { case IKE_CREATED: @@ -1644,10 +1642,7 @@ METHOD(ike_sa_t, roam, status_t, if (supports_extension(this, EXT_MOBIKE) && address) { /* if any addresses changed, send an updated list */ DBG1(DBG_IKE, "sending address list update using MOBIKE"); - mobike = ike_mobike_create(&this->public, TRUE); - mobike->addresses(mobike); - this->task_manager->queue_task(this->task_manager, - (task_t*)mobike); + this->task_manager->queue_mobike(this->task_manager, FALSE, TRUE); return this->task_manager->initiate(this->task_manager); } return SUCCESS; @@ -1675,9 +1670,7 @@ METHOD(ike_sa_t, roam, status_t, { DBG1(DBG_IKE, "requesting address change using MOBIKE"); } - mobike = ike_mobike_create(&this->public, TRUE); - mobike->roam(mobike, address); - this->task_manager->queue_task(this->task_manager, (task_t*)mobike); + this->task_manager->queue_mobike(this->task_manager, TRUE, address); return this->task_manager->initiate(this->task_manager); } diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index d23b237fa..dfc960891 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1041,6 +1041,12 @@ METHOD(task_manager_t, queue_ike_delete, void, queue_task(this, (task_t*)isakmp_delete_create(this->ike_sa, TRUE)); } +METHOD(task_manager_t, queue_mobike, void, + private_task_manager_t *this, bool roam, bool address) +{ + /* Not supported in IKEv1 */ +} + METHOD(task_manager_t, queue_child, void, private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, traffic_selector_t *tsi, traffic_selector_t *tsr) @@ -1147,6 +1153,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .queue_ike_rekey = _queue_ike_rekey, .queue_ike_reauth = _queue_ike_reauth, .queue_ike_delete = _queue_ike_delete, + .queue_mobike = _queue_mobike, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, .queue_child_delete = _queue_child_delete, diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 91589b15c..fe576694f 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1248,6 +1248,23 @@ METHOD(task_manager_t, queue_ike_delete, void, queue_task(this, (task_t*)ike_delete_create(this->ike_sa, TRUE)); } +METHOD(task_manager_t, queue_mobike, void, + private_task_manager_t *this, bool roam, bool address) +{ + ike_mobike_t *mobike; + + mobike = ike_mobike_create(this->ike_sa, TRUE); + if (roam) + { + mobike->roam(mobike, address); + } + else + { + mobike->addresses(mobike); + } + queue_task(this, &mobike->task); +} + METHOD(task_manager_t, queue_child, void, private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, traffic_selector_t *tsi, traffic_selector_t *tsr) @@ -1293,7 +1310,6 @@ METHOD(task_manager_t, queue_dpd, void, } } - METHOD(task_manager_t, adopt_tasks, void, private_task_manager_t *this, task_manager_t *other_public) { @@ -1402,6 +1418,7 @@ task_manager_v2_t *task_manager_v2_create(ike_sa_t *ike_sa) .queue_ike_rekey = _queue_ike_rekey, .queue_ike_reauth = _queue_ike_reauth, .queue_ike_delete = _queue_ike_delete, + .queue_mobike = _queue_mobike, .queue_child = _queue_child, .queue_child_rekey = _queue_child_rekey, .queue_child_delete = _queue_child_delete, diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 4087265c7..5602069b1 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -139,6 +139,14 @@ struct task_manager_t { */ void (*queue_ike_reauth)(task_manager_t *this); + /** + * Queue MOBIKE task + * + * @param roam TRUE to switch to new address + * @param address TRUE to include address list update + */ + void (*queue_mobike)(task_manager_t *this, bool roam, bool address); + /** * Queue IKE_SA delete tasks. */ From 3b08de850a1fb090de9d51f2aab3a973bbf1ff70 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 15:20:36 +0100 Subject: [PATCH 374/534] Removed obsolete task header inclusion in IKE_SA --- src/libcharon/sa/ike_sa.c | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 83d072c2a..1e24225b2 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -28,30 +28,6 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include #include #include From 326a94232d1286336e63fe3b4603f1fcdd6fe0fa Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 15:22:50 +0100 Subject: [PATCH 375/534] Moved eap/xauth classes out of protocol specific subdirectories --- src/libcharon/Makefile.am | 8 ++++---- src/libcharon/daemon.h | 4 ++-- src/libcharon/plugins/eap_aka/eap_aka_peer.h | 2 +- src/libcharon/plugins/eap_aka/eap_aka_server.h | 2 +- src/libcharon/plugins/eap_gtc/eap_gtc.h | 2 +- src/libcharon/plugins/eap_identity/eap_identity.h | 2 +- src/libcharon/plugins/eap_md5/eap_md5.h | 2 +- src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h | 2 +- src/libcharon/plugins/eap_peap/eap_peap.h | 2 +- src/libcharon/plugins/eap_peap/eap_peap_peer.h | 2 +- src/libcharon/plugins/eap_peap/eap_peap_server.h | 2 +- src/libcharon/plugins/eap_radius/eap_radius.h | 2 +- src/libcharon/plugins/eap_sim/eap_sim_peer.h | 2 +- src/libcharon/plugins/eap_sim/eap_sim_server.h | 2 +- src/libcharon/plugins/eap_tls/eap_tls.h | 2 +- src/libcharon/plugins/eap_tnc/eap_tnc.h | 2 +- src/libcharon/plugins/eap_ttls/eap_ttls.h | 2 +- src/libcharon/plugins/eap_ttls/eap_ttls_peer.c | 2 +- src/libcharon/plugins/eap_ttls/eap_ttls_server.c | 2 +- src/libcharon/plugins/xauth_generic/xauth_generic.h | 2 +- .../sa/{ikev2/authenticators => }/eap/eap_manager.c | 0 .../sa/{ikev2/authenticators => }/eap/eap_manager.h | 2 +- .../sa/{ikev2/authenticators => }/eap/eap_method.c | 0 .../sa/{ikev2/authenticators => }/eap/eap_method.h | 0 src/libcharon/sa/ikev2/authenticators/eap_authenticator.c | 2 +- .../sa/{ikev1/authenticators => }/xauth/xauth_manager.c | 0 .../sa/{ikev1/authenticators => }/xauth/xauth_manager.h | 2 +- .../sa/{ikev1/authenticators => }/xauth/xauth_method.c | 0 .../sa/{ikev1/authenticators => }/xauth/xauth_method.h | 0 29 files changed, 27 insertions(+), 27 deletions(-) rename src/libcharon/sa/{ikev2/authenticators => }/eap/eap_manager.c (100%) rename src/libcharon/sa/{ikev2/authenticators => }/eap/eap_manager.h (98%) rename src/libcharon/sa/{ikev2/authenticators => }/eap/eap_method.c (100%) rename src/libcharon/sa/{ikev2/authenticators => }/eap/eap_method.h (100%) rename src/libcharon/sa/{ikev1/authenticators => }/xauth/xauth_manager.c (100%) rename src/libcharon/sa/{ikev1/authenticators => }/xauth/xauth_manager.h (97%) rename src/libcharon/sa/{ikev1/authenticators => }/xauth/xauth_method.c (100%) rename src/libcharon/sa/{ikev1/authenticators => }/xauth/xauth_method.h (100%) diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 474b20521..ac19bfd5c 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -57,6 +57,10 @@ processing/jobs/start_action_job.c processing/jobs/start_action_job.h \ processing/jobs/roam_job.c processing/jobs/roam_job.h \ processing/jobs/update_sa_job.c processing/jobs/update_sa_job.h \ processing/jobs/inactivity_job.c processing/jobs/inactivity_job.h \ +sa/eap/eap_method.c sa/eap/eap_method.h \ +sa/eap/eap_manager.c sa/eap/eap_manager.h \ +sa/xauth/xauth_method.c sa/xauth/xauth_method.h \ +sa/xauth/xauth_manager.c sa/xauth/xauth_manager.h \ sa/authenticator.c sa/authenticator.h \ sa/child_sa.c sa/child_sa.h \ sa/ike_sa.c sa/ike_sa.h \ @@ -70,8 +74,6 @@ sa/task.c sa/task.h \ sa/ikev2/keymat_v2.c sa/ikev2/keymat_v2.h \ sa/ikev2/task_manager_v2.c sa/ikev2/task_manager_v2.h \ sa/ikev2/authenticators/eap_authenticator.c sa/ikev2/authenticators/eap_authenticator.h \ -sa/ikev2/authenticators/eap/eap_method.c sa/ikev2/authenticators/eap/eap_method.h \ -sa/ikev2/authenticators/eap/eap_manager.c sa/ikev2/authenticators/eap/eap_manager.h \ sa/ikev2/authenticators/psk_authenticator.c sa/ikev2/authenticators/psk_authenticator.h \ sa/ikev2/authenticators/pubkey_authenticator.c sa/ikev2/authenticators/pubkey_authenticator.h \ sa/ikev2/tasks/child_create.c sa/ikev2/tasks/child_create.h \ @@ -95,8 +97,6 @@ sa/ikev1/task_manager_v1.c sa/ikev1/task_manager_v1.h \ sa/ikev1/authenticators/psk_v1_authenticator.c sa/ikev1/authenticators/psk_v1_authenticator.h \ sa/ikev1/authenticators/pubkey_v1_authenticator.c sa/ikev1/authenticators/pubkey_v1_authenticator.h \ sa/ikev1/authenticators/hybrid_authenticator.c sa/ikev1/authenticators/hybrid_authenticator.h \ -sa/ikev1/authenticators/xauth/xauth_method.c sa/ikev1/authenticators/xauth/xauth_method.h \ -sa/ikev1/authenticators/xauth/xauth_manager.c sa/ikev1/authenticators/xauth/xauth_manager.h \ sa/ikev1/tasks/main_mode.c sa/ikev1/tasks/main_mode.h \ sa/ikev1/tasks/informational.c sa/ikev1/tasks/informational.h \ sa/ikev1/tasks/isakmp_cert_pre.c sa/ikev1/tasks/isakmp_cert_pre.h \ diff --git a/src/libcharon/daemon.h b/src/libcharon/daemon.h index 785ad23bf..bfbf774ff 100644 --- a/src/libcharon/daemon.h +++ b/src/libcharon/daemon.h @@ -148,8 +148,8 @@ typedef struct daemon_t daemon_t; #include #include #include -#include -#include +#include +#include #ifdef ME #include diff --git a/src/libcharon/plugins/eap_aka/eap_aka_peer.h b/src/libcharon/plugins/eap_aka/eap_aka_peer.h index 4fc1821c4..b6ab5cdc5 100644 --- a/src/libcharon/plugins/eap_aka/eap_aka_peer.h +++ b/src/libcharon/plugins/eap_aka/eap_aka_peer.h @@ -23,7 +23,7 @@ typedef struct eap_aka_peer_t eap_aka_peer_t; -#include +#include /** * EAP-AKA peer implementation. diff --git a/src/libcharon/plugins/eap_aka/eap_aka_server.h b/src/libcharon/plugins/eap_aka/eap_aka_server.h index 4819021d2..5c95180ac 100644 --- a/src/libcharon/plugins/eap_aka/eap_aka_server.h +++ b/src/libcharon/plugins/eap_aka/eap_aka_server.h @@ -23,7 +23,7 @@ typedef struct eap_aka_server_t eap_aka_server_t; -#include +#include /** * EAP-AKA server implementation. diff --git a/src/libcharon/plugins/eap_gtc/eap_gtc.h b/src/libcharon/plugins/eap_gtc/eap_gtc.h index 0ce46b303..4dac53cfb 100644 --- a/src/libcharon/plugins/eap_gtc/eap_gtc.h +++ b/src/libcharon/plugins/eap_gtc/eap_gtc.h @@ -23,7 +23,7 @@ typedef struct eap_gtc_t eap_gtc_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-GTC. diff --git a/src/libcharon/plugins/eap_identity/eap_identity.h b/src/libcharon/plugins/eap_identity/eap_identity.h index 811b19b5b..4e7f6fd9d 100644 --- a/src/libcharon/plugins/eap_identity/eap_identity.h +++ b/src/libcharon/plugins/eap_identity/eap_identity.h @@ -23,7 +23,7 @@ typedef struct eap_identity_t eap_identity_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP Identity. diff --git a/src/libcharon/plugins/eap_md5/eap_md5.h b/src/libcharon/plugins/eap_md5/eap_md5.h index 302abc4e6..5396535e1 100644 --- a/src/libcharon/plugins/eap_md5/eap_md5.h +++ b/src/libcharon/plugins/eap_md5/eap_md5.h @@ -23,7 +23,7 @@ typedef struct eap_md5_t eap_md5_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-MD5 (CHAP). diff --git a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h index 44050d0da..0e7abc397 100644 --- a/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h +++ b/src/libcharon/plugins/eap_mschapv2/eap_mschapv2.h @@ -23,7 +23,7 @@ typedef struct eap_mschapv2_t eap_mschapv2_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-MS-CHAPv2. diff --git a/src/libcharon/plugins/eap_peap/eap_peap.h b/src/libcharon/plugins/eap_peap/eap_peap.h index 7bf7b1d70..2756ad3e6 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap.h +++ b/src/libcharon/plugins/eap_peap/eap_peap.h @@ -23,7 +23,7 @@ typedef struct eap_peap_t eap_peap_t; -#include +#include /** * Implementation of eap_method_t using EAP-PEAP. diff --git a/src/libcharon/plugins/eap_peap/eap_peap_peer.h b/src/libcharon/plugins/eap_peap/eap_peap_peer.h index 61586b16c..196d4e2c4 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_peer.h +++ b/src/libcharon/plugins/eap_peap/eap_peap_peer.h @@ -26,7 +26,7 @@ typedef struct eap_peap_peer_t eap_peap_peer_t; #include "tls_application.h" #include -#include +#include /** * TLS application data handler as peer. diff --git a/src/libcharon/plugins/eap_peap/eap_peap_server.h b/src/libcharon/plugins/eap_peap/eap_peap_server.h index cc03d4ba9..4585a622a 100644 --- a/src/libcharon/plugins/eap_peap/eap_peap_server.h +++ b/src/libcharon/plugins/eap_peap/eap_peap_server.h @@ -26,7 +26,7 @@ typedef struct eap_peap_server_t eap_peap_server_t; #include "tls_application.h" #include -#include +#include /** * TLS application data handler as server. diff --git a/src/libcharon/plugins/eap_radius/eap_radius.h b/src/libcharon/plugins/eap_radius/eap_radius.h index 9cfdbb95d..875543554 100644 --- a/src/libcharon/plugins/eap_radius/eap_radius.h +++ b/src/libcharon/plugins/eap_radius/eap_radius.h @@ -23,7 +23,7 @@ typedef struct eap_radius_t eap_radius_t; -#include +#include /** * Implementation of the eap_method_t interface using a RADIUS server. diff --git a/src/libcharon/plugins/eap_sim/eap_sim_peer.h b/src/libcharon/plugins/eap_sim/eap_sim_peer.h index c32cb3120..38315b75a 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_peer.h +++ b/src/libcharon/plugins/eap_sim/eap_sim_peer.h @@ -21,7 +21,7 @@ #ifndef EAP_SIM_PEER_H_ #define EAP_SIM_PEER_H_ -#include +#include typedef struct eap_sim_peer_t eap_sim_peer_t; diff --git a/src/libcharon/plugins/eap_sim/eap_sim_server.h b/src/libcharon/plugins/eap_sim/eap_sim_server.h index a4a0eea63..84408c43c 100644 --- a/src/libcharon/plugins/eap_sim/eap_sim_server.h +++ b/src/libcharon/plugins/eap_sim/eap_sim_server.h @@ -21,7 +21,7 @@ #ifndef EAP_SIM_SERVER_H_ #define EAP_SIM_SERVER_H_ -#include +#include typedef struct eap_sim_server_t eap_sim_server_t; diff --git a/src/libcharon/plugins/eap_tls/eap_tls.h b/src/libcharon/plugins/eap_tls/eap_tls.h index 4227c9db3..6779c3994 100644 --- a/src/libcharon/plugins/eap_tls/eap_tls.h +++ b/src/libcharon/plugins/eap_tls/eap_tls.h @@ -23,7 +23,7 @@ typedef struct eap_tls_t eap_tls_t; -#include +#include /** * Implementation of eap_method_t using EAP-TLS. diff --git a/src/libcharon/plugins/eap_tnc/eap_tnc.h b/src/libcharon/plugins/eap_tnc/eap_tnc.h index 1c7e1b6fa..7709551a5 100644 --- a/src/libcharon/plugins/eap_tnc/eap_tnc.h +++ b/src/libcharon/plugins/eap_tnc/eap_tnc.h @@ -23,7 +23,7 @@ typedef struct eap_tnc_t eap_tnc_t; -#include +#include /** * Implementation of the eap_method_t interface using EAP-TNC. diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls.h b/src/libcharon/plugins/eap_ttls/eap_ttls.h index ca2b82477..84b1a2d19 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls.h +++ b/src/libcharon/plugins/eap_ttls/eap_ttls.h @@ -23,7 +23,7 @@ typedef struct eap_ttls_t eap_ttls_t; -#include +#include /** * Implementation of eap_method_t using EAP-TTLS. diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c index aa10c7d3d..e75bd2976 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_peer.c @@ -19,7 +19,7 @@ #include #include -#include +#include typedef struct private_eap_ttls_peer_t private_eap_ttls_peer_t; diff --git a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c index 2a2aee12f..d2417659c 100644 --- a/src/libcharon/plugins/eap_ttls/eap_ttls_server.c +++ b/src/libcharon/plugins/eap_ttls/eap_ttls_server.c @@ -19,7 +19,7 @@ #include #include -#include +#include typedef struct private_eap_ttls_server_t private_eap_ttls_server_t; diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.h b/src/libcharon/plugins/xauth_generic/xauth_generic.h index 04e3d47bb..5773589cb 100644 --- a/src/libcharon/plugins/xauth_generic/xauth_generic.h +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.h @@ -23,7 +23,7 @@ typedef struct xauth_generic_t xauth_generic_t; -#include +#include /** * Implementation of the xauth_method_t interface using cleartext secrets diff --git a/src/libcharon/sa/ikev2/authenticators/eap/eap_manager.c b/src/libcharon/sa/eap/eap_manager.c similarity index 100% rename from src/libcharon/sa/ikev2/authenticators/eap/eap_manager.c rename to src/libcharon/sa/eap/eap_manager.c diff --git a/src/libcharon/sa/ikev2/authenticators/eap/eap_manager.h b/src/libcharon/sa/eap/eap_manager.h similarity index 98% rename from src/libcharon/sa/ikev2/authenticators/eap/eap_manager.h rename to src/libcharon/sa/eap/eap_manager.h index 6b8754634..868eaef06 100644 --- a/src/libcharon/sa/ikev2/authenticators/eap/eap_manager.h +++ b/src/libcharon/sa/eap/eap_manager.h @@ -21,7 +21,7 @@ #ifndef EAP_MANAGER_H_ #define EAP_MANAGER_H_ -#include +#include typedef struct eap_manager_t eap_manager_t; diff --git a/src/libcharon/sa/ikev2/authenticators/eap/eap_method.c b/src/libcharon/sa/eap/eap_method.c similarity index 100% rename from src/libcharon/sa/ikev2/authenticators/eap/eap_method.c rename to src/libcharon/sa/eap/eap_method.c diff --git a/src/libcharon/sa/ikev2/authenticators/eap/eap_method.h b/src/libcharon/sa/eap/eap_method.h similarity index 100% rename from src/libcharon/sa/ikev2/authenticators/eap/eap_method.h rename to src/libcharon/sa/eap/eap_method.h diff --git a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c index 462436d80..b81c5c853 100644 --- a/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c +++ b/src/libcharon/sa/ikev2/authenticators/eap_authenticator.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include diff --git a/src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.c b/src/libcharon/sa/xauth/xauth_manager.c similarity index 100% rename from src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.c rename to src/libcharon/sa/xauth/xauth_manager.c diff --git a/src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.h b/src/libcharon/sa/xauth/xauth_manager.h similarity index 97% rename from src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.h rename to src/libcharon/sa/xauth/xauth_manager.h index e7e84d06b..929d5de8f 100644 --- a/src/libcharon/sa/ikev1/authenticators/xauth/xauth_manager.h +++ b/src/libcharon/sa/xauth/xauth_manager.h @@ -21,7 +21,7 @@ #ifndef XAUTH_MANAGER_H_ #define XAUTH_MANAGER_H_ -#include +#include typedef struct xauth_manager_t xauth_manager_t; diff --git a/src/libcharon/sa/ikev1/authenticators/xauth/xauth_method.c b/src/libcharon/sa/xauth/xauth_method.c similarity index 100% rename from src/libcharon/sa/ikev1/authenticators/xauth/xauth_method.c rename to src/libcharon/sa/xauth/xauth_method.c diff --git a/src/libcharon/sa/ikev1/authenticators/xauth/xauth_method.h b/src/libcharon/sa/xauth/xauth_method.h similarity index 100% rename from src/libcharon/sa/ikev1/authenticators/xauth/xauth_method.h rename to src/libcharon/sa/xauth/xauth_method.h From 7d788af0a0953a5b80b099ee99f0ebeb822ce1c1 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 15:28:55 +0100 Subject: [PATCH 376/534] Don't include ikev1/ikev2 subfolders in build when using --disable-ikev1/ikev2 --- src/libcharon/Makefile.am | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index ac19bfd5c..a6334e1a0 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -70,7 +70,10 @@ sa/ike_sa_manager.c sa/ike_sa_manager.h \ sa/task_manager.h sa/task_manager.c \ sa/shunt_manager.c sa/shunt_manager.h \ sa/trap_manager.c sa/trap_manager.h \ -sa/task.c sa/task.h \ +sa/task.c sa/task.h + +if USE_IKEV2 +libcharon_la_SOURCES += \ sa/ikev2/keymat_v2.c sa/ikev2/keymat_v2.h \ sa/ikev2/task_manager_v2.c sa/ikev2/task_manager_v2.h \ sa/ikev2/authenticators/eap_authenticator.c sa/ikev2/authenticators/eap_authenticator.h \ @@ -91,7 +94,11 @@ sa/ikev2/tasks/ike_mobike.c sa/ikev2/tasks/ike_mobike.h \ sa/ikev2/tasks/ike_rekey.c sa/ikev2/tasks/ike_rekey.h \ sa/ikev2/tasks/ike_reauth.c sa/ikev2/tasks/ike_reauth.h \ sa/ikev2/tasks/ike_auth_lifetime.c sa/ikev2/tasks/ike_auth_lifetime.h \ -sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h \ +sa/ikev2/tasks/ike_vendor.c sa/ikev2/tasks/ike_vendor.h +endif + +if USE_IKEV1 +libcharon_la_SOURCES += \ sa/ikev1/keymat_v1.c sa/ikev1/keymat_v1.h \ sa/ikev1/task_manager_v1.c sa/ikev1/task_manager_v1.h \ sa/ikev1/authenticators/psk_v1_authenticator.c sa/ikev1/authenticators/psk_v1_authenticator.h \ @@ -108,6 +115,7 @@ sa/ikev1/tasks/xauth.c sa/ikev1/tasks/xauth.h \ sa/ikev1/tasks/quick_mode.c sa/ikev1/tasks/quick_mode.h \ sa/ikev1/tasks/quick_delete.c sa/ikev1/tasks/quick_delete.h \ sa/ikev1/tasks/mode_config.c sa/ikev1/tasks/mode_config.h +endif daemon.lo : $(top_builddir)/config.status From 38bb727c067be3ac8292b7d85f99f5c9f82ea743 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 15:45:03 +0100 Subject: [PATCH 377/534] Don't accept IKEv2 packets if IKEv2 disabled --- src/libcharon/network/receiver.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index 9e4fddf5a..6b408cc54 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -376,8 +376,10 @@ static job_requeue_t receive_packets(private_receiver_t *this) /* check IKE major version */ switch (message->get_major_version(message)) { +#ifdef USE_IKEV2 case IKEV2_MAJOR_VERSION: break; +#endif /* USE_IKEV2 */ #ifdef USE_IKEV1 case IKEV1_MAJOR_VERSION: break; From 438a8d785f299f04ad67b8c0b1ce9f6ad03990b6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 15:50:31 +0100 Subject: [PATCH 378/534] Added a TODO for creating IKE_SAs with unsupported protocol version --- src/libcharon/sa/ike_sa.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 1e24225b2..000c3e539 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1871,11 +1871,6 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, private_ike_sa_t *this; static u_int32_t unique_id = 0; - if (version != IKEV1) - { - version = IKEV2; - } - INIT(this, .public = { .get_version = _get_version, @@ -1986,5 +1981,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, this->task_manager = task_manager_create(&this->public); this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); + /* TODO-IKEv1: check if keymat and task manager created successfully. + * Return NULL otherwise? */ + return &this->public; } From 5d1677f52da06a74a5b480eb4c6e046bee9d127e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 18:55:41 +0100 Subject: [PATCH 379/534] Added missing XAuth plugin feature enum names --- src/libstrongswan/plugins/plugin_feature.c | 2 ++ src/libstrongswan/plugins/plugin_feature.h | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/libstrongswan/plugins/plugin_feature.c b/src/libstrongswan/plugins/plugin_feature.c index 385e77b8b..330528885 100644 --- a/src/libstrongswan/plugins/plugin_feature.c +++ b/src/libstrongswan/plugins/plugin_feature.c @@ -40,6 +40,8 @@ ENUM(plugin_feature_names, FEATURE_NONE, FEATURE_CUSTOM, "CERT_ENCODE", "EAP_SERVER", "EAP_CLIENT", + "XAUTH_SERVER", + "XAUTH_CLIENT", "DATABASE", "FETCHER", "CUSTOM", diff --git a/src/libstrongswan/plugins/plugin_feature.h b/src/libstrongswan/plugins/plugin_feature.h index 54fd2c67f..344d1943d 100644 --- a/src/libstrongswan/plugins/plugin_feature.h +++ b/src/libstrongswan/plugins/plugin_feature.h @@ -129,16 +129,16 @@ struct plugin_feature_t { FEATURE_EAP_SERVER, /** EAP peer implementation */ FEATURE_EAP_PEER, + /** XAuth server implementation */ + FEATURE_XAUTH_SERVER, + /** XAuth peer implementation */ + FEATURE_XAUTH_PEER, /** database_t */ FEATURE_DATABASE, /** fetcher_t */ FEATURE_FETCHER, /** custom feature, described with a string */ FEATURE_CUSTOM, - /** XAuth server implementation */ - FEATURE_XAUTH_SERVER, - /** XAuth peer implementation */ - FEATURE_XAUTH_PEER, } type; /** More specific data for each type */ union { From 747f837cce905a58d5c8609104282d81bb5fd608 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 20:22:18 +0100 Subject: [PATCH 380/534] Added a flag to register local credential sets exclusively, disabling all others --- src/libcharon/plugins/stroke/stroke_cred.c | 8 +- .../credentials/credential_manager.c | 82 +++++++++++++++---- .../credentials/credential_manager.h | 6 +- .../plugins/revocation/revocation_validator.c | 2 +- src/pluto/keys.c | 4 +- 5 files changed, 79 insertions(+), 23 deletions(-) diff --git a/src/libcharon/plugins/stroke/stroke_cred.c b/src/libcharon/plugins/stroke/stroke_cred.c index 47381b75e..aff0e66b1 100644 --- a/src/libcharon/plugins/stroke/stroke_cred.c +++ b/src/libcharon/plugins/stroke/stroke_cred.c @@ -576,7 +576,7 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr, pin_data.keyid = chunk; pin_data.try = 1; cb = callback_cred_create_shared((void*)pin_cb, &pin_data); - lib->credmgr->add_local_set(lib->credmgr, &cb->set); + lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE); } else { @@ -585,7 +585,7 @@ static bool load_pin(private_stroke_cred_t *this, chunk_t line, int line_nr, id = identification_create_from_encoding(ID_KEY_ID, chunk); mem = mem_cred_create(); mem->add_shared(mem, shared, id, NULL); - lib->credmgr->add_local_set(lib->credmgr, &mem->set); + lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE); } /* unlock: smartcard needs the pin and potentially calls public set */ @@ -693,7 +693,7 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr, pp_data.path = path; pp_data.try = 1; cb = callback_cred_create_shared((void*)passphrase_cb, &pp_data); - lib->credmgr->add_local_set(lib->credmgr, &cb->set); + lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE); key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, BUILD_FROM_FILE, path, BUILD_END); @@ -710,7 +710,7 @@ static bool load_private(private_stroke_cred_t *this, chunk_t line, int line_nr, shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, secret); mem = mem_cred_create(); mem->add_shared(mem, shared, NULL); - lib->credmgr->add_local_set(lib->credmgr, &mem->set); + lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE); key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, key_type, BUILD_FROM_FILE, path, BUILD_END); diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index 4c310406e..944c26904 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -52,6 +52,11 @@ struct private_credential_manager_t { */ thread_value_t *local_sets; + /** + * Exclusive local sets, linked_list_t with credential_set_t + */ + thread_value_t *exclusive_local_sets; + /** * trust relationship and certificate cache */ @@ -117,12 +122,23 @@ typedef struct { enumerator_t *global; /** enumerator over local sets */ enumerator_t *local; + /** enumerator over exclusive local sets */ + enumerator_t *exclusive; } sets_enumerator_t; METHOD(enumerator_t, sets_enumerate, bool, sets_enumerator_t *this, credential_set_t **set) { + if (this->exclusive) + { + if (this->exclusive->enumerate(this->exclusive, set)) + { /* only enumerate last added */ + this->exclusive->destroy(this->exclusive); + this->exclusive = NULL; + return TRUE; + } + } if (this->global) { if (this->global->enumerate(this->global, set)) @@ -145,6 +161,7 @@ METHOD(enumerator_t, sets_destroy, void, { DESTROY_IF(this->global); DESTROY_IF(this->local); + DESTROY_IF(this->exclusive); free(this); } @@ -154,19 +171,28 @@ METHOD(enumerator_t, sets_destroy, void, static enumerator_t *create_sets_enumerator(private_credential_manager_t *this) { sets_enumerator_t *enumerator; - linked_list_t *local; + linked_list_t *list; INIT(enumerator, .public = { .enumerate = (void*)_sets_enumerate, .destroy = _sets_destroy, }, - .global = this->sets->create_enumerator(this->sets), ); - local = this->local_sets->get(this->local_sets); - if (local) + + list = this->exclusive_local_sets->get(this->exclusive_local_sets); + if (list && list->get_count(list)) { - enumerator->local = local->create_enumerator(local); + enumerator->exclusive = list->create_enumerator(list); + } + else + { + enumerator->global = this->sets->create_enumerator(this->sets); + list = this->local_sets->get(this->local_sets); + if (list) + { + enumerator->local = list->create_enumerator(list); + } } return &enumerator->public; } @@ -373,29 +399,53 @@ METHOD(credential_manager_t, get_shared, shared_key_t*, } METHOD(credential_manager_t, add_local_set, void, - private_credential_manager_t *this, credential_set_t *set) + private_credential_manager_t *this, credential_set_t *set, bool exclusive) { linked_list_t *sets; + thread_value_t *tv; - sets = this->local_sets->get(this->local_sets); + if (exclusive) + { + tv = this->exclusive_local_sets; + } + else + { + tv = this->local_sets; + } + sets = tv->get(tv); if (!sets) - { /* first invocation */ + { sets = linked_list_create(); - this->local_sets->set(this->local_sets, sets); + tv->set(tv, sets); + } + if (exclusive) + { + sets->insert_first(sets, set); + } + else + { + sets->insert_last(sets, set); } - sets->insert_last(sets, set); } METHOD(credential_manager_t, remove_local_set, void, private_credential_manager_t *this, credential_set_t *set) { linked_list_t *sets; + thread_value_t *tv; - sets = this->local_sets->get(this->local_sets); - sets->remove(sets, set, NULL); - if (sets->get_count(sets) == 0) + tv = this->local_sets; + sets = tv->get(tv); + if (sets && sets->remove(sets, set, NULL) && sets->get_count(sets) == 0) { - this->local_sets->set(this->local_sets, NULL); + tv->set(tv, NULL); + sets->destroy(sets); + } + tv = this->exclusive_local_sets; + sets = tv->get(tv); + if (sets && sets->remove(sets, set, NULL) && sets->get_count(sets) == 0) + { + tv->set(tv, NULL); sets->destroy(sets); } } @@ -864,7 +914,7 @@ METHOD(credential_manager_t, create_public_enumerator, enumerator_t*, if (auth) { enumerator->wrapper = auth_cfg_wrapper_create(auth); - add_local_set(this, &enumerator->wrapper->set); + add_local_set(this, &enumerator->wrapper->set, FALSE); } this->lock->read_lock(this->lock); return &enumerator->public; @@ -1105,6 +1155,7 @@ METHOD(credential_manager_t, destroy, void, this->sets->remove(this->sets, this->cache, NULL); this->sets->destroy(this->sets); this->local_sets->destroy(this->local_sets); + this->exclusive_local_sets->destroy(this->exclusive_local_sets); this->cache->destroy(this->cache); this->validators->destroy(this->validators); this->lock->destroy(this->lock); @@ -1149,6 +1200,7 @@ credential_manager_t *credential_manager_create() ); this->local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy); + this->exclusive_local_sets = thread_value_create((thread_cleanup_t)this->sets->destroy); this->sets->insert_first(this->sets, this->cache); return &this->public; diff --git a/src/libstrongswan/credentials/credential_manager.h b/src/libstrongswan/credentials/credential_manager.h index 4c662d13c..8a774f6f3 100644 --- a/src/libstrongswan/credentials/credential_manager.h +++ b/src/libstrongswan/credentials/credential_manager.h @@ -230,10 +230,14 @@ struct credential_manager_t { * operation, sets may be added for the calling thread only. This * does not require a write lock and is therefore a much less expensive * operation. + * The exclusive option allows to disable all other credential sets + * until the set is deregistered. * * @param set set to register + * @param exclusive TRUE to disable all other sets for this thread */ - void (*add_local_set)(credential_manager_t *this, credential_set_t *set); + void (*add_local_set)(credential_manager_t *this, credential_set_t *set, + bool exclusive); /** * Unregister a thread local credential set from the manager. diff --git a/src/libstrongswan/plugins/revocation/revocation_validator.c b/src/libstrongswan/plugins/revocation/revocation_validator.c index 34f347d1a..ff3ef14d8 100644 --- a/src/libstrongswan/plugins/revocation/revocation_validator.c +++ b/src/libstrongswan/plugins/revocation/revocation_validator.c @@ -103,7 +103,7 @@ static bool verify_ocsp(ocsp_response_t *response, auth_cfg_t *auth) bool verified = FALSE; wrapper = ocsp_response_wrapper_create((ocsp_response_t*)response); - lib->credmgr->add_local_set(lib->credmgr, &wrapper->set); + lib->credmgr->add_local_set(lib->credmgr, &wrapper->set, FALSE); subject = &response->certificate; responder = subject->get_issuer(subject); diff --git a/src/pluto/keys.c b/src/pluto/keys.c index a204d86cb..9031fcda5 100644 --- a/src/pluto/keys.c +++ b/src/pluto/keys.c @@ -621,7 +621,7 @@ static private_key_t* load_private_key(char* filename, prompt_pass_t *pass, callback_cred_t *cb; cb = callback_cred_create_shared((void*)whack_pass_cb, pass); - lib->credmgr->add_local_set(lib->credmgr, &cb->set); + lib->credmgr->add_local_set(lib->credmgr, &cb->set, FALSE); key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY, type, BUILD_FROM_FILE, path, BUILD_END); @@ -638,7 +638,7 @@ static private_key_t* load_private_key(char* filename, prompt_pass_t *pass, shared_key_t *shared; mem = mem_cred_create(); - lib->credmgr->add_local_set(lib->credmgr, &mem->set); + lib->credmgr->add_local_set(lib->credmgr, &mem->set, FALSE); shared = shared_key_create(SHARED_PRIVATE_KEY_PASS, chunk_clone(chunk_create(pass->secret, strlen(pass->secret)))); mem->add_shared(mem, shared, NULL); From 85fc1eb640904a93168a2cd9e92432e3df0bfdf7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 19 Dec 2011 20:21:02 +0100 Subject: [PATCH 381/534] Added an XAuth plugin that forwards authentication to EAP methods --- configure.in | 4 + src/libcharon/Makefile.am | 6 + src/libcharon/plugins/xauth_eap/Makefile.am | 17 ++ src/libcharon/plugins/xauth_eap/xauth_eap.c | 284 ++++++++++++++++++ src/libcharon/plugins/xauth_eap/xauth_eap.h | 49 +++ .../plugins/xauth_eap/xauth_eap_plugin.c | 60 ++++ .../plugins/xauth_eap/xauth_eap_plugin.h | 42 +++ 7 files changed, 462 insertions(+) create mode 100644 src/libcharon/plugins/xauth_eap/Makefile.am create mode 100644 src/libcharon/plugins/xauth_eap/xauth_eap.c create mode 100644 src/libcharon/plugins/xauth_eap/xauth_eap.h create mode 100644 src/libcharon/plugins/xauth_eap/xauth_eap_plugin.c create mode 100644 src/libcharon/plugins/xauth_eap/xauth_eap_plugin.h diff --git a/configure.in b/configure.in index 417e33794..1d28cfac2 100755 --- a/configure.in +++ b/configure.in @@ -130,6 +130,7 @@ ARG_ENABL_SET([eap-peap], [enable EAP PEAP authentication module.]) ARG_ENABL_SET([eap-tnc], [enable EAP TNC trusted network connect module.]) ARG_ENABL_SET([eap-radius], [enable RADIUS proxy authentication module.]) ARG_ENABL_SET([xauth-generic], [enable generic XAuth backend.]) +ARG_ENABL_SET([xauth-eap], [enable XAuth backend using EAP methods to verify passwords.]) ARG_ENABL_SET([tnc-ifmap], [enable TNC IF-MAP module.]) ARG_ENABL_SET([tnc-imc], [enable TNC IMC module.]) ARG_ENABL_SET([tnc-imv], [enable TNC IMV module.]) @@ -845,6 +846,7 @@ ADD_PLUGIN([eap-ttls], [c libcharon]) ADD_PLUGIN([eap-peap], [c libcharon]) ADD_PLUGIN([eap-tnc], [c libcharon]) ADD_PLUGIN([xauth-generic], [c libcharon]) +ADD_PLUGIN([xauth-eap], [c libcharon]) ADD_PLUGIN([tnc-ifmap], [c libcharon]) ADD_PLUGIN([tnc-imc], [c libcharon]) ADD_PLUGIN([tnc-imv], [c libcharon]) @@ -965,6 +967,7 @@ AM_CONDITIONAL(USE_EAP_PEAP, test x$eap_peap = xtrue) AM_CONDITIONAL(USE_EAP_TNC, test x$eap_tnc = xtrue) AM_CONDITIONAL(USE_EAP_RADIUS, test x$eap_radius = xtrue) AM_CONDITIONAL(USE_XAUTH_GENERIC, test x$xauth_generic = xtrue) +AM_CONDITIONAL(USE_XAUTH_EAP, test x$xauth_eap = xtrue) AM_CONDITIONAL(USE_TNC_IFMAP, test x$tnc_ifmap = xtrue) AM_CONDITIONAL(USE_TNC_IMC, test x$tnc_imc = xtrue) AM_CONDITIONAL(USE_TNC_IMV, test x$tnc_imv = xtrue) @@ -1148,6 +1151,7 @@ AC_OUTPUT( src/libcharon/plugins/eap_tnc/Makefile src/libcharon/plugins/eap_radius/Makefile src/libcharon/plugins/xauth_generic/Makefile + src/libcharon/plugins/xauth_eap/Makefile src/libcharon/plugins/tnc_ifmap/Makefile src/libcharon/plugins/tnc_imc/Makefile src/libcharon/plugins/tnc_imv/Makefile diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index a6334e1a0..8db43f188 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -524,3 +524,9 @@ if MONOLITHIC endif endif +if USE_XAUTH_EAP + SUBDIRS += plugins/xauth_eap +if MONOLITHIC + libcharon_la_LIBADD += plugins/xauth_eap/libstrongswan-xauth-eap.la +endif +endif diff --git a/src/libcharon/plugins/xauth_eap/Makefile.am b/src/libcharon/plugins/xauth_eap/Makefile.am new file mode 100644 index 000000000..f2cb0e26c --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libhydra \ + -I$(top_srcdir)/src/libcharon + +AM_CFLAGS = -rdynamic + +if MONOLITHIC +noinst_LTLIBRARIES = libstrongswan-xauth-eap.la +else +plugin_LTLIBRARIES = libstrongswan-xauth-eap.la +endif + +libstrongswan_xauth_eap_la_SOURCES = \ + xauth_eap_plugin.h xauth_eap_plugin.c \ + xauth_eap.h xauth_eap.c + +libstrongswan_xauth_eap_la_LDFLAGS = -module -avoid-version diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap.c b/src/libcharon/plugins/xauth_eap/xauth_eap.c new file mode 100644 index 000000000..e59084344 --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/xauth_eap.c @@ -0,0 +1,284 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_eap.h" + +#include + +#include +#include + +typedef struct private_xauth_eap_t private_xauth_eap_t; + +/** + * Private data of an xauth_eap_t object. + */ +struct private_xauth_eap_t { + + /** + * Public interface. + */ + xauth_eap_t public; + + /** + * ID of the server + */ + identification_t *server; + + /** + * ID of the peer + */ + identification_t *peer; + + /** + * Callback credential set + */ + callback_cred_t *cred; + + /** + * XAuth password + */ + chunk_t pass; +}; + +/** + * Callback credential set function + */ +static shared_key_t* shared_cb(private_xauth_eap_t *this, shared_key_type_t type, + identification_t *me, identification_t *other, + id_match_t *match_me, id_match_t *match_other) +{ + shared_key_t *shared; + + if (!this->pass.len) + { + return NULL; + } + if (type != SHARED_EAP && type != SHARED_ANY) + { + return NULL; + } + if (me) + { + if (!this->peer->equals(this->peer, me)) + { + return NULL; + } + if (match_me) + { + *match_me = ID_MATCH_PERFECT; + } + } + else if (match_me) + { + *match_me = ID_MATCH_ANY; + } + if (other) + { + if (!this->server->equals(this->server, other)) + { + return NULL; + } + if (match_other) + { + *match_other = ID_MATCH_PERFECT; + } + } + else if (match_other) + { + *match_other = ID_MATCH_ANY; + } + shared = shared_key_create(SHARED_EAP, chunk_clone(this->pass)); + this->pass = chunk_empty; + return shared; +} + +/** + * Do EAP exchanges to verify secret + */ +static bool verify_eap(private_xauth_eap_t *this, eap_method_t *backend) +{ + eap_payload_t *request, *response; + eap_method_t *frontend; + eap_type_t type; + u_int32_t vendor; + status_t status; + + if (backend->initiate(backend, &request) != NEED_MORE) + { + return FALSE; + } + type = request->get_type(request, &vendor); + frontend = charon->eap->create_instance(charon->eap, type, vendor, + EAP_PEER, this->server, this->peer); + if (!frontend) + { + DBG1(DBG_IKE, "XAuth-EAP backend requested %N, but not supported", + eap_type_names, type); + request->destroy(request); + return FALSE; + } + while (TRUE) + { + /* credential set is active in frontend only, but not in backend */ + lib->credmgr->add_local_set(lib->credmgr, &this->cred->set, TRUE); + status = frontend->process(frontend, request, &response); + lib->credmgr->remove_local_set(lib->credmgr, &this->cred->set); + request->destroy(request); + if (status != NEED_MORE) + { /* clients should never return SUCCESS */ + frontend->destroy(frontend); + return FALSE; + } + status = backend->process(backend, response, &request); + response->destroy(response); + switch (status) + { + case SUCCESS: + frontend->destroy(frontend); + return TRUE; + case NEED_MORE: + break; + default: + frontend->destroy(frontend); + return FALSE; + } + } +} + +METHOD(xauth_method_t, initiate, status_t, + private_xauth_eap_t *this, cp_payload_t **out) +{ + cp_payload_t *cp; + + cp = cp_payload_create_type(CONFIGURATION_V1, CFG_REQUEST); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_NAME, chunk_empty)); + cp->add_attribute(cp, configuration_attribute_create_chunk( + CONFIGURATION_ATTRIBUTE_V1, XAUTH_USER_PASSWORD, chunk_empty)); + *out = cp; + return NEED_MORE; +} + +METHOD(xauth_method_t, process, status_t, + private_xauth_eap_t *this, cp_payload_t *in, cp_payload_t **out) +{ + configuration_attribute_t *attr; + enumerator_t *enumerator; + identification_t *id; + chunk_t user = chunk_empty; + eap_method_t *backend; + eap_type_t type; + char *name; + bool ok; + + enumerator = in->create_attribute_enumerator(in); + while (enumerator->enumerate(enumerator, &attr)) + { + switch (attr->get_type(attr)) + { + case XAUTH_USER_NAME: + user = attr->get_chunk(attr); + break; + case XAUTH_USER_PASSWORD: + this->pass = attr->get_chunk(attr); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (!user.ptr || !this->pass.ptr) + { + DBG1(DBG_IKE, "peer did not respond to our XAuth request"); + return FAILED; + } + if (user.len) + { + id = identification_create_from_data(user); + if (!id) + { + DBG1(DBG_IKE, "failed to parse provided XAuth username"); + return FAILED; + } + this->peer->destroy(this->peer); + this->peer = id; + } + + name = lib->settings->get_str(lib->settings, + "charon.plugins.xauth-eap.backend", "radius"); + type = eap_type_from_string(name); + if (!type) + { + DBG1(DBG_CFG, "Unknown XAuth-EAP method: %s", name); + return FAILED; + } + backend = charon->eap->create_instance(charon->eap, type, 0, EAP_SERVER, + this->server, this->peer); + if (!backend) + { + DBG1(DBG_CFG, "XAuth-EAP method backend not supported: %s", name); + return FAILED; + } + ok = verify_eap(this, backend); + backend->destroy(backend); + if (ok) + { + return SUCCESS; + } + return FAILED; +} + +METHOD(xauth_method_t, get_identity, identification_t*, + private_xauth_eap_t *this) +{ + return this->peer; +} + +METHOD(xauth_method_t, destroy, void, + private_xauth_eap_t *this) +{ + this->cred->destroy(this->cred); + this->server->destroy(this->server); + this->peer->destroy(this->peer); + free(this); +} + +/* + * Described in header. + */ +xauth_eap_t *xauth_eap_create_server(identification_t *server, + identification_t *peer) +{ + private_xauth_eap_t *this; + + INIT(this, + .public = { + .xauth_method = { + .initiate = _initiate, + .process = _process, + .get_identity = _get_identity, + .destroy = _destroy, + }, + }, + .server = server->clone(server), + .peer = peer->clone(peer), + ); + + this->cred = callback_cred_create_shared((void*)shared_cb, this); + + return &this->public; +} diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap.h b/src/libcharon/plugins/xauth_eap/xauth_eap.h new file mode 100644 index 000000000..655e057e7 --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/xauth_eap.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_eap_i xauth_eap + * @{ @ingroup xauth_eap + */ + +#ifndef XAUTH_EAP_H_ +#define XAUTH_EAP_H_ + +typedef struct xauth_eap_t xauth_eap_t; + +#include + +/** + * XAuth methods that verifies XAuth credentials using EAP methods. + */ +struct xauth_eap_t { + + /** + * Implemented xauth_method_t interface. + */ + xauth_method_t xauth_method; +}; + +/** + * Creates the XAuth method using EAP, acting as server. + * + * @param server ID of the XAuth server + * @param peer ID of the XAuth client + * @return xauth_eap_t object + */ +xauth_eap_t *xauth_eap_create_server(identification_t *server, + identification_t *peer); + +#endif /** xauth_eap_H_ @}*/ diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.c b/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.c new file mode 100644 index 000000000..b776ec8ea --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "xauth_eap_plugin.h" +#include "xauth_eap.h" + +#include + +METHOD(plugin_t, get_name, char*, + xauth_eap_plugin_t *this) +{ + return "xauth-eap"; +} + +METHOD(plugin_t, get_features, int, + xauth_eap_plugin_t *this, plugin_feature_t *features[]) +{ + static plugin_feature_t f[] = { + PLUGIN_CALLBACK(xauth_method_register, xauth_eap_create_server), + PLUGIN_PROVIDE(XAUTH_SERVER, "eap"), + }; + *features = f; + return countof(f); +} + +METHOD(plugin_t, destroy, void, + xauth_eap_plugin_t *this) +{ + free(this); +} + +/* + * see header file + */ +plugin_t *xauth_eap_plugin_create() +{ + xauth_eap_plugin_t *this; + + INIT(this, + .plugin = { + .get_name = _get_name, + .get_features = _get_features, + .destroy = _destroy, + }, + ); + + return &this->plugin; +} diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.h b/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.h new file mode 100644 index 000000000..8ba0628b0 --- /dev/null +++ b/src/libcharon/plugins/xauth_eap/xauth_eap_plugin.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup xauth_eap xauth_eap + * @ingroup cplugins + * + * @defgroup xauth_eap_plugin xauth_eap_plugin + * @{ @ingroup xauth_eap + */ + +#ifndef XAUTH_EAP_PLUGIN_H_ +#define XAUTH_EAP_PLUGIN_H_ + +#include + +typedef struct xauth_eap_plugin_t xauth_eap_plugin_t; + +/** + * XAuth plugin using EAP to verify credentials. + */ +struct xauth_eap_plugin_t { + + /** + * implements plugin interface + */ + plugin_t plugin; +}; + +#endif /** XAUTH_EAP_PLUGIN_H_ @}*/ From 28e3c6595dd888166efe4bcab92fe6ae0d7603bd Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 11:15:15 +0100 Subject: [PATCH 382/534] Check if a config has been selected before narrowing selectors in quick mode --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 9e71642af..df7b6375f 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -697,8 +697,11 @@ METHOD(task_t, process_r, status_t, this->tsi = this->tsr = NULL; this->config = peer_cfg->select_child_cfg(peer_cfg, tsr, tsi, me, other); - this->tsi = select_ts(this, FALSE, tsi); - this->tsr = select_ts(this, TRUE, tsr); + if (this->config) + { + this->tsi = select_ts(this, FALSE, tsi); + this->tsr = select_ts(this, TRUE, tsr); + } tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); if (!this->config) From 87791f7538cfe3e138acb6528157b41e3f1872b0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 11:25:25 +0100 Subject: [PATCH 383/534] Added description for the xauth-eap plugin --- src/libcharon/plugins/xauth_eap/xauth_eap.h | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/libcharon/plugins/xauth_eap/xauth_eap.h b/src/libcharon/plugins/xauth_eap/xauth_eap.h index 655e057e7..70927247e 100644 --- a/src/libcharon/plugins/xauth_eap/xauth_eap.h +++ b/src/libcharon/plugins/xauth_eap/xauth_eap.h @@ -26,7 +26,13 @@ typedef struct xauth_eap_t xauth_eap_t; #include /** - * XAuth methods that verifies XAuth credentials using EAP methods. + * XAuth method that verifies XAuth credentials using EAP methods. + * + * To reuse existing authentication infrastructure, this XAuth method uses + * EAP to verify XAuth Username/Passwords. It is primarily designed to work + * with the EAP-RADIUS backend and can use any password-based EAP method + * over it. The credentials are fed locally on the IKE responder to a EAP + * client which talks to the backend instance, usually a RADIUS server. */ struct xauth_eap_t { @@ -46,4 +52,4 @@ struct xauth_eap_t { xauth_eap_t *xauth_eap_create_server(identification_t *server, identification_t *peer); -#endif /** xauth_eap_H_ @}*/ +#endif /** XAUTH_EAP_H_ @}*/ From be83ea7ebf76c3747550fd85e209b23c111868dc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 13:24:43 +0100 Subject: [PATCH 384/534] Drop IKEv1 main/aggressive modes if peer to aggressive --- src/libcharon/network/receiver.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index 6b408cc54..d069919cc 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -272,8 +272,9 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message) half_open = charon->ike_sa_manager->get_half_open_count( charon->ike_sa_manager, NULL); - /* check for cookies */ - if (this->cookie_threshold && half_open >= this->cookie_threshold && + /* check for cookies in IKEv2 */ + if (message->get_major_version(message) == IKEV2_MAJOR_VERSION && + this->cookie_threshold && half_open >= this->cookie_threshold && !check_cookie(this, message)) { u_int32_t now = time_monotonic(NULL); @@ -293,7 +294,7 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message) DBG1(DBG_NET, "generating new cookie secret after %d uses", this->secret_used); memcpy(this->secret_old, this->secret, SECRET_LENGTH); - this->rng->get_bytes(this->rng, SECRET_LENGTH, this->secret); + this->rng->get_bytes(this->rng, SECRET_LENGTH, this->secret); this->secret_switch = now; this->secret_used = 0; } @@ -345,6 +346,7 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message) */ static job_requeue_t receive_packets(private_receiver_t *this) { + ike_sa_id_t *id; packet_t *packet; message_t *message; status_t status; @@ -395,7 +397,6 @@ static job_requeue_t receive_packets(private_receiver_t *this) return JOB_REQUEUE_DIRECT; } - /* TODO-IKEv1: drop too agressive mainmodes */ if (message->get_request(message) && message->get_exchange_type(message) == IKE_SA_INIT) { @@ -405,6 +406,18 @@ static job_requeue_t receive_packets(private_receiver_t *this) return JOB_REQUEUE_DIRECT; } } + if (message->get_exchange_type(message) == ID_PROT || + message->get_exchange_type(message) == AGGRESSIVE) + { + id = message->get_ike_sa_id(message); + if (id->get_responder_spi(id) == 0 && + drop_ike_sa_init(this, message)) + { + message->destroy(message); + return JOB_REQUEUE_DIRECT; + } + } + if (this->receive_delay) { if (this->receive_delay_type == 0 || From 53300badedeab783b0965bbae3253e092f281c5e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 13:19:52 +0100 Subject: [PATCH 385/534] Send correct INVALID_MAJOR_VERSION when receiving packet with unsupported protocol --- src/libcharon/network/receiver.c | 101 +++++++++++++++++++------------ 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/src/libcharon/network/receiver.c b/src/libcharon/network/receiver.c index d069919cc..599249fcb 100644 --- a/src/libcharon/network/receiver.c +++ b/src/libcharon/network/receiver.c @@ -136,35 +136,34 @@ struct private_receiver_t { /** * send a notify back to the sender */ -static void send_notify(message_t *request, notify_type_t type, chunk_t data) +static void send_notify(message_t *request, int major, exchange_type_t exchange, + notify_type_t type, chunk_t data) { - if (request->get_request(request) && - request->get_exchange_type(request) == IKE_SA_INIT) - { - message_t *response; - host_t *src, *dst; - packet_t *packet; - ike_sa_id_t *ike_sa_id; + ike_sa_id_t *ike_sa_id; + message_t *response; + host_t *src, *dst; + packet_t *packet; - response = message_create(IKEV2_MAJOR_VERSION, IKEV2_MINOR_VERSION); - dst = request->get_source(request); - src = request->get_destination(request); - response->set_source(response, src->clone(src)); - response->set_destination(response, dst->clone(dst)); - response->set_exchange_type(response, request->get_exchange_type(request)); + response = message_create(major, 0); + response->set_exchange_type(response, exchange); + response->add_notify(response, FALSE, type, data); + dst = request->get_source(request); + src = request->get_destination(request); + response->set_source(response, src->clone(src)); + response->set_destination(response, dst->clone(dst)); + if (major == IKEV2_MAJOR_VERSION) + { response->set_request(response, FALSE); - response->set_message_id(response, 0); - ike_sa_id = request->get_ike_sa_id(request); - ike_sa_id->switch_initiator(ike_sa_id); - response->set_ike_sa_id(response, ike_sa_id); - response->add_notify(response, FALSE, type, data); - if (response->generate(response, NULL, &packet) == SUCCESS) - { - charon->sender->send(charon->sender, packet); - response->destroy(response); - } } - /* TODO-IKEv1: send IKEv1 specific notifies */ + response->set_message_id(response, 0); + ike_sa_id = request->get_ike_sa_id(request); + ike_sa_id->switch_initiator(ike_sa_id); + response->set_ike_sa_id(response, ike_sa_id); + if (response->generate(response, NULL, &packet) == SUCCESS) + { + charon->sender->send(charon->sender, packet); + } + response->destroy(response); } /** @@ -286,7 +285,7 @@ static bool drop_ike_sa_init(private_receiver_t *this, message_t *message) message->get_destination(message)); DBG2(DBG_NET, "sending COOKIE notify to %H", message->get_source(message)); - send_notify(message, COOKIE, cookie); + send_notify(message, IKEV2_MAJOR_VERSION, IKE_SA_INIT, COOKIE, cookie); chunk_free(&cookie); if (++this->secret_used > COOKIE_REUSE) { @@ -350,6 +349,7 @@ static job_requeue_t receive_packets(private_receiver_t *this) packet_t *packet; message_t *message; status_t status; + bool supported = TRUE; /* read in a packet */ status = charon->socket->receive(charon->socket, &packet); @@ -378,25 +378,48 @@ static job_requeue_t receive_packets(private_receiver_t *this) /* check IKE major version */ switch (message->get_major_version(message)) { -#ifdef USE_IKEV2 case IKEV2_MAJOR_VERSION: +#ifndef USE_IKEV2 + if (message->get_exchange_type(message) == IKE_SA_INIT && + message->get_request(message)) + { + send_notify(message, IKEV1_MAJOR_VERSION, INFORMATIONAL_V1, + INVALID_MAJOR_VERSION, chunk_empty); + supported = FALSE; + } +#endif /* USE_IKEV2 */ break; + case IKEV1_MAJOR_VERSION: +#ifndef USE_IKEV1 + if (message->get_exchange_type(message) == ID_PROT || + message->get_exchange_type(message) == AGGRESSIVE) + { + send_notify(message, IKEV2_MAJOR_VERSION, INFORMATIONAL, + INVALID_MAJOR_VERSION, chunk_empty); + supported = FALSE; + } +#endif /* USE_IKEV1 */ + break; + default: +#ifdef USE_IKEV2 + send_notify(message, IKEV2_MAJOR_VERSION, INFORMATIONAL, + INVALID_MAJOR_VERSION, chunk_empty); #endif /* USE_IKEV2 */ #ifdef USE_IKEV1 - case IKEV1_MAJOR_VERSION: - break; + send_notify(message, IKEV1_MAJOR_VERSION, INFORMATIONAL_V1, + INVALID_MAJOR_VERSION, chunk_empty); #endif /* USE_IKEV1 */ - default: - DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, " - "sending INVALID_MAJOR_VERSION", - message->get_major_version(message), - message->get_minor_version(message), - packet->get_source(packet)); - send_notify(message, INVALID_MAJOR_VERSION, chunk_empty); - message->destroy(message); - return JOB_REQUEUE_DIRECT; + supported = FALSE; + break; + } + if (!supported) + { + DBG1(DBG_NET, "received unsupported IKE version %d.%d from %H, sending " + "INVALID_MAJOR_VERSION", message->get_major_version(message), + message->get_minor_version(message), packet->get_source(packet)); + message->destroy(message); + return JOB_REQUEUE_DIRECT; } - if (message->get_request(message) && message->get_exchange_type(message) == IKE_SA_INIT) { From 82b1e5e270a2cd15edede0cbb216d7e9be1152d4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 16:07:00 +0100 Subject: [PATCH 386/534] Accept NULL as keymat when generating a message --- src/libcharon/encoding/message.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index cf2a66efa..2bf44cb3a 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1419,8 +1419,8 @@ METHOD(message_t, generate, status_t, encryption_payload_t *encryption = NULL; payload_type_t next_type; enumerator_t *enumerator; - aead_t *aead; - chunk_t chunk; + aead_t *aead = NULL; + chunk_t chunk, hash = chunk_empty; char str[BUF_LEN]; u_int32_t *lenpos; bool encrypted = FALSE, *reserved; @@ -1458,7 +1458,10 @@ METHOD(message_t, generate, status_t, else { /* get a hash for this message, if any is required */ - chunk_t hash = keymat_v1->get_hash_phase2(keymat_v1, &this->public); + if (keymat_v1) + { + hash = keymat_v1->get_hash_phase2(keymat_v1, &this->public); + } if (hash.ptr) { /* insert a HASH payload as first payload */ hash_payload_t *hash_payload; @@ -1494,7 +1497,10 @@ METHOD(message_t, generate, status_t, DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); - aead = keymat->get_aead(keymat, FALSE); + if (keymat) + { + aead = keymat->get_aead(keymat, FALSE); + } if (aead && encrypted) { encryption = wrap_payloads(this); From 986237603f06dd3503f524eafb76e6ab0d4fcf29 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 16:22:56 +0100 Subject: [PATCH 387/534] Fix ike_version_t enum names --- src/libcharon/config/peer_cfg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index b58bdce55..fb9d54bfe 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -26,7 +26,7 @@ #include ENUM(ike_version_names, IKE_ANY, IKEV2, - "IKEv1/2" + "IKEv1/2", "IKEv1", "IKEv2", ); From 448e2e294578abeba0eafc8a502d942221d2483d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 16:23:12 +0100 Subject: [PATCH 388/534] Check message version before processing it on an IKE_SA --- src/libcharon/sa/ike_sa.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 000c3e539..5916116e5 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1117,6 +1117,16 @@ METHOD(ike_sa_t, process_message, status_t, { /* do not handle messages in passive state */ return FAILED; } + if (message->get_major_version(message) != this->version) + { + DBG1(DBG_IKE, "ignoring %N IKEv%u exchange on %N SA", + exchange_type_names, message->get_exchange_type(message), + message->get_major_version(message), + ike_version_names, this->version); + /* TODO-IKEv1: fall back to IKEv1 if we receive an IKEv1 + * INVALID_MAJOR_VERSION on an IKEv2 SA. */ + return FAILED; + } status = this->task_manager->process_message(this->task_manager, message); if (this->flush_auth_cfg && this->state == IKE_ESTABLISHED) { From 451ebecc85382bebc1acff9ad664d21573ba4894 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 17:59:45 +0100 Subject: [PATCH 389/534] Implemented migration of Main Mode task --- src/libcharon/sa/ikev1/tasks/main_mode.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index 7f263260c..cd790787f 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -1103,7 +1103,20 @@ METHOD(task_t, get_type, task_type_t, METHOD(task_t, migrate, void, private_main_mode_t *this, ike_sa_t *ike_sa) { + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->proposal); + DESTROY_IF(this->dh); + chunk_free(&this->dh_value); + chunk_free(&this->nonce_i); + chunk_free(&this->nonce_r); + chunk_free(&this->sa_payload); + this->ike_sa = ike_sa; + this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + this->state = MM_INIT; + this->peer_cfg = NULL; + this->proposal = NULL; + this->dh = NULL; } METHOD(task_t, destroy, void, From 5903acd0fff11a159c0a5274384908122ede73d0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 18:00:03 +0100 Subject: [PATCH 390/534] Implemented migration of certificate handling tasks --- src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c | 1 + src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c index 30e1c6d84..5fbd04aea 100644 --- a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c @@ -307,6 +307,7 @@ METHOD(task_t, migrate, void, private_isakmp_cert_post_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; + this->state = CR_SA; } METHOD(task_t, destroy, void, diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c index db25bf3a3..25c4af6e8 100644 --- a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c @@ -491,6 +491,8 @@ METHOD(task_t, migrate, void, private_isakmp_cert_pre_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; + this->state = CR_SA; + this->send_req = TRUE; } METHOD(task_t, destroy, void, From ca037076bfd31578410af900a3a667efa165df78 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 18:00:57 +0100 Subject: [PATCH 391/534] Implemented migration of XAuth task --- src/libcharon/sa/ikev1/tasks/xauth.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c index b4d690094..f55299398 100644 --- a/src/libcharon/sa/ikev1/tasks/xauth.c +++ b/src/libcharon/sa/ikev1/tasks/xauth.c @@ -354,7 +354,25 @@ METHOD(task_t, get_type, task_type_t, METHOD(task_t, migrate, void, private_xauth_t *this, ike_sa_t *ike_sa) { + DESTROY_IF(this->xauth); + DESTROY_IF(this->cp); + this->ike_sa = ike_sa; + this->xauth = NULL; + this->cp = NULL; + this->user = NULL; + this->status = XAUTH_FAILED; + + if (this->initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } } METHOD(task_t, destroy, void, From bce22af29e340b92d98d3937e6ef6d694ee125c9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 18:01:12 +0100 Subject: [PATCH 392/534] Implemented migration of quick mode task --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 28 +++++++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index df7b6375f..13db2bb91 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -114,11 +114,6 @@ struct private_quick_mode_t { */ u_int64_t lifebytes; - /** - * Notify type in case of error - */ - notify_type_t notify_type; - /** states of quick mode */ enum { QM_INIT, @@ -895,7 +890,30 @@ METHOD(task_t, get_type, task_type_t, METHOD(task_t, migrate, void, private_quick_mode_t *this, ike_sa_t *ike_sa) { + chunk_free(&this->nonce_i); + chunk_free(&this->nonce_r); + DESTROY_IF(this->tsi); + DESTROY_IF(this->tsr); + DESTROY_IF(this->proposal); + DESTROY_IF(this->child_sa); + DESTROY_IF(this->dh); + this->ike_sa = ike_sa; + this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + this->state = QM_INIT; + this->tsi = NULL; + this->tsr = NULL; + this->proposal = NULL; + this->child_sa = NULL; + this->dh = NULL; + this->spi_i = 0; + this->spi_r = 0; + + if (!this->initiator) + { + DESTROY_IF(this->config); + this->config = NULL; + } } METHOD(task_t, destroy, void, From 94450913ef0e75945e95631db8151e2d7c9e77a3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 18:01:25 +0100 Subject: [PATCH 393/534] Fixed migration of NATD task --- src/libcharon/sa/ikev1/tasks/isakmp_natd.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_natd.c b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c index 88ee327ba..44910175a 100644 --- a/src/libcharon/sa/ikev1/tasks/isakmp_natd.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_natd.c @@ -393,6 +393,7 @@ METHOD(task_t, migrate, void, private_isakmp_natd_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; + this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); this->src_seen = FALSE; this->dst_seen = FALSE; this->src_matched = FALSE; From d9c1dae2938154828c363b3d0f15d74ced54a18f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 18:02:01 +0100 Subject: [PATCH 394/534] Implemented resetting of IKEv1 task manager, enabling additional keyingtries --- src/libcharon/sa/ike_sa.c | 2 +- src/libcharon/sa/ikev1/task_manager_v1.c | 28 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 5916116e5..78ffbe5b9 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1488,7 +1488,7 @@ METHOD(ike_sa_t, retransmit, status_t, { case IKE_CONNECTING: { - /* retry IKE_SA_INIT if we have multiple keyingtries */ + /* retry IKE_SA_INIT/Main Mode if we have multiple keyingtries */ u_int32_t tries = this->peer_cfg->get_keyingtries(this->peer_cfg); this->keyingtry++; if (tries == 0 || tries > this->keyingtry) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index dfc960891..37c3f76fb 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1103,6 +1103,34 @@ METHOD(task_manager_t, incr_mid, void, METHOD(task_manager_t, reset, void, private_task_manager_t *this, u_int32_t initiate, u_int32_t respond) { + enumerator_t *enumerator; + task_t *task; + + /* reset message counters and retransmit packets */ + DESTROY_IF(this->responding.packet); + DESTROY_IF(this->initiating.packet); + this->responding.packet = NULL; + this->initiating.packet = NULL; + this->initiating.mid = 0; + this->initiating.seqnr = 0; + this->initiating.retransmitted = 0; + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + + /* reset queued tasks */ + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, &task)) + { + task->migrate(task, this->ike_sa); + } + enumerator->destroy(enumerator); + + /* reset active tasks */ + while (this->active_tasks->remove_last(this->active_tasks, + (void**)&task) == SUCCESS) + { + task->migrate(task, this->ike_sa); + this->queued_tasks->insert_first(this->queued_tasks, task); + } } METHOD(task_manager_t, create_task_enumerator, enumerator_t*, From fd5d6bb08e62a795b3700ac6ec1da6bb0bb1f319 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 20 Dec 2011 18:49:49 +0100 Subject: [PATCH 395/534] Use IPSEC DOI also for ISAKMP SA deletes. --- src/libcharon/encoding/payloads/delete_payload.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index dec1ba72a..007411f37 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -357,6 +357,7 @@ delete_payload_t *delete_payload_create(payload_type_t type, }, .next_payload = NO_PAYLOAD, .protocol_id = protocol_id, + .doi = IKEV1_DOI_IPSEC, .type = type, ); this->payload_length = get_header_length(this); @@ -370,7 +371,6 @@ delete_payload_t *delete_payload_create(payload_type_t type, } else { - this->doi = IKEV1_DOI_IPSEC, this->spi_size = 4; } return &this->public; From 8ed976c061a7093d2d29d0c31a541aee8e9ec448 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 19:03:12 +0100 Subject: [PATCH 396/534] Don't requeue IKEv1 init tasks if they already exist in a second keyingtry --- src/libcharon/sa/ikev1/task_manager_v1.c | 47 +++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 37c3f76fb..f31f49783 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1013,14 +1013,51 @@ METHOD(task_manager_t, queue_task, void, this->queued_tasks->insert_last(this->queued_tasks, task); } +/** + * Check if a given task has been queued already + */ +static bool has_queued(private_task_manager_t *this, task_type_t type) +{ + enumerator_t *enumerator; + bool found = FALSE; + task_t *task; + + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); + while (enumerator->enumerate(enumerator, &task)) + { + if (task->get_type(task) == type) + { + found = TRUE; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + METHOD(task_manager_t, queue_ike, void, private_task_manager_t *this) { - queue_task(this, (task_t*)isakmp_vendor_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)isakmp_cert_pre_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)main_mode_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)isakmp_cert_post_create(this->ike_sa, TRUE)); - queue_task(this, (task_t*)isakmp_natd_create(this->ike_sa, TRUE)); + if (!has_queued(this, TASK_ISAKMP_VENDOR)) + { + queue_task(this, (task_t*)isakmp_vendor_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_ISAKMP_CERT_PRE)) + { + queue_task(this, (task_t*)isakmp_cert_pre_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_MAIN_MODE)) + { + queue_task(this, (task_t*)main_mode_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_ISAKMP_CERT_POST)) + { + queue_task(this, (task_t*)isakmp_cert_post_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_ISAKMP_NATD)) + { + queue_task(this, (task_t*)isakmp_natd_create(this->ike_sa, TRUE)); + } } METHOD(task_manager_t, queue_ike_rekey, void, From 8573b18d225cb7888e7c249870a80aae102a339a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 19:08:29 +0100 Subject: [PATCH 397/534] Fixed scheduling of IKEv2 init tasks in a second keyingtry --- src/libcharon/sa/ikev2/task_manager_v2.c | 66 ++++++++++++++++-------- 1 file changed, 44 insertions(+), 22 deletions(-) diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index fe576694f..23ef054fb 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1177,57 +1177,79 @@ METHOD(task_manager_t, queue_task, void, this->queued_tasks->insert_last(this->queued_tasks, task); } -METHOD(task_manager_t, queue_ike, void, - private_task_manager_t *this) +/** + * Check if a given task has been queued already + */ +static bool has_queued(private_task_manager_t *this, task_type_t type) { - peer_cfg_t *peer_cfg; - enumerator_t *enumerator; - bool has_init = FALSE, has_auth = FALSE; + bool found = FALSE; task_t *task; - /* when initiating with a non-first keying try, IKE_AUTH is still queued, - * but IKE_INIT is not */ - enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); + enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); while (enumerator->enumerate(enumerator, &task)) { - switch (task->get_type(task)) + if (task->get_type(task) == type) { - case TASK_IKE_INIT: - has_init = TRUE; - break; - case TASK_IKE_AUTH: - has_auth = TRUE; - break; - default: - break; + found = TRUE; + break; } } enumerator->destroy(enumerator); + return found; +} - if (!has_init) +METHOD(task_manager_t, queue_ike, void, + private_task_manager_t *this) +{ + if (!has_queued(this, TASK_IKE_VENDOR)) { queue_task(this, (task_t*)ike_vendor_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_INIT)) + { queue_task(this, (task_t*)ike_init_create(this->ike_sa, TRUE, NULL)); + } + if (!has_queued(this, TASK_IKE_NATD)) + { queue_task(this, (task_t*)ike_natd_create(this->ike_sa, TRUE)); } - if (!has_auth) + if (!has_queued(this, TASK_IKE_CERT_PRE)) { queue_task(this, (task_t*)ike_cert_pre_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_AUTH)) + { queue_task(this, (task_t*)ike_auth_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_CERT_POST)) + { queue_task(this, (task_t*)ike_cert_post_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_CONFIG)) + { queue_task(this, (task_t*)ike_config_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_AUTH_LIFETIME)) + { queue_task(this, (task_t*)ike_auth_lifetime_create(this->ike_sa, TRUE)); + } + if (!has_queued(this, TASK_IKE_MOBIKE)) + { + peer_cfg_t *peer_cfg; peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); if (peer_cfg->use_mobike(peer_cfg)) { queue_task(this, (task_t*)ike_mobike_create(this->ike_sa, TRUE)); } -#ifdef ME - queue_task(this, (task_t*)ike_me_create(this->ike_sa, TRUE)); -#endif /* ME */ } +#ifdef ME + if (!has_queued(this, TASK_IKE_ME)) + { + queue_task(this, (task_t*)ike_me_create(this->ike_sa, TRUE)); + } +#endif /* ME */ } METHOD(task_manager_t, queue_ike_rekey, void, From 6379c679aedd4e61c01fed2689e60de484616bc4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Dec 2011 19:20:51 +0100 Subject: [PATCH 398/534] Set used auth_class in PSKv1 authenticator to comply to constraints --- src/libcharon/sa/authenticator.c | 2 +- .../sa/ikev1/authenticators/hybrid_authenticator.c | 7 ++++--- .../sa/ikev1/authenticators/psk_v1_authenticator.c | 14 +++++++++++++- .../sa/ikev1/authenticators/psk_v1_authenticator.h | 3 ++- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/libcharon/sa/authenticator.c b/src/libcharon/sa/authenticator.c index ea1889a61..8d4b04b66 100644 --- a/src/libcharon/sa/authenticator.c +++ b/src/libcharon/sa/authenticator.c @@ -127,7 +127,7 @@ authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, case AUTH_XAUTH_RESP_PSK: return (authenticator_t*)psk_v1_authenticator_create(ike_sa, initiator, dh, dh_value, sa_payload, - id_payload); + id_payload, FALSE); case AUTH_RSA: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: diff --git a/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c b/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c index f1bc1ecc2..689f5f376 100644 --- a/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c +++ b/src/libcharon/sa/ikev1/authenticators/hybrid_authenticator.c @@ -16,6 +16,7 @@ #include "hybrid_authenticator.h" #include +#include typedef struct private_hybrid_authenticator_t private_hybrid_authenticator_t; @@ -89,10 +90,10 @@ hybrid_authenticator_t *hybrid_authenticator_create(ike_sa_t *ike_sa, .destroy = _destroy, }, }, + .hash = (authenticator_t*)psk_v1_authenticator_create(ike_sa, initiator, + dh, dh_value, sa_payload, id_payload, TRUE), .sig = authenticator_create_v1(ike_sa, initiator, AUTH_RSA, dh, - dh_value, sa_payload, id_payload), - .hash = authenticator_create_v1(ike_sa, initiator, AUTH_PSK, - dh, dh_value, sa_payload, chunk_clone(id_payload)), + dh_value, sa_payload, chunk_clone(id_payload)), ); if (!this->sig || !this->hash) { diff --git a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c index ce794a286..769c0dad3 100644 --- a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c +++ b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.c @@ -60,6 +60,11 @@ struct private_psk_v1_authenticator_t { * Encoded ID payload, without fixed header */ chunk_t id_payload; + + /** + * Used for Hybrid authentication to build hash without PSK? + */ + bool hybrid; }; METHOD(authenticator_t, build, status_t, @@ -90,6 +95,7 @@ METHOD(authenticator_t, process, status_t, hash_payload_t *hash_payload; keymat_v1_t *keymat; chunk_t hash, dh; + auth_cfg_t *auth; hash_payload = (hash_payload_t*)message->get_payload(message, HASH_V1); if (!hash_payload) @@ -107,6 +113,11 @@ METHOD(authenticator_t, process, status_t, if (chunk_equals(hash, hash_payload->get_hash(hash_payload))) { free(hash.ptr); + if (!this->hybrid) + { + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); + } return SUCCESS; } free(hash.ptr); @@ -127,7 +138,7 @@ METHOD(authenticator_t, destroy, void, psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, bool initiator, diffie_hellman_t *dh, chunk_t dh_value, chunk_t sa_payload, - chunk_t id_payload) + chunk_t id_payload, bool hybrid) { private_psk_v1_authenticator_t *this; @@ -146,6 +157,7 @@ psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, .dh_value = dh_value, .sa_payload = sa_payload, .id_payload = id_payload, + .hybrid = hybrid, ); return &this->public; diff --git a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h index 194b96456..d48410074 100644 --- a/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h +++ b/src/libcharon/sa/ikev1/authenticators/psk_v1_authenticator.h @@ -46,11 +46,12 @@ struct psk_v1_authenticator_t { * @param sa_payload generated SA payload data, without payload header * @param id_payload encoded ID payload of peer to authenticate or verify * without payload header (gets owned) + * @param hybrid TRUE if used for hybrid authentication without PSK * @return PSK authenticator */ psk_v1_authenticator_t *psk_v1_authenticator_create(ike_sa_t *ike_sa, bool initiator, diffie_hellman_t *dh, chunk_t dh_value, chunk_t sa_payload, - chunk_t id_payload); + chunk_t id_payload, bool hybrid); #endif /** PSK_V1_AUTHENTICATOR_H_ @}*/ From daee47ba466c96eca5accbb0cac737465915b4f8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 10:53:05 +0100 Subject: [PATCH 399/534] Send a delete for every CHILD_SA before deleting IKE_SA --- src/libcharon/sa/ikev1/task_manager_v1.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index f31f49783..da889be76 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -349,13 +349,13 @@ METHOD(task_manager_t, initiate, status_t, new_mid = TRUE; break; } - if (activate_task(this, TASK_ISAKMP_DELETE)) + if (activate_task(this, TASK_QUICK_DELETE)) { exchange = INFORMATIONAL_V1; new_mid = TRUE; break; } - if (activate_task(this, TASK_QUICK_DELETE)) + if (activate_task(this, TASK_ISAKMP_DELETE)) { exchange = INFORMATIONAL_V1; new_mid = TRUE; @@ -499,7 +499,7 @@ METHOD(task_manager_t, initiate, status_t, break; } } - return SUCCESS; + return initiate(this); } /** @@ -1075,6 +1075,18 @@ METHOD(task_manager_t, queue_ike_reauth, void, METHOD(task_manager_t, queue_ike_delete, void, private_task_manager_t *this) { + enumerator_t *enumerator; + child_sa_t *child_sa; + + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, &child_sa)) + { + queue_task(this, (task_t*) + quick_delete_create(this->ike_sa, child_sa->get_protocol(child_sa), + child_sa->get_spi(child_sa, TRUE), FALSE)); + } + enumerator->destroy(enumerator); + queue_task(this, (task_t*)isakmp_delete_create(this->ike_sa, TRUE)); } From 3d54ae94d935fa60b3f3228e7a0ad1ba92092e84 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 12:05:34 +0100 Subject: [PATCH 400/534] Handle initiation of not supported IKE versions properly --- src/libcharon/control/controller.c | 11 ++++++ .../plugins/android/android_service.c | 11 +++++- src/libcharon/plugins/maemo/maemo_service.c | 10 ++++- src/libcharon/plugins/nm/nm_service.c | 8 ++++ src/libcharon/sa/ike_sa.c | 26 ++++++++++--- src/libcharon/sa/ike_sa_manager.c | 37 +++++++++++-------- src/libcharon/sa/ikev2/tasks/ike_reauth.c | 10 +++-- src/libcharon/sa/ikev2/tasks/ike_rekey.c | 16 +++++--- src/libcharon/sa/trap_manager.c | 29 ++++++++------- 9 files changed, 111 insertions(+), 47 deletions(-) diff --git a/src/libcharon/control/controller.c b/src/libcharon/control/controller.c index 0f247962b..4aded8f9d 100644 --- a/src/libcharon/control/controller.c +++ b/src/libcharon/control/controller.c @@ -217,6 +217,17 @@ METHOD(job_t, initiate_execute, void, ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, peer_cfg); + if (!ike_sa) + { + listener->child_cfg->destroy(listener->child_cfg); + peer_cfg->destroy(peer_cfg); + /* trigger down event to release listener */ + listener->ike_sa = charon->ike_sa_manager->checkout_new( + charon->ike_sa_manager, IKE_ANY, TRUE); + DESTROY_IF(listener->ike_sa); + listener->status = FAILED; + return; + } listener->ike_sa = ike_sa; if (ike_sa->get_peer_cfg(ike_sa) == NULL) diff --git a/src/libcharon/plugins/android/android_service.c b/src/libcharon/plugins/android/android_service.c index 96603ab29..8aba925a2 100644 --- a/src/libcharon/plugins/android/android_service.c +++ b/src/libcharon/plugins/android/android_service.c @@ -300,12 +300,17 @@ static job_requeue_t initiate(private_android_service_t *this) 0, "255.255.255.255", 65535); child_cfg->add_traffic_selector(child_cfg, FALSE, ts); peer_cfg->add_child_cfg(peer_cfg, child_cfg); - /* get an additional reference because initiate consumes one */ - child_cfg->get_ref(child_cfg); /* get us an IKE_SA */ ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, peer_cfg); + if (!ike_sa) + { + peer_cfg->destroy(peer_cfg); + send_status(this, VPN_ERROR_CONNECTION_FAILED); + return JOB_REQUEUE_NONE; + } + if (!ike_sa->get_peer_cfg(ike_sa)) { ike_sa->set_peer_cfg(ike_sa, peer_cfg); @@ -318,6 +323,8 @@ static job_requeue_t initiate(private_android_service_t *this) /* confirm that we received the request */ send_status(this, i); + /* get an additional reference because initiate consumes one */ + child_cfg->get_ref(child_cfg); if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS) { DBG1(DBG_CFG, "failed to initiate tunnel"); diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index 58361a408..69eac084c 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -355,12 +355,16 @@ static gboolean initiate_connection(private_maemo_service_t *this, 0, "255.255.255.255", 65535); child_cfg->add_traffic_selector(child_cfg, FALSE, ts); peer_cfg->add_child_cfg(peer_cfg, child_cfg); - /* get an additional reference because initiate consumes one */ - child_cfg->get_ref(child_cfg); /* get us an IKE_SA */ ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, peer_cfg); + if (!ike_sa) + { + peer_cfg->destroy(peer_cfg); + this->status = VPN_STATUS_CONNECTION_FAILED; + return FALSE; + } if (!ike_sa->get_peer_cfg(ike_sa)) { ike_sa->set_peer_cfg(ike_sa, peer_cfg); @@ -374,6 +378,8 @@ static gboolean initiate_connection(private_maemo_service_t *this, this->public.listener.ike_state_change = _ike_state_change; charon->bus->add_listener(charon->bus, &this->public.listener); + /* get an additional reference because initiate consumes one */ + child_cfg->get_ref(child_cfg); if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS) { DBG1(DBG_CFG, "failed to initiate tunnel"); diff --git a/src/libcharon/plugins/nm/nm_service.c b/src/libcharon/plugins/nm/nm_service.c index 8135476fd..788291531 100644 --- a/src/libcharon/plugins/nm/nm_service.c +++ b/src/libcharon/plugins/nm/nm_service.c @@ -533,6 +533,13 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, */ ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, peer_cfg); + if (!ike_sa) + { + peer_cfg->destroy(peer_cfg); + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, + "IKE version not supported."); + return FALSE; + } if (!ike_sa->get_peer_cfg(ike_sa)) { ike_sa->set_peer_cfg(ike_sa, peer_cfg); @@ -550,6 +557,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, /** * Initiate */ + child_cfg->get_ref(child_cfg); if (ike_sa->initiate(ike_sa, child_cfg, 0, NULL, NULL) != SUCCESS) { charon->bus->remove_listener(charon->bus, &priv->listener); diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 78ffbe5b9..442eb7208 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1412,6 +1412,10 @@ METHOD(ike_sa_t, reestablish, status_t, new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, this->version, TRUE); + if (!new) + { + return FAILED; + } new->set_peer_cfg(new, this->peer_cfg); host = this->other_host; new->set_other_host(new, host->clone(host)); @@ -1802,7 +1806,7 @@ METHOD(ike_sa_t, destroy, void, charon->bus->set_sa(charon->bus, &this->public); set_state(this, IKE_DESTROYING); - this->task_manager->destroy(this->task_manager); + DESTROY_IF(this->task_manager); /* remove attributes first, as we pass the IKE_SA to the handler */ while (this->attributes->remove_last(this->attributes, @@ -1820,7 +1824,7 @@ METHOD(ike_sa_t, destroy, void, /* unset SA after here to avoid usage by the listeners */ charon->bus->set_sa(charon->bus, NULL); - this->keymat->destroy(this->keymat); + DESTROY_IF(this->keymat); if (this->my_virtual_ip) { @@ -1881,6 +1885,15 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, private_ike_sa_t *this; static u_int32_t unique_id = 0; + if (version == IKE_ANY) + { /* prefer IKEv2 if protocol not specified */ +#ifdef USE_IKEV2 + version = IKEV2; +#else + version = IKEV1; +#endif + } + INIT(this, .public = { .get_version = _get_version, @@ -1991,8 +2004,11 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, this->task_manager = task_manager_create(&this->public); this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); - /* TODO-IKEv1: check if keymat and task manager created successfully. - * Return NULL otherwise? */ - + if (!this->task_manager || !this->keymat) + { + DBG1(DBG_IKE, "IKE version %d not supported", this->version); + destroy(this); + return NULL; + } return &this->public; } diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 776b2b7ae..d992ce1dc 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -955,9 +955,11 @@ METHOD(ike_sa_manager_t, checkout_new, ike_sa_t*, ike_sa = ike_sa_create(ike_sa_id, initiator, version); ike_sa_id->destroy(ike_sa_id); - DBG2(DBG_MGR, "created IKE_SA %s[%u]", ike_sa->get_name(ike_sa), - ike_sa->get_unique_id(ike_sa)); - + if (ike_sa) + { + DBG2(DBG_MGR, "created IKE_SA %s[%u]", ike_sa->get_name(ike_sa), + ike_sa->get_unique_id(ike_sa)); + } return ike_sa; } @@ -1033,23 +1035,26 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, { /* no IKE_SA found, create a new one */ id->set_responder_spi(id, get_spi(this)); - entry = entry_create(); - /* a new SA checked out by message is a responder SA */ - entry->ike_sa = ike_sa_create(id, FALSE, ike_version); - entry->ike_sa_id = id->clone(id); + ike_sa = ike_sa_create(id, FALSE, ike_version); + if (ike_sa) + { + entry = entry_create(); + /* a new SA checked out by message is a responder SA */ + entry->ike_sa = ike_sa; + entry->ike_sa_id = id->clone(id); - segment = put_entry(this, entry); - entry->checked_out = TRUE; - unlock_single_segment(this, segment); + segment = put_entry(this, entry); + entry->checked_out = TRUE; + unlock_single_segment(this, segment); - entry->message_id = message->get_message_id(message); - entry->init_hash = hash; - ike_sa = entry->ike_sa; + entry->message_id = message->get_message_id(message); + entry->init_hash = hash; - DBG2(DBG_MGR, "created IKE_SA %s[%u]", - ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); + DBG2(DBG_MGR, "created IKE_SA %s[%u]", + ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); + } } - else + if (ike_sa == NULL) { chunk_free(&hash); DBG1(DBG_MGR, "ignoring message, no such IKE_SA"); diff --git a/src/libcharon/sa/ikev2/tasks/ike_reauth.c b/src/libcharon/sa/ikev2/tasks/ike_reauth.c index d9f3fe8de..8371b8b6a 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_reauth.c +++ b/src/libcharon/sa/ikev2/tasks/ike_reauth.c @@ -54,7 +54,6 @@ METHOD(task_t, process_i, status_t, ike_sa_t *new; host_t *host; enumerator_t *enumerator; - ike_version_t version; child_sa_t *child_sa; peer_cfg_t *peer_cfg; @@ -75,9 +74,12 @@ METHOD(task_t, process_i, status_t, return FAILED; } - version = this->ike_sa->get_version(this->ike_sa); - new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, version, - TRUE); + new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, + this->ike_sa->get_version(this->ike_sa), TRUE); + if (!new) + { /* shouldn't happen */ + return FAILED; + } new->set_peer_cfg(new, peer_cfg); host = this->ike_sa->get_other_host(this->ike_sa); diff --git a/src/libcharon/sa/ikev2/tasks/ike_rekey.c b/src/libcharon/sa/ikev2/tasks/ike_rekey.c index 2cfcdc1fc..c3c6cf00e 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_rekey.c +++ b/src/libcharon/sa/ikev2/tasks/ike_rekey.c @@ -123,16 +123,20 @@ METHOD(task_t, process_i_delete, status_t, METHOD(task_t, build_i, status_t, private_ike_rekey_t *this, message_t *message) { + ike_version_t version; peer_cfg_t *peer_cfg; host_t *other_host; /* create new SA only on first try */ if (this->new_sa == NULL) { - ike_version_t version = this->ike_sa->get_version(this->ike_sa); + version = this->ike_sa->get_version(this->ike_sa); this->new_sa = charon->ike_sa_manager->checkout_new( charon->ike_sa_manager, version, TRUE); - + if (!this->new_sa) + { /* shouldn't happen */ + return FAILED; + } peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); other_host = this->ike_sa->get_other_host(this->ike_sa); this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); @@ -149,7 +153,6 @@ METHOD(task_t, process_r, status_t, private_ike_rekey_t *this, message_t *message) { enumerator_t *enumerator; - ike_version_t version; peer_cfg_t *peer_cfg; child_sa_t *child_sa; @@ -177,9 +180,12 @@ METHOD(task_t, process_r, status_t, } enumerator->destroy(enumerator); - version = this->ike_sa->get_version(this->ike_sa); this->new_sa = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, - version, FALSE); + this->ike_sa->get_version(this->ike_sa), FALSE); + if (!this->new_sa) + { /* shouldn't happen */ + return FAILED; + } peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); this->new_sa->set_peer_cfg(this->new_sa, peer_cfg); diff --git a/src/libcharon/sa/trap_manager.c b/src/libcharon/sa/trap_manager.c index bf9f8432c..3f434dae1 100644 --- a/src/libcharon/sa/trap_manager.c +++ b/src/libcharon/sa/trap_manager.c @@ -274,21 +274,24 @@ METHOD(trap_manager_t, acquire, void, peer = found->peer_cfg; ike_sa = charon->ike_sa_manager->checkout_by_config( charon->ike_sa_manager, peer); - if (ike_sa->get_peer_cfg(ike_sa) == NULL) + if (ike_sa) { - ike_sa->set_peer_cfg(ike_sa, peer); - } - child->get_ref(child); - reqid = found->child_sa->get_reqid(found->child_sa); - if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) - { - found->pending = ike_sa; - charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); - } - else - { - charon->ike_sa_manager->checkin_and_destroy( + if (ike_sa->get_peer_cfg(ike_sa) == NULL) + { + ike_sa->set_peer_cfg(ike_sa, peer); + } + child->get_ref(child); + reqid = found->child_sa->get_reqid(found->child_sa); + if (ike_sa->initiate(ike_sa, child, reqid, src, dst) != DESTROY_ME) + { + found->pending = ike_sa; + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + else + { + charon->ike_sa_manager->checkin_and_destroy( charon->ike_sa_manager, ike_sa); + } } } this->lock->unlock(this->lock); From 3bacc1f4298619effcdb5f575667d27dfb06cab5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 12:13:43 +0100 Subject: [PATCH 401/534] Added a keymat_t version to cast it safely --- src/libcharon/sa/ikev1/keymat_v1.c | 7 +++++++ src/libcharon/sa/ikev2/keymat_v2.c | 7 +++++++ src/libcharon/sa/keymat.h | 7 +++++++ 3 files changed, 21 insertions(+) diff --git a/src/libcharon/sa/ikev1/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c index 100c9526a..a0dbd5296 100644 --- a/src/libcharon/sa/ikev1/keymat_v1.c +++ b/src/libcharon/sa/ikev1/keymat_v1.c @@ -946,6 +946,12 @@ METHOD(keymat_v1_t, confirm_iv, void, } } +METHOD(keymat_t, get_version, ike_version_t, + private_keymat_v1_t *this) +{ + return IKEV1; +} + METHOD(keymat_t, create_dh, diffie_hellman_t*, private_keymat_v1_t *this, diffie_hellman_group_t group) { @@ -984,6 +990,7 @@ keymat_v1_t *keymat_v1_create(bool initiator) INIT(this, .public = { .keymat = { + .get_version = _get_version, .create_dh = _create_dh, .get_aead = _get_aead, .destroy = _destroy, diff --git a/src/libcharon/sa/ikev2/keymat_v2.c b/src/libcharon/sa/ikev2/keymat_v2.c index aacff0a99..3adceeec4 100644 --- a/src/libcharon/sa/ikev2/keymat_v2.c +++ b/src/libcharon/sa/ikev2/keymat_v2.c @@ -71,6 +71,12 @@ struct private_keymat_v2_t { chunk_t skp_verify; }; +METHOD(keymat_t, get_version, ike_version_t, + private_keymat_v2_t *this) +{ + return IKEV2; +} + METHOD(keymat_t, create_dh, diffie_hellman_t*, private_keymat_v2_t *this, diffie_hellman_group_t group) { @@ -563,6 +569,7 @@ keymat_v2_t *keymat_v2_create(bool initiator) INIT(this, .public = { .keymat = { + .get_version = _get_version, .create_dh = _create_dh, .get_aead = _get_aead, .destroy = _destroy, diff --git a/src/libcharon/sa/keymat.h b/src/libcharon/sa/keymat.h index 4a551a8f5..9de2574e1 100644 --- a/src/libcharon/sa/keymat.h +++ b/src/libcharon/sa/keymat.h @@ -36,6 +36,13 @@ typedef struct keymat_t keymat_t; */ struct keymat_t { + /** + * Get IKE version of this keymat. + * + * @return IKEV1 for keymat_v1_t, IKEV2 for keymat_v2_t + */ + ike_version_t (*get_version)(keymat_t *this); + /** * Create a diffie hellman object for key agreement. * From 07b8ec7c00626f2bbf8fa3e9aded9df520d50221 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 12:39:21 +0100 Subject: [PATCH 402/534] Cast keymat safely, not based on external input --- src/libcharon/encoding/message.c | 80 ++++++++++++++++++-------------- 1 file changed, 44 insertions(+), 36 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 2bf44cb3a..46384a5ac 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1450,18 +1450,10 @@ METHOD(message_t, generate, status_t, { order_payloads(this); } - - if (this->major_version == IKEV2_MAJOR_VERSION) - { - encrypted = this->rule->encrypted; - } - else + if (keymat && keymat->get_version(keymat) == IKEV1) { /* get a hash for this message, if any is required */ - if (keymat_v1) - { - hash = keymat_v1->get_hash_phase2(keymat_v1, &this->public); - } + hash = keymat_v1->get_hash_phase2(keymat_v1, &this->public); if (hash.ptr) { /* insert a HASH payload as first payload */ hash_payload_t *hash_payload; @@ -1475,24 +1467,28 @@ METHOD(message_t, generate, status_t, } chunk_free(&hash); } - if (!encrypted) + } + if (this->major_version == IKEV2_MAJOR_VERSION) + { + encrypted = this->rule->encrypted; + } + else if (!encrypted) + { + /* If at least one payload requires encryption, encrypt the message. + * If no key material is available, the flag will be reset below. */ + enumerator = this->payloads->create_enumerator(this->payloads); + while (enumerator->enumerate(enumerator, (void**)&payload)) { - /* If at least one payload requires encryption, encrypt the message. - * If no key material is available, the flag will be reset below. */ - enumerator = this->payloads->create_enumerator(this->payloads); - while (enumerator->enumerate(enumerator, (void**)&payload)) - { - payload_rule_t *rule; + payload_rule_t *rule; - rule = get_payload_rule(this, payload->get_type(payload)); - if (rule && rule->encrypted) - { - this->is_encrypted = encrypted = TRUE; - break; - } + rule = get_payload_rule(this, payload->get_type(payload)); + if (rule && rule->encrypted) + { + this->is_encrypted = encrypted = TRUE; + break; } - enumerator->destroy(enumerator); } + enumerator->destroy(enumerator); } DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); @@ -1591,9 +1587,12 @@ METHOD(message_t, generate, status_t, htoun32(lenpos, chunk.len); this->packet->set_data(this->packet, chunk_clone(chunk)); if (this->is_encrypted) - { /* update the IV for the next IKEv1 message */ + { + /* update the IV for the next IKEv1 message */ chunk_t last_block; - size_t bs = aead->get_block_size(aead); + size_t bs; + + bs = aead->get_block_size(aead); last_block = chunk_create(chunk.ptr + chunk.len - bs, bs); keymat_v1->update_iv(keymat_v1, this->message_id, last_block); keymat_v1->confirm_iv(keymat_v1, this->message_id); @@ -1727,6 +1726,7 @@ static status_t parse_payloads(private_message_t *this) { /* wrap the whole encrypted IKEv1 message in a special encryption * payload which is then handled just like a regular payload */ encryption_payload_t *encryption; + status = this->parser->parse_payload(this->parser, ENCRYPTED_V1, (payload_t**)&encryption); if (status != SUCCESS) @@ -1817,7 +1817,19 @@ static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) status = VERIFY_ERROR; break; } + if (!keymat) + { + DBG1(DBG_ENC, "found encryption payload, but no keymat"); + status = INVALID_ARG; + break; + } aead = keymat->get_aead(keymat, TRUE); + if (!aead) + { + DBG1(DBG_ENC, "found encryption payload, but no transform set"); + status = INVALID_ARG; + break; + } bs = aead->get_block_size(aead); encryption->set_transform(encryption, aead); chunk = this->packet->get_data(this->packet); @@ -1828,7 +1840,7 @@ static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) status = VERIFY_ERROR; break; } - if (type == ENCRYPTED_V1) + if (keymat->get_version(keymat) == IKEV1) { /* instead of associated data we provide the IV, we also update * the IV with the last encrypted block */ keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; @@ -1982,7 +1994,7 @@ METHOD(message_t, parse_body, status_t, DBG1(DBG_ENC, "parsed %s", get_string(this, str, sizeof(str))); - if (this->major_version == IKEV1_MAJOR_VERSION) + if (keymat && keymat->get_version(keymat) == IKEV1) { keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; chunk_t hash; @@ -2019,15 +2031,11 @@ METHOD(message_t, parse_body, status_t, DBG2(DBG_ENC, "verified IKEv1 message with hash %B", &hash); chunk_free(&hash); } + if (this->is_encrypted) + { /* message verified, confirm IV */ + keymat_v1->confirm_iv(keymat_v1, this->message_id); + } } - - if (this->is_encrypted) - { /* TODO-IKEv1: this should be done later when we know this is no - * retransmit */ - keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; - keymat_v1->confirm_iv(keymat_v1, this->message_id); - } - return SUCCESS; } From dd5c3787dc38373237626796f7efeab63b8418c4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 13:54:40 +0100 Subject: [PATCH 403/534] Give a hint that decryption failed if payload length invalid --- src/libcharon/encoding/payloads/encryption_payload.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c index f3c4b3996..096079ad7 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.c +++ b/src/libcharon/encoding/payloads/encryption_payload.c @@ -432,6 +432,13 @@ static status_t parse(private_encryption_payload_t *this, chunk_t plain) { payload_t *payload; + if (plain.len < 4 || untoh16(plain.ptr + 2) > plain.len) + { + DBG1(DBG_ENC, "invalid %N payload length, decryption failed?", + payload_type_names, type); + parser->destroy(parser); + return PARSE_ERROR; + } if (parser->parse_payload(parser, type, &payload) != SUCCESS) { parser->destroy(parser); From 8a395e889c3417ecacaa9718bd569d454473a9e7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 13:55:30 +0100 Subject: [PATCH 404/534] Fixed leak of a hash when checking out by hash --- src/libcharon/sa/ike_sa_manager.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index d992ce1dc..35b9cab25 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1027,6 +1027,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, ike_sa = entry->ike_sa; DBG2(DBG_MGR, "IKE_SA %s[%u] checked out by hash", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); + chunk_free(&hash); } unlock_single_segment(this, segment); } From db1dc81329abd95274f2b81a55b4bcc421bb2479 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Wed, 21 Dec 2011 13:46:47 +0100 Subject: [PATCH 405/534] IKEv1 ATTRIBUTES_NOT_SUPPORTED error notify added. --- src/libcharon/encoding/payloads/notify_payload.c | 6 ++++-- src/libcharon/encoding/payloads/notify_payload.h | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index d5de611e7..19a32d696 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -36,7 +36,8 @@ ENUM_NEXT(notify_type_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYN "INVALID_MESSAGE_ID"); ENUM_NEXT(notify_type_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVALID_SPI"); -ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, +ENUM_NEXT(notify_type_names, ATTRIBUTES_NOT_SUPPORTED, NO_PROPOSAL_CHOSEN, INVALID_SPI, + "ATTRIBUTES_NOT_SUPPORTED", "NO_PROPOSAL_CHOSEN"); ENUM_NEXT(notify_type_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN, "PAYLOAD_MALFORMED", @@ -131,7 +132,8 @@ ENUM_NEXT(notify_type_short_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVAL "INVAL_MID"); ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVAL_SPI"); -ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, +ENUM_NEXT(notify_type_short_names, ATTRIBUTES_NOT_SUPPORTED, NO_PROPOSAL_CHOSEN, INVALID_SPI, + "ATTR_UNSUP", "NO_PROP"); ENUM_NEXT(notify_type_short_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN, "PLD_MAL", diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index c6d09daa7..d105cc21a 100644 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -47,6 +47,9 @@ enum notify_type_t { INVALID_EXCHANGE_TYPE = 7, INVALID_MESSAGE_ID = 9, INVALID_SPI = 11, + /* IKEv1 only */ + ATTRIBUTES_NOT_SUPPORTED = 13, + /* IKEv1 alias */ NO_PROPOSAL_CHOSEN = 14, /* IKEv1 only */ PAYLOAD_MALFORMED = 16, From 9276f7121c52bc970c156bd238dc10d98334e2a3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 14:38:36 +0100 Subject: [PATCH 406/534] Always queue a new passive task when receiving an IKEv1 INFORMATIONAL --- src/libcharon/sa/ikev1/task_manager_v1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index da889be76..227475209 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -655,7 +655,8 @@ static status_t process_request(private_task_manager_t *this, task_t *task = NULL; bool send_response = FALSE; - if (this->passive_tasks->get_count(this->passive_tasks) == 0) + if (message->get_exchange_type(message) == INFORMATIONAL_V1 || + this->passive_tasks->get_count(this->passive_tasks) == 0) { /* create tasks depending on request type, if not already some queued */ switch (message->get_exchange_type(message)) { From 253d7e3eff9e0351a075c248594f0afde9a5971f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 14:39:05 +0100 Subject: [PATCH 407/534] Don't process notifies in quick mode task when we get an INFORMATIONAL --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 13db2bb91..94e5bb85a 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -758,7 +758,8 @@ METHOD(task_t, process_r, status_t, } case QM_NEGOTIATED: { - if (has_notify_errors(this, message)) + if (message->get_exchange_type(message) == INFORMATIONAL_V1 || + has_notify_errors(this, message)) { return SUCCESS; } From 96f98a8c1164c9f08d1015b67434db248781ad63 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 15:01:29 +0100 Subject: [PATCH 408/534] Accept IKEv1 INVALID_KE_INFORMATION notifies without data --- src/libcharon/encoding/payloads/notify_payload.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index 19a32d696..6f3784219 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -405,7 +405,7 @@ METHOD(payload_t, verify, status_t, { case INVALID_KE_PAYLOAD: { - if (this->notify_data.len != 2) + if (this->type == NOTIFY && this->notify_data.len != 2) { bad_length = TRUE; } @@ -425,7 +425,7 @@ METHOD(payload_t, verify, status_t, case INVALID_MAJOR_VERSION: case NO_PROPOSAL_CHOSEN: { - if ((this->notify_data.len != 0) && (this->type == NOTIFY)) + if (this->type == NOTIFY && this->notify_data.len != 0) { bad_length = TRUE; } From dc8e964775c63ffa5d6646728115d63f7a19224a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 15:02:02 +0100 Subject: [PATCH 409/534] Queue IKEv1 INFORMATIONALS with higher priority to process notifies first --- src/libcharon/sa/ikev1/task_manager_v1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 227475209..c0bc03045 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -688,7 +688,7 @@ static status_t process_request(private_task_manager_t *this, break; case INFORMATIONAL_V1: task = (task_t *)informational_create(this->ike_sa, NULL); - this->passive_tasks->insert_last(this->passive_tasks, task); + this->passive_tasks->insert_first(this->passive_tasks, task); break; case TRANSACTION: if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) @@ -904,7 +904,7 @@ METHOD(task_manager_t, process_message, status_t, if ((mid && mid == this->initiating.mid) || (this->initiating.mid == 0 && msg->get_exchange_type(msg) == this->initiating.type && - this->active_tasks->get_count(this->active_tasks))) + this->active_tasks->get_count(this->active_tasks))) { msg->set_request(msg, FALSE); status = parse_message(this, msg); From f5a84055fe8ecfb22b67af554bf1b43c9c3e751b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 21 Dec 2011 17:08:08 +0100 Subject: [PATCH 410/534] Implemented responder retransmission, currently enabled for quick mode only --- src/libcharon/sa/ike_sa_manager.c | 2 +- src/libcharon/sa/ikev1/task_manager_v1.c | 180 +++++++++++++++-------- 2 files changed, 121 insertions(+), 61 deletions(-) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 35b9cab25..9ec0d34d8 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1071,7 +1071,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, if (message->get_request(message) && message->get_message_id(message) == entry->message_id) { - DBG1(DBG_MGR, "ignoring request with ID %d, already processing", + DBG1(DBG_MGR, "ignoring request with ID %u, already processing", entry->message_id); } else if (wait_for_entry(this, entry, segment)) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index c0bc03045..371cdf721 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -42,6 +42,14 @@ */ #define MAX_OLD_HASHES 2 +/** + * First sequence number of responding packets. + * + * To distinguish retransmission jobs for initiating and responding packets, + * we split up the sequence counter and use the upper half for responding. + */ +#define RESPONDING_SEQ INT_MAX + typedef struct exchange_t exchange_t; /** @@ -86,6 +94,11 @@ struct private_task_manager_t { * Exchange we are currently handling as responder */ struct { + /** + * Message ID of the last response + */ + u_int32_t mid; + /** * Hash of a previously received message */ @@ -96,6 +109,16 @@ struct private_task_manager_t { */ packet_t *packet; + /** + * Sequence number of the last sent message + */ + u_int32_t seqnr; + + /** + * how many times we have retransmitted so far + */ + u_int retransmitted; + } responding; /** @@ -228,46 +251,63 @@ static bool activate_task(private_task_manager_t *this, task_type_t type) return found; } -METHOD(task_manager_t, retransmit, status_t, - private_task_manager_t *this, u_int32_t message_seqnr) +/** + * Retransmit a packet, either as initiator or as responder + */ +static status_t retransmit_packet(private_task_manager_t *this, u_int32_t seqnr, + u_int mid, u_int retransmitted, packet_t *packet) { - /* this.initiating packet used as marker for received response */ - if (message_seqnr == this->initiating.seqnr && this->initiating.packet ) + u_int32_t t; + + if (retransmitted > this->retransmit_tries) { - u_int32_t timeout; - packet_t *packet; - job_t *job; - - if (this->initiating.retransmitted <= this->retransmit_tries) + DBG1(DBG_IKE, "giving up after %u retransmits", retransmitted - 1); + if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) { - timeout = (u_int32_t)(this->retransmit_timeout * 1000.0 * - pow(this->retransmit_base, this->initiating.retransmitted)); + charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); } - else - { - DBG1(DBG_IKE, "giving up after %d retransmits", - this->initiating.retransmitted - 1); - if (this->ike_sa->get_state(this->ike_sa) != IKE_CONNECTING) - { - charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); - } - return DESTROY_ME; - } - - if (this->initiating.retransmitted) - { - DBG1(DBG_IKE, "retransmit %d of request with message ID %u seqnr (%d)", - this->initiating.retransmitted, this->initiating.mid, message_seqnr); - } - packet = this->initiating.packet->clone(this->initiating.packet); - charon->sender->send(charon->sender, packet); - - this->initiating.retransmitted++; - job = (job_t*)retransmit_job_create(this->initiating.seqnr, - this->ike_sa->get_id(this->ike_sa)); - lib->scheduler->schedule_job_ms(lib->scheduler, job, timeout); + return DESTROY_ME; } - return SUCCESS; + t = (u_int32_t)(this->retransmit_timeout * 1000.0 * + pow(this->retransmit_base, retransmitted)); + if (retransmitted) + { + DBG1(DBG_IKE, "sending retransmit %u of %s message ID %u, seq %u", + retransmitted, seqnr < RESPONDING_SEQ ? "request" : "response", + mid, seqnr < RESPONDING_SEQ ? seqnr : seqnr - RESPONDING_SEQ); + } + charon->sender->send(charon->sender, packet->clone(packet)); + lib->scheduler->schedule_job_ms(lib->scheduler, (job_t*) + retransmit_job_create(seqnr, this->ike_sa->get_id(this->ike_sa)), t); + return NEED_MORE; +} + +METHOD(task_manager_t, retransmit, status_t, + private_task_manager_t *this, u_int32_t seqnr) +{ + status_t status = SUCCESS; + + if (seqnr == this->initiating.seqnr && this->initiating.packet) + { + status = retransmit_packet(this, seqnr, this->initiating.mid, + this->initiating.retransmitted, this->initiating.packet); + if (status == NEED_MORE) + { + this->initiating.retransmitted++; + status = SUCCESS; + } + } + if (seqnr == this->responding.seqnr && this->responding.packet) + { + status = retransmit_packet(this, seqnr, this->responding.mid, + this->responding.retransmitted, this->responding.packet); + if (status == NEED_MORE) + { + this->responding.retransmitted++; + status = SUCCESS; + } + } + return status; } METHOD(task_manager_t, initiate, status_t, @@ -461,8 +501,8 @@ METHOD(task_manager_t, initiate, status_t, message->destroy(message); return initiate(this); } - this->initiating.seqnr++; + DESTROY_IF(this->initiating.packet); status = this->ike_sa->generate_message(this->ike_sa, message, &this->initiating.packet); if (status != SUCCESS) @@ -474,16 +514,25 @@ METHOD(task_manager_t, initiate, status_t, charon->bus->ike_updown(charon->bus, this->ike_sa, FALSE); return DESTROY_ME; } - message->destroy(message); + this->initiating.seqnr++; if (expect_response) { + message->destroy(message); return retransmit(this, this->initiating.seqnr); } - charon->sender->send(charon->sender, - this->initiating.packet->clone(this->initiating.packet)); - this->initiating.packet->destroy(this->initiating.packet); - this->initiating.packet = NULL; + if (message->get_exchange_type(message) == QUICK_MODE) + { /* keep the packet for retransmission in quick mode. The responder + * might request a retransmission */ + charon->sender->send(charon->sender, + this->initiating.packet->clone(this->initiating.packet)); + } + else + { + charon->sender->send(charon->sender, this->initiating.packet); + this->initiating.packet = NULL; + } + message->destroy(message); if (exchange == INFORMATIONAL_V1) { @@ -502,14 +551,6 @@ METHOD(task_manager_t, initiate, status_t, return initiate(this); } -/** - * handle exchange collisions - */ -static bool handle_collisions(private_task_manager_t *this, task_t *task) -{ - return FALSE; -} - /** * build a response depending on the "passive" task list */ @@ -519,7 +560,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) task_t *task; message_t *message; host_t *me, *other; - bool delete = FALSE, flushed = FALSE; + bool delete = FALSE, flushed = FALSE, expect_request = FALSE; status_t status; me = request->get_destination(request); @@ -533,6 +574,10 @@ static status_t build_response(private_task_manager_t *this, message_t *request) message->set_message_id(message, request->get_message_id(request)); message->set_request(message, FALSE); + this->responding.mid = request->get_message_id(request); + this->responding.retransmitted = 0; + this->responding.seqnr++; + enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); while (enumerator->enumerate(enumerator, (void*)&task)) { @@ -541,17 +586,14 @@ static status_t build_response(private_task_manager_t *this, message_t *request) case SUCCESS: /* task completed, remove it */ this->passive_tasks->remove_at(this->passive_tasks, enumerator); - if (!handle_collisions(this, task)) - { - task->destroy(task); - } + task->destroy(task); continue; case NEED_MORE: /* processed, but task needs another exchange */ - if (handle_collisions(this, task)) - { - this->passive_tasks->remove_at(this->passive_tasks, - enumerator); + if (task->get_type(task) == TASK_QUICK_MODE) + { /* we rely on initiator retransmission, except for + * three-message exchanges */ + expect_request = TRUE; } continue; case ALREADY_DONE: @@ -587,8 +629,12 @@ static status_t build_response(private_task_manager_t *this, message_t *request) return DESTROY_ME; } + if (expect_request && !delete) + { + return retransmit(this, this->responding.seqnr); + } charon->sender->send(charon->sender, - this->responding.packet->clone(this->responding.packet)); + this->responding.packet->clone(this->responding.packet)); if (delete) { return DESTROY_ME; @@ -895,6 +941,16 @@ METHOD(task_manager_t, process_message, status_t, { if (this->initiating.old_hashes[i] == hash) { + if (this->initiating.packet && + i == (this->initiating.old_hash_pos % MAX_OLD_HASHES) && + msg->get_exchange_type(msg) == QUICK_MODE) + { + DBG1(DBG_IKE, "received retransmit of response with ID %u, " + "resending last request", mid); + charon->sender->send(charon->sender, + this->initiating.packet->clone(this->initiating.packet)); + return SUCCESS; + } DBG1(DBG_IKE, "received retransmit of response with ID %u, " "but next request already sent", mid); return SUCCESS; @@ -921,7 +977,7 @@ METHOD(task_manager_t, process_message, status_t, flush(this); return DESTROY_ME; } - this->initiating.old_hashes[(this->initiating.old_hash_pos++) % + this->initiating.old_hashes[(++this->initiating.old_hash_pos) % MAX_OLD_HASHES] = hash; } else @@ -975,6 +1031,7 @@ METHOD(task_manager_t, process_message, status_t, ike_sa_id_t *ike_sa_id; ike_cfg_t *ike_cfg; job_t *job; + ike_cfg = charon->backends->get_ike_cfg(charon->backends, me, other); if (ike_cfg == NULL) { @@ -1160,6 +1217,8 @@ METHOD(task_manager_t, reset, void, DESTROY_IF(this->responding.packet); DESTROY_IF(this->initiating.packet); this->responding.packet = NULL; + this->responding.seqnr = RESPONDING_SEQ; + this->responding.retransmitted = 0; this->initiating.packet = NULL; this->initiating.mid = 0; this->initiating.seqnr = 0; @@ -1248,6 +1307,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) }, .ike_sa = ike_sa, .initiating.type = EXCHANGE_TYPE_UNDEFINED, + .responding.seqnr = RESPONDING_SEQ, .rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK), .queued_tasks = linked_list_create(), .active_tasks = linked_list_create(), From 5f1df0a060e25f189f8856331d6bf3ce4ac83b73 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 22 Dec 2011 13:26:38 +0100 Subject: [PATCH 411/534] Double check that we could select a TS as quick mode responder --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 94e5bb85a..017ce97d4 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -699,10 +699,10 @@ METHOD(task_t, process_r, status_t, } tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); - if (!this->config) + if (!this->config || !this->tsi || !this->tsr) { - DBG1(DBG_IKE, "no child config found"); - return send_notify(this, NO_PROPOSAL_CHOSEN); + DBG1(DBG_IKE, "no matching CHILD_SA config found"); + return send_notify(this, INVALID_ID_INFORMATION); } sa_payload = (sa_payload_t*)message->get_payload(message, From 14dc7941656d85dc53e9da2bc3a7c3440d904f0e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 2 Jan 2012 13:36:10 +0100 Subject: [PATCH 412/534] Support installing of quick mode SAs with a specific reqid --- src/libcharon/sa/ikev1/task_manager_v1.c | 7 ++++++- src/libcharon/sa/ikev1/tasks/quick_mode.c | 16 ++++++++++++++-- src/libcharon/sa/ikev1/tasks/quick_mode.h | 7 +++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 371cdf721..f388bc835 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1158,7 +1158,12 @@ METHOD(task_manager_t, queue_child, void, private_task_manager_t *this, child_cfg_t *cfg, u_int32_t reqid, traffic_selector_t *tsi, traffic_selector_t *tsr) { - queue_task(this, (task_t*)quick_mode_create(this->ike_sa, cfg, tsi, tsr)); + quick_mode_t *task; + + task = quick_mode_create(this->ike_sa, cfg, tsi, tsr); + task->use_reqid(task, reqid); + + queue_task(this, &task->task); } METHOD(task_manager_t, queue_child_rekey, void, diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 017ce97d4..b9acdb054 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -114,6 +114,11 @@ struct private_quick_mode_t { */ u_int64_t lifebytes; + /** + * Reqid to use, 0 for auto-allocate + */ + u_int32_t reqid; + /** states of quick mode */ enum { QM_INIT, @@ -552,7 +557,7 @@ METHOD(task_t, build_i, status_t, this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), - this->config, 0, udp); + this->config, this->reqid, udp); list = this->config->get_proposals(this->config, FALSE); @@ -753,7 +758,7 @@ METHOD(task_t, process_r, status_t, this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), - this->config, 0, udp); + this->config, this->reqid, udp); return NEED_MORE; } case QM_NEGOTIATED: @@ -888,6 +893,12 @@ METHOD(task_t, get_type, task_type_t, return TASK_QUICK_MODE; } +METHOD(quick_mode_t, use_reqid, void, + private_quick_mode_t *this, u_int32_t reqid) +{ + this->reqid = reqid; +} + METHOD(task_t, migrate, void, private_quick_mode_t *this, ike_sa_t *ike_sa) { @@ -946,6 +957,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, .migrate = _migrate, .destroy = _destroy, }, + .use_reqid = _use_reqid, }, .ike_sa = ike_sa, .initiator = config != NULL, diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.h b/src/libcharon/sa/ikev1/tasks/quick_mode.h index 82790c768..88fbe4935 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.h +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.h @@ -36,6 +36,13 @@ struct quick_mode_t { * Implements the task_t interface */ task_t task; + + /** + * Use a specific reqid to install this CHILD_SA. + * + * @param reqid reqid to use + */ + void (*use_reqid)(quick_mode_t *this, u_int32_t reqid); }; /** From 634ac410a2f8cb9d12a704fdf6c37bdbd2e3fa67 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 2 Jan 2012 14:26:32 +0100 Subject: [PATCH 413/534] Don't return FAILED if a CHILD_SA to delete could not be found --- src/libcharon/sa/ikev1/tasks/quick_delete.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c index a5f27c5e0..bb7d20bdc 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_delete.c +++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c @@ -114,7 +114,7 @@ METHOD(task_t, build_i, status_t, return SUCCESS; } - return FAILED; + return ALREADY_DONE; } METHOD(task_t, process_i, status_t, From 23eb447c9ab518e47f653fa67e80ba60fee6e9bc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 2 Jan 2012 14:27:10 +0100 Subject: [PATCH 414/534] Implemented CHILD_SA rekeying --- src/libcharon/sa/ikev1/task_manager_v1.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index f388bc835..ea4cb8a1b 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1169,7 +1169,24 @@ METHOD(task_manager_t, queue_child, void, METHOD(task_manager_t, queue_child_rekey, void, private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) { - /* TODO-IKEv1: CHILD rekeying */ + child_sa_t *child_sa; + child_cfg_t *cfg; + quick_mode_t *task; + + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE); + if (!child_sa) + { + child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, FALSE); + } + if (child_sa && child_sa->get_state(child_sa) == CHILD_INSTALLED) + { + child_sa->set_state(child_sa, CHILD_REKEYING); + cfg = child_sa->get_config(child_sa); + task = quick_mode_create(this->ike_sa, cfg->get_ref(cfg), NULL, NULL); + task->use_reqid(task, child_sa->get_reqid(child_sa)); + + queue_task(this, &task->task); + } } METHOD(task_manager_t, queue_child_delete, void, From 07202a2bf1b4caf3ceabe016128c890ec27ccb91 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 2 Jan 2012 15:39:16 +0100 Subject: [PATCH 415/534] Be less verbose when deleting SAs triggered by a hard expire --- .../kernel_netlink/kernel_netlink_ipsec.c | 41 +++++++++---------- .../kernel_netlink/kernel_netlink_shared.c | 5 +++ 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c index e51aeaf65..49f5c3378 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -1737,30 +1737,27 @@ METHOD(kernel_ipsec_t, del_sa, status_t, mrk->m = mark.mask; } - if (this->socket_xfrm->send_ack(this->socket_xfrm, hdr) != SUCCESS) + switch (this->socket_xfrm->send_ack(this->socket_xfrm, hdr)) { - if (mark.value) - { - DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x " - "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask); - } - else - { - DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", - ntohl(spi)); - } - return FAILED; + case SUCCESS: + DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x (mark %u/0x%08x)", + ntohl(spi), mark.value, mark.mask); + return SUCCESS; + case NOT_FOUND: + return NOT_FOUND; + default: + if (mark.value) + { + DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x " + "(mark %u/0x%8x)", ntohl(spi), mark.value, mark.mask); + } + else + { + DBG1(DBG_KNL, "unable to delete SAD entry with SPI %.8x", + ntohl(spi)); + } + return FAILED; } - if (mark.value) - { - DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x (mark %u/0x%8x)", - ntohl(spi), mark.value, mark.mask); - } - else - { - DBG2(DBG_KNL, "deleted SAD entry with SPI %.8x", ntohl(spi)); - } - return SUCCESS; } METHOD(kernel_ipsec_t, update_sa, status_t, diff --git a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c index dad3fb68e..285f6c8b2 100644 --- a/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c +++ b/src/libhydra/plugins/kernel_netlink/kernel_netlink_shared.c @@ -206,6 +206,11 @@ METHOD(netlink_socket_t, netlink_send_ack, status_t, free(out); return ALREADY_DONE; } + if (-err->error == ESRCH) + { /* do not report missing entries */ + free(out); + return NOT_FOUND; + } DBG1(DBG_KNL, "received netlink error: %s (%d)", strerror(-err->error), -err->error); free(out); From 3a925f74ab3cc43bafa409b89feaa32caeb33364 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 2 Jan 2012 15:40:31 +0100 Subject: [PATCH 416/534] Do not query CHILD_SA during delete if they already expired --- src/libcharon/control/controller.c | 2 +- src/libcharon/kernel/kernel_handler.c | 2 +- src/libcharon/plugins/ha/ha_cache.c | 3 +- .../processing/jobs/delete_child_sa_job.c | 11 ++++-- .../processing/jobs/delete_child_sa_job.h | 4 +- .../processing/jobs/inactivity_job.c | 2 +- src/libcharon/sa/ike_sa.c | 5 ++- src/libcharon/sa/ike_sa.h | 4 +- src/libcharon/sa/ikev1/task_manager_v1.c | 7 ++-- src/libcharon/sa/ikev1/tasks/informational.c | 2 +- src/libcharon/sa/ikev1/tasks/quick_delete.c | 39 ++++++++++++++----- src/libcharon/sa/ikev1/tasks/quick_delete.h | 3 +- src/libcharon/sa/ikev1/tasks/quick_mode.c | 2 +- src/libcharon/sa/ikev2/task_manager_v2.c | 8 ++-- src/libcharon/sa/ikev2/tasks/child_delete.c | 39 ++++++++++++++----- src/libcharon/sa/ikev2/tasks/child_delete.h | 3 +- src/libcharon/sa/ikev2/tasks/child_rekey.c | 2 +- src/libcharon/sa/task_manager.h | 3 +- 18 files changed, 97 insertions(+), 44 deletions(-) diff --git a/src/libcharon/control/controller.c b/src/libcharon/control/controller.c index 4aded8f9d..11f40388f 100644 --- a/src/libcharon/control/controller.c +++ b/src/libcharon/control/controller.c @@ -368,7 +368,7 @@ METHOD(job_t, terminate_child_execute, void, charon->bus->set_sa(charon->bus, ike_sa); if (ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)) != DESTROY_ME) + child_sa->get_spi(child_sa, TRUE), FALSE) != DESTROY_ME) { charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); listener->status = SUCCESS; diff --git a/src/libcharon/kernel/kernel_handler.c b/src/libcharon/kernel/kernel_handler.c index 51fccb1ac..aa5c4e059 100644 --- a/src/libcharon/kernel/kernel_handler.c +++ b/src/libcharon/kernel/kernel_handler.c @@ -84,7 +84,7 @@ METHOD(kernel_listener_t, expire, bool, protocol_id_names, proto, ntohl(spi), reqid); if (hard) { - job = (job_t*)delete_child_sa_job_create(reqid, proto, spi); + job = (job_t*)delete_child_sa_job_create(reqid, proto, spi, hard); } else { diff --git a/src/libcharon/plugins/ha/ha_cache.c b/src/libcharon/plugins/ha/ha_cache.c index 970a8a2b9..7b7a953e5 100644 --- a/src/libcharon/plugins/ha/ha_cache.c +++ b/src/libcharon/plugins/ha/ha_cache.c @@ -212,7 +212,8 @@ static status_t rekey_children(ike_sa_t *ike_sa) DBG1(DBG_CFG, "resyncing CHILD_SA using a delete"); status = ike_sa->delete_child_sa(ike_sa, child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE)); + child_sa->get_spi(child_sa, TRUE), + FALSE); } else { diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.c b/src/libcharon/processing/jobs/delete_child_sa_job.c index bd8bb9562..ac1dfd663 100644 --- a/src/libcharon/processing/jobs/delete_child_sa_job.c +++ b/src/libcharon/processing/jobs/delete_child_sa_job.c @@ -44,6 +44,11 @@ struct private_delete_child_sa_job_t { * inbound SPI of the CHILD_SA */ u_int32_t spi; + + /** + * Delete for an expired CHILD_SA + */ + bool expired; }; METHOD(job_t, destroy, void, @@ -66,7 +71,7 @@ METHOD(job_t, execute, void, } else { - ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi); + ike_sa->delete_child_sa(ike_sa, this->protocol, this->spi, this->expired); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } @@ -83,8 +88,7 @@ METHOD(job_t, get_priority, job_priority_t, * Described in header */ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, - protocol_id_t protocol, - u_int32_t spi) + protocol_id_t protocol, u_int32_t spi, bool expired) { private_delete_child_sa_job_t *this; @@ -99,6 +103,7 @@ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, .reqid = reqid, .protocol = protocol, .spi = spi, + .expired = expired, ); return &this->public; diff --git a/src/libcharon/processing/jobs/delete_child_sa_job.h b/src/libcharon/processing/jobs/delete_child_sa_job.h index fc0e2b518..be6d578bc 100644 --- a/src/libcharon/processing/jobs/delete_child_sa_job.h +++ b/src/libcharon/processing/jobs/delete_child_sa_job.h @@ -50,10 +50,10 @@ struct delete_child_sa_job_t { * @param reqid reqid of the CHILD_SA, as used in kernel * @param protocol protocol of the CHILD_SA * @param spi security parameter index of the CHILD_SA + * @param expired TRUE if CHILD_SA already expired * @return delete_child_sa_job_t object */ delete_child_sa_job_t *delete_child_sa_job_create(u_int32_t reqid, - protocol_id_t protocol, - u_int32_t spi); + protocol_id_t protocol, u_int32_t spi, bool expired); #endif /** DELETE_CHILD_SA_JOB_H_ @}*/ diff --git a/src/libcharon/processing/jobs/inactivity_job.c b/src/libcharon/processing/jobs/inactivity_job.c index 251b9ab03..55fc0093a 100644 --- a/src/libcharon/processing/jobs/inactivity_job.c +++ b/src/libcharon/processing/jobs/inactivity_job.c @@ -108,7 +108,7 @@ METHOD(job_t, execute, void, { DBG1(DBG_JOB, "deleting CHILD_SA after %d seconds " "of inactivity", this->timeout); - status = ike_sa->delete_child_sa(ike_sa, proto, delete); + status = ike_sa->delete_child_sa(ike_sa, proto, delete, FALSE); } } if (status == DESTROY_ME) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 442eb7208..e5b2f8f66 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1256,9 +1256,10 @@ METHOD(ike_sa_t, rekey_child_sa, status_t, } METHOD(ike_sa_t, delete_child_sa, status_t, - private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) + private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi, bool expired) { - this->task_manager->queue_child_delete(this->task_manager, protocol, spi); + this->task_manager->queue_child_delete(this->task_manager, + protocol, spi, expired); return this->task_manager->initiate(this->task_manager); } diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index e50356451..c5bf60b5d 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -845,11 +845,13 @@ struct ike_sa_t { * * @param protocol protocol of the SA * @param spi inbound SPI of the CHILD_SA + * @param expired TRUE if CHILD_SA is expired * @return * - NOT_FOUND, if IKE_SA has no such CHILD_SA * - SUCCESS, if delete message sent */ - status_t (*delete_child_sa) (ike_sa_t *this, protocol_id_t protocol, u_int32_t spi); + status_t (*delete_child_sa)(ike_sa_t *this, protocol_id_t protocol, + u_int32_t spi, bool expired); /** * Destroy a CHILD SA with the specified protocol/SPI. diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index ea4cb8a1b..3a6cf5163 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1141,7 +1141,7 @@ METHOD(task_manager_t, queue_ike_delete, void, { queue_task(this, (task_t*) quick_delete_create(this->ike_sa, child_sa->get_protocol(child_sa), - child_sa->get_spi(child_sa, TRUE), FALSE)); + child_sa->get_spi(child_sa, TRUE), FALSE, FALSE)); } enumerator->destroy(enumerator); @@ -1190,10 +1190,11 @@ METHOD(task_manager_t, queue_child_rekey, void, } METHOD(task_manager_t, queue_child_delete, void, - private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi, + bool expired) { queue_task(this, (task_t*)quick_delete_create(this->ike_sa, protocol, - spi, FALSE)); + spi, FALSE, expired)); } METHOD(task_manager_t, queue_dpd, void, diff --git a/src/libcharon/sa/ikev1/tasks/informational.c b/src/libcharon/sa/ikev1/tasks/informational.c index 9de5c2e71..999b497dc 100644 --- a/src/libcharon/sa/ikev1/tasks/informational.c +++ b/src/libcharon/sa/ikev1/tasks/informational.c @@ -108,7 +108,7 @@ METHOD(task_t, process_r, status_t, else { this->del = (task_t*)quick_delete_create(this->ike_sa, - PROTO_NONE, 0, FALSE); + PROTO_NONE, 0, FALSE, FALSE); } } break; diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c index bb7d20bdc..9a502f58c 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_delete.c +++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c @@ -54,6 +54,11 @@ struct private_quick_delete_t { * Send delete even if SA does not exist */ bool force; + + /** + * SA already expired? + */ + bool expired; }; /** @@ -78,16 +83,29 @@ static bool delete_child(private_quick_delete_t *this, child_sa->set_state(child_sa, CHILD_DELETING); - child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in); - child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out); + if (this->expired) + { + DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), + ntohl(child_sa->get_spi(child_sa, FALSE)), + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } + else + { + child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in); + child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out); - DBG0(DBG_IKE, "closing CHILD_SA %s{%d} " - "with SPIs %.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R", - child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), - ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, - ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); + DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs " + "%.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, + ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } charon->bus->child_updown(charon->bus, child_sa, FALSE); @@ -190,7 +208,7 @@ METHOD(task_t, destroy, void, * Described in header. */ quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi, bool force) + u_int32_t spi, bool force, bool expired) { private_quick_delete_t *this; @@ -206,6 +224,7 @@ quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, .protocol = protocol, .spi = spi, .force = force, + .expired = expired, ); if (protocol != PROTO_NONE) diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.h b/src/libcharon/sa/ikev1/tasks/quick_delete.h index 1cdf07c48..864262392 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_delete.h +++ b/src/libcharon/sa/ikev1/tasks/quick_delete.h @@ -46,9 +46,10 @@ struct quick_delete_t { * @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder * @param spi inbound SPI of CHILD_SA to delete * @param force send delete even if SA does not exist + * @param expired TRUE if SA already expired * @return quick_delete task to handle by the task_manager */ quick_delete_t *quick_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi, bool force); + u_int32_t spi, bool force, bool expired); #endif /** QUICK_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index b9acdb054..dc0a01099 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -773,7 +773,7 @@ METHOD(task_t, process_r, status_t, this->ike_sa->queue_task(this->ike_sa, (task_t*)quick_delete_create(this->ike_sa, this->proposal->get_protocol(this->proposal), - this->spi_i, TRUE)); + this->spi_i, TRUE, TRUE)); return ALREADY_DONE; } return SUCCESS; diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 23ef054fb..36252a81d 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -825,7 +825,7 @@ static status_t process_request(private_task_manager_t *this, else { task = (task_t*)child_delete_create(this->ike_sa, - PROTO_NONE, 0); + PROTO_NONE, 0, FALSE); } break; } @@ -1308,9 +1308,11 @@ METHOD(task_manager_t, queue_child_rekey, void, } METHOD(task_manager_t, queue_child_delete, void, - private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi) + private_task_manager_t *this, protocol_id_t protocol, u_int32_t spi, + bool expired) { - queue_task(this, (task_t*)child_delete_create(this->ike_sa, protocol, spi)); + queue_task(this, (task_t*)child_delete_create(this->ike_sa, + protocol, spi, expired)); } METHOD(task_manager_t, queue_dpd, void, diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.c b/src/libcharon/sa/ikev2/tasks/child_delete.c index c5151abf1..644af782c 100644 --- a/src/libcharon/sa/ikev2/tasks/child_delete.c +++ b/src/libcharon/sa/ikev2/tasks/child_delete.c @@ -61,6 +61,11 @@ struct private_child_delete_t { */ bool rekeyed; + /** + * CHILD_SA already expired? + */ + bool expired; + /** * CHILD_SAs which get deleted */ @@ -247,16 +252,29 @@ static void log_children(private_child_delete_t *this) enumerator = this->child_sas->create_enumerator(this->child_sas); while (enumerator->enumerate(enumerator, (void**)&child_sa)) { - child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in); - child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out); + if (this->expired) + { + DBG0(DBG_IKE, "closing expired CHILD_SA %s{%d} " + "with SPIs %.8x_i %.8x_o and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), + ntohl(child_sa->get_spi(child_sa, FALSE)), + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } + else + { + child_sa->get_usestats(child_sa, TRUE, NULL, &bytes_in); + child_sa->get_usestats(child_sa, FALSE, NULL, &bytes_out); - DBG0(DBG_IKE, "closing CHILD_SA %s{%d} " - "with SPIs %.8x_i (%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R", - child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), - ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, - ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, - child_sa->get_traffic_selectors(child_sa, TRUE), - child_sa->get_traffic_selectors(child_sa, FALSE)); + DBG0(DBG_IKE, "closing CHILD_SA %s{%d} with SPIs %.8x_i " + "(%llu bytes) %.8x_o (%llu bytes) and TS %#R=== %#R", + child_sa->get_name(child_sa), child_sa->get_reqid(child_sa), + ntohl(child_sa->get_spi(child_sa, TRUE)), bytes_in, + ntohl(child_sa->get_spi(child_sa, FALSE)), bytes_out, + child_sa->get_traffic_selectors(child_sa, TRUE), + child_sa->get_traffic_selectors(child_sa, FALSE)); + } } enumerator->destroy(enumerator); } @@ -356,7 +374,7 @@ METHOD(task_t, destroy, void, * Described in header. */ child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi) + u_int32_t spi, bool expired) { private_child_delete_t *this; @@ -373,6 +391,7 @@ child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, .child_sas = linked_list_create(), .protocol = protocol, .spi = spi, + .expired = expired, ); if (protocol != PROTO_NONE) diff --git a/src/libcharon/sa/ikev2/tasks/child_delete.h b/src/libcharon/sa/ikev2/tasks/child_delete.h index 34d399ce3..4c8b3498a 100644 --- a/src/libcharon/sa/ikev2/tasks/child_delete.h +++ b/src/libcharon/sa/ikev2/tasks/child_delete.h @@ -52,9 +52,10 @@ struct child_delete_t { * @param ike_sa IKE_SA this task works for * @param protocol protocol of CHILD_SA to delete, PROTO_NONE as responder * @param spi inbound SPI of CHILD_SA to delete + * @param expired TRUE if CHILD_SA already expired * @return child_delete task to handle by the task_manager */ child_delete_t *child_delete_create(ike_sa_t *ike_sa, protocol_id_t protocol, - u_int32_t spi); + u_int32_t spi, bool expired); #endif /** CHILD_DELETE_H_ @}*/ diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c index 50a8aad95..28de072c0 100644 --- a/src/libcharon/sa/ikev2/tasks/child_rekey.c +++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c @@ -352,7 +352,7 @@ METHOD(task_t, process_i, status_t, protocol = to_delete->get_protocol(to_delete); /* rekeying done, delete the obsolete CHILD_SA using a subtask */ - this->child_delete = child_delete_create(this->ike_sa, protocol, spi); + this->child_delete = child_delete_create(this->ike_sa, protocol, spi, FALSE); this->public.task.build = (status_t(*)(task_t*,message_t*))build_i_delete; this->public.task.process = (status_t(*)(task_t*,message_t*))process_i_delete; diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index 5602069b1..b49c9a96b 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -177,9 +177,10 @@ struct task_manager_t { * * @param protocol CHILD_SA protocol, AH|ESP * @param spi CHILD_SA SPI to rekey + * @param expired TRUE if SA already expired */ void (*queue_child_delete)(task_manager_t *this, protocol_id_t protocol, - u_int32_t spi); + u_int32_t spi, bool expired); /** * Queue liveness checking tasks. From 31bd5c8c0e3a913fec42b775acd250147cd5fca8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 2 Jan 2012 15:49:20 +0100 Subject: [PATCH 417/534] Reply quick mode with the same SA lifetime that we received --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index dc0a01099..ff52204a9 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -510,15 +510,15 @@ static void apply_lifetimes(private_quick_mode_t *this, sa_payload_t *sa_payload lifebytes = sa_payload->get_lifebytes(sa_payload); if (this->lifetime != lifetime) { - DBG1(DBG_IKE, "received %us lifetime, configured %us, using lower", + DBG1(DBG_IKE, "received %us lifetime, configured %us", lifetime, this->lifetime); - this->lifetime = min(this->lifetime, lifetime); + this->lifetime = lifetime; } if (this->lifebytes != lifebytes) { - DBG1(DBG_IKE, "received %llu lifebytes, configured %llu, using lower", + DBG1(DBG_IKE, "received %llu lifebytes, configured %llu", lifebytes, this->lifebytes); - this->lifebytes = min(this->lifebytes, lifebytes); + this->lifebytes = lifebytes; } } From f56c3c53f605f7ae807a92651d7ced6d21ce8023 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 2 Jan 2012 16:36:39 +0100 Subject: [PATCH 418/534] As responder, try to reuse the reqid of the CHILD_SA the initiator is rekeying --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index ff52204a9..0e8eea95a 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -661,6 +661,42 @@ static bool has_notify_errors(private_quick_mode_t *this, message_t *message) return err; } +/** + * Check if this is a rekey for an existing CHILD_SA, reuse reqid if so + */ +static void check_for_rekeyed_child(private_quick_mode_t *this) +{ + enumerator_t *enumerator, *policies; + traffic_selector_t *local, *remote; + child_sa_t *child_sa; + + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (this->reqid == 0 && enumerator->enumerate(enumerator, &child_sa)) + { + if (child_sa->get_state(child_sa) == CHILD_INSTALLED && + streq(child_sa->get_name(child_sa), + this->config->get_name(this->config))) + { + policies = child_sa->create_policy_enumerator(child_sa); + if (policies->enumerate(policies, &local, &remote)) + { + if (local->equals(local, this->tsr) && + remote->equals(remote, this->tsi) && + this->proposal->equals(this->proposal, + child_sa->get_proposal(child_sa))) + { + this->reqid = child_sa->get_reqid(child_sa); + child_sa->set_state(child_sa, CHILD_REKEYING); + DBG1(DBG_IKE, "detected rekeying of CHILD_SA %s{%u}", + child_sa->get_name(child_sa), this->reqid); + } + } + policies->destroy(policies); + } + } + enumerator->destroy(enumerator); +} + METHOD(task_t, process_r, status_t, private_quick_mode_t *this, message_t *message) { @@ -755,6 +791,8 @@ METHOD(task_t, process_r, status_t, } } + check_for_rekeyed_child(this); + this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), From 3d86d76b86841d681b5f8a2025efda7f17aa3bb3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 2 Jan 2012 16:38:30 +0100 Subject: [PATCH 419/534] Fixed create_shared_enumerator method description --- src/libstrongswan/credentials/credential_manager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstrongswan/credentials/credential_manager.h b/src/libstrongswan/credentials/credential_manager.h index 8a774f6f3..4b9f914c4 100644 --- a/src/libstrongswan/credentials/credential_manager.h +++ b/src/libstrongswan/credentials/credential_manager.h @@ -89,7 +89,7 @@ struct credential_manager_t { * @param type kind of requested shared key * @param first first subject between key is shared * @param second second subject between key is shared - * @return enumerator over shared keys + * @return enumerator over (shared_key_t*,id_match_t,id_match_t) */ enumerator_t *(*create_shared_enumerator)(credential_manager_t *this, shared_key_type_t type, From 462c9a4f72ec94ae993863341502d78a411f4e71 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 2 Jan 2012 16:38:47 +0100 Subject: [PATCH 420/534] Try all matching XAuth secrets we find, not only the first one --- .../plugins/xauth_generic/xauth_generic.c | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/src/libcharon/plugins/xauth_generic/xauth_generic.c b/src/libcharon/plugins/xauth_generic/xauth_generic.c index 6350a130f..907de4322 100644 --- a/src/libcharon/plugins/xauth_generic/xauth_generic.c +++ b/src/libcharon/plugins/xauth_generic/xauth_generic.c @@ -100,7 +100,8 @@ METHOD(xauth_method_t, process_server, status_t, shared_key_t *shared; identification_t *id; chunk_t user = chunk_empty, pass = chunk_empty; - status_t status = SUCCESS; + status_t status = FAILED; + int tried = 0; enumerator = in->create_attribute_enumerator(in); while (enumerator->enumerate(enumerator, &attr)) @@ -136,20 +137,31 @@ METHOD(xauth_method_t, process_server, status_t, this->peer = id; } - shared = lib->credmgr->get_shared(lib->credmgr, SHARED_EAP, - this->server, this->peer); - if (!shared) + enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr, + SHARED_EAP, this->server, this->peer); + while (enumerator->enumerate(enumerator, &shared, NULL, NULL)) { - DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'", - this->server, this->peer); - status = FAILED; + if (chunk_equals(shared->get_key(shared), pass)) + { + status = SUCCESS; + break; + } + tried++; } - else if (!chunk_equals(shared->get_key(shared), pass)) + enumerator->destroy(enumerator); + if (status != SUCCESS) { - DBG1(DBG_IKE, "failed to authenticate '%Y' with XAuth", this->peer); - status = FAILED; + if (!tried) + { + DBG1(DBG_IKE, "no XAuth secret found for '%Y' - '%Y'", + this->server, this->peer); + } + else + { + DBG1(DBG_IKE, "none of %d found XAuth secrets for '%Y' - '%Y' " + "matched", tried, this->server, this->peer); + } } - DESTROY_IF(shared); return status; } From e32820f5935806bc2a06f90cfb77923de3a72323 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 29 Dec 2011 00:05:04 +0100 Subject: [PATCH 421/534] Add functions to set mode cfg identifier --- src/libcharon/encoding/payloads/cp_payload.c | 13 +++++++++++++ src/libcharon/encoding/payloads/cp_payload.h | 14 ++++++++++++++ 2 files changed, 27 insertions(+) mode change 100644 => 100755 src/libcharon/encoding/payloads/cp_payload.c mode change 100644 => 100755 src/libcharon/encoding/payloads/cp_payload.h diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c old mode 100644 new mode 100755 index c8cffa3f7..40f6ae48f --- a/src/libcharon/encoding/payloads/cp_payload.c +++ b/src/libcharon/encoding/payloads/cp_payload.c @@ -269,6 +269,17 @@ METHOD(cp_payload_t, get_config_type, config_type_t, return this->cfg_type; } +METHOD(cp_payload_t, get_identifier, u_int16_t, + private_cp_payload_t *this) +{ + return this->identifier; +} +METHOD(cp_payload_t, set_identifier, void, + private_cp_payload_t *this, u_int16_t identifier) +{ + this->identifier = identifier; +} + METHOD2(payload_t, cp_payload_t, destroy, void, private_cp_payload_t *this) { @@ -299,6 +310,8 @@ cp_payload_t *cp_payload_create_type(payload_type_t type, config_type_t cfg_type .create_attribute_enumerator = _create_attribute_enumerator, .add_attribute = _add_attribute, .get_type = _get_config_type, + .get_identifier = _get_identifier, + .set_identifier = _set_identifier, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, diff --git a/src/libcharon/encoding/payloads/cp_payload.h b/src/libcharon/encoding/payloads/cp_payload.h old mode 100644 new mode 100755 index 0e3cf53bc..5eb1e06a7 --- a/src/libcharon/encoding/payloads/cp_payload.h +++ b/src/libcharon/encoding/payloads/cp_payload.h @@ -77,6 +77,20 @@ struct cp_payload_t { */ config_type_t (*get_type) (cp_payload_t *this); + /** + * Set the configuration payload identifier (IKEv1 only). + * + @param identifier identifier to set + */ + void (*set_identifier) (cp_payload_t *this, u_int16_t identifier); + + /** + * Get the configuration payload identifier (IKEv1 only). + * + * @return identifier + */ + u_int16_t (*get_identifier) (cp_payload_t *this); + /** * Destroys an cp_payload_t object. */ From d71092ceed514b312b4bbd2a1b9e2300e256d1f7 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Thu, 29 Dec 2011 00:06:12 +0100 Subject: [PATCH 422/534] Setting Mode Cfg identifier for CFG_ACK messages. --- src/libcharon/sa/ikev1/tasks/xauth.c | 7 +++++++ 1 file changed, 7 insertions(+) mode change 100644 => 100755 src/libcharon/sa/ikev1/tasks/xauth.c diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c old mode 100644 new mode 100755 index f55299398..20d6d8a17 --- a/src/libcharon/sa/ikev1/tasks/xauth.c +++ b/src/libcharon/sa/ikev1/tasks/xauth.c @@ -64,6 +64,11 @@ struct private_xauth_t { */ cp_payload_t *cp; + /** + * received identifier + */ + u_int16_t identifier; + /** * status of Xauth exchange */ @@ -197,6 +202,7 @@ METHOD(task_t, build_r_ack, status_t, cp_payload_t *cp; cp = cp_payload_create_type(CONFIGURATION_V1, CFG_ACK); + cp->set_identifier(cp, this->identifier); cp->add_attribute(cp, configuration_attribute_create_chunk( CONFIGURATION_ATTRIBUTE_V1, XAUTH_STATUS, chunk_empty)); @@ -270,6 +276,7 @@ METHOD(task_t, process_r, status_t, this->xauth->get_identity(this->xauth)); } } + this->identifier = cp->get_identifier(cp); this->public.task.build = _build_r_ack; return NEED_MORE; } From 54773729a88196dfa394fa8ca4639318f99c43eb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 3 Jan 2012 11:57:35 +0100 Subject: [PATCH 423/534] Queue Mode Config tasks after main mode as initiator, not as responder --- src/libcharon/sa/ikev1/tasks/main_mode.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index cd790787f..a9486e839 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -950,12 +950,6 @@ METHOD(task_t, build_r, status_t, authenticator->destroy(authenticator); save_auth_cfg(this, TRUE); - if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) - { - this->ike_sa->queue_task(this->ike_sa, - (task_t*)mode_config_create(this->ike_sa, TRUE)); - } - switch (this->auth_method) { case AUTH_XAUTH_INIT_PSK: @@ -1072,6 +1066,12 @@ METHOD(task_t, process_i, status_t, } save_auth_cfg(this, FALSE); + if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE)); + } + switch (this->auth_method) { case AUTH_XAUTH_INIT_PSK: From 2da3ff7a5235cd86146a02e0a57f63a1a2b8e3e8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 3 Jan 2012 11:27:41 +0100 Subject: [PATCH 424/534] Set a condition flag if peer has been authenticated using XAuth --- src/libcharon/sa/ike_sa.h | 5 +++++ src/libcharon/sa/ikev1/tasks/xauth.c | 1 + 2 files changed, 6 insertions(+) diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index c5bf60b5d..b7c96fdfb 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -159,6 +159,11 @@ enum ike_condition_t { * Initial contact received */ COND_INIT_CONTACT_SEEN = (1<<8), + + /** + * Peer has been authenticated using XAuth + */ + COND_XAUTH_AUTHENTICATED = (1<<9), }; /** diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c index 20d6d8a17..7e7e84a8e 100755 --- a/src/libcharon/sa/ikev1/tasks/xauth.c +++ b/src/libcharon/sa/ikev1/tasks/xauth.c @@ -310,6 +310,7 @@ METHOD(task_t, process_i_status, status_t, return FAILED; } establish(this); + this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE); return SUCCESS; } From 7e9e1f96dff783123ed91073779c55223b109278 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 3 Jan 2012 11:28:45 +0100 Subject: [PATCH 425/534] Don't trigger reauthentication if initiator authenticated using XAuth --- src/libcharon/sa/ike_sa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index e5b2f8f66..c7a8a97f3 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1326,6 +1326,7 @@ METHOD(ike_sa_t, reauth, status_t, { DBG1(DBG_IKE, "initiator did not reauthenticate as requested"); if (this->other_virtual_ip != NULL || + has_condition(this, COND_XAUTH_AUTHENTICATED) || has_condition(this, COND_EAP_AUTHENTICATED) #ifdef ME /* as mediation server we too cannot reauth the IKE_SA */ From 9c64f214f17bda979468ae5f5664c8dec5e49610 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 3 Jan 2012 11:58:40 +0100 Subject: [PATCH 426/534] Support initiation of childless IKEv1 ISAKMP SAs --- src/libcharon/sa/ike_sa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index c7a8a97f3..73b4ba24b 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1066,7 +1066,7 @@ METHOD(ike_sa_t, initiate, status_t, #endif /* ME */ ) { - child_cfg->destroy(child_cfg); + DESTROY_IF(child_cfg); DBG1(DBG_IKE, "unable to initiate to %%any"); charon->bus->alert(charon->bus, ALERT_PEER_ADDR_FAILED); return DESTROY_ME; @@ -1090,6 +1090,7 @@ METHOD(ike_sa_t, initiate, status_t, } else #endif /* ME */ + if (child_cfg) { /* normal IKE_SA with CHILD_SA */ this->task_manager->queue_child(this->task_manager, child_cfg, reqid, From 17c64d5ff9bd2076883f4d5eea23923e61b857ff Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 3 Jan 2012 11:59:21 +0100 Subject: [PATCH 427/534] Establish IKE_SA only once as XAuth responder --- src/libcharon/sa/ikev1/tasks/xauth.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c index 7e7e84a8e..8d8744b3d 100755 --- a/src/libcharon/sa/ikev1/tasks/xauth.c +++ b/src/libcharon/sa/ikev1/tasks/xauth.c @@ -268,7 +268,6 @@ METHOD(task_t, process_r, status_t, { DBG1(DBG_IKE, "XAuth authentication of '%Y' (myself) successful", this->xauth->get_identity(this->xauth)); - establish(this); } else { From 4f49b06843038f933e69bf480ece37350f80b1fb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 3 Jan 2012 12:00:12 +0100 Subject: [PATCH 428/534] Initiate IKEv1 reauthentication, take over all children --- src/libcharon/sa/ikev1/task_manager_v1.c | 54 +++++++++++++++++++++--- 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 3a6cf5163..7dbfb5c23 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1118,16 +1118,56 @@ METHOD(task_manager_t, queue_ike, void, } } -METHOD(task_manager_t, queue_ike_rekey, void, - private_task_manager_t *this) -{ - /* TODO-IKEv1: IKE_SA rekeying */ -} - METHOD(task_manager_t, queue_ike_reauth, void, private_task_manager_t *this) { - /* TODO-IKEv1: IKE_SA reauth */ + enumerator_t *enumerator; + child_sa_t *child_sa; + ike_sa_t *new; + host_t *host; + + new = charon->ike_sa_manager->checkout_new(charon->ike_sa_manager, + this->ike_sa->get_version(this->ike_sa), TRUE); + if (!new) + { /* shouldn't happen */ + return; + } + + new->set_peer_cfg(new, this->ike_sa->get_peer_cfg(this->ike_sa)); + 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); + new->set_my_host(new, host->clone(host)); + host = this->ike_sa->get_virtual_ip(this->ike_sa, TRUE); + if (host) + { + new->set_virtual_ip(new, TRUE, host); + } + + enumerator = this->ike_sa->create_child_sa_enumerator(this->ike_sa); + while (enumerator->enumerate(enumerator, &child_sa)) + { + this->ike_sa->remove_child_sa(this->ike_sa, enumerator); + new->add_child_sa(new, child_sa); + } + enumerator->destroy(enumerator); + + if (new->initiate(new, NULL, 0, NULL, NULL) != DESTROY_ME) + { + charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); + } + else + { + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, new); + DBG1(DBG_IKE, "reauthenticating IKE_SA failed"); + } + charon->bus->set_sa(charon->bus, this->ike_sa); +} + +METHOD(task_manager_t, queue_ike_rekey, void, + private_task_manager_t *this) +{ + queue_ike_reauth(this); } METHOD(task_manager_t, queue_ike_delete, void, From c9d68d17f0a004e36b57fcf46f87d8254263deb5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 3 Jan 2012 13:33:18 +0100 Subject: [PATCH 429/534] Include peer config overtime in negotiated ISAKMP SA lifetime --- src/libcharon/sa/ikev1/tasks/main_mode.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index a9486e839..75f167b1d 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -548,6 +548,7 @@ METHOD(task_t, build_i, status_t, this->lifetime = this->peer_cfg->get_rekey_time(this->peer_cfg, FALSE); } + this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg); proposals = this->ike_cfg->get_proposals(this->ike_cfg); sa_payload = sa_payload_create_from_proposals_v1(proposals, this->lifetime, 0, this->auth_method, MODE_NONE, FALSE); @@ -1006,9 +1007,9 @@ METHOD(task_t, process_i, status_t, if (lifetime != this->lifetime) { DBG1(DBG_IKE, "received lifetime %us does not match configured " - "%us, using lower value", lifetime, this->lifetime); + "lifetime %us", lifetime, this->lifetime); } - this->lifetime = min(this->lifetime, lifetime); + this->lifetime = lifetime; auth_method = sa_payload->get_auth_method(sa_payload); if (auth_method != this->auth_method) { From 1b79299b8931d3f77a120c8444d8ac0d53d65cb0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 3 Jan 2012 14:47:44 +0100 Subject: [PATCH 430/534] Set ISAKMP SA state to rekeying after triggering reauthentication --- src/libcharon/sa/ikev1/task_manager_v1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 7dbfb5c23..364b6db38 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1155,6 +1155,7 @@ METHOD(task_manager_t, queue_ike_reauth, void, if (new->initiate(new, NULL, 0, NULL, NULL) != DESTROY_ME) { charon->ike_sa_manager->checkin(charon->ike_sa_manager, new); + this->ike_sa->set_state(this->ike_sa, IKE_REKEYING); } else { From beab4a90aef5aea018d2bb2159cae3dbfd760cee Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 4 Jan 2012 17:32:41 +0100 Subject: [PATCH 431/534] Query for XAuth identity in get_other_eap_id(), too --- src/libcharon/sa/ike_sa.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 73b4ba24b..d659a3c68 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1182,6 +1182,10 @@ METHOD(ike_sa_t, get_other_eap_id, identification_t*, /* prefer EAP-Identity of last round */ current = cfg->get(cfg, AUTH_RULE_EAP_IDENTITY); if (!current || current->get_type(current) == ID_ANY) + { + current = cfg->get(cfg, AUTH_RULE_XAUTH_IDENTITY); + } + if (!current || current->get_type(current) == ID_ANY) { current = cfg->get(cfg, AUTH_RULE_IDENTITY); } From cb1a145ce29e8ba39e73f8d314f788265498a66f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 3 Jan 2012 16:23:37 +0100 Subject: [PATCH 432/534] Added an IKE_SA manager method to enumerate IKE_SA IDs filtered by identities --- src/libcharon/sa/ike_sa_manager.c | 81 ++++++++++++++++++------------- src/libcharon/sa/ike_sa_manager.h | 12 +++++ 2 files changed, 59 insertions(+), 34 deletions(-) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 9ec0d34d8..2b4418f24 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -266,7 +266,7 @@ static bool connected_peers_match(connected_peers_t *connected_peers, { return my_id->equals(my_id, connected_peers->my_id) && other_id->equals(other_id, connected_peers->other_id) && - family == connected_peers->family; + (!family || family == connected_peers->family); } typedef struct segment_t segment_t; @@ -1444,29 +1444,23 @@ METHOD(ike_sa_manager_t, checkin_and_destroy, void, charon->bus->set_sa(charon->bus, NULL); } -METHOD(ike_sa_manager_t, check_uniqueness, bool, - private_ike_sa_manager_t *this, ike_sa_t *ike_sa, bool force_replace) +/** + * Cleanup function for create_id_enumerator + */ +static void id_enumerator_cleanup(linked_list_t *ids) { - bool cancel = FALSE; - peer_cfg_t *peer_cfg; - unique_policy_t policy; - linked_list_t *list, *duplicate_ids = NULL; - enumerator_t *enumerator; - ike_sa_id_t *duplicate_id = NULL; - identification_t *me, *other; + ids->destroy_offset(ids, offsetof(ike_sa_id_t, destroy)); +} + +METHOD(ike_sa_manager_t, create_id_enumerator, enumerator_t*, + private_ike_sa_manager_t *this, identification_t *me, + identification_t *other, int family) +{ + linked_list_t *list, *ids = NULL; + connected_peers_t *current; u_int row, segment; rwlock_t *lock; - peer_cfg = ike_sa->get_peer_cfg(ike_sa); - policy = peer_cfg->get_unique_policy(peer_cfg); - if (policy == UNIQUE_NO && !force_replace) - { - return FALSE; - } - - me = ike_sa->get_my_id(ike_sa); - other = ike_sa->get_other_id(ike_sa); - row = chunk_hash_inc(other->get_encoding(other), chunk_hash(me->get_encoding(me))) & this->table_mask; segment = row & this->segment_mask; @@ -1476,33 +1470,52 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool, list = this->connected_peers_table[row]; if (list) { - connected_peers_t *current; - host_t *other_host; - - other_host = ike_sa->get_other_host(ike_sa); if (list->find_first(list, (linked_list_match_t)connected_peers_match, - (void**)¤t, me, other, - (uintptr_t)other_host->get_family(other_host)) == SUCCESS) + (void**)¤t, me, other, (uintptr_t)family) == SUCCESS) { - /* clone the list, so we can release the lock */ - duplicate_ids = current->sas->clone_offset(current->sas, - offsetof(ike_sa_id_t, clone)); + ids = current->sas->clone_offset(current->sas, + offsetof(ike_sa_id_t, clone)); } } lock->unlock(lock); - if (!duplicate_ids) + if (!ids) + { + return enumerator_create_empty(); + } + return enumerator_create_cleaner(ids->create_enumerator(ids), + (void*)id_enumerator_cleanup, ids); +} + +METHOD(ike_sa_manager_t, check_uniqueness, bool, + private_ike_sa_manager_t *this, ike_sa_t *ike_sa, bool force_replace) +{ + bool cancel = FALSE; + peer_cfg_t *peer_cfg; + unique_policy_t policy; + enumerator_t *enumerator; + ike_sa_id_t *id = NULL; + identification_t *me, *other; + host_t *other_host; + + peer_cfg = ike_sa->get_peer_cfg(ike_sa); + policy = peer_cfg->get_unique_policy(peer_cfg); + if (policy == UNIQUE_NO && !force_replace) { return FALSE; } + me = ike_sa->get_my_id(ike_sa); + other = ike_sa->get_other_id(ike_sa); + other_host = ike_sa->get_other_host(ike_sa); - enumerator = duplicate_ids->create_enumerator(duplicate_ids); - while (enumerator->enumerate(enumerator, &duplicate_id)) + enumerator = create_id_enumerator(this, me, other, + other_host->get_family(other_host)); + while (enumerator->enumerate(enumerator, &id)) { status_t status = SUCCESS; ike_sa_t *duplicate; - duplicate = checkout(this, duplicate_id); + duplicate = checkout(this, id); if (!duplicate) { continue; @@ -1552,7 +1565,6 @@ METHOD(ike_sa_manager_t, check_uniqueness, bool, } } enumerator->destroy(enumerator); - duplicate_ids->destroy_offset(duplicate_ids, offsetof(ike_sa_id_t, destroy)); /* reset thread's current IKE_SA after checkin */ charon->bus->set_sa(charon->bus, ike_sa); return cancel; @@ -1789,6 +1801,7 @@ ike_sa_manager_t *ike_sa_manager_create() .check_uniqueness = _check_uniqueness, .has_contact = _has_contact, .create_enumerator = _create_enumerator, + .create_id_enumerator = _create_id_enumerator, .checkin = _checkin, .checkin_and_destroy = _checkin_and_destroy, .get_count = _get_count, diff --git a/src/libcharon/sa/ike_sa_manager.h b/src/libcharon/sa/ike_sa_manager.h index bf75b76bb..0f9a6d177 100644 --- a/src/libcharon/sa/ike_sa_manager.h +++ b/src/libcharon/sa/ike_sa_manager.h @@ -169,6 +169,18 @@ struct ike_sa_manager_t { */ enumerator_t *(*create_enumerator) (ike_sa_manager_t* this, bool wait); + /** + * Create an enumerator over ike_sa_id_t*, matching peer identities. + * + * @param me local peer identity to match + * @param other remote peer identity to match + * @param family address family to match, 0 for any + * @return enumerator over ike_sa_id_t* + */ + enumerator_t* (*create_id_enumerator)(ike_sa_manager_t *this, + identification_t *me, identification_t *other, + int family); + /** * Checkin the SA after usage. * From 3a0b67bce593c99d5ae0dd5e2920c6772843ad7a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 4 Jan 2012 17:50:19 +0100 Subject: [PATCH 433/534] Destroy IKE_SA after reauthentication initiatend and lifetime limit reached --- src/libcharon/sa/ike_sa.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index d659a3c68..1992a6017 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1296,8 +1296,13 @@ METHOD(ike_sa_t, delete_, status_t, { switch (this->state) { - case IKE_ESTABLISHED: case IKE_REKEYING: + if (this->version == IKEV1) + { /* SA has been reauthenticated, delete */ + break; + } + /* FALL */ + case IKE_ESTABLISHED: this->task_manager->queue_ike_delete(this->task_manager); return this->task_manager->initiate(this->task_manager); case IKE_CREATED: From b147679a2c1b3c232a13f8f58418b4976571b8da Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 4 Jan 2012 17:51:22 +0100 Subject: [PATCH 434/534] Try to detect reauthentication as responder and adopt children to new SA --- src/libcharon/Makefile.am | 3 +- .../processing/jobs/adopt_children_job.c | 175 ++++++++++++++++++ .../processing/jobs/adopt_children_job.h | 49 +++++ src/libcharon/sa/ikev1/tasks/main_mode.c | 4 + src/libcharon/sa/ikev1/tasks/xauth.c | 3 + 5 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 src/libcharon/processing/jobs/adopt_children_job.c create mode 100644 src/libcharon/processing/jobs/adopt_children_job.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 8db43f188..979b725c3 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -114,7 +114,8 @@ sa/ikev1/tasks/isakmp_delete.c sa/ikev1/tasks/isakmp_delete.h \ sa/ikev1/tasks/xauth.c sa/ikev1/tasks/xauth.h \ sa/ikev1/tasks/quick_mode.c sa/ikev1/tasks/quick_mode.h \ sa/ikev1/tasks/quick_delete.c sa/ikev1/tasks/quick_delete.h \ -sa/ikev1/tasks/mode_config.c sa/ikev1/tasks/mode_config.h +sa/ikev1/tasks/mode_config.c sa/ikev1/tasks/mode_config.h \ +processing/jobs/adopt_children_job.c processing/jobs/adopt_children_job.h endif diff --git a/src/libcharon/processing/jobs/adopt_children_job.c b/src/libcharon/processing/jobs/adopt_children_job.c new file mode 100644 index 000000000..6f7e119da --- /dev/null +++ b/src/libcharon/processing/jobs/adopt_children_job.c @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * 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 "adopt_children_job.h" + +#include +#include + +typedef struct private_adopt_children_job_t private_adopt_children_job_t; + +/** + * Private data of an adopt_children_job_t object. + */ +struct private_adopt_children_job_t { + + /** + * Public adopt_children_job_t interface. + */ + adopt_children_job_t public; + + /** + * IKE_SA id to adopt children from + */ + ike_sa_id_t *id; +}; + +METHOD(job_t, destroy, void, + private_adopt_children_job_t *this) +{ + this->id->destroy(this->id); + free(this); +} + +METHOD(job_t, execute, void, + private_adopt_children_job_t *this) +{ + identification_t *my_id, *other_id, *xauth; + host_t *me, *other; + peer_cfg_t *cfg; + linked_list_t *children; + enumerator_t *enumerator, *childenum; + ike_sa_id_t *id; + ike_sa_t *ike_sa; + child_sa_t *child_sa; + + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, this->id); + if (ike_sa) + { + /* get what we need from new SA */ + me = ike_sa->get_my_host(ike_sa); + me = me->clone(me); + other = ike_sa->get_other_host(ike_sa); + other = other->clone(other); + my_id = ike_sa->get_my_id(ike_sa); + my_id = my_id->clone(my_id); + other_id = ike_sa->get_other_id(ike_sa); + other_id = other_id->clone(other_id); + xauth = ike_sa->get_other_eap_id(ike_sa); + xauth = xauth->clone(xauth); + cfg = ike_sa->get_peer_cfg(ike_sa); + cfg->get_ref(cfg); + + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + + /* find old SA to adopt children from */ + children = linked_list_create(); + enumerator = charon->ike_sa_manager->create_id_enumerator( + charon->ike_sa_manager, my_id, other_id, + other->get_family(other)); + while (enumerator->enumerate(enumerator, &id)) + { + if (id->equals(id, this->id)) + { /* not from self */ + continue; + } + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id); + if (ike_sa) + { + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + me->equals(me, ike_sa->get_my_host(ike_sa)) && + other->equals(other, ike_sa->get_other_host(ike_sa)) && + xauth->equals(xauth, ike_sa->get_other_eap_id(ike_sa)) && + cfg->equals(cfg, ike_sa->get_peer_cfg(ike_sa))) + { + childenum = ike_sa->create_child_sa_enumerator(ike_sa); + while (childenum->enumerate(childenum, &child_sa)) + { + ike_sa->remove_child_sa(ike_sa, childenum); + children->insert_last(children, child_sa); + } + childenum->destroy(childenum); + DBG1(DBG_IKE, "detected reauth of existing IKE_SA, " + "adopting %d children", children->get_count(children)); + ike_sa->set_state(ike_sa, IKE_DELETING); + charon->ike_sa_manager->checkin_and_destroy( + charon->ike_sa_manager, ike_sa); + } + else + { + charon->ike_sa_manager->checkin( + charon->ike_sa_manager, ike_sa); + } + if (children->get_count(children)) + { + break; + } + } + } + enumerator->destroy(enumerator); + + me->destroy(me); + other->destroy(other); + my_id->destroy(my_id); + other_id->destroy(other_id); + xauth->destroy(xauth); + cfg->destroy(cfg); + + if (children->get_count(children)) + { + /* adopt children by new SA */ + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + this->id); + if (ike_sa) + { + while (children->remove_last(children, + (void**)&child_sa) == SUCCESS) + { + ike_sa->add_child_sa(ike_sa, child_sa); + } + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + } + children->destroy_offset(children, offsetof(child_sa_t, destroy)); + } + destroy(this); +} + +METHOD(job_t, get_priority, job_priority_t, + private_adopt_children_job_t *this) +{ + return JOB_PRIO_HIGH; +} + +/** + * See header + */ +adopt_children_job_t *adopt_children_job_create(ike_sa_id_t *id) +{ + private_adopt_children_job_t *this; + + INIT(this, + .public = { + .job_interface = { + .execute = _execute, + .get_priority = _get_priority, + .destroy = _destroy, + }, + }, + .id = id->clone(id), + ); + + return &this->public; +} diff --git a/src/libcharon/processing/jobs/adopt_children_job.h b/src/libcharon/processing/jobs/adopt_children_job.h new file mode 100644 index 000000000..073504abd --- /dev/null +++ b/src/libcharon/processing/jobs/adopt_children_job.h @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup adopt_children_job adopt_children_job + * @{ @ingroup cjobs + */ + +#ifndef ADOPT_CHILDREN_JOB_H_ +#define ADOPT_CHILDREN_JOB_H_ + +#include +#include +#include + +typedef struct adopt_children_job_t adopt_children_job_t; + +/** + * Job adopting children after IKEv1 reauthentication from old SA. + */ +struct adopt_children_job_t { + + /** + * Implements job_t. + */ + job_t job_interface; +}; + +/** + * Create a adopt_children_job instance. + * + * @param id ike_sa_id_t of old ISAKMP SA to adopt children from + * @return job + */ +adopt_children_job_t *adopt_children_job_create(ike_sa_id_t *id); + +#endif /** ADOPT_CHILDREN_JOB_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index 75f167b1d..3c0a2520e 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -32,6 +32,7 @@ #include #include #include +#include typedef struct private_main_mode_t private_main_mode_t; @@ -966,6 +967,9 @@ METHOD(task_t, build_r, status_t, return FAILED; default: establish(this); + lib->processor->queue_job(lib->processor, (job_t*) + adopt_children_job_create( + this->ike_sa->get_id(this->ike_sa))); return SUCCESS; } } diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c index 8d8744b3d..e836bed16 100755 --- a/src/libcharon/sa/ikev1/tasks/xauth.c +++ b/src/libcharon/sa/ikev1/tasks/xauth.c @@ -18,6 +18,7 @@ #include #include #include +#include typedef struct private_xauth_t private_xauth_t; @@ -212,6 +213,8 @@ METHOD(task_t, build_r_ack, status_t, if (this->status == XAUTH_OK) { establish(this); + lib->processor->queue_job(lib->processor, (job_t*) + adopt_children_job_create(this->ike_sa->get_id(this->ike_sa))); return SUCCESS; } return FAILED; From 927c1dd9d2d7f932c40b890e275184d007c6743d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 4 Jan 2012 14:43:15 +0100 Subject: [PATCH 435/534] Support IKEv1 proposal encodings having both lifebytes and a lifetime --- .../encoding/payloads/proposal_substructure.c | 141 ++++++++---------- 1 file changed, 66 insertions(+), 75 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 77a4fe434..ba7ef9961 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -769,122 +769,113 @@ METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*, return this->transforms->create_enumerator(this->transforms); } -/** - * Get an attribute from a selected transform - */ -static u_int64_t get_attr_tfrm(transform_substructure_t *transform, - transform_attribute_type_t type) -{ - enumerator_t *enumerator; - transform_attribute_t *attr; - u_int64_t value = 0; - - enumerator = transform->create_attribute_enumerator(transform); - while (enumerator->enumerate(enumerator, &attr)) - { - if (attr->get_attribute_type(attr) == type) - { - value = attr->get_value(attr); - break; - } - } - enumerator->destroy(enumerator); - return value; -} - - /** * Get an attribute from any transform, 0 if not found */ static u_int64_t get_attr(private_proposal_substructure_t *this, - transform_attribute_type_t type, transform_substructure_t **sel) + transform_attribute_type_t type) { + enumerator_t *transforms, *attributes; transform_substructure_t *transform; - enumerator_t *enumerator; - u_int64_t value = 0; + transform_attribute_t *attr; - enumerator = this->transforms->create_enumerator(this->transforms); - while (enumerator->enumerate(enumerator, &transform)) + transforms = this->transforms->create_enumerator(this->transforms); + while (transforms->enumerate(transforms, &transform)) { - value = get_attr_tfrm(transform, type); - if (value) + attributes = transform->create_attribute_enumerator(transform); + while (attributes->enumerate(attributes, &attr)) { - if (sel) + if (attr->get_attribute_type(attr) == type) { - *sel = transform; + attributes->destroy(attributes); + transforms->destroy(transforms); + return attr->get_value(attr); } - break; } + attributes->destroy(attributes); } - enumerator->destroy(enumerator); - return value; + transforms->destroy(transforms); + return 0; +} + +/** + * Look up a lifetime duration of a given kind in all transforms + */ +static u_int64_t get_life_duration(private_proposal_substructure_t *this, + transform_attribute_type_t type_attr, ikev1_life_type_t type, + transform_attribute_type_t dur_attr) +{ + enumerator_t *transforms, *attributes; + transform_substructure_t *transform; + transform_attribute_t *attr; + + transforms = this->transforms->create_enumerator(this->transforms); + while (transforms->enumerate(transforms, &transform)) + { + attributes = transform->create_attribute_enumerator(transform); + while (attributes->enumerate(attributes, &attr)) + { + if (attr->get_attribute_type(attr) == type_attr && + attr->get_value(attr) == type) + { /* got type attribute, look for duration following next */ + while (attributes->enumerate(attributes, &attr)) + { + if (attr->get_attribute_type(attr) == dur_attr) + { + attributes->destroy(attributes); + transforms->destroy(transforms); + return attr->get_value(attr); + } + } + } + } + attributes->destroy(attributes); + } + transforms->destroy(transforms); + return 0; } METHOD(proposal_substructure_t, get_lifetime, u_int32_t, private_proposal_substructure_t *this) { - transform_substructure_t *transform; - ikev1_life_type_t type; + u_int32_t duration; switch (this->protocol_id) { case PROTO_IKE: - type = get_attr(this, TATTR_PH1_LIFE_TYPE, &transform); - if (type == IKEV1_LIFE_TYPE_SECONDS) - { - return get_attr_tfrm(transform, TATTR_PH1_LIFE_DURATION); - } - break; + return get_life_duration(this, TATTR_PH1_LIFE_TYPE, + IKEV1_LIFE_TYPE_SECONDS, TATTR_PH1_LIFE_DURATION); case PROTO_ESP: - type = get_attr(this, TATTR_PH2_SA_LIFE_TYPE, &transform); - if (type == IKEV1_LIFE_TYPE_SECONDS) - { - return get_attr_tfrm(transform, TATTR_PH2_SA_LIFE_DURATION); - } - else if (type != IKEV1_LIFE_TYPE_KILOBYTES) + duration = get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE, + IKEV1_LIFE_TYPE_SECONDS, TATTR_PH2_SA_LIFE_DURATION); + if (!duration) { /* default to 8 hours, RFC 2407 */ return 28800; } - break; + return duration; default: - break; + return 0; } - return 0; } METHOD(proposal_substructure_t, get_lifebytes, u_int64_t, private_proposal_substructure_t *this) { - transform_substructure_t *transform; - ikev1_life_type_t type; - switch (this->protocol_id) { - case PROTO_IKE: - type = get_attr(this, TATTR_PH1_LIFE_TYPE, &transform); - if (type == IKEV1_LIFE_TYPE_KILOBYTES) - { - return get_attr_tfrm(transform, TATTR_PH1_LIFE_DURATION); - } - break; case PROTO_ESP: - type = get_attr(this, TATTR_PH2_SA_LIFE_TYPE, &transform); - if (type == IKEV1_LIFE_TYPE_KILOBYTES) - { - return get_attr_tfrm(transform, TATTR_PH1_LIFE_DURATION); - } - break; + return 1000 * get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE, + IKEV1_LIFE_TYPE_KILOBYTES, TATTR_PH2_SA_LIFE_DURATION); + case PROTO_IKE: default: - break; + return 0; } - return 0; - } METHOD(proposal_substructure_t, get_auth_method, auth_method_t, private_proposal_substructure_t *this) { - switch (get_attr(this, TATTR_PH1_AUTH_METHOD, NULL)) + switch (get_attr(this, TATTR_PH1_AUTH_METHOD)) { case IKEV1_AUTH_PSK: return AUTH_PSK; @@ -908,7 +899,7 @@ METHOD(proposal_substructure_t, get_encap_mode, ipsec_mode_t, private_proposal_substructure_t *this, bool *udp) { *udp = FALSE; - switch (get_attr(this, TATTR_PH2_ENCAP_MODE, NULL)) + switch (get_attr(this, TATTR_PH2_ENCAP_MODE)) { case IKEV1_ENCAP_TRANSPORT: return MODE_TRANSPORT; @@ -1110,7 +1101,7 @@ static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH2_SA_LIFE_DURATION, lifetime)); } - else if (lifebytes) + if (lifebytes) { transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, From 90731f38c9fdb0af1d726d0ec3aa6550a018420c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 5 Jan 2012 15:02:40 +0100 Subject: [PATCH 436/534] Install quick mode CHILD_SAs with negotiated encapsulation mode --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 29 +++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 0e8eea95a..fb7e1a0ff 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -119,6 +119,11 @@ struct private_quick_mode_t { */ u_int32_t reqid; + /** + * Negotiated mode, tunnel or transport + */ + ipsec_mode_t mode; + /** states of quick mode */ enum { QM_INIT, @@ -137,7 +142,7 @@ static bool install(private_quick_mode_t *this) this->child_sa->set_proposal(this->child_sa, this->proposal); this->child_sa->set_state(this->child_sa, CHILD_INSTALLING); - this->child_sa->set_mode(this->child_sa, MODE_TUNNEL); + this->child_sa->set_mode(this->child_sa, this->mode); this->child_sa->set_protocol(this->child_sa, this->proposal->get_protocol(this->proposal)); @@ -550,10 +555,10 @@ METHOD(task_t, build_i, status_t, sa_payload_t *sa_payload; linked_list_t *list; proposal_t *proposal; - ipsec_mode_t mode; diffie_hellman_group_t group; - bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); + bool udp; + udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), @@ -574,8 +579,8 @@ METHOD(task_t, build_i, status_t, } enumerator->destroy(enumerator); - mode = this->config->get_mode(this->config); - if (udp && mode == MODE_TRANSPORT) + this->mode = this->config->get_mode(this->config); + if (udp && this->mode == MODE_TRANSPORT) { /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */ add_nat_oa_payloads(this, message); @@ -584,7 +589,7 @@ METHOD(task_t, build_i, status_t, get_lifetimes(this); sa_payload = sa_payload_create_from_proposals_v1(list, this->lifetime, this->lifebytes, AUTH_NONE, - mode, udp); + this->mode, udp); list->destroy_offset(list, offsetof(proposal_t, destroy)); message->add_payload(message, &sa_payload->payload_interface); @@ -709,7 +714,7 @@ METHOD(task_t, process_r, status_t, peer_cfg_t *peer_cfg; host_t *me, *other; u_int16_t group; - bool udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); + bool udp; if (!get_ts(this, message)) { @@ -760,6 +765,7 @@ METHOD(task_t, process_r, status_t, get_lifetimes(this); apply_lifetimes(this, sa_payload); + this->mode = sa_payload->get_encap_mode(sa_payload, &udp); if (!this->proposal) { @@ -829,8 +835,7 @@ METHOD(task_t, build_r, status_t, case QM_INIT: { sa_payload_t *sa_payload; - ipsec_mode_t mode; - bool udp = this->child_sa->has_encap(this->child_sa); + bool udp; this->spi_r = this->child_sa->alloc_spi(this->child_sa, PROTO_ESP); if (!this->spi_r) @@ -840,8 +845,8 @@ METHOD(task_t, build_r, status_t, } this->proposal->set_spi(this->proposal, this->spi_r); - mode = this->config->get_mode(this->config); - if (udp && mode == MODE_TRANSPORT) + udp = this->child_sa->has_encap(this->child_sa); + if (udp && this->mode == MODE_TRANSPORT) { /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */ add_nat_oa_payloads(this, message); @@ -849,7 +854,7 @@ METHOD(task_t, build_r, status_t, sa_payload = sa_payload_create_from_proposal_v1(this->proposal, this->lifetime, this->lifebytes, AUTH_NONE, - mode, udp); + this->mode, udp); message->add_payload(message, &sa_payload->payload_interface); if (!add_nonce(this, &this->nonce_r, message)) From 44dcd5944ab878cb5bbbec6aa79d5d99b109d33f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 13:41:35 +0100 Subject: [PATCH 437/534] Fix error handling if no PSK found for main mode --- src/libcharon/sa/ikev1/tasks/main_mode.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index 3c0a2520e..2fc06ca1a 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -799,11 +799,11 @@ static shared_key_t *lookup_shared_key(private_main_mode_t *this) { shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, my_id, other_id); - } - else - { - DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]", - my_id, me, other_id, other); + if (!shared_key) + { + DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]", + my_id, me, other_id, other); + } } } else @@ -862,6 +862,10 @@ static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_RESP_PSK: shared_key = lookup_shared_key(this); + if (!shared_key) + { + return FALSE; + } break; default: break; From c29a89b80d09f867e7e5587c3035c4358c39cdfa Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 17:04:41 +0100 Subject: [PATCH 438/534] Implemented a common Phase 1 helper class to use by main and aggressive modes --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/ikev1/phase1.c | 605 ++++++++++++++++++++++++++++++++ src/libcharon/sa/ikev1/phase1.h | 148 ++++++++ 3 files changed, 754 insertions(+) create mode 100644 src/libcharon/sa/ikev1/phase1.c create mode 100644 src/libcharon/sa/ikev1/phase1.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 979b725c3..999810bc6 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -104,6 +104,7 @@ sa/ikev1/task_manager_v1.c sa/ikev1/task_manager_v1.h \ sa/ikev1/authenticators/psk_v1_authenticator.c sa/ikev1/authenticators/psk_v1_authenticator.h \ sa/ikev1/authenticators/pubkey_v1_authenticator.c sa/ikev1/authenticators/pubkey_v1_authenticator.h \ sa/ikev1/authenticators/hybrid_authenticator.c sa/ikev1/authenticators/hybrid_authenticator.h \ +sa/ikev1/phase1.c sa/ikev1/phase1.h \ sa/ikev1/tasks/main_mode.c sa/ikev1/tasks/main_mode.h \ sa/ikev1/tasks/informational.c sa/ikev1/tasks/informational.h \ sa/ikev1/tasks/isakmp_cert_pre.c sa/ikev1/tasks/isakmp_cert_pre.h \ diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c new file mode 100644 index 000000000..8d844ac5a --- /dev/null +++ b/src/libcharon/sa/ikev1/phase1.c @@ -0,0 +1,605 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "phase1.h" + +#include +#include +#include +#include + +typedef struct private_phase1_t private_phase1_t; + +/** + * Private data of an phase1_t object. + */ +struct private_phase1_t { + + /** + * Public phase1_t interface. + */ + phase1_t public; + + /** + * IKE_SA we negotiate + */ + ike_sa_t *ike_sa; + + /** + * Acting as initiator + */ + bool initiator; + + /** + * Extracted SA payload bytes + */ + chunk_t sa_payload; + + /** + * DH exchange + */ + diffie_hellman_t *dh; + + /** + * Keymat derivation (from SA) + */ + keymat_v1_t *keymat; + + /** + * Received public DH value from peer + */ + chunk_t dh_value; + + /** + * Initiators nonce + */ + chunk_t nonce_i; + + /** + * Responder nonce + */ + chunk_t nonce_r; +}; + +/** + * Get the first authentcation config from peer config + */ +static auth_cfg_t *get_auth_cfg(peer_cfg_t *peer_cfg, bool local) +{ + enumerator_t *enumerator; + auth_cfg_t *cfg = NULL; + + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); + enumerator->enumerate(enumerator, &cfg); + enumerator->destroy(enumerator); + return cfg; +} + +/** + * Lookup a shared secret for this IKE_SA + */ +static shared_key_t *lookup_shared_key(private_phase1_t *this, + peer_cfg_t *peer_cfg) +{ + host_t *me, *other; + identification_t *my_id, *other_id; + shared_key_t *shared_key = NULL; + auth_cfg_t *my_auth, *other_auth; + enumerator_t *enumerator; + + /* try to get a PSK for IP addresses */ + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + my_id = identification_create_from_sockaddr(me->get_sockaddr(me)); + other_id = identification_create_from_sockaddr(other->get_sockaddr(other)); + if (my_id && other_id) + { + shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, + my_id, other_id); + } + DESTROY_IF(my_id); + DESTROY_IF(other_id); + if (shared_key) + { + return shared_key; + } + + if (peer_cfg) + { /* as initiator, use identities from configuraiton */ + my_auth = get_auth_cfg(peer_cfg, TRUE); + other_auth = get_auth_cfg(peer_cfg, FALSE); + if (my_auth && other_auth) + { + my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY); + other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY); + if (my_id && other_id) + { + shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, + my_id, other_id); + if (!shared_key) + { + DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]", + my_id, me, other_id, other); + } + } + } + return shared_key; + } + /* as responder, we try to find a config by IP */ + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + me, other, NULL, NULL, IKEV1); + while (enumerator->enumerate(enumerator, &peer_cfg)) + { + my_auth = get_auth_cfg(peer_cfg, TRUE); + other_auth = get_auth_cfg(peer_cfg, FALSE); + if (my_auth && other_auth) + { + my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY); + other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY); + if (my_id && other_id) + { + shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, + my_id, other_id); + if (shared_key) + { + break; + } + else + { + DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]", + my_id, me, other_id, other); + } + } + } + } + enumerator->destroy(enumerator); + if (!peer_cfg) + { + DBG1(DBG_IKE, "no shared key found for %H - %H", me, other); + } + return shared_key; +} + +METHOD(phase1_t, create_hasher, bool, + private_phase1_t *this, proposal_t *proposal) +{ + return this->keymat->create_hasher(this->keymat, proposal); +} + +METHOD(phase1_t, create_dh, bool, + private_phase1_t *this, diffie_hellman_group_t group) +{ + this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, group); + return this->dh != NULL; +} + +METHOD(phase1_t, derive_keys, bool, + private_phase1_t *this, peer_cfg_t *peer_cfg, auth_method_t method, + proposal_t *proposal) +{ + shared_key_t *shared_key = NULL; + + switch (method) + { + case AUTH_PSK: + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_RESP_PSK: + shared_key = lookup_shared_key(this, peer_cfg); + if (!shared_key) + { + return FALSE; + } + break; + default: + break; + } + + if (!this->keymat->derive_ike_keys(this->keymat, proposal, + this->dh, this->dh_value, this->nonce_i, this->nonce_r, + this->ike_sa->get_id(this->ike_sa), method, shared_key)) + { + DESTROY_IF(shared_key); + DBG1(DBG_IKE, "key derivation for %N failed", auth_method_names, method); + return FALSE; + } + DESTROY_IF(shared_key); + charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, + this->nonce_i, this->nonce_r, NULL); + return TRUE; +} + +/** + * Check if a peer skipped authentication by using Hybrid authentication + */ +static bool skipped_auth(private_phase1_t *this, + auth_method_t method, bool local) +{ + bool initiator; + + initiator = local == this->initiator; + if (initiator && method == AUTH_HYBRID_INIT_RSA) + { + return TRUE; + } + if (!initiator && method == AUTH_HYBRID_RESP_RSA) + { + return TRUE; + } + return FALSE; +} + +/** + * Check if remote authentication constraints fulfilled + */ +static bool check_constraints(private_phase1_t *this, auth_method_t method) +{ + identification_t *id; + auth_cfg_t *auth, *cfg; + peer_cfg_t *peer_cfg; + + auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); + /* auth identity to comply */ + id = this->ike_sa->get_other_id(this->ike_sa); + auth->add(auth, AUTH_RULE_IDENTITY, id->clone(id)); + if (skipped_auth(this, method, FALSE)) + { + return TRUE; + } + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + cfg = get_auth_cfg(peer_cfg, FALSE); + return cfg && auth->complies(auth, cfg, TRUE); +} + +/** + * Save authentication information after authentication succeeded + */ +static void save_auth_cfg(private_phase1_t *this, + auth_method_t method, bool local) +{ + auth_cfg_t *auth; + + if (skipped_auth(this, method, local)) + { + return; + } + auth = auth_cfg_create(); + /* for local config, we _copy_ entires from the config, as it contains + * certificates we must send later. */ + auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), local); + this->ike_sa->add_auth_cfg(this->ike_sa, local, auth); +} + +/** + * Create an authenticator instance + */ +static authenticator_t* create_authenticator(private_phase1_t *this, + auth_method_t method, chunk_t id) +{ + authenticator_t *authenticator; + + authenticator = authenticator_create_v1(this->ike_sa, this->initiator, + method, this->dh, this->dh_value, this->sa_payload, id); + if (!authenticator) + { + DBG1(DBG_IKE, "negotiated authentication method %N not supported", + auth_method_names, method); + } + return authenticator; +} + +METHOD(phase1_t, verify_auth, bool, + private_phase1_t *this, auth_method_t method, message_t *message, + chunk_t id_data) +{ + authenticator_t *authenticator; + status_t status; + + authenticator = create_authenticator(this, method, id_data); + if (authenticator) + { + status = authenticator->process(authenticator, message); + authenticator->destroy(authenticator); + if (status == SUCCESS && check_constraints(this, method)) + { + save_auth_cfg(this, method, FALSE); + return TRUE; + } + } + return FALSE; +} + +METHOD(phase1_t, build_auth, bool, + private_phase1_t *this, auth_method_t method, message_t *message, + chunk_t id_data) +{ + authenticator_t *authenticator; + status_t status; + + authenticator = create_authenticator(this, method, id_data); + if (authenticator) + { + status = authenticator->build(authenticator, message); + authenticator->destroy(authenticator); + if (status == SUCCESS) + { + save_auth_cfg(this, method, TRUE); + return TRUE; + } + } + return FALSE; +} + +/** + * Get the two auth classes from local or remote config + */ +static void get_auth_class(peer_cfg_t *peer_cfg, bool local, + auth_class_t *c1, auth_class_t *c2) +{ + enumerator_t *enumerator; + auth_cfg_t *auth; + + *c1 = *c2 = AUTH_CLASS_ANY; + + enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); + while (enumerator->enumerate(enumerator, &auth)) + { + if (*c1 == AUTH_CLASS_ANY) + { + *c1 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); + } + else + { + *c2 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); + break; + } + } + enumerator->destroy(enumerator); +} + +METHOD(phase1_t, get_auth_method, auth_method_t, + private_phase1_t *this, peer_cfg_t *peer_cfg) +{ + auth_class_t i1, i2, r1, r2; + + get_auth_class(peer_cfg, this->initiator, &i1, &i2); + get_auth_class(peer_cfg, !this->initiator, &r1, &r2); + + if (i1 == AUTH_CLASS_PUBKEY && r1 == AUTH_CLASS_PUBKEY) + { + if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) + { + /* TODO-IKEv1: ECDSA? */ + return AUTH_RSA; + } + if (i2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_INIT_RSA; + } + if (r2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_RESP_RSA; + } + } + if (i1 == AUTH_CLASS_PSK && r1 == AUTH_CLASS_PSK) + { + if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) + { + return AUTH_PSK; + } + if (i2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_INIT_PSK; + } + if (r2 == AUTH_CLASS_XAUTH) + { + return AUTH_XAUTH_RESP_PSK; + } + } + if (i1 == AUTH_CLASS_XAUTH && r1 == AUTH_CLASS_PUBKEY && + i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) + { + return AUTH_HYBRID_INIT_RSA; + } + return AUTH_NONE; +} + +METHOD(phase1_t, select_config, peer_cfg_t*, + private_phase1_t *this, auth_method_t method, identification_t *id) +{ + enumerator_t *enumerator; + peer_cfg_t *current, *found = NULL; + host_t *me, *other; + + me = this->ike_sa->get_my_host(this->ike_sa); + other = this->ike_sa->get_other_host(this->ike_sa); + DBG1(DBG_CFG, "looking for %N peer configs matching %H...%H[%Y]", + auth_method_names, method, me, other, id); + enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, + me, other, NULL, id, IKEV1); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (get_auth_method(this, current) == method) + { + found = current->get_ref(current); + break; + } + } + enumerator->destroy(enumerator); + + if (found) + { + DBG2(DBG_CFG, "selected peer config \"%s\"", found->get_name(found)); + } + return found; +} + +METHOD(phase1_t, get_id, identification_t*, + private_phase1_t *this, peer_cfg_t *peer_cfg, bool local) +{ + auth_cfg_t *auth; + + auth = get_auth_cfg(peer_cfg, local); + if (auth) + { + return auth->get(auth, AUTH_RULE_IDENTITY); + } + return NULL; +} + +METHOD(phase1_t, save_sa_payload, bool, + private_phase1_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload, *sa = NULL; + chunk_t data; + size_t offset = IKE_HEADER_LENGTH; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) + { + sa = payload; + break; + } + else + { + offset += payload->get_length(payload); + } + } + enumerator->destroy(enumerator); + + data = message->get_packet_data(message); + if (sa && data.len >= offset + sa->get_length(sa)) + { + /* Get SA payload without 4 byte fixed header */ + data = chunk_skip(data, offset); + data.len = sa->get_length(sa); + data = chunk_skip(data, 4); + this->sa_payload = chunk_clone(data); + return TRUE; + } + DBG1(DBG_IKE, "unable to extract SA payload encoding"); + return FALSE; +} + +METHOD(phase1_t, add_nonce_ke, bool, + private_phase1_t *this, message_t *message) +{ + nonce_payload_t *nonce_payload; + ke_payload_t *ke_payload; + chunk_t nonce; + rng_t *rng; + + ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, this->dh); + message->add_payload(message, &ke_payload->payload_interface); + + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_IKE, "no RNG found to create nonce"); + return FALSE; + } + rng->allocate_bytes(rng, NONCE_SIZE, &nonce); + rng->destroy(rng); + + nonce_payload = nonce_payload_create(NONCE_V1); + nonce_payload->set_nonce(nonce_payload, nonce); + message->add_payload(message, &nonce_payload->payload_interface); + + if (this->initiator) + { + this->nonce_i = nonce; + } + else + { + this->nonce_r = nonce; + } + return TRUE; +} + +METHOD(phase1_t, get_nonce_ke, bool, + private_phase1_t *this, message_t *message) +{ + nonce_payload_t *nonce_payload; + ke_payload_t *ke_payload; + + ke_payload = (ke_payload_t*)message->get_payload(message, KEY_EXCHANGE_V1); + if (!ke_payload) + { + DBG1(DBG_IKE, "KE payload missing in message"); + return FALSE; + } + this->dh_value = chunk_clone(ke_payload->get_key_exchange_data(ke_payload)); + this->dh->set_other_public_value(this->dh, this->dh_value); + + nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1); + if (!nonce_payload) + { + DBG1(DBG_IKE, "NONCE payload missing in message"); + return FALSE; + } + + if (this->initiator) + { + this->nonce_r = nonce_payload->get_nonce(nonce_payload); + } + else + { + this->nonce_i = nonce_payload->get_nonce(nonce_payload); + } + return TRUE; +} + +METHOD(phase1_t, destroy, void, + private_phase1_t *this) +{ + chunk_free(&this->sa_payload); + DESTROY_IF(this->dh); + free(this->dh_value.ptr); + free(this->nonce_i.ptr); + free(this->nonce_r.ptr); + free(this); +} + +/** + * See header + */ +phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator) +{ + private_phase1_t *this; + + INIT(this, + .public = { + .create_hasher = _create_hasher, + .create_dh = _create_dh, + .derive_keys = _derive_keys, + .get_auth_method = _get_auth_method, + .get_id = _get_id, + .select_config = _select_config, + .verify_auth = _verify_auth, + .build_auth = _build_auth, + .save_sa_payload = _save_sa_payload, + .add_nonce_ke = _add_nonce_ke, + .get_nonce_ke = _get_nonce_ke, + .destroy = _destroy, + }, + .ike_sa = ike_sa, + .initiator = initiator, + .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa), + ); + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/phase1.h b/src/libcharon/sa/ikev1/phase1.h new file mode 100644 index 000000000..22b9dd68a --- /dev/null +++ b/src/libcharon/sa/ikev1/phase1.h @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup phase1 phase1 + * @{ @ingroup ikev1 + */ + +#ifndef PHASE1_H_ +#define PHASE1_H_ + +typedef struct phase1_t phase1_t; + +#include +#include + +/** + * Common phase 1 helper for main and aggressive mode. + */ +struct phase1_t { + + /** + * Create keymat hasher. + * + * @param proposal negotiated proposal + * @return TRUE if hasher created + */ + bool (*create_hasher)(phase1_t *this, proposal_t *proposal); + + /** + * Create DH object using SA keymat. + * + * @param group negotiated DH group + * @return TRUE if group supported + */ + bool (*create_dh)(phase1_t *this, diffie_hellman_group_t group); + + /** + * Derive key material. + * + * @param peer_cfg peer config to look up shared key for, or NULL + * @param method negotiated authenticated method + * @param proposal selected IKE proposal + * @return TRUE if successful + */ + bool (*derive_keys)(phase1_t *this, peer_cfg_t *peer_cfg, + auth_method_t method, proposal_t *proposal); + /** + * Verify a HASH or SIG payload in message. + * + * @param method negotiated auth method + * @param message message containing HASH or SIG payload + * @param id_data encoded identity, including protocol/port fields + * @return TRUE if verified successfully + */ + bool (*verify_auth)(phase1_t *this, auth_method_t method, + message_t *message, chunk_t id_data); + + /** + * Build a HASH or SIG payload and add it to message. + * + * @param method negotiated auth method + * @param message message to add payload to + * @param id_data encoded identity, including protocol/port fields + * @return TRUE if built successfully + */ + bool (*build_auth)(phase1_t *this, auth_method_t method, + message_t *message, chunk_t id_data); + + /** + * Get the IKEv1 authentication method defined by peer config. + * + * @param peer_cfg peer config to get auth method from + * @return auth method, or AUTH_NONE + */ + auth_method_t (*get_auth_method)(phase1_t *this, peer_cfg_t *peer_cfg); + + /** + * Select a peer config as responder. + * + * @param method used authentication method + * @param id initiator identity + * @return selected peer config, NULL if none found + */ + peer_cfg_t* (*select_config)(phase1_t *this, auth_method_t method, + identification_t *id); + + /** + * Get configured identity from peer config. + * + * @param peer_cfg peer config to get identity from + * @param local TRUE to get own identity, FALSE for remote + * @return identity, pointing to internal config data + */ + identification_t* (*get_id)(phase1_t *this, peer_cfg_t *peer_cfg, bool local); + + /** + * Extract and store SA payload bytes from encoded message. + * + * @param message message to extract SA payload bytes from + * @return TRUE if SA payload found + */ + bool (*save_sa_payload)(phase1_t *this, message_t *message); + + /** + * Add Nonce and KE payload to message. + * + * @param message message to add payloads + * @return TRUE if payloads added successfully + */ + bool (*add_nonce_ke)(phase1_t *this, message_t *message); + + /** + * Extract Nonce and KE payload from message. + * + * @param message message to get payloads from + * @return TRUE if payloads extracted successfully + */ + bool (*get_nonce_ke)(phase1_t *this, message_t *message); + + /** + * Destroy a phase1_t. + */ + void (*destroy)(phase1_t *this); +}; + +/** + * Create a phase1 instance. + * + * @param ike_sa IKE_SA to set up + * @param initiator TRUE if initiating actively + * @return Phase 1 helper + */ +phase1_t *phase1_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** PHASE1_H_ @}*/ From b4bd8756127b55fb4631f4ec5f6db8779af0ce29 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 17:05:16 +0100 Subject: [PATCH 439/534] Make use of the new Phase 1 helper class in main mode --- src/libcharon/sa/ikev1/tasks/main_mode.c | 652 +++-------------------- 1 file changed, 73 insertions(+), 579 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index 2fc06ca1a..a3b567870 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -21,11 +21,8 @@ #include #include -#include -#include +#include #include -#include -#include #include #include #include @@ -56,6 +53,11 @@ struct private_main_mode_t { */ bool initiator; + /** + * Common phase 1 helper class + */ + phase1_t *ph1; + /** * IKE config to establish */ @@ -66,51 +68,11 @@ struct private_main_mode_t { */ peer_cfg_t *peer_cfg; - /** - * Local authentication configuration - */ - auth_cfg_t *my_auth; - - /** - * Remote authentication configuration - */ - auth_cfg_t *other_auth; - /** * selected IKE proposal */ proposal_t *proposal; - /** - * DH exchange - */ - diffie_hellman_t *dh; - - /** - * Keymat derivation (from SA) - */ - keymat_v1_t *keymat; - - /** - * Received public DH value from peer - */ - chunk_t dh_value; - - /** - * Initiators nonce - */ - chunk_t nonce_i; - - /** - * Responder nonce - */ - chunk_t nonce_r; - - /** - * Encoded SA initiator payload used for authentication - */ - chunk_t sa_payload; - /** * Negotiated SA lifetime */ @@ -119,7 +81,7 @@ struct private_main_mode_t { /** * Negotiated authentication method */ - auth_method_t auth_method; + auth_method_t method; /** states of main mode */ enum { @@ -131,298 +93,20 @@ struct private_main_mode_t { }; /** - * Get the first authentcation config from peer config + * Set IKE_SA to established state */ -static auth_cfg_t *get_auth_cfg(peer_cfg_t *peer_cfg, bool local) +static void establish(private_main_mode_t *this) { - enumerator_t *enumerator; - auth_cfg_t *cfg = NULL; + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); - enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); - enumerator->enumerate(enumerator, &cfg); - enumerator->destroy(enumerator); - return cfg; -} - -/** - * Create an authenticator, if supported - */ -static authenticator_t *create_authenticator(private_main_mode_t *this, - id_payload_t *id) -{ - authenticator_t *authenticator; - authenticator = authenticator_create_v1(this->ike_sa, this->initiator, - this->auth_method, this->dh, - this->dh_value, this->sa_payload, - id->get_encoded(id)); - if (!authenticator) - { - DBG1(DBG_IKE, "negotiated authentication method %N not supported", - auth_method_names, this->auth_method); - } - return authenticator; -} - -/** - * Save the encoded SA payload of a message - */ -static bool save_sa_payload(private_main_mode_t *this, message_t *message) -{ - enumerator_t *enumerator; - payload_t *payload, *sa = NULL; - chunk_t data; - size_t offset = IKE_HEADER_LENGTH; - - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) - { - if (payload->get_type(payload) == SECURITY_ASSOCIATION_V1) - { - sa = payload; - break; - } - else - { - offset += payload->get_length(payload); - } - } - enumerator->destroy(enumerator); - - data = message->get_packet_data(message); - if (sa && data.len >= offset + sa->get_length(sa)) - { - /* Get SA payload without 4 byte fixed header */ - data = chunk_skip(data, offset); - data.len = sa->get_length(sa); - data = chunk_skip(data, 4); - this->sa_payload = chunk_clone(data); - return TRUE; - } - return FALSE; -} - -/** - * Generate and add NONCE, KE payload - */ -static bool add_nonce_ke(private_main_mode_t *this, chunk_t *nonce, - message_t *message) -{ - nonce_payload_t *nonce_payload; - ke_payload_t *ke_payload; - rng_t *rng; - - ke_payload = ke_payload_create_from_diffie_hellman(KEY_EXCHANGE_V1, - this->dh); - message->add_payload(message, &ke_payload->payload_interface); - - rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); - if (!rng) - { - DBG1(DBG_IKE, "no RNG found to create nonce"); - return FALSE; - } - rng->allocate_bytes(rng, NONCE_SIZE, nonce); - rng->destroy(rng); - - nonce_payload = nonce_payload_create(NONCE_V1); - nonce_payload->set_nonce(nonce_payload, *nonce); - message->add_payload(message, &nonce_payload->payload_interface); - - return TRUE; -} - -/** - * Extract nonce from NONCE payload, process KE payload - */ -static bool get_nonce_ke(private_main_mode_t *this, chunk_t *nonce, - message_t *message) -{ - nonce_payload_t *nonce_payload; - ke_payload_t *ke_payload; - - ke_payload = (ke_payload_t*)message->get_payload(message, KEY_EXCHANGE_V1); - if (!ke_payload) - { - DBG1(DBG_IKE, "KE payload missing in message"); - return FALSE; - } - this->dh_value = chunk_clone(ke_payload->get_key_exchange_data(ke_payload)); - this->dh->set_other_public_value(this->dh, this->dh_value); - - nonce_payload = (nonce_payload_t*)message->get_payload(message, NONCE_V1); - if (!nonce_payload) - { - DBG1(DBG_IKE, "NONCE payload missing in message"); - return FALSE; - } - *nonce = nonce_payload->get_nonce(nonce_payload); - - return TRUE; -} - -/** - * Get the two auth classes from local or remote config - */ -static void get_auth_class(peer_cfg_t *peer_cfg, bool local, - auth_class_t *c1, auth_class_t *c2) -{ - enumerator_t *enumerator; - auth_cfg_t *auth; - - *c1 = *c2 = AUTH_CLASS_ANY; - - enumerator = peer_cfg->create_auth_cfg_enumerator(peer_cfg, local); - while (enumerator->enumerate(enumerator, &auth)) - { - if (*c1 == AUTH_CLASS_ANY) - { - *c1 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); - } - else - { - *c2 = (uintptr_t)auth->get(auth, AUTH_RULE_AUTH_CLASS); - break; - } - } - enumerator->destroy(enumerator); -} - -/** - * Get auth method to use from a peer config - */ -static auth_method_t get_auth_method(private_main_mode_t *this, - peer_cfg_t *peer_cfg) -{ - auth_class_t i1, i2, r1, r2; - - get_auth_class(peer_cfg, this->initiator, &i1, &i2); - get_auth_class(peer_cfg, !this->initiator, &r1, &r2); - - if (i1 == AUTH_CLASS_PUBKEY && r1 == AUTH_CLASS_PUBKEY) - { - if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) - { - /* TODO-IKEv1: ECDSA? */ - return AUTH_RSA; - } - if (i2 == AUTH_CLASS_XAUTH) - { - return AUTH_XAUTH_INIT_RSA; - } - if (r2 == AUTH_CLASS_XAUTH) - { - return AUTH_XAUTH_RESP_RSA; - } - } - if (i1 == AUTH_CLASS_PSK && r1 == AUTH_CLASS_PSK) - { - if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) - { - return AUTH_PSK; - } - if (i2 == AUTH_CLASS_XAUTH) - { - return AUTH_XAUTH_INIT_PSK; - } - if (r2 == AUTH_CLASS_XAUTH) - { - return AUTH_XAUTH_RESP_PSK; - } - } - if (i1 == AUTH_CLASS_XAUTH && r1 == AUTH_CLASS_PUBKEY && - i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) - { - return AUTH_HYBRID_INIT_RSA; - } - return AUTH_NONE; -} - -/** - * Check if a peer skipped authentication by using Hybrid authentication - */ -static bool skipped_auth(private_main_mode_t *this, bool local) -{ - bool initiator; - - initiator = local == this->initiator; - if (initiator && this->auth_method == AUTH_HYBRID_INIT_RSA) - { - return TRUE; - } - if (!initiator && this->auth_method == AUTH_HYBRID_RESP_RSA) - { - return TRUE; - } - return FALSE; -} - -/** - * Check if remote authentication constraints fulfilled - */ -static bool check_constraints(private_main_mode_t *this) -{ - identification_t *id; - auth_cfg_t *auth; - - auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - /* auth identity to comply */ - id = this->ike_sa->get_other_id(this->ike_sa); - auth->add(auth, AUTH_RULE_IDENTITY, id->clone(id)); - if (skipped_auth(this, FALSE)) - { - return TRUE; - } - return auth->complies(auth, this->other_auth, TRUE); -} - -/** - * Save authentication information after authentication succeeded - */ -static void save_auth_cfg(private_main_mode_t *this, bool local) -{ - auth_cfg_t *auth; - - if (skipped_auth(this, local)) - { - return; - } - auth = auth_cfg_create(); - /* for local config, we _copy_ entires from the config, as it contains - * certificates we must send later. */ - auth->merge(auth, this->ike_sa->get_auth_cfg(this->ike_sa, local), local); - this->ike_sa->add_auth_cfg(this->ike_sa, local, auth); -} - -/** - * Select the best configuration as responder - */ -static peer_cfg_t *select_config(private_main_mode_t *this, identification_t *id) -{ - enumerator_t *enumerator; - peer_cfg_t *current, *found = NULL; - host_t *me, *other; - - me = this->ike_sa->get_my_host(this->ike_sa); - other = this->ike_sa->get_other_host(this->ike_sa); - DBG1(DBG_CFG, "looking for %N peer configs matching %H...%H[%Y]", - auth_method_names, this->auth_method, me, other, id); - enumerator = charon->backends->create_peer_cfg_enumerator(charon->backends, - me, other, NULL, id, IKEV1); - while (enumerator->enumerate(enumerator, ¤t)) - { - if (get_auth_method(this, current) == this->auth_method) - { - found = current->get_ref(current); - break; - } - } - enumerator->destroy(enumerator); - - if (found) - { - DBG2(DBG_CFG, "selected peer config \"%s\"", found->get_name(found)); - } - return found; + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); } /** @@ -519,31 +203,24 @@ METHOD(task_t, build_i, status_t, linked_list_t *proposals; packet_t *packet; - this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - DBG0(DBG_IKE, "initiating IKE_SA %s[%d] to %H", + DBG0(DBG_IKE, "initiating main mode IKE_SA %s[%d] to %H", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); this->peer_cfg->get_ref(this->peer_cfg); - this->my_auth = get_auth_cfg(this->peer_cfg, TRUE); - this->other_auth = get_auth_cfg(this->peer_cfg, FALSE); - if (!this->my_auth || !this->other_auth) - { - DBG1(DBG_CFG, "no auth config found"); - return FAILED; - } - this->auth_method = get_auth_method(this, this->peer_cfg); - if (this->auth_method == AUTH_NONE) + this->method = this->ph1->get_auth_method(this->ph1, this->peer_cfg); + if (this->method == AUTH_NONE) { DBG1(DBG_CFG, "configuration uses unsupported authentication"); return FAILED; } this->lifetime = this->peer_cfg->get_reauth_time(this->peer_cfg, - FALSE); + FALSE); if (!this->lifetime) { /* fall back to rekey time of no rekey time configured */ this->lifetime = this->peer_cfg->get_rekey_time(this->peer_cfg, @@ -552,7 +229,7 @@ METHOD(task_t, build_i, status_t, this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg); proposals = this->ike_cfg->get_proposals(this->ike_cfg); sa_payload = sa_payload_create_from_proposals_v1(proposals, - this->lifetime, 0, this->auth_method, MODE_NONE, FALSE); + this->lifetime, 0, this->method, MODE_NONE, FALSE); proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); message->add_payload(message, &sa_payload->payload_interface); @@ -565,9 +242,8 @@ METHOD(task_t, build_i, status_t, return FAILED; } packet->destroy(packet); - if (!save_sa_payload(this, message)) + if (!this->ph1->save_sa_payload(this->ph1, message)) { - DBG1(DBG_IKE, "SA payload invalid"); return FAILED; } @@ -578,7 +254,7 @@ METHOD(task_t, build_i, status_t, { u_int16_t group; - if (!this->keymat->create_hasher(this->keymat, this->proposal)) + if (!this->ph1->create_hasher(this->ph1, this->proposal)) { return send_notify(this, NO_PROPOSAL_CHOSEN); } @@ -588,14 +264,12 @@ METHOD(task_t, build_i, status_t, DBG1(DBG_IKE, "DH group selection failed"); return send_notify(this, NO_PROPOSAL_CHOSEN); } - this->dh = this->keymat->keymat.create_dh(&this->keymat->keymat, - group); - if (!this->dh) + if (!this->ph1->create_dh(this->ph1, group)) { DBG1(DBG_IKE, "negotiated DH group not supported"); return send_notify(this, INVALID_KEY_INFORMATION); } - if (!add_nonce_ke(this, &this->nonce_i, message)) + if (!this->ph1->add_nonce_ke(this->ph1, message)) { return send_notify(this, INVALID_KEY_INFORMATION); } @@ -604,31 +278,24 @@ METHOD(task_t, build_i, status_t, } case MM_KE: { - authenticator_t *authenticator; id_payload_t *id_payload; identification_t *id; - id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY); + id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE); if (!id) { DBG1(DBG_CFG, "own identity not known"); return send_notify(this, INVALID_ID_INFORMATION); } - this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); - id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - authenticator = create_authenticator(this, id_payload); - if (!authenticator || authenticator->build(authenticator, - message) != SUCCESS) + if (!this->ph1->build_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) { - DESTROY_IF(authenticator); return send_notify(this, AUTHENTICATION_FAILED); } - authenticator->destroy(authenticator); - save_auth_cfg(this, TRUE); this->state = MM_AUTH; return NEED_MORE; @@ -649,7 +316,7 @@ METHOD(task_t, process_r, status_t, sa_payload_t *sa_payload; this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); - DBG0(DBG_IKE, "%H is initiating a Main Mode", + DBG0(DBG_IKE, "%H is initiating a Main Mode IKE_SA", message->get_source(message)); this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); @@ -659,9 +326,13 @@ METHOD(task_t, process_r, status_t, sa_payload = (sa_payload_t*)message->get_payload(message, SECURITY_ASSOCIATION_V1); - if (!sa_payload || !save_sa_payload(this, message)) + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + if (!this->ph1->save_sa_payload(this->ph1, message)) { - DBG1(DBG_IKE, "SA payload missing or invalid"); return send_notify(this, INVALID_PAYLOAD_TYPE); } @@ -675,7 +346,7 @@ METHOD(task_t, process_r, status_t, return send_notify(this, NO_PROPOSAL_CHOSEN); } - this->auth_method = sa_payload->get_auth_method(sa_payload); + this->method = sa_payload->get_auth_method(sa_payload); this->lifetime = sa_payload->get_lifetime(sa_payload); this->state = MM_SA; @@ -685,7 +356,7 @@ METHOD(task_t, process_r, status_t, { u_int16_t group; - if (!this->keymat->create_hasher(this->keymat, this->proposal)) + if (!this->ph1->create_hasher(this->ph1, this->proposal)) { return send_notify(this, INVALID_KEY_INFORMATION); } @@ -695,13 +366,12 @@ METHOD(task_t, process_r, status_t, DBG1(DBG_IKE, "DH group selection failed"); return send_notify(this, INVALID_KEY_INFORMATION); } - this->dh = lib->crypto->create_dh(lib->crypto, group); - if (!this->dh) + if (!this->ph1->create_dh(this->ph1, group)) { DBG1(DBG_IKE, "negotiated DH group not supported"); return send_notify(this, INVALID_KEY_INFORMATION); } - if (!get_nonce_ke(this, &this->nonce_i, message)) + if (!this->ph1->get_nonce_ke(this->ph1, message)) { return send_notify(this, INVALID_PAYLOAD_TYPE); } @@ -710,7 +380,6 @@ METHOD(task_t, process_r, status_t, } case MM_KE: { - authenticator_t *authenticator; id_payload_t *id_payload; identification_t *id; @@ -723,7 +392,8 @@ METHOD(task_t, process_r, status_t, id = id_payload->get_identification(id_payload); this->ike_sa->set_other_id(this->ike_sa, id); - this->peer_cfg = select_config(this, id); + this->peer_cfg = this->ph1->select_config(this->ph1, + this->method, id); if (!this->peer_cfg) { DBG1(DBG_IKE, "no peer config found"); @@ -731,28 +401,11 @@ METHOD(task_t, process_r, status_t, } this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); - this->my_auth = get_auth_cfg(this->peer_cfg, TRUE); - this->other_auth = get_auth_cfg(this->peer_cfg, FALSE); - if (!this->my_auth || !this->other_auth) - { - DBG1(DBG_IKE, "auth config missing"); - return send_notify(this, AUTHENTICATION_FAILED); - } - - authenticator = create_authenticator(this, id_payload); - if (!authenticator || authenticator->process(authenticator, - message) != SUCCESS) - { - DESTROY_IF(authenticator); - return send_notify(this, AUTHENTICATION_FAILED); - } - authenticator->destroy(authenticator); - if (!check_constraints(this)) + if (!this->ph1->verify_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) { return send_notify(this, AUTHENTICATION_FAILED); } - save_auth_cfg(this, FALSE); - this->state = MM_AUTH; if (has_notify_errors(this, message)) { @@ -765,143 +418,6 @@ METHOD(task_t, process_r, status_t, } } -/** - * Lookup a shared secret for this IKE_SA - */ -static shared_key_t *lookup_shared_key(private_main_mode_t *this) -{ - host_t *me, *other; - identification_t *my_id, *other_id; - shared_key_t *shared_key = NULL; - - /* try to get a PSK for IP addresses */ - me = this->ike_sa->get_my_host(this->ike_sa); - other = this->ike_sa->get_other_host(this->ike_sa); - my_id = identification_create_from_sockaddr(me->get_sockaddr(me)); - other_id = identification_create_from_sockaddr(other->get_sockaddr(other)); - if (my_id && other_id) - { - shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, - my_id, other_id); - } - DESTROY_IF(my_id); - DESTROY_IF(other_id); - if (shared_key) - { - return shared_key; - } - - if (this->my_auth && this->other_auth) - { /* as initiator, use identities from configuraiton */ - my_id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY); - other_id = this->other_auth->get(this->other_auth, AUTH_RULE_IDENTITY); - if (my_id && other_id) - { - shared_key = lib->credmgr->get_shared(lib->credmgr, SHARED_IKE, - my_id, other_id); - if (!shared_key) - { - DBG1(DBG_IKE, "no shared key found for '%Y'[%H] - '%Y'[%H]", - my_id, me, other_id, other); - } - } - } - else - { /* as responder, we try to find a config by IP */ - enumerator_t *enumerator; - auth_cfg_t *my_auth, *other_auth; - peer_cfg_t *peer_cfg = NULL; - - enumerator = charon->backends->create_peer_cfg_enumerator( - charon->backends, me, other, NULL, NULL, IKEV1); - while (enumerator->enumerate(enumerator, &peer_cfg)) - { - my_auth = get_auth_cfg(peer_cfg, TRUE); - other_auth = get_auth_cfg(peer_cfg, FALSE); - if (my_auth && other_auth) - { - my_id = my_auth->get(my_auth, AUTH_RULE_IDENTITY); - other_id = other_auth->get(other_auth, AUTH_RULE_IDENTITY); - if (my_id && other_id) - { - shared_key = lib->credmgr->get_shared(lib->credmgr, - SHARED_IKE, my_id, other_id); - if (shared_key) - { - break; - } - else - { - DBG1(DBG_IKE, "no shared key found for " - "'%Y'[%H] - '%Y'[%H]", my_id, me, other_id, other); - } - } - } - } - enumerator->destroy(enumerator); - if (!peer_cfg) - { - DBG1(DBG_IKE, "no shared key found for %H - %H", me, other); - } - } - return shared_key; -} - -/** - * Derive key material for this IKE_SA - */ -static bool derive_keys(private_main_mode_t *this, chunk_t nonce_i, - chunk_t nonce_r) -{ - ike_sa_id_t *id = this->ike_sa->get_id(this->ike_sa); - shared_key_t *shared_key = NULL; - - switch (this->auth_method) - { - case AUTH_PSK: - case AUTH_XAUTH_INIT_PSK: - case AUTH_XAUTH_RESP_PSK: - shared_key = lookup_shared_key(this); - if (!shared_key) - { - return FALSE; - } - break; - default: - break; - } - if (!this->keymat->derive_ike_keys(this->keymat, this->proposal, this->dh, - this->dh_value, nonce_i, nonce_r, id, this->auth_method, shared_key)) - { - DESTROY_IF(shared_key); - DBG1(DBG_IKE, "key derivation for %N failed", - auth_method_names, this->auth_method); - return FALSE; - } - DESTROY_IF(shared_key); - charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, nonce_i, nonce_r, - NULL); - - return TRUE; -} - -/** - * Set IKE_SA to established state - */ -static void establish(private_main_mode_t *this) -{ - DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", - this->ike_sa->get_name(this->ike_sa), - this->ike_sa->get_unique_id(this->ike_sa), - this->ike_sa->get_my_host(this->ike_sa), - this->ike_sa->get_my_id(this->ike_sa), - this->ike_sa->get_other_host(this->ike_sa), - this->ike_sa->get_other_id(this->ike_sa)); - - this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); - charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); -} - METHOD(task_t, build_r, status_t, private_main_mode_t *this, message_t *message) { @@ -912,18 +428,19 @@ METHOD(task_t, build_r, status_t, sa_payload_t *sa_payload; sa_payload = sa_payload_create_from_proposal_v1(this->proposal, - this->lifetime, 0, this->auth_method, MODE_NONE, FALSE); + this->lifetime, 0, this->method, MODE_NONE, FALSE); message->add_payload(message, &sa_payload->payload_interface); return NEED_MORE; } case MM_KE: { - if (!add_nonce_ke(this, &this->nonce_r, message)) + if (!this->ph1->add_nonce_ke(this->ph1, message)) { return send_notify(this, INVALID_KEY_INFORMATION); } - if (!derive_keys(this, this->nonce_i, this->nonce_r)) + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method, + this->proposal)) { return send_notify(this, INVALID_KEY_INFORMATION); } @@ -931,11 +448,10 @@ METHOD(task_t, build_r, status_t, } case MM_AUTH: { - authenticator_t *authenticator; id_payload_t *id_payload; identification_t *id; - id = this->my_auth->get(this->my_auth, AUTH_RULE_IDENTITY); + id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE); if (!id) { DBG1(DBG_CFG, "own identity not known"); @@ -946,17 +462,12 @@ METHOD(task_t, build_r, status_t, id_payload = id_payload_create_from_identification(ID_V1, id); message->add_payload(message, &id_payload->payload_interface); - authenticator = create_authenticator(this, id_payload); - if (!authenticator || authenticator->build(authenticator, - message) != SUCCESS) + if (!this->ph1->build_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) { - DESTROY_IF(authenticator); return send_notify(this, AUTHENTICATION_FAILED); } - authenticator->destroy(authenticator); - save_auth_cfg(this, TRUE); - - switch (this->auth_method) + switch (this->method) { case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_INIT_RSA: @@ -991,7 +502,7 @@ METHOD(task_t, process_i, status_t, { linked_list_t *list; sa_payload_t *sa_payload; - auth_method_t auth_method; + auth_method_t method; u_int32_t lifetime; sa_payload = (sa_payload_t*)message->get_payload(message, @@ -1018,22 +529,23 @@ METHOD(task_t, process_i, status_t, "lifetime %us", lifetime, this->lifetime); } this->lifetime = lifetime; - auth_method = sa_payload->get_auth_method(sa_payload); - if (auth_method != this->auth_method) + method = sa_payload->get_auth_method(sa_payload); + if (method != this->method) { DBG1(DBG_IKE, "received %N authentication, but configured %N, " - "continue with configured", auth_method_names, auth_method, - auth_method_names, this->auth_method); + "continue with configured", auth_method_names, method, + auth_method_names, this->method); } return NEED_MORE; } case MM_KE: { - if (!get_nonce_ke(this, &this->nonce_r, message)) + if (!this->ph1->get_nonce_ke(this->ph1, message)) { return send_notify(this, INVALID_PAYLOAD_TYPE); } - if (!derive_keys(this, this->nonce_i, this->nonce_r)) + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, + this->method, this->proposal)) { return send_notify(this, INVALID_KEY_INFORMATION); } @@ -1041,9 +553,8 @@ METHOD(task_t, process_i, status_t, } case MM_AUTH: { - authenticator_t *authenticator; id_payload_t *id_payload; - identification_t *id; + identification_t *id, *cid; id_payload = (id_payload_t*)message->get_payload(message, ID_V1); if (!id_payload) @@ -1052,28 +563,20 @@ METHOD(task_t, process_i, status_t, return send_delete(this); } id = id_payload->get_identification(id_payload); - if (!id->matches(id, this->other_auth->get(this->other_auth, - AUTH_RULE_IDENTITY))) + cid = this->ph1->get_id(this->ph1, this->peer_cfg, FALSE); + if (cid && !id->matches(id, cid)) { - DBG1(DBG_IKE, "IDir does not match"); + DBG1(DBG_IKE, "IDir '%Y' does not match to '%Y'", id, cid); id->destroy(id); return send_delete(this); } this->ike_sa->set_other_id(this->ike_sa, id); - authenticator = create_authenticator(this, id_payload); - if (!authenticator || authenticator->process(authenticator, - message) != SUCCESS) - { - DESTROY_IF(authenticator); - return send_delete(this); - } - authenticator->destroy(authenticator); - if (!check_constraints(this)) + if (!this->ph1->verify_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) { return send_delete(this); } - save_auth_cfg(this, FALSE); if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) { @@ -1081,7 +584,7 @@ METHOD(task_t, process_i, status_t, (task_t*)mode_config_create(this->ike_sa, TRUE)); } - switch (this->auth_method) + switch (this->method) { case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_INIT_RSA: @@ -1114,18 +617,13 @@ METHOD(task_t, migrate, void, { DESTROY_IF(this->peer_cfg); DESTROY_IF(this->proposal); - DESTROY_IF(this->dh); - chunk_free(&this->dh_value); - chunk_free(&this->nonce_i); - chunk_free(&this->nonce_r); - chunk_free(&this->sa_payload); + this->ph1->destroy(this->ph1); this->ike_sa = ike_sa; - this->keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); this->state = MM_INIT; this->peer_cfg = NULL; this->proposal = NULL; - this->dh = NULL; + this->ph1 = phase1_create(ike_sa, this->initiator); } METHOD(task_t, destroy, void, @@ -1133,11 +631,7 @@ METHOD(task_t, destroy, void, { DESTROY_IF(this->peer_cfg); DESTROY_IF(this->proposal); - DESTROY_IF(this->dh); - free(this->dh_value.ptr); - free(this->nonce_i.ptr); - free(this->nonce_r.ptr); - free(this->sa_payload.ptr); + this->ph1->destroy(this->ph1); free(this); } @@ -1157,7 +651,7 @@ main_mode_t *main_mode_create(ike_sa_t *ike_sa, bool initiator) }, }, .ike_sa = ike_sa, - .keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa), + .ph1 = phase1_create(ike_sa, initiator), .initiator = initiator, .state = MM_INIT, ); From ee325b555fa2c06f5f83503a4b914231c9fc68eb Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 17:09:38 +0100 Subject: [PATCH 440/534] Implemented aggressive mode using Phase 1 helper class --- src/libcharon/Makefile.am | 1 + .../sa/ikev1/tasks/aggressive_mode.c | 629 ++++++++++++++++++ .../sa/ikev1/tasks/aggressive_mode.h | 50 ++ src/libcharon/sa/task.c | 1 + src/libcharon/sa/task.h | 2 + 5 files changed, 683 insertions(+) create mode 100644 src/libcharon/sa/ikev1/tasks/aggressive_mode.c create mode 100644 src/libcharon/sa/ikev1/tasks/aggressive_mode.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am index 999810bc6..c85c472b8 100644 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -106,6 +106,7 @@ sa/ikev1/authenticators/pubkey_v1_authenticator.c sa/ikev1/authenticators/pubkey sa/ikev1/authenticators/hybrid_authenticator.c sa/ikev1/authenticators/hybrid_authenticator.h \ sa/ikev1/phase1.c sa/ikev1/phase1.h \ sa/ikev1/tasks/main_mode.c sa/ikev1/tasks/main_mode.h \ +sa/ikev1/tasks/aggressive_mode.c sa/ikev1/tasks/aggressive_mode.h \ sa/ikev1/tasks/informational.c sa/ikev1/tasks/informational.h \ sa/ikev1/tasks/isakmp_cert_pre.c sa/ikev1/tasks/isakmp_cert_pre.h \ sa/ikev1/tasks/isakmp_cert_post.c sa/ikev1/tasks/isakmp_cert_post.h \ diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c new file mode 100644 index 000000000..2c4e14e43 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -0,0 +1,629 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "aggressive_mode.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef struct private_aggressive_mode_t private_aggressive_mode_t; + +/** + * Private members of a aggressive_mode_t task. + */ +struct private_aggressive_mode_t { + + /** + * Public methods and task_t interface. + */ + aggressive_mode_t public; + + /** + * Assigned IKE_SA. + */ + ike_sa_t *ike_sa; + + /** + * Are we the initiator? + */ + bool initiator; + + /** + * Common phase 1 helper class + */ + phase1_t *ph1; + + /** + * IKE config to establish + */ + ike_cfg_t *ike_cfg; + + /** + * Peer config to use + */ + peer_cfg_t *peer_cfg; + + /** + * selected IKE proposal + */ + proposal_t *proposal; + + /** + * Negotiated SA lifetime + */ + u_int32_t lifetime; + + /** + * Negotiated authentication method + */ + auth_method_t method; + + /** + * Encoded ID payload, without fixed header + */ + chunk_t id_data; + + /** states of aggressive mode */ + enum { + AM_INIT, + AM_AUTH, + } state; +}; + +/** + * Set IKE_SA to established state + */ +static void establish(private_aggressive_mode_t *this) +{ + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_my_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa), + this->ike_sa->get_other_id(this->ike_sa)); + + this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); + charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); +} + +/** + * Check for notify errors, return TRUE if error found + */ +static bool has_notify_errors(private_aggressive_mode_t *this, message_t *message) +{ + enumerator_t *enumerator; + payload_t *payload; + bool err = FALSE; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY_V1) + { + notify_payload_t *notify; + notify_type_t type; + + notify = (notify_payload_t*)payload; + type = notify->get_notify_type(notify); + if (type < 16384) + { + DBG1(DBG_IKE, "received %N error notify", + notify_type_names, type); + err = TRUE; + } + else + { + DBG1(DBG_IKE, "received %N notify", notify_type_names, type); + } + } + } + enumerator->destroy(enumerator); + + return err; +} + +/** + * Queue a task sending a notify in an INFORMATIONAL exchange + */ +static status_t send_notify(private_aggressive_mode_t *this, notify_type_t type) +{ + notify_payload_t *notify; + ike_sa_id_t *ike_sa_id; + u_int64_t spi_i, spi_r; + chunk_t spi; + + notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_IKE, type); + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_r = ike_sa_id->get_responder_spi(ike_sa_id); + spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r)); + notify->set_spi_data(notify, spi); + + this->ike_sa->queue_task(this->ike_sa, + (task_t*)informational_create(this->ike_sa, notify)); + /* cancel all active/passive tasks in favour of informational */ + return ALREADY_DONE; +} + +/** + * Queue a delete task if authentication failed as initiator + */ +static status_t send_delete(private_aggressive_mode_t *this) +{ + this->ike_sa->queue_task(this->ike_sa, + (task_t*)isakmp_delete_create(this->ike_sa, TRUE)); + /* cancel all active tasks in favour of informational */ + return ALREADY_DONE; +} + +METHOD(task_t, build_i, status_t, + private_aggressive_mode_t *this, message_t *message) +{ + switch (this->state) + { + case AM_INIT: + { + sa_payload_t *sa_payload; + id_payload_t *id_payload; + linked_list_t *proposals; + identification_t *id; + packet_t *packet; + u_int16_t group; + + DBG0(DBG_IKE, "initiating aggressive mode IKE_SA %s[%d] to %H", + this->ike_sa->get_name(this->ike_sa), + this->ike_sa->get_unique_id(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + this->peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + this->peer_cfg->get_ref(this->peer_cfg); + + this->method = this->ph1->get_auth_method(this->ph1, this->peer_cfg); + if (this->method == AUTH_NONE) + { + DBG1(DBG_CFG, "configuration uses unsupported authentication"); + return FAILED; + } + this->lifetime = this->peer_cfg->get_reauth_time(this->peer_cfg, + FALSE); + if (!this->lifetime) + { /* fall back to rekey time of no rekey time configured */ + this->lifetime = this->peer_cfg->get_rekey_time(this->peer_cfg, + FALSE); + } + this->lifetime += this->peer_cfg->get_over_time(this->peer_cfg); + proposals = this->ike_cfg->get_proposals(this->ike_cfg); + sa_payload = sa_payload_create_from_proposals_v1(proposals, + this->lifetime, 0, this->method, MODE_NONE, FALSE); + proposals->destroy_offset(proposals, offsetof(proposal_t, destroy)); + + message->add_payload(message, &sa_payload->payload_interface); + + group = this->ike_cfg->get_dh_group(this->ike_cfg); + if (group == MODP_NONE) + { + DBG1(DBG_IKE, "DH group selection failed"); + return FAILED; + } + if (!this->ph1->create_dh(this->ph1, group)) + { + DBG1(DBG_IKE, "DH group %N not supported", + diffie_hellman_group_names, group); + return FAILED; + } + if (!this->ph1->add_nonce_ke(this->ph1, message)) + { + return FAILED; + } + id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE); + if (!id) + { + DBG1(DBG_CFG, "own identity not known"); + return FAILED; + } + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); + id_payload = id_payload_create_from_identification(ID_V1, id); + this->id_data = id_payload->get_encoded(id_payload); + message->add_payload(message, &id_payload->payload_interface); + + /* pregenerate message to store SA payload */ + if (this->ike_sa->generate_message(this->ike_sa, message, + &packet) != SUCCESS) + { + DBG1(DBG_IKE, "pregenerating SA payload failed"); + return FAILED; + } + packet->destroy(packet); + if (!this->ph1->save_sa_payload(this->ph1, message)) + { + DBG1(DBG_IKE, "SA payload invalid"); + return FAILED; + } + this->state = AM_AUTH; + return NEED_MORE; + } + case AM_AUTH: + { + if (!this->ph1->build_auth(this->ph1, this->method, message, + this->id_data)) + { + this->id_data = chunk_empty; + return send_notify(this, AUTHENTICATION_FAILED); + } + this->id_data = chunk_empty; + + if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE)); + } + + switch (this->method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: + case AUTH_HYBRID_INIT_RSA: + /* wait for XAUTH request */ + return SUCCESS; + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_RESP_RSA: + /* TODO-IKEv1: not yet */ + return FAILED; + default: + establish(this); + return SUCCESS; + } + } + default: + return FAILED; + } +} + +METHOD(task_t, process_r, status_t, + private_aggressive_mode_t *this, message_t *message) +{ + switch (this->state) + { + case AM_INIT: + { + sa_payload_t *sa_payload; + id_payload_t *id_payload; + identification_t *id; + linked_list_t *list; + u_int16_t group; + + this->ike_cfg = this->ike_sa->get_ike_cfg(this->ike_sa); + DBG0(DBG_IKE, "%H is initiating a Aggressive Mode IKE_SA", + message->get_source(message)); + this->ike_sa->set_state(this->ike_sa, IKE_CONNECTING); + + this->ike_sa->update_hosts(this->ike_sa, + message->get_destination(message), + message->get_source(message), TRUE); + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + if (!this->ph1->save_sa_payload(this->ph1, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + + list = sa_payload->get_proposals(sa_payload); + this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, + list, FALSE); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no proposal found"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + + this->method = sa_payload->get_auth_method(sa_payload); + this->lifetime = sa_payload->get_lifetime(sa_payload); + + if (!this->proposal->get_algorithm(this->proposal, + DIFFIE_HELLMAN_GROUP, &group, NULL)) + { + DBG1(DBG_IKE, "DH group selection failed"); + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->create_dh(this->ph1, group)) + { + DBG1(DBG_IKE, "negotiated DH group not supported"); + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->get_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + + id_payload = (id_payload_t*)message->get_payload(message, ID_V1); + if (!id_payload) + { + DBG1(DBG_IKE, "IDii payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + + id = id_payload->get_identification(id_payload); + this->id_data = id_payload->get_encoded(id_payload); + this->ike_sa->set_other_id(this->ike_sa, id); + this->peer_cfg = this->ph1->select_config(this->ph1, + this->method, id); + if (!this->peer_cfg) + { + DBG1(DBG_IKE, "no peer config found"); + return send_notify(this, AUTHENTICATION_FAILED); + } + this->ike_sa->set_peer_cfg(this->ike_sa, this->peer_cfg); + + this->state = AM_AUTH; + if (has_notify_errors(this, message)) + { + return FAILED; + } + return NEED_MORE; + } + case AM_AUTH: + { + if (!this->ph1->verify_auth(this->ph1, this->method, message, + this->id_data)) + { + this->id_data = chunk_empty; + return send_delete(this); + } + this->id_data = chunk_empty; + + switch (this->method) + { + case AUTH_XAUTH_INIT_PSK: + case AUTH_XAUTH_INIT_RSA: + case AUTH_HYBRID_INIT_RSA: + this->ike_sa->queue_task(this->ike_sa, + (task_t*)xauth_create(this->ike_sa, TRUE)); + return SUCCESS; + case AUTH_XAUTH_RESP_PSK: + case AUTH_XAUTH_RESP_RSA: + case AUTH_HYBRID_RESP_RSA: + /* TODO-IKEv1: not yet supported */ + return FAILED; + default: + establish(this); + lib->processor->queue_job(lib->processor, (job_t*) + adopt_children_job_create( + this->ike_sa->get_id(this->ike_sa))); + return SUCCESS; + } + } + default: + return FAILED; + } +} + +METHOD(task_t, build_r, status_t, + private_aggressive_mode_t *this, message_t *message) +{ + if (this->state == AM_AUTH) + { + sa_payload_t *sa_payload; + id_payload_t *id_payload; + identification_t *id; + + sa_payload = sa_payload_create_from_proposal_v1(this->proposal, + this->lifetime, 0, this->method, MODE_NONE, FALSE); + message->add_payload(message, &sa_payload->payload_interface); + + if (!this->ph1->add_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + if (!this->ph1->create_hasher(this->ph1, this->proposal)) + { + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method, + this->proposal)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + + id = this->ph1->get_id(this->ph1, this->peer_cfg, TRUE); + if (!id) + { + DBG1(DBG_CFG, "own identity not known"); + return send_notify(this, INVALID_ID_INFORMATION); + } + this->ike_sa->set_my_id(this->ike_sa, id->clone(id)); + + id_payload = id_payload_create_from_identification(ID_V1, id); + message->add_payload(message, &id_payload->payload_interface); + + if (!this->ph1->build_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + return NEED_MORE; + } + return FAILED; +} + +METHOD(task_t, process_i, status_t, + private_aggressive_mode_t *this, message_t *message) +{ + if (this->state == AM_AUTH) + { + auth_method_t method; + sa_payload_t *sa_payload; + id_payload_t *id_payload; + identification_t *id, *cid; + linked_list_t *list; + u_int32_t lifetime; + + sa_payload = (sa_payload_t*)message->get_payload(message, + SECURITY_ASSOCIATION_V1); + if (!sa_payload) + { + DBG1(DBG_IKE, "SA payload missing"); + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + list = sa_payload->get_proposals(sa_payload); + this->proposal = this->ike_cfg->select_proposal(this->ike_cfg, + list, FALSE); + list->destroy_offset(list, offsetof(proposal_t, destroy)); + if (!this->proposal) + { + DBG1(DBG_IKE, "no proposal found"); + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + + lifetime = sa_payload->get_lifetime(sa_payload); + if (lifetime != this->lifetime) + { + DBG1(DBG_IKE, "received lifetime %us does not match configured " + "lifetime %us", lifetime, this->lifetime); + } + this->lifetime = lifetime; + method = sa_payload->get_auth_method(sa_payload); + if (method != this->method) + { + DBG1(DBG_IKE, "received %N authentication, but configured %N, " + "continue with configured", auth_method_names, method, + auth_method_names, this->method); + } + if (!this->ph1->get_nonce_ke(this->ph1, message)) + { + return send_notify(this, INVALID_PAYLOAD_TYPE); + } + if (!this->ph1->create_hasher(this->ph1, this->proposal)) + { + return send_notify(this, NO_PROPOSAL_CHOSEN); + } + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method, + this->proposal)) + { + return send_notify(this, INVALID_KEY_INFORMATION); + } + + id_payload = (id_payload_t*)message->get_payload(message, ID_V1); + if (!id_payload) + { + DBG1(DBG_IKE, "IDir payload missing"); + return send_delete(this); + } + id = id_payload->get_identification(id_payload); + cid = this->ph1->get_id(this->ph1, this->peer_cfg, FALSE); + if (cid && !id->matches(id, cid)) + { + DBG1(DBG_IKE, "IDir '%Y' does not match to '%Y'", id, cid); + id->destroy(id); + return send_notify(this, INVALID_ID_INFORMATION); + } + this->ike_sa->set_other_id(this->ike_sa, id); + + if (!this->ph1->verify_auth(this->ph1, this->method, message, + id_payload->get_encoded(id_payload))) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + return NEED_MORE; + } + return FAILED; +} + +METHOD(task_t, get_type, task_type_t, + private_aggressive_mode_t *this) +{ + return TASK_AGGRESSIVE_MODE; +} + +METHOD(task_t, migrate, void, + private_aggressive_mode_t *this, ike_sa_t *ike_sa) +{ + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->proposal); + this->ph1->destroy(this->ph1); + chunk_free(&this->id_data); + + this->ike_sa = ike_sa; + this->state = AM_INIT; + this->peer_cfg = NULL; + this->proposal = NULL; + this->ph1 = phase1_create(ike_sa, this->initiator); +} + +METHOD(task_t, destroy, void, + private_aggressive_mode_t *this) +{ + DESTROY_IF(this->peer_cfg); + DESTROY_IF(this->proposal); + this->ph1->destroy(this->ph1); + chunk_free(&this->id_data); + free(this); +} + +/* + * Described in header. + */ +aggressive_mode_t *aggressive_mode_create(ike_sa_t *ike_sa, bool initiator) +{ + private_aggressive_mode_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + }, + .ike_sa = ike_sa, + .ph1 = phase1_create(ike_sa, initiator), + .initiator = initiator, + .state = AM_INIT, + ); + + if (initiator) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.h b/src/libcharon/sa/ikev1/tasks/aggressive_mode.h new file mode 100644 index 000000000..b532addad --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup aggressive_mode aggressive_mode + * @{ @ingroup tasks + */ + +#ifndef AGGRESSIVE_MODE_H_ +#define AGGRESSIVE_MODE_H_ + +typedef struct aggressive_mode_t aggressive_mode_t; + +#include +#include +#include + +/** + * IKEv1 aggressive mode, establishes an IKE_SA without identity protection. + */ +struct aggressive_mode_t { + + /** + * Implements the task_t interface + */ + task_t task; +}; + +/** + * Create a new AGGRESSIVE_MODE task. + * + * @param ike_sa IKE_SA this task works for + * @param initiator TRUE if task initiated locally + * @return task to handle by the task_manager + */ +aggressive_mode_t *aggressive_mode_create(ike_sa_t *ike_sa, bool initiator); + +#endif /** AGGRESSIVE_MODE_H_ @}*/ diff --git a/src/libcharon/sa/task.c b/src/libcharon/sa/task.c index ce61c4088..0c08a2874 100644 --- a/src/libcharon/sa/task.c +++ b/src/libcharon/sa/task.c @@ -37,6 +37,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST, "CHILD_DELETE", "CHILD_REKEY", "MAIN_MODE", + "AGGRESSIVE_MODE", "INFORMATIONAL", "ISAKMP_DELETE", "XAUTH", diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h index 0afdf4351..6b5c92930 100644 --- a/src/libcharon/sa/task.h +++ b/src/libcharon/sa/task.h @@ -71,6 +71,8 @@ enum task_type_t { TASK_CHILD_REKEY, /** IKEv1 main mode */ TASK_MAIN_MODE, + /** IKEv1 aggressive mode */ + TASK_AGGRESSIVE_MODE, /** IKEv1 informational exchange */ TASK_INFORMATIONAL, /** IKEv1 delete using an informational */ From ebc7bcb55013245e74da596292e20dcbf6219a91 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 17:10:18 +0100 Subject: [PATCH 441/534] Encrypt payloads of third aggressive mode message --- src/libcharon/encoding/message.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 46384a5ac..e6036177a 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -510,9 +510,9 @@ static payload_rule_t aggressive_i_rules[] = { {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, {ID_V1, 0, 1, FALSE, FALSE}, - {CERTIFICATE_V1, 0, 1, FALSE, FALSE}, - {SIGNATURE_V1, 0, 1, FALSE, FALSE}, - {HASH_V1, 0, 1, FALSE, FALSE}, + {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, + {SIGNATURE_V1, 0, 1, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, }; /** From a347c1ac437803c23aa8858089d99f4f604fcebc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 17:10:48 +0100 Subject: [PATCH 442/534] Fix sending of CERTREQ/CERT payloads in aggressive mode --- src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c | 9 +++++++-- src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c index 5fbd04aea..b88b9e31a 100644 --- a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c @@ -286,9 +286,14 @@ METHOD(task_t, process_i, status_t, } case AGGRESSIVE: { - if (!use_certs(this, message)) + if (this->state == CR_SA) { - return SUCCESS; + if (!use_certs(this, message)) + { + return SUCCESS; + } + this->state = CR_AUTH; + return NEED_MORE; } return SUCCESS; } diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c index 25c4af6e8..8d0405730 100644 --- a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c @@ -426,6 +426,10 @@ METHOD(task_t, build_r, status_t, switch (this->state) { case CR_SA: + if (this->send_req) + { + build_certreqs(this, message); + } this->state = CR_AUTH; return NEED_MORE; case CR_AUTH: @@ -474,6 +478,7 @@ METHOD(task_t, process_i, status_t, } process_certreqs(this, message); process_certs(this, message); + this->state = CR_AUTH; return SUCCESS; } default: From 5ce59d4c06e000079779fc66cdf9d14995247f3d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 16:32:41 +0000 Subject: [PATCH 443/534] Added an aggressive mode peer_cfg option --- src/conftest/config.c | 2 +- src/libcharon/config/peer_cfg.c | 19 ++++++++++++++++--- src/libcharon/config/peer_cfg.h | 14 +++++++++++--- .../plugins/android/android_service.c | 2 +- src/libcharon/plugins/ha/ha_tunnel.c | 2 +- .../plugins/load_tester/load_tester_config.c | 3 ++- src/libcharon/plugins/maemo/maemo_service.c | 2 +- src/libcharon/plugins/medcli/medcli_config.c | 6 +++--- src/libcharon/plugins/medsrv/medsrv_config.c | 2 +- src/libcharon/plugins/nm/nm_service.c | 2 +- src/libcharon/plugins/sql/sql_config.c | 2 +- src/libcharon/plugins/stroke/stroke_config.c | 2 +- src/libcharon/plugins/uci/uci_config.c | 2 +- 13 files changed, 41 insertions(+), 19 deletions(-) diff --git a/src/conftest/config.c b/src/conftest/config.c index 51d491de5..a62363cd8 100644 --- a/src/conftest/config.c +++ b/src/conftest/config.c @@ -252,7 +252,7 @@ static peer_cfg_t *load_peer_config(private_config_t *this, ike_cfg = load_ike_config(this, settings, config); peer_cfg = peer_cfg_create(config, IKEV2, ike_cfg, CERT_ALWAYS_SEND, - UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, 0, + UNIQUE_NO, 1, 0, 0, 0, 0, FALSE, FALSE, 0, NULL, NULL, FALSE, NULL, NULL); auth = auth_cfg_create(); diff --git a/src/libcharon/config/peer_cfg.c b/src/libcharon/config/peer_cfg.c index fb9d54bfe..b278dc337 100644 --- a/src/libcharon/config/peer_cfg.c +++ b/src/libcharon/config/peer_cfg.c @@ -105,6 +105,11 @@ struct private_peer_cfg_t { */ bool use_mobike; + /** + * Use aggressive mode? + */ + bool aggressive; + /** * Time before starting rekeying */ @@ -381,6 +386,12 @@ METHOD(peer_cfg_t, use_mobike, bool, return this->use_mobike; } +METHOD(peer_cfg_t, use_aggressive, bool, + private_peer_cfg_t *this) +{ + return this->aggressive; +} + METHOD(peer_cfg_t, get_dpd, u_int32_t, private_peer_cfg_t *this) { @@ -574,9 +585,9 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, unique_policy_t unique, u_int32_t keyingtries, u_int32_t rekey_time, u_int32_t reauth_time, u_int32_t jitter_time, u_int32_t over_time, - bool mobike, u_int32_t dpd, host_t *virtual_ip, - char *pool, bool mediation, peer_cfg_t *mediated_by, - identification_t *peer_id) + bool mobike, bool aggressive, u_int32_t dpd, + host_t *virtual_ip, char *pool, bool mediation, + peer_cfg_t *mediated_by, identification_t *peer_id) { private_peer_cfg_t *this; @@ -605,6 +616,7 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, .get_reauth_time = _get_reauth_time, .get_over_time = _get_over_time, .use_mobike = _use_mobike, + .use_aggressive = _use_aggressive, .get_dpd = _get_dpd, .get_virtual_ip = _get_virtual_ip, .get_pool = _get_pool, @@ -632,6 +644,7 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, .jitter_time = jitter_time, .over_time = over_time, .use_mobike = mobike, + .aggressive = aggressive, .dpd = dpd, .virtual_ip = virtual_ip, .pool = strdupnull(pool), diff --git a/src/libcharon/config/peer_cfg.h b/src/libcharon/config/peer_cfg.h index dcbe6aa9e..969ccabf2 100644 --- a/src/libcharon/config/peer_cfg.h +++ b/src/libcharon/config/peer_cfg.h @@ -256,6 +256,13 @@ struct peer_cfg_t { */ bool (*use_mobike) (peer_cfg_t *this); + /** + * Use/Accept aggressive mode with IKEv1?. + * + * @return TRUE to use aggressive mode + */ + bool (*use_aggressive)(peer_cfg_t *this); + /** * Get the DPD check interval. * @@ -357,6 +364,7 @@ struct peer_cfg_t { * @param jitter_time timerange to randomly subtract from rekey/reauth time * @param over_time maximum overtime before closing a rekeying/reauth SA * @param mobike use MOBIKE (RFC4555) if peer supports it + * @param aggressive use/accept aggressive mode with IKEv1 * @param dpd DPD check interval, 0 to disable * @param virtual_ip virtual IP for local host, or NULL * @param pool pool name to get configuration attributes from, or NULL @@ -370,8 +378,8 @@ peer_cfg_t *peer_cfg_create(char *name, ike_version_t ike_version, unique_policy_t unique, u_int32_t keyingtries, u_int32_t rekey_time, u_int32_t reauth_time, u_int32_t jitter_time, u_int32_t over_time, - bool mobike, u_int32_t dpd, host_t *virtual_ip, - char *pool, bool mediation, peer_cfg_t *mediated_by, - identification_t *peer_id); + bool mobike, bool aggressive, u_int32_t dpd, + host_t *virtual_ip, char *pool, bool mediation, + peer_cfg_t *mediated_by, identification_t *peer_id); #endif /** PEER_CFG_H_ @}*/ diff --git a/src/libcharon/plugins/android/android_service.c b/src/libcharon/plugins/android/android_service.c index 8aba925a2..62fd52b12 100644 --- a/src/libcharon/plugins/android/android_service.c +++ b/src/libcharon/plugins/android/android_service.c @@ -277,7 +277,7 @@ static job_requeue_t initiate(private_android_service_t *this) UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, 0, /* mobike, DPD */ + TRUE, FALSE, 0, /* mobike, aggressive, DPD */ host_create_from_string("0.0.0.0", 0) /* virt */, NULL, FALSE, NULL, NULL); /* pool, mediation */ diff --git a/src/libcharon/plugins/ha/ha_tunnel.c b/src/libcharon/plugins/ha/ha_tunnel.c index 1f87c3d86..6f20620f2 100644 --- a/src/libcharon/plugins/ha/ha_tunnel.c +++ b/src/libcharon/plugins/ha/ha_tunnel.c @@ -207,7 +207,7 @@ static void setup_tunnel(private_ha_tunnel_t *this, remote, IKEV2_UDP_PORT); ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); peer_cfg = peer_cfg_create("ha", IKEV2, ike_cfg, CERT_NEVER_SEND, - UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, 30, + UNIQUE_KEEP, 0, 86400, 0, 7200, 3600, FALSE, FALSE, 30, NULL, NULL, FALSE, NULL, NULL); auth_cfg = auth_cfg_create(); diff --git a/src/libcharon/plugins/load_tester/load_tester_config.c b/src/libcharon/plugins/load_tester/load_tester_config.c index 301c9cc63..83853b8de 100644 --- a/src/libcharon/plugins/load_tester/load_tester_config.c +++ b/src/libcharon/plugins/load_tester/load_tester_config.c @@ -253,7 +253,8 @@ static peer_cfg_t* generate_config(private_load_tester_config_t *this, uint num) CERT_SEND_IF_ASKED, UNIQUE_NO, 1, /* keytries */ this->ike_rekey, 0, /* rekey, reauth */ 0, this->ike_rekey, /* jitter, overtime */ - FALSE, this->dpd_delay, /* mobike, dpddelay */ + FALSE, FALSE, /* mobike, aggressive mode */ + this->dpd_delay, /* dpddelay */ this->vip ? this->vip->clone(this->vip) : NULL, this->pool, FALSE, NULL, NULL); if (num) diff --git a/src/libcharon/plugins/maemo/maemo_service.c b/src/libcharon/plugins/maemo/maemo_service.c index 69eac084c..67d2b2984 100644 --- a/src/libcharon/plugins/maemo/maemo_service.c +++ b/src/libcharon/plugins/maemo/maemo_service.c @@ -332,7 +332,7 @@ static gboolean initiate_connection(private_maemo_service_t *this, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, 0, /* mobike, DPD */ + TRUE, FALSE, 0, /* mobike, aggressive, DPD */ host_create_from_string("0.0.0.0", 0) /* virt */, NULL, FALSE, NULL, NULL); /* pool, mediation */ diff --git a/src/libcharon/plugins/medcli/medcli_config.c b/src/libcharon/plugins/medcli/medcli_config.c index f768eeb4e..7fa0152bd 100644 --- a/src/libcharon/plugins/medcli/medcli_config.c +++ b/src/libcharon/plugins/medcli/medcli_config.c @@ -126,7 +126,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, this->dpd, /* mobike, dpddelay */ + TRUE, FALSE, this->dpd, /* mobike, aggressive, dpddelay */ NULL, NULL, /* vip, pool */ TRUE, NULL, NULL); /* mediation, med by, peer id */ e->destroy(e); @@ -163,7 +163,7 @@ METHOD(backend_t, get_peer_cfg_by_name, peer_cfg_t*, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, this->dpd, /* mobike, dpddelay */ + TRUE, FALSE, this->dpd, /* mobike, aggressive, dpddelay */ NULL, NULL, /* vip, pool */ FALSE, med_cfg, /* mediation, med by */ identification_create_from_encoding(ID_KEY_ID, other)); @@ -238,7 +238,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, this->dpd, /* mobike, dpddelay */ + TRUE, FALSE, this->dpd, /* mobike, aggr., dpddelay */ NULL, NULL, /* vip, pool */ FALSE, NULL, NULL); /* mediation, med by, peer id */ diff --git a/src/libcharon/plugins/medsrv/medsrv_config.c b/src/libcharon/plugins/medsrv/medsrv_config.c index fc3963a3d..366558ac2 100644 --- a/src/libcharon/plugins/medsrv/medsrv_config.c +++ b/src/libcharon/plugins/medsrv/medsrv_config.c @@ -92,7 +92,7 @@ METHOD(backend_t, create_peer_cfg_enumerator, enumerator_t*, CERT_NEVER_SEND, UNIQUE_REPLACE, 1, this->rekey*60, 0, /* keytries, rekey, reauth */ this->rekey*5, this->rekey*3, /* jitter, overtime */ - TRUE, this->dpd, /* mobike, dpddelay */ + TRUE, FALSE, this->dpd, /* mobike, aggr., dpddelay */ NULL, NULL, /* vip, pool */ TRUE, NULL, NULL); /* mediation, med by, peer id */ e->destroy(e); diff --git a/src/libcharon/plugins/nm/nm_service.c b/src/libcharon/plugins/nm/nm_service.c index 788291531..d51b699ae 100644 --- a/src/libcharon/plugins/nm/nm_service.c +++ b/src/libcharon/plugins/nm/nm_service.c @@ -503,7 +503,7 @@ static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, CERT_SEND_IF_ASKED, UNIQUE_REPLACE, 1, /* keyingtries */ 36000, 0, /* rekey 10h, reauth none */ 600, 600, /* jitter, over 10min */ - TRUE, 0, /* mobike, DPD */ + TRUE, FALSE, 0, /* mobike, aggressive, DPD */ virtual ? host_create_from_string("0.0.0.0", 0) : NULL, NULL, FALSE, NULL, NULL); /* pool, mediation */ auth = auth_cfg_create(); diff --git a/src/libcharon/plugins/sql/sql_config.c b/src/libcharon/plugins/sql/sql_config.c index ef181f66c..b06bd3706 100644 --- a/src/libcharon/plugins/sql/sql_config.c +++ b/src/libcharon/plugins/sql/sql_config.c @@ -370,7 +370,7 @@ static peer_cfg_t *build_peer_cfg(private_sql_config_t *this, enumerator_t *e, peer_cfg = peer_cfg_create( name, IKEV2, ike, cert_policy, uniqueid, keyingtries, rekeytime, reauthtime, jitter, overtime, - mobike, dpd_delay, vip, pool, + mobike, FALSE, dpd_delay, vip, pool, mediation, mediated_cfg, peer_id); auth = auth_cfg_create(); auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_method); diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index 08339a475..e39233b7e 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -689,7 +689,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, msg->add_conn.version, ike_cfg, msg->add_conn.me.sendcert, unique, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, - msg->add_conn.mobike, msg->add_conn.dpd.delay, + msg->add_conn.mobike, FALSE, msg->add_conn.dpd.delay, vip, msg->add_conn.other.sourceip_mask ? msg->add_conn.name : msg->add_conn.other.sourceip, msg->add_conn.ikeme.mediation, mediated_by, peer_id); diff --git a/src/libcharon/plugins/uci/uci_config.c b/src/libcharon/plugins/uci/uci_config.c index 4e48b933a..b4e99c3f2 100644 --- a/src/libcharon/plugins/uci/uci_config.c +++ b/src/libcharon/plugins/uci/uci_config.c @@ -175,7 +175,7 @@ METHOD(enumerator_t, peer_enumerator_enumerate, bool, name, IKEV2, ike_cfg, CERT_SEND_IF_ASKED, UNIQUE_NO, 1, create_rekey(ike_rekey), 0, /* keytries, rekey, reauth */ 1800, 900, /* jitter, overtime */ - TRUE, 60, /* mobike, dpddelay */ + TRUE, FALSE, 60, /* mobike, aggr., dpddelay */ NULL, NULL, /* vip, pool */ FALSE, NULL, NULL); /* mediation, med by, peer id */ auth = auth_cfg_create(); From 91c212fd6a69b3ecc721b091880b7c01ba9779b7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 16:33:15 +0000 Subject: [PATCH 444/534] Select IKEv1 configurations by main/aggressive mode option --- src/libcharon/sa/ikev1/phase1.c | 6 ++++-- src/libcharon/sa/ikev1/phase1.h | 3 ++- src/libcharon/sa/ikev1/tasks/aggressive_mode.c | 2 +- src/libcharon/sa/ikev1/tasks/main_mode.c | 2 +- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c index 8d844ac5a..ed5fbe5c9 100644 --- a/src/libcharon/sa/ikev1/phase1.c +++ b/src/libcharon/sa/ikev1/phase1.c @@ -416,7 +416,8 @@ METHOD(phase1_t, get_auth_method, auth_method_t, } METHOD(phase1_t, select_config, peer_cfg_t*, - private_phase1_t *this, auth_method_t method, identification_t *id) + private_phase1_t *this, auth_method_t method, bool aggressive, + identification_t *id) { enumerator_t *enumerator; peer_cfg_t *current, *found = NULL; @@ -430,7 +431,8 @@ METHOD(phase1_t, select_config, peer_cfg_t*, me, other, NULL, id, IKEV1); while (enumerator->enumerate(enumerator, ¤t)) { - if (get_auth_method(this, current) == method) + if (get_auth_method(this, current) == method && + current->use_aggressive(current) == aggressive) { found = current->get_ref(current); break; diff --git a/src/libcharon/sa/ikev1/phase1.h b/src/libcharon/sa/ikev1/phase1.h index 22b9dd68a..994c85be7 100644 --- a/src/libcharon/sa/ikev1/phase1.h +++ b/src/libcharon/sa/ikev1/phase1.h @@ -91,11 +91,12 @@ struct phase1_t { * Select a peer config as responder. * * @param method used authentication method + * @param aggressive TRUE to get an aggressive mode config * @param id initiator identity * @return selected peer config, NULL if none found */ peer_cfg_t* (*select_config)(phase1_t *this, auth_method_t method, - identification_t *id); + bool aggressive, identification_t *id); /** * Get configured identity from peer config. diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c index 2c4e14e43..483351db2 100644 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -380,7 +380,7 @@ METHOD(task_t, process_r, status_t, this->id_data = id_payload->get_encoded(id_payload); this->ike_sa->set_other_id(this->ike_sa, id); this->peer_cfg = this->ph1->select_config(this->ph1, - this->method, id); + this->method, TRUE, id); if (!this->peer_cfg) { DBG1(DBG_IKE, "no peer config found"); diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index a3b567870..52c2258e5 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -393,7 +393,7 @@ METHOD(task_t, process_r, status_t, id = id_payload->get_identification(id_payload); this->ike_sa->set_other_id(this->ike_sa, id); this->peer_cfg = this->ph1->select_config(this->ph1, - this->method, id); + this->method, FALSE, id); if (!this->peer_cfg) { DBG1(DBG_IKE, "no peer config found"); From 830ab2ae7f71d4d46df4b10109d5c679fe4dd77b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 16:35:02 +0000 Subject: [PATCH 445/534] Handle aggressive mode task in IKEv1 task manager --- src/libcharon/sa/ikev1/task_manager_v1.c | 42 ++++++++++++++++++++---- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 364b6db38..2dd0df9f4 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -346,9 +347,13 @@ METHOD(task_manager_t, initiate, status_t, if (activate_task(this, TASK_MAIN_MODE)) { exchange = ID_PROT; - activate_task(this, TASK_ISAKMP_CERT_POST); - activate_task(this, TASK_ISAKMP_NATD); } + else if (activate_task(this, TASK_AGGRESSIVE_MODE)) + { + exchange = AGGRESSIVE; + } + activate_task(this, TASK_ISAKMP_CERT_POST); + activate_task(this, TASK_ISAKMP_NATD); break; case IKE_CONNECTING: if (activate_task(this, TASK_ISAKMP_DELETE)) @@ -418,6 +423,9 @@ METHOD(task_manager_t, initiate, status_t, case TASK_MAIN_MODE: exchange = ID_PROT; break; + case TASK_AGGRESSIVE_MODE: + exchange = AGGRESSIVE; + break; case TASK_QUICK_MODE: exchange = QUICK_MODE; break; @@ -719,8 +727,17 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); break; case AGGRESSIVE: - /* TODO-IKEv1: agressive mode */ - return FAILED; + task = (task_t *)isakmp_vendor_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)isakmp_cert_pre_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t *)aggressive_mode_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t*)isakmp_cert_post_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + task = (task_t *)isakmp_natd_create(this->ike_sa, FALSE); + this->passive_tasks->insert_last(this->passive_tasks, task); + break; case QUICK_MODE: if (this->ike_sa->get_state(this->ike_sa) != IKE_ESTABLISHED) { @@ -1096,6 +1113,8 @@ static bool has_queued(private_task_manager_t *this, task_type_t type) METHOD(task_manager_t, queue_ike, void, private_task_manager_t *this) { + peer_cfg_t *peer_cfg; + if (!has_queued(this, TASK_ISAKMP_VENDOR)) { queue_task(this, (task_t*)isakmp_vendor_create(this->ike_sa, TRUE)); @@ -1104,9 +1123,20 @@ METHOD(task_manager_t, queue_ike, void, { queue_task(this, (task_t*)isakmp_cert_pre_create(this->ike_sa, TRUE)); } - if (!has_queued(this, TASK_MAIN_MODE)) + peer_cfg = this->ike_sa->get_peer_cfg(this->ike_sa); + if (peer_cfg->use_aggressive(peer_cfg)) { - queue_task(this, (task_t*)main_mode_create(this->ike_sa, TRUE)); + if (!has_queued(this, TASK_AGGRESSIVE_MODE)) + { + queue_task(this, (task_t*)aggressive_mode_create(this->ike_sa, TRUE)); + } + } + else + { + if (!has_queued(this, TASK_MAIN_MODE)) + { + queue_task(this, (task_t*)main_mode_create(this->ike_sa, TRUE)); + } } if (!has_queued(this, TASK_ISAKMP_CERT_POST)) { From e129168ba6299c8d2384381f4c06b99ded548030 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 17:44:43 +0100 Subject: [PATCH 446/534] Added a "aggressive" ipsec.conf connection option --- src/libcharon/plugins/stroke/stroke_config.c | 2 +- src/starter/args.c | 1 + src/starter/confread.h | 1 + src/starter/keywords.h | 1 + src/starter/keywords.txt | 1 + src/starter/starterstroke.c | 1 + src/stroke/stroke_msg.h | 1 + 7 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index e39233b7e..bc2518a08 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -689,7 +689,7 @@ static peer_cfg_t *build_peer_cfg(private_stroke_config_t *this, msg->add_conn.version, ike_cfg, msg->add_conn.me.sendcert, unique, msg->add_conn.rekey.tries, rekey, reauth, jitter, over, - msg->add_conn.mobike, FALSE, msg->add_conn.dpd.delay, + msg->add_conn.mobike, msg->add_conn.aggressive, msg->add_conn.dpd.delay, vip, msg->add_conn.other.sourceip_mask ? msg->add_conn.name : msg->add_conn.other.sourceip, msg->add_conn.ikeme.mediation, mediated_by, peer_id); diff --git a/src/starter/args.c b/src/starter/args.c index 65d0a753c..88133dd53 100644 --- a/src/starter/args.c +++ b/src/starter/args.c @@ -204,6 +204,7 @@ static const token_info_t token_info[] = { ARG_MISC, 0, NULL /* KW_PFS */ }, { ARG_MISC, 0, NULL /* KW_COMPRESS */ }, { ARG_ENUM, offsetof(starter_conn_t, install_policy), LST_bool }, + { ARG_ENUM, offsetof(starter_conn_t, aggressive), LST_bool }, { ARG_MISC, 0, NULL /* KW_AUTH */ }, { ARG_MISC, 0, NULL /* KW_AUTHBY */ }, { ARG_MISC, 0, NULL /* KW_EAP */ }, diff --git a/src/starter/confread.h b/src/starter/confread.h index 47bd84603..25f37e633 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -132,6 +132,7 @@ struct starter_conn { sa_family_t addr_family; sa_family_t tunnel_addr_family; bool install_policy; + bool aggressive; starter_end_t left, right; unsigned long id; diff --git a/src/starter/keywords.h b/src/starter/keywords.h index 02be919ea..71e31e9f5 100644 --- a/src/starter/keywords.h +++ b/src/starter/keywords.h @@ -67,6 +67,7 @@ typedef enum { KW_PFS, KW_COMPRESS, KW_INSTALLPOLICY, + KW_AGGRESSIVE, KW_AUTH, KW_AUTHBY, KW_EAP, diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt index 548fa2f70..bd1f9304c 100644 --- a/src/starter/keywords.txt +++ b/src/starter/keywords.txt @@ -61,6 +61,7 @@ type, KW_TYPE pfs, KW_PFS compress, KW_COMPRESS installpolicy, KW_INSTALLPOLICY +aggressive, KW_AGGRESSIVE auth, KW_AUTH authby, KW_AUTHBY keylife, KW_KEYLIFE diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index c4d9fa2e9..9fbfffc83 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -265,6 +265,7 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) msg.add_conn.force_encap = (conn->policy & POLICY_FORCE_ENCAP) != 0; msg.add_conn.ipcomp = (conn->policy & POLICY_COMPRESS) != 0; msg.add_conn.install_policy = conn->install_policy; + msg.add_conn.aggressive = conn->aggressive; msg.add_conn.crl_policy = cfg->setup.strictcrlpolicy; msg.add_conn.unique = cfg->setup.uniqueids; msg.add_conn.algorithms.ike = push_string(&msg, conn->ike); diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index af566b952..825228e9d 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -249,6 +249,7 @@ struct stroke_msg_t { char *xauth_identity; int mode; int mobike; + int aggressive; int force_encap; int ipcomp; time_t inactivity; From c40963b457f27464bc88390c7e6419d461264b47 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 9 Jan 2012 18:12:17 +0100 Subject: [PATCH 447/534] Enforce encapsulation mode of configuration, in case initiator proposes both --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index fb7e1a0ff..dedeab189 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -765,7 +765,6 @@ METHOD(task_t, process_r, status_t, get_lifetimes(this); apply_lifetimes(this, sa_payload); - this->mode = sa_payload->get_encap_mode(sa_payload, &udp); if (!this->proposal) { @@ -799,6 +798,7 @@ METHOD(task_t, process_r, status_t, check_for_rekeyed_child(this); + udp = this->ike_sa->has_condition(this->ike_sa, COND_NAT_ANY); this->child_sa = child_sa_create( this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), @@ -846,6 +846,7 @@ METHOD(task_t, build_r, status_t, this->proposal->set_spi(this->proposal, this->spi_r); udp = this->child_sa->has_encap(this->child_sa); + this->mode = this->config->get_mode(this->config); if (udp && this->mode == MODE_TRANSPORT) { /* TODO-IKEv1: disable NAT-T for TRANSPORT mode by default? */ From bd8d1f1d9c96a816a7b172c05a9a51d6af22b758 Mon Sep 17 00:00:00 2001 From: Tobias Brunner Date: Tue, 10 Jan 2012 10:58:29 +0100 Subject: [PATCH 448/534] Accept unencrypted Aggressive Mode messages. Racoon does not encrypt the third message during Aggressive Mode. --- src/libcharon/encoding/message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index e6036177a..99aca870a 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1882,7 +1882,8 @@ static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) encryption->destroy(encryption); } if (payload_is_known(type) && !was_encrypted && - !is_connectivity_check(this, payload)) + !is_connectivity_check(this, payload) && + this->exchange_type != AGGRESSIVE) { rule = get_payload_rule(this, type); if (!rule || rule->encrypted) From 37c12bd31e1429105ba592593cc9410ffd7f6d57 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 11:23:04 +0100 Subject: [PATCH 449/534] Streamlined debug output when initiating IKEv1 IKE_SAs --- src/libcharon/sa/ikev1/tasks/aggressive_mode.c | 2 +- src/libcharon/sa/ikev1/tasks/main_mode.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c index 483351db2..1fe36a9d5 100644 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -194,7 +194,7 @@ METHOD(task_t, build_i, status_t, packet_t *packet; u_int16_t group; - DBG0(DBG_IKE, "initiating aggressive mode IKE_SA %s[%d] to %H", + DBG0(DBG_IKE, "initiating Aggressive Mode IKE_SA %s[%d] to %H", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa)); diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index 52c2258e5..ba1a9ad1d 100644 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -203,7 +203,7 @@ METHOD(task_t, build_i, status_t, linked_list_t *proposals; packet_t *packet; - DBG0(DBG_IKE, "initiating main mode IKE_SA %s[%d] to %H", + DBG0(DBG_IKE, "initiating Main Mode IKE_SA %s[%d] to %H", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa)); From 346dad30d41db490367824617bd0b6ddd86f991f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 11:37:06 +0100 Subject: [PATCH 450/534] Request and handle retransmission of a lost third aggressive mode message --- src/libcharon/sa/ikev1/task_manager_v1.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 2dd0df9f4..f7415a5ad 100644 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -529,9 +529,10 @@ METHOD(task_manager_t, initiate, status_t, message->destroy(message); return retransmit(this, this->initiating.seqnr); } - if (message->get_exchange_type(message) == QUICK_MODE) - { /* keep the packet for retransmission in quick mode. The responder - * might request a retransmission */ + if (message->get_exchange_type(message) == QUICK_MODE || + message->get_exchange_type(message) == AGGRESSIVE) + { /* keep the packet for retransmission in quick/aggressive mode. + * The responder might request a retransmission */ charon->sender->send(charon->sender, this->initiating.packet->clone(this->initiating.packet)); } @@ -598,7 +599,8 @@ static status_t build_response(private_task_manager_t *this, message_t *request) continue; case NEED_MORE: /* processed, but task needs another exchange */ - if (task->get_type(task) == TASK_QUICK_MODE) + if (task->get_type(task) == TASK_QUICK_MODE || + task->get_type(task) == TASK_AGGRESSIVE_MODE) { /* we rely on initiator retransmission, except for * three-message exchanges */ expect_request = TRUE; @@ -960,7 +962,8 @@ METHOD(task_manager_t, process_message, status_t, { if (this->initiating.packet && i == (this->initiating.old_hash_pos % MAX_OLD_HASHES) && - msg->get_exchange_type(msg) == QUICK_MODE) + (msg->get_exchange_type(msg) == QUICK_MODE || + msg->get_exchange_type(msg) == AGGRESSIVE)) { DBG1(DBG_IKE, "received retransmit of response with ID %u, " "resending last request", mid); From 36c8169629048bd6da234bdb691b781376fd3a93 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 10 Jan 2012 14:31:51 +0100 Subject: [PATCH 451/534] DPD_R_U_THERE defines added --- src/libcharon/encoding/payloads/notify_payload.c | 12 +++++++++++- src/libcharon/encoding/payloads/notify_payload.h | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) mode change 100644 => 100755 src/libcharon/encoding/payloads/notify_payload.c mode change 100644 => 100755 src/libcharon/encoding/payloads/notify_payload.h diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c old mode 100644 new mode 100755 index 6f3784219..5918eb426 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -108,7 +108,10 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, IPSEC_REPLAY_COUNTER_SYNC, MS_NOTI "IPSEC_REPLAY_COUNTER_SYNC"); ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, IPSEC_REPLAY_COUNTER_SYNC, "INITIAL_CONTACT"); -ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, INITIAL_CONTACT_IKEV1, +ENUM_NEXT(notify_type_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1, + "DPD_R_U_THERE", + "DPD_R_U_THERE_ACK"); +ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, DPD_R_U_THERE_ACK, "USE_BEET_MODE"); ENUM_NEXT(notify_type_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE, "ME_MEDIATION", @@ -485,6 +488,13 @@ METHOD(payload_t, verify, status_t, bad_length = TRUE; } break; + case DPD_R_U_THERE: + case DPD_R_U_THERE_ACK: + if (this->notify_data.len != 4) + { + bad_length = TRUE; + } + break; default: /* TODO: verify */ break; diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h old mode 100644 new mode 100755 index d105cc21a..597962dd1 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -140,6 +140,9 @@ enum notify_type_t { IPSEC_REPLAY_COUNTER_SYNC = 16423, /* IKEv1 initial contact */ INITIAL_CONTACT_IKEV1 = 24578, + /* IKEv1 DPD */ + DPD_R_U_THERE = 36136, + DPD_R_U_THERE_ACK = 36137, /* BEET mode, not even a draft yet. private use */ USE_BEET_MODE = 40961, /* IKE-ME, private use */ From 3e6b740336e8df61b1a94a1b21f142731f0fd912 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 10 Jan 2012 14:37:39 +0100 Subject: [PATCH 452/534] Isakmp_dpd task added. --- src/libcharon/Makefile.am | 1 + src/libcharon/sa/ikev1/task_manager_v1.c | 85 +++++- src/libcharon/sa/ikev1/task_manager_v1.h | 5 + .../sa/ikev1/tasks/aggressive_mode.c | 2 +- src/libcharon/sa/ikev1/tasks/informational.c | 36 ++- src/libcharon/sa/ikev1/tasks/informational.h | 3 +- src/libcharon/sa/ikev1/tasks/isakmp_dpd.c | 278 ++++++++++++++++++ src/libcharon/sa/ikev1/tasks/isakmp_dpd.h | 38 +++ src/libcharon/sa/ikev1/tasks/main_mode.c | 2 +- src/libcharon/sa/ikev1/tasks/quick_mode.c | 2 +- src/libcharon/sa/task.h | 3 + 11 files changed, 446 insertions(+), 9 deletions(-) mode change 100644 => 100755 src/libcharon/Makefile.am mode change 100644 => 100755 src/libcharon/sa/ikev1/task_manager_v1.c mode change 100644 => 100755 src/libcharon/sa/ikev1/task_manager_v1.h mode change 100644 => 100755 src/libcharon/sa/ikev1/tasks/aggressive_mode.c mode change 100644 => 100755 src/libcharon/sa/ikev1/tasks/informational.c mode change 100644 => 100755 src/libcharon/sa/ikev1/tasks/informational.h create mode 100755 src/libcharon/sa/ikev1/tasks/isakmp_dpd.c create mode 100755 src/libcharon/sa/ikev1/tasks/isakmp_dpd.h mode change 100644 => 100755 src/libcharon/sa/ikev1/tasks/main_mode.c mode change 100644 => 100755 src/libcharon/sa/ikev1/tasks/quick_mode.c mode change 100644 => 100755 src/libcharon/sa/task.h diff --git a/src/libcharon/Makefile.am b/src/libcharon/Makefile.am old mode 100644 new mode 100755 index c85c472b8..d5e139412 --- a/src/libcharon/Makefile.am +++ b/src/libcharon/Makefile.am @@ -113,6 +113,7 @@ sa/ikev1/tasks/isakmp_cert_post.c sa/ikev1/tasks/isakmp_cert_post.h \ sa/ikev1/tasks/isakmp_natd.c sa/ikev1/tasks/isakmp_natd.h \ sa/ikev1/tasks/isakmp_vendor.c sa/ikev1/tasks/isakmp_vendor.h \ sa/ikev1/tasks/isakmp_delete.c sa/ikev1/tasks/isakmp_delete.h \ +sa/ikev1/tasks/isakmp_dpd.c sa/ikev1/tasks/isakmp_dpd.h \ sa/ikev1/tasks/xauth.c sa/ikev1/tasks/xauth.h \ sa/ikev1/tasks/quick_mode.c sa/ikev1/tasks/quick_mode.h \ sa/ikev1/tasks/quick_delete.c sa/ikev1/tasks/quick_delete.h \ diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c old mode 100644 new mode 100755 index f7415a5ad..7e1ff616a --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -31,6 +31,8 @@ #include #include #include +#include + #include #include @@ -197,6 +199,16 @@ struct private_task_manager_t { * Base to calculate retransmission timeout */ double retransmit_base; + + /** + * Sequence number for sending DPD requests + */ + u_int32_t dpd_send_seqnr; + + /** + * Sequence number for received DPD requests + */ + u_int32_t dpd_rec_seqnr; }; /** @@ -406,6 +418,13 @@ METHOD(task_manager_t, initiate, status_t, new_mid = TRUE; break; } + + if (activate_task(this, TASK_ISAKMP_DPD)) + { + exchange = INFORMATIONAL_V1; + new_mid = TRUE; + break; + } break; default: break; @@ -580,7 +599,20 @@ static status_t build_response(private_task_manager_t *this, message_t *request) /* send response along the path the request came in */ message->set_source(message, me->clone(me)); message->set_destination(message, other->clone(other)); - message->set_message_id(message, request->get_message_id(request)); + + /* Create new message id for informational exchanges*/ + if (request->get_exchange_type(request) == INFORMATIONAL_V1) + { + u_int32_t message_id; + + this->rng->get_bytes(this->rng, sizeof(message_id), + (void*)&message_id); + message->set_message_id(message, message_id); + } + else + { + message->set_message_id(message, request->get_message_id(request)); + } message->set_request(message, FALSE); this->responding.mid = request->get_message_id(request); @@ -710,6 +742,7 @@ static status_t process_request(private_task_manager_t *this, enumerator_t *enumerator; task_t *task = NULL; bool send_response = FALSE; + bool informational = FALSE; if (message->get_exchange_type(message) == INFORMATIONAL_V1 || this->passive_tasks->get_count(this->passive_tasks) == 0) @@ -752,8 +785,9 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); break; case INFORMATIONAL_V1: - task = (task_t *)informational_create(this->ike_sa, NULL); + task = (task_t *)informational_create(this->ike_sa, NULL, this->dpd_rec_seqnr); this->passive_tasks->insert_first(this->passive_tasks, task); + informational = TRUE; break; case TRANSACTION: if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) @@ -784,6 +818,15 @@ static status_t process_request(private_task_manager_t *this, case NEED_MORE: /* processed, but task needs at least another call to build() */ send_response = TRUE; + if (informational && !this->dpd_rec_seqnr) + { + /* Update the received DPD sequence number if it the first received one */ + if (task->get_type(task) == TASK_ISAKMP_DPD) + { + isakmp_dpd_t *isakmp_dpd = (isakmp_dpd_t *)task; + this->dpd_rec_seqnr = isakmp_dpd->get_dpd_seqnr(isakmp_dpd); + } + } continue; case ALREADY_DONE: send_response = FALSE; @@ -950,6 +993,7 @@ METHOD(task_manager_t, process_message, status_t, u_int32_t hash, mid, i; host_t *me, *other; status_t status; + bool dpd_response = FALSE; /* TODO-IKEv1: update hosts more selectively */ me = msg->get_destination(msg); @@ -977,7 +1021,27 @@ METHOD(task_manager_t, process_message, status_t, } } - if ((mid && mid == this->initiating.mid) || + /* DPD Acks are not sent with a same message ID as the request.*/ + if (msg->get_exchange_type(msg) == INFORMATIONAL_V1 && + this->active_tasks->get_count(this->active_tasks)) + { + enumerator_t *enumerator; + task_t *task; + /* In case of ongoing DPD request, let the DPD task handle all information exchanges. */ + enumerator = this->active_tasks->create_enumerator(this->active_tasks); + while (enumerator->enumerate(enumerator, (void**)&task)) + { + if (task->get_type(task) == TASK_ISAKMP_DPD) + { + dpd_response = TRUE; + break; + } + } + enumerator->destroy(enumerator); + } + + + if ((mid && mid == this->initiating.mid) || dpd_response || (this->initiating.mid == 0 && msg->get_exchange_type(msg) == this->initiating.type && this->active_tasks->get_count(this->active_tasks))) @@ -1271,10 +1335,16 @@ METHOD(task_manager_t, queue_child_delete, void, spi, FALSE, expired)); } +METHOD(task_manager_v1_t, get_dpd_seqnr, u_int32_t, + private_task_manager_t *this) +{ + return this->dpd_send_seqnr++; +} + METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { - /* TODO-IKEv1: DPD checking */ + queue_task(this, (task_t*)isakmp_dpd_create(this->ike_sa, NULL, _get_dpd_seqnr(&this->public))); } METHOD(task_manager_t, adopt_tasks, void, @@ -1401,6 +1471,7 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .create_task_enumerator = _create_task_enumerator, .destroy = _destroy, }, + .get_dpd_seqnr = _get_dpd_seqnr, }, .ike_sa = ike_sa, .initiating.type = EXCHANGE_TYPE_UNDEFINED, @@ -1417,5 +1488,11 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) "charon.retransmit_base", RETRANSMIT_BASE), ); + this->rng->get_bytes(this->rng, sizeof(this->dpd_send_seqnr), + (void*)&this->dpd_send_seqnr); + + this->dpd_send_seqnr &= 0x7FFFFFFF; + return &this->public; } + diff --git a/src/libcharon/sa/ikev1/task_manager_v1.h b/src/libcharon/sa/ikev1/task_manager_v1.h old mode 100644 new mode 100755 index 99cd35e32..58b20d0c2 --- a/src/libcharon/sa/ikev1/task_manager_v1.h +++ b/src/libcharon/sa/ikev1/task_manager_v1.h @@ -34,6 +34,11 @@ struct task_manager_v1_t { * Implements task_manager_t. */ task_manager_t task_manager; + + /** + * Get new sequence number to use for sending DPD request. + */ + u_int32_t (*get_dpd_seqnr) (task_manager_v1_t *this); }; /** diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c old mode 100644 new mode 100755 index 1fe36a9d5..df0c94b28 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -164,7 +164,7 @@ static status_t send_notify(private_aggressive_mode_t *this, notify_type_t type) notify->set_spi_data(notify, spi); this->ike_sa->queue_task(this->ike_sa, - (task_t*)informational_create(this->ike_sa, notify)); + (task_t*)informational_create(this->ike_sa, notify, 0)); /* cancel all active/passive tasks in favour of informational */ return ALREADY_DONE; } diff --git a/src/libcharon/sa/ikev1/tasks/informational.c b/src/libcharon/sa/ikev1/tasks/informational.c old mode 100644 new mode 100755 index 999b497dc..2af641e86 --- a/src/libcharon/sa/ikev1/tasks/informational.c +++ b/src/libcharon/sa/ikev1/tasks/informational.c @@ -18,6 +18,8 @@ #include #include #include +#include + #include typedef struct private_informational_t private_informational_t; @@ -46,6 +48,16 @@ struct private_informational_t { * Delete subtask */ task_t *del; + + /** + * DPD subtask + */ + task_t *dpd; + + /** + * DPD sequence number + */ + u_int32_t dpd_seqnr; }; METHOD(task_t, build_i, status_t, @@ -80,6 +92,15 @@ METHOD(task_t, process_r, status_t, this->ike_sa->set_condition(this->ike_sa, COND_INIT_CONTACT_SEEN, TRUE); } + else if (type == DPD_R_U_THERE) + { + DBG3(DBG_IKE, "received DPD request"); + this->dpd = (task_t*)isakmp_dpd_create(this->ike_sa, notify, this->dpd_seqnr); + } + else if (type == DPD_R_U_THERE_ACK) + { + DBG3(DBG_IKE, "received DPD request ack"); + } else if (type < 16384) { DBG1(DBG_IKE, "received %N error notify", @@ -123,6 +144,11 @@ METHOD(task_t, process_r, status_t, { return this->del->process(this->del, message); } + + if (this->dpd && status == SUCCESS) + { + return this->dpd->process(this->dpd, message); + } return status; } @@ -133,6 +159,13 @@ METHOD(task_t, build_r, status_t, { return this->del->build(this->del, message); } + + if (this->dpd) + { + status_t status = this->dpd->build(this->dpd, message); + this->dpd->destroy(this->dpd); + return status; + } return FAILED; } @@ -165,7 +198,7 @@ METHOD(task_t, destroy, void, /* * Described in header. */ -informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify) +informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify, u_int32_t dpd_seqnr) { private_informational_t *this; @@ -179,6 +212,7 @@ informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify }, .ike_sa = ike_sa, .notify = notify, + .dpd_seqnr = dpd_seqnr, ); if (notify) diff --git a/src/libcharon/sa/ikev1/tasks/informational.h b/src/libcharon/sa/ikev1/tasks/informational.h old mode 100644 new mode 100755 index f1543dc58..59b811000 --- a/src/libcharon/sa/ikev1/tasks/informational.h +++ b/src/libcharon/sa/ikev1/tasks/informational.h @@ -44,8 +44,9 @@ struct informational_t { * * @param ike_sa IKE_SA this task works for * @param notify notify to send as initiator, NULL if responder + * @param dpd_seqnr DPD sequence number, incoming or outgoing * @return task to handle by the task_manager */ -informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify); +informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify, u_int32_t dpd_seqnr); #endif /** INFORMATIONAL_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c new file mode 100755 index 000000000..ec0a1eddc --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c @@ -0,0 +1,278 @@ +#include "isakmp_dpd.h" + +#include +#include + +#include + +#ifdef SLIPSTREAM +/* Should be the last include */ +#include +#endif /* SLIPSTREAM */ + +typedef struct private_isakmp_dpd_t private_isakmp_dpd_t; + +/** + * Private members of a isakmp_dpd_t task. + */ +struct private_isakmp_dpd_t { + + /** + * Public methods and task_t interface. + */ + isakmp_dpd_t public; + + /** + * Sequence number. + */ + u_int32_t seqnr; + + /** + * Notify payload, only provided for requests. + */ + notify_payload_t *notify; + + /** + * IKE SA we are serving. + */ + ike_sa_t *ike_sa; +}; + +/** + * Get DPD sequence number from notify payload. + */ +static bool get_seqnr(notify_payload_t *notify, u_int32_t *seqnr) +{ + chunk_t chunk = notify->get_notification_data(notify); + + if( chunk.ptr && chunk.len == 4) + { + u_int32_t seqnr_read = *((u_int32_t*)chunk.ptr); + + *seqnr = ntohl(seqnr_read); + + return TRUE; + } + + DBG1(DBG_IKE, "no DPD seqnr received"); + + return FALSE; +} + +/** + * Add notify payload to message. + */ +static void add_notify(private_isakmp_dpd_t *this, message_t *message, notify_type_t type) +{ + notify_payload_t *notify; + + ike_sa_id_t *ike_sa_id; + u_int64_t spi_i, spi_r; + u_int32_t seqnr; + chunk_t spi; + + notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, + PROTO_IKE, type); + + seqnr = htonl(this->seqnr); + ike_sa_id = this->ike_sa->get_id(this->ike_sa); + spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); + spi_r = ike_sa_id->get_responder_spi(ike_sa_id); + spi = chunk_cata("cc", chunk_from_thing(spi_i), chunk_from_thing(spi_r)); + + notify->set_spi_data(notify, spi); + notify->set_notification_data(notify, chunk_from_thing(seqnr)); + + message->add_payload(message, (payload_t*)notify); +} + +METHOD(isakmp_dpd_t, get_dpd_seqnr, u_int32_t, + private_isakmp_dpd_t *this) +{ + return this->seqnr; +} + +METHOD(task_t, build_i, status_t, + private_isakmp_dpd_t *this, message_t *message) +{ + add_notify(this, message, DPD_R_U_THERE); + + return NEED_MORE; +} + +METHOD(task_t, build_r, status_t, + private_isakmp_dpd_t *this, message_t *message) +{ + add_notify(this, message, DPD_R_U_THERE_ACK); + + return SUCCESS; +} + +METHOD(task_t, process_i, status_t, + private_isakmp_dpd_t *this, message_t *message) +{ + enumerator_t *enumerator; + notify_payload_t *notify; + notify_type_t type; + payload_t *payload; + task_t *info_task = NULL; + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + switch (payload->get_type(payload)) + { + case NOTIFY_V1: + notify = (notify_payload_t*)payload; + type = notify->get_notify_type(notify); + + if (type == DPD_R_U_THERE_ACK) + { + u_int32_t seqnr; + + if (!get_seqnr(notify, &seqnr)) + { + return FAILED; + } + + if (this->seqnr != seqnr) + { + DBG1(DBG_IKE, "received DPD Ack with unexpected seqnr (%u) expect (%u)",seqnr,this->seqnr); + return SUCCESS; + } + + DBG4(DBG_IKE, "received DPD Ack with seqnr (%u)",seqnr); + + return SUCCESS; + + } + else if (type == DPD_R_U_THERE) + { + u_int32_t expected = this->seqnr + 1; + + if (!get_seqnr(notify, &this->seqnr)) + { + return FAILED; + } + + if (expected != 1 && this->seqnr != expected) + { + DBG1(DBG_IKE, "received DPD request with unexpected seqnr (%u) expect (%u)", + this->seqnr,expected); + return SUCCESS; + } + + DBG4(DBG_IKE, "received DPD request with seqnr %u",this->seqnr); + + this->public.task.build = _build_r; + return NEED_MORE; + } + else + { + info_task = (task_t*)informational_create(this->ike_sa, NULL, 0); + } + continue; + + default: + continue; + } + break; + } + enumerator->destroy(enumerator); + + if (info_task) + { + status_t status = info_task->process(info_task, message); + /* Assuming that the informational task will not need to send other replies than dpd */ + info_task->destroy(info_task); + return status; + } + + return SUCCESS; +} + +METHOD(task_t, process_r, status_t, + private_isakmp_dpd_t *this, message_t *message) +{ + u_int32_t expected = this->seqnr + 1; + + if (this->notify) + { + if (!get_seqnr(this->notify, &this->seqnr)) + { + return FAILED; + } + + if (expected != 1 && this->seqnr != expected) + { + DBG1(DBG_IKE, "received DPD request with unexpected seqnr (%u) expect (%u)", + this->seqnr,expected); + return SUCCESS; + } + + DBG4(DBG_IKE, "DPD request received with seqnr %u",this->seqnr); + } + else + { + DBG1(DBG_IKE, "no notify provided"); + return FAILED; + } + return NEED_MORE; +} + + +METHOD(task_t, get_type, task_type_t, + private_isakmp_dpd_t *this) +{ + return TASK_ISAKMP_DPD; +} + + +METHOD(task_t, migrate, void, + private_isakmp_dpd_t *this, ike_sa_t *ike_sa) +{ + this->ike_sa = ike_sa; + this->seqnr = 0; + +} + +METHOD(task_t, destroy, void, + private_isakmp_dpd_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, notify_payload_t *notify, u_int32_t seqnr) +{ + private_isakmp_dpd_t *this; + + INIT(this, + .public = { + .task = { + .get_type = _get_type, + .migrate = _migrate, + .destroy = _destroy, + }, + .get_dpd_seqnr = _get_dpd_seqnr, + }, + .notify = notify, + .ike_sa = ike_sa, + .seqnr = seqnr, + ); + + if (!notify) + { + this->public.task.build = _build_i; + this->public.task.process = _process_i; + } + else + { + this->public.task.build = _build_r; + this->public.task.process = _process_r; + } + + return &this->public; +} diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h new file mode 100755 index 000000000..5d940b8d4 --- /dev/null +++ b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h @@ -0,0 +1,38 @@ +#ifndef ISAKMP_DPD_H_ +#define ISAPMP_DPD_H_ + +typedef struct isakmp_dpd_t isakmp_dpd_t; + +#include +#include +#include + +/** + * Task of type isakmp_dpd, detects dead peers. + * + * + */ +struct isakmp_dpd_t { + + /** + * Implements the task_t interface + */ + task_t task; + + /** + * Get the received dpd seqnr. + * + * @return protocol ID + */ + u_int32_t (*get_dpd_seqnr) (isakmp_dpd_t *dpd_task); +}; + +/** + * Create a new isakmp_dpd task. + * + * @param initiator TRUE if task is the original initiator + * @return isakmp_dpd task to handle by the task_manager + */ +isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, notify_payload_t *notify, u_int32_t seqnr); + +#endif /** ISAKMP_DPD_H_ @}*/ \ No newline at end of file diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c old mode 100644 new mode 100755 index ba1a9ad1d..f1e3290a7 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -176,7 +176,7 @@ static status_t send_notify(private_main_mode_t *this, notify_type_t type) notify->set_spi_data(notify, spi); this->ike_sa->queue_task(this->ike_sa, - (task_t*)informational_create(this->ike_sa, notify)); + (task_t*)informational_create(this->ike_sa, notify, 0)); /* cancel all active/passive tasks in favour of informational */ return ALREADY_DONE; } diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c old mode 100644 new mode 100755 index dedeab189..b27b00de7 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -539,7 +539,7 @@ static status_t send_notify(private_quick_mode_t *this, notify_type_t type) notify->set_spi(notify, this->spi_i); this->ike_sa->queue_task(this->ike_sa, - (task_t*)informational_create(this->ike_sa, notify)); + (task_t*)informational_create(this->ike_sa, notify, 0)); /* cancel all active/passive tasks in favour of informational */ return ALREADY_DONE; } diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h old mode 100644 new mode 100755 index 6b5c92930..1b42bf1a4 --- a/src/libcharon/sa/task.h +++ b/src/libcharon/sa/task.h @@ -93,6 +93,9 @@ enum task_type_t { TASK_ISAKMP_CERT_PRE, /** IKEv1 post-authentication certificate handling */ TASK_ISAKMP_CERT_POST, + /** IKEv1 DPD */ + TASK_ISAKMP_DPD, + }; /** From c9a160953e09bd3edfb09d9a11f19b61ff33d550 Mon Sep 17 00:00:00 2001 From: Clavister OpenSource Date: Tue, 10 Jan 2012 14:38:01 +0100 Subject: [PATCH 453/534] Send DPD vendor ID --- src/libcharon/sa/ikev1/tasks/isakmp_vendor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) mode change 100644 => 100755 src/libcharon/sa/ikev1/tasks/isakmp_vendor.c diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c old mode 100644 new mode 100755 index a1d64863c..8b5776dda --- a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c @@ -70,7 +70,7 @@ static struct { "\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"}, /* draft-ietf-ipsec-dpd-00 */ - { "DPD", 0, FALSE, 16, + { "DPD", 0, TRUE, 16, "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"}, { "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16, From 1e624ce876fa4fd631b5e52b9a2d6966b2b2fae6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 13:32:06 +0100 Subject: [PATCH 454/534] Don't retransmit, rekey, reauth or DPD check SAs when in PASSIVE state --- src/libcharon/sa/ike_sa.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 1992a6017..fbe125987 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -563,6 +563,10 @@ METHOD(ike_sa_t, send_dpd, status_t, job_t *job; time_t diff, delay; + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } delay = this->peer_cfg->get_dpd(this->peer_cfg); if (this->task_manager->busy(this->task_manager)) { @@ -1256,6 +1260,10 @@ METHOD(ike_sa_t, remove_child_sa, void, METHOD(ike_sa_t, rekey_child_sa, status_t, private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi) { + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } this->task_manager->queue_child_rekey(this->task_manager, protocol, spi); return this->task_manager->initiate(this->task_manager); } @@ -1263,6 +1271,10 @@ METHOD(ike_sa_t, rekey_child_sa, status_t, METHOD(ike_sa_t, delete_child_sa, status_t, private_ike_sa_t *this, protocol_id_t protocol, u_int32_t spi, bool expired) { + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } this->task_manager->queue_child_delete(this->task_manager, protocol, spi, expired); return this->task_manager->initiate(this->task_manager); @@ -1322,6 +1334,10 @@ METHOD(ike_sa_t, delete_, status_t, METHOD(ike_sa_t, rekey, status_t, private_ike_sa_t *this) { + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } this->task_manager->queue_ike_rekey(this->task_manager); return this->task_manager->initiate(this->task_manager); } @@ -1329,6 +1345,10 @@ METHOD(ike_sa_t, rekey, status_t, METHOD(ike_sa_t, reauth, status_t, private_ike_sa_t *this) { + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } /* we can't reauthenticate as responder when we use EAP or virtual IPs. * If the peer does not support RFC4478, there is no way to keep the * IKE_SA up. */ @@ -1496,6 +1516,10 @@ METHOD(ike_sa_t, reestablish, status_t, METHOD(ike_sa_t, retransmit, status_t, private_ike_sa_t *this, u_int32_t message_id) { + if (this->state == IKE_PASSIVE) + { + return INVALID_STATE; + } this->stats[STAT_OUTBOUND] = time_monotonic(NULL); if (this->task_manager->retransmit(this->task_manager, message_id) != SUCCESS) { From 31689338d616b157c4e3f254bc9e8ba400488095 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 15:44:17 +0100 Subject: [PATCH 455/534] Remove unused DPD sequence number getter on task manager --- src/libcharon/sa/ikev1/task_manager_v1.c | 10 ++-------- src/libcharon/sa/ikev1/task_manager_v1.h | 5 ----- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 7e1ff616a..01427f6ea 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1335,16 +1335,11 @@ METHOD(task_manager_t, queue_child_delete, void, spi, FALSE, expired)); } -METHOD(task_manager_v1_t, get_dpd_seqnr, u_int32_t, - private_task_manager_t *this) -{ - return this->dpd_send_seqnr++; -} - METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { - queue_task(this, (task_t*)isakmp_dpd_create(this->ike_sa, NULL, _get_dpd_seqnr(&this->public))); + queue_task(this, (task_t*)isakmp_dpd_create(this->ike_sa, NULL, + this->dpd_send_seqnr++)); } METHOD(task_manager_t, adopt_tasks, void, @@ -1471,7 +1466,6 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) .create_task_enumerator = _create_task_enumerator, .destroy = _destroy, }, - .get_dpd_seqnr = _get_dpd_seqnr, }, .ike_sa = ike_sa, .initiating.type = EXCHANGE_TYPE_UNDEFINED, diff --git a/src/libcharon/sa/ikev1/task_manager_v1.h b/src/libcharon/sa/ikev1/task_manager_v1.h index 58b20d0c2..99cd35e32 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.h +++ b/src/libcharon/sa/ikev1/task_manager_v1.h @@ -34,11 +34,6 @@ struct task_manager_v1_t { * Implements task_manager_t. */ task_manager_t task_manager; - - /** - * Get new sequence number to use for sending DPD request. - */ - u_int32_t (*get_dpd_seqnr) (task_manager_v1_t *this); }; /** From 3fca5bd123021dadada62557798ec1f7b107a41a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 16:02:46 +0100 Subject: [PATCH 456/534] Check if we have an RNG for IKEv1 task manager before using it --- src/libcharon/sa/ikev1/task_manager_v1.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 01427f6ea..c07df41f0 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -334,12 +334,6 @@ METHOD(task_manager_t, initiate, status_t, exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED; bool new_mid = FALSE, expect_response = FALSE, flushed = FALSE; - if (!this->rng) - { - DBG1(DBG_IKE, "no RNG supported"); - return FAILED; - } - if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED) { DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress", @@ -1132,7 +1126,7 @@ METHOD(task_manager_t, process_message, status_t, job = (job_t*)delete_ike_sa_job_create(ike_sa_id, FALSE); lib->scheduler->schedule_job(lib->scheduler, job, lib->settings->get_int(lib->settings, - "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); + "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); } this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, time_monotonic(NULL)); @@ -1482,9 +1476,15 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) "charon.retransmit_base", RETRANSMIT_BASE), ); - this->rng->get_bytes(this->rng, sizeof(this->dpd_send_seqnr), - (void*)&this->dpd_send_seqnr); + if (!this->rng) + { + DBG1(DBG_IKE, "no RNG found, unable to create IKE_SA"); + destroy(this); + return NULL; + } + this->rng->get_bytes(this->rng, sizeof(this->dpd_send_seqnr), + (void*)&this->dpd_send_seqnr); this->dpd_send_seqnr &= 0x7FFFFFFF; return &this->public; From 5f2f864efc8f1ab0462c0f0edfd5af1ee5311728 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 17:09:20 +0100 Subject: [PATCH 457/534] Support IKEv1 notifies in message_t.get_notify() --- src/libcharon/encoding/message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 99aca870a..4ca119dd5 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1142,7 +1142,8 @@ METHOD(message_t, get_notify, notify_payload_t*, enumerator = create_payload_enumerator(this); while (enumerator->enumerate(enumerator, &payload)) { - if (payload->get_type(payload) == NOTIFY) + if (payload->get_type(payload) == NOTIFY || + payload->get_type(payload) == NOTIFY_V1) { notify = (notify_payload_t*)payload; if (notify->get_notify_type(notify) == type) From bb2d4e188270800e3b3574acad1f7e6b6fd51e48 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 17:09:47 +0100 Subject: [PATCH 458/534] Print IKEv1 notify types in message summary --- src/libcharon/encoding/message.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 4ca119dd5..dd7f8ecc7 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1192,7 +1192,8 @@ static char* get_string(private_message_t *this, char *buf, int len) } pos += written; len -= written; - if (payload->get_type(payload) == NOTIFY) + if (payload->get_type(payload) == NOTIFY || + payload->get_type(payload) == NOTIFY_V1) { notify_payload_t *notify; notify_type_t type; From 5ac4c2e1a9658bad4018cf8ede82d89dd7de6fc7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 17:10:22 +0100 Subject: [PATCH 459/534] Added missing short enum names for DPD notify types --- src/libcharon/encoding/payloads/notify_payload.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index 5918eb426..7c3aac18f 100755 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -207,7 +207,10 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, IPSEC_REPLAY_COUNTER_SYNC, M "RPL_CTR_SYN"); ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, IPSEC_REPLAY_COUNTER_SYNC, "INITIAL_CONTACT"); -ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, INITIAL_CONTACT_IKEV1, +ENUM_NEXT(notify_type_short_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1, + "DPD", + "DPD_ACK"); +ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, DPD_R_U_THERE_ACK, "BEET_MODE"); ENUM_NEXT(notify_type_short_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE, "ME_MED", From 2ddd45c9a76a77d673cca5ce0bd2ea0bb7ee859a Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 17:21:52 +0100 Subject: [PATCH 460/534] Simplified DPD handling by using a task for a single message only --- src/libcharon/sa/ikev1/task_manager_v1.c | 71 +++--- .../sa/ikev1/tasks/aggressive_mode.c | 2 +- src/libcharon/sa/ikev1/tasks/informational.c | 35 +-- src/libcharon/sa/ikev1/tasks/informational.h | 5 +- src/libcharon/sa/ikev1/tasks/isakmp_dpd.c | 223 ++++-------------- src/libcharon/sa/ikev1/tasks/isakmp_dpd.h | 46 ++-- src/libcharon/sa/ikev1/tasks/main_mode.c | 2 +- src/libcharon/sa/ikev1/tasks/quick_mode.c | 2 +- 8 files changed, 114 insertions(+), 272 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index c07df41f0..ec5eee155 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -203,12 +203,12 @@ struct private_task_manager_t { /** * Sequence number for sending DPD requests */ - u_int32_t dpd_send_seqnr; + u_int32_t dpd_send; /** * Sequence number for received DPD requests */ - u_int32_t dpd_rec_seqnr; + u_int32_t dpd_recv; }; /** @@ -736,7 +736,8 @@ static status_t process_request(private_task_manager_t *this, enumerator_t *enumerator; task_t *task = NULL; bool send_response = FALSE; - bool informational = FALSE; + notify_payload_t *notify; + chunk_t data; if (message->get_exchange_type(message) == INFORMATIONAL_V1 || this->passive_tasks->get_count(this->passive_tasks) == 0) @@ -779,9 +780,27 @@ static status_t process_request(private_task_manager_t *this, this->passive_tasks->insert_last(this->passive_tasks, task); break; case INFORMATIONAL_V1: - task = (task_t *)informational_create(this->ike_sa, NULL, this->dpd_rec_seqnr); + notify = message->get_notify(message, DPD_R_U_THERE); + if (notify) + { + data = notify->get_notification_data(notify); + if (this->dpd_recv == 0 && data.len == 4) + { /* first DPD request, initialize counter */ + this->dpd_recv = untoh32(data.ptr); + } + task = (task_t *)isakmp_dpd_create(this->ike_sa, FALSE, + this->dpd_recv++); + } + else if (message->get_notify(message, DPD_R_U_THERE_ACK)) + { + task = (task_t *)isakmp_dpd_create(this->ike_sa, TRUE, + this->dpd_send - 1); + } + else + { + task = (task_t *)informational_create(this->ike_sa, NULL); + } this->passive_tasks->insert_first(this->passive_tasks, task); - informational = TRUE; break; case TRANSACTION: if (this->ike_sa->get_state(this->ike_sa) == IKE_ESTABLISHED) @@ -812,15 +831,6 @@ static status_t process_request(private_task_manager_t *this, case NEED_MORE: /* processed, but task needs at least another call to build() */ send_response = TRUE; - if (informational && !this->dpd_rec_seqnr) - { - /* Update the received DPD sequence number if it the first received one */ - if (task->get_type(task) == TASK_ISAKMP_DPD) - { - isakmp_dpd_t *isakmp_dpd = (isakmp_dpd_t *)task; - this->dpd_rec_seqnr = isakmp_dpd->get_dpd_seqnr(isakmp_dpd); - } - } continue; case ALREADY_DONE: send_response = FALSE; @@ -987,7 +997,6 @@ METHOD(task_manager_t, process_message, status_t, u_int32_t hash, mid, i; host_t *me, *other; status_t status; - bool dpd_response = FALSE; /* TODO-IKEv1: update hosts more selectively */ me = msg->get_destination(msg); @@ -1015,27 +1024,7 @@ METHOD(task_manager_t, process_message, status_t, } } - /* DPD Acks are not sent with a same message ID as the request.*/ - if (msg->get_exchange_type(msg) == INFORMATIONAL_V1 && - this->active_tasks->get_count(this->active_tasks)) - { - enumerator_t *enumerator; - task_t *task; - /* In case of ongoing DPD request, let the DPD task handle all information exchanges. */ - enumerator = this->active_tasks->create_enumerator(this->active_tasks); - while (enumerator->enumerate(enumerator, (void**)&task)) - { - if (task->get_type(task) == TASK_ISAKMP_DPD) - { - dpd_response = TRUE; - break; - } - } - enumerator->destroy(enumerator); - } - - - if ((mid && mid == this->initiating.mid) || dpd_response || + if ((mid && mid == this->initiating.mid) || (this->initiating.mid == 0 && msg->get_exchange_type(msg) == this->initiating.type && this->active_tasks->get_count(this->active_tasks))) @@ -1332,8 +1321,8 @@ METHOD(task_manager_t, queue_child_delete, void, METHOD(task_manager_t, queue_dpd, void, private_task_manager_t *this) { - queue_task(this, (task_t*)isakmp_dpd_create(this->ike_sa, NULL, - this->dpd_send_seqnr++)); + queue_task(this, (task_t*)isakmp_dpd_create(this->ike_sa, TRUE, + this->dpd_send++)); } METHOD(task_manager_t, adopt_tasks, void, @@ -1483,9 +1472,9 @@ task_manager_v1_t *task_manager_v1_create(ike_sa_t *ike_sa) return NULL; } - this->rng->get_bytes(this->rng, sizeof(this->dpd_send_seqnr), - (void*)&this->dpd_send_seqnr); - this->dpd_send_seqnr &= 0x7FFFFFFF; + this->rng->get_bytes(this->rng, sizeof(this->dpd_send), + (void*)&this->dpd_send); + this->dpd_send &= 0x7FFFFFFF; return &this->public; } diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c index df0c94b28..1fe36a9d5 100755 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -164,7 +164,7 @@ static status_t send_notify(private_aggressive_mode_t *this, notify_type_t type) notify->set_spi_data(notify, spi); this->ike_sa->queue_task(this->ike_sa, - (task_t*)informational_create(this->ike_sa, notify, 0)); + (task_t*)informational_create(this->ike_sa, notify)); /* cancel all active/passive tasks in favour of informational */ return ALREADY_DONE; } diff --git a/src/libcharon/sa/ikev1/tasks/informational.c b/src/libcharon/sa/ikev1/tasks/informational.c index 2af641e86..4e53e5c04 100755 --- a/src/libcharon/sa/ikev1/tasks/informational.c +++ b/src/libcharon/sa/ikev1/tasks/informational.c @@ -18,7 +18,6 @@ #include #include #include -#include #include @@ -48,16 +47,6 @@ struct private_informational_t { * Delete subtask */ task_t *del; - - /** - * DPD subtask - */ - task_t *dpd; - - /** - * DPD sequence number - */ - u_int32_t dpd_seqnr; }; METHOD(task_t, build_i, status_t, @@ -92,15 +81,6 @@ METHOD(task_t, process_r, status_t, this->ike_sa->set_condition(this->ike_sa, COND_INIT_CONTACT_SEEN, TRUE); } - else if (type == DPD_R_U_THERE) - { - DBG3(DBG_IKE, "received DPD request"); - this->dpd = (task_t*)isakmp_dpd_create(this->ike_sa, notify, this->dpd_seqnr); - } - else if (type == DPD_R_U_THERE_ACK) - { - DBG3(DBG_IKE, "received DPD request ack"); - } else if (type < 16384) { DBG1(DBG_IKE, "received %N error notify", @@ -144,11 +124,6 @@ METHOD(task_t, process_r, status_t, { return this->del->process(this->del, message); } - - if (this->dpd && status == SUCCESS) - { - return this->dpd->process(this->dpd, message); - } return status; } @@ -159,13 +134,6 @@ METHOD(task_t, build_r, status_t, { return this->del->build(this->del, message); } - - if (this->dpd) - { - status_t status = this->dpd->build(this->dpd, message); - this->dpd->destroy(this->dpd); - return status; - } return FAILED; } @@ -198,7 +166,7 @@ METHOD(task_t, destroy, void, /* * Described in header. */ -informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify, u_int32_t dpd_seqnr) +informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify) { private_informational_t *this; @@ -212,7 +180,6 @@ informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify }, .ike_sa = ike_sa, .notify = notify, - .dpd_seqnr = dpd_seqnr, ); if (notify) diff --git a/src/libcharon/sa/ikev1/tasks/informational.h b/src/libcharon/sa/ikev1/tasks/informational.h index 59b811000..26d8d5167 100755 --- a/src/libcharon/sa/ikev1/tasks/informational.h +++ b/src/libcharon/sa/ikev1/tasks/informational.h @@ -19,7 +19,7 @@ */ #ifndef INFORMATIONAL_H_ -#define informational_H_ +#define INFORMATIONAL_H_ typedef struct informational_t informational_t; @@ -44,9 +44,8 @@ struct informational_t { * * @param ike_sa IKE_SA this task works for * @param notify notify to send as initiator, NULL if responder - * @param dpd_seqnr DPD sequence number, incoming or outgoing * @return task to handle by the task_manager */ -informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify, u_int32_t dpd_seqnr); +informational_t *informational_create(ike_sa_t *ike_sa, notify_payload_t *notify); #endif /** INFORMATIONAL_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c index ec0a1eddc..e2ed17dcd 100755 --- a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c @@ -1,14 +1,22 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + #include "isakmp_dpd.h" -#include -#include - #include - -#ifdef SLIPSTREAM -/* Should be the last include */ -#include -#endif /* SLIPSTREAM */ +#include typedef struct private_isakmp_dpd_t private_isakmp_dpd_t; @@ -28,9 +36,9 @@ struct private_isakmp_dpd_t { u_int32_t seqnr; /** - * Notify payload, only provided for requests. + * DPD initiator? */ - notify_payload_t *notify; + bool initiator; /** * IKE SA we are serving. @@ -38,42 +46,19 @@ struct private_isakmp_dpd_t { ike_sa_t *ike_sa; }; -/** - * Get DPD sequence number from notify payload. - */ -static bool get_seqnr(notify_payload_t *notify, u_int32_t *seqnr) -{ - chunk_t chunk = notify->get_notification_data(notify); - - if( chunk.ptr && chunk.len == 4) - { - u_int32_t seqnr_read = *((u_int32_t*)chunk.ptr); - - *seqnr = ntohl(seqnr_read); - - return TRUE; - } - - DBG1(DBG_IKE, "no DPD seqnr received"); - - return FALSE; -} - -/** - * Add notify payload to message. - */ -static void add_notify(private_isakmp_dpd_t *this, message_t *message, notify_type_t type) +METHOD(task_t, build, status_t, + private_isakmp_dpd_t *this, message_t *message) { notify_payload_t *notify; - + notify_type_t type; ike_sa_id_t *ike_sa_id; u_int64_t spi_i, spi_r; u_int32_t seqnr; chunk_t spi; + type = this->initiator ? DPD_R_U_THERE : DPD_R_U_THERE_ACK; notify = notify_payload_create_from_protocol_and_type(NOTIFY_V1, - PROTO_IKE, type); - + PROTO_IKE, type); seqnr = htonl(this->seqnr); ike_sa_id = this->ike_sa->get_id(this->ike_sa); spi_i = ike_sa_id->get_initiator_spi(ike_sa_id); @@ -84,156 +69,53 @@ static void add_notify(private_isakmp_dpd_t *this, message_t *message, notify_ty notify->set_notification_data(notify, chunk_from_thing(seqnr)); message->add_payload(message, (payload_t*)notify); -} - -METHOD(isakmp_dpd_t, get_dpd_seqnr, u_int32_t, - private_isakmp_dpd_t *this) -{ - return this->seqnr; -} - -METHOD(task_t, build_i, status_t, - private_isakmp_dpd_t *this, message_t *message) -{ - add_notify(this, message, DPD_R_U_THERE); - - return NEED_MORE; -} - -METHOD(task_t, build_r, status_t, - private_isakmp_dpd_t *this, message_t *message) -{ - add_notify(this, message, DPD_R_U_THERE_ACK); return SUCCESS; } -METHOD(task_t, process_i, status_t, +METHOD(task_t, process, status_t, private_isakmp_dpd_t *this, message_t *message) { - enumerator_t *enumerator; notify_payload_t *notify; notify_type_t type; - payload_t *payload; - task_t *info_task = NULL; + u_int32_t seqnr = 0; + chunk_t chunk; - enumerator = message->create_payload_enumerator(message); - while (enumerator->enumerate(enumerator, &payload)) + type = this->initiator ? DPD_R_U_THERE_ACK : DPD_R_U_THERE; + notify = message->get_notify(message, type); + if (notify) { - switch (payload->get_type(payload)) + chunk = notify->get_notification_data(notify); + if (chunk.len == 4) { - case NOTIFY_V1: - notify = (notify_payload_t*)payload; - type = notify->get_notify_type(notify); - - if (type == DPD_R_U_THERE_ACK) - { - u_int32_t seqnr; - - if (!get_seqnr(notify, &seqnr)) - { - return FAILED; - } - - if (this->seqnr != seqnr) - { - DBG1(DBG_IKE, "received DPD Ack with unexpected seqnr (%u) expect (%u)",seqnr,this->seqnr); - return SUCCESS; - } - - DBG4(DBG_IKE, "received DPD Ack with seqnr (%u)",seqnr); - - return SUCCESS; - + seqnr = untoh32(chunk.ptr); + if (seqnr == this->seqnr) + { + if (!this->initiator) + { /* queue DPD_ACK */ + this->ike_sa->queue_task(this->ike_sa, + &isakmp_dpd_create(this->ike_sa, FALSE, + this->seqnr)->task); } - else if (type == DPD_R_U_THERE) - { - u_int32_t expected = this->seqnr + 1; - - if (!get_seqnr(notify, &this->seqnr)) - { - return FAILED; - } - - if (expected != 1 && this->seqnr != expected) - { - DBG1(DBG_IKE, "received DPD request with unexpected seqnr (%u) expect (%u)", - this->seqnr,expected); - return SUCCESS; - } - - DBG4(DBG_IKE, "received DPD request with seqnr %u",this->seqnr); - - this->public.task.build = _build_r; - return NEED_MORE; - } - else - { - info_task = (task_t*)informational_create(this->ike_sa, NULL, 0); - } - continue; - - default: - continue; + return SUCCESS; + } } - break; } - enumerator->destroy(enumerator); - - if (info_task) - { - status_t status = info_task->process(info_task, message); - /* Assuming that the informational task will not need to send other replies than dpd */ - info_task->destroy(info_task); - return status; - } - + DBG1(DBG_IKE, "received invalid DPD sequence number %u (expected %u), " + "ignored", seqnr, this->seqnr); return SUCCESS; } -METHOD(task_t, process_r, status_t, - private_isakmp_dpd_t *this, message_t *message) -{ - u_int32_t expected = this->seqnr + 1; - - if (this->notify) - { - if (!get_seqnr(this->notify, &this->seqnr)) - { - return FAILED; - } - - if (expected != 1 && this->seqnr != expected) - { - DBG1(DBG_IKE, "received DPD request with unexpected seqnr (%u) expect (%u)", - this->seqnr,expected); - return SUCCESS; - } - - DBG4(DBG_IKE, "DPD request received with seqnr %u",this->seqnr); - } - else - { - DBG1(DBG_IKE, "no notify provided"); - return FAILED; - } - return NEED_MORE; -} - - METHOD(task_t, get_type, task_type_t, private_isakmp_dpd_t *this) { return TASK_ISAKMP_DPD; } - METHOD(task_t, migrate, void, private_isakmp_dpd_t *this, ike_sa_t *ike_sa) { this->ike_sa = ike_sa; - this->seqnr = 0; - } METHOD(task_t, destroy, void, @@ -245,7 +127,8 @@ METHOD(task_t, destroy, void, /* * Described in header. */ -isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, notify_payload_t *notify, u_int32_t seqnr) +isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, bool initiator, + u_int32_t seqnr) { private_isakmp_dpd_t *this; @@ -253,26 +136,16 @@ isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, notify_payload_t *notify, u_in .public = { .task = { .get_type = _get_type, + .build = _build, + .process = _process, .migrate = _migrate, .destroy = _destroy, }, - .get_dpd_seqnr = _get_dpd_seqnr, }, - .notify = notify, .ike_sa = ike_sa, .seqnr = seqnr, + .initiator = initiator, ); - if (!notify) - { - this->public.task.build = _build_i; - this->public.task.process = _process_i; - } - else - { - this->public.task.build = _build_r; - this->public.task.process = _process_r; - } - return &this->public; } diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h index 5d940b8d4..688d19fd8 100755 --- a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h +++ b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.h @@ -1,5 +1,25 @@ +/* + * Copyright (C) 2012 Martin Willi + * Copyright (C) 2012 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See . + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup isakmp_dpd isakmp_dpd + * @{ @ingroup tasks + */ + #ifndef ISAKMP_DPD_H_ -#define ISAPMP_DPD_H_ +#define ISAKMP_DPD_H_ typedef struct isakmp_dpd_t isakmp_dpd_t; @@ -8,9 +28,7 @@ typedef struct isakmp_dpd_t isakmp_dpd_t; #include /** - * Task of type isakmp_dpd, detects dead peers. - * - * + * IKEv1 dead peer detection task. */ struct isakmp_dpd_t { @@ -18,21 +36,17 @@ struct isakmp_dpd_t { * Implements the task_t interface */ task_t task; - - /** - * Get the received dpd seqnr. - * - * @return protocol ID - */ - u_int32_t (*get_dpd_seqnr) (isakmp_dpd_t *dpd_task); }; /** - * Create a new isakmp_dpd task. + * Create a new ISAKMP_DPD task. * - * @param initiator TRUE if task is the original initiator - * @return isakmp_dpd task to handle by the task_manager + * @param ike_sa associated IKE_SA + * @param initiator TRUE if DPD initiator + * @param seqnr DPD sequence number to use/expect + * @return ISAKMP_DPD task to handle by the task_manager */ -isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, notify_payload_t *notify, u_int32_t seqnr); +isakmp_dpd_t *isakmp_dpd_create(ike_sa_t *ike_sa, bool initiator, + u_int32_t seqnr); -#endif /** ISAKMP_DPD_H_ @}*/ \ No newline at end of file +#endif /** ISAKMP_DPD_H_ @}*/ diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index f1e3290a7..ba1a9ad1d 100755 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -176,7 +176,7 @@ static status_t send_notify(private_main_mode_t *this, notify_type_t type) notify->set_spi_data(notify, spi); this->ike_sa->queue_task(this->ike_sa, - (task_t*)informational_create(this->ike_sa, notify, 0)); + (task_t*)informational_create(this->ike_sa, notify)); /* cancel all active/passive tasks in favour of informational */ return ALREADY_DONE; } diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index b27b00de7..dedeab189 100755 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -539,7 +539,7 @@ static status_t send_notify(private_quick_mode_t *this, notify_type_t type) notify->set_spi(notify, this->spi_i); this->ike_sa->queue_task(this->ike_sa, - (task_t*)informational_create(this->ike_sa, notify, 0)); + (task_t*)informational_create(this->ike_sa, notify)); /* cancel all active/passive tasks in favour of informational */ return ALREADY_DONE; } From ff6b084ac4e9ca27a306a2836f7b341d9129ea5b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 17:26:42 +0100 Subject: [PATCH 461/534] Confirm message reception time only if DPD sequence number valid --- src/libcharon/sa/ikev1/task_manager_v1.c | 11 ++++++++--- src/libcharon/sa/ikev1/tasks/isakmp_dpd.c | 2 ++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index ec5eee155..562a9eb42 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -735,7 +735,7 @@ static status_t process_request(private_task_manager_t *this, { enumerator_t *enumerator; task_t *task = NULL; - bool send_response = FALSE; + bool send_response = FALSE, dpd = FALSE; notify_payload_t *notify; chunk_t data; @@ -790,11 +790,13 @@ static status_t process_request(private_task_manager_t *this, } task = (task_t *)isakmp_dpd_create(this->ike_sa, FALSE, this->dpd_recv++); + dpd = TRUE; } else if (message->get_notify(message, DPD_R_U_THERE_ACK)) { task = (task_t *)isakmp_dpd_create(this->ike_sa, TRUE, this->dpd_send - 1); + dpd = TRUE; } else { @@ -817,6 +819,11 @@ static status_t process_request(private_task_manager_t *this, return FAILED; } } + if (!dpd) + { + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); + } /* let the tasks process the message */ enumerator = this->passive_tasks->create_enumerator(this->passive_tasks); while (enumerator->enumerate(enumerator, (void*)&task)) @@ -1117,8 +1124,6 @@ METHOD(task_manager_t, process_message, status_t, lib->settings->get_int(lib->settings, "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); } - this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, - time_monotonic(NULL)); this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); charon->bus->message(charon->bus, msg, TRUE); if (process_request(this, msg) != SUCCESS) diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c index e2ed17dcd..e470e90ad 100755 --- a/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_dpd.c @@ -91,6 +91,8 @@ METHOD(task_t, process, status_t, seqnr = untoh32(chunk.ptr); if (seqnr == this->seqnr) { + this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, + time_monotonic(NULL)); if (!this->initiator) { /* queue DPD_ACK */ this->ike_sa->queue_task(this->ike_sa, From 214d4e409049147aa6fa87c1e3f2aa5262a7e32b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 17:28:25 +0100 Subject: [PATCH 462/534] Added missing DPD task name --- src/libcharon/sa/task.c | 1 + src/libcharon/sa/task.h | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/task.c b/src/libcharon/sa/task.c index 0c08a2874..4336b23ff 100644 --- a/src/libcharon/sa/task.c +++ b/src/libcharon/sa/task.c @@ -46,6 +46,7 @@ ENUM(task_type_names, TASK_IKE_INIT, TASK_ISAKMP_CERT_POST, "QUICK_DELETE", "ISAKMP_VENDOR", "ISAKMP_NATD", + "ISAKMP_DPD", "ISAKMP_CERT_PRE", "ISAKMP_CERT_POST", ); diff --git a/src/libcharon/sa/task.h b/src/libcharon/sa/task.h index 1b42bf1a4..255b9a393 100755 --- a/src/libcharon/sa/task.h +++ b/src/libcharon/sa/task.h @@ -89,13 +89,12 @@ enum task_type_t { TASK_ISAKMP_VENDOR, /** IKEv1 NAT detection */ TASK_ISAKMP_NATD, + /** IKEv1 DPD */ + TASK_ISAKMP_DPD, /** IKEv1 pre-authentication certificate handling */ TASK_ISAKMP_CERT_PRE, /** IKEv1 post-authentication certificate handling */ TASK_ISAKMP_CERT_POST, - /** IKEv1 DPD */ - TASK_ISAKMP_DPD, - }; /** From 11aadd772291c3c4d392b6457778a94a8e94c7c5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 17:40:07 +0100 Subject: [PATCH 463/534] Disable DPD checking for peers not supporting it --- src/libcharon/sa/ike_sa.c | 14 +++++++++++++- src/libcharon/sa/ike_sa.h | 5 +++++ src/libcharon/sa/ikev1/tasks/isakmp_vendor.c | 4 ++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index fbe125987..98d636fe1 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -670,7 +670,14 @@ METHOD(ike_sa_t, set_state, void, /* start DPD checks */ if (this->peer_cfg->get_dpd(this->peer_cfg)) { - send_dpd(this); + if (supports_extension(this, EXT_DPD)) + { + send_dpd(this); + } + else + { + DBG1(DBG_IKE, "DPD not supported by peer, disabled"); + } } } break; @@ -2037,6 +2044,11 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id, bool initiator, "charon.flush_auth_cfg", FALSE), ); + if (version == IKEV2) + { /* always supported with IKEv2 */ + enable_extension(this, EXT_DPD); + } + this->task_manager = task_manager_create(&this->public); this->my_host->set_port(this->my_host, IKEV2_UDP_PORT); diff --git a/src/libcharon/sa/ike_sa.h b/src/libcharon/sa/ike_sa.h index b7c96fdfb..3fc0a7be2 100644 --- a/src/libcharon/sa/ike_sa.h +++ b/src/libcharon/sa/ike_sa.h @@ -108,6 +108,11 @@ enum ike_extension_t { * peer supports XAuth authentication, draft-ietf-ipsec-isakmp-xauth-06 */ EXT_XAUTH = (1<<7), + + /** + * peer supports DPD detection, RFC 3706 (or IKEv2) + */ + EXT_DPD = (1<<8), }; /** diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c index 8b5776dda..ea0dff5e0 100755 --- a/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_vendor.c @@ -69,8 +69,8 @@ static struct { { "NAT-T (RFC 3947)", EXT_NATT, TRUE, 16, "\x4a\x13\x1c\x81\x07\x03\x58\x45\x5c\x57\x28\xf2\x0e\x95\x45\x2f"}, - /* draft-ietf-ipsec-dpd-00 */ - { "DPD", 0, TRUE, 16, + /* Dead peer detection, RFC 3706 */ + { "DPD", EXT_DPD, TRUE, 16, "\xaf\xca\xd7\x13\x68\xa1\xf1\xc9\x6b\x86\x96\xfc\x77\x57\x01\x00"}, { "draft-stenberg-ipsec-nat-traversal-01", 0, FALSE, 16, From 1b82eb23a2416583c464b296161d795a87d1d868 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 10 Jan 2012 19:13:58 +0100 Subject: [PATCH 464/534] Handle retransmission of DPD exchange, both as initiator and responder --- src/libcharon/sa/ikev1/task_manager_v1.c | 59 +++++++++++++++--------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 562a9eb42..a7c088bac 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -332,7 +332,7 @@ METHOD(task_manager_t, initiate, status_t, host_t *me, *other; status_t status; exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED; - bool new_mid = FALSE, expect_response = FALSE, flushed = FALSE; + bool new_mid = FALSE, expect_response = FALSE, flushed = FALSE, keep = FALSE; if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED) { @@ -412,7 +412,6 @@ METHOD(task_manager_t, initiate, status_t, new_mid = TRUE; break; } - if (activate_task(this, TASK_ISAKMP_DPD)) { exchange = INFORMATIONAL_V1; @@ -485,6 +484,11 @@ METHOD(task_manager_t, initiate, status_t, case SUCCESS: /* task completed, remove it */ this->active_tasks->remove_at(this->active_tasks, enumerator); + if (task->get_type(task) == AGGRESSIVE || + task->get_type(task) == QUICK_MODE) + { /* last message of three message exchange */ + keep = TRUE; + } task->destroy(task); continue; case NEED_MORE: @@ -513,10 +517,22 @@ METHOD(task_manager_t, initiate, status_t, } enumerator->destroy(enumerator); - if (this->active_tasks->get_count(this->active_tasks) == 0) + if (this->active_tasks->get_count(this->active_tasks) == 0 && + (exchange == QUICK_MODE || exchange == AGGRESSIVE)) { /* tasks completed, no exchange active anymore */ this->initiating.type = EXCHANGE_TYPE_UNDEFINED; } + if (exchange == INFORMATIONAL_V1) + { + if (message->get_notify(message, DPD_R_U_THERE)) + { + expect_response = TRUE; + } + if (message->get_notify(message, DPD_R_U_THERE_ACK)) + { + keep = TRUE; + } + } if (flushed) { message->destroy(message); @@ -537,15 +553,13 @@ METHOD(task_manager_t, initiate, status_t, } this->initiating.seqnr++; - if (expect_response) + if (expect_response ) { message->destroy(message); return retransmit(this, this->initiating.seqnr); } - if (message->get_exchange_type(message) == QUICK_MODE || - message->get_exchange_type(message) == AGGRESSIVE) - { /* keep the packet for retransmission in quick/aggressive mode. - * The responder might request a retransmission */ + if (keep) + { /* keep the packet for retransmission, the responder might request it */ charon->sender->send(charon->sender, this->initiating.packet->clone(this->initiating.packet)); } @@ -593,20 +607,7 @@ static status_t build_response(private_task_manager_t *this, message_t *request) /* send response along the path the request came in */ message->set_source(message, me->clone(me)); message->set_destination(message, other->clone(other)); - - /* Create new message id for informational exchanges*/ - if (request->get_exchange_type(request) == INFORMATIONAL_V1) - { - u_int32_t message_id; - - this->rng->get_bytes(this->rng, sizeof(message_id), - (void*)&message_id); - message->set_message_id(message, message_id); - } - else - { - message->set_message_id(message, request->get_message_id(request)); - } + message->set_message_id(message, request->get_message_id(request)); message->set_request(message, FALSE); this->responding.mid = request->get_message_id(request); @@ -858,6 +859,12 @@ static status_t process_request(private_task_manager_t *this, } enumerator->destroy(enumerator); + if (dpd && this->initiating.type == INFORMATIONAL_V1) + { /* got a DPD reply, cancel any retransmission */ + this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + DESTROY_IF(this->initiating.packet); + this->initiating.packet = NULL; + } if (send_response) { if (build_response(this, message) != SUCCESS) @@ -1065,6 +1072,14 @@ METHOD(task_manager_t, process_message, status_t, charon->sender->send(charon->sender, this->responding.packet->clone(this->responding.packet)); } + else if (this->initiating.packet && + this->initiating.type == INFORMATIONAL_V1) + { + DBG1(DBG_IKE, "received retransmit of DPD request, " + "retransmitting response"); + charon->sender->send(charon->sender, + this->initiating.packet->clone(this->initiating.packet)); + } else { DBG1(DBG_IKE, "received retransmit of request with ID %u, " From 477559cab5900ea5d40147597698a23dd83414f7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 13 Jan 2012 09:27:26 +0100 Subject: [PATCH 465/534] Continue with next exchange after sending an INFORMATIONAL --- src/libcharon/sa/ikev1/task_manager_v1.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index a7c088bac..30a5c3105 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -334,7 +334,8 @@ METHOD(task_manager_t, initiate, status_t, exchange_type_t exchange = EXCHANGE_TYPE_UNDEFINED; bool new_mid = FALSE, expect_response = FALSE, flushed = FALSE, keep = FALSE; - if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED) + if (this->initiating.type != EXCHANGE_TYPE_UNDEFINED && + this->initiating.type != INFORMATIONAL_V1) { DBG2(DBG_IKE, "delaying task initiation, %N exchange in progress", exchange_type_names, this->initiating.type); From c654d949f33c1d2d7586b25a35631ec730ecfd7d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 16 Jan 2012 15:31:53 +0100 Subject: [PATCH 466/534] Fix "incoming" flag passed to bus_t.message() hook --- src/libcharon/sa/ikev1/task_manager_v1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 30a5c3105..5695b4e3e 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1053,7 +1053,7 @@ METHOD(task_manager_t, process_message, status_t, this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, time_monotonic(NULL)); this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); - charon->bus->message(charon->bus, msg, FALSE); + charon->bus->message(charon->bus, msg, TRUE); if (process_response(this, msg) != SUCCESS) { flush(this); From 5b7fc7686187838d738ad7985cd3dc808c5bc30f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 16 Jan 2012 15:57:46 +0100 Subject: [PATCH 467/534] Don't invoke updown hook when flushing SAs for IKEv1, tasks will do it --- src/libcharon/sa/ike_sa_manager.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 2b4418f24..79a52c918 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1695,16 +1695,18 @@ METHOD(ike_sa_manager_t, flush, void, while (enumerator->enumerate(enumerator, &entry, &segment)) { charon->bus->set_sa(charon->bus, entry->ike_sa); - /* as the delete never gets processed, fire down events */ - switch (entry->ike_sa->get_state(entry->ike_sa)) - { - case IKE_ESTABLISHED: - case IKE_REKEYING: - case IKE_DELETING: - charon->bus->ike_updown(charon->bus, entry->ike_sa, FALSE); - break; - default: - break; + if (entry->ike_sa->get_version(entry->ike_sa) == IKEV2) + { /* as the delete never gets processed, fire down events */ + switch (entry->ike_sa->get_state(entry->ike_sa)) + { + case IKE_ESTABLISHED: + case IKE_REKEYING: + case IKE_DELETING: + charon->bus->ike_updown(charon->bus, entry->ike_sa, FALSE); + break; + default: + break; + } } entry->ike_sa->delete(entry->ike_sa); } From 669d8bded29d895678b74ed19cab21e34235d657 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 16 Jan 2012 16:17:27 +0100 Subject: [PATCH 468/534] Invoke child_rekey hook instead of child_updown when rekeying a quick mode --- src/libcharon/sa/ikev1/task_manager_v1.c | 1 + src/libcharon/sa/ikev1/tasks/quick_mode.c | 30 +++++++++++++++++++++-- src/libcharon/sa/ikev1/tasks/quick_mode.h | 7 ++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 5695b4e3e..3e46266da 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1326,6 +1326,7 @@ METHOD(task_manager_t, queue_child_rekey, void, cfg = child_sa->get_config(child_sa); task = quick_mode_create(this->ike_sa, cfg->get_ref(cfg), NULL, NULL); task->use_reqid(task, child_sa->get_reqid(child_sa)); + task->rekey(task, child_sa->get_spi(child_sa, TRUE)); queue_task(this, &task->task); } diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index dedeab189..bc2b5cfd1 100755 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -119,6 +119,11 @@ struct private_quick_mode_t { */ u_int32_t reqid; + /** + * SPI of SA we rekey + */ + u_int32_t rekey; + /** * Negotiated mode, tunnel or transport */ @@ -139,6 +144,7 @@ static bool install(private_quick_mode_t *this) status_t status, status_i, status_o; chunk_t encr_i, encr_r, integ_i, integ_r; linked_list_t *tsi, *tsr; + child_sa_t *old = NULL; this->child_sa->set_proposal(this->child_sa, this->proposal); this->child_sa->set_state(this->child_sa, CHILD_INSTALLING); @@ -219,8 +225,20 @@ static bool install(private_quick_mode_t *this) this->child_sa->get_traffic_selectors(this->child_sa, TRUE), this->child_sa->get_traffic_selectors(this->child_sa, FALSE)); - charon->bus->child_updown(charon->bus, this->child_sa, TRUE); - + if (this->rekey) + { + old = this->ike_sa->get_child_sa(this->ike_sa, + this->proposal->get_protocol(this->proposal), + this->rekey, TRUE); + } + if (old) + { + charon->bus->child_rekey(charon->bus, old, this->child_sa); + } + else + { + charon->bus->child_updown(charon->bus, this->child_sa, TRUE); + } this->child_sa = NULL; return TRUE; @@ -691,6 +709,7 @@ static void check_for_rekeyed_child(private_quick_mode_t *this) child_sa->get_proposal(child_sa))) { this->reqid = child_sa->get_reqid(child_sa); + this->rekey = child_sa->get_spi(child_sa, TRUE); child_sa->set_state(child_sa, CHILD_REKEYING); DBG1(DBG_IKE, "detected rekeying of CHILD_SA %s{%u}", child_sa->get_name(child_sa), this->reqid); @@ -943,6 +962,12 @@ METHOD(quick_mode_t, use_reqid, void, this->reqid = reqid; } +METHOD(quick_mode_t, rekey, void, + private_quick_mode_t *this, u_int32_t spi) +{ + this->rekey = spi; +} + METHOD(task_t, migrate, void, private_quick_mode_t *this, ike_sa_t *ike_sa) { @@ -1002,6 +1027,7 @@ quick_mode_t *quick_mode_create(ike_sa_t *ike_sa, child_cfg_t *config, .destroy = _destroy, }, .use_reqid = _use_reqid, + .rekey = _rekey, }, .ike_sa = ike_sa, .initiator = config != NULL, diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.h b/src/libcharon/sa/ikev1/tasks/quick_mode.h index 88fbe4935..295fb1926 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.h +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.h @@ -43,6 +43,13 @@ struct quick_mode_t { * @param reqid reqid to use */ void (*use_reqid)(quick_mode_t *this, u_int32_t reqid); + + /** + * Set the SPI of the old SA, if rekeying. + * + * @param spi spi of SA to rekey + */ + void (*rekey)(quick_mode_t *this, u_int32_t spi); }; /** From b6ac063c363b076959f38d5c01461947a58e8677 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 16 Jan 2012 16:18:01 +0100 Subject: [PATCH 469/534] Don't invoke a child_updown hook when a quick mode to delete has been rekeyed --- src/libcharon/sa/ikev1/tasks/quick_delete.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_delete.c b/src/libcharon/sa/ikev1/tasks/quick_delete.c index 9a502f58c..6e4194ee2 100644 --- a/src/libcharon/sa/ikev1/tasks/quick_delete.c +++ b/src/libcharon/sa/ikev1/tasks/quick_delete.c @@ -69,6 +69,7 @@ static bool delete_child(private_quick_delete_t *this, { u_int64_t bytes_in, bytes_out; child_sa_t *child_sa; + bool rekeyed; child_sa = this->ike_sa->get_child_sa(this->ike_sa, protocol, spi, TRUE); if (!child_sa) @@ -81,6 +82,7 @@ static bool delete_child(private_quick_delete_t *this, this->spi = spi = child_sa->get_spi(child_sa, TRUE); } + rekeyed = child_sa->get_state(child_sa) == CHILD_REKEYING; child_sa->set_state(child_sa, CHILD_DELETING); if (this->expired) @@ -107,7 +109,10 @@ static bool delete_child(private_quick_delete_t *this, child_sa->get_traffic_selectors(child_sa, FALSE)); } - charon->bus->child_updown(charon->bus, child_sa, FALSE); + if (!rekeyed) + { + charon->bus->child_updown(charon->bus, child_sa, FALSE); + } this->ike_sa->destroy_child_sa(this->ike_sa, protocol, spi); From 1a0648490ccf55f7d8c823c8f5ff5b59d7763a54 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 16 Jan 2012 16:47:18 +0100 Subject: [PATCH 470/534] Invoke ike_updown hooks for reauthenticated IKEv1 SAs --- src/libcharon/processing/jobs/adopt_children_job.c | 1 + src/libcharon/sa/ike_sa.c | 1 + 2 files changed, 2 insertions(+) diff --git a/src/libcharon/processing/jobs/adopt_children_job.c b/src/libcharon/processing/jobs/adopt_children_job.c index 6f7e119da..744b7f9b7 100644 --- a/src/libcharon/processing/jobs/adopt_children_job.c +++ b/src/libcharon/processing/jobs/adopt_children_job.c @@ -104,6 +104,7 @@ METHOD(job_t, execute, void, DBG1(DBG_IKE, "detected reauth of existing IKE_SA, " "adopting %d children", children->get_count(children)); ike_sa->set_state(ike_sa, IKE_DELETING); + charon->bus->ike_updown(charon->bus, ike_sa, FALSE); charon->ike_sa_manager->checkin_and_destroy( charon->ike_sa_manager, ike_sa); } diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 98d636fe1..cff7990f1 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1318,6 +1318,7 @@ METHOD(ike_sa_t, delete_, status_t, case IKE_REKEYING: if (this->version == IKEV1) { /* SA has been reauthenticated, delete */ + charon->bus->ike_updown(charon->bus, &this->public, FALSE); break; } /* FALL */ From f420f51f55f3641553411b74f4925bd9f64116b5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 18 Jan 2012 13:12:07 +0100 Subject: [PATCH 471/534] Invoke authorization hooks for IKEv1 connections --- .../sa/ikev1/tasks/aggressive_mode.c | 50 +++++++++++++++---- src/libcharon/sa/ikev1/tasks/main_mode.c | 47 +++++++++++++---- src/libcharon/sa/ikev1/tasks/xauth.c | 23 +++++++-- 3 files changed, 95 insertions(+), 25 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c index 1fe36a9d5..b89b71b4c 100755 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -95,8 +95,14 @@ struct private_aggressive_mode_t { /** * Set IKE_SA to established state */ -static void establish(private_aggressive_mode_t *this) +static bool establish(private_aggressive_mode_t *this) { + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + return FALSE; + } + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa), @@ -107,6 +113,8 @@ static void establish(private_aggressive_mode_t *this) this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + return TRUE; } /** @@ -278,28 +286,31 @@ METHOD(task_t, build_i, status_t, } this->id_data = chunk_empty; - if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) - { - this->ike_sa->queue_task(this->ike_sa, - (task_t*)mode_config_create(this->ike_sa, TRUE)); - } - switch (this->method) { case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_INIT_RSA: case AUTH_HYBRID_INIT_RSA: /* wait for XAUTH request */ - return SUCCESS; + break; case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: case AUTH_HYBRID_RESP_RSA: /* TODO-IKEv1: not yet */ return FAILED; default: - establish(this); - return SUCCESS; + if (!establish(this)) + { + return send_notify(this, AUTHENTICATION_FAILED); + } + break; } + if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE)); + } + return SUCCESS; } default: return FAILED; @@ -405,6 +416,13 @@ METHOD(task_t, process_r, status_t, } this->id_data = chunk_empty; + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "Aggressive Mode authorization hook forbids " + "IKE_SA, cancelling"); + return send_delete(this); + } + switch (this->method) { case AUTH_XAUTH_INIT_PSK: @@ -419,7 +437,10 @@ METHOD(task_t, process_r, status_t, /* TODO-IKEv1: not yet supported */ return FAILED; default: - establish(this); + if (!establish(this)) + { + return send_delete(this); + } lib->processor->queue_job(lib->processor, (job_t*) adopt_children_job_create( this->ike_sa->get_id(this->ike_sa))); @@ -557,6 +578,13 @@ METHOD(task_t, process_i, status_t, { return send_notify(this, AUTHENTICATION_FAILED); } + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "Aggressive Mode authorization hook forbids IKE_SA, " + "cancelling"); + return send_notify(this, AUTHENTICATION_FAILED); + } + return NEED_MORE; } return FAILED; diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index ba1a9ad1d..c1a61cede 100755 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -95,8 +95,14 @@ struct private_main_mode_t { /** * Set IKE_SA to established state */ -static void establish(private_main_mode_t *this) +static bool establish(private_main_mode_t *this) { + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + return FALSE; + } + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa), @@ -107,6 +113,8 @@ static void establish(private_main_mode_t *this) this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + return TRUE; } /** @@ -406,6 +414,13 @@ METHOD(task_t, process_r, status_t, { return send_notify(this, AUTHENTICATION_FAILED); } + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "Main Mode authorization hook forbids IKE_SA, " + "cancelling"); + return send_notify(this, AUTHENTICATION_FAILED); + } + this->state = MM_AUTH; if (has_notify_errors(this, message)) { @@ -467,6 +482,7 @@ METHOD(task_t, build_r, status_t, { return send_notify(this, AUTHENTICATION_FAILED); } + switch (this->method) { case AUTH_XAUTH_INIT_PSK: @@ -481,7 +497,10 @@ METHOD(task_t, build_r, status_t, /* TODO-IKEv1: not yet supported */ return FAILED; default: - establish(this); + if (!establish(this)) + { + return send_notify(this, AUTHENTICATION_FAILED); + } lib->processor->queue_job(lib->processor, (job_t*) adopt_children_job_create( this->ike_sa->get_id(this->ike_sa))); @@ -577,29 +596,37 @@ METHOD(task_t, process_i, status_t, { return send_delete(this); } - - if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) + if (!charon->bus->authorize(charon->bus, FALSE)) { - this->ike_sa->queue_task(this->ike_sa, - (task_t*)mode_config_create(this->ike_sa, TRUE)); + DBG1(DBG_IKE, "Main Mode authorization hook forbids IKE_SA, " + "cancelling"); + return send_delete(this); } - switch (this->method) { case AUTH_XAUTH_INIT_PSK: case AUTH_XAUTH_INIT_RSA: case AUTH_HYBRID_INIT_RSA: /* wait for XAUTH request */ - return SUCCESS; + break; case AUTH_XAUTH_RESP_PSK: case AUTH_XAUTH_RESP_RSA: case AUTH_HYBRID_RESP_RSA: /* TODO-IKEv1: not yet */ return FAILED; default: - establish(this); - return SUCCESS; + if (!establish(this)) + { + return send_delete(this); + } + break; } + if (this->peer_cfg->get_virtual_ip(this->peer_cfg)) + { + this->ike_sa->queue_task(this->ike_sa, + (task_t*)mode_config_create(this->ike_sa, TRUE)); + } + return SUCCESS; } default: return FAILED; diff --git a/src/libcharon/sa/ikev1/tasks/xauth.c b/src/libcharon/sa/ikev1/tasks/xauth.c index e836bed16..aa79811f7 100755 --- a/src/libcharon/sa/ikev1/tasks/xauth.c +++ b/src/libcharon/sa/ikev1/tasks/xauth.c @@ -140,8 +140,19 @@ static xauth_method_t *load_method(private_xauth_t* this) /** * Set IKE_SA to established state */ -static void establish(private_xauth_t *this) +static bool establish(private_xauth_t *this) { + if (!charon->bus->authorize(charon->bus, FALSE)) + { + DBG1(DBG_IKE, "XAuth authorization hook forbids IKE_SA, cancelling"); + return FALSE; + } + if (!charon->bus->authorize(charon->bus, TRUE)) + { + DBG1(DBG_IKE, "final authorization hook forbids IKE_SA, cancelling"); + return FALSE; + } + DBG0(DBG_IKE, "IKE_SA %s[%d] established between %H[%Y]...%H[%Y]", this->ike_sa->get_name(this->ike_sa), this->ike_sa->get_unique_id(this->ike_sa), @@ -152,6 +163,8 @@ static void establish(private_xauth_t *this) this->ike_sa->set_state(this->ike_sa, IKE_ESTABLISHED); charon->bus->ike_updown(charon->bus, this->ike_sa, TRUE); + + return TRUE; } METHOD(task_t, build_i_status, status_t, @@ -210,9 +223,8 @@ METHOD(task_t, build_r_ack, status_t, message->add_payload(message, (payload_t *)cp); - if (this->status == XAUTH_OK) + if (this->status == XAUTH_OK && establish(this)) { - establish(this); lib->processor->queue_job(lib->processor, (job_t*) adopt_children_job_create(this->ike_sa->get_id(this->ike_sa))); return SUCCESS; @@ -311,7 +323,10 @@ METHOD(task_t, process_i_status, status_t, DBG1(DBG_IKE, "destroying IKE_SA after failed XAuth authentication"); return FAILED; } - establish(this); + if (!establish(this)) + { + return FAILED; + } this->ike_sa->set_condition(this->ike_sa, COND_XAUTH_AUTHENTICATED, TRUE); return SUCCESS; } From 696fa8e003f9e0a441f805ef2809b150fd47cc79 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 18 Jan 2012 13:28:15 +0100 Subject: [PATCH 472/534] Invoke bus_t.narrow hook in quick mode exchange --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 43 +++++++++++++++++++---- 1 file changed, 36 insertions(+), 7 deletions(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index bc2b5cfd1..6956dcb40 100755 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -156,8 +156,26 @@ static bool install(private_quick_mode_t *this) encr_i = encr_r = integ_i = integ_r = chunk_empty; tsi = linked_list_create(); tsr = linked_list_create(); - tsi->insert_last(tsi, this->tsi); - tsr->insert_last(tsr, this->tsr); + tsi->insert_last(tsi, this->tsi->clone(this->tsi)); + tsr->insert_last(tsr, this->tsr->clone(this->tsr)); + if (this->initiator) + { + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_INITIATOR_POST_AUTH, tsi, tsr); + } + else + { + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_RESPONDER, tsr, tsi); + } + if (tsi->get_count(tsi) == 0 || tsr->get_count(tsr) == 0) + { + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); + DBG1(DBG_IKE, "no acceptable traffic selectors found"); + return FALSE; + } + if (this->keymat->derive_child_keys(this->keymat, this->proposal, this->dh, this->spi_i, this->spi_r, this->nonce_i, this->nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) @@ -188,8 +206,8 @@ static bool install(private_quick_mode_t *this) (status_i != SUCCESS) ? "inbound " : "", (status_i != SUCCESS && status_o != SUCCESS) ? "and ": "", (status_o != SUCCESS) ? "outbound " : ""); - tsi->destroy(tsi); - tsr->destroy(tsr); + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); return FALSE; } @@ -201,8 +219,8 @@ static bool install(private_quick_mode_t *this) { status = this->child_sa->add_policies(this->child_sa, tsr, tsi); } - tsi->destroy(tsi); - tsr->destroy(tsr); + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); if (status != SUCCESS) { DBG1(DBG_IKE, "unable to install IPsec policies (SPD) in kernel"); @@ -571,7 +589,7 @@ METHOD(task_t, build_i, status_t, { enumerator_t *enumerator; sa_payload_t *sa_payload; - linked_list_t *list; + linked_list_t *list, *tsi, *tsr; proposal_t *proposal; diffie_hellman_group_t group; bool udp; @@ -631,6 +649,17 @@ METHOD(task_t, build_i, status_t, } this->tsi = select_ts(this, TRUE, NULL); this->tsr = select_ts(this, FALSE, NULL); + tsi = linked_list_create(); + tsr = linked_list_create(); + tsi->insert_last(tsi, this->tsi); + tsr->insert_last(tsr, this->tsr); + this->tsi = this->tsr = NULL; + charon->bus->narrow(charon->bus, this->child_sa, + NARROW_INITIATOR_PRE_AUTH, tsi, tsr); + tsi->remove_first(tsi, (void**)&this->tsi); + tsr->remove_first(tsr, (void**)&this->tsr); + tsi->destroy_offset(tsi, offsetof(traffic_selector_t, destroy)); + tsr->destroy_offset(tsr, offsetof(traffic_selector_t, destroy)); if (!this->tsi || !this->tsr) { return FAILED; From 3957a6e4f31eb893668caf7cad8b352a6e65e06f Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 18 Jan 2012 17:24:08 +0100 Subject: [PATCH 473/534] Get a reference for the child_cfg passed to child_create_create() --- src/libcharon/sa/ikev2/tasks/child_rekey.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/ikev2/tasks/child_rekey.c b/src/libcharon/sa/ikev2/tasks/child_rekey.c index 28de072c0..17102b0d4 100644 --- a/src/libcharon/sa/ikev2/tasks/child_rekey.c +++ b/src/libcharon/sa/ikev2/tasks/child_rekey.c @@ -161,8 +161,8 @@ METHOD(task_t, build_i, status_t, /* ... our CHILD_CREATE task does the hard work for us. */ if (!this->child_create) { - this->child_create = child_create_create(this->ike_sa, config, TRUE, - NULL, NULL); + this->child_create = child_create_create(this->ike_sa, + config->get_ref(config), TRUE, NULL, NULL); } reqid = this->child_sa->get_reqid(this->child_sa); this->child_create->use_reqid(this->child_create, reqid); From 6bc6f67b0f661483fdec413d73f80e419438f817 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 18 Jan 2012 17:24:31 +0100 Subject: [PATCH 474/534] Updated HA plugin to new IKEv2 specific keymat functions --- src/libcharon/plugins/ha/ha_dispatcher.c | 28 ++++++++++++++++-------- src/libcharon/plugins/ha/ha_ike.c | 8 ++++--- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 71c458a89..5f48143b7 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -16,6 +16,7 @@ #include "ha_dispatcher.h" #include +#include #include typedef struct private_ha_dispatcher_t private_ha_dispatcher_t; @@ -82,6 +83,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message u_int16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED; chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty; chunk_t secret = chunk_empty, old_skd = chunk_empty; + bool ok = FALSE; enumerator = message->create_attribute_enumerator(message); while (enumerator->enumerate(enumerator, &attribute, &value)) @@ -132,13 +134,11 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message if (ike_sa) { proposal_t *proposal; - keymat_t *keymat; /* quick and dirty hack of a DH implementation ;-) */ diffie_hellman_t dh = { .get_shared_secret = get_shared_secret, .destroy = (void*)&secret }; proposal = proposal_create(PROTO_IKE, 0); - keymat = ike_sa->get_keymat(ike_sa); if (integ) { proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, integ, 0); @@ -152,8 +152,14 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0); } charon->bus->set_sa(charon->bus, ike_sa); - if (keymat->derive_ike_keys(keymat, proposal, &dh, nonce_i, nonce_r, - ike_sa->get_id(ike_sa), old_prf, old_skd)) + if (ike_sa->get_version(ike_sa) == IKEV2) + { + keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); + + ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, &dh, nonce_i, + nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd); + } + if (ok) { if (old_sa) { @@ -462,8 +468,7 @@ static void process_child_add(private_ha_dispatcher_t *this, child_cfg_t *config = NULL; child_sa_t *child_sa; proposal_t *proposal; - keymat_t *keymat; - bool initiator = FALSE, failed = FALSE; + bool initiator = FALSE, failed = FALSE, ok = FALSE; u_int32_t inbound_spi = 0, outbound_spi = 0; u_int16_t inbound_cpi = 0, outbound_cpi = 0; u_int8_t mode = MODE_TUNNEL, ipcomp = 0; @@ -569,10 +574,15 @@ static void process_child_add(private_ha_dispatcher_t *this, proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len); } proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0); - keymat = ike_sa->get_keymat(ike_sa); + if (ike_sa->get_version(ike_sa) == IKEV2) + { + keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); - if (!keymat->derive_child_keys(keymat, proposal, secret.ptr ? &dh : NULL, - nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r)) + ok = keymat_v2->derive_child_keys(keymat_v2, + proposal, secret.ptr ? &dh : NULL, nonce_i, nonce_r, + &encr_i, &integ_i, &encr_r, &integ_r); + } + if (!ok) { DBG1(DBG_CHD, "HA CHILD_SA key derivation failed"); child_sa->destroy(child_sa); diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index ce1067134..7da11b558 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -15,6 +15,8 @@ #include "ha_ike.h" +#include + typedef struct private_ha_ike_t private_ha_ike_t; /** @@ -88,12 +90,12 @@ METHOD(listener_t, ike_keys, bool, m = ha_message_create(HA_IKE_ADD); m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); - if (rekey) + if (rekey && rekey->get_version(rekey) == IKEV2) { chunk_t skd; - keymat_t *keymat; + keymat_v2_t *keymat; - keymat = rekey->get_keymat(rekey); + keymat = (keymat_v2_t*)rekey->get_keymat(rekey); m->add_attribute(m, HA_IKE_REKEY_ID, rekey->get_id(rekey)); m->add_attribute(m, HA_ALG_OLD_PRF, keymat->get_skd(keymat, &skd)); m->add_attribute(m, HA_OLD_SKD, skd); From 3624b09e21b0deab788db0dfea63e2c324d5284c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 18 Jan 2012 17:42:06 +0100 Subject: [PATCH 475/534] Set selected proposal on IKEv1 SA, don't pass it separately to Phase 1 helper --- src/libcharon/sa/ikev1/phase1.c | 11 ++++++----- src/libcharon/sa/ikev1/phase1.h | 6 ++---- src/libcharon/sa/ikev1/tasks/aggressive_mode.c | 12 ++++++------ src/libcharon/sa/ikev1/tasks/main_mode.c | 12 ++++++------ 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c index ed5fbe5c9..a5fa6ea1b 100644 --- a/src/libcharon/sa/ikev1/phase1.c +++ b/src/libcharon/sa/ikev1/phase1.c @@ -173,9 +173,10 @@ static shared_key_t *lookup_shared_key(private_phase1_t *this, } METHOD(phase1_t, create_hasher, bool, - private_phase1_t *this, proposal_t *proposal) + private_phase1_t *this) { - return this->keymat->create_hasher(this->keymat, proposal); + return this->keymat->create_hasher(this->keymat, + this->ike_sa->get_proposal(this->ike_sa)); } METHOD(phase1_t, create_dh, bool, @@ -186,8 +187,7 @@ METHOD(phase1_t, create_dh, bool, } METHOD(phase1_t, derive_keys, bool, - private_phase1_t *this, peer_cfg_t *peer_cfg, auth_method_t method, - proposal_t *proposal) + private_phase1_t *this, peer_cfg_t *peer_cfg, auth_method_t method) { shared_key_t *shared_key = NULL; @@ -206,7 +206,8 @@ METHOD(phase1_t, derive_keys, bool, break; } - if (!this->keymat->derive_ike_keys(this->keymat, proposal, + if (!this->keymat->derive_ike_keys(this->keymat, + this->ike_sa->get_proposal(this->ike_sa), this->dh, this->dh_value, this->nonce_i, this->nonce_r, this->ike_sa->get_id(this->ike_sa), method, shared_key)) { diff --git a/src/libcharon/sa/ikev1/phase1.h b/src/libcharon/sa/ikev1/phase1.h index 994c85be7..91210c31f 100644 --- a/src/libcharon/sa/ikev1/phase1.h +++ b/src/libcharon/sa/ikev1/phase1.h @@ -34,10 +34,9 @@ struct phase1_t { /** * Create keymat hasher. * - * @param proposal negotiated proposal * @return TRUE if hasher created */ - bool (*create_hasher)(phase1_t *this, proposal_t *proposal); + bool (*create_hasher)(phase1_t *this); /** * Create DH object using SA keymat. @@ -52,11 +51,10 @@ struct phase1_t { * * @param peer_cfg peer config to look up shared key for, or NULL * @param method negotiated authenticated method - * @param proposal selected IKE proposal * @return TRUE if successful */ bool (*derive_keys)(phase1_t *this, peer_cfg_t *peer_cfg, - auth_method_t method, proposal_t *proposal); + auth_method_t method); /** * Verify a HASH or SIG payload in message. * diff --git a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c index b89b71b4c..9621e7099 100755 --- a/src/libcharon/sa/ikev1/tasks/aggressive_mode.c +++ b/src/libcharon/sa/ikev1/tasks/aggressive_mode.c @@ -360,6 +360,7 @@ METHOD(task_t, process_r, status_t, DBG1(DBG_IKE, "no proposal found"); return send_notify(this, NO_PROPOSAL_CHOSEN); } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); this->method = sa_payload->get_auth_method(sa_payload); this->lifetime = sa_payload->get_lifetime(sa_payload); @@ -469,12 +470,11 @@ METHOD(task_t, build_r, status_t, { return send_notify(this, INVALID_KEY_INFORMATION); } - if (!this->ph1->create_hasher(this->ph1, this->proposal)) + if (!this->ph1->create_hasher(this->ph1)) { return send_notify(this, NO_PROPOSAL_CHOSEN); } - if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method, - this->proposal)) + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method)) { return send_notify(this, INVALID_KEY_INFORMATION); } @@ -528,6 +528,7 @@ METHOD(task_t, process_i, status_t, DBG1(DBG_IKE, "no proposal found"); return send_notify(this, NO_PROPOSAL_CHOSEN); } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); lifetime = sa_payload->get_lifetime(sa_payload); if (lifetime != this->lifetime) @@ -547,12 +548,11 @@ METHOD(task_t, process_i, status_t, { return send_notify(this, INVALID_PAYLOAD_TYPE); } - if (!this->ph1->create_hasher(this->ph1, this->proposal)) + if (!this->ph1->create_hasher(this->ph1)) { return send_notify(this, NO_PROPOSAL_CHOSEN); } - if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method, - this->proposal)) + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method)) { return send_notify(this, INVALID_KEY_INFORMATION); } diff --git a/src/libcharon/sa/ikev1/tasks/main_mode.c b/src/libcharon/sa/ikev1/tasks/main_mode.c index c1a61cede..a7be22916 100755 --- a/src/libcharon/sa/ikev1/tasks/main_mode.c +++ b/src/libcharon/sa/ikev1/tasks/main_mode.c @@ -262,7 +262,7 @@ METHOD(task_t, build_i, status_t, { u_int16_t group; - if (!this->ph1->create_hasher(this->ph1, this->proposal)) + if (!this->ph1->create_hasher(this->ph1)) { return send_notify(this, NO_PROPOSAL_CHOSEN); } @@ -353,6 +353,7 @@ METHOD(task_t, process_r, status_t, DBG1(DBG_IKE, "no proposal found"); return send_notify(this, NO_PROPOSAL_CHOSEN); } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); this->method = sa_payload->get_auth_method(sa_payload); this->lifetime = sa_payload->get_lifetime(sa_payload); @@ -364,7 +365,7 @@ METHOD(task_t, process_r, status_t, { u_int16_t group; - if (!this->ph1->create_hasher(this->ph1, this->proposal)) + if (!this->ph1->create_hasher(this->ph1)) { return send_notify(this, INVALID_KEY_INFORMATION); } @@ -454,8 +455,7 @@ METHOD(task_t, build_r, status_t, { return send_notify(this, INVALID_KEY_INFORMATION); } - if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method, - this->proposal)) + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method)) { return send_notify(this, INVALID_KEY_INFORMATION); } @@ -540,6 +540,7 @@ METHOD(task_t, process_i, status_t, DBG1(DBG_IKE, "no proposal found"); return send_notify(this, NO_PROPOSAL_CHOSEN); } + this->ike_sa->set_proposal(this->ike_sa, this->proposal); lifetime = sa_payload->get_lifetime(sa_payload); if (lifetime != this->lifetime) @@ -563,8 +564,7 @@ METHOD(task_t, process_i, status_t, { return send_notify(this, INVALID_PAYLOAD_TYPE); } - if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, - this->method, this->proposal)) + if (!this->ph1->derive_keys(this->ph1, this->peer_cfg, this->method)) { return send_notify(this, INVALID_KEY_INFORMATION); } From c3f1839ab7b675ab6f05467b7909d44fa28300a9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 18 Jan 2012 17:49:52 +0100 Subject: [PATCH 476/534] Apply proposal to a HA synced IKE_SA --- src/libcharon/plugins/ha/ha_dispatcher.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 5f48143b7..6cd305671 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -175,6 +175,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message old_sa = NULL; } ike_sa->set_state(ike_sa, IKE_CONNECTING); + ike_sa->set_proposal(ike_sa, proposal); this->cache->cache(this->cache, ike_sa, message); message = NULL; charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); From 5763367cac7668c11949871635ed71a2dc1a7f5b Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 18 Jan 2012 17:50:07 +0100 Subject: [PATCH 477/534] Show IKE version in ipsec statusall --- src/libcharon/plugins/stroke/stroke_list.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index 19fc46418..c69eef628 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -118,8 +118,9 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) ike_proposal = ike_sa->get_proposal(ike_sa); - fprintf(out, "%12s[%d]: IKE SPIs: %.16"PRIx64"_i%s %.16"PRIx64"_r%s", + fprintf(out, "%12s[%d]: %N SPIs: %.16"PRIx64"_i%s %.16"PRIx64"_r%s", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), + ike_version_names, ike_sa->get_version(ike_sa), id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "", id->get_responder_spi(id), id->is_initiator(id) ? "" : "*"); From 264514826cf8417d5c86a4ff8ea7a3c4b23149a4 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 18 Jan 2012 18:24:48 +0100 Subject: [PATCH 478/534] Use a more complete implementation of a HA specific diffie_hellman_t --- src/libcharon/plugins/ha/ha_dispatcher.c | 61 +++++++++++++++++++----- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 6cd305671..f0e6e5ecf 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -20,6 +20,7 @@ #include typedef struct private_ha_dispatcher_t private_ha_dispatcher_t; +typedef struct ha_diffie_hellman_t ha_diffie_hellman_t; /** * Private data of an ha_dispatcher_t object. @@ -63,14 +64,52 @@ struct private_ha_dispatcher_t { }; /** - * Quick and dirty hack implementation of diffie_hellman_t.get_shared_secret + * DH implementation for HA synced DH values */ -static status_t get_shared_secret(diffie_hellman_t *this, chunk_t *secret) +struct ha_diffie_hellman_t { + + /** + * Implements diffie_hellman_t + */ + diffie_hellman_t dh; + + /** + * Shared secret + */ + chunk_t secret; +}; + +METHOD(diffie_hellman_t, dh_get_shared_secret, status_t, + ha_diffie_hellman_t *this, chunk_t *secret) { - *secret = chunk_clone((*(chunk_t*)this->destroy)); + *secret = chunk_clone(this->secret); return SUCCESS; } +METHOD(diffie_hellman_t, dh_destroy, void, + ha_diffie_hellman_t *this) +{ + free(this); +} + +/** + * Create a HA synced DH implementation + */ +static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret) +{ + ha_diffie_hellman_t *this; + + INIT(this, + .dh = { + .get_shared_secret = _dh_get_shared_secret, + .destroy = _dh_destroy, + }, + .secret = secret, + ); + + return &this->dh; +} + /** * Process messages of type IKE_ADD */ @@ -134,9 +173,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message if (ike_sa) { proposal_t *proposal; - /* quick and dirty hack of a DH implementation ;-) */ - diffie_hellman_t dh = { .get_shared_secret = get_shared_secret, - .destroy = (void*)&secret }; + diffie_hellman_t *dh; proposal = proposal_create(PROTO_IKE, 0); if (integ) @@ -152,13 +189,15 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0); } charon->bus->set_sa(charon->bus, ike_sa); + dh = ha_diffie_hellman_create(secret); if (ike_sa->get_version(ike_sa) == IKEV2) { keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); - ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, &dh, nonce_i, + ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, dh, nonce_i, nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd); } + dh->destroy(dh); if (ok) { if (old_sa) @@ -479,9 +518,7 @@ static void process_child_add(private_ha_dispatcher_t *this, chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty; chunk_t encr_i, integ_i, encr_r, integ_r; linked_list_t *local_ts, *remote_ts; - /* quick and dirty hack of a DH implementation */ - diffie_hellman_t dh = { .get_shared_secret = get_shared_secret, - .destroy = (void*)&secret }; + diffie_hellman_t *dh; enumerator = message->create_attribute_enumerator(message); while (enumerator->enumerate(enumerator, &attribute, &value)) @@ -575,14 +612,16 @@ static void process_child_add(private_ha_dispatcher_t *this, proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len); } proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0); + dh = ha_diffie_hellman_create(secret); if (ike_sa->get_version(ike_sa) == IKEV2) { keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); ok = keymat_v2->derive_child_keys(keymat_v2, - proposal, secret.ptr ? &dh : NULL, nonce_i, nonce_r, + proposal, secret.ptr ? dh : NULL, nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r); } + dh->destroy(dh); if (!ok) { DBG1(DBG_CHD, "HA CHILD_SA key derivation failed"); From 23f9e7a18dde587557e4ee8c34acc60211d947f3 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Wed, 18 Jan 2012 18:34:07 +0100 Subject: [PATCH 479/534] Pass IKEv1 specific keymat to ike_keys hook --- src/libcharon/bus/bus.c | 7 ++++--- src/libcharon/bus/bus.h | 7 +++++-- src/libcharon/bus/listeners/listener.h | 7 +++++-- src/libcharon/plugins/ha/ha_ike.c | 3 ++- src/libcharon/sa/ikev1/phase1.c | 4 ++-- src/libcharon/sa/ikev2/tasks/ike_init.c | 4 ++-- 6 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c index bf0ab2286..c1b2bd458 100644 --- a/src/libcharon/bus/bus.c +++ b/src/libcharon/bus/bus.c @@ -438,7 +438,8 @@ METHOD(bus_t, message, void, METHOD(bus_t, ike_keys, void, private_bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey) + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, + ike_sa_t *rekey, shared_key_t *shared) { enumerator_t *enumerator; entry_t *entry; @@ -453,8 +454,8 @@ METHOD(bus_t, ike_keys, void, continue; } entry->calling++; - keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, - nonce_i, nonce_r, rekey); + keep = entry->listener->ike_keys(entry->listener, ike_sa, dh, dh_other, + nonce_i, nonce_r, rekey, shared); entry->calling--; if (!keep) { diff --git a/src/libcharon/bus/bus.h b/src/libcharon/bus/bus.h index 69060d383..07b334f29 100644 --- a/src/libcharon/bus/bus.h +++ b/src/libcharon/bus/bus.h @@ -264,12 +264,15 @@ struct bus_t { * * @param ike_sa IKE_SA this keymat belongs to * @param dh diffie hellman shared secret + * @param dh_other others DH public value (IKEv1 only) * @param nonce_i initiators nonce * @param nonce_r responders nonce - * @param rekey IKE_SA we are rekeying, if any + * @param rekey IKE_SA we are rekeying, if any (IKEv2 only) + * @param shared shared key used for key derivation (IKEv1-PSK only) */ void (*ike_keys)(bus_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey); + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, + ike_sa_t *rekey, shared_key_t *shared); /** * CHILD_SA keymat hook. * diff --git a/src/libcharon/bus/listeners/listener.h b/src/libcharon/bus/listeners/listener.h index 21caed064..efadea8c5 100644 --- a/src/libcharon/bus/listeners/listener.h +++ b/src/libcharon/bus/listeners/listener.h @@ -97,13 +97,16 @@ struct listener_t { * * @param ike_sa IKE_SA this keymat belongs to * @param dh diffie hellman shared secret + * @param dh_other others DH public value (IKEv1 only) * @param nonce_i initiators nonce * @param nonce_r responders nonce - * @param rekey IKE_SA we are rekeying, if any + * @param rekey IKE_SA we are rekeying, if any (IKEv2 only) + * @param shared shared key used for key derivation (IKEv1-PSK only) * @return TRUE to stay registered, FALSE to unregister */ bool (*ike_keys)(listener_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey); + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, + ike_sa_t *rekey, shared_key_t *shared); /** * Hook called with CHILD_SA key material. diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index 7da11b558..bcdd09b3e 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -71,7 +71,8 @@ static ike_extension_t copy_extension(ike_sa_t *ike_sa, ike_extension_t ext) METHOD(listener_t, ike_keys, bool, private_ha_ike_t *this, ike_sa_t *ike_sa, diffie_hellman_t *dh, - chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey) + chunk_t dh_other, chunk_t nonce_i, chunk_t nonce_r, ike_sa_t *rekey, + shared_key_t *shared) { ha_message_t *m; chunk_t secret; diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c index a5fa6ea1b..d36b022aa 100644 --- a/src/libcharon/sa/ikev1/phase1.c +++ b/src/libcharon/sa/ikev1/phase1.c @@ -215,9 +215,9 @@ METHOD(phase1_t, derive_keys, bool, DBG1(DBG_IKE, "key derivation for %N failed", auth_method_names, method); return FALSE; } + charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, this->dh_value, + this->nonce_i, this->nonce_r, NULL, shared_key); DESTROY_IF(shared_key); - charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, - this->nonce_i, this->nonce_r, NULL); return TRUE; } diff --git a/src/libcharon/sa/ikev2/tasks/ike_init.c b/src/libcharon/sa/ikev2/tasks/ike_init.c index ceae484d0..de68e8662 100644 --- a/src/libcharon/sa/ikev2/tasks/ike_init.c +++ b/src/libcharon/sa/ikev2/tasks/ike_init.c @@ -354,8 +354,8 @@ static bool derive_keys(private_ike_init_t *this, { return FALSE; } - charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, - nonce_i, nonce_r, this->old_sa); + charon->bus->ike_keys(charon->bus, this->ike_sa, this->dh, chunk_empty, + nonce_i, nonce_r, this->old_sa, NULL); return TRUE; } From 8bcd9bd1611ab83d43774a99d01779e123e95f40 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 19 Jan 2012 11:11:22 +0100 Subject: [PATCH 480/534] Added support to sync IKEv1 SAs key material in HA plugin --- src/libcharon/plugins/ha/ha_dispatcher.c | 75 +++++++++++++++++++++--- src/libcharon/plugins/ha/ha_ike.c | 12 ++++ src/libcharon/plugins/ha/ha_message.c | 8 +++ src/libcharon/plugins/ha/ha_message.h | 10 +++- 4 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index f0e6e5ecf..b20ced473 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -17,6 +17,7 @@ #include #include +#include #include typedef struct private_ha_dispatcher_t private_ha_dispatcher_t; @@ -77,6 +78,11 @@ struct ha_diffie_hellman_t { * Shared secret */ chunk_t secret; + + /** + * Own public value + */ + chunk_t pub; }; METHOD(diffie_hellman_t, dh_get_shared_secret, status_t, @@ -86,6 +92,12 @@ METHOD(diffie_hellman_t, dh_get_shared_secret, status_t, return SUCCESS; } +METHOD(diffie_hellman_t, dh_get_my_public_value, void, + ha_diffie_hellman_t *this, chunk_t *value) +{ + *value = chunk_clone(this->pub); +} + METHOD(diffie_hellman_t, dh_destroy, void, ha_diffie_hellman_t *this) { @@ -95,16 +107,18 @@ METHOD(diffie_hellman_t, dh_destroy, void, /** * Create a HA synced DH implementation */ -static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret) +static diffie_hellman_t *ha_diffie_hellman_create(chunk_t secret, chunk_t pub) { ha_diffie_hellman_t *this; INIT(this, .dh = { .get_shared_secret = _dh_get_shared_secret, + .get_my_public_value = _dh_get_my_public_value, .destroy = _dh_destroy, }, .secret = secret, + .pub = pub, ); return &this->dh; @@ -119,9 +133,11 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message ha_message_value_t value; enumerator_t *enumerator; ike_sa_t *ike_sa = NULL, *old_sa = NULL; + ike_version_t version = IKEV2; u_int16_t encr = 0, len = 0, integ = 0, prf = 0, old_prf = PRF_UNDEFINED; chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty; chunk_t secret = chunk_empty, old_skd = chunk_empty; + chunk_t dh_local = chunk_empty, dh_remote = chunk_empty, psk = chunk_empty; bool ok = FALSE; enumerator = message->create_attribute_enumerator(message); @@ -131,12 +147,15 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message { case HA_IKE_ID: ike_sa = ike_sa_create(value.ike_sa_id, - value.ike_sa_id->is_initiator(value.ike_sa_id), IKEV2); + value.ike_sa_id->is_initiator(value.ike_sa_id), version); break; case HA_IKE_REKEY_ID: old_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, value.ike_sa_id); break; + case HA_IKE_VERSION: + version = value.u8; + break; case HA_NONCE_I: nonce_i = value.chunk; break; @@ -146,6 +165,15 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message case HA_SECRET: secret = value.chunk; break; + case HA_LOCAL_DH: + dh_local = value.chunk; + break; + case HA_REMOTE_DH: + dh_remote = value.chunk; + break; + case HA_PSK: + psk = value.chunk; + break; case HA_OLD_SKD: old_skd = value.chunk; break; @@ -189,7 +217,7 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, prf, 0); } charon->bus->set_sa(charon->bus, ike_sa); - dh = ha_diffie_hellman_create(secret); + dh = ha_diffie_hellman_create(secret, dh_local); if (ike_sa->get_version(ike_sa) == IKEV2) { keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); @@ -197,6 +225,22 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message ok = keymat_v2->derive_ike_keys(keymat_v2, proposal, dh, nonce_i, nonce_r, ike_sa->get_id(ike_sa), old_prf, old_skd); } + if (ike_sa->get_version(ike_sa) == IKEV1) + { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + shared_key_t *shared = NULL; + auth_method_t method = AUTH_RSA; + + if (psk.len) + { + method = AUTH_PSK; + shared = shared_key_create(SHARED_IKE, chunk_clone(psk)); + } + ok = keymat_v1->derive_ike_keys(keymat_v1, proposal, + dh, dh_remote, nonce_i, nonce_r, + ike_sa->get_id(ike_sa), method, shared); + DESTROY_IF(shared); + } dh->destroy(dh); if (ok) { @@ -518,7 +562,7 @@ static void process_child_add(private_ha_dispatcher_t *this, chunk_t nonce_i = chunk_empty, nonce_r = chunk_empty, secret = chunk_empty; chunk_t encr_i, integ_i, encr_r, integ_r; linked_list_t *local_ts, *remote_ts; - diffie_hellman_t *dh; + diffie_hellman_t *dh = NULL; enumerator = message->create_attribute_enumerator(message); while (enumerator->enumerate(enumerator, &attribute, &value)) @@ -612,16 +656,29 @@ static void process_child_add(private_ha_dispatcher_t *this, proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, len); } proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, esn, 0); - dh = ha_diffie_hellman_create(secret); + if (secret.len) + { + dh = ha_diffie_hellman_create(secret, chunk_empty); + } if (ike_sa->get_version(ike_sa) == IKEV2) { keymat_v2_t *keymat_v2 = (keymat_v2_t*)ike_sa->get_keymat(ike_sa); - ok = keymat_v2->derive_child_keys(keymat_v2, - proposal, secret.ptr ? dh : NULL, nonce_i, nonce_r, - &encr_i, &integ_i, &encr_r, &integ_r); + ok = keymat_v2->derive_child_keys(keymat_v2, proposal, dh, + nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r); } - dh->destroy(dh); + if (ike_sa->get_version(ike_sa) == IKEV1) + { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + u_int32_t spi_i, spi_r; + + spi_i = initiator ? inbound_spi : outbound_spi; + spi_r = initiator ? outbound_spi : inbound_spi; + + ok = keymat_v1->derive_child_keys(keymat_v1, proposal, dh, spi_i, spi_r, + nonce_i, nonce_r, &encr_i, &integ_i, &encr_r, &integ_r); + } + DESTROY_IF(dh); if (!ok) { DBG1(DBG_CHD, "HA CHILD_SA key derivation failed"); diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index bcdd09b3e..bee6e2a6d 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -89,6 +89,7 @@ METHOD(listener_t, ike_keys, bool, } m = ha_message_create(HA_IKE_ADD); + m->add_attribute(m, HA_IKE_VERSION, ike_sa->get_version(ike_sa)); m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); if (rekey && rekey->get_version(rekey) == IKEV2) @@ -123,6 +124,17 @@ METHOD(listener_t, ike_keys, bool, m->add_attribute(m, HA_NONCE_R, nonce_r); m->add_attribute(m, HA_SECRET, secret); chunk_clear(&secret); + if (ike_sa->get_version(ike_sa) == IKEV1) + { + dh->get_my_public_value(dh, &secret); + m->add_attribute(m, HA_LOCAL_DH, secret); + chunk_free(&secret); + m->add_attribute(m, HA_REMOTE_DH, dh_other); + if (shared) + { + m->add_attribute(m, HA_PSK, shared->get_key(shared)); + } + } this->socket->push(this->socket, m); this->cache->cache(this->cache, ike_sa, m); diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c index f98f78dd4..7df705a8a 100644 --- a/src/libcharon/plugins/ha/ha_message.c +++ b/src/libcharon/plugins/ha/ha_message.c @@ -213,6 +213,7 @@ METHOD(ha_message_t, add_attribute, void, break; } /* u_int8_t */ + case HA_IKE_VERSION: case HA_INITIATOR: case HA_IPSEC_MODE: case HA_IPCOMP: @@ -263,6 +264,9 @@ METHOD(ha_message_t, add_attribute, void, case HA_NONCE_I: case HA_NONCE_R: case HA_SECRET: + case HA_LOCAL_DH: + case HA_REMOTE_DH: + case HA_PSK: case HA_OLD_SKD: { chunk_t chunk; @@ -426,6 +430,7 @@ METHOD(enumerator_t, attribute_enumerate, bool, return TRUE; } /* u_int8_t */ + case HA_IKE_VERSION: case HA_INITIATOR: case HA_IPSEC_MODE: case HA_IPCOMP: @@ -479,6 +484,9 @@ METHOD(enumerator_t, attribute_enumerate, bool, case HA_NONCE_I: case HA_NONCE_R: case HA_SECRET: + case HA_LOCAL_DH: + case HA_REMOTE_DH: + case HA_PSK: case HA_OLD_SKD: { size_t len; diff --git a/src/libcharon/plugins/ha/ha_message.h b/src/libcharon/plugins/ha/ha_message.h index 1f8eabd62..b937d39b5 100644 --- a/src/libcharon/plugins/ha/ha_message.h +++ b/src/libcharon/plugins/ha/ha_message.h @@ -76,7 +76,7 @@ extern enum_name_t *ha_message_type_names; enum ha_message_attribute_t { /** ike_sa_id_t*, to identify IKE_SA */ HA_IKE_ID = 1, - /** ike_Sa_id_t*, identifies IKE_SA which gets rekeyed */ + /** ike_sa_id_t*, identifies IKE_SA which gets rekeyed */ HA_IKE_REKEY_ID, /** identification_t*, local identity */ HA_LOCAL_ID, @@ -142,6 +142,14 @@ enum ha_message_attribute_t { HA_SEGMENT, /** u_int16_t, Extended Sequence numbers */ HA_ESN, + /** u_int8_t, IKE version */ + HA_IKE_VERSION, + /** chunk_t, own DH public value */ + HA_LOCAL_DH, + /** chunk_t, remote DH public value */ + HA_REMOTE_DH, + /** chunk_t, shared secret for IKEv1 key derivation */ + HA_PSK, }; /** From a0fa7a7f64e17482f81b1e803a3d2af9408ce8c5 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 19 Jan 2012 15:54:38 +0100 Subject: [PATCH 481/534] Clear initiator flag when checking out initial IKEv1 SA from message --- src/libcharon/sa/ike_sa_manager.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 79a52c918..24e1388d9 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -997,6 +997,10 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*, { ike_version = IKEV1; is_init = TRUE; + if (id->is_initiator(id)) + { /* not set in IKEv1, switch back before applying to new SA */ + id->switch_initiator(id); + } } } } From ae92641806c1b45d266487590f13f622c0478d1d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 19 Jan 2012 15:55:29 +0100 Subject: [PATCH 482/534] Create IKEv1 keymat hasher explicitly on sync --- src/libcharon/plugins/ha/ha_dispatcher.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index b20ced473..e3080c449 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -236,9 +236,12 @@ static void process_ike_add(private_ha_dispatcher_t *this, ha_message_t *message method = AUTH_PSK; shared = shared_key_create(SHARED_IKE, chunk_clone(psk)); } - ok = keymat_v1->derive_ike_keys(keymat_v1, proposal, - dh, dh_remote, nonce_i, nonce_r, - ike_sa->get_id(ike_sa), method, shared); + if (keymat_v1->create_hasher(keymat_v1, proposal)) + { + ok = keymat_v1->derive_ike_keys(keymat_v1, proposal, + dh, dh_remote, nonce_i, nonce_r, + ike_sa->get_id(ike_sa), method, shared); + } DESTROY_IF(shared); } dh->destroy(dh); From 47b8f6ef4b3637e94d4b211721b38ba263f6d9c0 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 19 Jan 2012 16:22:25 +0100 Subject: [PATCH 483/534] Invoke bus_t.message hook twice, once plain and parsed, once encoded and encrypted --- src/conftest/hooks/add_notify.c | 4 +- src/conftest/hooks/add_payload.c | 4 +- src/conftest/hooks/custom_proposal.c | 4 +- src/conftest/hooks/force_cookie.c | 4 +- src/conftest/hooks/ignore_message.c | 4 +- src/conftest/hooks/ike_auth_fill.c | 4 +- src/conftest/hooks/log_id.c | 4 +- src/conftest/hooks/log_ke.c | 4 +- src/conftest/hooks/log_proposals.c | 4 +- src/conftest/hooks/log_ts.c | 4 +- src/conftest/hooks/pretend_auth.c | 45 +++++++++--------- src/conftest/hooks/rebuild_auth.c | 47 ++++++++++--------- src/conftest/hooks/set_critical.c | 4 +- src/conftest/hooks/set_ike_initiator.c | 4 +- src/conftest/hooks/set_ike_request.c | 4 +- src/conftest/hooks/set_ike_spi.c | 4 +- src/conftest/hooks/set_ike_version.c | 4 +- src/conftest/hooks/set_length.c | 4 +- src/conftest/hooks/set_proposal_number.c | 4 +- src/conftest/hooks/set_reserved.c | 4 +- src/conftest/hooks/unsort_message.c | 4 +- src/libcharon/bus/bus.c | 4 +- src/libcharon/bus/bus.h | 7 ++- src/libcharon/bus/listeners/listener.h | 6 ++- .../plugins/duplicheck/duplicheck_listener.c | 4 +- src/libcharon/plugins/farp/farp_listener.c | 4 +- src/libcharon/plugins/ha/ha_ike.c | 3 +- src/libcharon/plugins/led/led_listener.c | 4 +- src/libcharon/sa/ike_sa.c | 11 ++++- src/libcharon/sa/ikev1/task_manager_v1.c | 6 ++- src/libcharon/sa/ikev2/task_manager_v2.c | 5 +- 31 files changed, 124 insertions(+), 98 deletions(-) diff --git a/src/conftest/hooks/add_notify.c b/src/conftest/hooks/add_notify.c index a9731960b..e3fbbc878 100644 --- a/src/conftest/hooks/add_notify.c +++ b/src/conftest/hooks/add_notify.c @@ -60,9 +60,9 @@ struct private_add_notify_t { METHOD(listener_t, message, bool, private_add_notify_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/add_payload.c b/src/conftest/hooks/add_payload.c index 03a47cc23..37484e808 100644 --- a/src/conftest/hooks/add_payload.c +++ b/src/conftest/hooks/add_payload.c @@ -62,9 +62,9 @@ struct private_add_payload_t { METHOD(listener_t, message, bool, private_add_payload_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/custom_proposal.c b/src/conftest/hooks/custom_proposal.c index 4acea18ce..958bc1052 100644 --- a/src/conftest/hooks/custom_proposal.c +++ b/src/conftest/hooks/custom_proposal.c @@ -111,9 +111,9 @@ static linked_list_t* load_proposals(private_custom_proposal_t *this, METHOD(listener_t, message, bool, private_custom_proposal_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/force_cookie.c b/src/conftest/hooks/force_cookie.c index e2ccb66a8..1b044db14 100644 --- a/src/conftest/hooks/force_cookie.c +++ b/src/conftest/hooks/force_cookie.c @@ -32,9 +32,9 @@ struct private_force_cookie_t { METHOD(listener_t, message, bool, private_force_cookie_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming && message->get_request(message) && + if (incoming && plain && message->get_request(message) && message->get_exchange_type(message) == IKE_SA_INIT) { enumerator_t *enumerator; diff --git a/src/conftest/hooks/ignore_message.c b/src/conftest/hooks/ignore_message.c index 210f3ac50..3cb5f2059 100644 --- a/src/conftest/hooks/ignore_message.c +++ b/src/conftest/hooks/ignore_message.c @@ -45,9 +45,9 @@ struct private_ignore_message_t { METHOD(listener_t, message, bool, private_ignore_message_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming == this->in && + if (incoming == this->in && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/ike_auth_fill.c b/src/conftest/hooks/ike_auth_fill.c index 7362c19f4..09590d4f3 100644 --- a/src/conftest/hooks/ike_auth_fill.c +++ b/src/conftest/hooks/ike_auth_fill.c @@ -92,9 +92,9 @@ static size_t calculate_wire_size(message_t *message, ike_sa_t *ike_sa) METHOD(listener_t, message, bool, private_ike_auth_fill_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/log_id.c b/src/conftest/hooks/log_id.c index ad14cea10..07dd6a44e 100644 --- a/src/conftest/hooks/log_id.c +++ b/src/conftest/hooks/log_id.c @@ -32,9 +32,9 @@ struct private_log_id_t { METHOD(listener_t, message, bool, private_log_id_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (incoming && plain) { enumerator_t *enumerator; payload_t *payload; diff --git a/src/conftest/hooks/log_ke.c b/src/conftest/hooks/log_ke.c index 231c0a8d8..710482326 100644 --- a/src/conftest/hooks/log_ke.c +++ b/src/conftest/hooks/log_ke.c @@ -32,9 +32,9 @@ struct private_log_ke_t { METHOD(listener_t, message, bool, private_log_ke_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (incoming && plain) { enumerator_t *enumerator; payload_t *payload; diff --git a/src/conftest/hooks/log_proposals.c b/src/conftest/hooks/log_proposals.c index 8c330ab3d..347b83209 100644 --- a/src/conftest/hooks/log_proposals.c +++ b/src/conftest/hooks/log_proposals.c @@ -32,9 +32,9 @@ struct private_log_proposals_t { METHOD(listener_t, message, bool, private_log_proposals_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (incoming && plain) { enumerator_t *enumerator, *proposals; payload_t *payload; diff --git a/src/conftest/hooks/log_ts.c b/src/conftest/hooks/log_ts.c index fb7c89a0a..f212efa12 100644 --- a/src/conftest/hooks/log_ts.c +++ b/src/conftest/hooks/log_ts.c @@ -32,9 +32,9 @@ struct private_log_ts_t { METHOD(listener_t, message, bool, private_log_ts_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (incoming && plain) { enumerator_t *enumerator; payload_t *payload; diff --git a/src/conftest/hooks/pretend_auth.c b/src/conftest/hooks/pretend_auth.c index 3a7bb4f6b..cfc39e3a9 100644 --- a/src/conftest/hooks/pretend_auth.c +++ b/src/conftest/hooks/pretend_auth.c @@ -311,35 +311,38 @@ static void process_auth_response(private_pretend_auth_t *this, METHOD(listener_t, message, bool, private_pretend_auth_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (incoming) + if (plain) { - if (!message->get_request(message)) + if (incoming) { - if (message->get_exchange_type(message) == IKE_SA_INIT) + if (!message->get_request(message)) { - process_init_response(this, ike_sa, message); - } - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_message_id(message) == 1) - { - process_auth_response(this, ike_sa, message); + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + process_init_response(this, ike_sa, message); + } + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_message_id(message) == 1) + { + process_auth_response(this, ike_sa, message); + } } } - } - else - { - if (message->get_request(message)) + else { - if (message->get_exchange_type(message) == IKE_SA_INIT) + if (message->get_request(message)) { - process_init_request(this, ike_sa, message); - } - if (message->get_exchange_type(message) == IKE_AUTH && - message->get_message_id(message) == 1) - { - process_auth_request(this, ike_sa, message); + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + process_init_request(this, ike_sa, message); + } + if (message->get_exchange_type(message) == IKE_AUTH && + message->get_message_id(message) == 1) + { + process_auth_request(this, ike_sa, message); + } } } } diff --git a/src/conftest/hooks/rebuild_auth.c b/src/conftest/hooks/rebuild_auth.c index 1197eb2dc..8ee4e14b1 100644 --- a/src/conftest/hooks/rebuild_auth.c +++ b/src/conftest/hooks/rebuild_auth.c @@ -175,34 +175,37 @@ static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa, METHOD(listener_t, message, bool, private_rebuild_auth_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && message->get_message_id(message) == 1) + if (plain) { - rebuild_auth(this, ike_sa, message); - } - if (message->get_exchange_type(message) == IKE_SA_INIT) - { - if (incoming) + if (!incoming && message->get_message_id(message) == 1) { - nonce_payload_t *nonce; - - nonce = (nonce_payload_t*)message->get_payload(message, NONCE); - if (nonce) - { - free(this->nonce.ptr); - this->nonce = nonce->get_nonce(nonce); - } + rebuild_auth(this, ike_sa, message); } - else + if (message->get_exchange_type(message) == IKE_SA_INIT) { - packet_t *packet; - - if (message->generate(message, NULL, &packet) == SUCCESS) + if (incoming) { - free(this->ike_init.ptr); - this->ike_init = chunk_clone(packet->get_data(packet)); - packet->destroy(packet); + nonce_payload_t *nonce; + + nonce = (nonce_payload_t*)message->get_payload(message, NONCE); + if (nonce) + { + free(this->nonce.ptr); + this->nonce = nonce->get_nonce(nonce); + } + } + else + { + packet_t *packet; + + if (message->generate(message, NULL, &packet) == SUCCESS) + { + free(this->ike_init.ptr); + this->ike_init = chunk_clone(packet->get_data(packet)); + packet->destroy(packet); + } } } } diff --git a/src/conftest/hooks/set_critical.c b/src/conftest/hooks/set_critical.c index caf2215c3..8ec84e13d 100644 --- a/src/conftest/hooks/set_critical.c +++ b/src/conftest/hooks/set_critical.c @@ -47,9 +47,9 @@ struct private_set_critical_t { METHOD(listener_t, message, bool, private_set_critical_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_ike_initiator.c b/src/conftest/hooks/set_ike_initiator.c index 6ba43eaca..1674f0a2d 100644 --- a/src/conftest/hooks/set_ike_initiator.c +++ b/src/conftest/hooks/set_ike_initiator.c @@ -42,9 +42,9 @@ struct private_set_ike_initiator_t { METHOD(listener_t, message, bool, private_set_ike_initiator_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_ike_request.c b/src/conftest/hooks/set_ike_request.c index baabea66a..fd5b6de61 100644 --- a/src/conftest/hooks/set_ike_request.c +++ b/src/conftest/hooks/set_ike_request.c @@ -42,9 +42,9 @@ struct private_set_ike_request_t { METHOD(listener_t, message, bool, private_set_ike_request_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_ike_spi.c b/src/conftest/hooks/set_ike_spi.c index 14a0da9cd..bda02580d 100644 --- a/src/conftest/hooks/set_ike_spi.c +++ b/src/conftest/hooks/set_ike_spi.c @@ -52,9 +52,9 @@ struct private_set_ike_spi_t { METHOD(listener_t, message, bool, private_set_ike_spi_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_ike_version.c b/src/conftest/hooks/set_ike_version.c index d2de9dc81..ca52879d1 100644 --- a/src/conftest/hooks/set_ike_version.c +++ b/src/conftest/hooks/set_ike_version.c @@ -57,9 +57,9 @@ struct private_set_ike_version_t { METHOD(listener_t, message, bool, private_set_ike_version_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_length.c b/src/conftest/hooks/set_length.c index eb72e72d9..c1a867a99 100644 --- a/src/conftest/hooks/set_length.c +++ b/src/conftest/hooks/set_length.c @@ -50,9 +50,9 @@ struct private_set_length_t { METHOD(listener_t, message, bool, private_set_length_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_proposal_number.c b/src/conftest/hooks/set_proposal_number.c index 839ca1f37..0cc3cfc63 100644 --- a/src/conftest/hooks/set_proposal_number.c +++ b/src/conftest/hooks/set_proposal_number.c @@ -69,9 +69,9 @@ static void copy_proposal_algs(proposal_t *from, proposal_t *to, METHOD(listener_t, message, bool, private_set_proposal_number_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/set_reserved.c b/src/conftest/hooks/set_reserved.c index 77a605d2a..d1a4a977b 100644 --- a/src/conftest/hooks/set_reserved.c +++ b/src/conftest/hooks/set_reserved.c @@ -163,9 +163,9 @@ static void set_byte(private_set_reserved_t *this, message_t *message, METHOD(listener_t, message, bool, private_set_reserved_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/conftest/hooks/unsort_message.c b/src/conftest/hooks/unsort_message.c index b37b261a4..1b2b302af 100644 --- a/src/conftest/hooks/unsort_message.c +++ b/src/conftest/hooks/unsort_message.c @@ -45,9 +45,9 @@ struct private_unsort_message_t { METHOD(listener_t, message, bool, private_unsort_message_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming) + bool incoming, bool plain) { - if (!incoming && + if (!incoming && plain && message->get_request(message) == this->req && message->get_message_id(message) == this->id) { diff --git a/src/libcharon/bus/bus.c b/src/libcharon/bus/bus.c index c1b2bd458..ed09288dd 100644 --- a/src/libcharon/bus/bus.c +++ b/src/libcharon/bus/bus.c @@ -406,7 +406,7 @@ METHOD(bus_t, child_state_change, void, } METHOD(bus_t, message, void, - private_bus_t *this, message_t *message, bool incoming) + private_bus_t *this, message_t *message, bool incoming, bool plain) { enumerator_t *enumerator; ike_sa_t *ike_sa; @@ -425,7 +425,7 @@ METHOD(bus_t, message, void, } entry->calling++; keep = entry->listener->message(entry->listener, ike_sa, - message, incoming); + message, incoming, plain); entry->calling--; if (!keep) { diff --git a/src/libcharon/bus/bus.h b/src/libcharon/bus/bus.h index 07b334f29..a2cf41bba 100644 --- a/src/libcharon/bus/bus.h +++ b/src/libcharon/bus/bus.h @@ -235,10 +235,15 @@ struct bus_t { /** * Message send/receive hook. * + * The hook is invoked twice for each message: Once with plain, parsed data + * and once encoded and encrypted. + * * @param message message to send/receive * @param incoming TRUE for incoming messages, FALSE for outgoing + * @param plain TRUE if message is parsed and decrypted, FALSE it not + * @param */ - void (*message)(bus_t *this, message_t *message, bool incoming); + void (*message)(bus_t *this, message_t *message, bool incoming, bool plain); /** * IKE_SA authorization hook. diff --git a/src/libcharon/bus/listeners/listener.h b/src/libcharon/bus/listeners/listener.h index efadea8c5..f04b20fdf 100644 --- a/src/libcharon/bus/listeners/listener.h +++ b/src/libcharon/bus/listeners/listener.h @@ -84,13 +84,17 @@ struct listener_t { /** * Hook called for received/sent messages of an IKE_SA. * + * The hook is invoked twice for each message: Once with plain, parsed data + * and once encoded and encrypted. + * * @param ike_sa IKE_SA sending/receiving a message * @param message message object * @param incoming TRUE for incoming messages, FALSE for outgoing + * @param plain TRUE if message is parsed and decrypted, FALSE it not * @return TRUE to stay registered, FALSE to unregister */ bool (*message)(listener_t *this, ike_sa_t *ike_sa, message_t *message, - bool incoming); + bool incoming, bool plain); /** * Hook called with IKE_SA key material. diff --git a/src/libcharon/plugins/duplicheck/duplicheck_listener.c b/src/libcharon/plugins/duplicheck/duplicheck_listener.c index 226b2bd4e..4f59e034f 100644 --- a/src/libcharon/plugins/duplicheck/duplicheck_listener.c +++ b/src/libcharon/plugins/duplicheck/duplicheck_listener.c @@ -176,9 +176,9 @@ METHOD(listener_t, ike_updown, bool, METHOD(listener_t, message_hook, bool, private_duplicheck_listener_t *this, ike_sa_t *ike_sa, - message_t *message, bool incoming) + message_t *message, bool incoming, bool plain) { - if (incoming && !message->get_request(message)) + if (incoming && plain && !message->get_request(message)) { identification_t *id; entry_t *entry; diff --git a/src/libcharon/plugins/farp/farp_listener.c b/src/libcharon/plugins/farp/farp_listener.c index 8eed49778..30709c9eb 100644 --- a/src/libcharon/plugins/farp/farp_listener.c +++ b/src/libcharon/plugins/farp/farp_listener.c @@ -78,9 +78,9 @@ METHOD(listener_t, ike_updown, bool, METHOD(listener_t, message_hook, bool, private_farp_listener_t *this, ike_sa_t *ike_sa, - message_t *message, bool incoming) + message_t *message, bool incoming, bool plain) { - if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + if (plain && ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && message->get_exchange_type(message) == IKE_AUTH && !message->get_request(message)) { diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index bee6e2a6d..b18cd6f11 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -237,7 +237,8 @@ METHOD(listener_t, ike_state_change, bool, } METHOD(listener_t, message_hook, bool, - private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, bool incoming) + private_ha_ike_t *this, ike_sa_t *ike_sa, message_t *message, + bool incoming, bool plain) { if (this->tunnel && this->tunnel->is_sa(this->tunnel, ike_sa)) { /* do not sync SA between nodes */ diff --git a/src/libcharon/plugins/led/led_listener.c b/src/libcharon/plugins/led/led_listener.c index 4aae2abe5..9d6c5a63c 100644 --- a/src/libcharon/plugins/led/led_listener.c +++ b/src/libcharon/plugins/led/led_listener.c @@ -189,9 +189,9 @@ METHOD(listener_t, ike_state_change, bool, METHOD(listener_t, message_hook, bool, private_led_listener_t *this, ike_sa_t *ike_sa, - message_t *message, bool incoming) + message_t *message, bool incoming, bool plain) { - if (incoming || message->get_request(message)) + if (plain && (incoming || message->get_request(message))) { blink_activity(this); } diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index cff7990f1..fd43cab68 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -904,6 +904,8 @@ METHOD(ike_sa_t, update_hosts, void, METHOD(ike_sa_t, generate_message, status_t, private_ike_sa_t *this, message_t *message, packet_t **packet) { + status_t status; + if (message->is_encoded(message)) { /* already done */ *packet = message->get_packet(message); @@ -911,8 +913,13 @@ METHOD(ike_sa_t, generate_message, status_t, } this->stats[STAT_OUTBOUND] = time_monotonic(NULL); message->set_ike_sa_id(message, this->ike_sa_id); - charon->bus->message(charon->bus, message, FALSE); - return message->generate(message, this->keymat, packet); + charon->bus->message(charon->bus, message, FALSE, TRUE); + status = message->generate(message, this->keymat, packet); + if (status == SUCCESS) + { + charon->bus->message(charon->bus, message, FALSE, FALSE); + } + return status; } METHOD(ike_sa_t, set_kmaddress, void, diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index 3e46266da..ac3824bc6 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1045,6 +1045,7 @@ METHOD(task_manager_t, process_message, status_t, this->active_tasks->get_count(this->active_tasks))) { msg->set_request(msg, FALSE); + charon->bus->message(charon->bus, msg, TRUE, FALSE); status = parse_message(this, msg); if (status != SUCCESS) { @@ -1053,7 +1054,7 @@ METHOD(task_manager_t, process_message, status_t, this->ike_sa->set_statistic(this->ike_sa, STAT_INBOUND, time_monotonic(NULL)); this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); - charon->bus->message(charon->bus, msg, TRUE); + charon->bus->message(charon->bus, msg, TRUE, TRUE); if (process_response(this, msg) != SUCCESS) { flush(this); @@ -1110,6 +1111,7 @@ METHOD(task_manager_t, process_message, status_t, } msg->set_request(msg, TRUE); + charon->bus->message(charon->bus, msg, TRUE, FALSE); status = parse_message(this, msg); if (status != SUCCESS) { @@ -1141,7 +1143,7 @@ METHOD(task_manager_t, process_message, status_t, "charon.half_open_timeout", HALF_OPEN_IKE_SA_TIMEOUT)); } this->ike_sa->update_hosts(this->ike_sa, me, other, TRUE); - charon->bus->message(charon->bus, msg, TRUE); + charon->bus->message(charon->bus, msg, TRUE, TRUE); if (process_request(this, msg) != SUCCESS) { flush(this); diff --git a/src/libcharon/sa/ikev2/task_manager_v2.c b/src/libcharon/sa/ikev2/task_manager_v2.c index 36252a81d..178cec6d6 100644 --- a/src/libcharon/sa/ikev2/task_manager_v2.c +++ b/src/libcharon/sa/ikev2/task_manager_v2.c @@ -1036,6 +1036,7 @@ METHOD(task_manager_t, process_message, status_t, status_t status; u_int32_t mid; + charon->bus->message(charon->bus, msg, TRUE, FALSE); status = parse_message(this, msg); if (status != SUCCESS) { @@ -1087,7 +1088,7 @@ METHOD(task_manager_t, process_message, status_t, this->ike_sa->update_hosts(this->ike_sa, me, other, mid == 1); } } - charon->bus->message(charon->bus, msg, TRUE); + charon->bus->message(charon->bus, msg, TRUE, TRUE); if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ return SUCCESS; @@ -1132,7 +1133,7 @@ METHOD(task_manager_t, process_message, status_t, this->ike_sa->update_hosts(this->ike_sa, me, other, FALSE); } } - charon->bus->message(charon->bus, msg, TRUE); + charon->bus->message(charon->bus, msg, TRUE, TRUE); if (msg->get_exchange_type(msg) == EXCHANGE_TYPE_UNDEFINED) { /* ignore messages altered to EXCHANGE_TYPE_UNDEFINED */ return SUCCESS; From c8531b7e699e3d680cfbb1332f5cdfd446f2f400 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 19 Jan 2012 16:34:59 +0100 Subject: [PATCH 484/534] Added support for Phase1 IV synchronization to HA plugin --- src/libcharon/plugins/ha/ha_cache.c | 17 +++++ src/libcharon/plugins/ha/ha_dispatcher.c | 54 +++++++++++++++ src/libcharon/plugins/ha/ha_ike.c | 86 +++++++++++++++--------- src/libcharon/plugins/ha/ha_message.c | 5 +- src/libcharon/plugins/ha/ha_message.h | 4 ++ 5 files changed, 134 insertions(+), 32 deletions(-) diff --git a/src/libcharon/plugins/ha/ha_cache.c b/src/libcharon/plugins/ha/ha_cache.c index 7b7a953e5..e21b461a7 100644 --- a/src/libcharon/plugins/ha/ha_cache.c +++ b/src/libcharon/plugins/ha/ha_cache.c @@ -88,6 +88,8 @@ typedef struct { ha_message_t *midi; /* last responder mid */ ha_message_t *midr; + /* last IV update */ + ha_message_t *iv; } entry_t; /** @@ -114,6 +116,7 @@ static void entry_destroy(entry_t *entry) entry->add->destroy(entry->add); DESTROY_IF(entry->midi); DESTROY_IF(entry->midr); + DESTROY_IF(entry->iv); free(entry); } @@ -164,6 +167,16 @@ METHOD(ha_cache_t, cache, void, } message->destroy(message); break; + case HA_IKE_IV: + entry = this->cache->get(this->cache, ike_sa); + if (entry) + { + DESTROY_IF(entry->iv); + entry->iv = message; + break; + } + message->destroy(message); + break; case HA_IKE_DELETE: entry = this->cache->remove(this->cache, ike_sa); if (entry) @@ -309,6 +322,10 @@ METHOD(ha_cache_t, resync, void, { this->socket->push(this->socket, entry->midr); } + if (entry->iv) + { + this->socket->push(this->socket, entry->iv); + } } } enumerator->destroy(enumerator); diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index e3080c449..197bb5e24 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -478,6 +478,57 @@ static void process_ike_mid(private_ha_dispatcher_t *this, } } +/** + * Process messages of type IKE_IV + */ +static void process_ike_iv(private_ha_dispatcher_t *this, ha_message_t *message) +{ + ha_message_attribute_t attribute; + ha_message_value_t value; + enumerator_t *enumerator; + ike_sa_t *ike_sa = NULL; + chunk_t iv = chunk_empty; + + enumerator = message->create_attribute_enumerator(message); + while (enumerator->enumerate(enumerator, &attribute, &value)) + { + switch (attribute) + { + case HA_IKE_ID: + ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, + value.ike_sa_id); + break; + case HA_IV: + iv = value.chunk; + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (ike_sa) + { + if (ike_sa->get_version(ike_sa) == IKEV1) + { + if (iv.len) + { + keymat_v1_t *keymat; + + keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + keymat->update_iv(keymat, 0, iv); + keymat->confirm_iv(keymat, 0); + } + } + this->cache->cache(this->cache, ike_sa, message); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + } + else + { + message->destroy(message); + } +} + /** * Process messages of type IKE_DELETE */ @@ -932,6 +983,9 @@ static job_requeue_t dispatch(private_ha_dispatcher_t *this) case HA_IKE_MID_RESPONDER: process_ike_mid(this, message, FALSE); break; + case HA_IKE_IV: + process_ike_iv(this, message); + break; case HA_IKE_DELETE: process_ike_delete(this, message); break; diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index b18cd6f11..97fc85600 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -16,6 +16,7 @@ #include "ha_ike.h" #include +#include typedef struct private_ha_ike_t private_ha_ike_t; @@ -245,39 +246,62 @@ METHOD(listener_t, message_hook, bool, return TRUE; } - if (message->get_exchange_type(message) != IKE_SA_INIT && - message->get_request(message)) - { /* we sync on requests, but skip it on IKE_SA_INIT */ - ha_message_t *m; + if (plain && ike_sa->get_version(ike_sa) == IKEV2) + { + if (message->get_exchange_type(message) != IKE_SA_INIT && + message->get_request(message)) + { /* we sync on requests, but skip it on IKE_SA_INIT */ + ha_message_t *m; - if (incoming) - { - m = ha_message_create(HA_IKE_MID_RESPONDER); - } - else - { - m = ha_message_create(HA_IKE_MID_INITIATOR); - } - m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); - m->add_attribute(m, HA_MID, message->get_message_id(message) + 1); - this->socket->push(this->socket, m); - this->cache->cache(this->cache, ike_sa, m); - } - if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && - message->get_exchange_type(message) == IKE_AUTH && - !message->get_request(message)) - { /* After IKE_SA has been established, sync peers virtual IP. - * We cannot sync it in the state_change hook, it is installed later. - * TODO: where to sync local VIP? */ - ha_message_t *m; - host_t *vip; - - vip = ike_sa->get_virtual_ip(ike_sa, FALSE); - if (vip) - { - m = ha_message_create(HA_IKE_UPDATE); + if (incoming) + { + m = ha_message_create(HA_IKE_MID_RESPONDER); + } + else + { + m = ha_message_create(HA_IKE_MID_INITIATOR); + } m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); - m->add_attribute(m, HA_REMOTE_VIP, vip); + m->add_attribute(m, HA_MID, message->get_message_id(message) + 1); + this->socket->push(this->socket, m); + this->cache->cache(this->cache, ike_sa, m); + } + if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + message->get_exchange_type(message) == IKE_AUTH && + !message->get_request(message)) + { /* After IKE_SA has been established, sync peers virtual IP. + * We cannot sync it in the state_change hook, it is installed later. + * TODO: where to sync local VIP? */ + ha_message_t *m; + host_t *vip; + + vip = ike_sa->get_virtual_ip(ike_sa, FALSE); + if (vip) + { + m = ha_message_create(HA_IKE_UPDATE); + m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); + m->add_attribute(m, HA_REMOTE_VIP, vip); + this->socket->push(this->socket, m); + this->cache->cache(this->cache, ike_sa, m); + } + } + } + if (!plain && ike_sa->get_version(ike_sa) == IKEV1) + { + ha_message_t *m; + keymat_v1_t *keymat; + u_int32_t mid; + chunk_t iv; + + mid = message->get_message_id(message); + if (mid == 0) + { + keymat = (keymat_v1_t*)ike_sa->get_keymat(ike_sa); + iv = keymat->get_iv(keymat, mid); + m = ha_message_create(HA_IKE_IV); + m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); + m->add_attribute(m, HA_IV, iv); + free(iv.ptr); this->socket->push(this->socket, m); this->cache->cache(this->cache, ike_sa, m); } diff --git a/src/libcharon/plugins/ha/ha_message.c b/src/libcharon/plugins/ha/ha_message.c index 7df705a8a..c7c624d32 100644 --- a/src/libcharon/plugins/ha/ha_message.c +++ b/src/libcharon/plugins/ha/ha_message.c @@ -46,7 +46,7 @@ struct private_ha_message_t { chunk_t buf; }; -ENUM(ha_message_type_names, HA_IKE_ADD, HA_RESYNC, +ENUM(ha_message_type_names, HA_IKE_ADD, HA_IKE_IV, "IKE_ADD", "IKE_UPDATE", "IKE_MID_INITIATOR", @@ -58,6 +58,7 @@ ENUM(ha_message_type_names, HA_IKE_ADD, HA_RESYNC, "SEGMENT_TAKE", "STATUS", "RESYNC", + "IKE_IV", ); typedef struct ike_sa_id_encoding_t ike_sa_id_encoding_t; @@ -267,6 +268,7 @@ METHOD(ha_message_t, add_attribute, void, case HA_LOCAL_DH: case HA_REMOTE_DH: case HA_PSK: + case HA_IV: case HA_OLD_SKD: { chunk_t chunk; @@ -487,6 +489,7 @@ METHOD(enumerator_t, attribute_enumerate, bool, case HA_LOCAL_DH: case HA_REMOTE_DH: case HA_PSK: + case HA_IV: case HA_OLD_SKD: { size_t len; diff --git a/src/libcharon/plugins/ha/ha_message.h b/src/libcharon/plugins/ha/ha_message.h index b937d39b5..89f9fc391 100644 --- a/src/libcharon/plugins/ha/ha_message.h +++ b/src/libcharon/plugins/ha/ha_message.h @@ -63,6 +63,8 @@ enum ha_message_type_t { HA_STATUS, /** segments the receiving node is requested to resync */ HA_RESYNC, + /** IV synchronization for IKEv1 Main/Aggressive mode */ + HA_IKE_IV, }; /** @@ -150,6 +152,8 @@ enum ha_message_attribute_t { HA_REMOTE_DH, /** chunk_t, shared secret for IKEv1 key derivation */ HA_PSK, + /** chunk_t, IV for next IKEv1 message */ + HA_IV, }; /** From 868d92a402f5b6ace5cc7e777c12c98a508b0f9d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 11:23:27 +0100 Subject: [PATCH 485/534] Sync new IKE_SA condition/extension flags --- src/libcharon/plugins/ha/ha_dispatcher.c | 4 ++++ src/libcharon/plugins/ha/ha_ike.c | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 197bb5e24..7ce23b3c6 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -379,6 +379,8 @@ static void process_ike_update(private_ha_dispatcher_t *this, set_extension(ike_sa, value.u32, EXT_STRONGSWAN); set_extension(ike_sa, value.u32, EXT_EAP_ONLY_AUTHENTICATION); set_extension(ike_sa, value.u32, EXT_MS_WINDOWS); + set_extension(ike_sa, value.u32, EXT_XAUTH); + set_extension(ike_sa, value.u32, EXT_DPD); break; case HA_CONDITIONS: set_condition(ike_sa, value.u32, COND_NAT_ANY); @@ -389,6 +391,8 @@ static void process_ike_update(private_ha_dispatcher_t *this, set_condition(ike_sa, value.u32, COND_CERTREQ_SEEN); set_condition(ike_sa, value.u32, COND_ORIGINAL_INITIATOR); set_condition(ike_sa, value.u32, COND_STALE); + set_condition(ike_sa, value.u32, COND_INIT_CONTACT_SEEN); + set_condition(ike_sa, value.u32, COND_XAUTH_AUTHENTICATED); break; default: break; diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index 97fc85600..ce3131b0b 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -175,7 +175,9 @@ METHOD(listener_t, ike_updown, bool, | copy_condition(ike_sa, COND_EAP_AUTHENTICATED) | copy_condition(ike_sa, COND_CERTREQ_SEEN) | copy_condition(ike_sa, COND_ORIGINAL_INITIATOR) - | copy_condition(ike_sa, COND_STALE); + | copy_condition(ike_sa, COND_STALE) + | copy_condition(ike_sa, COND_INIT_CONTACT_SEEN) + | copy_condition(ike_sa, COND_XAUTH_AUTHENTICATED); extension = copy_extension(ike_sa, EXT_NATT) | copy_extension(ike_sa, EXT_MOBIKE) @@ -183,7 +185,9 @@ METHOD(listener_t, ike_updown, bool, | copy_extension(ike_sa, EXT_MULTIPLE_AUTH) | copy_extension(ike_sa, EXT_STRONGSWAN) | copy_extension(ike_sa, EXT_EAP_ONLY_AUTHENTICATION) - | copy_extension(ike_sa, EXT_MS_WINDOWS); + | copy_extension(ike_sa, EXT_MS_WINDOWS) + | copy_extension(ike_sa, EXT_XAUTH) + | copy_extension(ike_sa, EXT_DPD); id = ike_sa->get_id(ike_sa); From b226fd300d0f15023c80150e28dd1dd9aa9b741e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 11:36:26 +0100 Subject: [PATCH 486/534] Sync remote virtual IP for IKEv1 SAs --- src/libcharon/plugins/ha/ha_ike.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index ce3131b0b..09899a8f6 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -296,6 +296,7 @@ METHOD(listener_t, message_hook, bool, keymat_v1_t *keymat; u_int32_t mid; chunk_t iv; + host_t *vip; mid = message->get_message_id(message); if (mid == 0) @@ -309,6 +310,18 @@ METHOD(listener_t, message_hook, bool, this->socket->push(this->socket, m); this->cache->cache(this->cache, ike_sa, m); } + if (!incoming && message->get_exchange_type(message) == TRANSACTION) + { + vip = ike_sa->get_virtual_ip(ike_sa, FALSE); + if (vip) + { + m = ha_message_create(HA_IKE_UPDATE); + m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); + m->add_attribute(m, HA_REMOTE_VIP, vip); + this->socket->push(this->socket, m); + this->cache->cache(this->cache, ike_sa, m); + } + } } return TRUE; } From a46b8e16adf710f827af6cc4aeb9733708bd58c6 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 12:21:13 +0100 Subject: [PATCH 487/534] Set thread specific SA on bus for each enumerated IKE_SA --- src/libcharon/sa/ike_sa_manager.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index 24e1388d9..b617a1332 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1269,6 +1269,7 @@ static bool enumerator_filter_wait(private_ike_sa_manager_t *this, if (wait_for_entry(this, *in, *segment)) { *out = (*in)->ike_sa; + charon->bus->set_sa(charon->bus, *out); return TRUE; } return FALSE; @@ -1285,17 +1286,26 @@ static bool enumerator_filter_skip(private_ike_sa_manager_t *this, !(*in)->checked_out) { *out = (*in)->ike_sa; + charon->bus->set_sa(charon->bus, *out); return TRUE; } return FALSE; } +/** + * Reset threads SA after enumeration + */ +static void reset_sa(void *data) +{ + charon->bus->set_sa(charon->bus, NULL); +} + METHOD(ike_sa_manager_t, create_enumerator, enumerator_t*, private_ike_sa_manager_t* this, bool wait) { return enumerator_create_filter(create_table_enumerator(this), wait ? (void*)enumerator_filter_wait : (void*)enumerator_filter_skip, - this, NULL); + this, reset_sa); } METHOD(ike_sa_manager_t, checkin, void, From 783c4969669cc0347c2a115f15f181e824cdd865 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 12:21:48 +0100 Subject: [PATCH 488/534] Update state before triggering DPD, as we cancel it if PASSIVE --- src/libcharon/sa/ike_sa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index fd43cab68..5a27de5e7 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -672,6 +672,7 @@ METHOD(ike_sa_t, set_state, void, { if (supports_extension(this, EXT_DPD)) { + this->state = state; send_dpd(this); } else From fd6fbf17640b2a999111d5bee1b7560b6e923815 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 12:22:56 +0100 Subject: [PATCH 489/534] Setting message ID on task manager sets DPD sequence numbers in IKEv1 --- src/libcharon/sa/ikev1/task_manager_v1.c | 8 ++++++++ src/libcharon/sa/task_manager.h | 6 ++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libcharon/sa/ikev1/task_manager_v1.c b/src/libcharon/sa/ikev1/task_manager_v1.c index ac3824bc6..8ebaa9d8e 100755 --- a/src/libcharon/sa/ikev1/task_manager_v1.c +++ b/src/libcharon/sa/ikev1/task_manager_v1.c @@ -1393,6 +1393,14 @@ METHOD(task_manager_t, reset, void, this->initiating.seqnr = 0; this->initiating.retransmitted = 0; this->initiating.type = EXCHANGE_TYPE_UNDEFINED; + if (initiate != UINT_MAX) + { + this->dpd_send = initiate; + } + if (respond != UINT_MAX) + { + this->dpd_recv = respond; + } /* reset queued tasks */ enumerator = this->queued_tasks->create_enumerator(this->queued_tasks); diff --git a/src/libcharon/sa/task_manager.h b/src/libcharon/sa/task_manager.h index b49c9a96b..cbebc0a21 100644 --- a/src/libcharon/sa/task_manager.h +++ b/src/libcharon/sa/task_manager.h @@ -229,9 +229,11 @@ struct task_manager_t { * resets the message IDs and resets all active tasks using the migrate() * method. * Use a value of UINT_MAX to keep the current message ID. + * For IKEv1, the arguments do not set the message ID, but the DPD sequence + * number counters. * - * @param initiate message ID to initiate exchanges (send) - * @param respond message ID to respond to exchanges (expect) + * @param initiate message ID / DPD seq to initiate exchanges (send) + * @param respond message ID / DPD seq to respond to exchanges (expect) */ void (*reset) (task_manager_t *this, u_int32_t initiate, u_int32_t respond); From fed5c33440d609721cfdd5992f269c52a6191539 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 12:23:46 +0100 Subject: [PATCH 490/534] Synchronize IKEv1 DPD sequence numbers --- src/libcharon/plugins/ha/ha_ike.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/libcharon/plugins/ha/ha_ike.c b/src/libcharon/plugins/ha/ha_ike.c index 09899a8f6..c8ad0f845 100644 --- a/src/libcharon/plugins/ha/ha_ike.c +++ b/src/libcharon/plugins/ha/ha_ike.c @@ -323,6 +323,36 @@ METHOD(listener_t, message_hook, bool, } } } + if (plain && ike_sa->get_version(ike_sa) == IKEV1 && + message->get_exchange_type(message) == INFORMATIONAL_V1) + { + ha_message_t *m; + notify_payload_t *notify; + chunk_t data; + u_int32_t seq; + + notify = message->get_notify(message, DPD_R_U_THERE); + if (notify) + { + data = notify->get_notification_data(notify); + if (data.len == 4) + { + seq = untoh32(data.ptr); + if (incoming) + { + m = ha_message_create(HA_IKE_MID_RESPONDER); + } + else + { + m = ha_message_create(HA_IKE_MID_INITIATOR); + } + m->add_attribute(m, HA_IKE_ID, ike_sa->get_id(ike_sa)); + m->add_attribute(m, HA_MID, seq + 1); + this->socket->push(this->socket, m); + this->cache->cache(this->cache, ike_sa, m); + } + } + } return TRUE; } From aa3b53e7165da9d03ccc23a0f0feeeeda6e76219 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 13:42:37 +0100 Subject: [PATCH 491/534] Adopt children after syncing a rekeyed IKEv1 SA --- src/libcharon/plugins/ha/ha_dispatcher.c | 6 ++++++ src/libcharon/processing/jobs/adopt_children_job.c | 3 ++- src/libcharon/sa/ike_sa_manager.c | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libcharon/plugins/ha/ha_dispatcher.c b/src/libcharon/plugins/ha/ha_dispatcher.c index 7ce23b3c6..328b923b0 100644 --- a/src/libcharon/plugins/ha/ha_dispatcher.c +++ b/src/libcharon/plugins/ha/ha_dispatcher.c @@ -19,6 +19,7 @@ #include #include #include +#include typedef struct private_ha_dispatcher_t private_ha_dispatcher_t; typedef struct ha_diffie_hellman_t ha_diffie_hellman_t; @@ -427,6 +428,11 @@ static void process_ike_update(private_ha_dispatcher_t *this, } } } + if (ike_sa->get_version(ike_sa) == IKEV1) + { + lib->processor->queue_job(lib->processor, (job_t*) + adopt_children_job_create(ike_sa->get_id(ike_sa))); + } this->cache->cache(this->cache, ike_sa, message); charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); } diff --git a/src/libcharon/processing/jobs/adopt_children_job.c b/src/libcharon/processing/jobs/adopt_children_job.c index 744b7f9b7..93da960f8 100644 --- a/src/libcharon/processing/jobs/adopt_children_job.c +++ b/src/libcharon/processing/jobs/adopt_children_job.c @@ -88,7 +88,8 @@ METHOD(job_t, execute, void, ike_sa = charon->ike_sa_manager->checkout(charon->ike_sa_manager, id); if (ike_sa) { - if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + if ((ike_sa->get_state(ike_sa) == IKE_ESTABLISHED || + ike_sa->get_state(ike_sa) == IKE_PASSIVE) && me->equals(me, ike_sa->get_my_host(ike_sa)) && other->equals(other, ike_sa->get_other_host(ike_sa)) && xauth->equals(xauth, ike_sa->get_other_eap_id(ike_sa)) && diff --git a/src/libcharon/sa/ike_sa_manager.c b/src/libcharon/sa/ike_sa_manager.c index b617a1332..455d5386a 100644 --- a/src/libcharon/sa/ike_sa_manager.c +++ b/src/libcharon/sa/ike_sa_manager.c @@ -1375,7 +1375,8 @@ METHOD(ike_sa_manager_t, checkin, void, } /* apply identities for duplicate test */ - if (ike_sa->get_state(ike_sa) == IKE_ESTABLISHED && + if ((ike_sa->get_state(ike_sa) == IKE_ESTABLISHED || + ike_sa->get_state(ike_sa) == IKE_PASSIVE) && entry->my_id == NULL && entry->other_id == NULL) { if (ike_sa->get_version(ike_sa) == IKEV1) From a994050e9ce0ab4b1c058d15096b6d657d3ca1c8 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 13:54:39 +0100 Subject: [PATCH 492/534] Don't re-resolve addresses during initiate if they have already been set --- src/libcharon/sa/ike_sa.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ike_sa.c b/src/libcharon/sa/ike_sa.c index 5a27de5e7..c5683e93b 100644 --- a/src/libcharon/sa/ike_sa.c +++ b/src/libcharon/sa/ike_sa.c @@ -1077,7 +1077,11 @@ METHOD(ike_sa_t, initiate, status_t, { if (this->state == IKE_CREATED) { - resolve_hosts(this); + if (this->my_host->is_anyaddr(this->my_host) || + this->other_host->is_anyaddr(this->other_host)) + { + resolve_hosts(this); + } if (this->other_host->is_anyaddr(this->other_host) #ifdef ME From 05cb240215b6a496327d151cd180fd58759e45e1 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 14:57:18 +0100 Subject: [PATCH 493/534] Use ATTRIBUTE_VALUE rule in configuration attribute to parse it with correct length --- src/libcharon/encoding/payloads/configuration_attribute.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index db2e447a9..4e3df9055 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -77,7 +77,7 @@ static encoding_rule_t encodings_v2[] = { /* Length of attribute value */ { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length_or_value)}, /* Value of attribute if attribute format flag is zero */ - { CHUNK_DATA, offsetof(private_configuration_attribute_t, value) }, + { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }, }; /* From c390569a76524a72e25a8885f3f8dc920700207d Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 15:00:06 +0100 Subject: [PATCH 494/534] Renamed CONFIGURATION_ATTRIBUTE_LENGTH to streamline it with other ATTRIBUTE rules --- src/libcharon/encoding/generator.c | 6 +++--- src/libcharon/encoding/parser.c | 2 +- src/libcharon/encoding/payloads/configuration_attribute.c | 8 ++++---- src/libcharon/encoding/payloads/encodings.c | 2 +- src/libcharon/encoding/payloads/encodings.h | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 823a4ec10..bf4480193 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -214,7 +214,7 @@ static void generate_u_int_type(private_generator_t *this, break; case U_INT_16: case PAYLOAD_LENGTH: - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: number_of_bits = 16; break; case U_INT_32: @@ -329,7 +329,7 @@ static void generate_u_int_type(private_generator_t *this, } case U_INT_16: case PAYLOAD_LENGTH: - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: { u_int16_t val = htons(*((u_int16_t*)(this->data_struct + offset))); if (this->debug) @@ -481,7 +481,7 @@ METHOD(generator_t, generate_payload, void, case SPI_SIZE: case TS_TYPE: case ATTRIBUTE_TYPE: - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: generate_u_int_type(this, rules[i].type, rules[i].offset); break; case RESERVED_BIT: diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index 8f1d667fc..a599de60f 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -546,7 +546,7 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: { if (!parse_uint16(this, rule_number, output + rule->offset)) { diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index 4e3df9055..482eca882 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -71,13 +71,13 @@ struct private_configuration_attribute_t { */ static encoding_rule_t encodings_v2[] = { /* 1 reserved bit */ - { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved) }, + { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved) }, /* type of the attribute as 15 bit unsigned integer */ - { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, /* Length of attribute value */ - { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length_or_value)}, + { ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length_or_value)}, /* Value of attribute if attribute format flag is zero */ - { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }, + { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }, }; /* diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index 7515c947f..62de81120 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -32,7 +32,7 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "ATTRIBUTE_FORMAT", "ATTRIBUTE_TYPE", "ATTRIBUTE_LENGTH_OR_VALUE", - "CONFIGURATION_ATTRIBUTE_LENGTH", + "ATTRIBUTE_LENGTH", "ATTRIBUTE_VALUE", "TS_TYPE", "ADDRESS", diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index 124814ff5..54830bc8c 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -241,7 +241,7 @@ enum encoding_type_t { * The value is written to the associated data struct. * The current read pointer is moved 16 bit forward afterwards. */ - CONFIGURATION_ATTRIBUTE_LENGTH, + ATTRIBUTE_LENGTH, /** * Depending on the field of type ATTRIBUTE_FORMAT From c791def8c13ccb587ec9e37570f9a957af6a515e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 15:33:26 +0100 Subject: [PATCH 495/534] Added support for authby/xauth_server legacy options --- src/libcharon/plugins/stroke/stroke_config.c | 43 +------------- src/starter/starterstroke.c | 59 +++++++++++++------- 2 files changed, 40 insertions(+), 62 deletions(-) diff --git a/src/libcharon/plugins/stroke/stroke_config.c b/src/libcharon/plugins/stroke/stroke_config.c index bc2518a08..8ca1464fb 100644 --- a/src/libcharon/plugins/stroke/stroke_config.c +++ b/src/libcharon/plugins/stroke/stroke_config.c @@ -266,7 +266,6 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, char *auth, *id, *cert, *ca; stroke_end_t *end, *other_end; auth_cfg_t *cfg; - char eap_buf[32]; /* select strings */ if (local) @@ -314,47 +313,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this, { if (primary) { - if (local) - { /* "leftauth" not defined, fall back to deprecated "authby" */ - switch (msg->add_conn.auth_method) - { - default: - case AUTH_CLASS_PUBKEY: - auth = "pubkey"; - break; - case AUTH_CLASS_PSK: - auth = "psk"; - break; - case AUTH_CLASS_EAP: - auth = "eap"; - break; - case AUTH_CLASS_ANY: - auth = "any"; - break; - } - } - else - { /* "rightauth" not defined, fall back to deprecated "eap" */ - if (msg->add_conn.eap_type) - { - if (msg->add_conn.eap_vendor) - { - snprintf(eap_buf, sizeof(eap_buf), "eap-%d-%d", - msg->add_conn.eap_type, - msg->add_conn.eap_vendor); - } - else - { - snprintf(eap_buf, sizeof(eap_buf), "eap-%d", - msg->add_conn.eap_type); - } - auth = eap_buf; - } - else - { /* not EAP => no constraints for this peer */ - auth = "any"; - } - } + auth = "pubkey"; } else { /* no second authentication round, fine. But load certificates diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 9fbfffc83..c527ae0b4 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -198,26 +198,6 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) msg.length = offsetof(stroke_msg_t, buffer); msg.add_conn.version = conn->keyexchange; msg.add_conn.name = push_string(&msg, connection_name(conn)); - - /* PUBKEY is preferred to PSK and EAP */ - if (conn->policy & POLICY_PUBKEY) - { - msg.add_conn.auth_method = AUTH_CLASS_PUBKEY; - } - else if (conn->policy & POLICY_PSK) - { - msg.add_conn.auth_method = AUTH_CLASS_PSK; - } - else if (conn->policy & POLICY_XAUTH_PSK) - { - msg.add_conn.auth_method = AUTH_CLASS_EAP; - } - else - { - msg.add_conn.auth_method = AUTH_CLASS_ANY; - } - msg.add_conn.eap_type = conn->eap_type; - msg.add_conn.eap_vendor = conn->eap_vendor; msg.add_conn.eap_identity = push_string(&msg, conn->eap_identity); msg.add_conn.aaa_identity = push_string(&msg, conn->aaa_identity); msg.add_conn.xauth_identity = push_string(&msg, conn->xauth_identity); @@ -287,6 +267,45 @@ int starter_stroke_add_conn(starter_config_t *cfg, starter_conn_t *conn) starter_stroke_add_end(&msg, &msg.add_conn.me, &conn->left); starter_stroke_add_end(&msg, &msg.add_conn.other, &conn->right); + if (!msg.add_conn.me.auth && !msg.add_conn.other.auth) + { /* leftauth/rightauth not set, use legacy options */ + if (conn->policy & POLICY_PUBKEY) + { + msg.add_conn.me.auth = push_string(&msg, "pubkey"); + msg.add_conn.other.auth = push_string(&msg, "pubkey"); + } + else if (conn->policy & POLICY_PSK) + { + msg.add_conn.me.auth = push_string(&msg, "psk"); + msg.add_conn.other.auth = push_string(&msg, "psk"); + } + else if (conn->policy & POLICY_XAUTH_RSASIG) + { + msg.add_conn.me.auth = push_string(&msg, "pubkey"); + msg.add_conn.other.auth = push_string(&msg, "pubkey"); + if (conn->policy & POLICY_XAUTH_SERVER) + { + msg.add_conn.other.auth2 = push_string(&msg, "xauth"); + } + else + { + msg.add_conn.me.auth2 = push_string(&msg, "xauth"); + } + } + else if (conn->policy & POLICY_XAUTH_PSK) + { + msg.add_conn.me.auth = push_string(&msg, "psk"); + msg.add_conn.other.auth = push_string(&msg, "psk"); + if (conn->policy & POLICY_XAUTH_SERVER) + { + msg.add_conn.other.auth2 = push_string(&msg, "xauth"); + } + else + { + msg.add_conn.me.auth2 = push_string(&msg, "xauth"); + } + } + } return send_stroke_msg(&msg); } From c8d46f295948d01aef96fba5413206d2ae0a16f9 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Fri, 20 Jan 2012 16:03:18 +0100 Subject: [PATCH 496/534] Dropped support of deprecated authby=eap and eap= options --- man/ipsec.conf.5.in | 37 ++++--------------------------------- src/starter/args.c | 1 - src/starter/confread.c | 34 +--------------------------------- src/starter/confread.h | 2 -- src/starter/keywords.h | 1 - src/starter/keywords.txt | 1 - src/stroke/stroke.c | 1 - src/stroke/stroke_msg.h | 4 ---- 8 files changed, 5 insertions(+), 76 deletions(-) diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in index e2835bde3..2f914b0c8 100644 --- a/man/ipsec.conf.5.in +++ b/man/ipsec.conf.5.in @@ -247,7 +247,7 @@ acceptable values are .br The IKEv2 daemon currently supports ESP only. .TP -.BR authby " = " pubkey " | rsasig | ecdsasig | psk | eap | never | xauth..." +.BR authby " = " pubkey " | rsasig | ecdsasig | psk | never | xauthpsk | xauthrsasig" how the two security gateways should authenticate each other; acceptable values are .B psk @@ -269,12 +269,7 @@ IKEv1 additionally supports the values and .B xauthrsasig that will enable eXtended AUTHentication (XAUTH) in addition to IKEv1 main mode -based on shared secrets or digital RSA signatures, respectively. -IKEv2 additionally supports the value -.BR eap , -which indicates an initiator to request EAP authentication. The EAP method -to use is selected by the server (see -.BR eap ). +based on shared secrets or digital RSA signatures, respectively. This parameter is deprecated for IKEv2 connections, as two peers do not need to agree on an authentication method. Use the .B leftauth @@ -377,31 +372,6 @@ might trigger a closeaction when not desired. defines the timeout interval, after which a CHILD_SA is closed if it did not send or receive any traffic. Currently supported in IKEv2 connections only. .TP -.BR eap " = md5 | mschapv2 | radius | ... | | - -defines the EAP type to propose as server if the client requests EAP -authentication. Currently supported values are -.B aka -for EAP-AKA, -.B gtc -for EAP-GTC, -.B md5 -for EAP-MD5, -.B mschapv2 -for EAP-MS-CHAPv2, -.B radius -for the EAP-RADIUS proxy and -.B sim -for EAP-SIM. Additionally, IANA assigned EAP method numbers are accepted, or a -definition in the form -.B eap=type-vendor -(e.g. eap=7-12345) can be used to specify vendor specific EAP types. -This parameter is deprecated in the favour of -.B leftauth. - -To forward EAP authentication to a RADIUS server using the EAP-RADIUS plugin, -set -.BR eap=radius . -.TP .BR eap_identity " = " defines the identity the client uses to reply to a EAP Identity request. If defined on the EAP server, the defined identity will be used as peer @@ -598,12 +568,13 @@ For .B eap, an optional EAP method can be appended. Currently defined methods are .BR eap-aka , +.BR eap-sim , .BR eap-gtc , .BR eap-md5 , .BR eap-tls , .B eap-mschapv2 and -.BR eap-sim . +.BR eap-radius . Alternatively, IANA assigned EAP method numbers are accepted. Vendor specific EAP methods are defined in the form .B eap-type-vendor diff --git a/src/starter/args.c b/src/starter/args.c index 88133dd53..0699eb058 100644 --- a/src/starter/args.c +++ b/src/starter/args.c @@ -207,7 +207,6 @@ static const token_info_t token_info[] = { ARG_ENUM, offsetof(starter_conn_t, aggressive), LST_bool }, { ARG_MISC, 0, NULL /* KW_AUTH */ }, { ARG_MISC, 0, NULL /* KW_AUTHBY */ }, - { ARG_MISC, 0, NULL /* KW_EAP */ }, { ARG_STR, offsetof(starter_conn_t, eap_identity), NULL }, { ARG_STR, offsetof(starter_conn_t, aaa_identity), NULL }, { ARG_MISC, 0, NULL /* KW_MOBIKE */ }, diff --git a/src/starter/confread.c b/src/starter/confread.c index 1da4eb025..ce69fd724 100644 --- a/src/starter/confread.c +++ b/src/starter/confread.c @@ -22,8 +22,6 @@ #include -#include - #include "../pluto/constants.h" #include "../pluto/defs.h" #include "../pluto/log.h" @@ -668,7 +666,7 @@ static void load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg { conn->policy |= POLICY_XAUTH_RSASIG | POLICY_ENCRYPT; } - else if (streq(value, "xauthpsk") || streq(value, "eap")) + else if (streq(value, "xauthpsk")) { conn->policy |= POLICY_XAUTH_PSK | POLICY_ENCRYPT; } @@ -687,36 +685,6 @@ static void load_conn(starter_conn_t *conn, kw_list_t *kw, starter_config_t *cfg } } break; - case KW_EAP: - { - char *sep; - - /* check for vendor-type format */ - sep = strchr(kw->value, '-'); - if (sep) - { - *(sep++) = '\0'; - conn->eap_type = atoi(kw->value); - conn->eap_vendor = atoi(sep); - if (conn->eap_type == 0 || conn->eap_vendor == 0) - { - plog("# invalid EAP type: %s=%s", kw->entry->name, kw->value); - cfg->err++; - } - break; - } - conn->eap_type = eap_type_from_string(kw->value); - if (conn->eap_type == 0) - { - conn->eap_type = atoi(kw->value); - if (conn->eap_type == 0) - { - plog("# unknown EAP type: %s=%s", kw->entry->name, kw->value); - cfg->err++; - } - } - break; - } case KW_MARK: if (!handle_mark(kw->value, &conn->mark_in)) { diff --git a/src/starter/confread.h b/src/starter/confread.h index 25f37e633..19c404e2e 100644 --- a/src/starter/confread.h +++ b/src/starter/confread.h @@ -110,8 +110,6 @@ struct starter_conn { starter_state_t state; keyexchange_t keyexchange; - u_int32_t eap_type; - u_int32_t eap_vendor; char *eap_identity; char *aaa_identity; char *xauth_identity; diff --git a/src/starter/keywords.h b/src/starter/keywords.h index 71e31e9f5..3374fa8c7 100644 --- a/src/starter/keywords.h +++ b/src/starter/keywords.h @@ -70,7 +70,6 @@ typedef enum { KW_AGGRESSIVE, KW_AUTH, KW_AUTHBY, - KW_EAP, KW_EAP_IDENTITY, KW_AAA_IDENTITY, KW_MOBIKE, diff --git a/src/starter/keywords.txt b/src/starter/keywords.txt index bd1f9304c..d31fd2461 100644 --- a/src/starter/keywords.txt +++ b/src/starter/keywords.txt @@ -47,7 +47,6 @@ nat_traversal, KW_NAT_TRAVERSAL keep_alive, KW_KEEP_ALIVE force_keepalive, KW_FORCE_KEEPALIVE virtual_private, KW_VIRTUAL_PRIVATE -eap, KW_EAP eap_identity, KW_EAP_IDENTITY aaa_identity, KW_AAA_IDENTITY mobike, KW_MOBIKE diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c index 697115a84..e70245362 100644 --- a/src/stroke/stroke.c +++ b/src/stroke/stroke.c @@ -139,7 +139,6 @@ static int add_connection(char *name, msg.add_conn.name = push_string(&msg, name); msg.add_conn.version = 2; - msg.add_conn.auth_method = 2; msg.add_conn.mode = 1; msg.add_conn.mobike = 1; msg.add_conn.dpd.action = 1; diff --git a/src/stroke/stroke_msg.h b/src/stroke/stroke_msg.h index 825228e9d..be12cabbe 100644 --- a/src/stroke/stroke_msg.h +++ b/src/stroke/stroke_msg.h @@ -240,10 +240,6 @@ struct stroke_msg_t { struct { char *name; int version; - /* next three are deprecated, use stroke_end_t.auth instead */ - int auth_method; - u_int32_t eap_type; - u_int32_t eap_vendor; char *eap_identity; char *aaa_identity; char *xauth_identity; From 6261c0c3b7a79ff3ac2492af878d8fb5d681b4dc Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 23 Jan 2012 12:25:00 +0100 Subject: [PATCH 497/534] Support encoding of IKEv1 ECDSA proposals --- .../encoding/payloads/proposal_substructure.c | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index ba7ef9961..b761b86f6 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -237,6 +237,9 @@ typedef enum { IKEV1_AUTH_RSA_SIG = 3, IKEV1_AUTH_RSA_ENC = 4, IKEV1_AUTH_RSA_ENC_REV = 5, + IKEV1_AUTH_ECDSA_256 = 9, + IKEV1_AUTH_ECDSA_384 = 10, + IKEV1_AUTH_ECDSA_521 = 11, IKEV1_AUTH_XAUTH_INIT_PSK = 65001, IKEV1_AUTH_XAUTH_RESP_PSK = 65002, IKEV1_AUTH_XAUTH_INIT_DSS = 65003, @@ -594,10 +597,14 @@ static u_int16_t get_ikev1_auth(auth_method_t method) return IKEV1_AUTH_XAUTH_INIT_RSA; case AUTH_HYBRID_INIT_RSA: return IKEV1_AUTH_HYBRID_INIT_RSA; - default: - /* TODO-IKEv1: Handle other XAUTH methods */ - /* TODO-IKEv1: Handle ECDSA methods */ + case AUTH_ECDSA_256: + return IKEV1_AUTH_ECDSA_256; + case AUTH_ECDSA_384: + return IKEV1_AUTH_ECDSA_384; + case AUTH_ECDSA_521: + return IKEV1_AUTH_ECDSA_521; case AUTH_PSK: + default: return IKEV1_AUTH_PSK; } } @@ -654,7 +661,6 @@ static void add_to_proposal_v1_ike(proposal_t *proposal, value, 0); break; default: - /* TODO-IKEv1: lifetimes, authentication and other attributes */ break; } } @@ -696,7 +702,6 @@ static void add_to_proposal_v1_esp(proposal_t *proposal, value, 0); break; default: - /* TODO-IKEv1: lifetimes other attributes */ break; } } @@ -889,8 +894,13 @@ METHOD(proposal_substructure_t, get_auth_method, auth_method_t, return AUTH_XAUTH_INIT_RSA; case IKEV1_AUTH_HYBRID_INIT_RSA: return AUTH_HYBRID_INIT_RSA; + case IKEV1_AUTH_ECDSA_256: + return AUTH_ECDSA_256; + case IKEV1_AUTH_ECDSA_384: + return AUTH_ECDSA_384; + case IKEV1_AUTH_ECDSA_521: + return AUTH_ECDSA_521; default: - /* TODO-IKEv1: other XAUTH, ECDSA sigs */ return AUTH_NONE; } } From 5aef6bd0f35ef690e2d2fb84155c77783bfd2bc7 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 23 Jan 2012 12:25:38 +0100 Subject: [PATCH 498/534] Accept NULL auth_cfg_t passed to credential_manager_t.get_private() --- src/conftest/hooks/rebuild_auth.c | 5 +- src/libcharon/plugins/stroke/stroke_list.c | 5 +- .../credentials/credential_manager.c | 58 ++++++++++--------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/conftest/hooks/rebuild_auth.c b/src/conftest/hooks/rebuild_auth.c index 8ee4e14b1..eb95833e8 100644 --- a/src/conftest/hooks/rebuild_auth.c +++ b/src/conftest/hooks/rebuild_auth.c @@ -58,7 +58,6 @@ static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa, enumerator_t *enumerator; chunk_t octets, auth_data; private_key_t *private; - auth_cfg_t *auth; payload_t *payload; auth_payload_t *auth_payload; auth_method_t auth_method; @@ -91,10 +90,8 @@ static bool rebuild_auth(private_rebuild_auth_t *this, ike_sa_t *ike_sa, id = identification_create_from_encoding(data.ptr[4], chunk_skip(data, 8)); generator->destroy(generator); - auth = auth_cfg_create(); private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, - this->id ?: id, auth); - auth->destroy(auth); + this->id ?: id, NULL); if (private == NULL) { DBG1(DBG_CFG, "no private key found for '%Y' to rebuild AUTH", diff --git a/src/libcharon/plugins/stroke/stroke_list.c b/src/libcharon/plugins/stroke/stroke_list.c index c69eef628..8bb1a98ef 100644 --- a/src/libcharon/plugins/stroke/stroke_list.c +++ b/src/libcharon/plugins/stroke/stroke_list.c @@ -685,15 +685,12 @@ static void list_public_key(public_key_t *public, FILE *out) private_key_t *private = NULL; chunk_t keyid; identification_t *id; - auth_cfg_t *auth; if (public->get_fingerprint(public, KEYID_PUBKEY_SHA1, &keyid)) { id = identification_create_from_encoding(ID_KEY_ID, keyid); - auth = auth_cfg_create(); private = lib->credmgr->get_private(lib->credmgr, - public->get_type(public), id, auth); - auth->destroy(auth); + public->get_type(public), id, NULL); id->destroy(id); } diff --git a/src/libstrongswan/credentials/credential_manager.c b/src/libstrongswan/credentials/credential_manager.c index 944c26904..b8f8ae8e3 100644 --- a/src/libstrongswan/credentials/credential_manager.c +++ b/src/libstrongswan/credentials/credential_manager.c @@ -1047,42 +1047,45 @@ METHOD(credential_manager_t, get_private, private_key_t*, } } - /* if a specific certificate is preferred, check for a matching key */ - cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); - if (cert) + if (auth) { - private = get_private_by_cert(this, cert, type); - if (private) + /* if a specific certificate is preferred, check for a matching key */ + cert = auth->get(auth, AUTH_RULE_SUBJECT_CERT); + if (cert) { - trustchain = build_trustchain(this, cert, auth); - if (trustchain) + private = get_private_by_cert(this, cert, type); + if (private) { - auth->merge(auth, trustchain, FALSE); - trustchain->destroy(trustchain); + trustchain = build_trustchain(this, cert, auth); + if (trustchain) + { + auth->merge(auth, trustchain, FALSE); + trustchain->destroy(trustchain); + } + return private; } - return private; } - } - /* try to build a trust chain for each certificate found */ - enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE); - while (enumerator->enumerate(enumerator, &cert)) - { - private = get_private_by_cert(this, cert, type); - if (private) + /* try to build a trust chain for each certificate found */ + enumerator = create_cert_enumerator(this, CERT_ANY, type, id, FALSE); + while (enumerator->enumerate(enumerator, &cert)) { - trustchain = build_trustchain(this, cert, auth); - if (trustchain) + private = get_private_by_cert(this, cert, type); + if (private) { - auth->merge(auth, trustchain, FALSE); - trustchain->destroy(trustchain); - break; + trustchain = build_trustchain(this, cert, auth); + if (trustchain) + { + auth->merge(auth, trustchain, FALSE); + trustchain->destroy(trustchain); + break; + } + private->destroy(private); + private = NULL; } - private->destroy(private); - private = NULL; } + enumerator->destroy(enumerator); } - enumerator->destroy(enumerator); /* if no valid trustchain was found, fall back to the first usable cert */ if (!private) @@ -1093,7 +1096,10 @@ METHOD(credential_manager_t, get_private, private_key_t*, private = get_private_by_cert(this, cert, type); if (private) { - auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert)); + if (auth) + { + auth->add(auth, AUTH_RULE_SUBJECT_CERT, cert->get_ref(cert)); + } break; } } From 5be386ff8e6baab12e904668a07c155454cb0520 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 23 Jan 2012 12:26:42 +0100 Subject: [PATCH 499/534] Exchange certificates when using IKEv1 ECDSA authentication --- src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c | 3 +++ src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c index b88b9e31a..b5ef4cda1 100644 --- a/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_post.c @@ -75,6 +75,9 @@ static bool use_certs(private_isakmp_cert_post_t *this, message_t *message) switch (sa_payload->get_auth_method(sa_payload)) { case AUTH_RSA: + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: case AUTH_HYBRID_INIT_RSA: diff --git a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c index 8d0405730..8ba5a2aa7 100644 --- a/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c +++ b/src/libcharon/sa/ikev1/tasks/isakmp_cert_pre.c @@ -317,6 +317,9 @@ static bool use_certs(private_isakmp_cert_pre_t *this, message_t *message) } /* FALL */ case AUTH_RSA: + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: use = TRUE; From 83b152dd4fadccffd72332803ea0d4e3b25542ce Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 23 Jan 2012 12:27:57 +0100 Subject: [PATCH 500/534] Support ECDSA signatures in IKEv1 pubkey authenticator --- src/libcharon/sa/authenticator.c | 8 +++- .../authenticators/pubkey_v1_authenticator.c | 39 +++++++++++-------- .../authenticators/pubkey_v1_authenticator.h | 3 +- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/src/libcharon/sa/authenticator.c b/src/libcharon/sa/authenticator.c index 8d4b04b66..91bb7715f 100644 --- a/src/libcharon/sa/authenticator.c +++ b/src/libcharon/sa/authenticator.c @@ -133,7 +133,13 @@ authenticator_t *authenticator_create_v1(ike_sa_t *ike_sa, bool initiator, case AUTH_XAUTH_RESP_RSA: return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa, initiator, dh, dh_value, sa_payload, - id_payload); + id_payload, KEY_RSA); + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: + return (authenticator_t*)pubkey_v1_authenticator_create(ike_sa, + initiator, dh, dh_value, sa_payload, + id_payload, KEY_ECDSA); case AUTH_HYBRID_INIT_RSA: case AUTH_HYBRID_RESP_RSA: return (authenticator_t*)hybrid_authenticator_create(ike_sa, diff --git a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c index 56fcf2c9d..8d3f21c49 100644 --- a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c +++ b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.c @@ -60,6 +60,11 @@ struct private_pubkey_v1_authenticator_t { * Encoded ID payload, without fixed header */ chunk_t id_payload; + + /** + * Key type to use + */ + key_type_t type; }; METHOD(authenticator_t, build, status_t, @@ -72,19 +77,20 @@ METHOD(authenticator_t, build, status_t, private_key_t *private; identification_t *id; auth_cfg_t *auth; - key_type_t type; - signature_scheme_t scheme; + signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_NULL; - /* TODO-IKEv1: other key types */ - type = KEY_RSA; - scheme = SIGN_RSA_EMSA_PKCS1_NULL; + if (this->type == KEY_ECDSA) + { + scheme = SIGN_ECDSA_WITH_NULL; + } id = this->ike_sa->get_my_id(this->ike_sa); auth = this->ike_sa->get_auth_cfg(this->ike_sa, TRUE); - private = lib->credmgr->get_private(lib->credmgr, type, id, auth); + private = lib->credmgr->get_private(lib->credmgr, this->type, id, auth); if (!private) { - DBG1(DBG_IKE, "no private key found for '%Y'", id); + DBG1(DBG_IKE, "no %N private key found for '%Y'", + key_type_names, this->type, id); return NOT_FOUND; } @@ -125,13 +131,13 @@ METHOD(authenticator_t, process, status_t, auth_cfg_t *auth, *current_auth; enumerator_t *enumerator; status_t status = NOT_FOUND; - key_type_t type; - signature_scheme_t scheme; identification_t *id; + signature_scheme_t scheme = SIGN_RSA_EMSA_PKCS1_NULL; - /* TODO-IKEv1: currently RSA only */ - type = KEY_RSA; - scheme = SIGN_RSA_EMSA_PKCS1_NULL; + if (this->type == KEY_ECDSA) + { + scheme = SIGN_ECDSA_WITH_NULL; + } sig_payload = (hash_payload_t*)message->get_payload(message, SIGNATURE_V1); if (!sig_payload) @@ -150,14 +156,14 @@ METHOD(authenticator_t, process, status_t, sig = sig_payload->get_hash(sig_payload); auth = this->ike_sa->get_auth_cfg(this->ike_sa, FALSE); - enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, type, + enumerator = lib->credmgr->create_public_enumerator(lib->credmgr, this->type, id, auth); while (enumerator->enumerate(enumerator, &public, ¤t_auth)) { if (public->verify(public, scheme, hash, sig)) { DBG1(DBG_IKE, "authentication of '%Y' with %N successful", - id, key_type_names, type); + id, key_type_names, this->type); status = SUCCESS; auth->merge(auth, current_auth, FALSE); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); @@ -174,7 +180,7 @@ METHOD(authenticator_t, process, status_t, if (status != SUCCESS) { DBG1(DBG_IKE, "no trusted %N public key found for '%Y'", - key_type_names, type, id); + key_type_names, this->type, id); } return status; } @@ -192,7 +198,7 @@ METHOD(authenticator_t, destroy, void, pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, bool initiator, diffie_hellman_t *dh, chunk_t dh_value, chunk_t sa_payload, - chunk_t id_payload) + chunk_t id_payload, key_type_t type) { private_pubkey_v1_authenticator_t *this; @@ -211,6 +217,7 @@ pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, .dh_value = dh_value, .sa_payload = sa_payload, .id_payload = id_payload, + .type = type, ); return &this->public; diff --git a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h index bafc3a2b2..154d83c26 100644 --- a/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h +++ b/src/libcharon/sa/ikev1/authenticators/pubkey_v1_authenticator.h @@ -46,11 +46,12 @@ struct pubkey_v1_authenticator_t { * @param sa_payload generated SA payload data, without payload header * @param id_payload encoded ID payload of peer to authenticate or verify * without payload header (gets owned) + * @param type key type to use, KEY_RSA or KEY_ECDSA * @return pubkey authenticator */ pubkey_v1_authenticator_t *pubkey_v1_authenticator_create(ike_sa_t *ike_sa, bool initiator, diffie_hellman_t *dh, chunk_t dh_value, chunk_t sa_payload, - chunk_t id_payload); + chunk_t id_payload, key_type_t type); #endif /** PUBKEY_V1_AUTHENTICATOR_H_ @}*/ From 4c685e8850dd41021352b300985d37912c99731c Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 23 Jan 2012 12:28:55 +0100 Subject: [PATCH 501/534] Select public key auth method by checking what key we have --- src/libcharon/sa/ikev1/keymat_v1.c | 3 + src/libcharon/sa/ikev1/phase1.c | 100 +++++++++++++++++++++++++++-- 2 files changed, 99 insertions(+), 4 deletions(-) diff --git a/src/libcharon/sa/ikev1/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c index a0dbd5296..7a85aa07b 100644 --- a/src/libcharon/sa/ikev1/keymat_v1.c +++ b/src/libcharon/sa/ikev1/keymat_v1.c @@ -427,6 +427,9 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, break; } case AUTH_RSA: + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: case AUTH_XAUTH_INIT_RSA: case AUTH_XAUTH_RESP_RSA: case AUTH_HYBRID_INIT_RSA: diff --git a/src/libcharon/sa/ikev1/phase1.c b/src/libcharon/sa/ikev1/phase1.c index d36b022aa..c29e5c783 100644 --- a/src/libcharon/sa/ikev1/phase1.c +++ b/src/libcharon/sa/ikev1/phase1.c @@ -369,8 +369,67 @@ static void get_auth_class(peer_cfg_t *peer_cfg, bool local, enumerator->destroy(enumerator); } -METHOD(phase1_t, get_auth_method, auth_method_t, - private_phase1_t *this, peer_cfg_t *peer_cfg) +/** + * Select an auth method to use by checking what key we have + */ +static auth_method_t get_pubkey_method(private_phase1_t *this, auth_cfg_t *auth) +{ + auth_method_t method = AUTH_NONE; + identification_t *id; + private_key_t *private; + + if (auth) + { + id = (identification_t*)auth->get(auth, AUTH_RULE_IDENTITY); + if (id) + { + private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, NULL); + if (private) + { + switch (private->get_type(private)) + { + case KEY_RSA: + method = AUTH_RSA; + break; + case KEY_ECDSA: + switch (private->get_keysize(private)) + { + case 256: + method = AUTH_ECDSA_256; + break; + case 384: + method = AUTH_ECDSA_384; + break; + case 521: + method = AUTH_ECDSA_521; + break; + default: + DBG1(DBG_IKE, "%d bit ECDSA private key size not " + "supported", private->get_keysize(private)); + break; + } + break; + default: + DBG1(DBG_IKE, "private key of type %N not supported", + key_type_names, private->get_type(private)); + break; + } + private->destroy(private); + } + else + { + DBG1(DBG_IKE, "no private key found for '%Y'", id); + } + } + } + return method; +} + +/** + * Calculate authentication method from a peer config + */ +static auth_method_t calc_auth_method(private_phase1_t *this, + peer_cfg_t *peer_cfg) { auth_class_t i1, i2, r1, r2; @@ -381,7 +440,7 @@ METHOD(phase1_t, get_auth_method, auth_method_t, { if (i2 == AUTH_CLASS_ANY && r2 == AUTH_CLASS_ANY) { - /* TODO-IKEv1: ECDSA? */ + /* for any pubkey method, return RSA */ return AUTH_RSA; } if (i2 == AUTH_CLASS_XAUTH) @@ -416,6 +475,39 @@ METHOD(phase1_t, get_auth_method, auth_method_t, return AUTH_NONE; } +METHOD(phase1_t, get_auth_method, auth_method_t, + private_phase1_t *this, peer_cfg_t *peer_cfg) +{ + auth_method_t method; + + method = calc_auth_method(this, peer_cfg); + if (method == AUTH_RSA) + { + return get_pubkey_method(this, get_auth_cfg(peer_cfg, TRUE)); + } + return method; +} + +/** + * Check if a peer config can be used with a given auth method + */ +static bool check_auth_method(private_phase1_t *this, peer_cfg_t *peer_cfg, + auth_method_t given) +{ + auth_method_t method; + + method = calc_auth_method(this, peer_cfg); + switch (given) + { + case AUTH_ECDSA_256: + case AUTH_ECDSA_384: + case AUTH_ECDSA_521: + return method == AUTH_RSA; + default: + return method == given; + } +} + METHOD(phase1_t, select_config, peer_cfg_t*, private_phase1_t *this, auth_method_t method, bool aggressive, identification_t *id) @@ -432,7 +524,7 @@ METHOD(phase1_t, select_config, peer_cfg_t*, me, other, NULL, id, IKEV1); while (enumerator->enumerate(enumerator, ¤t)) { - if (get_auth_method(this, current) == method && + if (check_auth_method(this, current, method) && current->use_aggressive(current) == aggressive) { found = current->get_ref(current); From a0c17d4157a34af9b0a198dcff338423551aac2e Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 23 Jan 2012 12:46:46 +0100 Subject: [PATCH 502/534] Use a dedicated PRF for HASH/SIG payloads using ECDSA specific hasher --- src/libcharon/sa/ikev1/keymat_v1.c | 51 ++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 14 deletions(-) diff --git a/src/libcharon/sa/ikev1/keymat_v1.c b/src/libcharon/sa/ikev1/keymat_v1.c index 7a85aa07b..00de6f042 100644 --- a/src/libcharon/sa/ikev1/keymat_v1.c +++ b/src/libcharon/sa/ikev1/keymat_v1.c @@ -65,9 +65,9 @@ struct private_keymat_v1_t { prf_t *prf; /** - * Negotiated PRF algorithm + * PRF to create Phase 1 HASH payloads */ - pseudo_random_function_t prf_alg; + prf_t *prf_auth; /** * Crypter wrapped in an aead_t interface @@ -366,6 +366,7 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, auth_method_t auth, shared_key_t *shared_key) { chunk_t g_xy, g_xi, g_xr, dh_me, spi_i, spi_r, nonces, data, skeyid_e; + chunk_t skeyid; u_int16_t alg; spi_i = chunk_alloca(sizeof(u_int64_t)); @@ -381,7 +382,6 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, return FALSE; } } - this->prf_alg = alg; this->prf = lib->crypto->create_prf(lib->crypto, alg); if (!this->prf) { @@ -423,7 +423,7 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, psk = shared_key->get_key(shared_key); adjust_keylen(alg, &psk); this->prf->set_key(this->prf, psk); - this->prf->allocate_bytes(this->prf, nonces, &this->skeyid); + this->prf->allocate_bytes(this->prf, nonces, &skeyid); break; } case AUTH_RSA: @@ -436,7 +436,7 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, case AUTH_HYBRID_RESP_RSA: { this->prf->set_key(this->prf, nonces); - this->prf->allocate_bytes(this->prf, g_xy, &this->skeyid); + this->prf->allocate_bytes(this->prf, g_xy, &skeyid); break; } default: @@ -445,32 +445,57 @@ METHOD(keymat_v1_t, derive_ike_keys, bool, chunk_clear(&g_xy); return FALSE; } - adjust_keylen(alg, &this->skeyid); - DBG4(DBG_IKE, "SKEYID %B", &this->skeyid); + adjust_keylen(alg, &skeyid); + DBG4(DBG_IKE, "SKEYID %B", &skeyid); + this->prf->set_key(this->prf, skeyid); /* SKEYID_d = prf(SKEYID, g^xy | CKY-I | CKY-R | 0) */ data = chunk_cat("cccc", g_xy, spi_i, spi_r, octet_0); - this->prf->set_key(this->prf, this->skeyid); this->prf->allocate_bytes(this->prf, data, &this->skeyid_d); chunk_clear(&data); DBG4(DBG_IKE, "SKEYID_d %B", &this->skeyid_d); /* SKEYID_a = prf(SKEYID, SKEYID_d | g^xy | CKY-I | CKY-R | 1) */ data = chunk_cat("ccccc", this->skeyid_d, g_xy, spi_i, spi_r, octet_1); - this->prf->set_key(this->prf, this->skeyid); this->prf->allocate_bytes(this->prf, data, &this->skeyid_a); chunk_clear(&data); DBG4(DBG_IKE, "SKEYID_a %B", &this->skeyid_a); /* SKEYID_e = prf(SKEYID, SKEYID_a | g^xy | CKY-I | CKY-R | 2) */ data = chunk_cat("ccccc", this->skeyid_a, g_xy, spi_i, spi_r, octet_2); - this->prf->set_key(this->prf, this->skeyid); this->prf->allocate_bytes(this->prf, data, &skeyid_e); chunk_clear(&data); DBG4(DBG_IKE, "SKEYID_e %B", &skeyid_e); chunk_clear(&g_xy); + switch (auth) + { + case AUTH_ECDSA_256: + alg = PRF_HMAC_SHA2_256; + break; + case AUTH_ECDSA_384: + alg = PRF_HMAC_SHA2_384; + break; + case AUTH_ECDSA_521: + alg = PRF_HMAC_SHA2_512; + break; + default: + /* use proposal algorithm */ + break; + } + this->prf_auth = lib->crypto->create_prf(lib->crypto, alg); + if (!this->prf_auth) + { + DBG1(DBG_IKE, "%N %N not supported!", + transform_type_names, PSEUDO_RANDOM_FUNCTION, + pseudo_random_function_names, alg); + chunk_clear(&skeyid); + return FALSE; + } + this->prf_auth->set_key(this->prf_auth, skeyid); + chunk_clear(&skeyid); + this->aead = create_aead(proposal, this->prf, skeyid_e); if (!this->aead) { @@ -667,8 +692,7 @@ METHOD(keymat_v1_t, get_hash, chunk_t, DBG3(DBG_IKE, "HASH_%c data %B", initiator ? 'I' : 'R', &data); - this->prf->set_key(this->prf, this->skeyid); - this->prf->allocate_bytes(this->prf, data, &hash); + this->prf_auth->allocate_bytes(this->prf_auth, data, &hash); DBG3(DBG_IKE, "HASH_%c %B", initiator ? 'I' : 'R', &hash); @@ -971,9 +995,9 @@ METHOD(keymat_t, destroy, void, private_keymat_v1_t *this) { DESTROY_IF(this->prf); + DESTROY_IF(this->prf_auth); DESTROY_IF(this->aead); DESTROY_IF(this->hasher); - chunk_clear(&this->skeyid); chunk_clear(&this->skeyid_d); chunk_clear(&this->skeyid_a); chunk_free(&this->phase1_iv.iv); @@ -1011,7 +1035,6 @@ keymat_v1_t *keymat_v1_create(bool initiator) .ivs = linked_list_create(), .qms = linked_list_create(), .initiator = initiator, - .prf_alg = PRF_UNDEFINED, ); return &this->public; From c60246a6181cdb3306ec423246e2821b734a02ed Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 23 Jan 2012 13:49:56 +0100 Subject: [PATCH 503/534] Support inactivity timeout in IKEv1 CHILD_SAs --- src/libcharon/sa/ikev1/tasks/quick_mode.c | 25 ++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/libcharon/sa/ikev1/tasks/quick_mode.c b/src/libcharon/sa/ikev1/tasks/quick_mode.c index 6956dcb40..d8bc2884c 100755 --- a/src/libcharon/sa/ikev1/tasks/quick_mode.c +++ b/src/libcharon/sa/ikev1/tasks/quick_mode.c @@ -26,6 +26,7 @@ #include #include #include +#include typedef struct private_quick_mode_t private_quick_mode_t; @@ -136,6 +137,25 @@ struct private_quick_mode_t { } state; }; +/** + * Schedule inactivity timeout for CHILD_SA with reqid, if enabled + */ +static void schedule_inactivity_timeout(private_quick_mode_t *this) +{ + u_int32_t timeout; + bool close_ike; + + timeout = this->config->get_inactivity(this->config); + if (timeout) + { + close_ike = lib->settings->get_bool(lib->settings, + "charon.inactivity_close_ike", FALSE); + lib->scheduler->schedule_job(lib->scheduler, (job_t*) + inactivity_job_create(this->child_sa->get_reqid(this->child_sa), + timeout, close_ike), timeout); + } +} + /** * Install negotiated CHILD_SA */ @@ -257,8 +277,11 @@ static bool install(private_quick_mode_t *this) { charon->bus->child_updown(charon->bus, this->child_sa, TRUE); } + if (!this->rekey) + { + schedule_inactivity_timeout(this); + } this->child_sa = NULL; - return TRUE; } From 75e3d90d43ccd55bc439a12080a824bdc71a2fba Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Mon, 23 Jan 2012 14:35:57 +0100 Subject: [PATCH 504/534] Updated ipsec.conf man page for the use of IKEv1 with pluto --- man/ipsec.conf.5.in | 405 ++++++++------------------------------------ 1 file changed, 73 insertions(+), 332 deletions(-) diff --git a/man/ipsec.conf.5.in b/man/ipsec.conf.5.in index 2f914b0c8..f6e2c227f 100644 --- a/man/ipsec.conf.5.in +++ b/man/ipsec.conf.5.in @@ -172,9 +172,9 @@ keying, rekeying, and general control. The path to control the connection is called 'ISAKMP SA' in IKEv1 and 'IKE SA' in the IKEv2 protocol. That what is being negotiated, the kernel level data path, is called 'IPsec SA' or 'Child SA'. -strongSwan currently uses two separate keying daemons. \fIpluto\fP handles -all IKEv1 connections, \fIcharon\fP is the daemon handling the IKEv2 -protocol. +strongSwan previously used two separate keying daemons, \fIpluto\fP and +\fIcharon\fP. This manual does not discuss \fIpluto\fP options anymore, but +only \fIcharon\fP that since strongSwan 5.0 supports both IKEv1 and IKEv2. .PP To avoid trivial editing of the configuration file to suit it to each system involved in a connection, @@ -237,16 +237,6 @@ identity (such as EAP-TLS), but it does not match the IKEv2 gateway identity. includes conn section .BR . .TP -.BR auth " = " esp " | ah" -whether authentication should be done as part of -ESP encryption, or separately using the AH protocol; -acceptable values are -.B esp -(the default) and -.BR ah . -.br -The IKEv2 daemon currently supports ESP only. -.TP .BR authby " = " pubkey " | rsasig | ecdsasig | psk | never | xauthpsk | xauthrsasig" how the two security gateways should authenticate each other; acceptable values are @@ -270,10 +260,10 @@ and .B xauthrsasig that will enable eXtended AUTHentication (XAUTH) in addition to IKEv1 main mode based on shared secrets or digital RSA signatures, respectively. -This parameter is deprecated for IKEv2 connections, as two peers do not need -to agree on an authentication method. Use the +This parameter is deprecated, as two peers do not need to agree on an +authentication method in IKEv2. Use the .B leftauth -parameter instead to define authentication methods in IKEv2. +parameter instead to define authentication methods. .TP .BR auto " = " ignore " | add | route | start" what operation, if any, should be done automatically at IPsec startup; @@ -318,7 +308,8 @@ and prefer compressed. A value of .B no prevents IPsec from proposing compression; -a proposal to compress will still be accepted. +a proposal to compress will still be accepted. IPComp is currently not supported +with IKEv1. .TP .BR dpdaction " = " none " | clear | hold | restart" controls the use of the Dead Peer Detection protocol (DPD, RFC 3706) where @@ -336,16 +327,9 @@ put in the hold state .RB ( hold ) or restarted .RB ( restart ). -For IKEv1, the default is +The default is .B none -which disables the active sending of R_U_THERE notifications. -Nevertheless pluto will always send the DPD Vendor ID during connection set up -in order to signal the readiness to act passively as a responder if the peer -wants to use DPD. For IKEv2, -.B none -does't make sense, since all messages are used to detect dead peers. If specified, -it has the same meaning as the default -.RB ( clear ). +which disables the active sending of DPD messages. .TP .BR dpddelay " = " 30s " |