Implemented limited payload parsing for IKEv1 SA payloads
authorMartin Willi <martin@revosec.ch>
Wed, 16 Nov 2011 12:46:54 +0000 (13:46 +0100)
committerMartin Willi <martin@revosec.ch>
Tue, 20 Mar 2012 16:30:40 +0000 (17:30 +0100)
src/libcharon/encoding/payloads/proposal_substructure.c
src/libcharon/encoding/payloads/proposal_substructure.h
src/libcharon/encoding/payloads/sa_payload.c
src/libcharon/encoding/payloads/transform_attribute.c
src/libcharon/encoding/payloads/transform_attribute.h
src/libcharon/encoding/payloads/transform_substructure.c
src/libcharon/encoding/payloads/transform_substructure.h

index 4753d57..efa748b 100644 (file)
@@ -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);
index d0ba1fd..86ccd5b 100644 (file)
@@ -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_ @}*/
index af30126..0612263 100644 (file)
@@ -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.
index 7d21258..e928dcd 100644 (file)
 #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;
 }
index a5fe015..21bde46 100644 (file)
@@ -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.
index 3f04b35..141898a 100644 (file)
@@ -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,
index 102dbb3..e6a7f8e 100644 (file)
@@ -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_ @}*/