Implemented limited payload parsing for IKEv1 SA payloads

This commit is contained in:
Martin Willi
2012-03-20 17:30:40 +01:00
parent 3f6d1b13a7
commit 1bf2971ff2
7 changed files with 557 additions and 176 deletions
@@ -25,7 +25,7 @@
#include <daemon.h> #include <daemon.h>
/** /**
* IKEv1 Value for a proposal payload. * IKEv2 Value for a proposal payload.
*/ */
#define PROPOSAL_TYPE_VALUE 2 #define PROPOSAL_TYPE_VALUE 2
@@ -84,16 +84,43 @@ struct private_proposal_substructure_t {
/** /**
* Transforms are stored in a linked_list_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. * Encoding rules for a IKEv1 Proposal substructure.
*
* The defined offsets are the positions in a object of type
* private_proposal_substructure_t.
*/ */
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 */ /* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) },
/* 1 Reserved Byte */ /* 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, METHOD(payload_t, verify, status_t,
private_proposal_substructure_t *this) 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, private_proposal_substructure_t *this, encoding_rule_t **rules,
size_t *rule_count) size_t *rule_count)
{ {
*rules = proposal_substructure_encodings; if (this->type == PROPOSAL_SUBSTRUCTURE)
*rule_count = countof(proposal_substructure_encodings); {
*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, METHOD(payload_t, get_type, payload_type_t,
private_proposal_substructure_t *this) private_proposal_substructure_t *this)
{ {
return PROPOSAL_SUBSTRUCTURE; return this->type;
} }
METHOD(payload_t, get_next_type, payload_type_t, METHOD(payload_t, get_next_type, payload_type_t,
@@ -301,43 +406,206 @@ METHOD(proposal_substructure_t, get_spi, chunk_t,
return this->spi; 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*, METHOD(proposal_substructure_t, get_proposal, proposal_t*,
private_proposal_substructure_t *this) private_proposal_substructure_t *this)
{ {
enumerator_t *enumerator;
transform_substructure_t *transform; transform_substructure_t *transform;
enumerator_t *enumerator;
proposal_t *proposal; proposal_t *proposal;
u_int64_t spi;
proposal = proposal_create(this->protocol_id, this->proposal_number); proposal = proposal_create(this->protocol_id, this->proposal_number);
enumerator = this->transforms->create_enumerator(this->transforms); enumerator = this->transforms->create_enumerator(this->transforms);
while (enumerator->enumerate(enumerator, &transform)) while (enumerator->enumerate(enumerator, &transform))
{ {
transform_type_t transform_type; if (this->type == PROPOSAL_SUBSTRUCTURE)
u_int16_t transform_id; {
u_int16_t key_length = 0; add_to_proposal_v2(proposal, transform);
}
transform_type = transform->get_transform_type(transform); else
transform_id = transform->get_transform_id(transform); {
transform->get_key_length(transform, &key_length); switch (this->protocol_id)
{
proposal->add_algorithm(proposal, transform_type, transform_id, key_length); 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); enumerator->destroy(enumerator);
switch (this->spi.len) switch (this->spi.len)
{ {
case 4: case 4:
spi = *((u_int32_t*)this->spi.ptr); proposal->set_spi(proposal, *((u_int32_t*)this->spi.ptr));
break; break;
case 8: case 8:
spi = *((u_int64_t*)this->spi.ptr); proposal->set_spi(proposal, *((u_int64_t*)this->spi.ptr));
break; break;
default: default:
spi = 0; break;
} }
proposal->set_spi(proposal, spi);
return proposal; return proposal;
} }
@@ -352,7 +620,7 @@ METHOD2(payload_t, proposal_substructure_t, destroy, void,
private_proposal_substructure_t *this) private_proposal_substructure_t *this)
{ {
this->transforms->destroy_offset(this->transforms, this->transforms->destroy_offset(this->transforms,
offsetof(transform_substructure_t, destroy)); offsetof(payload_t, destroy));
chunk_free(&this->spi); chunk_free(&this->spi);
free(this); free(this);
} }
@@ -360,7 +628,7 @@ METHOD2(payload_t, proposal_substructure_t, destroy, void,
/* /*
* Described in header. * Described in header.
*/ */
proposal_substructure_t *proposal_substructure_create() proposal_substructure_t *proposal_substructure_create(payload_type_t type)
{ {
private_proposal_substructure_t *this; private_proposal_substructure_t *this;
@@ -389,6 +657,7 @@ proposal_substructure_t *proposal_substructure_create()
.next_payload = NO_PAYLOAD, .next_payload = NO_PAYLOAD,
.proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH, .proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH,
.transforms = linked_list_create(), .transforms = linked_list_create(),
.type = type,
); );
return &this->public; return &this->public;
@@ -398,21 +667,28 @@ proposal_substructure_t *proposal_substructure_create()
* Described in header. * Described in header.
*/ */
proposal_substructure_t *proposal_substructure_create_from_proposal( proposal_substructure_t *proposal_substructure_create_from_proposal(
proposal_t *proposal) payload_type_t type, proposal_t *proposal)
{ {
transform_substructure_t *transform; transform_substructure_t *transform;
private_proposal_substructure_t *this; private_proposal_substructure_t *this;
u_int16_t alg, key_size; u_int16_t alg, key_size;
enumerator_t *enumerator; 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 */ /* encryption algorithm is only available in ESP */
enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM);
while (enumerator->enumerate(enumerator, &alg, &key_size)) while (enumerator->enumerate(enumerator, &alg, &key_size))
{ {
transform = transform_substructure_create_type(ENCRYPTION_ALGORITHM, transform = transform_substructure_create_type(subtype,
alg, key_size); ENCRYPTION_ALGORITHM, alg, key_size);
add_transform_substructure(this, transform); add_transform_substructure(this, transform);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
@@ -421,8 +697,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal(
enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM);
while (enumerator->enumerate(enumerator, &alg, &key_size)) while (enumerator->enumerate(enumerator, &alg, &key_size))
{ {
transform = transform_substructure_create_type(INTEGRITY_ALGORITHM, transform = transform_substructure_create_type(subtype,
alg, key_size); INTEGRITY_ALGORITHM, alg, key_size);
add_transform_substructure(this, transform); add_transform_substructure(this, transform);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
@@ -431,8 +707,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal(
enumerator = proposal->create_enumerator(proposal, PSEUDO_RANDOM_FUNCTION); enumerator = proposal->create_enumerator(proposal, PSEUDO_RANDOM_FUNCTION);
while (enumerator->enumerate(enumerator, &alg, &key_size)) while (enumerator->enumerate(enumerator, &alg, &key_size))
{ {
transform = transform_substructure_create_type(PSEUDO_RANDOM_FUNCTION, transform = transform_substructure_create_type(subtype,
alg, key_size); PSEUDO_RANDOM_FUNCTION, alg, key_size);
add_transform_substructure(this, transform); add_transform_substructure(this, transform);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
@@ -441,8 +717,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal(
enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP);
while (enumerator->enumerate(enumerator, &alg, NULL)) while (enumerator->enumerate(enumerator, &alg, NULL))
{ {
transform = transform_substructure_create_type(DIFFIE_HELLMAN_GROUP, transform = transform_substructure_create_type(subtype,
alg, 0); DIFFIE_HELLMAN_GROUP, alg, 0);
add_transform_substructure(this, transform); add_transform_substructure(this, transform);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
@@ -451,8 +727,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal(
enumerator = proposal->create_enumerator(proposal, EXTENDED_SEQUENCE_NUMBERS); enumerator = proposal->create_enumerator(proposal, EXTENDED_SEQUENCE_NUMBERS);
while (enumerator->enumerate(enumerator, &alg, NULL)) while (enumerator->enumerate(enumerator, &alg, NULL))
{ {
transform = transform_substructure_create_type(EXTENDED_SEQUENCE_NUMBERS, transform = transform_substructure_create_type(subtype,
alg, 0); EXTENDED_SEQUENCE_NUMBERS, alg, 0);
add_transform_substructure(this, transform); add_transform_substructure(this, transform);
} }
enumerator->destroy(enumerator); enumerator->destroy(enumerator);
@@ -37,9 +37,7 @@ typedef struct proposal_substructure_t proposal_substructure_t;
#define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8 #define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8
/** /**
* Class representing an IKEv2-PROPOSAL SUBSTRUCTURE. * Class representing an IKEv1/IKEv2 proposal substructure.
*
* The PROPOSAL SUBSTRUCTURE format is described in RFC section 3.3.1.
*/ */
struct proposal_substructure_t { struct proposal_substructure_t {
@@ -126,17 +124,19 @@ struct proposal_substructure_t {
/** /**
* Creates an empty proposal_substructure_t object * 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. * 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 * @param proposal proposal to build a substruct out of it
* @return proposal_substructure_t object * @return proposal_substructure_t object
*/ */
proposal_substructure_t *proposal_substructure_create_from_proposal( proposal_substructure_t *proposal_substructure_create_from_proposal(
proposal_t *proposal); payload_type_t type, proposal_t *proposal);
#endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/ #endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/
+17 -2
View File
@@ -158,11 +158,16 @@ static encoding_rule_t encodings_v2[] = {
METHOD(payload_t, verify, status_t, METHOD(payload_t, verify, status_t,
private_sa_payload_t *this) private_sa_payload_t *this)
{ {
int expected_number = 1, current_number; int expected_number = 0, current_number;
status_t status = SUCCESS; status_t status = SUCCESS;
enumerator_t *enumerator; enumerator_t *enumerator;
proposal_substructure_t *substruct; proposal_substructure_t *substruct;
if (this->type == SECURITY_ASSOCIATION)
{
expected_number = 1;
}
/* check proposal numbering */ /* check proposal numbering */
enumerator = this->proposals->create_enumerator(this->proposals); enumerator = this->proposals->create_enumerator(this->proposals);
while (enumerator->enumerate(enumerator, (void**)&substruct)) 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) private_sa_payload_t *this, proposal_t *proposal)
{ {
proposal_substructure_t *substruct, *last; proposal_substructure_t *substruct, *last;
payload_type_t subtype = PROPOSAL_SUBSTRUCTURE;
u_int count; u_int count;
count = this->proposals->get_count(this->proposals); 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) if (count > 0)
{ {
this->proposals->get_last(this->proposals, (void**)&last); 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; linked_list_t *list;
proposal_t *proposal; proposal_t *proposal;
if (this->type == SECURITY_ASSOCIATION_V1)
{ /* IKEv1 proposals start with 0 */
struct_number = ignore_struct_number = -1;
}
list = linked_list_create(); list = linked_list_create();
/* we do not support proposals split up to two proposal substructures, as /* we do not support proposals split up to two proposal substructures, as
* AH+ESP bundles are not supported in RFC4301 anymore. * AH+ESP bundles are not supported in RFC4301 anymore.
@@ -23,6 +23,44 @@
#include <encoding/payloads/encodings.h> #include <encoding/payloads/encodings.h>
#include <library.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; 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). * Attribute value as chunk if attribute_format is 0 (FALSE).
*/ */
chunk_t attribute_value; 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. * Encoding rules for IKEv1/IKEv2 transform attributes
*
* The defined offsets are the positions in a object of type
* private_transform_attribute_t.
*/ */
encoding_rule_t transform_attribute_encodings[] = { static encoding_rule_t encodings[] = {
/* Flag defining the format of this payload */ /* Flag defining the format of this payload */
{ ATTRIBUTE_FORMAT, offsetof(private_transform_attribute_t, attribute_format) }, { ATTRIBUTE_FORMAT, offsetof(private_transform_attribute_t, attribute_format) },
/* type of the attribute as 15 bit unsigned integer */ /* 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, private_transform_attribute_t *this, encoding_rule_t **rules,
size_t *rule_count) size_t *rule_count)
{ {
*rules = transform_attribute_encodings; *rules = encodings;
*rule_count = countof(transform_attribute_encodings); *rule_count = countof(encodings);
} }
METHOD(payload_t, get_type, payload_type_t, METHOD(payload_t, get_type, payload_type_t,
private_transform_attribute_t *this) private_transform_attribute_t *this)
{ {
return TRANSFORM_ATTRIBUTE; return this->type;
} }
METHOD(payload_t, get_next_type, payload_type_t, 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*, METHOD(transform_attribute_t, clone_, transform_attribute_t*,
private_transform_attribute_t *this) 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->attribute_format = this->attribute_format;
new_clone->attribute_type = this->attribute_type; new->attribute_type = this->attribute_type;
new_clone->attribute_length_or_value = this->attribute_length_or_value; 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, METHOD2(payload_t, transform_attribute_t, destroy, void,
@@ -217,7 +250,7 @@ METHOD2(payload_t, transform_attribute_t, destroy, void,
/* /*
* Described in header. * Described in header.
*/ */
transform_attribute_t *transform_attribute_create() transform_attribute_t *transform_attribute_create(payload_type_t type)
{ {
private_transform_attribute_t *this; private_transform_attribute_t *this;
@@ -242,6 +275,7 @@ transform_attribute_t *transform_attribute_create()
.destroy = _destroy, .destroy = _destroy,
}, },
.attribute_format = TRUE, .attribute_format = TRUE,
.type = type,
); );
return &this->public; 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 *transform_attribute_create_key_length(u_int16_t key_length)
{ {
transform_attribute_t *attribute = transform_attribute_create(); transform_attribute_t *attribute;
attribute->set_attribute_type(attribute, KEY_LENGTH);
attribute = transform_attribute_create(TRANSFORM_ATTRIBUTE);
attribute->set_attribute_type(attribute, TATTR_IKEV2_KEY_LENGTH);
attribute->set_value(attribute, key_length); attribute->set_value(attribute, key_length);
return attribute; return attribute;
} }
@@ -28,26 +28,66 @@ typedef struct transform_attribute_t transform_attribute_t;
#include <library.h> #include <library.h>
#include <encoding/payloads/payload.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 { enum transform_attribute_type_t {
ATTRIBUTE_UNDEFINED = 16384, /** IKEv1 Phase 1 attributes */
KEY_LENGTH = 14 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. * Enum names for IKEv1 Phase 2 transform_attribute_type_t.
* */
* The TRANSFORM ATTRIBUTE format is described in RFC section 3.3.5. 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 { struct transform_attribute_t {
/** /**
* The payload_t interface. * The payload_t interface.
*/ */
@@ -117,9 +157,10 @@ struct transform_attribute_t {
/** /**
* Creates an empty transform_attribute_t object. * Creates an empty transform_attribute_t object.
* *
* @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1
* @return transform_attribute_t object * @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. * Creates an transform_attribute_t of type KEY_LENGTH.
@@ -41,10 +41,11 @@ struct private_transform_substructure_t {
* Next payload type. * Next payload type.
*/ */
u_int8_t next_payload; u_int8_t next_payload;
/** /**
* Reserved bytes * Reserved byte
*/ */
u_int8_t reserved[2]; u_int8_t reserved[3];
/** /**
* Length of this payload. * Length of this payload.
@@ -52,43 +53,70 @@ struct private_transform_substructure_t {
u_int16_t transform_length; 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. * Transforms Attributes are stored in a linked_list_t.
*/ */
linked_list_t *attributes; 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. * Encoding rules for TRANSFORM_SUBSTRUCTURE
*
* The defined offsets are the positions in a object of type
* private_transform_substructure_t.
*/ */
encoding_rule_t transform_substructure_encodings[] = { static encoding_rule_t encodings_v2[] = {
/* 1 Byte next payload type, stored in the field next_payload */ /* 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 */ /* 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*/ /* 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 is a number of 8 bit */ /* transform type */
{ U_INT_8, offsetof(private_transform_substructure_t, 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 */ /* 1 Reserved Byte */
{ RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) },
/* transform ID is a number of 8 bit */ /* Length of the whole transform substructure*/
{ U_INT_16, offsetof(private_transform_substructure_t, transform_id) }, { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)},
/* Attributes are stored in a transform attribute, /* transform number */
offset points to a linked_list_t pointer */ { U_INT_8, offsetof(private_transform_substructure_t, transform_ton)},
{ TRANSFORM_ATTRIBUTES, offsetof(private_transform_substructure_t, attributes) } /* 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 ! ! 0 (last) or 3 ! RESERVED ! Transform Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
!Transform Type ! RESERVED ! Transform ID ! ! Tfrm Typ or # ! Tfrm ID IKEv1 ! Transform ID IKEv2 !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! ! ! !
~ Transform Attributes ~ ~ Transform Attributes ~
@@ -118,23 +146,6 @@ METHOD(payload_t, verify, status_t,
return FAILED; 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); enumerator = this->attributes->create_enumerator(this->attributes);
while (enumerator->enumerate(enumerator, &attribute)) 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, private_transform_substructure_t *this, encoding_rule_t **rules,
size_t *rule_count) size_t *rule_count)
{ {
*rules = transform_substructure_encodings; if (this->type == TRANSFORM_ATTRIBUTE)
*rule_count = countof(transform_substructure_encodings); {
*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, METHOD(payload_t, get_type, payload_type_t,
private_transform_substructure_t *this) private_transform_substructure_t *this)
{ {
return TRANSFORM_SUBSTRUCTURE; return this->type;
} }
METHOD(payload_t, get_next_type, payload_type_t, 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. * 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; enumerator_t *enumerator;
payload_t *attribute; 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) private_transform_substructure_t *this)
{ {
return this->transform_type; return this->transform_ton;
} }
METHOD(transform_substructure_t, get_transform_id, u_int16_t, METHOD(transform_substructure_t, get_transform_id, u_int16_t,
private_transform_substructure_t *this) 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, METHOD(transform_substructure_t, create_attribute_enumerator, enumerator_t*,
private_transform_substructure_t *this, u_int16_t *key_length) private_transform_substructure_t *this)
{ {
enumerator_t *enumerator; return this->attributes->create_enumerator(this->attributes);
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;
} }
METHOD2(payload_t, transform_substructure_t, destroy, void, METHOD2(payload_t, transform_substructure_t, destroy, void,
private_transform_substructure_t *this) private_transform_substructure_t *this)
{ {
this->attributes->destroy_offset(this->attributes, this->attributes->destroy_offset(this->attributes,
offsetof(transform_attribute_t, destroy)); offsetof(payload_t, destroy));
free(this); free(this);
} }
/* /*
* Described in header. * Described in header.
*/ */
transform_substructure_t *transform_substructure_create() transform_substructure_t *transform_substructure_create(payload_type_t type)
{ {
private_transform_substructure_t *this; private_transform_substructure_t *this;
@@ -264,14 +273,15 @@ transform_substructure_t *transform_substructure_create()
.destroy = _destroy, .destroy = _destroy,
}, },
.set_is_last_transform = _set_is_last_transform, .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_transform_id = _get_transform_id,
.get_key_length = _get_key_length, .create_attribute_enumerator = _create_attribute_enumerator,
.destroy = _destroy, .destroy = _destroy,
}, },
.next_payload = NO_PAYLOAD, .next_payload = NO_PAYLOAD,
.transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH, .transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH,
.attributes = linked_list_create(), .attributes = linked_list_create(),
.type = type,
); );
return &this->public; return &this->public;
} }
@@ -279,15 +289,22 @@ transform_substructure_t *transform_substructure_create()
/* /*
* Described in header * Described in header
*/ */
transform_substructure_t *transform_substructure_create_type( transform_substructure_t *transform_substructure_create_type(payload_type_t type,
transform_type_t type, u_int16_t id, u_int16_t key_length) u_int8_t type_or_number, u_int16_t id, u_int16_t key_length)
{ {
private_transform_substructure_t *this; 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_ton = type_or_number;
this->transform_id = id; if (type == TRANSFORM_SUBSTRUCTURE)
{
this->transform_id_v2 = id;
}
else
{
this->transform_id_v1 = id;
}
if (key_length) if (key_length)
{ {
this->attributes->insert_last(this->attributes, this->attributes->insert_last(this->attributes,
@@ -45,9 +45,7 @@ typedef struct transform_substructure_t transform_substructure_t;
#define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8 #define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8
/** /**
* Class representing an IKEv2- TRANSFORM SUBSTRUCTURE. * Class representing an IKEv1/IKEv2 transform substructure.
*
* The TRANSFORM SUBSTRUCTURE format is described in RFC section 3.3.2.
*/ */
struct transform_substructure_t { struct transform_substructure_t {
@@ -75,11 +73,11 @@ struct transform_substructure_t {
void (*set_is_last_transform) (transform_substructure_t *this, bool is_last); 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. * @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. * 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); 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 enumerator over transform_attribute_t*
* @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!
*/ */
status_t (*get_key_length) (transform_substructure_t *this, enumerator_t* (*create_attribute_enumerator)(transform_substructure_t *this);
u_int16_t *key_length);
/** /**
* Destroys an transform_substructure_t object. * Destroys an transform_substructure_t object.
@@ -109,19 +102,21 @@ struct transform_substructure_t {
/** /**
* Creates an empty transform_substructure_t object. * Creates an empty transform_substructure_t object.
* *
* @param type TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1
* @return created transform_substructure_t object * @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. * Creates an empty transform_substructure_t object.
* *
* @param type type of transform to create * @param type TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1
* @param id transform id specifc for the transform type * @param type_or_number Type (IKEv2) or number (IKEv1) of transform
* @param key_length key length for key length attribute, 0 to omit * @param id transform id specifc for the transform type
* @return transform_substructure_t object * @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_substructure_t *transform_substructure_create_type(payload_type_t type,
transform_type_t type, u_int16_t id, u_int16_t key_length); u_int8_t type_or_number, u_int16_t id, u_int16_t key_length);
#endif /** TRANSFORM_SUBSTRUCTURE_H_ @}*/ #endif /** TRANSFORM_SUBSTRUCTURE_H_ @}*/