diff options
author | Martin Willi <martin@revosec.ch> | 2011-11-16 13:46:54 +0100 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2012-03-20 17:30:40 +0100 |
commit | 1bf2971ff2d63f1f1c4d59d1091b8a1b11b0ef62 (patch) | |
tree | dc7c9946dcd757cca853b7ce2f6edc4c2381442a | |
parent | 3f6d1b13a7d53bf465c65687e18425d14a143af8 (diff) | |
download | strongswan-1bf2971ff2d63f1f1c4d59d1091b8a1b11b0ef62.tar.bz2 strongswan-1bf2971ff2d63f1f1c4d59d1091b8a1b11b0ef62.tar.xz |
Implemented limited payload parsing for IKEv1 SA payloads
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 <daemon.h> /** - * 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; + + if (type == PROPOSAL_SUBSTRUCTURE_V1) + { + /* TODO-IKEv1: IKEv1 specific proposal encoding */ + subtype = TRANSFORM_SUBSTRUCTURE_V1; + } - this = (private_proposal_substructure_t*)proposal_substructure_create(); + 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 <encoding/payloads/encodings.h> #include <library.h> +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; -}; - -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); + /** + * Payload type, TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 + */ + payload_type_t type; +}; /** - * 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 <library.h> #include <encoding/payloads/payload.h> - /** - * 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_ @}*/ |