summaryrefslogtreecommitdiff
path: root/src/libcharon/encoding
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/encoding')
-rw-r--r--src/libcharon/encoding/generator.c154
-rw-r--r--src/libcharon/encoding/generator.h8
-rw-r--r--src/libcharon/encoding/message.c770
-rw-r--r--src/libcharon/encoding/message.h65
-rw-r--r--src/libcharon/encoding/parser.c232
-rw-r--r--src/libcharon/encoding/payloads/auth_payload.c23
-rw-r--r--src/libcharon/encoding/payloads/auth_payload.h7
-rw-r--r--src/libcharon/encoding/payloads/cert_payload.c58
-rw-r--r--src/libcharon/encoding/payloads/cert_payload.h27
-rw-r--r--src/libcharon/encoding/payloads/certreq_payload.c74
-rw-r--r--src/libcharon/encoding/payloads/certreq_payload.h34
-rw-r--r--src/libcharon/encoding/payloads/configuration_attribute.c211
-rw-r--r--src/libcharon/encoding/payloads/configuration_attribute.h44
-rw-r--r--src/libcharon/encoding/payloads/cp_payload.c144
-rw-r--r--src/libcharon/encoding/payloads/cp_payload.h35
-rw-r--r--src/libcharon/encoding/payloads/delete_payload.c143
-rw-r--r--src/libcharon/encoding/payloads/delete_payload.h21
-rw-r--r--src/libcharon/encoding/payloads/eap_payload.c189
-rw-r--r--src/libcharon/encoding/payloads/eap_payload.h29
-rw-r--r--src/libcharon/encoding/payloads/encodings.c20
-rw-r--r--src/libcharon/encoding/payloads/encodings.h199
-rw-r--r--src/libcharon/encoding/payloads/encryption_payload.c177
-rw-r--r--src/libcharon/encoding/payloads/encryption_payload.h16
-rw-r--r--src/libcharon/encoding/payloads/endpoint_notify.c2
-rw-r--r--src/libcharon/encoding/payloads/hash_payload.c177
-rw-r--r--src/libcharon/encoding/payloads/hash_payload.h67
-rw-r--r--src/libcharon/encoding/payloads/id_payload.c304
-rw-r--r--src/libcharon/encoding/payloads/id_payload.h48
-rw-r--r--src/libcharon/encoding/payloads/ike_header.c195
-rw-r--r--src/libcharon/encoding/payloads/ike_header.h139
-rw-r--r--src/libcharon/encoding/payloads/ke_payload.c76
-rw-r--r--src/libcharon/encoding/payloads/ke_payload.h32
-rw-r--r--src/libcharon/encoding/payloads/nonce_payload.c54
-rw-r--r--src/libcharon/encoding/payloads/nonce_payload.h14
-rw-r--r--src/libcharon/encoding/payloads/notify_payload.c284
-rw-r--r--src/libcharon/encoding/payloads/notify_payload.h62
-rw-r--r--src/libcharon/encoding/payloads/payload.c159
-rw-r--r--src/libcharon/encoding/payloads/payload.h175
-rw-r--r--src/libcharon/encoding/payloads/proposal_substructure.c1218
-rw-r--r--src/libcharon/encoding/payloads/proposal_substructure.h120
-rw-r--r--src/libcharon/encoding/payloads/sa_payload.c366
-rw-r--r--src/libcharon/encoding/payloads/sa_payload.h94
-rw-r--r--src/libcharon/encoding/payloads/traffic_selector_substructure.c22
-rw-r--r--src/libcharon/encoding/payloads/traffic_selector_substructure.h5
-rw-r--r--src/libcharon/encoding/payloads/transform_attribute.c185
-rw-r--r--src/libcharon/encoding/payloads/transform_attribute.h104
-rw-r--r--src/libcharon/encoding/payloads/transform_substructure.c188
-rw-r--r--src/libcharon/encoding/payloads/transform_substructure.h39
-rw-r--r--src/libcharon/encoding/payloads/ts_payload.c26
-rw-r--r--src/libcharon/encoding/payloads/ts_payload.h5
-rw-r--r--src/libcharon/encoding/payloads/unknown_payload.c27
-rw-r--r--src/libcharon/encoding/payloads/unknown_payload.h5
-rw-r--r--src/libcharon/encoding/payloads/vendor_id_payload.c37
-rw-r--r--src/libcharon/encoding/payloads/vendor_id_payload.h16
54 files changed, 5280 insertions, 1645 deletions
diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c
index 60fa7e0c4..2dfaf43df 100644
--- a/src/libcharon/encoding/generator.c
+++ b/src/libcharon/encoding/generator.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2011 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -108,6 +109,11 @@ struct private_generator_t {
* to hold the length of the transform attribute in bytes.
*/
u_int16_t attribute_length;
+
+ /**
+ * TRUE, if debug messages should be logged during generation.
+ */
+ bool debug;
};
/**
@@ -155,8 +161,11 @@ static void make_space_available(private_generator_t *this, int bits)
new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE;
out_position_offset = this->out_position - this->buffer;
- DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte",
- old_buffer_size, new_buffer_size);
+ if (this->debug)
+ {
+ DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte",
+ old_buffer_size, new_buffer_size);
+ }
this->buffer = realloc(this->buffer,new_buffer_size);
this->out_position = (this->buffer + out_position_offset);
@@ -205,7 +214,7 @@ static void generate_u_int_type(private_generator_t *this,
break;
case U_INT_16:
case PAYLOAD_LENGTH:
- case CONFIGURATION_ATTRIBUTE_LENGTH:
+ case ATTRIBUTE_LENGTH:
number_of_bits = 16;
break;
case U_INT_32:
@@ -244,7 +253,10 @@ static void generate_u_int_type(private_generator_t *this,
low = *(this->out_position) & 0x0F;
/* high is set, low_val is not changed */
*(this->out_position) = high | low;
- DBG3(DBG_ENC, " => %d", *(this->out_position));
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, " => %d", *(this->out_position));
+ }
/* write position is not changed, just bit position is moved */
this->current_bit = 4;
}
@@ -255,7 +267,10 @@ static void generate_u_int_type(private_generator_t *this,
/* low of current byte in buffer has to be set to the new value*/
low = *((u_int8_t *)(this->data_struct + offset)) & 0x0F;
*(this->out_position) = high | low;
- DBG3(DBG_ENC, " => %d", *(this->out_position));
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, " => %d", *(this->out_position));
+ }
this->out_position++;
this->current_bit = 0;
}
@@ -274,7 +289,10 @@ static void generate_u_int_type(private_generator_t *this,
{
/* 8 bit values are written as they are */
*this->out_position = *((u_int8_t *)(this->data_struct + offset));
- DBG3(DBG_ENC, " => %d", *(this->out_position));
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, " => %d", *(this->out_position));
+ }
this->out_position++;
break;
}
@@ -299,7 +317,10 @@ static void generate_u_int_type(private_generator_t *this,
val |= 0x8000;
}
val = htons(val);
- DBG3(DBG_ENC, " => %d", val);
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, " => %d", val);
+ }
/* write bytes to buffer (set bit is overwritten) */
write_bytes_to_buffer(this, &val, sizeof(u_int16_t));
this->current_bit = 0;
@@ -308,17 +329,23 @@ static void generate_u_int_type(private_generator_t *this,
}
case U_INT_16:
case PAYLOAD_LENGTH:
- case CONFIGURATION_ATTRIBUTE_LENGTH:
+ case ATTRIBUTE_LENGTH:
{
u_int16_t val = htons(*((u_int16_t*)(this->data_struct + offset)));
- DBG3(DBG_ENC, " => %b", &val, sizeof(u_int16_t));
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, " %b", &val, sizeof(u_int16_t));
+ }
write_bytes_to_buffer(this, &val, sizeof(u_int16_t));
break;
}
case U_INT_32:
{
u_int32_t val = htonl(*((u_int32_t*)(this->data_struct + offset)));
- DBG3(DBG_ENC, " => %b", &val, sizeof(u_int32_t));
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, " %b", &val, sizeof(u_int32_t));
+ }
write_bytes_to_buffer(this, &val, sizeof(u_int32_t));
break;
}
@@ -327,8 +354,11 @@ static void generate_u_int_type(private_generator_t *this,
/* 64 bit are written as-is, no host order conversion */
write_bytes_to_buffer(this, this->data_struct + offset,
sizeof(u_int64_t));
- DBG3(DBG_ENC, " => %b", this->data_struct + offset,
- sizeof(u_int64_t));
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, " %b", this->data_struct + offset,
+ sizeof(u_int64_t));
+ }
break;
}
default:
@@ -361,7 +391,10 @@ static void generate_flag(private_generator_t *this, u_int32_t offset)
}
*(this->out_position) = *(this->out_position) | flag;
- DBG3(DBG_ENC, " => %d", *this->out_position);
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, " => %d", *this->out_position);
+ }
this->current_bit++;
if (this->current_bit >= 8)
@@ -380,12 +413,16 @@ static void generate_from_chunk(private_generator_t *this, u_int32_t offset)
if (this->current_bit != 0)
{
- DBG1(DBG_ENC, "can not generate a chunk at Bitpos %d", this->current_bit);
+ DBG1(DBG_ENC, "can not generate a chunk at bitpos %d",
+ this->current_bit);
return ;
}
value = (chunk_t *)(this->data_struct + offset);
- DBG3(DBG_ENC, " => %B", value);
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, " %B", value);
+ }
write_bytes_to_buffer(this, value->ptr, value->len);
}
@@ -397,15 +434,17 @@ METHOD(generator_t, get_chunk, chunk_t,
*lenpos = (u_int32_t*)(this->buffer + this->header_length_offset);
data = chunk_create(this->buffer, get_length(this));
- DBG3(DBG_ENC, "generated data of this generator %B", &data);
+ if (this->debug)
+ {
+ DBG3(DBG_ENC, "generated data of this generator %B", &data);
+ }
return data;
}
METHOD(generator_t, generate_payload, void,
- private_generator_t *this,payload_t *payload)
+ private_generator_t *this, payload_t *payload)
{
- int i, offset_start;
- size_t rule_count;
+ int i, offset_start, rule_count;
encoding_rule_t *rules;
payload_type_t payload_type;
@@ -414,17 +453,23 @@ METHOD(generator_t, generate_payload, void,
offset_start = this->out_position - this->buffer;
- DBG2(DBG_ENC, "generating payload of type %N",
- payload_type_names, payload_type);
+ if (this->debug)
+ {
+ DBG2(DBG_ENC, "generating payload of type %N",
+ payload_type_names, payload_type);
+ }
/* each payload has its own encoding rules */
- payload->get_encoding_rules(payload, &rules, &rule_count);
+ rule_count = payload->get_encoding_rules(payload, &rules);
for (i = 0; i < rule_count;i++)
{
- DBG2(DBG_ENC, " generating rule %d %N",
- i, encoding_type_names, rules[i].type);
- switch (rules[i].type)
+ if (this->debug)
+ {
+ DBG2(DBG_ENC, " generating rule %d %N",
+ i, encoding_type_names, rules[i].type);
+ }
+ switch ((int)rules[i].type)
{
case U_INT_4:
case U_INT_8:
@@ -436,7 +481,7 @@ METHOD(generator_t, generate_payload, void,
case SPI_SIZE:
case TS_TYPE:
case ATTRIBUTE_TYPE:
- case CONFIGURATION_ATTRIBUTE_LENGTH:
+ case ATTRIBUTE_LENGTH:
generate_u_int_type(this, rules[i].type, rules[i].offset);
break;
case RESERVED_BIT:
@@ -449,26 +494,19 @@ METHOD(generator_t, generate_payload, void,
break;
case ADDRESS:
case SPI:
- case KEY_EXCHANGE_DATA:
- case NOTIFICATION_DATA:
- case NONCE_DATA:
- case ID_DATA:
- case AUTH_DATA:
- case CERT_DATA:
- case CERTREQ_DATA:
- case SPIS:
- case CONFIGURATION_ATTRIBUTE_VALUE:
- case VID_DATA:
- case EAP_DATA:
+ case CHUNK_DATA:
case ENCRYPTED_DATA:
- case UNKNOWN_DATA:
generate_from_chunk(this, rules[i].offset);
break;
- case PROPOSALS:
- case TRANSFORMS:
- case TRANSFORM_ATTRIBUTES:
- case CONFIGURATION_ATTRIBUTES:
- case TRAFFIC_SELECTORS:
+ case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE:
+ case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1:
+ case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE:
+ case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1:
+ case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE:
+ case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1:
+ case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE:
+ case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1:
+ case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE:
{
linked_list_t *proposals;
enumerator_t *enumerator;
@@ -507,7 +545,10 @@ METHOD(generator_t, generate_payload, void,
{
if (!this->attribute_format)
{
- DBG2(DBG_ENC, "attribute value has not fixed size");
+ if (this->debug)
+ {
+ DBG2(DBG_ENC, "attribute value has not fixed size");
+ }
/* the attribute value is generated */
generate_from_chunk(this, rules[i].offset);
}
@@ -519,11 +560,14 @@ METHOD(generator_t, generate_payload, void,
return;
}
}
- DBG2(DBG_ENC, "generating %N payload finished",
- payload_type_names, payload_type);
- DBG3(DBG_ENC, "generated data for this payload %b",
- this->buffer + offset_start,
- (u_int)(this->out_position - this->buffer - offset_start));
+ if (this->debug)
+ {
+ DBG2(DBG_ENC, "generating %N payload finished",
+ payload_type_names, payload_type);
+ DBG3(DBG_ENC, "generated data for this payload %b",
+ this->buffer + offset_start,
+ (u_int)(this->out_position - this->buffer - offset_start));
+ }
}
METHOD(generator_t, destroy, void,
@@ -547,6 +591,7 @@ generator_t *generator_create()
.destroy = _destroy,
},
.buffer = malloc(GENERATOR_DATA_BUFFER_SIZE),
+ .debug = TRUE,
);
this->out_position = this->buffer;
@@ -555,3 +600,14 @@ generator_t *generator_create()
return &this->public;
}
+/*
+ * Described in header
+ */
+generator_t *generator_create_no_dbg()
+{
+ private_generator_t *this = (private_generator_t*)generator_create();
+
+ this->debug = FALSE;
+
+ return &this->public;
+}
diff --git a/src/libcharon/encoding/generator.h b/src/libcharon/encoding/generator.h
index fe561fdfd..c2c0aad2a 100644
--- a/src/libcharon/encoding/generator.h
+++ b/src/libcharon/encoding/generator.h
@@ -72,4 +72,12 @@ struct generator_t {
*/
generator_t *generator_create(void);
+/**
+ * Constructor to create a generator that does not log any debug messages > 1.
+ *
+ * @return generator_t object.
+ */
+generator_t *generator_create_no_dbg(void);
+
+
#endif /** GENERATOR_H_ @}*/
diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c
index 2b5399294..d3b72ea95 100644
--- a/src/libcharon/encoding/message.c
+++ b/src/libcharon/encoding/message.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006-2011 Tobias Brunner
* Copyright (C) 2005-2010 Martin Willi
* Copyright (C) 2010 revosec AG
* Copyright (C) 2006 Daniel Roethlisberger
@@ -24,37 +24,47 @@
#include <library.h>
#include <daemon.h>
-#include <sa/ike_sa_id.h>
+#include <sa/ikev1/keymat_v1.h>
#include <encoding/generator.h>
#include <encoding/parser.h>
-#include <utils/linked_list.h>
#include <encoding/payloads/encodings.h>
#include <encoding/payloads/payload.h>
+#include <encoding/payloads/hash_payload.h>
#include <encoding/payloads/encryption_payload.h>
#include <encoding/payloads/unknown_payload.h>
#include <encoding/payloads/cp_payload.h>
/**
- * Max number of notify payloads per IKEv2 Message
+ * Max number of notify payloads per IKEv2 message
*/
#define MAX_NOTIFY_PAYLOADS 20
/**
- * Max number of delete payloads per IKEv2 Message
+ * Max number of delete payloads per IKEv2 message
*/
#define MAX_DELETE_PAYLOADS 20
/**
- * Max number of certificate payloads per IKEv2 Message
+ * Max number of certificate payloads per IKEv2 message
*/
#define MAX_CERT_PAYLOADS 8
/**
- * Max number of Vendor ID payloads per IKEv2 Message
+ * Max number of vendor ID payloads per IKEv2 message
*/
#define MAX_VID_PAYLOADS 20
/**
+ * Max number of certificate request payloads per IKEv1 message
+ */
+#define MAX_CERTREQ_PAYLOADS 5
+
+/**
+ * Max number of NAT-D payloads per IKEv1 message
+ */
+#define MAX_NAT_D_PAYLOADS 5
+
+/**
* A payload rule defines the rules for a payload
* in a specific message rule. It defines if and how
* many times a payload must/can occur in a message
@@ -414,6 +424,273 @@ static payload_order_t me_connect_r_order[] = {
};
#endif /* ME */
+#ifdef USE_IKEV1
+/**
+ * Message rule for ID_PROT from initiator.
+ */
+static payload_rule_t id_prot_i_rules[] = {
+/* payload type min max encr suff */
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE},
+ {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE},
+ {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE},
+ {NONCE_V1, 0, 1, FALSE, FALSE},
+ {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE},
+ {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE},
+ {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE},
+ {ID_V1, 0, 1, TRUE, FALSE},
+ {CERTIFICATE_V1, 0, 2, TRUE, FALSE},
+ {SIGNATURE_V1, 0, 1, TRUE, FALSE},
+ {HASH_V1, 0, 1, TRUE, FALSE},
+};
+
+/**
+ * payload order for ID_PROT from initiator.
+ */
+static payload_order_t id_prot_i_order[] = {
+/* payload type notify type */
+ {SECURITY_ASSOCIATION_V1, 0},
+ {KEY_EXCHANGE_V1, 0},
+ {NONCE_V1, 0},
+ {ID_V1, 0},
+ {CERTIFICATE_V1, 0},
+ {SIGNATURE_V1, 0},
+ {HASH_V1, 0},
+ {CERTIFICATE_REQUEST_V1, 0},
+ {NOTIFY_V1, 0},
+ {VENDOR_ID_V1, 0},
+ {NAT_D_V1, 0},
+};
+
+/**
+ * Message rule for ID_PROT from responder.
+ */
+static payload_rule_t id_prot_r_rules[] = {
+/* payload type min max encr suff */
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE},
+ {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE},
+ {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE},
+ {NONCE_V1, 0, 1, FALSE, FALSE},
+ {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE},
+ {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE},
+ {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE},
+ {ID_V1, 0, 1, TRUE, FALSE},
+ {CERTIFICATE_V1, 0, 2, TRUE, FALSE},
+ {SIGNATURE_V1, 0, 1, TRUE, FALSE},
+ {HASH_V1, 0, 1, TRUE, FALSE},
+};
+
+/**
+ * payload order for ID_PROT from responder.
+ */
+static payload_order_t id_prot_r_order[] = {
+/* payload type notify type */
+ {SECURITY_ASSOCIATION_V1, 0},
+ {KEY_EXCHANGE_V1, 0},
+ {NONCE_V1, 0},
+ {ID_V1, 0},
+ {CERTIFICATE_V1, 0},
+ {SIGNATURE_V1, 0},
+ {HASH_V1, 0},
+ {CERTIFICATE_REQUEST_V1, 0},
+ {NOTIFY_V1, 0},
+ {VENDOR_ID_V1, 0},
+ {NAT_D_V1, 0},
+};
+
+/**
+ * Message rule for AGGRESSIVE from initiator.
+ */
+static payload_rule_t aggressive_i_rules[] = {
+/* payload type min max encr suff */
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE},
+ {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE},
+ {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE},
+ {NONCE_V1, 0, 1, FALSE, FALSE},
+ {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE},
+ {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE},
+ {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE},
+ {ID_V1, 0, 1, FALSE, FALSE},
+ {CERTIFICATE_V1, 0, 1, TRUE, FALSE},
+ {SIGNATURE_V1, 0, 1, TRUE, FALSE},
+ {HASH_V1, 0, 1, TRUE, FALSE},
+};
+
+/**
+ * payload order for AGGRESSIVE from initiator.
+ */
+static payload_order_t aggressive_i_order[] = {
+/* payload type notify type */
+ {SECURITY_ASSOCIATION_V1, 0},
+ {KEY_EXCHANGE_V1, 0},
+ {NONCE_V1, 0},
+ {ID_V1, 0},
+ {CERTIFICATE_V1, 0},
+ {NAT_D_V1, 0},
+ {SIGNATURE_V1, 0},
+ {HASH_V1, 0},
+ {CERTIFICATE_REQUEST_V1, 0},
+ {NOTIFY_V1, 0},
+ {VENDOR_ID_V1, 0},
+};
+
+/**
+ * Message rule for AGGRESSIVE from responder.
+ */
+static payload_rule_t aggressive_r_rules[] = {
+/* payload type min max encr suff */
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE},
+ {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE},
+ {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE},
+ {NONCE_V1, 0, 1, FALSE, FALSE},
+ {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE},
+ {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE},
+ {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE},
+ {ID_V1, 0, 1, FALSE, FALSE},
+ {CERTIFICATE_V1, 0, 1, FALSE, FALSE},
+ {SIGNATURE_V1, 0, 1, FALSE, FALSE},
+ {HASH_V1, 0, 1, FALSE, FALSE},
+};
+
+/**
+ * payload order for AGGRESSIVE from responder.
+ */
+static payload_order_t aggressive_r_order[] = {
+/* payload type notify type */
+ {SECURITY_ASSOCIATION_V1, 0},
+ {KEY_EXCHANGE_V1, 0},
+ {NONCE_V1, 0},
+ {ID_V1, 0},
+ {CERTIFICATE_V1, 0},
+ {NAT_D_V1, 0},
+ {SIGNATURE_V1, 0},
+ {HASH_V1, 0},
+ {CERTIFICATE_REQUEST_V1, 0},
+ {NOTIFY_V1, 0},
+ {VENDOR_ID_V1, 0},
+};
+
+/**
+ * Message rule for INFORMATIONAL_V1 from initiator.
+ */
+static payload_rule_t informational_i_rules_v1[] = {
+/* payload type min max encr suff */
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE},
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE},
+ {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE},
+ {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE},
+};
+
+/**
+ * payload order for INFORMATIONAL_V1 from initiator.
+ */
+static payload_order_t informational_i_order_v1[] = {
+/* payload type notify type */
+ {NOTIFY_V1, 0},
+ {DELETE_V1, 0},
+ {VENDOR_ID_V1, 0},
+};
+
+/**
+ * Message rule for INFORMATIONAL_V1 from responder.
+ */
+static payload_rule_t informational_r_rules_v1[] = {
+/* payload type min max encr suff */
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE},
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE},
+ {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE},
+ {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE},
+};
+
+/**
+ * payload order for INFORMATIONAL_V1 from responder.
+ */
+static payload_order_t informational_r_order_v1[] = {
+/* payload type notify type */
+ {NOTIFY_V1, 0},
+ {DELETE_V1, 0},
+ {VENDOR_ID_V1, 0},
+};
+
+/**
+ * Message rule for QUICK_MODE from initiator.
+ */
+static payload_rule_t quick_mode_i_rules[] = {
+/* payload type min max encr suff */
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE},
+ {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE},
+ {HASH_V1, 0, 1, TRUE, FALSE},
+ {SECURITY_ASSOCIATION_V1, 0, 2, TRUE, FALSE},
+ {NONCE_V1, 0, 1, TRUE, FALSE},
+ {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE},
+ {ID_V1, 0, 2, TRUE, FALSE},
+ {NAT_OA_V1, 0, 2, TRUE, FALSE},
+};
+
+/**
+ * payload order for QUICK_MODE from initiator.
+ */
+static payload_order_t quick_mode_i_order[] = {
+/* payload type notify type */
+ {NOTIFY_V1, 0},
+ {VENDOR_ID_V1, 0},
+ {HASH_V1, 0},
+ {SECURITY_ASSOCIATION_V1, 0},
+ {NONCE_V1, 0},
+ {KEY_EXCHANGE_V1, 0},
+ {ID_V1, 0},
+ {NAT_OA_V1, 0},
+};
+
+/**
+ * Message rule for QUICK_MODE from responder.
+ */
+static payload_rule_t quick_mode_r_rules[] = {
+/* payload type min max encr suff */
+ {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE},
+ {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE},
+ {HASH_V1, 0, 1, TRUE, FALSE},
+ {SECURITY_ASSOCIATION_V1, 0, 2, TRUE, FALSE},
+ {NONCE_V1, 0, 1, TRUE, FALSE},
+ {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE},
+ {ID_V1, 0, 2, TRUE, FALSE},
+ {NAT_OA_V1, 0, 2, TRUE, FALSE},
+};
+
+/**
+ * payload order for QUICK_MODE from responder.
+ */
+static payload_order_t quick_mode_r_order[] = {
+/* payload type notify type */
+ {NOTIFY_V1, 0},
+ {VENDOR_ID_V1, 0},
+ {HASH_V1, 0},
+ {SECURITY_ASSOCIATION_V1, 0},
+ {NONCE_V1, 0},
+ {KEY_EXCHANGE_V1, 0},
+ {ID_V1, 0},
+ {NAT_OA_V1, 0},
+};
+
+/**
+ * Message rule for TRANSACTION.
+ */
+static payload_rule_t transaction_payload_rules_v1[] = {
+/* payload type min max encr suff */
+ {HASH_V1, 0, 1, TRUE, FALSE},
+ {CONFIGURATION_V1, 1, 1, FALSE, FALSE},
+};
+
+/**
+ * Payload order for TRANSACTION.
+ */
+static payload_order_t transaction_payload_order_v1[] = {
+/* payload type notify type */
+ {HASH_V1, 0},
+ {CONFIGURATION_V1, 0},
+};
+
+#endif /* USE_IKEV1 */
+
/**
* Message rules, defines allowed payloads.
*/
@@ -460,6 +737,49 @@ static message_rule_t message_rules[] = {
countof(me_connect_r_order), me_connect_r_order,
},
#endif /* ME */
+#ifdef USE_IKEV1
+ {ID_PROT, TRUE, FALSE,
+ countof(id_prot_i_rules), id_prot_i_rules,
+ countof(id_prot_i_order), id_prot_i_order,
+ },
+ {ID_PROT, FALSE, FALSE,
+ countof(id_prot_r_rules), id_prot_r_rules,
+ countof(id_prot_r_order), id_prot_r_order,
+ },
+ {AGGRESSIVE, TRUE, FALSE,
+ countof(aggressive_i_rules), aggressive_i_rules,
+ countof(aggressive_i_order), aggressive_i_order,
+ },
+ {AGGRESSIVE, FALSE, FALSE,
+ countof(aggressive_r_rules), aggressive_r_rules,
+ countof(aggressive_r_order), aggressive_r_order,
+ },
+ {INFORMATIONAL_V1, TRUE, TRUE,
+ countof(informational_i_rules_v1), informational_i_rules_v1,
+ countof(informational_i_order_v1), informational_i_order_v1,
+ },
+ {INFORMATIONAL_V1, FALSE, TRUE,
+ countof(informational_r_rules_v1), informational_r_rules_v1,
+ countof(informational_r_order_v1), informational_r_order_v1,
+ },
+ {QUICK_MODE, TRUE, TRUE,
+ countof(quick_mode_i_rules), quick_mode_i_rules,
+ countof(quick_mode_i_order), quick_mode_i_order,
+ },
+ {QUICK_MODE, FALSE, TRUE,
+ countof(quick_mode_r_rules), quick_mode_r_rules,
+ countof(quick_mode_r_order), quick_mode_r_order,
+ },
+ {TRANSACTION, TRUE, TRUE,
+ countof(transaction_payload_rules_v1), transaction_payload_rules_v1,
+ countof(transaction_payload_order_v1), transaction_payload_order_v1,
+ },
+ {TRANSACTION, FALSE, TRUE,
+ countof(transaction_payload_rules_v1), transaction_payload_rules_v1,
+ countof(transaction_payload_order_v1), transaction_payload_order_v1,
+ },
+ /* TODO-IKEv1: define rules for other exchanges */
+#endif /* USE_IKEV1 */
};
@@ -501,6 +821,11 @@ struct private_message_t {
bool is_request;
/**
+ * The message is encrypted (IKEv1)
+ */
+ bool is_encrypted;
+
+ /**
* Higher version supported?
*/
bool version_flag;
@@ -508,7 +833,7 @@ struct private_message_t {
/**
* Reserved bits in IKE header
*/
- bool reserved[5];
+ bool reserved[2];
/**
* Sorting of message disabled?
@@ -739,7 +1064,14 @@ METHOD(message_t, add_notify, void,
payload->destroy(payload);
}
}
- notify = notify_payload_create();
+ if (this->major_version == IKEV2_MAJOR_VERSION)
+ {
+ notify = notify_payload_create(NOTIFY);
+ }
+ else
+ {
+ notify = notify_payload_create(NOTIFY_V1);
+ }
notify->set_notify_type(notify, type);
notify->set_notification_data(notify, data);
add_payload(this, (payload_t*)notify);
@@ -810,7 +1142,8 @@ METHOD(message_t, get_notify, notify_payload_t*,
enumerator = create_payload_enumerator(this);
while (enumerator->enumerate(enumerator, &payload))
{
- if (payload->get_type(payload) == NOTIFY)
+ if (payload->get_type(payload) == NOTIFY ||
+ payload->get_type(payload) == NOTIFY_V1)
{
notify = (notify_payload_t*)payload;
if (notify->get_notify_type(notify) == type)
@@ -837,7 +1170,7 @@ static char* get_string(private_message_t *this, char *buf, int len)
memset(buf, 0, len);
len--;
- written = snprintf(pos, len, "%N %s %d [",
+ written = snprintf(pos, len, "%N %s %u [",
exchange_type_names, this->exchange_type,
this->is_request ? "request" : "response",
this->message_id);
@@ -859,7 +1192,8 @@ static char* get_string(private_message_t *this, char *buf, int len)
}
pos += written;
len -= written;
- if (payload->get_type(payload) == NOTIFY)
+ if (payload->get_type(payload) == NOTIFY ||
+ payload->get_type(payload) == NOTIFY_V1)
{
notify_payload_t *notify;
notify_type_t type;
@@ -1017,7 +1351,7 @@ static void order_payloads(private_message_t *this)
}
/**
- * Wrap payloads in a encryption payload
+ * Wrap payloads in an encryption payload
*/
static encryption_payload_t* wrap_payloads(private_message_t *this)
{
@@ -1033,7 +1367,14 @@ static encryption_payload_t* wrap_payloads(private_message_t *this)
payloads->insert_last(payloads, current);
}
- encryption = encryption_payload_create();
+ if (this->is_encrypted)
+ {
+ encryption = encryption_payload_create(ENCRYPTED_V1);
+ }
+ else
+ {
+ encryption = encryption_payload_create(ENCRYPTED);
+ }
while (payloads->remove_first(payloads, (void**)&current) == SUCCESS)
{
payload_rule_t *rule;
@@ -1046,8 +1387,8 @@ static encryption_payload_t* wrap_payloads(private_message_t *this)
{
encrypt = rule->encrypted;
}
- if (encrypt)
- {
+ if (encrypt || this->is_encrypted)
+ { /* encryption is forced for IKEv1 */
DBG2(DBG_ENC, "insert payload %N to encryption payload",
payload_type_names, type);
encryption->add_payload(encryption, current);
@@ -1071,17 +1412,20 @@ METHOD(message_t, disable_sort, void,
}
METHOD(message_t, generate, status_t,
- private_message_t *this, aead_t *aead, packet_t **packet)
+ private_message_t *this, keymat_t *keymat, packet_t **packet)
{
+ keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat;
generator_t *generator;
ike_header_t *ike_header;
payload_t *payload, *next;
encryption_payload_t *encryption = NULL;
+ payload_type_t next_type;
enumerator_t *enumerator;
- chunk_t chunk;
+ aead_t *aead = NULL;
+ chunk_t chunk, hash = chunk_empty;
char str[BUF_LEN];
u_int32_t *lenpos;
- bool *reserved;
+ bool encrypted = FALSE, *reserved;
int i;
if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED)
@@ -1108,27 +1452,77 @@ METHOD(message_t, generate, status_t,
{
order_payloads(this);
}
+ if (keymat && keymat->get_version(keymat) == IKEV1)
+ {
+ /* get a hash for this message, if any is required */
+ if (keymat_v1->get_hash_phase2(keymat_v1, &this->public, &hash))
+ { /* insert a HASH payload as first payload */
+ hash_payload_t *hash_payload;
+
+ hash_payload = hash_payload_create(HASH_V1);
+ hash_payload->set_hash(hash_payload, hash);
+ this->payloads->insert_first(this->payloads, hash_payload);
+ if (this->exchange_type == INFORMATIONAL_V1)
+ {
+ this->is_encrypted = encrypted = TRUE;
+ }
+ chunk_free(&hash);
+ }
+ }
+ if (this->major_version == IKEV2_MAJOR_VERSION)
+ {
+ encrypted = this->rule->encrypted;
+ }
+ else if (!encrypted)
+ {
+ /* If at least one payload requires encryption, encrypt the message.
+ * If no key material is available, the flag will be reset below. */
+ enumerator = this->payloads->create_enumerator(this->payloads);
+ while (enumerator->enumerate(enumerator, (void**)&payload))
+ {
+ payload_rule_t *rule;
+
+ rule = get_payload_rule(this, payload->get_type(payload));
+ if (rule && rule->encrypted)
+ {
+ this->is_encrypted = encrypted = TRUE;
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+ }
DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str)));
- if (aead && this->rule->encrypted)
+ if (keymat)
+ {
+ aead = keymat->get_aead(keymat, FALSE);
+ }
+ if (aead && encrypted)
{
encryption = wrap_payloads(this);
}
else
{
DBG2(DBG_ENC, "not encrypting payloads");
+ this->is_encrypted = FALSE;
}
- ike_header = ike_header_create();
- ike_header->set_maj_version(ike_header, this->major_version);
- ike_header->set_min_version(ike_header, this->minor_version);
+ ike_header = ike_header_create_version(this->major_version,
+ this->minor_version);
ike_header->set_exchange_type(ike_header, this->exchange_type);
ike_header->set_message_id(ike_header, this->message_id);
- ike_header->set_response_flag(ike_header, !this->is_request);
- ike_header->set_version_flag(ike_header, this->version_flag);
- ike_header->set_initiator_flag(ike_header,
+ if (this->major_version == IKEV2_MAJOR_VERSION)
+ {
+ ike_header->set_response_flag(ike_header, !this->is_request);
+ ike_header->set_version_flag(ike_header, this->version_flag);
+ ike_header->set_initiator_flag(ike_header,
this->ike_sa_id->is_initiator(this->ike_sa_id));
+ }
+ else
+ {
+ ike_header->set_encryption_flag(ike_header, this->is_encrypted);
+ }
ike_header->set_initiator_spi(ike_header,
this->ike_sa_id->get_initiator_spi(this->ike_sa_id));
ike_header->set_responder_spi(ike_header,
@@ -1156,22 +1550,38 @@ METHOD(message_t, generate, status_t,
payload = next;
}
enumerator->destroy(enumerator);
- payload->set_next_type(payload, encryption ? ENCRYPTED : NO_PAYLOAD);
+ if (this->is_encrypted)
+ { /* for encrypted IKEv1 messages */
+ next_type = encryption->payload_interface.get_next_type(
+ (payload_t*)encryption);
+ }
+ else
+ {
+ next_type = encryption ? ENCRYPTED : NO_PAYLOAD;
+ }
+ payload->set_next_type(payload, next_type);
generator->generate_payload(generator, payload);
ike_header->destroy(ike_header);
if (encryption)
- {
- u_int32_t *lenpos;
-
- /* build associated data (without header of encryption payload) */
- chunk = generator->get_chunk(generator, &lenpos);
+ { /* set_transform() has to be called before get_length() */
encryption->set_transform(encryption, aead);
- /* fill in length, including encryption payload */
- htoun32(lenpos, chunk.len + encryption->get_length(encryption));
-
+ if (this->is_encrypted)
+ { /* for IKEv1 instead of associated data we provide the IV */
+ if (!keymat_v1->get_iv(keymat_v1, this->message_id, &chunk))
+ {
+ generator->destroy(generator);
+ return FAILED;
+ }
+ }
+ else
+ { /* build associated data (without header of encryption payload) */
+ chunk = generator->get_chunk(generator, &lenpos);
+ /* fill in length, including encryption payload */
+ htoun32(lenpos, chunk.len + encryption->get_length(encryption));
+ }
this->payloads->insert_last(this->payloads, encryption);
- if (!encryption->encrypt(encryption, chunk))
+ if (encryption->encrypt(encryption, chunk) != SUCCESS)
{
generator->destroy(generator);
return INVALID_STATE;
@@ -1181,8 +1591,22 @@ METHOD(message_t, generate, status_t,
chunk = generator->get_chunk(generator, &lenpos);
htoun32(lenpos, chunk.len);
this->packet->set_data(this->packet, chunk_clone(chunk));
+ if (this->is_encrypted)
+ {
+ /* update the IV for the next IKEv1 message */
+ chunk_t last_block;
+ size_t bs;
+
+ bs = aead->get_block_size(aead);
+ last_block = chunk_create(chunk.ptr + chunk.len - bs, bs);
+ if (!keymat_v1->update_iv(keymat_v1, this->message_id, last_block) ||
+ !keymat_v1->confirm_iv(keymat_v1, this->message_id))
+ {
+ generator->destroy(generator);
+ return FAILED;
+ }
+ }
generator->destroy(generator);
-
*packet = this->packet->clone(this->packet);
return SUCCESS;
}
@@ -1204,7 +1628,7 @@ METHOD(message_t, get_packet_data, chunk_t,
{
return chunk_empty;
}
- return chunk_clone(this->packet->get_data(this->packet));
+ return this->packet->get_data(this->packet);
}
METHOD(message_t, parse_header, status_t,
@@ -1237,15 +1661,24 @@ METHOD(message_t, parse_header, status_t,
}
DESTROY_IF(this->ike_sa_id);
- this->ike_sa_id = ike_sa_id_create(ike_header->get_initiator_spi(ike_header),
+ this->ike_sa_id = ike_sa_id_create(
+ ike_header->get_maj_version(ike_header),
+ ike_header->get_initiator_spi(ike_header),
ike_header->get_responder_spi(ike_header),
ike_header->get_initiator_flag(ike_header));
this->exchange_type = ike_header->get_exchange_type(ike_header);
this->message_id = ike_header->get_message_id(ike_header);
- this->is_request = !ike_header->get_response_flag(ike_header);
this->major_version = ike_header->get_maj_version(ike_header);
this->minor_version = ike_header->get_min_version(ike_header);
+ if (this->major_version == IKEV2_MAJOR_VERSION)
+ {
+ this->is_request = !ike_header->get_response_flag(ike_header);
+ }
+ else
+ {
+ this->is_encrypted = ike_header->get_encryption_flag(ike_header);
+ }
this->first_payload = ike_header->payload_interface.get_next_type(
&ike_header->payload_interface);
for (i = 0; i < countof(this->reserved); i++)
@@ -1257,19 +1690,12 @@ METHOD(message_t, parse_header, status_t,
this->reserved[i] = *reserved;
}
}
- DBG2(DBG_ENC, "parsed a %N %s", exchange_type_names, this->exchange_type,
- this->is_request ? "request" : "response");
-
ike_header->destroy(ike_header);
- this->rule = get_message_rule(this);
- if (!this->rule)
- {
- DBG1(DBG_ENC, "no message rules specified for a %N %s",
- exchange_type_names, this->exchange_type,
- this->is_request ? "request" : "response");
- }
- return status;
+ DBG2(DBG_ENC, "parsed a %N %s header", exchange_type_names,
+ this->exchange_type, this->major_version == IKEV1_MAJOR_VERSION ?
+ "message" : (this->is_request ? "request" : "response"));
+ return SUCCESS;
}
/**
@@ -1298,15 +1724,83 @@ static bool is_connectivity_check(private_message_t *this, payload_t *payload)
}
/**
+ * Parses and verifies the unencrypted payloads contained in the message
+ */
+static status_t parse_payloads(private_message_t *this)
+{
+ payload_type_t type = this->first_payload;
+ payload_t *payload;
+ status_t status;
+
+ if (this->is_encrypted)
+ { /* wrap the whole encrypted IKEv1 message in a special encryption
+ * payload which is then handled just like a regular payload */
+ encryption_payload_t *encryption;
+
+ status = this->parser->parse_payload(this->parser, ENCRYPTED_V1,
+ (payload_t**)&encryption);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "failed to wrap encrypted IKEv1 message");
+ return PARSE_ERROR;
+ }
+ encryption->payload_interface.set_next_type((payload_t*)encryption,
+ this->first_payload);
+ this->payloads->insert_last(this->payloads, encryption);
+ return SUCCESS;
+ }
+
+ while (type != NO_PAYLOAD)
+ {
+ DBG2(DBG_ENC, "starting parsing a %N payload",
+ payload_type_names, type);
+
+ status = this->parser->parse_payload(this->parser, type, &payload);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "payload type %N could not be parsed",
+ payload_type_names, type);
+ return PARSE_ERROR;
+ }
+
+ DBG2(DBG_ENC, "verifying payload of type %N", payload_type_names, type);
+ status = payload->verify(payload);
+ if (status != SUCCESS)
+ {
+ DBG1(DBG_ENC, "%N payload verification failed",
+ payload_type_names, type);
+ payload->destroy(payload);
+ return VERIFY_ERROR;
+ }
+
+ DBG2(DBG_ENC, "%N payload verified. Adding to payload list",
+ payload_type_names, type);
+ this->payloads->insert_last(this->payloads, payload);
+
+ /* an encryption payload is the last one, so STOP here. decryption is
+ * done later */
+ if (type == ENCRYPTED)
+ {
+ DBG2(DBG_ENC, "%N payload found. Stop parsing",
+ payload_type_names, type);
+ break;
+ }
+ type = payload->get_next_type(payload);
+ }
+ return SUCCESS;
+}
+
+/**
* Decrypt payload from the encryption payload
*/
-static status_t decrypt_payloads(private_message_t *this, aead_t *aead)
+static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat)
{
bool was_encrypted = FALSE;
payload_t *payload, *previous = NULL;
enumerator_t *enumerator;
payload_rule_t *rule;
payload_type_t type;
+ aead_t *aead;
status_t status = SUCCESS;
enumerator = this->payloads->create_enumerator(this->payloads);
@@ -1316,11 +1810,12 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead)
DBG2(DBG_ENC, "process payload of type %N", payload_type_names, type);
- if (type == ENCRYPTED)
+ if (type == ENCRYPTED || type == ENCRYPTED_V1)
{
encryption_payload_t *encryption;
payload_t *encrypted;
chunk_t chunk;
+ size_t bs;
encryption = (encryption_payload_t*)payload;
@@ -1332,16 +1827,57 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead)
status = VERIFY_ERROR;
break;
}
+ if (!keymat)
+ {
+ DBG1(DBG_ENC, "found encryption payload, but no keymat");
+ status = INVALID_ARG;
+ break;
+ }
+ aead = keymat->get_aead(keymat, TRUE);
+ if (!aead)
+ {
+ DBG1(DBG_ENC, "found encryption payload, but no transform set");
+ status = INVALID_ARG;
+ break;
+ }
+ bs = aead->get_block_size(aead);
encryption->set_transform(encryption, aead);
chunk = this->packet->get_data(this->packet);
- if (chunk.len < encryption->get_length(encryption))
+ if (chunk.len < encryption->get_length(encryption) ||
+ chunk.len < bs)
{
DBG1(DBG_ENC, "invalid payload length");
status = VERIFY_ERROR;
break;
}
- chunk.len -= encryption->get_length(encryption);
- status = encryption->decrypt(encryption, chunk);
+ if (keymat->get_version(keymat) == IKEV1)
+ { /* instead of associated data we provide the IV, we also update
+ * the IV with the last encrypted block */
+ keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat;
+ chunk_t iv;
+
+ if (keymat_v1->get_iv(keymat_v1, this->message_id, &iv))
+ {
+ status = encryption->decrypt(encryption, iv);
+ if (status == SUCCESS)
+ {
+ if (!keymat_v1->update_iv(keymat_v1, this->message_id,
+ chunk_create(chunk.ptr + chunk.len - bs, bs)))
+ {
+ status = FAILED;
+ }
+ }
+ }
+ else
+ {
+ status = FAILED;
+ }
+ }
+ else
+ {
+ chunk.len -= encryption->get_length(encryption);
+ status = encryption->decrypt(encryption, chunk);
+ }
if (status != SUCCESS)
{
break;
@@ -1369,7 +1905,8 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead)
encryption->destroy(encryption);
}
if (payload_is_known(type) && !was_encrypted &&
- !is_connectivity_check(this, payload))
+ !is_connectivity_check(this, payload) &&
+ this->exchange_type != AGGRESSIVE)
{
rule = get_payload_rule(this, type);
if (!rule || rule->encrypted)
@@ -1396,7 +1933,7 @@ static status_t verify(private_message_t *this)
DBG2(DBG_ENC, "verifying message structure");
- /* check for payloads with wrong count*/
+ /* check for payloads with wrong count */
for (i = 0; i < this->rule->rule_count; i++)
{
enumerator_t *enumerator;
@@ -1443,57 +1980,30 @@ static status_t verify(private_message_t *this)
}
METHOD(message_t, parse_body, status_t,
- private_message_t *this, aead_t *aead)
+ private_message_t *this, keymat_t *keymat)
{
status_t status = SUCCESS;
- payload_t *payload;
- payload_type_t type;
char str[BUF_LEN];
- type = this->first_payload;
-
DBG2(DBG_ENC, "parsing body of message, first payload is %N",
- payload_type_names, type);
+ payload_type_names, this->first_payload);
- while (type != NO_PAYLOAD)
+ this->rule = get_message_rule(this);
+ if (!this->rule)
{
- DBG2(DBG_ENC, "starting parsing a %N payload",
- payload_type_names, type);
-
- status = this->parser->parse_payload(this->parser, type, &payload);
- if (status != SUCCESS)
- {
- DBG1(DBG_ENC, "payload type %N could not be parsed",
- payload_type_names, type);
- return this->exchange_type == IKE_SA_INIT ? PARSE_ERROR : FAILED;
- }
-
- DBG2(DBG_ENC, "verifying payload of type %N", payload_type_names, type);
- status = payload->verify(payload);
- if (status != SUCCESS)
- {
- DBG1(DBG_ENC, "%N payload verification failed",
- payload_type_names, type);
- payload->destroy(payload);
- return this->exchange_type == IKE_SA_INIT ? VERIFY_ERROR : FAILED;
- }
-
- DBG2(DBG_ENC, "%N payload verified. Adding to payload list",
- payload_type_names, type);
- this->payloads->insert_last(this->payloads, payload);
+ DBG1(DBG_ENC, "no message rules specified for a %N %s",
+ exchange_type_names, this->exchange_type,
+ this->is_request ? "request" : "response");
+ return NOT_SUPPORTED;
+ }
- /* an encryption payload is the last one, so STOP here. decryption is
- * done later */
- if (type == ENCRYPTED)
- {
- DBG2(DBG_ENC, "%N payload found. Stop parsing",
- payload_type_names, type);
- break;
- }
- type = payload->get_next_type(payload);
+ status = parse_payloads(this);
+ if (status != SUCCESS)
+ { /* error is already logged */
+ return status;
}
- status = decrypt_payloads(this, aead);
+ status = decrypt_payloads(this, keymat);
if (status != SUCCESS)
{
DBG1(DBG_ENC, "could not decrypt payloads");
@@ -1508,6 +2018,50 @@ METHOD(message_t, parse_body, status_t,
DBG1(DBG_ENC, "parsed %s", get_string(this, str, sizeof(str)));
+ if (keymat && keymat->get_version(keymat) == IKEV1)
+ {
+ keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat;
+ chunk_t hash;
+
+ if (keymat_v1->get_hash_phase2(keymat_v1, &this->public, &hash))
+ {
+ hash_payload_t *hash_payload;
+ chunk_t other_hash;
+
+ if (this->first_payload != HASH_V1)
+ {
+ if (this->exchange_type == INFORMATIONAL_V1)
+ {
+ DBG1(DBG_ENC, "ignoring unprotected INFORMATIONAL from %H",
+ this->packet->get_source(this->packet));
+ }
+ else
+ {
+ DBG1(DBG_ENC, "expected HASH payload as first payload");
+ }
+ chunk_free(&hash);
+ return VERIFY_ERROR;
+ }
+ hash_payload = (hash_payload_t*)get_payload(this, HASH_V1);
+ other_hash = hash_payload->get_hash(hash_payload);
+ DBG3(DBG_ENC, "HASH received %B\nHASH expected %B",
+ &other_hash, &hash);
+ if (!chunk_equals(hash, other_hash))
+ {
+ DBG1(DBG_ENC, "received HASH payload does not match");
+ chunk_free(&hash);
+ return FAILED;
+ }
+ chunk_free(&hash);
+ }
+ if (this->is_encrypted)
+ { /* message verified, confirm IV */
+ if (!keymat_v1->confirm_iv(keymat_v1, this->message_id))
+ {
+ return FAILED;
+ }
+ }
+ }
return SUCCESS;
}
@@ -1522,7 +2076,7 @@ METHOD(message_t, destroy, void,
}
/*
- * Described in Header-File
+ * Described in header.
*/
message_t *message_create_from_packet(packet_t *packet)
{
@@ -1567,8 +2121,6 @@ message_t *message_create_from_packet(packet_t *packet)
.get_packet_data = _get_packet_data,
.destroy = _destroy,
},
- .major_version = IKE_MAJOR_VERSION,
- .minor_version = IKE_MINOR_VERSION,
.exchange_type = EXCHANGE_TYPE_UNDEFINED,
.is_request = TRUE,
.first_payload = NO_PAYLOAD,
@@ -1577,14 +2129,18 @@ message_t *message_create_from_packet(packet_t *packet)
.parser = parser_create(packet->get_data(packet)),
);
- return (&this->public);
+ return &this->public;
}
/*
- * Described in Header.
+ * Described in header.
*/
-message_t *message_create()
+message_t *message_create(int major, int minor)
{
- return message_create_from_packet(packet_create());
-}
+ message_t *this = message_create_from_packet(packet_create());
+ this->set_major_version(this, major);
+ this->set_minor_version(this, minor);
+
+ return this;
+}
diff --git a/src/libcharon/encoding/message.h b/src/libcharon/encoding/message.h
index 0e78ea436..6d558daf6 100644
--- a/src/libcharon/encoding/message.h
+++ b/src/libcharon/encoding/message.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006-2007 Tobias Brunner
+ * Copyright (C) 2006-2011 Tobias Brunner
* Copyright (C) 2005-2009 Martin Willi
* Copyright (C) 2006 Daniel Roethlisberger
* Copyright (C) 2005 Jan Hutter
@@ -27,15 +27,15 @@
typedef struct message_t message_t;
#include <library.h>
-#include <sa/ike_sa_id.h>
-#include <network/packet.h>
#include <encoding/payloads/ike_header.h>
#include <encoding/payloads/notify_payload.h>
+#include <sa/keymat.h>
+#include <sa/ike_sa_id.h>
+#include <utils/packet.h>
#include <utils/linked_list.h>
-#include <crypto/aead.h>
/**
- * This class is used to represent an IKEv2-Message.
+ * This class is used to represent an IKE-Message.
*
* The message handles parsing and generation of payloads
* via parser_t/generator_t. Encryption is done transparently
@@ -182,7 +182,7 @@ struct message_t {
* all payloads to encrypt are added to the encryption payload, which is
* always the last one.
*
- * @param payload payload to append
+ * @param payload payload to append
*/
void (*add_payload) (message_t *this, payload_t *payload);
@@ -208,14 +208,14 @@ struct message_t {
/**
* Parses header of message.
*
- * Begins parisng of a message created via message_create_from_packet().
+ * Begins parsing of a message created via message_create_from_packet().
* The parsing context is stored, so a subsequent call to parse_body()
* will continue the parsing process.
*
* @return
- * - SUCCESS if header could be parsed
+ * - SUCCESS if header could be parsed
* - PARSE_ERROR if corrupted/invalid data found
- * - FAILED if consistence check of header failed
+ * - FAILED if consistency check of header failed
*/
status_t (*parse_header) (message_t *this);
@@ -228,15 +228,15 @@ struct message_t {
* If there are encrypted payloads, they get decrypted and verified using
* the given aead transform (if given).
*
- * @param aead aead transform to verify/decrypt message
+ * @param keymat keymat to verify/decrypt message
* @return
- * - SUCCESS if parsing successful
+ * - SUCCESS if parsing successful
* - PARSE_ERROR if message parsing failed
- * - VERIFY_ERROR if message verification failed (bad syntax)
- * - FAILED if integrity check failed
- * - INVALID_STATE if aead not supplied, but needed
+ * - VERIFY_ERROR if message verification failed (bad syntax)
+ * - FAILED if integrity check failed
+ * - INVALID_STATE if aead not supplied, but needed
*/
- status_t (*parse_body) (message_t *this, aead_t *aead);
+ status_t (*parse_body) (message_t *this, keymat_t *keymat);
/**
* Generates the UDP packet of specific message.
@@ -247,15 +247,15 @@ struct message_t {
* Generation is only done once, multiple calls will just return a copy
* of the packet.
*
- * @param aead aead transform to encrypt/sign message
+ * @param keymat keymat to encrypt/sign message
* @param packet copy of generated packet
* @return
- * - SUCCESS if packet could be generated
- * - INVALID_STATE if exchange type is currently not set
- * - NOT_FOUND if no rules found for message generation
- * - INVALID_STATE if aead not supplied but needed.
+ * - SUCCESS if packet could be generated
+ * - INVALID_STATE if exchange type is currently not set
+ * - NOT_FOUND if no rules found for message generation
+ * - INVALID_STATE if aead not supplied but needed.
*/
- status_t (*generate) (message_t *this, aead_t *aead, packet_t **packet);
+ status_t (*generate) (message_t *this, keymat_t *keymat, packet_t **packet);
/**
* Check if the message has already been encoded using generate().
@@ -278,7 +278,7 @@ struct message_t {
* Sets the source host informations.
*
* @warning host_t object is not getting cloned and gets destroyed by
- * message_t.destroy or next call of message_t.set_source.
+ * message_t.destroy or next call of message_t.set_source.
*
* @param host host_t object representing source host
*/
@@ -298,7 +298,7 @@ struct message_t {
* Sets the destination host informations.
*
* @warning host_t object is not getting cloned and gets destroyed by
- * message_t.destroy or next call of message_t.set_destination.
+ * message_t.destroy or next call of message_t.set_destination.
*
* @param host host_t object representing destination host
*/
@@ -344,9 +344,9 @@ struct message_t {
packet_t * (*get_packet) (message_t *this);
/**
- * Returns a clone of the internal stored packet_t data.
+ * Returns a chunk pointing to internal packet_t data.
*
- * @return clone of the internal stored packet_t data.
+ * @return packet data.
*/
chunk_t (*get_packet_data) (message_t *this);
@@ -357,26 +357,27 @@ struct message_t {
};
/**
- * Creates an message_t object from a incoming UDP Packet.
+ * Creates a message_t object from an incoming UDP packet.
*
* The given packet gets owned by the message. The message is uninitialized,
* call parse_header() to populate header fields.
*
* @param packet packet_t object which is assigned to message
- * @return message_t object
+ * @return message_t object
*/
-message_t * message_create_from_packet(packet_t *packet);
-
+message_t *message_create_from_packet(packet_t *packet);
/**
- * Creates an empty message_t object.
+ * Creates an empty message_t object for a specific major/minor version.
*
* - exchange_type is set to NOT_SET
* - original_initiator is set to TRUE
* - is_request is set to TRUE
*
- * @return message_t object
+ * @param major major IKE version of this message
+ * @param minor minor IKE version of this message
+ * @return message_t object
*/
-message_t * message_create(void);
+message_t *message_create(int major, int minor);
#endif /** MESSAGE_H_ @}*/
diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c
index e49210309..e4b140c3e 100644
--- a/src/libcharon/encoding/parser.c
+++ b/src/libcharon/encoding/parser.c
@@ -137,7 +137,7 @@ static bool parse_uint4(private_parser_t *this, int rule_number,
}
if (output_pos)
{
- DBG3(DBG_ENC, " => %d", *output_pos);
+ DBG3(DBG_ENC, " => %hhu", *output_pos);
}
return TRUE;
}
@@ -159,7 +159,7 @@ static bool parse_uint8(private_parser_t *this, int rule_number,
if (output_pos)
{
*output_pos = *(this->byte_pos);
- DBG3(DBG_ENC, " => %d", *output_pos);
+ DBG3(DBG_ENC, " => %hhu", *output_pos);
}
this->byte_pos++;
return TRUE;
@@ -183,7 +183,7 @@ static bool parse_uint15(private_parser_t *this, int rule_number,
{
memcpy(output_pos, this->byte_pos, sizeof(u_int16_t));
*output_pos = ntohs(*output_pos) & ~0x8000;
- DBG3(DBG_ENC, " => %d", *output_pos);
+ DBG3(DBG_ENC, " => %hu", *output_pos);
}
this->byte_pos += sizeof(u_int16_t);
this->bit_pos = 0;
@@ -208,7 +208,7 @@ static bool parse_uint16(private_parser_t *this, int rule_number,
{
memcpy(output_pos, this->byte_pos, sizeof(u_int16_t));
*output_pos = ntohs(*output_pos);
- DBG3(DBG_ENC, " => %d", *output_pos);
+ DBG3(DBG_ENC, " => %hu", *output_pos);
}
this->byte_pos += sizeof(u_int16_t);
return TRUE;
@@ -231,7 +231,7 @@ static bool parse_uint32(private_parser_t *this, int rule_number,
{
memcpy(output_pos, this->byte_pos, sizeof(u_int32_t));
*output_pos = ntohl(*output_pos);
- DBG3(DBG_ENC, " => %d", *output_pos);
+ DBG3(DBG_ENC, " => %u", *output_pos);
}
this->byte_pos += sizeof(u_int32_t);
return TRUE;
@@ -254,7 +254,7 @@ static bool parse_bytes(private_parser_t *this, int rule_number,
if (output_pos)
{
memcpy(output_pos, this->byte_pos, bytes);
- DBG3(DBG_ENC, " => %b", output_pos, bytes);
+ DBG3(DBG_ENC, " %b", output_pos, bytes);
}
this->byte_pos += bytes;
return TRUE;
@@ -352,7 +352,7 @@ static bool parse_chunk(private_parser_t *this, int rule_number,
{
*output_pos = chunk_alloc(length);
memcpy(output_pos->ptr, this->byte_pos, length);
- DBG3(DBG_ENC, " => %b", output_pos->ptr, length);
+ DBG3(DBG_ENC, " %b", output_pos->ptr, length);
}
this->byte_pos += length;
return TRUE;
@@ -363,11 +363,10 @@ METHOD(parser_t, parse_payload, status_t,
{
payload_t *pld;
void *output;
- size_t rule_count;
- int payload_length = 0, spi_size = 0, attribute_length = 0;
+ int payload_length = 0, spi_size = 0, attribute_length = 0, header_length;
u_int16_t ts_type = 0;
bool attribute_format = FALSE;
- int rule_number;
+ int rule_number, rule_count;
encoding_rule_t *rule;
/* create instance of the payload to parse */
@@ -381,15 +380,17 @@ METHOD(parser_t, parse_payload, status_t,
/* base pointer for output, avoids casting in every rule */
output = pld;
-
/* parse the payload with its own rulse */
- pld->get_encoding_rules(pld, &this->rules, &rule_count);
+ rule_count = pld->get_encoding_rules(pld, &this->rules);
for (rule_number = 0; rule_number < rule_count; rule_number++)
{
+ /* update header length for each rule, as it is dynamic (SPIs) */
+ header_length = pld->get_header_length(pld);
+
rule = &(this->rules[rule_number]);
DBG2(DBG_ENC, " parsing rule %d %N",
rule_number, encoding_type_names, rule->type);
- switch (rule->type)
+ switch ((int)rule->type)
{
case U_INT_4:
{
@@ -457,7 +458,8 @@ METHOD(parser_t, parse_payload, status_t,
}
/* parsed u_int16 should be aligned */
payload_length = *(u_int16_t*)(output + rule->offset);
- if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH)
+ /* all payloads must have at least 4 bytes header */
+ if (payload_length < 4)
{
pld->destroy(pld);
return PARSE_ERROR;
@@ -484,49 +486,41 @@ METHOD(parser_t, parse_payload, status_t,
}
break;
}
- case PROPOSALS:
+ case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE:
+ case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1:
+ case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE:
+ case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1:
+ case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE:
+ case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1:
+ case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE:
+ case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1:
+ case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE:
{
- if (payload_length < SA_PAYLOAD_HEADER_LENGTH ||
+ if (payload_length < header_length ||
!parse_list(this, rule_number, output + rule->offset,
- PROPOSAL_SUBSTRUCTURE,
- payload_length - SA_PAYLOAD_HEADER_LENGTH))
+ rule->type - PAYLOAD_LIST,
+ payload_length - header_length))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
- case TRANSFORMS:
+ case CHUNK_DATA:
{
- if (payload_length <
- spi_size + PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH ||
- !parse_list(this, rule_number, output + rule->offset,
- TRANSFORM_SUBSTRUCTURE, payload_length - spi_size -
- PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case TRANSFORM_ATTRIBUTES:
- {
- if (payload_length < TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH ||
- !parse_list(this, rule_number, output + rule->offset,
- TRANSFORM_ATTRIBUTE,
- payload_length - TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH))
+ if (payload_length < header_length ||
+ !parse_chunk(this, rule_number, output + rule->offset,
+ payload_length - header_length))
{
pld->destroy(pld);
return PARSE_ERROR;
}
break;
}
- case CONFIGURATION_ATTRIBUTES:
+ case ENCRYPTED_DATA:
{
- if (payload_length < CP_PAYLOAD_HEADER_LENGTH ||
- !parse_list(this, rule_number, output + rule->offset,
- CONFIGURATION_ATTRIBUTE,
- payload_length - CP_PAYLOAD_HEADER_LENGTH))
+ if (!parse_chunk(this, rule_number, output + rule->offset,
+ this->input_roof - this->byte_pos))
{
pld->destroy(pld);
return PARSE_ERROR;
@@ -552,7 +546,7 @@ METHOD(parser_t, parse_payload, status_t,
}
break;
}
- case CONFIGURATION_ATTRIBUTE_LENGTH:
+ case ATTRIBUTE_LENGTH:
{
if (!parse_uint16(this, rule_number, output + rule->offset))
{
@@ -583,137 +577,6 @@ METHOD(parser_t, parse_payload, status_t,
}
break;
}
- case NONCE_DATA:
- {
- if (payload_length < NONCE_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - NONCE_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case ID_DATA:
- {
- if (payload_length < ID_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - ID_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case AUTH_DATA:
- {
- if (payload_length < AUTH_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - AUTH_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case CERT_DATA:
- {
- if (payload_length < CERT_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - CERT_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case CERTREQ_DATA:
- {
- if (payload_length < CERTREQ_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - CERTREQ_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case EAP_DATA:
- {
- if (payload_length < EAP_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - EAP_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case SPIS:
- {
- if (payload_length < DELETE_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - DELETE_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case VID_DATA:
- {
- if (payload_length < VENDOR_ID_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - VENDOR_ID_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case CONFIGURATION_ATTRIBUTE_VALUE:
- {
- if (!parse_chunk(this, rule_number, output + rule->offset,
- attribute_length))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case KEY_EXCHANGE_DATA:
- {
- if (payload_length < KE_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - KE_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case NOTIFICATION_DATA:
- {
- if (payload_length < NOTIFY_PAYLOAD_HEADER_LENGTH + spi_size ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - NOTIFY_PAYLOAD_HEADER_LENGTH - spi_size))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case ENCRYPTED_DATA:
- {
- if (payload_length < ENCRYPTION_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - ENCRYPTION_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
case TS_TYPE:
{
if (!parse_uint8(this, rule_number, output + rule->offset))
@@ -736,29 +599,6 @@ METHOD(parser_t, parse_payload, status_t,
}
break;
}
- case TRAFFIC_SELECTORS:
- {
- if (payload_length < TS_PAYLOAD_HEADER_LENGTH ||
- !parse_list(this, rule_number, output + rule->offset,
- TRAFFIC_SELECTOR_SUBSTRUCTURE,
- payload_length - TS_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
- case UNKNOWN_DATA:
- {
- if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH ||
- !parse_chunk(this, rule_number, output + rule->offset,
- payload_length - UNKNOWN_PAYLOAD_HEADER_LENGTH))
- {
- pld->destroy(pld);
- return PARSE_ERROR;
- }
- break;
- }
default:
{
DBG1(DBG_ENC, " no rule to parse rule %d %N",
diff --git a/src/libcharon/encoding/payloads/auth_payload.c b/src/libcharon/encoding/payloads/auth_payload.c
index cb44a997c..2410a1aaa 100644
--- a/src/libcharon/encoding/payloads/auth_payload.c
+++ b/src/libcharon/encoding/payloads/auth_payload.c
@@ -74,7 +74,7 @@ struct private_auth_payload_t {
* The defined offsets are the positions in a object of type
* private_auth_payload_t.
*/
-encoding_rule_t auth_payload_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_auth_payload_t, next_payload) },
/* the critical bit */
@@ -96,7 +96,7 @@ encoding_rule_t auth_payload_encodings[] = {
{ RESERVED_BYTE, offsetof(private_auth_payload_t, reserved_byte[1]) },
{ RESERVED_BYTE, offsetof(private_auth_payload_t, reserved_byte[2]) },
/* some auth data bytes, length is defined in PAYLOAD_LENGTH */
- { AUTH_DATA, offsetof(private_auth_payload_t, auth_data) }
+ { CHUNK_DATA, offsetof(private_auth_payload_t, auth_data) }
};
/*
@@ -119,11 +119,17 @@ METHOD(payload_t, verify, status_t,
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_auth_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_auth_payload_t *this, encoding_rule_t **rules)
{
- *rules = auth_payload_encodings;
- *rule_count = countof(auth_payload_encodings);
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_auth_payload_t *this)
+{
+ return 8;
}
METHOD(payload_t, get_type, payload_type_t,
@@ -167,7 +173,7 @@ METHOD(auth_payload_t, set_data, void,
{
free(this->auth_data.ptr);
this->auth_data = chunk_clone(data);
- this->payload_length = AUTH_PAYLOAD_HEADER_LENGTH + this->auth_data.len;
+ this->payload_length = get_header_length(this) + this->auth_data.len;
}
METHOD(auth_payload_t, get_data, chunk_t,
@@ -195,6 +201,7 @@ auth_payload_t *auth_payload_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -208,7 +215,7 @@ auth_payload_t *auth_payload_create()
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = AUTH_PAYLOAD_HEADER_LENGTH,
+ .payload_length = get_header_length(this),
);
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/auth_payload.h b/src/libcharon/encoding/payloads/auth_payload.h
index e4c4e6ae3..b922d12c8 100644
--- a/src/libcharon/encoding/payloads/auth_payload.h
+++ b/src/libcharon/encoding/payloads/auth_payload.h
@@ -26,12 +26,7 @@ typedef struct auth_payload_t auth_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
-#include <sa/authenticators/authenticator.h>
-
-/**
- * Length of a auth payload without the auth data in bytes.
- */
-#define AUTH_PAYLOAD_HEADER_LENGTH 8
+#include <sa/authenticator.h>
/**
* Class representing an IKEv2 AUTH payload.
diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c
index c42cec680..3a230b91e 100644
--- a/src/libcharon/encoding/payloads/cert_payload.c
+++ b/src/libcharon/encoding/payloads/cert_payload.c
@@ -86,6 +86,11 @@ struct private_cert_payload_t {
* TRUE if the "Hash and URL" data is invalid
*/
bool invalid_hash_and_url;
+
+ /**
+ * The payload type.
+ */
+ payload_type_t type;
};
/**
@@ -95,7 +100,7 @@ struct private_cert_payload_t {
* private_cert_payload_t.
*
*/
-encoding_rule_t cert_payload_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_cert_payload_t, next_payload) },
/* the critical bit */
@@ -113,7 +118,7 @@ encoding_rule_t cert_payload_encodings[] = {
/* 1 Byte CERT type*/
{ U_INT_8, offsetof(private_cert_payload_t, encoding) },
/* some cert data bytes, length is defined in PAYLOAD_LENGTH */
- { CERT_DATA, offsetof(private_cert_payload_t, data) }
+ { CHUNK_DATA, offsetof(private_cert_payload_t, data) }
};
/*
@@ -166,17 +171,23 @@ METHOD(payload_t, verify, status_t,
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_cert_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_cert_payload_t *this, encoding_rule_t **rules)
+{
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_cert_payload_t *this)
{
- *rules = cert_payload_encodings;
- *rule_count = countof(cert_payload_encodings);
+ return 5;
}
METHOD(payload_t, get_type, payload_type_t,
private_cert_payload_t *this)
{
- return CERTIFICATE;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -261,7 +272,7 @@ METHOD2(payload_t, cert_payload_t, destroy, void,
/*
* Described in header
*/
-cert_payload_t *cert_payload_create()
+cert_payload_t *cert_payload_create(payload_type_t type)
{
private_cert_payload_t *this;
@@ -270,6 +281,7 @@ cert_payload_t *cert_payload_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -283,7 +295,8 @@ cert_payload_t *cert_payload_create()
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = CERT_PAYLOAD_HEADER_LENGTH,
+ .payload_length = get_header_length(this),
+ .type = type,
);
return &this->public;
}
@@ -291,10 +304,12 @@ cert_payload_t *cert_payload_create()
/*
* Described in header
*/
-cert_payload_t *cert_payload_create_from_cert(certificate_t *cert)
+cert_payload_t *cert_payload_create_from_cert(payload_type_t type,
+ certificate_t *cert)
{
- private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create();
+ private_cert_payload_t *this;
+ this = (private_cert_payload_t*)cert_payload_create(type);
switch (cert->get_type(cert))
{
case CERT_X509:
@@ -312,7 +327,8 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert)
free(this);
return NULL;
}
- this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len;
+ this->payload_length = get_header_length(this) + this->data.len;
+
return &this->public;
}
@@ -321,23 +337,29 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert)
*/
cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url)
{
- private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create();
+ private_cert_payload_t *this;
+ this = (private_cert_payload_t*)cert_payload_create(CERTIFICATE);
this->encoding = ENC_X509_HASH_AND_URL;
this->data = chunk_cat("cc", hash, chunk_create(url, strlen(url)));
- this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len;
+ this->payload_length = get_header_length(this) + this->data.len;
+
return &this->public;
}
/*
* Described in header
*/
-cert_payload_t *cert_payload_create_custom(cert_encoding_t type, chunk_t data)
+cert_payload_t *cert_payload_create_custom(payload_type_t type,
+ cert_encoding_t encoding, chunk_t data)
{
- private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create();
+ private_cert_payload_t *this;
- this->encoding = type;
+ this = (private_cert_payload_t*)cert_payload_create(type);
+ this->encoding = encoding;
this->data = data;
- this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len;
+ this->payload_length = get_header_length(this) + this->data.len;
+
return &this->public;
}
+
diff --git a/src/libcharon/encoding/payloads/cert_payload.h b/src/libcharon/encoding/payloads/cert_payload.h
index 21b503a40..19ed2ccd2 100644
--- a/src/libcharon/encoding/payloads/cert_payload.h
+++ b/src/libcharon/encoding/payloads/cert_payload.h
@@ -31,11 +31,6 @@ typedef enum cert_encoding_t cert_encoding_t;
#include <encoding/payloads/payload.h>
/**
- * Length of a cert payload without the cert data in bytes.
- */
-#define CERT_PAYLOAD_HEADER_LENGTH 5
-
-/**
* Certifcate encodings, as in RFC4306
*/
enum cert_encoding_t {
@@ -60,9 +55,7 @@ enum cert_encoding_t {
extern enum_name_t *cert_encoding_names;
/**
- * Class representing an IKEv2 CERT payload.
- *
- * The CERT payload format is described in RFC section 3.6.
+ * Class representing an IKEv1/IKEv2 CERT payload.
*/
struct cert_payload_t {
@@ -103,7 +96,6 @@ struct cert_payload_t {
*/
char *(*get_url)(cert_payload_t *this);
-
/**
* Destroys the cert_payload object.
*/
@@ -113,23 +105,26 @@ struct cert_payload_t {
/**
* Creates an empty certificate payload.
*
+ * @param type payload type (for IKEv1 or IKEv2)
* @return cert_payload_t object
*/
-cert_payload_t *cert_payload_create(void);
+cert_payload_t *cert_payload_create(payload_type_t type);
/**
* Creates a certificate payload with an embedded certificate.
*
+ * @param type payload type (for IKEv1 or IKEv2)
* @param cert certificate to embed
* @return cert_payload_t object
*/
-cert_payload_t *cert_payload_create_from_cert(certificate_t *cert);
+cert_payload_t *cert_payload_create_from_cert(payload_type_t type,
+ certificate_t *cert);
/**
- * Creates a certificate payload with hash and URL encoding of a certificate.
+ * Creates an IKEv2 certificate payload with hash and URL encoding.
*
* @param hash hash of the DER encoded certificate (get's cloned)
- * @param url the URL to locate the certificate (get's cloned)
+ * @param url URL to the certificate
* @return cert_payload_t object
*/
cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url);
@@ -137,10 +132,12 @@ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url);
/**
* Creates a custom certificate payload using type and associated data.
*
- * @param type encoding type of certificate
+ * @param type payload type (for IKEv1 or IKEv2)
+ * @param encoding encoding type of certificate
* @param data associated data (gets owned)
* @return cert_payload_t object
*/
-cert_payload_t *cert_payload_create_custom(cert_encoding_t type, chunk_t data);
+cert_payload_t *cert_payload_create_custom(payload_type_t type,
+ cert_encoding_t encoding, chunk_t data);
#endif /** CERT_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c
index 02015f273..df5e73b5b 100644
--- a/src/libcharon/encoding/payloads/certreq_payload.c
+++ b/src/libcharon/encoding/payloads/certreq_payload.c
@@ -64,15 +64,17 @@ struct private_certreq_payload_t {
* The contained certreq data value.
*/
chunk_t data;
+
+ /**
+ * Payload type CERTIFICATE_REQUEST or CERTIFICATE_REQUEST_V1
+ */
+ payload_type_t type;
};
/**
- * Encoding rules to parse or generate a CERTREQ payload
- *
- * The defined offsets are the positions in a object of type
- * private_certreq_payload_t.
+ * Encoding rules for CERTREQ payload.
*/
-encoding_rule_t certreq_payload_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_certreq_payload_t, next_payload) },
/* the critical bit */
@@ -90,7 +92,7 @@ encoding_rule_t certreq_payload_encodings[] = {
/* 1 Byte CERTREQ type*/
{ U_INT_8, offsetof(private_certreq_payload_t, encoding) },
/* some certreq data bytes, length is defined in PAYLOAD_LENGTH */
- { CERTREQ_DATA, offsetof(private_certreq_payload_t, data) }
+ { CHUNK_DATA, offsetof(private_certreq_payload_t, data) }
};
/*
@@ -109,7 +111,8 @@ encoding_rule_t certreq_payload_encodings[] = {
METHOD(payload_t, verify, status_t,
private_certreq_payload_t *this)
{
- if (this->encoding == ENC_X509_SIGNATURE)
+ if (this->type == CERTIFICATE_REQUEST &&
+ this->encoding == ENC_X509_SIGNATURE)
{
if (this->data.len % HASH_SIZE_SHA1)
{
@@ -121,17 +124,23 @@ METHOD(payload_t, verify, status_t,
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_certreq_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_certreq_payload_t *this, encoding_rule_t **rules)
+{
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_certreq_payload_t *this)
{
- *rules = certreq_payload_encodings;
- *rule_count = countof(certreq_payload_encodings);
+ return 5;
}
METHOD(payload_t, get_type, payload_type_t,
private_certreq_payload_t *this)
{
- return CERTIFICATE_REQUEST;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -152,6 +161,16 @@ METHOD(payload_t, get_length, size_t,
return this->payload_length;
}
+METHOD(certreq_payload_t, get_dn, identification_t*,
+ private_certreq_payload_t *this)
+{
+ if (this->data.len)
+ {
+ return identification_create_from_encoding(ID_DER_ASN1_DN, this->data);
+ }
+ return NULL;
+}
+
METHOD(certreq_payload_t, add_keyid, void,
private_certreq_payload_t *this, chunk_t keyid)
{
@@ -199,6 +218,10 @@ METHOD(certreq_payload_t, create_keyid_enumerator, enumerator_t*,
{
keyid_enumerator_t *enumerator;
+ if (this->type == CERTIFICATE_REQUEST_V1)
+ {
+ return enumerator_create_empty();
+ }
INIT(enumerator,
.public = {
.enumerate = (void*)_keyid_enumerate,
@@ -231,7 +254,7 @@ METHOD2(payload_t, certreq_payload_t, destroy, void,
/*
* Described in header
*/
-certreq_payload_t *certreq_payload_create()
+certreq_payload_t *certreq_payload_create(payload_type_t type)
{
private_certreq_payload_t *this;
@@ -240,6 +263,7 @@ certreq_payload_t *certreq_payload_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -250,9 +274,11 @@ certreq_payload_t *certreq_payload_create()
.get_cert_type = _get_cert_type,
.add_keyid = _add_keyid,
.destroy = _destroy,
+ .get_dn = _get_dn,
},
.next_payload = NO_PAYLOAD,
- .payload_length = CERTREQ_PAYLOAD_HEADER_LENGTH,
+ .payload_length = get_header_length(this),
+ .type = type,
);
return &this->public;
}
@@ -262,8 +288,10 @@ certreq_payload_t *certreq_payload_create()
*/
certreq_payload_t *certreq_payload_create_type(certificate_type_t type)
{
- private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create();
+ private_certreq_payload_t *this;
+ this = (private_certreq_payload_t*)
+ certreq_payload_create(CERTIFICATE_REQUEST);
switch (type)
{
case CERT_X509:
@@ -278,3 +306,19 @@ certreq_payload_t *certreq_payload_create_type(certificate_type_t type)
return &this->public;
}
+/*
+ * Described in header
+ */
+certreq_payload_t *certreq_payload_create_dn(identification_t *id)
+{
+ private_certreq_payload_t *this;
+
+ this = (private_certreq_payload_t*)
+ certreq_payload_create(CERTIFICATE_REQUEST_V1);
+
+ this->encoding = ENC_X509_SIGNATURE;
+ this->data = chunk_clone(id->get_encoding(id));
+ this->payload_length = get_header_length(this) + this->data.len;
+
+ return &this->public;
+}
diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h
index 914063628..cce71c0ad 100644
--- a/src/libcharon/encoding/payloads/certreq_payload.h
+++ b/src/libcharon/encoding/payloads/certreq_payload.h
@@ -27,25 +27,20 @@ typedef struct certreq_payload_t certreq_payload_t;
#include <library.h>
#include <encoding/payloads/payload.h>
#include <encoding/payloads/cert_payload.h>
+#include <utils/identification.h>
/**
- * Length of a CERTREQ payload without the CERTREQ data in bytes.
- */
-#define CERTREQ_PAYLOAD_HEADER_LENGTH 5
-
-/**
- * Class representing an IKEv2 CERTREQ payload.
- *
- * The CERTREQ payload format is described in RFC section 3.7.
+ * Class representing an IKEv1/IKEv2 CERTREQ payload.
*/
struct certreq_payload_t {
+
/**
* The payload_t interface.
*/
payload_t payload_interface;
/**
- * Create an enumerator over contained keyids.
+ * Create an enumerator over contained keyids (IKEv2 only).
*
* @return enumerator over chunk_t's.
*/
@@ -59,7 +54,7 @@ struct certreq_payload_t {
certificate_type_t (*get_cert_type)(certreq_payload_t *this);
/**
- * Add a certificates keyid to the payload.
+ * Add a certificates keyid to the payload (IKEv2 only).
*
* @param keyid keyid of the trusted certifcate
* @return
@@ -67,6 +62,13 @@ struct certreq_payload_t {
void (*add_keyid)(certreq_payload_t *this, chunk_t keyid);
/**
+ * Get the distinguished name of the payload (IKEv1 only).
+ *
+ * @return DN as identity, must be destroyed
+ */
+ identification_t* (*get_dn)(certreq_payload_t *this);
+
+ /**
* Destroys an certreq_payload_t object.
*/
void (*destroy) (certreq_payload_t *this);
@@ -77,14 +79,22 @@ struct certreq_payload_t {
*
* @return certreq payload
*/
-certreq_payload_t *certreq_payload_create(void);
+certreq_payload_t *certreq_payload_create(payload_type_t payload_type);
/**
- * Creates an empty certreq_payload_t for a kind of certificates.
+ * Creates an empty IKEv2 certreq_payload_t for a kind of certificates.
*
* @param type type of the added keyids
* @return certreq payload
*/
certreq_payload_t *certreq_payload_create_type(certificate_type_t type);
+/**
+ * Creates a IKEv1 certreq_payload_t for a given distinguished name.
+ *
+ * @param id distinguished name, does not get owned
+ * @return certreq payload
+ */
+certreq_payload_t *certreq_payload_create_dn(identification_t *id);
+
#endif /** CERTREQ_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c
index e608497bd..482eca882 100644
--- a/src/libcharon/encoding/payloads/configuration_attribute.c
+++ b/src/libcharon/encoding/payloads/configuration_attribute.c
@@ -36,41 +36,48 @@ struct private_configuration_attribute_t {
configuration_attribute_t public;
/**
- * Reserved bit
+ * Value encoded in length field?
+ */
+ bool af_flag;
+
+ /**
+ * Reserved bit (af_flag in IKEv2)
*/
bool reserved;
/**
* Type of the attribute.
*/
- u_int16_t type;
+ u_int16_t attr_type;
/**
- * Length of the attribute.
+ * Length of the attribute, value if af_flag set.
*/
- u_int16_t length;
+ u_int16_t length_or_value;
/**
* Attribute value as chunk.
*/
chunk_t value;
+
+ /**
+ * Payload type, CONFIGURATION_ATTRIBUTE or DATA_ATTRIBUTE_V1
+ */
+ payload_type_t type;
};
/**
- * Encoding rules to parse or generate a configuration attribute.
- *
- * The defined offsets are the positions in a object of type
- * private_configuration_attribute_t.
+ * Encoding rules for a IKEv2 configuration attribute / IKEv1 data attribute
*/
-encoding_rule_t configuration_attribute_encodings[] = {
+static encoding_rule_t encodings_v2[] = {
/* 1 reserved bit */
- { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved)},
+ { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved) },
/* type of the attribute as 15 bit unsigned integer */
- { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, type) },
+ { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) },
/* Length of attribute value */
- { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length) },
+ { ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length_or_value)},
/* Value of attribute if attribute format flag is zero */
- { CONFIGURATION_ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }
+ { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) },
};
/*
@@ -85,87 +92,142 @@ encoding_rule_t configuration_attribute_encodings[] = {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
+/**
+ * Encoding rules for a IKEv1 data attribute
+ */
+static encoding_rule_t encodings_v1[] = {
+ /* AF Flag */
+ { ATTRIBUTE_FORMAT, offsetof(private_configuration_attribute_t, af_flag) },
+ /* type of the attribute as 15 bit unsigned integer */
+ { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) },
+ /* Length of attribute value */
+ { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_configuration_attribute_t, length_or_value)},
+ /* Value of attribute if attribute format flag is zero */
+ { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) },
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ !F| Attribute Type ! Length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | |
+ ~ Value ~
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+
METHOD(payload_t, verify, status_t,
private_configuration_attribute_t *this)
{
bool failed = FALSE;
- if (this->length != this->value.len)
- {
- DBG1(DBG_ENC, "invalid attribute length");
- return FAILED;
- }
-
- switch (this->type)
+ switch (this->attr_type)
{
- case INTERNAL_IP4_ADDRESS:
- case INTERNAL_IP4_NETMASK:
- case INTERNAL_IP4_DNS:
- case INTERNAL_IP4_NBNS:
- case INTERNAL_ADDRESS_EXPIRY:
- case INTERNAL_IP4_DHCP:
- if (this->length != 0 && this->length != 4)
+ case INTERNAL_IP4_ADDRESS:
+ case INTERNAL_IP4_NETMASK:
+ case INTERNAL_IP4_DNS:
+ case INTERNAL_IP4_NBNS:
+ case INTERNAL_ADDRESS_EXPIRY:
+ case INTERNAL_IP4_DHCP:
+ if (this->length_or_value != 0 && this->length_or_value != 4)
{
failed = TRUE;
}
break;
- case INTERNAL_IP4_SUBNET:
- if (this->length != 0 && this->length != 8)
+ case INTERNAL_IP4_SUBNET:
+ if (this->length_or_value != 0 && this->length_or_value != 8)
{
failed = TRUE;
}
break;
- case INTERNAL_IP6_ADDRESS:
- case INTERNAL_IP6_SUBNET:
- if (this->length != 0 && this->length != 17)
+ case INTERNAL_IP6_ADDRESS:
+ case INTERNAL_IP6_SUBNET:
+ if (this->length_or_value != 0 && this->length_or_value != 17)
{
failed = TRUE;
}
break;
- case INTERNAL_IP6_DNS:
- case INTERNAL_IP6_NBNS:
- case INTERNAL_IP6_DHCP:
- if (this->length != 0 && this->length != 16)
+ case INTERNAL_IP6_DNS:
+ case INTERNAL_IP6_NBNS:
+ case INTERNAL_IP6_DHCP:
+ if (this->length_or_value != 0 && this->length_or_value != 16)
{
failed = TRUE;
}
break;
- case SUPPORTED_ATTRIBUTES:
- if (this->length % 2)
+ case SUPPORTED_ATTRIBUTES:
+ if (this->length_or_value % 2)
{
failed = TRUE;
}
break;
- case APPLICATION_VERSION:
+ case APPLICATION_VERSION:
+ case INTERNAL_IP4_SERVER:
+ case INTERNAL_IP6_SERVER:
+ case XAUTH_TYPE:
+ case XAUTH_USER_NAME:
+ case XAUTH_USER_PASSWORD:
+ case XAUTH_PASSCODE:
+ case XAUTH_MESSAGE:
+ case XAUTH_CHALLENGE:
+ case XAUTH_DOMAIN:
+ case XAUTH_STATUS:
+ case XAUTH_NEXT_PIN:
+ case XAUTH_ANSWER:
+ case UNITY_BANNER:
+ case UNITY_SAVE_PASSWD:
+ case UNITY_DEF_DOMAIN:
+ case UNITY_SPLITDNS_NAME:
+ case UNITY_SPLIT_INCLUDE:
+ case UNITY_NATT_PORT:
+ case UNITY_LOCAL_LAN:
+ case UNITY_PFS:
+ case UNITY_FW_TYPE:
+ case UNITY_BACKUP_SERVERS:
+ case UNITY_DDNS_HOSTNAME:
/* any length acceptable */
break;
- default:
+ default:
DBG1(DBG_ENC, "unknown attribute type %N",
- configuration_attribute_type_names, this->type);
+ configuration_attribute_type_names, this->attr_type);
break;
}
if (failed)
{
DBG1(DBG_ENC, "invalid attribute length %d for %N",
- this->length, configuration_attribute_type_names, this->type);
+ this->length_or_value, configuration_attribute_type_names,
+ this->attr_type);
return FAILED;
}
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_configuration_attribute_t *this, encoding_rule_t **rules,
- size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_configuration_attribute_t *this, encoding_rule_t **rules)
+{
+ if (this->type == CONFIGURATION_ATTRIBUTE)
+ {
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+ }
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_configuration_attribute_t *this)
{
- *rules = configuration_attribute_encodings;
- *rule_count = countof(configuration_attribute_encodings);
+ return 4;
}
METHOD(payload_t, get_type, payload_type_t,
private_configuration_attribute_t *this)
{
- return CONFIGURATION_ATTRIBUTE;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -182,21 +244,35 @@ METHOD(payload_t, set_next_type, void,
METHOD(payload_t, get_length, size_t,
private_configuration_attribute_t *this)
{
- return this->value.len + CONFIGURATION_ATTRIBUTE_HEADER_LENGTH;
+ return get_header_length(this) + this->value.len;
}
METHOD(configuration_attribute_t, get_cattr_type, configuration_attribute_type_t,
private_configuration_attribute_t *this)
{
- return this->type;
+ return this->attr_type;
}
-METHOD(configuration_attribute_t, get_value, chunk_t,
+METHOD(configuration_attribute_t, get_chunk, chunk_t,
private_configuration_attribute_t *this)
{
+ if (this->af_flag)
+ {
+ return chunk_from_thing(this->length_or_value);
+ }
return this->value;
}
+METHOD(configuration_attribute_t, get_value, u_int16_t,
+ private_configuration_attribute_t *this)
+{
+ if (this->af_flag)
+ {
+ return this->length_or_value;
+ }
+ return 0;
+}
+
METHOD2(payload_t, configuration_attribute_t, destroy, void,
private_configuration_attribute_t *this)
{
@@ -207,7 +283,7 @@ METHOD2(payload_t, configuration_attribute_t, destroy, void,
/*
* Described in header.
*/
-configuration_attribute_t *configuration_attribute_create()
+configuration_attribute_t *configuration_attribute_create(payload_type_t type)
{
private_configuration_attribute_t *this;
@@ -216,16 +292,19 @@ configuration_attribute_t *configuration_attribute_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
.get_type = _get_type,
.destroy = _destroy,
},
+ .get_chunk = _get_chunk,
.get_value = _get_value,
.get_type = _get_cattr_type,
.destroy = _destroy,
},
+ .type = type
);
return &this->public;
}
@@ -233,15 +312,33 @@ configuration_attribute_t *configuration_attribute_create()
/*
* Described in header.
*/
+configuration_attribute_t *configuration_attribute_create_chunk(
+ payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk)
+{
+ private_configuration_attribute_t *this;
+
+ this = (private_configuration_attribute_t*)
+ configuration_attribute_create(type);
+ this->attr_type = ((u_int16_t)attr_type) & 0x7FFF;
+ this->value = chunk_clone(chunk);
+ this->length_or_value = chunk.len;
+
+ return &this->public;
+}
+
+/*
+ * Described in header.
+ */
configuration_attribute_t *configuration_attribute_create_value(
- configuration_attribute_type_t type, chunk_t value)
+ configuration_attribute_type_t attr_type, u_int16_t value)
{
private_configuration_attribute_t *this;
- this = (private_configuration_attribute_t*)configuration_attribute_create();
- this->type = ((u_int16_t)type) & 0x7FFF;
- this->value = chunk_clone(value);
- this->length = value.len;
+ this = (private_configuration_attribute_t*)
+ configuration_attribute_create(CONFIGURATION_ATTRIBUTE_V1);
+ this->attr_type = ((u_int16_t)attr_type) & 0x7FFF;
+ this->length_or_value = value;
+ this->af_flag = TRUE;
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/configuration_attribute.h b/src/libcharon/encoding/payloads/configuration_attribute.h
index 6e4b018bb..ecc0f9c07 100644
--- a/src/libcharon/encoding/payloads/configuration_attribute.h
+++ b/src/libcharon/encoding/payloads/configuration_attribute.h
@@ -29,14 +29,7 @@ typedef struct configuration_attribute_t configuration_attribute_t;
#include <encoding/payloads/payload.h>
/**
- * Configuration attribute header length in bytes.
- */
-#define CONFIGURATION_ATTRIBUTE_HEADER_LENGTH 4
-
-/**
- * Class representing an IKEv2-CONFIGURATION Attribute.
- *
- * The CONFIGURATION ATTRIBUTE format is described in RFC section 3.15.1.
+ * Class representing an IKEv2 configuration attribute / IKEv1 data attribute.
*/
struct configuration_attribute_t {
@@ -53,11 +46,18 @@ struct configuration_attribute_t {
configuration_attribute_type_t (*get_type)(configuration_attribute_t *this);
/**
- * Returns the value of the attribute.
+ * Returns the value of the attribute as chunk.
*
* @return chunk_t pointing to the internal value
*/
- chunk_t (*get_value) (configuration_attribute_t *this);
+ chunk_t (*get_chunk) (configuration_attribute_t *this);
+
+ /**
+ * Returns the 2 byte value of the attribute as u_int16.
+ *
+ * @return attribute value
+ */
+ u_int16_t (*get_value) (configuration_attribute_t *this);
/**
* Destroys an configuration_attribute_t object.
@@ -68,18 +68,30 @@ struct configuration_attribute_t {
/**
* Creates an empty configuration attribute.
*
- * @return created configuration attribute
+ * @param type CONFIGURATION_ATTRIBUTE or CONFIGURATION_ATTRIBUTE_V1
+ * @return created configuration attribute
*/
-configuration_attribute_t *configuration_attribute_create();
+configuration_attribute_t *configuration_attribute_create(payload_type_t type);
/**
* Creates a configuration attribute with type and value.
*
- * @param type type of configuration attribute
- * @param value value, gets cloned
- * @return created configuration attribute
+ * @param type CONFIGURATION_ATTRIBUTE or CONFIGURATION_ATTRIBUTE_V1
+ * @param attr_type type of configuration attribute
+ * @param chunk attribute value, gets cloned
+ * @return created configuration attribute
+ */
+configuration_attribute_t *configuration_attribute_create_chunk(
+ payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk);
+
+/**
+ * Creates a IKEv1 configuration attribute with 2 bytes value (IKEv1 only).
+ *
+ * @param attr_type type of configuration attribute
+ * @param value attribute value, gets cloned
+ * @return created CONFIGURATION_ATTRIBUTE_V1 configuration attribute
*/
configuration_attribute_t *configuration_attribute_create_value(
- configuration_attribute_type_t type, chunk_t value);
+ configuration_attribute_type_t attr_type, u_int16_t value);
#endif /** CONFIGURATION_ATTRIBUTE_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c
index 82e9e51b7..40f6ae48f 100644
--- a/src/libcharon/encoding/payloads/cp_payload.c
+++ b/src/libcharon/encoding/payloads/cp_payload.c
@@ -44,7 +44,7 @@ struct private_cp_payload_t {
/**
* Next payload type.
*/
- u_int8_t next_payload;
+ u_int8_t next_payload;
/**
* Critical flag.
@@ -67,6 +67,11 @@ struct private_cp_payload_t {
u_int16_t payload_length;
/**
+ * Identifier field, IKEv1 only
+ */
+ u_int16_t identifier;
+
+ /**
* List of attributes, as configuration_attribute_t
*/
linked_list_t *attributes;
@@ -74,38 +79,40 @@ struct private_cp_payload_t {
/**
* Config Type.
*/
- u_int8_t type;
+ u_int8_t cfg_type;
+
+ /**
+ * CONFIGURATION or CONFIGURATION_V1
+ */
+ payload_type_t type;
};
/**
- * Encoding rules to parse or generate a IKEv2-CP Payload
- *
- * The defined offsets are the positions in a object of type
- * private_cp_payload_t.
+ * Encoding rules to for an IKEv2 configuration payload
*/
-encoding_rule_t cp_payload_encodings[] = {
+static encoding_rule_t encodings_v2[] = {
/* 1 Byte next payload type, stored in the field next_payload */
- { U_INT_8, offsetof(private_cp_payload_t, next_payload) },
+ { U_INT_8, offsetof(private_cp_payload_t, next_payload) },
/* the critical bit */
- { FLAG, offsetof(private_cp_payload_t, critical) },
+ { FLAG, offsetof(private_cp_payload_t, critical) },
/* 7 Bit reserved bits */
- { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) },
- { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) },
- { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) },
- { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) },
- { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) },
- { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) },
- { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) },
/* Length of the whole CP payload*/
- { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) },
- /* Proposals are stored in a proposal substructure,
- offset points to a linked_list_t pointer */
- { U_INT_8, offsetof(private_cp_payload_t, type) },
+ { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) },
+ { U_INT_8, offsetof(private_cp_payload_t, cfg_type) },
/* 3 reserved bytes */
- { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])},
- { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[1])},
- { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[2])},
- { CONFIGURATION_ATTRIBUTES, offsetof(private_cp_payload_t, attributes) }
+ { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])},
+ { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[1])},
+ { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[2])},
+ /* list of configuration attributes in a list */
+ { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE,
+ offsetof(private_cp_payload_t, attributes) },
};
/*
@@ -122,6 +129,47 @@ encoding_rule_t cp_payload_encodings[] = {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
+/**
+ * Encoding rules to for an IKEv1 configuration payload
+ */
+static encoding_rule_t encodings_v1[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_cp_payload_t, next_payload) },
+ /* the critical bit */
+ { FLAG, offsetof(private_cp_payload_t, critical) },
+ /* 7 Bit reserved bits */
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) },
+ { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) },
+ /* Length of the whole CP payload*/
+ { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) },
+ { U_INT_8, offsetof(private_cp_payload_t, cfg_type) },
+ /* 1 reserved bytes */
+ { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])},
+ { U_INT_16, offsetof(private_cp_payload_t, identifier)},
+ /* list of configuration attributes in a list */
+ { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1,
+ offsetof(private_cp_payload_t, attributes) },
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! CFG Type ! RESERVED ! Identifier !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Configuration Attributes ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
METHOD(payload_t, verify, status_t,
private_cp_payload_t *this)
{
@@ -142,17 +190,28 @@ METHOD(payload_t, verify, status_t,
return status;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_cp_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_cp_payload_t *this, encoding_rule_t **rules)
+{
+ if (this->type == CONFIGURATION)
+ {
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+ }
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_cp_payload_t *this)
{
- *rules = cp_payload_encodings;
- *rule_count = countof(cp_payload_encodings);
+ return 8;
}
METHOD(payload_t, get_type, payload_type_t,
private_cp_payload_t *this)
{
- return CONFIGURATION;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -175,7 +234,7 @@ static void compute_length(private_cp_payload_t *this)
enumerator_t *enumerator;
payload_t *attribute;
- this->payload_length = CP_PAYLOAD_HEADER_LENGTH;
+ this->payload_length = get_header_length(this);
enumerator = this->attributes->create_enumerator(this->attributes);
while (enumerator->enumerate(enumerator, &attribute))
@@ -207,7 +266,18 @@ METHOD(cp_payload_t, add_attribute, void,
METHOD(cp_payload_t, get_config_type, config_type_t,
private_cp_payload_t *this)
{
- return this->type;
+ return this->cfg_type;
+}
+
+METHOD(cp_payload_t, get_identifier, u_int16_t,
+ private_cp_payload_t *this)
+{
+ return this->identifier;
+}
+METHOD(cp_payload_t, set_identifier, void,
+ private_cp_payload_t *this, u_int16_t identifier)
+{
+ this->identifier = identifier;
}
METHOD2(payload_t, cp_payload_t, destroy, void,
@@ -221,7 +291,7 @@ METHOD2(payload_t, cp_payload_t, destroy, void,
/*
* Described in header.
*/
-cp_payload_t *cp_payload_create_type(config_type_t type)
+cp_payload_t *cp_payload_create_type(payload_type_t type, config_type_t cfg_type)
{
private_cp_payload_t *this;
@@ -230,6 +300,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type)
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -239,11 +310,14 @@ cp_payload_t *cp_payload_create_type(config_type_t type)
.create_attribute_enumerator = _create_attribute_enumerator,
.add_attribute = _add_attribute,
.get_type = _get_config_type,
+ .get_identifier = _get_identifier,
+ .set_identifier = _set_identifier,
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = CP_PAYLOAD_HEADER_LENGTH,
+ .payload_length = get_header_length(this),
.attributes = linked_list_create(),
+ .cfg_type = cfg_type,
.type = type,
);
return &this->public;
@@ -252,7 +326,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type)
/*
* Described in header.
*/
-cp_payload_t *cp_payload_create()
+cp_payload_t *cp_payload_create(payload_type_t type)
{
- return cp_payload_create_type(CFG_REQUEST);
+ return cp_payload_create_type(type, CFG_REQUEST);
}
diff --git a/src/libcharon/encoding/payloads/cp_payload.h b/src/libcharon/encoding/payloads/cp_payload.h
index afae6091a..5eb1e06a7 100644
--- a/src/libcharon/encoding/payloads/cp_payload.h
+++ b/src/libcharon/encoding/payloads/cp_payload.h
@@ -31,11 +31,6 @@ typedef struct cp_payload_t cp_payload_t;
#include <utils/enumerator.h>
/**
- * CP_PAYLOAD length in bytes without any proposal substructure.
- */
-#define CP_PAYLOAD_HEADER_LENGTH 8
-
-/**
* Config Type of an Configuration Payload.
*/
enum config_type_t {
@@ -51,9 +46,7 @@ enum config_type_t {
extern enum_name_t *config_type_names;
/**
- * Class representing an IKEv2-CP Payload.
- *
- * The CP Payload format is described in RFC section 3.15.
+ * Class representing an IKEv2 configuration / IKEv1 attribute payload.
*/
struct cp_payload_t {
@@ -85,6 +78,20 @@ struct cp_payload_t {
config_type_t (*get_type) (cp_payload_t *this);
/**
+ * Set the configuration payload identifier (IKEv1 only).
+ *
+ @param identifier identifier to set
+ */
+ void (*set_identifier) (cp_payload_t *this, u_int16_t identifier);
+
+ /**
+ * Get the configuration payload identifier (IKEv1 only).
+ *
+ * @return identifier
+ */
+ u_int16_t (*get_identifier) (cp_payload_t *this);
+
+ /**
* Destroys an cp_payload_t object.
*/
void (*destroy) (cp_payload_t *this);
@@ -93,16 +100,18 @@ struct cp_payload_t {
/**
* Creates an empty configuration payload
*
- * @return empty configuration payload
+ * @param type payload type, CONFIGURATION or CONFIGURATION_V1
+ * @return empty configuration payload
*/
-cp_payload_t *cp_payload_create();
+cp_payload_t *cp_payload_create(payload_type_t type);
/**
* Creates an cp_payload_t with type and value
*
- * @param config_type type of configuration payload to create
- * @return created configuration payload
+ * @param type payload type, CONFIGURATION or CONFIGURATION_V1
+ * @param cfg_type type of configuration payload to create
+ * @return created configuration payload
*/
-cp_payload_t *cp_payload_create_type(config_type_t config_type);
+cp_payload_t *cp_payload_create_type(payload_type_t type, config_type_t cfg_type);
#endif /** CP_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c
index e6ee07d39..007411f37 100644
--- a/src/libcharon/encoding/payloads/delete_payload.c
+++ b/src/libcharon/encoding/payloads/delete_payload.c
@@ -24,9 +24,9 @@ typedef struct private_delete_payload_t private_delete_payload_t;
/**
* Private data of an delete_payload_t object.
- *
*/
struct private_delete_payload_t {
+
/**
* Public delete_payload_t interface.
*/
@@ -45,7 +45,7 @@ struct private_delete_payload_t {
/**
* reserved bits
*/
- bool reserved[7];
+ bool reserved[8];
/**
* Length of this payload.
@@ -53,6 +53,11 @@ struct private_delete_payload_t {
u_int16_t payload_length;
/**
+ * IKEv1 Domain of Interpretation
+ */
+ u_int32_t doi;
+
+ /**
* Protocol ID.
*/
u_int8_t protocol_id;
@@ -71,19 +76,21 @@ struct private_delete_payload_t {
* The contained SPI's.
*/
chunk_t spis;
+
+ /**
+ * Payload type, DELETE or DELETE_V1
+ */
+ payload_type_t type;
};
/**
- * Encoding rules to parse or generate a DELETE payload
- *
- * The defined offsets are the positions in a object of type
- * private_delete_payload_t.
+ * Encoding rules for an IKEv2 delete payload.
*/
-encoding_rule_t delete_payload_encodings[] = {
+static encoding_rule_t encodings_v2[] = {
/* 1 Byte next payload type, stored in the field next_payload */
- { U_INT_8, offsetof(private_delete_payload_t, next_payload) },
+ { U_INT_8, offsetof(private_delete_payload_t, next_payload) },
/* the critical bit */
- { FLAG, offsetof(private_delete_payload_t, critical) },
+ { FLAG, offsetof(private_delete_payload_t, critical) },
/* 7 Bit reserved bits */
{ RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) },
{ RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) },
@@ -98,7 +105,47 @@ encoding_rule_t delete_payload_encodings[] = {
{ U_INT_8, offsetof(private_delete_payload_t, spi_size) },
{ U_INT_16, offsetof(private_delete_payload_t, spi_count) },
/* some delete data bytes, length is defined in PAYLOAD_LENGTH */
- { SPIS, offsetof(private_delete_payload_t, spis) }
+ { CHUNK_DATA, offsetof(private_delete_payload_t, spis) },
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload !C! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Protocol ID ! SPI Size ! # of SPIs !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Security Parameter Index(es) (SPI) ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Encoding rules for an IKEv1 delete payload.
+ */
+static encoding_rule_t encodings_v1[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_delete_payload_t, next_payload) },
+ /* 8 Bit reserved bits */
+ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) },
+ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) },
+ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[2]) },
+ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[3]) },
+ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[4]) },
+ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[5]) },
+ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[6]) },
+ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[7]) },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length) },
+ /* Domain of interpretation */
+ { U_INT_32, offsetof(private_delete_payload_t, doi) },
+ { U_INT_8, offsetof(private_delete_payload_t, protocol_id) },
+ { U_INT_8, offsetof(private_delete_payload_t, spi_size) },
+ { U_INT_16, offsetof(private_delete_payload_t, spi_count) },
+ /* some delete data bytes, length is defined in PAYLOAD_LENGTH */
+ { CHUNK_DATA, offsetof(private_delete_payload_t, spis) },
};
/*
@@ -107,6 +154,8 @@ encoding_rule_t delete_payload_encodings[] = {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Next Payload !C! RESERVED ! Payload Length !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! DOI !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! Protocol ID ! SPI Size ! # of SPIs !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! !
@@ -129,10 +178,19 @@ METHOD(payload_t, verify, status_t,
break;
case PROTO_IKE:
case 0:
- /* IKE deletion has no spi assigned! */
- if (this->spi_size != 0)
- {
- return FAILED;
+ if (this->type == DELETE)
+ { /* IKEv2 deletion has no spi assigned! */
+ if (this->spi_size != 0)
+ {
+ return FAILED;
+ }
+ }
+ else
+ { /* IKEv1 uses the two concatenated ISAKMP cookies as SPI */
+ if (this->spi_size != 16)
+ {
+ return FAILED;
+ }
}
break;
default:
@@ -145,17 +203,32 @@ METHOD(payload_t, verify, status_t,
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_delete_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_delete_payload_t *this, encoding_rule_t **rules)
{
- *rules = delete_payload_encodings;
- *rule_count = countof(delete_payload_encodings);
+ if (this->type == DELETE)
+ {
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+ }
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_delete_payload_t *this)
+{
+ if (this->type == DELETE)
+ {
+ return 8;
+ }
+ return 12;
}
METHOD(payload_t, get_payload_type, payload_type_t,
private_delete_payload_t *this)
{
- return DELETE;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -198,6 +271,16 @@ METHOD(delete_payload_t, add_spi, void,
}
}
+METHOD(delete_payload_t, set_ike_spi, void,
+ private_delete_payload_t *this, u_int64_t spi_i, u_int64_t spi_r)
+{
+ free(this->spis.ptr);
+ this->spis = chunk_cat("cc", chunk_from_thing(spi_i),
+ chunk_from_thing(spi_r));
+ this->spi_count = 1;
+ this->payload_length = get_header_length(this) + this->spi_size;
+}
+
/**
* SPI enumerator implementation
*/
@@ -249,7 +332,8 @@ METHOD2(payload_t, delete_payload_t, destroy, void,
/*
* Described in header
*/
-delete_payload_t *delete_payload_create(protocol_id_t protocol_id)
+delete_payload_t *delete_payload_create(payload_type_t type,
+ protocol_id_t protocol_id)
{
private_delete_payload_t *this;
@@ -258,6 +342,7 @@ delete_payload_t *delete_payload_create(protocol_id_t protocol_id)
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -266,13 +351,27 @@ delete_payload_t *delete_payload_create(protocol_id_t protocol_id)
},
.get_protocol_id = _get_protocol_id,
.add_spi = _add_spi,
+ .set_ike_spi = _set_ike_spi,
.create_spi_enumerator = _create_spi_enumerator,
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = DELETE_PAYLOAD_HEADER_LENGTH,
.protocol_id = protocol_id,
- .spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0,
+ .doi = IKEV1_DOI_IPSEC,
+ .type = type,
);
+ this->payload_length = get_header_length(this);
+
+ if (protocol_id == PROTO_IKE)
+ {
+ if (type == DELETE_V1)
+ {
+ this->spi_size = 16;
+ }
+ }
+ else
+ {
+ this->spi_size = 4;
+ }
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/delete_payload.h b/src/libcharon/encoding/payloads/delete_payload.h
index 026829f97..afce1ecf1 100644
--- a/src/libcharon/encoding/payloads/delete_payload.h
+++ b/src/libcharon/encoding/payloads/delete_payload.h
@@ -29,14 +29,7 @@ typedef struct delete_payload_t delete_payload_t;
#include <encoding/payloads/proposal_substructure.h>
/**
- * Length of a delete payload without the SPI in bytes.
- */
-#define DELETE_PAYLOAD_HEADER_LENGTH 8
-
-/**
- * Class representing an IKEv2 DELETE payload.
- *
- * The DELETE payload format is described in RFC section 3.11.
+ * Class representing an IKEv1 or a IKEv2 DELETE payload.
*/
struct delete_payload_t {
@@ -60,6 +53,14 @@ struct delete_payload_t {
void (*add_spi) (delete_payload_t *this, u_int32_t spi);
/**
+ * Set the IKE SPIs for an IKEv1 delete.
+ *
+ * @param spi_i initiator SPI
+ * @param spi_r responder SPI
+ */
+ void (*set_ike_spi)(delete_payload_t *this, u_int64_t spi_i, u_int64_t spi_r);
+
+ /**
* Get an enumerator over the SPIs in network order.
*
* @return enumerator over SPIs, u_int32_t
@@ -75,9 +76,11 @@ struct delete_payload_t {
/**
* Creates an empty delete_payload_t object.
*
+ * @param type DELETE or DELETE_V1
* @param protocol_id protocol, such as AH|ESP
* @return delete_payload_t object
*/
-delete_payload_t *delete_payload_create(protocol_id_t protocol_id);
+delete_payload_t *delete_payload_create(payload_type_t type,
+ protocol_id_t protocol_id);
#endif /** DELETE_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c
index cacaef222..dd2e25795 100644
--- a/src/libcharon/encoding/payloads/eap_payload.c
+++ b/src/libcharon/encoding/payloads/eap_payload.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2010 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -19,6 +20,8 @@
#include "eap_payload.h"
#include <daemon.h>
+#include <eap/eap.h>
+#include <bio/bio_writer.h>
typedef struct private_eap_payload_t private_eap_payload_t;
@@ -65,7 +68,7 @@ struct private_eap_payload_t {
* private_eap_payload_t.
*
*/
-static encoding_rule_t eap_payload_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_eap_payload_t, next_payload) },
/* the critical bit */
@@ -81,7 +84,7 @@ static encoding_rule_t eap_payload_encodings[] = {
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length) },
/* chunt to data, starting at "code" */
- { EAP_DATA, offsetof(private_eap_payload_t, data) },
+ { CHUNK_DATA, offsetof(private_eap_payload_t, data) },
};
/*
@@ -143,11 +146,17 @@ METHOD(payload_t, verify, status_t,
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_eap_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_eap_payload_t *this, encoding_rule_t **rules)
{
- *rules = eap_payload_encodings;
- *rule_count = sizeof(eap_payload_encodings) / sizeof(encoding_rule_t);
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_eap_payload_t *this)
+{
+ return 4;
}
METHOD(payload_t, get_payload_type, payload_type_t,
@@ -210,28 +219,93 @@ METHOD(eap_payload_t, get_identifier, u_int8_t,
return 0;
}
+/**
+ * Get the current type at the given offset into this->data.
+ * @return the new offset or 0 if failed
+ */
+static size_t extract_type(private_eap_payload_t *this, size_t offset,
+ eap_type_t *type, u_int32_t *vendor)
+{
+ if (this->data.len > offset)
+ {
+ *vendor = 0;
+ *type = this->data.ptr[offset];
+ if (*type != EAP_EXPANDED)
+ {
+ return offset + 1;
+ }
+ if (this->data.len >= offset + 8)
+ {
+ *vendor = untoh32(this->data.ptr + offset) & 0x00FFFFFF;
+ *type = untoh32(this->data.ptr + offset + 4);
+ return offset + 8;
+ }
+ }
+ return 0;
+}
+
METHOD(eap_payload_t, get_type, eap_type_t,
private_eap_payload_t *this, u_int32_t *vendor)
{
eap_type_t type;
*vendor = 0;
- if (this->data.len > 4)
+ if (extract_type(this, 4, &type, vendor))
{
- type = this->data.ptr[4];
- if (type != EAP_EXPANDED)
- {
- return type;
- }
- if (this->data.len >= 12)
- {
- *vendor = untoh32(this->data.ptr + 4) & 0x00FFFFFF;
- return untoh32(this->data.ptr + 8);
- }
+ return type;
}
return 0;
}
+/**
+ * Type enumerator
+ */
+typedef struct {
+ /** public interface */
+ enumerator_t public;
+ /** payload */
+ private_eap_payload_t *payload;
+ /** current offset in the data */
+ size_t offset;
+} type_enumerator_t;
+
+METHOD(enumerator_t, enumerate_types, bool,
+ type_enumerator_t *this, eap_type_t *type, u_int32_t *vendor)
+{
+ this->offset = extract_type(this->payload, this->offset, type, vendor);
+ return this->offset;
+}
+
+METHOD(eap_payload_t, get_types, enumerator_t*,
+ private_eap_payload_t *this)
+{
+ type_enumerator_t *enumerator;
+ eap_type_t type;
+ u_int32_t vendor;
+ size_t offset;
+
+ offset = extract_type(this, 4, &type, &vendor);
+ if (offset && type == EAP_NAK)
+ {
+ INIT(enumerator,
+ .public = {
+ .enumerate = (void*)_enumerate_types,
+ .destroy = (void*)free,
+ },
+ .payload = this,
+ .offset = offset,
+ );
+ return &enumerator->public;
+ }
+ return enumerator_create_empty();
+}
+
+METHOD(eap_payload_t, is_expanded, bool,
+ private_eap_payload_t *this)
+{
+ return this->data.len > 4 ? this->data.ptr[4] == EAP_EXPANDED : FALSE;
+}
+
METHOD2(payload_t, eap_payload_t, destroy, void,
private_eap_payload_t *this)
{
@@ -251,6 +325,7 @@ eap_payload_t *eap_payload_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -262,10 +337,12 @@ eap_payload_t *eap_payload_create()
.get_code = _get_code,
.get_identifier = _get_identifier,
.get_type = _get_type,
+ .get_types = _get_types,
+ .is_expanded = _is_expanded,
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = EAP_PAYLOAD_HEADER_LENGTH,
+ .payload_length = get_header_length(this),
);
return &this->public;
}
@@ -305,15 +382,81 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier)
return eap_payload_create_data(data);
}
+/**
+ * Write the given type either expanded or not
+ */
+static void write_type(bio_writer_t *writer, eap_type_t type, u_int32_t vendor,
+ bool expanded)
+{
+ if (expanded)
+ {
+ writer->write_uint8(writer, EAP_EXPANDED);
+ writer->write_uint24(writer, vendor);
+ writer->write_uint32(writer, type);
+ }
+ else
+ {
+ writer->write_uint8(writer, type);
+ }
+}
+
/*
* Described in header
*/
-eap_payload_t *eap_payload_create_nak(u_int8_t identifier)
+eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type,
+ u_int32_t vendor, bool expanded)
{
- chunk_t data;
+ enumerator_t *enumerator;
+ eap_type_t reg_type;
+ u_int32_t reg_vendor;
+ bio_writer_t *writer;
+ chunk_t length, data;
+ bool added_any = FALSE, found_vendor = FALSE;
+ eap_payload_t *payload;
+
+ writer = bio_writer_create(12);
+ writer->write_uint8(writer, EAP_RESPONSE);
+ writer->write_uint8(writer, identifier);
+ length = writer->skip(writer, 2);
+
+ write_type(writer, EAP_NAK, 0, expanded);
+
+ enumerator = charon->eap->create_enumerator(charon->eap, EAP_PEER);
+ while (enumerator->enumerate(enumerator, &reg_type, &reg_vendor))
+ {
+ if ((type && type != reg_type) ||
+ (type && vendor && vendor != reg_vendor))
+ { /* the preferred type is only sent if we actually find it */
+ continue;
+ }
+ if (!reg_vendor || expanded)
+ {
+ write_type(writer, reg_type, reg_vendor, expanded);
+ added_any = TRUE;
+ }
+ else if (reg_vendor)
+ { /* found vendor specifc method, but this is not an expanded Nak */
+ found_vendor = TRUE;
+ }
+ }
+ enumerator->destroy(enumerator);
- data = chunk_from_chars(EAP_RESPONSE, identifier, 0, 0, EAP_NAK);
- htoun16(data.ptr + 2, data.len);
- return eap_payload_create_data(data);
+ if (found_vendor)
+ { /* request an expanded authentication type */
+ write_type(writer, EAP_EXPANDED, 0, expanded);
+ added_any = TRUE;
+ }
+ if (!added_any)
+ { /* no methods added */
+ write_type(writer, 0, 0, expanded);
+ }
+
+ /* set length */
+ data = writer->get_buf(writer);
+ htoun16(length.ptr, data.len);
+
+ payload = eap_payload_create_data(data);
+ writer->destroy(writer);
+ return payload;
}
diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h
index 60d9c99d2..e8ed1c5e7 100644
--- a/src/libcharon/encoding/payloads/eap_payload.h
+++ b/src/libcharon/encoding/payloads/eap_payload.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -25,13 +26,8 @@
typedef struct eap_payload_t eap_payload_t;
#include <library.h>
+#include <eap/eap.h>
#include <encoding/payloads/payload.h>
-#include <sa/authenticators/eap/eap_method.h>
-
-/**
- * Length of a EAP payload without the EAP Message in bytes.
- */
-#define EAP_PAYLOAD_HEADER_LENGTH 4
/**
* Class representing an IKEv2 EAP payload.
@@ -87,6 +83,21 @@ struct eap_payload_t {
eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor);
/**
+ * Enumerate the EAP method types contained in an EAP-Nak (i.e. get_type()
+ * returns EAP_NAK).
+ *
+ * @return enumerator over (eap_type_t type, u_int32_t vendor)
+ */
+ enumerator_t* (*get_types) (eap_payload_t *this);
+
+ /**
+ * Check if the EAP method type is encoded in the Expanded Type format.
+ *
+ * @return TRUE if in Expanded Type format
+ */
+ bool (*is_expanded) (eap_payload_t *this);
+
+ /**
* Destroys an eap_payload_t object.
*/
void (*destroy) (eap_payload_t *this);
@@ -131,8 +142,12 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier);
* Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK.
*
* @param identifier EAP identifier to use in payload
+ * @param type preferred auth type, 0 to send all supported types
+ * @param vendor vendor identifier for auth type, 0 for default
+ * @param expanded TRUE to send an expanded Nak
* @return eap_payload_t object
*/
-eap_payload_t *eap_payload_create_nak(u_int8_t identifier);
+eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type,
+ u_int32_t vendor, bool expanded);
#endif /** EAP_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c
index 85caeda82..62de81120 100644
--- a/src/libcharon/encoding/payloads/encodings.c
+++ b/src/libcharon/encoding/payloads/encodings.c
@@ -29,30 +29,14 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA,
"HEADER_LENGTH",
"SPI_SIZE",
"SPI",
- "KEY_EXCHANGE_DATA",
- "NOTIFICATION_DATA",
- "PROPOSALS",
- "TRANSFORMS",
- "TRANSFORM_ATTRIBUTES",
- "CONFIGURATION_ATTRIBUTES",
- "CONFIGURATION_ATTRIBUTE_VALUE",
"ATTRIBUTE_FORMAT",
"ATTRIBUTE_TYPE",
"ATTRIBUTE_LENGTH_OR_VALUE",
- "CONFIGURATION_ATTRIBUTE_LENGTH",
+ "ATTRIBUTE_LENGTH",
"ATTRIBUTE_VALUE",
- "TRAFFIC_SELECTORS",
"TS_TYPE",
"ADDRESS",
- "NONCE_DATA",
- "ID_DATA",
- "AUTH_DATA",
- "CERT_DATA",
- "CERTREQ_DATA",
- "EAP_DATA",
- "SPIS",
- "VID_DATA",
- "UNKNOWN_DATA",
+ "CHUNK_DATA",
"IKE_SPI",
"ENCRYPTED_DATA",
);
diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h
index 52af4a984..54830bc8c 100644
--- a/src/libcharon/encoding/payloads/encodings.h
+++ b/src/libcharon/encoding/payloads/encodings.h
@@ -187,87 +187,6 @@ enum encoding_type_t {
SPI,
/**
- * Representating a Key Exchange Data field.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
- */
- KEY_EXCHANGE_DATA,
-
- /**
- * Representating a Notification field.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - spi size - 8) bytes are read and written into the chunk pointing to.
- */
- NOTIFICATION_DATA,
-
- /**
- * Representating one or more proposal substructures.
- *
- * The offset points to a linked_list_t pointer.
- *
- * When generating the proposal_substructure_t objects are stored
- * in the pointed linked_list.
- *
- * When parsing the parsed proposal_substructure_t objects have
- * to be stored in the pointed linked_list.
- */
- PROPOSALS,
-
- /**
- * Representating one or more transform substructures.
- *
- * The offset points to a linked_list_t pointer.
- *
- * When generating the transform_substructure_t objects are stored
- * in the pointed linked_list.
- *
- * When parsing the parsed transform_substructure_t objects have
- * to be stored in the pointed linked_list.
- */
- TRANSFORMS,
-
- /**
- * Representating one or more Attributes of a transform substructure.
- *
- * The offset points to a linked_list_t pointer.
- *
- * When generating the transform_attribute_t objects are stored
- * in the pointed linked_list.
- *
- * When parsing the parsed transform_attribute_t objects have
- * to be stored in the pointed linked_list.
- */
- TRANSFORM_ATTRIBUTES,
-
- /**
- * Representating one or more Attributes of a configuration payload.
- *
- * The offset points to a linked_list_t pointer.
- *
- * When generating the configuration_attribute_t objects are stored
- * in the pointed linked_list.
- *
- * When parsing the parsed configuration_attribute_t objects have
- * to be stored in the pointed linked_list.
- */
- CONFIGURATION_ATTRIBUTES,
-
- /**
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
- */
- CONFIGURATION_ATTRIBUTE_VALUE,
-
- /**
* Representing a 1 Bit flag specifying the format of a transform attribute.
*
* When generation, the next bit is set to 1 if the associated value
@@ -279,6 +198,7 @@ enum encoding_type_t {
* is moved 1 bit forward afterwards.
*/
ATTRIBUTE_FORMAT,
+
/**
* Representing a 15 Bit unsigned int value used as attribute type
* in an attribute transform.
@@ -321,7 +241,7 @@ enum encoding_type_t {
* The value is written to the associated data struct.
* The current read pointer is moved 16 bit forward afterwards.
*/
- CONFIGURATION_ATTRIBUTE_LENGTH,
+ ATTRIBUTE_LENGTH,
/**
* Depending on the field of type ATTRIBUTE_FORMAT
@@ -336,19 +256,6 @@ enum encoding_type_t {
ATTRIBUTE_VALUE,
/**
- * Representating one or more Traffic selectors of a TS payload.
- *
- * The offset points to a linked_list_t pointer.
- *
- * When generating the traffic_selector_substructure_t objects are stored
- * in the pointed linked_list.
- *
- * When parsing the parsed traffic_selector_substructure_t objects have
- * to be stored in the pointed linked_list.
- */
- TRAFFIC_SELECTORS,
-
- /**
* Representating a Traffic selector type field.
*
* When generating it must be changed from host to network order.
@@ -375,94 +282,9 @@ enum encoding_type_t {
ADDRESS,
/**
- * Representating a Nonce Data field.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
+ * Representing a variable length byte field.
*/
- NONCE_DATA,
-
- /**
- * Representating a ID Data field.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
- */
- ID_DATA,
-
- /**
- * Representating a AUTH Data field.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
- */
- AUTH_DATA,
-
- /**
- * Representating a CERT Data field.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to.
- */
- CERT_DATA,
-
- /**
- * Representating a CERTREQ Data field.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to.
- */
- CERTREQ_DATA,
-
- /**
- * Representating an EAP message field.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
- */
- EAP_DATA,
-
- /**
- * Representating the SPIS field in a DELETE payload.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to.
- */
- SPIS,
-
- /**
- * Representating the VID DATA field in a VENDOR ID payload.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
- */
- VID_DATA,
-
- /**
- * Representating the DATA of an unknown payload.
- *
- * When generating the content of the chunkt pointing to
- * is written.
- *
- * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to.
- */
- UNKNOWN_DATA,
+ CHUNK_DATA,
/**
* Representating an IKE_SPI field in an IKEv2 Header.
@@ -475,9 +297,20 @@ enum encoding_type_t {
IKE_SPI,
/**
- * Representing the encrypted data body of a encryption payload.
+ * Representating an encrypted IKEv1 message.
*/
ENCRYPTED_DATA,
+
+ /**
+ * Reprensenting a field containing a set of wrapped payloads.
+ *
+ * This type is not used directly, but as an offset to the wrapped payloads.
+ * The type of the wrapped payload is added to this encoding type.
+ *
+ * @note As payload types are added to this encoding type, it has
+ * to be the last in encoding_type_t.
+ */
+ PAYLOAD_LIST = 1000 /* no comma, read above! */
};
/**
diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c
index e7b8063b7..02e7b8bf3 100644
--- a/src/libcharon/encoding/payloads/encryption_payload.c
+++ b/src/libcharon/encoding/payloads/encryption_payload.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2005-2010 Martin Willi
* Copyright (C) 2010 revosec AG
+ * Copyright (C) 2011 Tobias Brunner
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -71,6 +72,11 @@ struct private_encryption_payload_t {
* Contained payloads
*/
linked_list_t *payloads;
+
+ /**
+ * Type of payload, ENCRYPTED or ENCRYPTED_V1
+ */
+ payload_type_t type;
};
/**
@@ -79,7 +85,7 @@ struct private_encryption_payload_t {
* The defined offsets are the positions in a object of type
* private_encryption_payload_t.
*/
-encoding_rule_t encryption_payload_encodings[] = {
+static encoding_rule_t encodings_v2[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_encryption_payload_t, next_payload) },
/* Critical and 7 reserved bits, all stored for reconstruction */
@@ -87,7 +93,7 @@ encoding_rule_t encryption_payload_encodings[] = {
/* Length of the whole encryption payload*/
{ PAYLOAD_LENGTH, offsetof(private_encryption_payload_t, payload_length) },
/* encrypted data, stored in a chunk. contains iv, data, padding */
- { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) },
+ { CHUNK_DATA, offsetof(private_encryption_payload_t, encrypted) },
};
/*
@@ -109,24 +115,59 @@ encoding_rule_t encryption_payload_encodings[] = {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
+/**
+ * Encoding rules to parse or generate a complete encrypted IKEv1 message.
+ *
+ * The defined offsets are the positions in a object of type
+ * private_encryption_payload_t.
+ */
+static encoding_rule_t encodings_v1[] = {
+ /* encrypted data, stored in a chunk */
+ { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) },
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Encrypted IKE Payloads !
+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! ! Padding (0-255 octets) !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
METHOD(payload_t, verify, status_t,
private_encryption_payload_t *this)
{
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_encryption_payload_t *this, encoding_rule_t **rules,
- size_t *count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_encryption_payload_t *this, encoding_rule_t **rules)
+{
+ if (this->type == ENCRYPTED)
+ {
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+ }
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_encryption_payload_t *this)
{
- *rules = encryption_payload_encodings;
- *count = countof(encryption_payload_encodings);
+ if (this->type == ENCRYPTED)
+ {
+ return 4;
+ }
+ return 0;
}
METHOD(payload_t, get_type, payload_type_t,
private_encryption_payload_t *this)
{
- return ENCRYPTED;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -138,7 +179,8 @@ METHOD(payload_t, get_next_type, payload_type_t,
METHOD(payload_t, set_next_type, void,
private_encryption_payload_t *this, payload_type_t type)
{
- /* the next payload is set during add */
+ /* the next payload is set during add, still allow this for IKEv1 */
+ this->next_payload = type;
}
/**
@@ -174,7 +216,7 @@ static void compute_length(private_encryption_payload_t *this)
length += this->aead->get_icv_size(this->aead);
}
}
- length += ENCRYPTION_PAYLOAD_HEADER_LENGTH;
+ length += get_header_length(this);
this->payload_length = length;
}
@@ -266,7 +308,7 @@ static chunk_t append_header(private_encryption_payload_t *this, chunk_t assoc)
return chunk_cat("cc", assoc, chunk_from_thing(header));
}
-METHOD(encryption_payload_t, encrypt, bool,
+METHOD(encryption_payload_t, encrypt, status_t,
private_encryption_payload_t *this, chunk_t assoc)
{
chunk_t iv, plain, padding, icv, crypt;
@@ -277,14 +319,14 @@ METHOD(encryption_payload_t, encrypt, bool,
if (this->aead == NULL)
{
DBG1(DBG_ENC, "encrypting encryption payload failed, transform missing");
- return FALSE;
+ return INVALID_STATE;
}
rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK);
if (!rng)
{
DBG1(DBG_ENC, "encrypting encryption payload failed, no RNG found");
- return FALSE;
+ return NOT_SUPPORTED;
}
assoc = append_header(this, assoc);
@@ -314,8 +356,14 @@ METHOD(encryption_payload_t, encrypt, bool,
crypt = chunk_create(plain.ptr, plain.len + padding.len);
generator->destroy(generator);
- rng->get_bytes(rng, iv.len, iv.ptr);
- rng->get_bytes(rng, padding.len - 1, padding.ptr);
+ if (!rng->get_bytes(rng, iv.len, iv.ptr) ||
+ !rng->get_bytes(rng, padding.len - 1, padding.ptr))
+ {
+ DBG1(DBG_ENC, "encrypting encryption payload failed, no IV or padding");
+ rng->destroy(rng);
+ free(assoc.ptr);
+ return FAILED;
+ }
padding.ptr[padding.len - 1] = padding.len - 1;
rng->destroy(rng);
@@ -325,14 +373,60 @@ METHOD(encryption_payload_t, encrypt, bool,
DBG3(DBG_ENC, "padding %B", &padding);
DBG3(DBG_ENC, "assoc %B", &assoc);
- this->aead->encrypt(this->aead, crypt, assoc, iv, NULL);
+ if (!this->aead->encrypt(this->aead, crypt, assoc, iv, NULL))
+ {
+ free(assoc.ptr);
+ return FAILED;
+ }
DBG3(DBG_ENC, "encrypted %B", &crypt);
DBG3(DBG_ENC, "ICV %B", &icv);
free(assoc.ptr);
- return TRUE;
+ return SUCCESS;
+}
+
+METHOD(encryption_payload_t, encrypt_v1, status_t,
+ private_encryption_payload_t *this, chunk_t iv)
+{
+ generator_t *generator;
+ chunk_t plain, padding;
+ size_t bs;
+
+ if (this->aead == NULL)
+ {
+ DBG1(DBG_ENC, "encryption failed, transform missing");
+ return INVALID_STATE;
+ }
+
+ generator = generator_create();
+ plain = generate(this, generator);
+ bs = this->aead->get_block_size(this->aead);
+ padding.len = bs - (plain.len % bs);
+
+ /* prepare data to encrypt:
+ * | plain | padding | */
+ free(this->encrypted.ptr);
+ this->encrypted = chunk_alloc(plain.len + padding.len);
+ memcpy(this->encrypted.ptr, plain.ptr, plain.len);
+ plain.ptr = this->encrypted.ptr;
+ padding.ptr = plain.ptr + plain.len;
+ memset(padding.ptr, 0, padding.len);
+ generator->destroy(generator);
+
+ DBG3(DBG_ENC, "encrypting payloads:");
+ DBG3(DBG_ENC, "plain %B", &plain);
+ DBG3(DBG_ENC, "padding %B", &padding);
+
+ if (!this->aead->encrypt(this->aead, this->encrypted, chunk_empty, iv, NULL))
+ {
+ return FAILED;
+ }
+
+ DBG3(DBG_ENC, "encrypted %B", &this->encrypted);
+
+ return SUCCESS;
}
/**
@@ -349,6 +443,13 @@ static status_t parse(private_encryption_payload_t *this, chunk_t plain)
{
payload_t *payload;
+ if (plain.len < 4 || untoh16(plain.ptr + 2) > plain.len)
+ {
+ DBG1(DBG_ENC, "invalid %N payload length, decryption failed?",
+ payload_type_names, type);
+ parser->destroy(parser);
+ return PARSE_ERROR;
+ }
if (parser->parse_payload(parser, type, &payload) != SUCCESS)
{
parser->destroy(parser);
@@ -438,6 +539,36 @@ METHOD(encryption_payload_t, decrypt, status_t,
return parse(this, plain);
}
+METHOD(encryption_payload_t, decrypt_v1, status_t,
+ private_encryption_payload_t *this, chunk_t iv)
+{
+ if (this->aead == NULL)
+ {
+ DBG1(DBG_ENC, "decryption failed, transform missing");
+ return INVALID_STATE;
+ }
+
+ /* data must be a multiple of block size */
+ if (iv.len != this->aead->get_block_size(this->aead) ||
+ this->encrypted.len < iv.len || this->encrypted.len % iv.len)
+ {
+ DBG1(DBG_ENC, "decryption failed, invalid length");
+ return FAILED;
+ }
+
+ DBG3(DBG_ENC, "decrypting payloads:");
+ DBG3(DBG_ENC, "encrypted %B", &this->encrypted);
+
+ if (!this->aead->decrypt(this->aead, this->encrypted, chunk_empty, iv, NULL))
+ {
+ return FAILED;
+ }
+
+ DBG3(DBG_ENC, "plain %B", &this->encrypted);
+
+ return parse(this, this->encrypted);
+}
+
METHOD(encryption_payload_t, set_transform, void,
private_encryption_payload_t *this, aead_t* aead)
{
@@ -455,7 +586,7 @@ METHOD2(payload_t, encryption_payload_t, destroy, void,
/*
* Described in header
*/
-encryption_payload_t *encryption_payload_create()
+encryption_payload_t *encryption_payload_create(payload_type_t type)
{
private_encryption_payload_t *this;
@@ -464,6 +595,7 @@ encryption_payload_t *encryption_payload_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -479,9 +611,16 @@ encryption_payload_t *encryption_payload_create()
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = ENCRYPTION_PAYLOAD_HEADER_LENGTH,
.payloads = linked_list_create(),
+ .type = type,
);
+ this->payload_length = get_header_length(this);
+
+ if (type == ENCRYPTED_V1)
+ {
+ this->public.encrypt = _encrypt_v1;
+ this->public.decrypt = _decrypt_v1;
+ }
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/encryption_payload.h b/src/libcharon/encoding/payloads/encryption_payload.h
index e99c42fb7..5c6069339 100644
--- a/src/libcharon/encoding/payloads/encryption_payload.h
+++ b/src/libcharon/encoding/payloads/encryption_payload.h
@@ -30,11 +30,6 @@ typedef struct encryption_payload_t encryption_payload_t;
#include <encoding/payloads/payload.h>
/**
- * Encrpytion payload length in bytes without IV and following data.
- */
-#define ENCRYPTION_PAYLOAD_HEADER_LENGTH 4
-
-/**
* The encryption payload as described in RFC section 3.14.
*/
struct encryption_payload_t {
@@ -77,14 +72,18 @@ struct encryption_payload_t {
* Generate, encrypt and sign contained payloads.
*
* @param assoc associated data
- * @return TRUE if encrypted
+ * @return
+ * - SUCCESS if encryption successful
+ * - FAILED if encryption failed
+ * - INVALID_STATE if aead not supplied, but needed
*/
- bool (*encrypt) (encryption_payload_t *this, chunk_t assoc);
+ status_t (*encrypt) (encryption_payload_t *this, chunk_t assoc);
/**
* Decrypt, verify and parse contained payloads.
*
* @param assoc associated data
+ * @return
* - SUCCESS if parsing successful
* - PARSE_ERROR if sub-payload parsing failed
* - VERIFY_ERROR if sub-payload verification failed
@@ -102,8 +101,9 @@ struct encryption_payload_t {
/**
* Creates an empty encryption_payload_t object.
*
+ * @param type ENCRYPTED or ENCRYPTED_V1
* @return encryption_payload_t object
*/
-encryption_payload_t *encryption_payload_create(void);
+encryption_payload_t *encryption_payload_create(payload_type_t type);
#endif /** ENCRYPTION_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/endpoint_notify.c b/src/libcharon/encoding/payloads/endpoint_notify.c
index 1ead0a052..25fb42acd 100644
--- a/src/libcharon/encoding/payloads/endpoint_notify.c
+++ b/src/libcharon/encoding/payloads/endpoint_notify.c
@@ -227,7 +227,7 @@ METHOD(endpoint_notify_t, build_notify, notify_payload_t*,
chunk_t data;
notify_payload_t *notify;
- notify = notify_payload_create();
+ notify = notify_payload_create(NOTIFY);
notify->set_notify_type(notify, ME_ENDPOINT);
data = build_notification_data(this);
notify->set_notification_data(notify, data);
diff --git a/src/libcharon/encoding/payloads/hash_payload.c b/src/libcharon/encoding/payloads/hash_payload.c
new file mode 100644
index 000000000..0cf63ba67
--- /dev/null
+++ b/src/libcharon/encoding/payloads/hash_payload.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+#include <stddef.h>
+
+#include "hash_payload.h"
+
+#include <encoding/payloads/encodings.h>
+
+typedef struct private_hash_payload_t private_hash_payload_t;
+
+/**
+ * Private data of an hash_payload_t object.
+ */
+struct private_hash_payload_t {
+
+ /**
+ * Public hash_payload_t interface.
+ */
+ hash_payload_t public;
+
+ /**
+ * Next payload type.
+ */
+ u_int8_t next_payload;
+
+ /**
+ * Reserved byte
+ */
+ u_int8_t reserved;
+
+ /**
+ * Length of this payload.
+ */
+ u_int16_t payload_length;
+
+ /**
+ * The contained hash value.
+ */
+ chunk_t hash;
+
+ /**
+ * either HASH_V1 or NAT_D_V1
+ */
+ payload_type_t type;
+};
+
+/**
+ * Encoding rules for an IKEv1 hash payload
+ */
+static encoding_rule_t encodings[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_hash_payload_t, next_payload) },
+ { RESERVED_BYTE, offsetof(private_hash_payload_t, reserved) },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_hash_payload_t, payload_length) },
+ /* Hash Data is from variable size */
+ { CHUNK_DATA, offsetof(private_hash_payload_t, hash) },
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Hash Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+METHOD(payload_t, verify, status_t,
+ private_hash_payload_t *this)
+{
+ return SUCCESS;
+}
+
+METHOD(payload_t, get_encoding_rules, int,
+ private_hash_payload_t *this, encoding_rule_t **rules)
+{
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_hash_payload_t *this)
+{
+ return 4;
+}
+
+METHOD(payload_t, get_type, payload_type_t,
+ private_hash_payload_t *this)
+{
+ return this->type;
+}
+
+METHOD(payload_t, get_next_type, payload_type_t,
+ private_hash_payload_t *this)
+{
+ return this->next_payload;
+}
+
+METHOD(payload_t, set_next_type, void,
+ private_hash_payload_t *this, payload_type_t type)
+{
+ this->next_payload = type;
+}
+
+METHOD(payload_t, get_length, size_t,
+ private_hash_payload_t *this)
+{
+ return this->payload_length;
+}
+
+METHOD(hash_payload_t, set_hash, void,
+ private_hash_payload_t *this, chunk_t hash)
+{
+ free(this->hash.ptr);
+ this->hash = chunk_clone(hash);
+ this->payload_length = get_header_length(this) + hash.len;
+}
+
+METHOD(hash_payload_t, get_hash, chunk_t,
+ private_hash_payload_t *this)
+{
+ return this->hash;
+}
+
+METHOD2(payload_t, hash_payload_t, destroy, void,
+ private_hash_payload_t *this)
+{
+ free(this->hash.ptr);
+ free(this);
+}
+
+/*
+ * Described in header
+ */
+hash_payload_t *hash_payload_create(payload_type_t type)
+{
+ private_hash_payload_t *this;
+
+ INIT(this,
+ .public = {
+ .payload_interface = {
+ .verify = _verify,
+ .get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
+ .get_length = _get_length,
+ .get_next_type = _get_next_type,
+ .set_next_type = _set_next_type,
+ .get_type = _get_type,
+ .destroy = _destroy,
+ },
+ .set_hash = _set_hash,
+ .get_hash = _get_hash,
+ .destroy = _destroy,
+ },
+ .next_payload = NO_PAYLOAD,
+ .payload_length = get_header_length(this),
+ .type = type,
+ );
+ return &this->public;
+}
diff --git a/src/libcharon/encoding/payloads/hash_payload.h b/src/libcharon/encoding/payloads/hash_payload.h
new file mode 100644
index 000000000..cfe28460c
--- /dev/null
+++ b/src/libcharon/encoding/payloads/hash_payload.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 Martin Willi
+ * Copyright (C) 2011 revosec AG
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup hash_payload hash_payload
+ * @{ @ingroup payloads
+ */
+
+#ifndef HASH_PAYLOAD_H_
+#define HASH_PAYLOAD_H_
+
+typedef struct hash_payload_t hash_payload_t;
+
+#include <library.h>
+#include <encoding/payloads/payload.h>
+
+/**
+ * Object representing an IKEv1 hash payload.
+ */
+struct hash_payload_t {
+
+ /**
+ * The payload_t interface.
+ */
+ payload_t payload_interface;
+
+ /**
+ * Set the hash value.
+ *
+ * @param hash chunk containing the hash, will be cloned
+ */
+ void (*set_hash) (hash_payload_t *this, chunk_t hash);
+
+ /**
+ * Get the hash value.
+ *
+ * @return chunkt to internal hash data
+ */
+ chunk_t (*get_hash) (hash_payload_t *this);
+
+ /**
+ * Destroys an hash_payload_t object.
+ */
+ void (*destroy) (hash_payload_t *this);
+};
+
+/**
+ * Creates an empty hash_payload_t object.
+ *
+ * @param type either HASH_V1 or NAT_D_V1
+ * @return hash_payload_t object
+ */
+hash_payload_t *hash_payload_create(payload_type_t type);
+
+#endif /** HASH_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c
index 3befadfe2..02b07d691 100644
--- a/src/libcharon/encoding/payloads/id_payload.c
+++ b/src/libcharon/encoding/payloads/id_payload.c
@@ -1,9 +1,8 @@
/*
- * Copyright (C) 2005-2010 Martin Willi
+ * Copyright (C) 2005-2011 Martin Willi
* Copyright (C) 2010 revosec AG
- * Copyright (C) 2007 Tobias Brunner
+ * Copyright (C) 2007-2011 Tobias Brunner
* Copyright (C) 2005 Jan Hutter
- *
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
@@ -28,20 +27,15 @@ typedef struct private_id_payload_t private_id_payload_t;
/**
* Private data of an id_payload_t object.
- *
*/
struct private_id_payload_t {
+
/**
* Public id_payload_t interface.
*/
id_payload_t public;
/**
- * one of ID_INITIATOR, ID_RESPONDER
- */
- payload_type_t payload_type;
-
- /**
* Next payload type.
*/
u_int8_t next_payload;
@@ -75,19 +69,31 @@ struct private_id_payload_t {
* The contained id data value.
*/
chunk_t id_data;
+
+ /**
+ * Tunneled protocol ID for IKEv1 quick modes.
+ */
+ u_int8_t protocol_id;
+
+ /**
+ * Tunneled port for IKEv1 quick modes.
+ */
+ u_int16_t port;
+
+ /**
+ * one of ID_INITIATOR, ID_RESPONDER, IDv1 and NAT_OA_V1
+ */
+ payload_type_t type;
};
/**
- * Encoding rules to parse or generate a ID payload
- *
- * The defined offsets are the positions in a object of type
- * private_id_payload_t.
+ * Encoding rules for an IKEv2 ID payload
*/
-encoding_rule_t id_payload_encodings[] = {
+static encoding_rule_t encodings_v2[] = {
/* 1 Byte next payload type, stored in the field next_payload */
- { U_INT_8, offsetof(private_id_payload_t, next_payload) },
+ { U_INT_8, offsetof(private_id_payload_t, next_payload) },
/* the critical bit */
- { FLAG, offsetof(private_id_payload_t, critical) },
+ { FLAG, offsetof(private_id_payload_t, critical) },
/* 7 Bit reserved bits */
{ RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[0]) },
{ RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[1]) },
@@ -97,7 +103,7 @@ encoding_rule_t id_payload_encodings[] = {
{ RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[5]) },
{ RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[6]) },
/* Length of the whole payload*/
- { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) },
+ { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) },
/* 1 Byte ID type*/
{ U_INT_8, offsetof(private_id_payload_t, id_type) },
/* 3 reserved bytes */
@@ -105,7 +111,7 @@ encoding_rule_t id_payload_encodings[] = {
{ RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[1])},
{ RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[2])},
/* some id data bytes, length is defined in PAYLOAD_LENGTH */
- { ID_DATA, offsetof(private_id_payload_t, id_data) }
+ { CHUNK_DATA, offsetof(private_id_payload_t, id_data) },
};
/*
@@ -122,29 +128,92 @@ encoding_rule_t id_payload_encodings[] = {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
+/**
+ * Encoding rules for an IKEv1 ID payload
+ */
+static encoding_rule_t encodings_v1[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_id_payload_t, next_payload) },
+ /* Reserved Byte is skipped */
+ { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[0])},
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) },
+ /* 1 Byte ID type*/
+ { U_INT_8, offsetof(private_id_payload_t, id_type) },
+ { U_INT_8, offsetof(private_id_payload_t, protocol_id) },
+ { U_INT_16, offsetof(private_id_payload_t, port) },
+ /* some id data bytes, length is defined in PAYLOAD_LENGTH */
+ { CHUNK_DATA, offsetof(private_id_payload_t, id_data) },
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! ID Type ! Protocol ID ! Port |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Identification Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
METHOD(payload_t, verify, status_t,
private_id_payload_t *this)
{
- if (this->id_type == 0 || this->id_type == 4)
+ bool bad_length = FALSE;
+
+ if (this->type == NAT_OA_V1 &&
+ this->id_type != ID_IPV4_ADDR && this->id_type != ID_IPV6_ADDR)
+ {
+ DBG1(DBG_ENC, "invalid ID type %N for %N payload", id_type_names,
+ this->id_type, payload_type_short_names, this->type);
+ return FAILED;
+ }
+ switch (this->id_type)
+ {
+ case ID_IPV4_ADDR_RANGE:
+ case ID_IPV4_ADDR_SUBNET:
+ bad_length = this->id_data.len != 8;
+ break;
+ case ID_IPV6_ADDR_RANGE:
+ case ID_IPV6_ADDR_SUBNET:
+ bad_length = this->id_data.len != 32;
+ break;
+ }
+ if (bad_length)
{
- /* reserved IDs */
- DBG1(DBG_ENC, "received ID with reserved type %d", this->id_type);
+ DBG1(DBG_ENC, "invalid %N length (%d bytes)",
+ id_type_names, this->id_type, this->id_data.len);
return FAILED;
}
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_id_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_id_payload_t *this, encoding_rule_t **rules)
+{
+ if (this->type == ID_V1 || this->type == NAT_OA_V1)
+ {
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+ }
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_id_payload_t *this)
{
- *rules = id_payload_encodings;
- *rule_count = countof(id_payload_encodings);
+ return 8;
}
METHOD(payload_t, get_type, payload_type_t,
private_id_payload_t *this)
{
- return this->payload_type;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -171,6 +240,102 @@ METHOD(id_payload_t, get_identification, identification_t*,
return identification_create_from_encoding(this->id_type, this->id_data);
}
+/**
+ * Create a traffic selector from an range ID
+ */
+static traffic_selector_t *get_ts_from_range(private_id_payload_t *this,
+ ts_type_t type)
+{
+ return traffic_selector_create_from_bytes(this->protocol_id, type,
+ chunk_create(this->id_data.ptr, this->id_data.len / 2), this->port,
+ chunk_skip(this->id_data, this->id_data.len / 2), this->port ?: 65535);
+}
+
+/**
+ * Create a traffic selector from an subnet ID
+ */
+static traffic_selector_t *get_ts_from_subnet(private_id_payload_t *this,
+ ts_type_t type)
+{
+ chunk_t net, netmask;
+ int i;
+
+ net = chunk_create(this->id_data.ptr, this->id_data.len / 2);
+ netmask = chunk_skip(this->id_data, this->id_data.len / 2);
+ for (i = 0; i < net.len; i++)
+ {
+ netmask.ptr[i] = (netmask.ptr[i] ^ 0xFF) | net.ptr[i];
+ }
+ return traffic_selector_create_from_bytes(this->protocol_id, type,
+ net, this->port, netmask, this->port ?: 65535);
+}
+
+/**
+ * Create a traffic selector from an IP ID
+ */
+static traffic_selector_t *get_ts_from_ip(private_id_payload_t *this,
+ ts_type_t type)
+{
+ return traffic_selector_create_from_bytes(this->protocol_id, type,
+ this->id_data, this->port, this->id_data, this->port ?: 65535);
+}
+
+METHOD(id_payload_t, get_ts, traffic_selector_t*,
+ private_id_payload_t *this)
+{
+ switch (this->id_type)
+ {
+ case ID_IPV4_ADDR_SUBNET:
+ if (this->id_data.len == 8)
+ {
+ return get_ts_from_subnet(this, TS_IPV4_ADDR_RANGE);
+ }
+ break;
+ case ID_IPV6_ADDR_SUBNET:
+ if (this->id_data.len == 32)
+ {
+ return get_ts_from_subnet(this, TS_IPV6_ADDR_RANGE);
+ }
+ break;
+ case ID_IPV4_ADDR_RANGE:
+ if (this->id_data.len == 8)
+ {
+ return get_ts_from_range(this, TS_IPV4_ADDR_RANGE);
+ }
+ break;
+ case ID_IPV6_ADDR_RANGE:
+ if (this->id_data.len == 32)
+ {
+ return get_ts_from_range(this, TS_IPV6_ADDR_RANGE);
+ }
+ break;
+ case ID_IPV4_ADDR:
+ if (this->id_data.len == 4)
+ {
+ return get_ts_from_ip(this, TS_IPV4_ADDR_RANGE);
+ }
+ break;
+ case ID_IPV6_ADDR:
+ if (this->id_data.len == 16)
+ {
+ return get_ts_from_ip(this, TS_IPV6_ADDR_RANGE);
+ }
+ break;
+ default:
+ break;
+ }
+ return NULL;
+}
+
+METHOD(id_payload_t, get_encoded, chunk_t,
+ private_id_payload_t *this)
+{
+ u_int16_t port = htons(this->port);
+ return chunk_cat("cccc", chunk_from_thing(this->id_type),
+ chunk_from_thing(this->protocol_id),
+ chunk_from_thing(port), this->id_data);
+}
+
METHOD2(payload_t, id_payload_t, destroy, void,
private_id_payload_t *this)
{
@@ -181,7 +346,7 @@ METHOD2(payload_t, id_payload_t, destroy, void,
/*
* Described in header.
*/
-id_payload_t *id_payload_create(payload_type_t payload_type)
+id_payload_t *id_payload_create(payload_type_t type)
{
private_id_payload_t *this;
@@ -190,6 +355,7 @@ id_payload_t *id_payload_create(payload_type_t payload_type)
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -197,11 +363,13 @@ id_payload_t *id_payload_create(payload_type_t payload_type)
.destroy = _destroy,
},
.get_identification = _get_identification,
+ .get_encoded = _get_encoded,
+ .get_ts = _get_ts,
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = ID_PAYLOAD_HEADER_LENGTH,
- .payload_type = payload_type,
+ .payload_length = get_header_length(this),
+ .type = type,
);
return &this->public;
}
@@ -209,15 +377,89 @@ id_payload_t *id_payload_create(payload_type_t payload_type)
/*
* Described in header.
*/
-id_payload_t *id_payload_create_from_identification(payload_type_t payload_type,
+id_payload_t *id_payload_create_from_identification(payload_type_t type,
identification_t *id)
{
private_id_payload_t *this;
- this = (private_id_payload_t*)id_payload_create(payload_type);
+ this = (private_id_payload_t*)id_payload_create(type);
this->id_data = chunk_clone(id->get_encoding(id));
this->id_type = id->get_type(id);
this->payload_length += this->id_data.len;
return &this->public;
}
+
+/*
+ * Described in header.
+ */
+id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts)
+{
+ private_id_payload_t *this;
+ u_int8_t mask;
+ host_t *net;
+
+ this = (private_id_payload_t*)id_payload_create(ID_V1);
+
+ if (ts->is_host(ts, NULL))
+ {
+ if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE)
+ {
+ this->id_type = ID_IPV4_ADDR;
+ }
+ else
+ {
+ this->id_type = ID_IPV6_ADDR;
+ }
+ this->id_data = chunk_clone(ts->get_from_address(ts));
+ }
+ else if (ts->to_subnet(ts, &net, &mask))
+ {
+ u_int8_t netmask[16], len, byte;
+
+ if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE)
+ {
+ this->id_type = ID_IPV4_ADDR_SUBNET;
+ len = 4;
+ }
+ else
+ {
+ this->id_type = ID_IPV6_ADDR_SUBNET;
+ len = 16;
+ }
+ memset(netmask, 0, sizeof(netmask));
+ for (byte = 0; byte < sizeof(netmask); byte++)
+ {
+ if (mask < 8)
+ {
+ netmask[byte] = 0xFF << (8 - mask);
+ break;
+ }
+ netmask[byte] = 0xFF;
+ mask -= 8;
+ }
+ this->id_data = chunk_cat("cc", net->get_address(net),
+ chunk_create(netmask, len));
+ net->destroy(net);
+ }
+ else
+ {
+ if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE)
+ {
+ this->id_type = ID_IPV4_ADDR_RANGE;
+ }
+ else
+ {
+ this->id_type = ID_IPV6_ADDR_RANGE;
+ }
+ this->id_data = chunk_cat("cc",
+ ts->get_from_address(ts), ts->get_to_address(ts));
+ net->destroy(net);
+ }
+ this->port = ts->get_from_port(ts);
+ this->protocol_id = ts->get_protocol(ts);
+ this->payload_length += this->id_data.len;
+
+ return &this->public;
+}
+
diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h
index 99831f85f..9a6249429 100644
--- a/src/libcharon/encoding/payloads/id_payload.h
+++ b/src/libcharon/encoding/payloads/id_payload.h
@@ -28,16 +28,10 @@ typedef struct id_payload_t id_payload_t;
#include <library.h>
#include <utils/identification.h>
#include <encoding/payloads/payload.h>
+#include <selectors/traffic_selector.h>
/**
- * Length of a id payload without the data in bytes.
- */
-#define ID_PAYLOAD_HEADER_LENGTH 8
-
-/**
- * Object representing an IKEv2 ID payload.
- *
- * The ID payload format is described in RFC section 3.5.
+ * Object representing an IKEv1 or an IKEv2 ID payload.
*/
struct id_payload_t {
@@ -54,6 +48,20 @@ struct id_payload_t {
identification_t *(*get_identification) (id_payload_t *this);
/**
+ * Creates a traffic selector form a ID_ADDR_SUBNET/RANGE identity.
+ *
+ * @return traffic selector, NULL on failure
+ */
+ traffic_selector_t* (*get_ts)(id_payload_t *this);
+
+ /**
+ * Get encoded payload without fixed payload header (used for IKEv1).
+ *
+ * @return encoded payload (gets allocated)
+ */
+ chunk_t (*get_encoded)(id_payload_t *this);
+
+ /**
* Destroys an id_payload_t object.
*/
void (*destroy) (id_payload_t *this);
@@ -62,19 +70,27 @@ struct id_payload_t {
/**
* Creates an empty id_payload_t object.
*
- * @param payload_type one of ID_INITIATOR, ID_RESPONDER
- * @return id_payload_t object
+ * @param type one of ID_INITIATOR, ID_RESPONDER, ID_V1 and NAT_OA_V1
+ * @return id_payload_t object
*/
-id_payload_t *id_payload_create(payload_type_t payload_type);
+id_payload_t *id_payload_create(payload_type_t type);
/**
* Creates an id_payload_t from an existing identification_t object.
*
- * @param payload_type one of ID_INITIATOR, ID_RESPONDER
- * @param identification identification_t object
- * @return id_payload_t object
+ * @param type one of ID_INITIATOR, ID_RESPONDER, ID_V1 and NAT_OA_V1
+ * @param id identification_t object
+ * @return id_payload_t object
+ */
+id_payload_t *id_payload_create_from_identification(payload_type_t type,
+ identification_t *id);
+
+/**
+ * Create an IKEv1 ID_ADDR_SUBNET/RANGE identity from a traffic selector.
+ *
+ * @param ts traffic selector
+ * @return ID_V1 id_paylad_t object.
*/
-id_payload_t *id_payload_create_from_identification(payload_type_t payload_type,
- identification_t *identification);
+id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts);
#endif /** ID_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/ike_header.c b/src/libcharon/encoding/payloads/ike_header.c
index 24d22f3a1..58b624192 100644
--- a/src/libcharon/encoding/payloads/ike_header.c
+++ b/src/libcharon/encoding/payloads/ike_header.c
@@ -81,12 +81,27 @@ struct private_ike_header_t {
* TRUE, if this is a response, FALSE if its a Request.
*/
bool response;
+
+ /**
+ * TRUE, if the packet is encrypted (IKEv1).
+ */
+ bool encryption;
+
+ /**
+ * TRUE, if the commit flag is set (IKEv1).
+ */
+ bool commit;
+
+ /**
+ * TRUE, if the auth only flag is set (IKEv1).
+ */
+ bool authonly;
} flags;
/**
* Reserved bits of IKE header
*/
- bool reserved[5];
+ bool reserved[2];
/**
* Associated Message-ID.
@@ -99,9 +114,15 @@ struct private_ike_header_t {
u_int32_t length;
};
-ENUM_BEGIN(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, EXCHANGE_TYPE_UNDEFINED,
- "EXCHANGE_TYPE_UNDEFINED");
-ENUM_NEXT(exchange_type_names, IKE_SA_INIT, IKE_SESSION_RESUME, EXCHANGE_TYPE_UNDEFINED,
+ENUM_BEGIN(exchange_type_names, ID_PROT, TRANSACTION,
+ "ID_PROT",
+ "AUTH_ONLY",
+ "AGGRESSIVE",
+ "INFORMATIONAL_V1",
+ "TRANSACTION");
+ENUM_NEXT(exchange_type_names, QUICK_MODE, IKE_SESSION_RESUME, TRANSACTION,
+ "QUICK_MODE",
+ "NEW_GROUP_MODE",
"IKE_SA_INIT",
"IKE_AUTH",
"CREATE_CHILD_SA",
@@ -110,18 +131,23 @@ ENUM_NEXT(exchange_type_names, IKE_SA_INIT, IKE_SESSION_RESUME, EXCHANGE_TYPE_UN
#ifdef ME
ENUM_NEXT(exchange_type_names, ME_CONNECT, ME_CONNECT, IKE_SESSION_RESUME,
"ME_CONNECT");
-ENUM_END(exchange_type_names, ME_CONNECT);
+ENUM_NEXT(exchange_type_names, EXCHANGE_TYPE_UNDEFINED,
+ EXCHANGE_TYPE_UNDEFINED, ME_CONNECT,
+ "EXCHANGE_TYPE_UNDEFINED");
#else
-ENUM_END(exchange_type_names, IKE_SESSION_RESUME);
+ENUM_NEXT(exchange_type_names, EXCHANGE_TYPE_UNDEFINED,
+ EXCHANGE_TYPE_UNDEFINED, IKE_SESSION_RESUME,
+ "EXCHANGE_TYPE_UNDEFINED");
#endif /* ME */
+ENUM_END(exchange_type_names, EXCHANGE_TYPE_UNDEFINED);
/**
- * Encoding rules to parse or generate a IKEv2-Header.
+ * Encoding rules to parse or generate a IKE-Header.
*
* The defined offsets are the positions in a object of type
* ike_header_t.
*/
-encoding_rule_t ike_header_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 8 Byte SPI, stored in the field initiator_spi */
{ IKE_SPI, offsetof(private_ike_header_t, initiator_spi) },
/* 8 Byte SPI, stored in the field responder_spi */
@@ -137,22 +163,20 @@ encoding_rule_t ike_header_encodings[] = {
/* 2 Bit reserved bits */
{ RESERVED_BIT, offsetof(private_ike_header_t, reserved[0]) },
{ RESERVED_BIT, offsetof(private_ike_header_t, reserved[1]) },
- /* 3 Bit flags, stored in the fields response, version and initiator */
+ /* 6 flags */
{ FLAG, offsetof(private_ike_header_t, flags.response) },
{ FLAG, offsetof(private_ike_header_t, flags.version) },
{ FLAG, offsetof(private_ike_header_t, flags.initiator) },
- /* 3 Bit reserved bits */
- { RESERVED_BIT, offsetof(private_ike_header_t, reserved[2]) },
- { RESERVED_BIT, offsetof(private_ike_header_t, reserved[3]) },
- { RESERVED_BIT, offsetof(private_ike_header_t, reserved[4]) },
+ { FLAG, offsetof(private_ike_header_t, flags.authonly) },
+ { FLAG, offsetof(private_ike_header_t, flags.commit) },
+ { FLAG, offsetof(private_ike_header_t, flags.encryption)},
/* 4 Byte message id, stored in the field message_id */
{ U_INT_32, offsetof(private_ike_header_t, message_id) },
/* 4 Byte length fied, stored in the field length */
- { HEADER_LENGTH,offsetof(private_ike_header_t, length) },
+ { HEADER_LENGTH, offsetof(private_ike_header_t, length) }
};
-
-/* 1 2 3
+/* 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
! IKE_SA Initiator's SPI !
@@ -172,35 +196,67 @@ encoding_rule_t ike_header_encodings[] = {
METHOD(payload_t, verify, status_t,
private_ike_header_t *this)
{
- if ((this->exchange_type < IKE_SA_INIT) ||
- ((this->exchange_type > INFORMATIONAL)
+ switch (this->exchange_type)
+ {
+ case ID_PROT:
+ case AGGRESSIVE:
+ if (this->message_id != 0)
+ {
+ return FAILED;
+ }
+ /* fall */
+ case AUTH_ONLY:
+ case INFORMATIONAL_V1:
+ case TRANSACTION:
+ case QUICK_MODE:
+ case NEW_GROUP_MODE:
+ if (this->maj_version != IKEV1_MAJOR_VERSION)
+ {
+ return FAILED;
+ }
+ break;
+ case IKE_SA_INIT:
+ case IKE_AUTH:
+ case CREATE_CHILD_SA:
+ case INFORMATIONAL:
+ case IKE_SESSION_RESUME:
#ifdef ME
- && (this->exchange_type != ME_CONNECT)
+ case ME_CONNECT:
#endif /* ME */
- ))
- {
- /* unsupported exchange type */
- return FAILED;
+ if (this->maj_version != IKEV2_MAJOR_VERSION)
+ {
+ return FAILED;
+ }
+ break;
+ default:
+ /* unsupported exchange type */
+ return FAILED;
}
- if (this->initiator_spi == 0
+ if (this->initiator_spi == 0)
+ {
#ifdef ME
- /* we allow zero spi for INFORMATIONAL exchanges,
- * to allow connectivity checks */
- && this->exchange_type != INFORMATIONAL
+ if (this->exchange_type != INFORMATIONAL)
+ /* we allow zero spi for INFORMATIONAL exchanges,
+ * to allow connectivity checks */
#endif /* ME */
- )
- {
- /* initiator spi not set */
- return FAILED;
+ {
+ return FAILED;
+ }
}
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_ike_header_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_ike_header_t *this, encoding_rule_t **rules)
+{
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_ike_header_t *this)
{
- *rules = ike_header_encodings;
- *rule_count = sizeof(ike_header_encodings) / sizeof(encoding_rule_t);
+ return IKE_HEADER_LENGTH;
}
METHOD(payload_t, get_type, payload_type_t,
@@ -311,6 +367,43 @@ METHOD(ike_header_t, set_initiator_flag, void,
this->flags.initiator = initiator;
}
+METHOD(ike_header_t, get_encryption_flag, bool,
+ private_ike_header_t *this)
+{
+ return this->flags.encryption;
+}
+
+METHOD(ike_header_t, set_encryption_flag, void,
+ private_ike_header_t *this, bool encryption)
+{
+ this->flags.encryption = encryption;
+}
+
+
+METHOD(ike_header_t, get_commit_flag, bool,
+ private_ike_header_t *this)
+{
+ return this->flags.commit;
+}
+
+METHOD(ike_header_t, set_commit_flag, void,
+ private_ike_header_t *this, bool commit)
+{
+ this->flags.commit = commit;
+}
+
+METHOD(ike_header_t, get_authonly_flag, bool,
+ private_ike_header_t *this)
+{
+ return this->flags.authonly;
+}
+
+METHOD(ike_header_t, set_authonly_flag, void,
+ private_ike_header_t *this, bool authonly)
+{
+ this->flags.authonly = authonly;
+}
+
METHOD(ike_header_t, get_exchange_type, u_int8_t,
private_ike_header_t *this)
{
@@ -353,6 +446,7 @@ ike_header_t *ike_header_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -373,21 +467,38 @@ ike_header_t *ike_header_create()
.set_version_flag = _set_version_flag,
.get_initiator_flag = _get_initiator_flag,
.set_initiator_flag = _set_initiator_flag,
+ .get_encryption_flag = _get_encryption_flag,
+ .set_encryption_flag = _set_encryption_flag,
+ .get_commit_flag = _get_commit_flag,
+ .set_commit_flag = _set_commit_flag,
+ .get_authonly_flag = _get_authonly_flag,
+ .set_authonly_flag = _set_authonly_flag,
.get_exchange_type = _get_exchange_type,
.set_exchange_type = _set_exchange_type,
.get_message_id = _get_message_id,
.set_message_id = _set_message_id,
.destroy = _destroy,
},
- .maj_version = IKE_MAJOR_VERSION,
- .min_version = IKE_MINOR_VERSION,
- .exchange_type = EXCHANGE_TYPE_UNDEFINED,
- .flags = {
- .initiator = TRUE,
- .version = HIGHER_VERSION_SUPPORTED_FLAG,
- },
.length = IKE_HEADER_LENGTH,
+ .exchange_type = EXCHANGE_TYPE_UNDEFINED,
);
return &this->public;
}
+
+/*
+ * Described in header.
+ */
+ike_header_t *ike_header_create_version(int major, int minor)
+{
+ ike_header_t *this = ike_header_create();
+
+ this->set_maj_version(this, major);
+ this->set_min_version(this, minor);
+ if (major == IKEV2_MAJOR_VERSION)
+ {
+ this->set_initiator_flag(this, TRUE);
+ }
+ return this;
+}
+
diff --git a/src/libcharon/encoding/payloads/ike_header.h b/src/libcharon/encoding/payloads/ike_header.h
index 5579a4961..e6b7d0dff 100644
--- a/src/libcharon/encoding/payloads/ike_header.h
+++ b/src/libcharon/encoding/payloads/ike_header.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 Tobias Brunner
- * Copyright (C) 2005-2006 Martin Willi
+ * Copyright (C) 2005-2011 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
*
@@ -30,19 +30,24 @@ typedef struct ike_header_t ike_header_t;
#include <encoding/payloads/payload.h>
/**
- * Major Version of IKEv2.
+ * Major Version of IKEv1 we implement.
*/
-#define IKE_MAJOR_VERSION 2
+#define IKEV1_MAJOR_VERSION 1
/**
- * Minor Version of IKEv2.
+ * Minor Version of IKEv1 we implement.
*/
-#define IKE_MINOR_VERSION 0
+#define IKEV1_MINOR_VERSION 0
/**
- * Flag in IKEv2-Header. Always 0.
+ * Major Version of IKEv2 we implement.
*/
-#define HIGHER_VERSION_SUPPORTED_FLAG 0
+#define IKEV2_MAJOR_VERSION 2
+
+/**
+ * Minor Version of IKEv2 we implement.
+ */
+#define IKEV2_MINOR_VERSION 0
/**
* Length of IKE Header in Bytes.
@@ -57,9 +62,39 @@ typedef struct ike_header_t ike_header_t;
enum exchange_type_t{
/**
- * EXCHANGE_TYPE_UNDEFINED. In private space, since not a official message type.
+ * Identity Protection (Main mode).
*/
- EXCHANGE_TYPE_UNDEFINED = 255,
+ ID_PROT = 2,
+
+ /**
+ * Authentication Only.
+ */
+ AUTH_ONLY = 3,
+
+ /**
+ * Aggresive (Aggressive mode)
+ */
+ AGGRESSIVE = 4,
+
+ /**
+ * Informational in IKEv1
+ */
+ INFORMATIONAL_V1 = 5,
+
+ /**
+ * Transaction (ISAKMP Cfg Mode "draft-ietf-ipsec-isakmp-mode-cfg-05")
+ */
+ TRANSACTION = 6,
+
+ /**
+ * Quick Mode
+ */
+ QUICK_MODE = 32,
+
+ /**
+ * New Group Mode
+ */
+ NEW_GROUP_MODE = 33,
/**
* IKE_SA_INIT.
@@ -77,7 +112,7 @@ enum exchange_type_t{
CREATE_CHILD_SA = 36,
/**
- * INFORMATIONAL.
+ * INFORMATIONAL in IKEv2.
*/
INFORMATIONAL = 37,
@@ -85,12 +120,18 @@ enum exchange_type_t{
* IKE_SESSION_RESUME (RFC 5723).
*/
IKE_SESSION_RESUME = 38,
+
#ifdef ME
/**
* ME_CONNECT
*/
- ME_CONNECT = 240
+ ME_CONNECT = 240,
#endif /* ME */
+
+ /**
+ * Undefined exchange type, in private space.
+ */
+ EXCHANGE_TYPE_UNDEFINED = 255,
};
/**
@@ -99,12 +140,7 @@ enum exchange_type_t{
extern enum_name_t *exchange_type_names;
/**
- * An object of this type represents an IKEv2 header and is used to
- * generate and parse IKEv2 headers.
- *
- * The header format of an IKEv2-Message is compatible to the
- * ISAKMP-Header format to allow implementations supporting
- * both versions of the IKE-protocol.
+ * An object of this type represents an IKE header of either IKEv1 or IKEv2.
*/
struct ike_header_t {
/**
@@ -115,7 +151,7 @@ struct ike_header_t {
/**
* Get the initiator spi.
*
- * @return initiator_spi
+ * @return initiator_spi
*/
u_int64_t (*get_initiator_spi) (ike_header_t *this);
@@ -129,7 +165,7 @@ struct ike_header_t {
/**
* Get the responder spi.
*
- * @return responder_spi
+ * @return responder_spi
*/
u_int64_t (*get_responder_spi) (ike_header_t *this);
@@ -143,7 +179,7 @@ struct ike_header_t {
/**
* Get the major version.
*
- * @return major version
+ * @return major version
*/
u_int8_t (*get_maj_version) (ike_header_t *this);
@@ -157,7 +193,7 @@ struct ike_header_t {
/**
* Get the minor version.
*
- * @return minor version
+ * @return minor version
*/
u_int8_t (*get_min_version) (ike_header_t *this);
@@ -171,7 +207,7 @@ struct ike_header_t {
/**
* Get the response flag.
*
- * @return response flag
+ * @return response flag
*/
bool (*get_response_flag) (ike_header_t *this);
@@ -185,7 +221,7 @@ struct ike_header_t {
/**
* Get "higher version supported"-flag.
*
- * @return version flag
+ * @return version flag
*/
bool (*get_version_flag) (ike_header_t *this);
@@ -199,7 +235,7 @@ struct ike_header_t {
/**
* Get the initiator flag.
*
- * @return initiator flag
+ * @return initiator flag
*/
bool (*get_initiator_flag) (ike_header_t *this);
@@ -211,9 +247,51 @@ struct ike_header_t {
void (*set_initiator_flag) (ike_header_t *this, bool initiator);
/**
+ * Get the encryption flag.
+ *
+ * @return encryption flag
+ */
+ bool (*get_encryption_flag) (ike_header_t *this);
+
+ /**
+ * Set the encryption flag.
+ *
+ * @param encryption encryption flag
+ */
+ void (*set_encryption_flag) (ike_header_t *this, bool encryption);
+
+ /**
+ * Get the commit flag.
+ *
+ * @return commit flag
+ */
+ bool (*get_commit_flag) (ike_header_t *this);
+
+ /**
+ * Set the commit flag.
+ *
+ * @param commit commit flag
+ */
+ void (*set_commit_flag) (ike_header_t *this, bool commit);
+
+ /**
+ * Get the authentication only flag.
+ *
+ * @return authonly flag
+ */
+ bool (*get_authonly_flag) (ike_header_t *this);
+
+ /**
+ * Set the authentication only flag.
+ *
+ * @param authonly authonly flag
+ */
+ void (*set_authonly_flag) (ike_header_t *this, bool authonly);
+
+ /**
* Get the exchange type.
*
- * @return exchange type
+ * @return exchange type
*/
u_int8_t (*get_exchange_type) (ike_header_t *this);
@@ -227,7 +305,7 @@ struct ike_header_t {
/**
* Get the message id.
*
- * @return message id
+ * @return message id
*/
u_int32_t (*get_message_id) (ike_header_t *this);
@@ -245,10 +323,17 @@ struct ike_header_t {
};
/**
- * Create an ike_header_t object
+ * Create an empty ike_header_t object.
*
* @return ike_header_t object
*/
ike_header_t *ike_header_create(void);
+/**
+ * Create an ike_header_t object for a specific major/minor version
+ *
+ * @return ike_header_t object
+ */
+ike_header_t *ike_header_create_version(int major, int minor);
+
#endif /** IKE_HEADER_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/ke_payload.c b/src/libcharon/encoding/payloads/ke_payload.c
index 999d73192..438ea46b9 100644
--- a/src/libcharon/encoding/payloads/ke_payload.c
+++ b/src/libcharon/encoding/payloads/ke_payload.c
@@ -67,15 +67,17 @@ struct private_ke_payload_t {
* Key Exchange Data of this KE payload.
*/
chunk_t key_exchange_data;
+
+ /**
+ * Payload type, KEY_EXCHANGE or KEY_EXCHANGE_V1
+ */
+ payload_type_t type;
};
/**
- * Encoding rules to parse or generate a IKEv2-KE Payload.
- *
- * The defined offsets are the positions in a object of type
- * private_ke_payload_t.
+ * Encoding rules for IKEv2 key exchange payload.
*/
-encoding_rule_t ke_payload_encodings[] = {
+static encoding_rule_t encodings_v2[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_ke_payload_t, next_payload) },
/* the critical bit */
@@ -96,7 +98,7 @@ encoding_rule_t ke_payload_encodings[] = {
{ RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[0])},
{ RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[1])},
/* Key Exchange Data is from variable size */
- { KEY_EXCHANGE_DATA, offsetof(private_ke_payload_t, key_exchange_data)}
+ { CHUNK_DATA, offsetof(private_ke_payload_t, key_exchange_data)},
};
/*
@@ -113,23 +115,62 @@ encoding_rule_t ke_payload_encodings[] = {
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
+static encoding_rule_t encodings_v1[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_ke_payload_t, next_payload) },
+ /* Reserved Byte */
+ { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[0])},
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_ke_payload_t, payload_length) },
+ /* Key Exchange Data is from variable size */
+ { CHUNK_DATA, offsetof(private_ke_payload_t, key_exchange_data)},
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Key Exchange Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+
METHOD(payload_t, verify, status_t,
private_ke_payload_t *this)
{
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_ke_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_ke_payload_t *this, encoding_rule_t **rules)
+{
+ if (this->type == KEY_EXCHANGE)
+ {
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+ }
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_ke_payload_t *this)
{
- *rules = ke_payload_encodings;
- *rule_count = countof(ke_payload_encodings);
+ if (this->type == KEY_EXCHANGE)
+ {
+ return 8;
+ }
+ return 4;
}
METHOD(payload_t, get_type, payload_type_t,
private_ke_payload_t *this)
{
- return KEY_EXCHANGE;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -172,7 +213,7 @@ METHOD2(payload_t, ke_payload_t, destroy, void,
/*
* Described in header
*/
-ke_payload_t *ke_payload_create()
+ke_payload_t *ke_payload_create(payload_type_t type)
{
private_ke_payload_t *this;
@@ -181,6 +222,7 @@ ke_payload_t *ke_payload_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -192,22 +234,24 @@ ke_payload_t *ke_payload_create()
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = KE_PAYLOAD_HEADER_LENGTH,
.dh_group_number = MODP_NONE,
+ .type = type,
);
+ this->payload_length = get_header_length(this);
return &this->public;
}
/*
* Described in header
*/
-ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *dh)
+ke_payload_t *ke_payload_create_from_diffie_hellman(payload_type_t type,
+ diffie_hellman_t *dh)
{
- private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create();
+ private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create(type);
dh->get_my_public_value(dh, &this->key_exchange_data);
this->dh_group_number = dh->get_dh_group(dh);
- this->payload_length = this->key_exchange_data.len + KE_PAYLOAD_HEADER_LENGTH;
+ this->payload_length += this->key_exchange_data.len;
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/ke_payload.h b/src/libcharon/encoding/payloads/ke_payload.h
index 65cc11883..5942954d9 100644
--- a/src/libcharon/encoding/payloads/ke_payload.h
+++ b/src/libcharon/encoding/payloads/ke_payload.h
@@ -31,16 +31,10 @@ typedef struct ke_payload_t ke_payload_t;
#include <crypto/diffie_hellman.h>
/**
- * KE payload length in bytes without any key exchange data.
- */
-#define KE_PAYLOAD_HEADER_LENGTH 8
-
-/**
- * Class representing an IKEv2-KE Payload.
- *
- * The KE Payload format is described in RFC section 3.4.
+ * Class representing an IKEv1 or IKEv2 key exchange payload.
*/
struct ke_payload_t {
+
/**
* The payload_t interface.
*/
@@ -54,32 +48,34 @@ struct ke_payload_t {
chunk_t (*get_key_exchange_data) (ke_payload_t *this);
/**
- * Gets the Diffie-Hellman Group Number of this KE payload.
+ * Gets the Diffie-Hellman Group Number of this KE payload (IKEv2 only).
*
* @return DH Group Number of this payload
*/
diffie_hellman_group_t (*get_dh_group_number) (ke_payload_t *this);
/**
- * Destroys an ke_payload_t object.
+ * Destroys a ke_payload_t object.
*/
void (*destroy) (ke_payload_t *this);
};
/**
- * Creates an empty ke_payload_t object
+ * Creates an empty ke_payload_t object.
*
- * @return ke_payload_t object
+ * @param type KEY_EXCHANGE or KEY_EXCHANGE_V1
+ * @return ke_payload_t object
*/
-ke_payload_t *ke_payload_create(void);
+ke_payload_t *ke_payload_create(payload_type_t type);
/**
- * Creates a ke_payload_t from a diffie_hellman_t
+ * Creates a ke_payload_t from a diffie_hellman_t.
*
- * @param diffie_hellman diffie hellman object containing group and key
- * @return ke_payload_t object
+ * @param type KEY_EXCHANGE or KEY_EXCHANGE_V1
+ * @param dh diffie hellman object containing group and key
+ * @return ke_payload_t object
*/
-ke_payload_t *ke_payload_create_from_diffie_hellman(
- diffie_hellman_t *diffie_hellman);
+ke_payload_t *ke_payload_create_from_diffie_hellman(payload_type_t type,
+ diffie_hellman_t *dh);
#endif /** KE_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/nonce_payload.c b/src/libcharon/encoding/payloads/nonce_payload.c
index 78000b8c6..3c5eeb535 100644
--- a/src/libcharon/encoding/payloads/nonce_payload.c
+++ b/src/libcharon/encoding/payloads/nonce_payload.c
@@ -19,6 +19,7 @@
#include "nonce_payload.h"
+#include <daemon.h>
#include <encoding/payloads/encodings.h>
typedef struct private_nonce_payload_t private_nonce_payload_t;
@@ -57,6 +58,11 @@ struct private_nonce_payload_t {
* The contained nonce value.
*/
chunk_t nonce;
+
+ /**
+ * Payload type, NONCE or NONCE_V1
+ */
+ payload_type_t type;
};
/**
@@ -65,7 +71,7 @@ struct private_nonce_payload_t {
* The defined offsets are the positions in a object of type
* private_nonce_payload_t.
*/
-encoding_rule_t nonce_payload_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_nonce_payload_t, next_payload) },
/* the critical bit */
@@ -81,7 +87,7 @@ encoding_rule_t nonce_payload_encodings[] = {
/* Length of the whole nonce payload*/
{ PAYLOAD_LENGTH, offsetof(private_nonce_payload_t, payload_length) },
/* some nonce bytes, lenth is defined in PAYLOAD_LENGTH */
- { NONCE_DATA, offsetof(private_nonce_payload_t, nonce) },
+ { CHUNK_DATA, offsetof(private_nonce_payload_t, nonce) },
};
/* 1 2 3
@@ -98,24 +104,48 @@ encoding_rule_t nonce_payload_encodings[] = {
METHOD(payload_t, verify, status_t,
private_nonce_payload_t *this)
{
- if (this->nonce.len < 16 || this->nonce.len > 256)
+ bool bad_length = FALSE;
+
+ if (this->nonce.len > 256)
+ {
+ bad_length = TRUE;
+ }
+ if (this->type == NONCE &&
+ this->nonce.len < 16)
+ {
+ bad_length = TRUE;
+ }
+ if (this->type == NONCE_V1 &&
+ this->nonce.len < 8)
+ {
+ bad_length = TRUE;
+ }
+ if (bad_length)
{
+ DBG1(DBG_ENC, "%N payload has invalid length (%d bytes)",
+ payload_type_names, this->type, this->nonce.len);
return FAILED;
}
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_nonce_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_nonce_payload_t *this, encoding_rule_t **rules)
+{
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_nonce_payload_t *this)
{
- *rules = nonce_payload_encodings;
- *rule_count = countof(nonce_payload_encodings);
+ return 4;
}
METHOD(payload_t, get_type, payload_type_t,
private_nonce_payload_t *this)
{
- return NONCE;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -140,7 +170,7 @@ METHOD(nonce_payload_t, set_nonce, void,
private_nonce_payload_t *this, chunk_t nonce)
{
this->nonce = chunk_clone(nonce);
- this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + nonce.len;
+ this->payload_length = get_header_length(this) + nonce.len;
}
METHOD(nonce_payload_t, get_nonce, chunk_t,
@@ -159,7 +189,7 @@ METHOD2(payload_t, nonce_payload_t, destroy, void,
/*
* Described in header
*/
-nonce_payload_t *nonce_payload_create()
+nonce_payload_t *nonce_payload_create(payload_type_t type)
{
private_nonce_payload_t *this;
@@ -168,6 +198,7 @@ nonce_payload_t *nonce_payload_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -179,7 +210,8 @@ nonce_payload_t *nonce_payload_create()
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = NONCE_PAYLOAD_HEADER_LENGTH,
+ .payload_length = get_header_length(this),
+ .type = type,
);
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/nonce_payload.h b/src/libcharon/encoding/payloads/nonce_payload.h
index e9212202e..5c47f5f9f 100644
--- a/src/libcharon/encoding/payloads/nonce_payload.h
+++ b/src/libcharon/encoding/payloads/nonce_payload.h
@@ -33,14 +33,7 @@ typedef struct nonce_payload_t nonce_payload_t;
#define NONCE_SIZE 32
/**
- * Length of a nonce payload without a nonce in bytes.
- */
-#define NONCE_PAYLOAD_HEADER_LENGTH 4
-
-/**
- * Object representing an IKEv2 Nonce payload.
- *
- * The Nonce payload format is described in RFC section 3.3.
+ * Object representing an IKEv1/IKEv2 Nonce payload.
*/
struct nonce_payload_t {
/**
@@ -71,8 +64,9 @@ struct nonce_payload_t {
/**
* Creates an empty nonce_payload_t object
*
- * @return nonce_payload_t object
+ * @param type NONCE or NONCE_V1
+ * @return nonce_payload_t object
*/
-nonce_payload_t *nonce_payload_create(void);
+nonce_payload_t *nonce_payload_create(payload_type_t type);
#endif /** NONCE_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c
index e03d1af67..d168e1c12 100644
--- a/src/libcharon/encoding/payloads/notify_payload.c
+++ b/src/libcharon/encoding/payloads/notify_payload.c
@@ -36,11 +36,18 @@ ENUM_NEXT(notify_type_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYN
"INVALID_MESSAGE_ID");
ENUM_NEXT(notify_type_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID,
"INVALID_SPI");
-ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI,
+ENUM_NEXT(notify_type_names, ATTRIBUTES_NOT_SUPPORTED, NO_PROPOSAL_CHOSEN, INVALID_SPI,
+ "ATTRIBUTES_NOT_SUPPORTED",
"NO_PROPOSAL_CHOSEN");
-ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN,
- "INVALID_KE_PAYLOAD");
-ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
+ENUM_NEXT(notify_type_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN,
+ "PAYLOAD_MALFORMED",
+ "INVALID_KE_PAYLOAD",
+ "INVALID_ID_INFORMATION",
+ "INVALID_CERT_ENCODING",
+ "INVALID_CERTIFICATE",
+ "CERT_TYPE_UNSUPPORTED",
+ "INVALID_CERT_AUTHORITY",
+ "INVALID_HASH_INFORMATION",
"AUTHENTICATION_FAILED");
ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED,
"SINGLE_PAIR_REQUIRED",
@@ -102,7 +109,14 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, PSK_CONFIRM, MS_NOTIFY_STATUS,
"SECURE PASSWORD_METHOD",
"PSK_PERSIST",
"PSK_CONFIRM");
-ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, PSK_CONFIRM,
+ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, PSK_CONFIRM,
+ "INITIAL_CONTACT");
+ENUM_NEXT(notify_type_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1,
+ "DPD_R_U_THERE",
+ "DPD_R_U_THERE_ACK");
+ENUM_NEXT(notify_type_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R_U_THERE_ACK,
+ "UNITY_LOAD_BALANCE");
+ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE,
"USE_BEET_MODE");
ENUM_NEXT(notify_type_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE,
"ME_MEDIATION",
@@ -127,11 +141,18 @@ ENUM_NEXT(notify_type_short_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVAL
"INVAL_MID");
ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID,
"INVAL_SPI");
-ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI,
+ENUM_NEXT(notify_type_short_names, ATTRIBUTES_NOT_SUPPORTED, NO_PROPOSAL_CHOSEN, INVALID_SPI,
+ "ATTR_UNSUP",
"NO_PROP");
-ENUM_NEXT(notify_type_short_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN,
- "INVAL_KE");
-ENUM_NEXT(notify_type_short_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD,
+ENUM_NEXT(notify_type_short_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN,
+ "PLD_MAL",
+ "INVAL_KE",
+ "INVAL_ID",
+ "INVAL_CERTEN",
+ "INVAL_CERT",
+ "CERT_UNSUP",
+ "INVAL_CA",
+ "INVAL_HASH",
"AUTH_FAILED");
ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED,
"SINGLE_PAIR",
@@ -193,7 +214,14 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, PSK_CONFIRM, MS_NOTIFY_STATU
"SEC_PASSWD",
"PSK_PST",
"PSK_CFM");
-ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, PSK_CONFIRM,
+ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, PSK_CONFIRM,
+ "INITIAL_CONTACT");
+ENUM_NEXT(notify_type_short_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1,
+ "DPD",
+ "DPD_ACK");
+ENUM_NEXT(notify_type_short_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R_U_THERE_ACK,
+ "UNITY_LB");
+ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE,
"BEET_MODE");
ENUM_NEXT(notify_type_short_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE,
"ME_MED",
@@ -232,7 +260,7 @@ struct private_notify_payload_t {
/**
* reserved bits
*/
- bool reserved[7];
+ bool reserved[8];
/**
* Length of this payload.
@@ -240,6 +268,11 @@ struct private_notify_payload_t {
u_int16_t payload_length;
/**
+ * Domain of interpretation, IKEv1 only.
+ */
+ u_int32_t doi;
+
+ /**
* Protocol id.
*/
u_int8_t protocol_id;
@@ -262,40 +295,42 @@ struct private_notify_payload_t {
/**
* Notification data.
*/
- chunk_t notification_data;
+ chunk_t notify_data;
+
+ /**
+ * Type of payload, NOTIFY or NOTIFY_V1
+ */
+ payload_type_t type;
};
/**
- * Encoding rules to parse or generate a IKEv2-Notify Payload.
- *
- * The defined offsets are the positions in a object of type
- * private_notify_payload_t.
+ * Encoding rules for an IKEv2 notification payload
*/
-encoding_rule_t notify_payload_encodings[] = {
+static encoding_rule_t encodings_v2[] = {
/* 1 Byte next payload type, stored in the field next_payload */
- { U_INT_8, offsetof(private_notify_payload_t, next_payload) },
+ { U_INT_8, offsetof(private_notify_payload_t, next_payload) },
/* the critical bit */
- { FLAG, offsetof(private_notify_payload_t, critical) },
+ { FLAG, offsetof(private_notify_payload_t, critical) },
/* 7 Bit reserved bits, nowhere stored */
- { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) },
- { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) },
- { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) },
- { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) },
- { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) },
- { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) },
- { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) },
/* Length of the whole payload*/
- { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) },
+ { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) },
/* Protocol ID as 8 bit field*/
- { U_INT_8, offsetof(private_notify_payload_t, protocol_id) },
+ { U_INT_8, offsetof(private_notify_payload_t, protocol_id) },
/* SPI Size as 8 bit field*/
- { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) },
+ { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) },
/* Notify message type as 16 bit field*/
- { U_INT_16, offsetof(private_notify_payload_t, notify_type) },
+ { U_INT_16, offsetof(private_notify_payload_t, notify_type) },
/* SPI as variable length field*/
- { SPI, offsetof(private_notify_payload_t, spi) },
+ { SPI, offsetof(private_notify_payload_t, spi) },
/* Key Exchange Data is from variable size */
- { NOTIFICATION_DATA,offsetof(private_notify_payload_t, notification_data) }
+ { CHUNK_DATA, offsetof(private_notify_payload_t, notify_data) },
};
/*
@@ -315,6 +350,57 @@ encoding_rule_t notify_payload_encodings[] = {
! !
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
+/**
+ * Encoding rules for an IKEv1 notification payload
+ */
+static encoding_rule_t encodings_v1[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_notify_payload_t, next_payload) },
+ /* 8 reserved bits */
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) },
+ { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[7]) },
+ /* Length of the whole payload*/
+ { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) },
+ /* DOI as 32 bit field*/
+ { U_INT_32, offsetof(private_notify_payload_t, doi) },
+ /* Protocol ID as 8 bit field*/
+ { U_INT_8, offsetof(private_notify_payload_t, protocol_id) },
+ /* SPI Size as 8 bit field*/
+ { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) },
+ /* Notify message type as 16 bit field*/
+ { U_INT_16, offsetof(private_notify_payload_t, notify_type) },
+ /* SPI as variable length field*/
+ { SPI, offsetof(private_notify_payload_t, spi) },
+ /* Key Exchange Data is from variable size */
+ { CHUNK_DATA, offsetof(private_notify_payload_t, notify_data) },
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! DOI !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Protocol ID ! SPI Size ! Notify Message Type !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Security Parameter Index (SPI) ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ Notification Data ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
METHOD(payload_t, verify, status_t,
private_notify_payload_t *this)
@@ -337,7 +423,7 @@ METHOD(payload_t, verify, status_t,
{
case INVALID_KE_PAYLOAD:
{
- if (this->notification_data.len != 2)
+ if (this->type == NOTIFY && this->notify_data.len != 2)
{
bad_length = TRUE;
}
@@ -347,7 +433,7 @@ METHOD(payload_t, verify, status_t,
case NAT_DETECTION_DESTINATION_IP:
case ME_CONNECTAUTH:
{
- if (this->notification_data.len != HASH_SIZE_SHA1)
+ if (this->notify_data.len != HASH_SIZE_SHA1)
{
bad_length = TRUE;
}
@@ -357,7 +443,7 @@ METHOD(payload_t, verify, status_t,
case INVALID_MAJOR_VERSION:
case NO_PROPOSAL_CHOSEN:
{
- if (this->notification_data.len != 0)
+ if (this->type == NOTIFY && this->notify_data.len != 0)
{
bad_length = TRUE;
}
@@ -365,7 +451,7 @@ METHOD(payload_t, verify, status_t,
}
case ADDITIONAL_IP4_ADDRESS:
{
- if (this->notification_data.len != 4)
+ if (this->notify_data.len != 4)
{
bad_length = TRUE;
}
@@ -373,7 +459,7 @@ METHOD(payload_t, verify, status_t,
}
case ADDITIONAL_IP6_ADDRESS:
{
- if (this->notification_data.len != 16)
+ if (this->notify_data.len != 16)
{
bad_length = TRUE;
}
@@ -381,7 +467,7 @@ METHOD(payload_t, verify, status_t,
}
case AUTH_LIFETIME:
{
- if (this->notification_data.len != 4)
+ if (this->notify_data.len != 4)
{
bad_length = TRUE;
}
@@ -389,30 +475,37 @@ METHOD(payload_t, verify, status_t,
}
case IPCOMP_SUPPORTED:
{
- if (this->notification_data.len != 3)
+ if (this->notify_data.len != 3)
{
bad_length = TRUE;
}
break;
}
case ME_ENDPOINT:
- if (this->notification_data.len != 8 &&
- this->notification_data.len != 12 &&
- this->notification_data.len != 24)
+ if (this->notify_data.len != 8 &&
+ this->notify_data.len != 12 &&
+ this->notify_data.len != 24)
{
bad_length = TRUE;
}
break;
case ME_CONNECTID:
- if (this->notification_data.len < 4 ||
- this->notification_data.len > 16)
+ if (this->notify_data.len < 4 ||
+ this->notify_data.len > 16)
{
bad_length = TRUE;
}
break;
case ME_CONNECTKEY:
- if (this->notification_data.len < 16 ||
- this->notification_data.len > 32)
+ if (this->notify_data.len < 16 ||
+ this->notify_data.len > 32)
+ {
+ bad_length = TRUE;
+ }
+ break;
+ case DPD_R_U_THERE:
+ case DPD_R_U_THERE_ACK:
+ if (this->notify_data.len != 4)
{
bad_length = TRUE;
}
@@ -425,23 +518,38 @@ METHOD(payload_t, verify, status_t,
{
DBG1(DBG_ENC, "invalid notify data length for %N (%d)",
notify_type_names, this->notify_type,
- this->notification_data.len);
+ this->notify_data.len);
return FAILED;
}
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_notify_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_notify_payload_t *this, encoding_rule_t **rules)
+{
+ if (this->type == NOTIFY)
+ {
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+ }
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_notify_payload_t *this)
{
- *rules = notify_payload_encodings;
- *rule_count = countof(notify_payload_encodings);
+ if (this->type == NOTIFY)
+ {
+ return 8 + this->spi_size;
+ }
+ return 12 + this->spi_size;
}
METHOD(payload_t, get_type, payload_type_t,
private_notify_payload_t *this)
{
- return NOTIFY;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -459,19 +567,9 @@ METHOD(payload_t, set_next_type, void,
/**
* recompute the payloads length.
*/
-static void compute_length (private_notify_payload_t *this)
+static void compute_length(private_notify_payload_t *this)
{
- size_t length = NOTIFY_PAYLOAD_HEADER_LENGTH;
-
- if (this->notification_data.ptr != NULL)
- {
- length += this->notification_data.len;
- }
- if (this->spi.ptr != NULL)
- {
- length += this->spi.len;
- }
- this->payload_length = length;
+ this->payload_length = get_header_length(this) + this->notify_data.len;
}
METHOD(payload_t, get_length, size_t,
@@ -539,24 +637,55 @@ METHOD(notify_payload_t, set_spi, void,
compute_length(this);
}
+METHOD(notify_payload_t, get_spi_data, chunk_t,
+ private_notify_payload_t *this)
+{
+ switch (this->protocol_id)
+ {
+ case PROTO_IKE:
+ if (this->spi.len == 16)
+ {
+ return this->spi;
+ }
+ default:
+ break;
+ }
+ return chunk_empty;
+}
+
+METHOD(notify_payload_t, set_spi_data, void,
+ private_notify_payload_t *this, chunk_t spi)
+{
+ chunk_free(&this->spi);
+ switch (this->protocol_id)
+ {
+ case PROTO_IKE:
+ this->spi = chunk_clone(spi);
+ default:
+ break;
+ }
+ this->spi_size = this->spi.len;
+ compute_length(this);
+}
+
METHOD(notify_payload_t, get_notification_data, chunk_t,
private_notify_payload_t *this)
{
- return this->notification_data;
+ return this->notify_data;
}
METHOD(notify_payload_t, set_notification_data, void,
private_notify_payload_t *this, chunk_t data)
{
- free(this->notification_data.ptr);
- this->notification_data = chunk_clone(data);
+ free(this->notify_data.ptr);
+ this->notify_data = chunk_clone(data);
compute_length(this);
}
METHOD2(payload_t, notify_payload_t, destroy, void,
private_notify_payload_t *this)
{
- free(this->notification_data.ptr);
+ free(this->notify_data.ptr);
free(this->spi.ptr);
free(this);
}
@@ -564,7 +693,7 @@ METHOD2(payload_t, notify_payload_t, destroy, void,
/*
* Described in header
*/
-notify_payload_t *notify_payload_create()
+notify_payload_t *notify_payload_create(payload_type_t type)
{
private_notify_payload_t *this;
@@ -573,6 +702,7 @@ notify_payload_t *notify_payload_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -585,13 +715,17 @@ notify_payload_t *notify_payload_create()
.set_notify_type = _set_notify_type,
.get_spi = _get_spi,
.set_spi = _set_spi,
+ .get_spi_data = _get_spi_data,
+ .set_spi_data = _set_spi_data,
.get_notification_data = _get_notification_data,
.set_notification_data = _set_notification_data,
.destroy = _destroy,
},
+ .doi = IKEV1_DOI_IPSEC,
.next_payload = NO_PAYLOAD,
- .payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH,
+ .type = type,
);
+ compute_length(this);
return &this->public;
}
@@ -599,12 +733,12 @@ notify_payload_t *notify_payload_create()
* Described in header.
*/
notify_payload_t *notify_payload_create_from_protocol_and_type(
- protocol_id_t protocol_id, notify_type_t notify_type)
+ payload_type_t type, protocol_id_t protocol, notify_type_t notify)
{
- notify_payload_t *notify = notify_payload_create();
+ notify_payload_t *this = notify_payload_create(type);
- notify->set_notify_type(notify, notify_type);
- notify->set_protocol_id(notify, protocol_id);
+ this->set_notify_type(this, notify);
+ this->set_protocol_id(this, protocol);
- return notify;
+ return this;
}
diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h
index ced282700..beec1e233 100644
--- a/src/libcharon/encoding/payloads/notify_payload.h
+++ b/src/libcharon/encoding/payloads/notify_payload.h
@@ -33,25 +33,36 @@ typedef struct notify_payload_t notify_payload_t;
#include <utils/linked_list.h>
/**
- * Notify payload length in bytes without any spi and notification data.
- */
-#define NOTIFY_PAYLOAD_HEADER_LENGTH 8
-
-/**
- * Notify message types.
- *
- * See IKEv2 RFC 3.10.1.
+ * Notify message types for IKEv2, and a subset for IKEv1.
*/
enum notify_type_t {
/* notify error messages */
UNSUPPORTED_CRITICAL_PAYLOAD = 1,
+ /* IKEv1 alias */
+ INVALID_PAYLOAD_TYPE = 1,
INVALID_IKE_SPI = 4,
INVALID_MAJOR_VERSION = 5,
INVALID_SYNTAX = 7,
+ /* IKEv1 alias */
+ INVALID_EXCHANGE_TYPE = 7,
INVALID_MESSAGE_ID = 9,
INVALID_SPI = 11,
+ /* IKEv1 only */
+ ATTRIBUTES_NOT_SUPPORTED = 13,
+ /* IKEv1 alias */
NO_PROPOSAL_CHOSEN = 14,
+ /* IKEv1 only */
+ PAYLOAD_MALFORMED = 16,
INVALID_KE_PAYLOAD = 17,
+ /* IKEv1 alias */
+ INVALID_KEY_INFORMATION = 17,
+ /* IKEv1 only */
+ INVALID_ID_INFORMATION = 18,
+ INVALID_CERT_ENCODING = 19,
+ INVALID_CERTIFICATE = 20,
+ CERT_TYPE_UNSUPPORTED = 21,
+ INVALID_CERT_AUTHORITY = 22,
+ INVALID_HASH_INFORMATION = 23,
AUTHENTICATION_FAILED = 24,
SINGLE_PAIR_REQUIRED = 34,
NO_ADDITIONAL_SAS = 35,
@@ -132,6 +143,13 @@ enum notify_type_t {
/* PACE - draft-kuegler-ipsecme-pace-ikev2 */
PSK_PERSIST = 16425,
PSK_CONFIRM = 16426,
+ /* IKEv1 initial contact */
+ INITIAL_CONTACT_IKEV1 = 24578,
+ /* IKEv1 DPD */
+ DPD_R_U_THERE = 36136,
+ DPD_R_U_THERE_ACK = 36137,
+ /* IKEv1 Cisco High Availability */
+ UNITY_LOAD_BALANCE = 40501,
/* BEET mode, not even a draft yet. private use */
USE_BEET_MODE = 40961,
/* IKE-ME, private use */
@@ -214,6 +232,24 @@ struct notify_payload_t {
void (*set_spi) (notify_payload_t *this, u_int32_t spi);
/**
+ * Returns the currently set spi of this payload.
+ *
+ * This is only valid for notifys with protocol ISAKMP
+ *
+ * @return SPI value
+ */
+ chunk_t (*get_spi_data) (notify_payload_t *this);
+
+ /**
+ * Sets the spi of this payload.
+ *
+ * This is only valid for notifys with protocol ISAKMP
+ *
+ * @param spi SPI value
+ */
+ void (*set_spi_data) (notify_payload_t *this, chunk_t spi);
+
+ /**
* Returns the currently set notification data of payload.
*
* Returned data are not copied.
@@ -241,18 +277,20 @@ struct notify_payload_t {
/**
* Creates an empty notify_payload_t object
*
+ * @param type payload type, NOTIFY or NOTIFY_V1
* @return created notify_payload_t object
*/
-notify_payload_t *notify_payload_create(void);
+notify_payload_t *notify_payload_create(payload_type_t type);
/**
* Creates an notify_payload_t object of specific type for specific protocol id.
*
- * @param protocol_id protocol id (IKE, AH or ESP)
- * @param type notify type (see notify_type_t)
+ * @param type payload type, NOTIFY or NOTIFY_V1
+ * @param protocol protocol id (IKE, AH or ESP)
+ * @param notify type of notify
* @return notify_payload_t object
*/
notify_payload_t *notify_payload_create_from_protocol_and_type(
- protocol_id_t protocol_id, notify_type_t type);
+ payload_type_t type, protocol_id_t protocol, notify_type_t notify);
#endif /** NOTIFY_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c
index a2c0a4385..dc158476b 100644
--- a/src/libcharon/encoding/payloads/payload.c
+++ b/src/libcharon/encoding/payloads/payload.c
@@ -20,6 +20,7 @@
#include <encoding/payloads/ike_header.h>
#include <encoding/payloads/sa_payload.h>
+
#include <encoding/payloads/nonce_payload.h>
#include <encoding/payloads/id_payload.h>
#include <encoding/payloads/ke_payload.h>
@@ -34,13 +35,30 @@
#include <encoding/payloads/cp_payload.h>
#include <encoding/payloads/configuration_attribute.h>
#include <encoding/payloads/eap_payload.h>
+#include <encoding/payloads/hash_payload.h>
#include <encoding/payloads/unknown_payload.h>
-
ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD,
"NO_PAYLOAD");
-ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION,
- GENERIC_SECURE_PASSWORD_METHOD, NO_PAYLOAD,
+ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, NO_PAYLOAD,
+ "SECURITY_ASSOCIATION_V1",
+ "PROPOSAL_V1",
+ "TRANSFORM_V1",
+ "KEY_EXCHANGE_V1",
+ "ID_V1",
+ "CERTIFICATE_V1",
+ "CERTIFICATE_REQUEST_V1",
+ "HASH_V1",
+ "SIGNATURE_V1",
+ "NONCE_V1",
+ "NOTIFY_V1",
+ "DELETE_V1",
+ "VENDOR_ID_V1",
+ "CONFIGURATION_V1");
+ENUM_NEXT(payload_type_names, NAT_D_V1, NAT_OA_V1, CONFIGURATION_V1,
+ "NAT_D_V1",
+ "NAT_OA_V1");
+ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWORD_METHOD, NAT_OA_V1,
"SECURITY_ASSOCIATION",
"KEY_EXCHANGE",
"ID_INITIATOR",
@@ -61,30 +79,56 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION,
#ifdef ME
ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD,
"ID_PEER");
-ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER,
+ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, ID_PEER,
"HEADER",
"PROPOSAL_SUBSTRUCTURE",
+ "PROPOSAL_SUBSTRUCTURE_V1",
"TRANSFORM_SUBSTRUCTURE",
+ "TRANSFORM_SUBSTRUCTURE_V1",
"TRANSFORM_ATTRIBUTE",
+ "TRANSFORM_ATTRIBUTE_V1",
"TRAFFIC_SELECTOR_SUBSTRUCTURE",
- "CONFIGURATION_ATTRIBUTE");
+ "CONFIGURATION_ATTRIBUTE",
+ "CONFIGURATION_ATTRIBUTE_V1",
+ "ENCRYPTED_V1");
#else
-ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE,
- GENERIC_SECURE_PASSWORD_METHOD,
+ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWORD_METHOD,
"HEADER",
"PROPOSAL_SUBSTRUCTURE",
+ "PROPOSAL_SUBSTRUCTURE_V1",
"TRANSFORM_SUBSTRUCTURE",
+ "TRANSFORM_SUBSTRUCTURE_V1",
"TRANSFORM_ATTRIBUTE",
+ "TRANSFORM_ATTRIBUTE_V1",
"TRAFFIC_SELECTOR_SUBSTRUCTURE",
- "CONFIGURATION_ATTRIBUTE");
+ "CONFIGURATION_ATTRIBUTE",
+ "CONFIGURATION_ATTRIBUTE_V1",
+ "ENCRYPTED_V1");
#endif /* ME */
-ENUM_END(payload_type_names, CONFIGURATION_ATTRIBUTE);
+ENUM_END(payload_type_names, ENCRYPTED_V1);
/* short forms of payload names */
ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD,
"--");
-ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION,
- GENERIC_SECURE_PASSWORD_METHOD, NO_PAYLOAD,
+ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, NO_PAYLOAD,
+ "SA",
+ "PROP",
+ "TRANS",
+ "KE",
+ "ID",
+ "CERT",
+ "CERTREQ",
+ "HASH",
+ "SIG",
+ "No",
+ "N",
+ "D",
+ "V",
+ "CP");
+ENUM_NEXT(payload_type_short_names, NAT_D_V1, NAT_OA_V1, CONFIGURATION_V1,
+ "NAT-D",
+ "NAT-OA");
+ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWORD_METHOD, NAT_OA_V1,
"SA",
"KE",
"IDi",
@@ -106,24 +150,33 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION,
ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER,
GENERIC_SECURE_PASSWORD_METHOD,
"IDp");
-ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER,
+ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, ID_PEER,
"HDR",
"PROP",
+ "PROP",
+ "TRANS",
"TRANS",
"TRANSATTR",
+ "TRANSATTR",
"TSSUB",
- "CPATTR");
+ "CATTR",
+ "CATTR",
+ "E");
#else
-ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE,
- GENERIC_SECURE_PASSWORD_METHOD,
+ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWORD_METHOD,
"HDR",
"PROP",
+ "PROP",
+ "TRANS",
"TRANS",
"TRANSATTR",
+ "TRANSATTR",
"TSSUB",
- "CPATTR");
+ "CATTR",
+ "CATTR",
+ "E");
#endif /* ME */
-ENUM_END(payload_type_short_names, CONFIGURATION_ATTRIBUTE);
+ENUM_END(payload_type_short_names, ENCRYPTED_V1);
/*
* see header
@@ -135,29 +188,36 @@ payload_t *payload_create(payload_type_t type)
case HEADER:
return (payload_t*)ike_header_create();
case SECURITY_ASSOCIATION:
- return (payload_t*)sa_payload_create();
+ case SECURITY_ASSOCIATION_V1:
+ return (payload_t*)sa_payload_create(type);
case PROPOSAL_SUBSTRUCTURE:
- return (payload_t*)proposal_substructure_create();
+ case PROPOSAL_SUBSTRUCTURE_V1:
+ return (payload_t*)proposal_substructure_create(type);
case TRANSFORM_SUBSTRUCTURE:
- return (payload_t*)transform_substructure_create();
+ case TRANSFORM_SUBSTRUCTURE_V1:
+ return (payload_t*)transform_substructure_create(type);
case TRANSFORM_ATTRIBUTE:
- return (payload_t*)transform_attribute_create();
+ case TRANSFORM_ATTRIBUTE_V1:
+ return (payload_t*)transform_attribute_create(type);
case NONCE:
- return (payload_t*)nonce_payload_create();
+ case NONCE_V1:
+ return (payload_t*)nonce_payload_create(type);
case ID_INITIATOR:
- return (payload_t*)id_payload_create(ID_INITIATOR);
case ID_RESPONDER:
- return (payload_t*)id_payload_create(ID_RESPONDER);
+ case ID_V1:
+ case NAT_OA_V1:
#ifdef ME
case ID_PEER:
- return (payload_t*)id_payload_create(ID_PEER);
#endif /* ME */
+ return (payload_t*)id_payload_create(type);
case AUTHENTICATION:
return (payload_t*)auth_payload_create();
case CERTIFICATE:
- return (payload_t*)cert_payload_create();
+ case CERTIFICATE_V1:
+ return (payload_t*)cert_payload_create(type);
case CERTIFICATE_REQUEST:
- return (payload_t*)certreq_payload_create();
+ case CERTIFICATE_REQUEST_V1:
+ return (payload_t*)certreq_payload_create(type);
case TRAFFIC_SELECTOR_SUBSTRUCTURE:
return (payload_t*)traffic_selector_substructure_create();
case TRAFFIC_SELECTOR_INITIATOR:
@@ -165,21 +225,32 @@ payload_t *payload_create(payload_type_t type)
case TRAFFIC_SELECTOR_RESPONDER:
return (payload_t*)ts_payload_create(FALSE);
case KEY_EXCHANGE:
- return (payload_t*)ke_payload_create();
+ case KEY_EXCHANGE_V1:
+ return (payload_t*)ke_payload_create(type);
case NOTIFY:
- return (payload_t*)notify_payload_create();
+ case NOTIFY_V1:
+ return (payload_t*)notify_payload_create(type);
case DELETE:
- return (payload_t*)delete_payload_create(0);
+ case DELETE_V1:
+ return (payload_t*)delete_payload_create(type, 0);
case VENDOR_ID:
- return (payload_t*)vendor_id_payload_create();
+ case VENDOR_ID_V1:
+ return (payload_t*)vendor_id_payload_create(type);
+ case HASH_V1:
+ case SIGNATURE_V1:
+ case NAT_D_V1:
+ return (payload_t*)hash_payload_create(type);
case CONFIGURATION:
- return (payload_t*)cp_payload_create();
+ case CONFIGURATION_V1:
+ return (payload_t*)cp_payload_create(type);
case CONFIGURATION_ATTRIBUTE:
- return (payload_t*)configuration_attribute_create();
+ case CONFIGURATION_ATTRIBUTE_V1:
+ return (payload_t*)configuration_attribute_create(type);
case EXTENSIBLE_AUTHENTICATION:
return (payload_t*)eap_payload_create();
case ENCRYPTED:
- return (payload_t*)encryption_payload_create();
+ case ENCRYPTED_V1:
+ return (payload_t*)encryption_payload_create(type);
default:
return (payload_t*)unknown_payload_create(type);
}
@@ -190,8 +261,19 @@ payload_t *payload_create(payload_type_t type)
*/
bool payload_is_known(payload_type_t type)
{
- if (type == HEADER ||
- (type >= SECURITY_ASSOCIATION && type <= EXTENSIBLE_AUTHENTICATION))
+ if (type == HEADER)
+ {
+ return TRUE;
+ }
+ if (type >= SECURITY_ASSOCIATION && type <= EXTENSIBLE_AUTHENTICATION)
+ {
+ return TRUE;
+ }
+ if (type >= SECURITY_ASSOCIATION_V1 && type <= CONFIGURATION_V1)
+ {
+ return TRUE;
+ }
+ if (type >= NAT_D_V1 && type <= NAT_OA_V1)
{
return TRUE;
}
@@ -210,10 +292,9 @@ bool payload_is_known(payload_type_t type)
void* payload_get_field(payload_t *payload, encoding_type_t type, u_int skip)
{
encoding_rule_t *rule;
- size_t count;
- int i;
+ int i, count;
- payload->get_encoding_rules(payload, &rule, &count);
+ count = payload->get_encoding_rules(payload, &rule);
for (i = 0; i < count; i++)
{
if (rule[i].type == type && skip-- == 0)
diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h
index a9af29b5b..d5e862601 100644
--- a/src/libcharon/encoding/payloads/payload.h
+++ b/src/libcharon/encoding/payloads/payload.h
@@ -29,14 +29,18 @@ typedef struct payload_t payload_t;
#include <library.h>
#include <encoding/payloads/encodings.h>
+/**
+ * Domain of interpretation used by IPsec/IKEv1
+ */
+#define IKEV1_DOI_IPSEC 1
/**
- * Payload-Types of a IKEv2-Message.
+ * Payload-Types of an IKE message.
*
* Header and substructures are also defined as
* payload types with values from PRIVATE USE space.
*/
-enum payload_type_t{
+enum payload_type_t {
/**
* End of payload list in next_payload
@@ -46,6 +50,86 @@ enum payload_type_t{
/**
* The security association (SA) payload containing proposals.
*/
+ SECURITY_ASSOCIATION_V1 = 1,
+
+ /**
+ * The proposal payload, containing transforms.
+ */
+ PROPOSAL_V1 = 2,
+
+ /**
+ * The transform payload.
+ */
+ TRANSFORM_V1 = 3,
+
+ /**
+ * The key exchange (KE) payload containing diffie-hellman values.
+ */
+ KEY_EXCHANGE_V1 = 4,
+
+ /**
+ * ID payload.
+ */
+ ID_V1 = 5,
+
+ /**
+ * Certificate payload with certificates (CERT).
+ */
+ CERTIFICATE_V1 = 6,
+
+ /**
+ * Certificate request payload.
+ */
+ CERTIFICATE_REQUEST_V1 = 7,
+
+ /**
+ * Hash payload.
+ */
+ HASH_V1 = 8,
+
+ /**
+ * Signature payload
+ */
+ SIGNATURE_V1 = 9,
+
+ /**
+ * Nonce payload.
+ */
+ NONCE_V1 = 10,
+
+ /**
+ * Notification payload.
+ */
+ NOTIFY_V1 = 11,
+
+ /**
+ * Delete payload.
+ */
+ DELETE_V1 = 12,
+
+ /**
+ * Vendor id payload.
+ */
+ VENDOR_ID_V1 = 13,
+
+ /**
+ * Attribute payload (ISAKMP Mode Config, aka configuration payload.
+ */
+ CONFIGURATION_V1 = 14,
+
+ /**
+ * NAT discovery payload (NAT-D).
+ */
+ NAT_D_V1 = 20,
+
+ /**
+ * NAT original address payload (NAT-OA)
+ */
+ NAT_OA_V1 = 21,
+
+ /**
+ * The security association (SA) payload containing proposals.
+ */
SECURITY_ASSOCIATION = 33,
/**
@@ -139,50 +223,60 @@ enum payload_type_t{
/**
* Header has a value of PRIVATE USE space.
*
- * This payload type is not sent over wire and just
- * used internally to handle IKEv2-Header like a payload.
+ * This type and all the following are never sent over wire and are
+ * used internally only.
*/
HEADER = 256,
/**
- * PROPOSAL_SUBSTRUCTURE has a value of PRIVATE USE space.
- *
- * This payload type is not sent over wire and just
- * used internally to handle a proposal substructure like a payload.
+ * PROPOSAL_SUBSTRUCTURE, IKEv2 proposals in a SA payload.
*/
- PROPOSAL_SUBSTRUCTURE = 257,
+ PROPOSAL_SUBSTRUCTURE,
/**
- * TRANSFORM_SUBSTRUCTURE has a value of PRIVATE USE space.
- *
- * This payload type is not sent over wire and just
- * used internally to handle a transform substructure like a payload.
+ * PROPOSAL_SUBSTRUCTURE_V1, IKEv1 proposals in a SA payload.
*/
- TRANSFORM_SUBSTRUCTURE = 258,
+ PROPOSAL_SUBSTRUCTURE_V1,
/**
- * TRANSFORM_ATTRIBUTE has a value of PRIVATE USE space.
- *
- * This payload type is not sent over wire and just
- * used internally to handle a transform attribute like a payload.
+ * TRANSFORM_SUBSTRUCTURE, IKEv2 transforms in a proposal substructure.
*/
- TRANSFORM_ATTRIBUTE = 259,
+ TRANSFORM_SUBSTRUCTURE,
/**
- * TRAFFIC_SELECTOR_SUBSTRUCTURE has a value of PRIVATE USE space.
- *
- * This payload type is not sent over wire and just
- * used internally to handle a transform selector like a payload.
+ * TRANSFORM_SUBSTRUCTURE_V1, IKEv1 transforms in a proposal substructure.
*/
- TRAFFIC_SELECTOR_SUBSTRUCTURE = 260,
+ TRANSFORM_SUBSTRUCTURE_V1,
/**
- * CONFIGURATION_ATTRIBUTE has a value of PRIVATE USE space.
- *
- * This payload type is not sent over wire and just
- * used internally to handle a transform attribute like a payload.
+ * TRANSFORM_ATTRIBUTE, IKEv2 attribute in a transform.
*/
- CONFIGURATION_ATTRIBUTE = 261,
+ TRANSFORM_ATTRIBUTE,
+
+ /**
+ * TRANSFORM_ATTRIBUTE_V1, IKEv1 attribute in a transform.
+ */
+ TRANSFORM_ATTRIBUTE_V1,
+
+ /**
+ * TRAFFIC_SELECTOR_SUBSTRUCTURE, traffic selector in a TS payload.
+ */
+ TRAFFIC_SELECTOR_SUBSTRUCTURE,
+
+ /**
+ * CONFIGURATION_ATTRIBUTE, IKEv2 attribute in a configuration payload.
+ */
+ CONFIGURATION_ATTRIBUTE,
+
+ /**
+ * CONFIGURATION_ATTRIBUTE_V1, IKEv1 attribute in a configuration payload.
+ */
+ CONFIGURATION_ATTRIBUTE_V1,
+
+ /**
+ * This is not really a payload, but rather the complete IKEv1 message.
+ */
+ ENCRYPTED_V1,
};
/**
@@ -207,43 +301,50 @@ struct payload_t {
/**
* Get encoding rules for this payload.
*
- * @param rules location to store pointer of first rule
- * @param rule_count location to store number of rules
+ * @param rules location to store pointer to rules
+ * @return number of rules
+ */
+ int (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules);
+
+ /**
+ * Get non-variable header length for a variable length payload.
+ *
+ * @return fixed length of the payload
*/
- void (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules, size_t *rule_count);
+ int (*get_header_length)(payload_t *this);
/**
* Get type of payload.
*
- * @return type of this payload
+ * @return type of this payload
*/
payload_type_t (*get_type) (payload_t *this);
/**
* Get type of next payload or NO_PAYLOAD (0) if this is the last one.
*
- * @return type of next payload
+ * @return type of next payload
*/
payload_type_t (*get_next_type) (payload_t *this);
/**
* Set type of next payload.
*
- * @param type type of next payload
+ * @param type type of next payload
*/
void (*set_next_type) (payload_t *this,payload_type_t type);
/**
* Get length of payload.
*
- * @return length of this payload
+ * @return length of this payload
*/
size_t (*get_length) (payload_t *this);
/**
* Verifies payload structure and makes consistence check.
*
- * @return SUCCESS, FAILED if consistence not given
+ * @return SUCCESS, FAILED if consistence not given
*/
status_t (*verify) (payload_t *this);
diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c
index 4753d574d..653f51a46 100644
--- a/src/libcharon/encoding/payloads/proposal_substructure.c
+++ b/src/libcharon/encoding/payloads/proposal_substructure.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2010 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -25,7 +26,7 @@
#include <daemon.h>
/**
- * IKEv1 Value for a proposal payload.
+ * IKEv2 Value for a proposal payload.
*/
#define PROPOSAL_TYPE_VALUE 2
@@ -84,16 +85,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.
+ */
+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 list */
+ { PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1,
+ offsetof(private_proposal_substructure_t, transforms) },
+};
+
+/**
+ * Encoding rules for a IKEv2 Proposal substructure.
*/
-encoding_rule_t proposal_substructure_encodings[] = {
+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 */
@@ -110,9 +138,9 @@ encoding_rule_t proposal_substructure_encodings[] = {
{ U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) },
/* SPI is a chunk of variable size*/
{ SPI, offsetof(private_proposal_substructure_t, spi) },
- /* Transforms are stored in a transform substructure,
- offset points to a linked_list_t pointer */
- { TRANSFORMS, offsetof(private_proposal_substructure_t, transforms) }
+ /* Transforms are stored in a transform substructure list */
+ { PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE,
+ offsetof(private_proposal_substructure_t, transforms) },
};
/*
@@ -131,6 +159,149 @@ 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,
+ /* FreeS/WAN proprietary */
+ IKEV1_ENCR_SERPENT_CBC = 65004,
+ IKEV1_ENCR_TWOFISH_CBC = 65005,
+} 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 encryption algorithm.
+ */
+typedef enum {
+ IKEV1_ESP_ENCR_DES_IV64 = 1,
+ IKEV1_ESP_ENCR_DES = 2,
+ IKEV1_ESP_ENCR_3DES = 3,
+ IKEV1_ESP_ENCR_RC5 = 4,
+ IKEV1_ESP_ENCR_IDEA = 5,
+ IKEV1_ESP_ENCR_CAST = 6,
+ IKEV1_ESP_ENCR_BLOWFISH = 7,
+ IKEV1_ESP_ENCR_3IDEA = 8,
+ IKEV1_ESP_ENCR_DES_IV32 = 9,
+ IKEV1_ESP_ENCR_RC4 = 10,
+ IKEV1_ESP_ENCR_NULL = 11,
+ IKEV1_ESP_ENCR_AES_CBC = 12,
+ IKEV1_ESP_ENCR_AES_CTR = 13,
+ IKEV1_ESP_ENCR_AES_CCM_8 = 14,
+ IKEV1_ESP_ENCR_AES_CCM_12 = 15,
+ IKEV1_ESP_ENCR_AES_CCM_16 = 16,
+ IKEV1_ESP_ENCR_AES_GCM_8 = 18,
+ IKEV1_ESP_ENCR_AES_GCM_12 = 19,
+ IKEV1_ESP_ENCR_AES_GCM_16 = 20,
+ IKEV1_ESP_ENCR_SEED_CBC = 21,
+ IKEV1_ESP_ENCR_CAMELLIA = 22,
+ IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC = 23,
+ /* FreeS/WAN proprietary */
+ IKEV1_ESP_ENCR_SERPENT = 252,
+ IKEV1_ESP_ENCR_TWOFISH = 253,
+} ikev1_esp_encr_transid_t;
+
+/**
+ * IKEv1 Transform ID ESP authentication algorithm.
+ */
+typedef enum {
+ IKEV1_ESP_AUTH_HMAC_MD5 = 1,
+ IKEV1_ESP_AUTH_HMAC_SHA = 2,
+ IKEV1_ESP_AUTH_DES_MAC = 3,
+ IKEV1_ESP_AUTH_KPDK = 4,
+ IKEV1_ESP_AUTH_HMAC_SHA2_256 = 5,
+ IKEV1_ESP_AUTH_HMAC_SHA2_384 = 6,
+ IKEV1_ESP_AUTH_HMAC_SHA2_512 = 7,
+ IKEV1_ESP_AUTH_HMAC_RIPEMD = 8,
+ IKEV1_ESP_AUTH_AES_XCBC_MAC = 9,
+ IKEV1_ESP_AUTH_SIG_RSA = 10,
+ IKEV1_ESP_AUTH_AES_128_GMAC = 11,
+ IKEV1_ESP_AUTH_AES_192_GMAC = 12,
+ IKEV1_ESP_AUTH_AES_256_GMAC = 13,
+} ikev1_esp_auth_transid_it;
+
+/**
+ * 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;
+
+/**
+ * IKEv1 authentication methods
+ */
+typedef enum {
+ IKEV1_AUTH_PSK = 1,
+ IKEV1_AUTH_DSS_SIG = 2,
+ IKEV1_AUTH_RSA_SIG = 3,
+ IKEV1_AUTH_RSA_ENC = 4,
+ IKEV1_AUTH_RSA_ENC_REV = 5,
+ IKEV1_AUTH_ECDSA_256 = 9,
+ IKEV1_AUTH_ECDSA_384 = 10,
+ IKEV1_AUTH_ECDSA_521 = 11,
+ /* XAuth Modes */
+ IKEV1_AUTH_XAUTH_INIT_PSK = 65001,
+ IKEV1_AUTH_XAUTH_RESP_PSK = 65002,
+ IKEV1_AUTH_XAUTH_INIT_DSS = 65003,
+ IKEV1_AUTH_XAUTH_RESP_DSS = 65004,
+ IKEV1_AUTH_XAUTH_INIT_RSA = 65005,
+ IKEV1_AUTH_XAUTH_RESP_RSA = 65006,
+ IKEV1_AUTH_XAUTH_INIT_RSA_ENC = 65007,
+ IKEV1_AUTH_XAUTH_RESP_RSA_ENC = 65008,
+ IKEV1_AUTH_XAUTH_INIT_RSA_ENC_REV = 65009,
+ IKEV1_AUTH_XAUTH_RESP_RSA_ENC_REV = 65010,
+ /* Hybrid Modes */
+ IKEV1_AUTH_HYBRID_INIT_RSA = 64221,
+ IKEV1_AUTH_HYBRID_RESP_RSA = 64222,
+ IKEV1_AUTH_HYBRID_INIT_DSS = 64223,
+ IKEV1_AUTH_HYBRID_RESP_DSS = 64224,
+} ikev1_auth_method_t;
+
+/**
+ * IKEv1 IPComp transform IDs
+ */
+typedef enum {
+ IKEV1_IPCOMP_OUI = 1,
+ IKEV1_IPCOMP_DEFLATE = 2,
+ IKEV1_IPCOMP_LZS = 3,
+} ikev1_ipcomp_transform_t;
+
METHOD(payload_t, verify, status_t,
private_proposal_substructure_t *this)
{
@@ -153,12 +324,19 @@ METHOD(payload_t, verify, status_t,
switch (this->protocol_id)
{
+ case PROTO_IPCOMP:
+ if (this->spi.len != 2)
+ {
+ DBG1(DBG_ENC, "invalid CPI length in IPCOMP proposal");
+ return FAILED;
+ }
+ break;
case PROTO_AH:
case PROTO_ESP:
if (this->spi.len != 4)
{
DBG1(DBG_ENC, "invalid SPI length in %N proposal",
- protocol_id_names, this->protocol_id);
+ protocol_id_names, this->protocol_id);
return FAILED;
}
break;
@@ -188,18 +366,28 @@ METHOD(payload_t, verify, status_t,
return status;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_proposal_substructure_t *this, encoding_rule_t **rules,
- size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_proposal_substructure_t *this, encoding_rule_t **rules)
{
- *rules = proposal_substructure_encodings;
- *rule_count = countof(proposal_substructure_encodings);
+ if (this->type == PROPOSAL_SUBSTRUCTURE)
+ {
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+ }
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_proposal_substructure_t *this)
+{
+ return 8 + this->spi_size;
}
METHOD(payload_t, get_type, payload_type_t,
private_proposal_substructure_t *this)
{
- return PROPOSAL_SUBSTRUCTURE;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -222,7 +410,7 @@ static void compute_length(private_proposal_substructure_t *this)
payload_t *transform;
this->transforms_count = 0;
- this->proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH + this->spi.len;
+ this->proposal_length = get_header_length(this);
enumerator = this->transforms->create_enumerator(this->transforms);
while (enumerator->enumerate(enumerator, &transform))
{
@@ -301,45 +489,486 @@ METHOD(proposal_substructure_t, get_spi, chunk_t,
return this->spi;
}
-METHOD(proposal_substructure_t, get_proposal, proposal_t*,
- private_proposal_substructure_t *this)
+METHOD(proposal_substructure_t, get_cpi, bool,
+ private_proposal_substructure_t *this, u_int16_t *cpi)
{
- enumerator_t *enumerator;
+
transform_substructure_t *transform;
- proposal_t *proposal;
- u_int64_t spi;
+ enumerator_t *enumerator;
- proposal = proposal_create(this->protocol_id, this->proposal_number);
+ if (this->protocol_id != PROTO_IPCOMP)
+ {
+ return FALSE;
+ }
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;
+ if (transform->get_transform_id(transform) == IKEV1_IPCOMP_DEFLATE)
+ {
+ if (cpi)
+ {
+ *cpi = *((u_int16_t*)this->spi.ptr);
+ }
+ enumerator->destroy(enumerator);
+ return TRUE;
+ }
+ }
+ enumerator->destroy(enumerator);
+ return FALSE;
+}
- transform_type = transform->get_transform_type(transform);
- transform_id = transform->get_transform_id(transform);
- transform->get_key_length(transform, &key_length);
+/**
+ * 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;
- proposal->add_algorithm(proposal, transform_type, transform_id, key_length);
+ 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);
+}
+
+/**
+ * Map IKEv1 to IKEv2 algorithms
+ */
+typedef struct {
+ u_int16_t ikev1;
+ u_int16_t ikev2;
+} algo_map_t;
+
+/**
+ * Encryption algorithm mapping
+ */
+static algo_map_t map_encr[] = {
+ { IKEV1_ENCR_DES_CBC, ENCR_DES },
+ { IKEV1_ENCR_IDEA_CBC, ENCR_IDEA },
+ { IKEV1_ENCR_BLOWFISH_CBC, ENCR_BLOWFISH },
+ { IKEV1_ENCR_3DES_CBC, ENCR_3DES },
+ { IKEV1_ENCR_CAST_CBC, ENCR_CAST },
+ { IKEV1_ENCR_AES_CBC, ENCR_AES_CBC },
+ { IKEV1_ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CBC },
+ { IKEV1_ENCR_SERPENT_CBC, ENCR_SERPENT_CBC },
+ { IKEV1_ENCR_TWOFISH_CBC, ENCR_TWOFISH_CBC },
+};
+
+/**
+ * Integrity algorithm mapping
+ */
+static algo_map_t map_integ[] = {
+ { IKEV1_HASH_MD5, AUTH_HMAC_MD5_96 },
+ { IKEV1_HASH_SHA1, AUTH_HMAC_SHA1_96 },
+ { IKEV1_HASH_SHA2_256, AUTH_HMAC_SHA2_256_128 },
+ { IKEV1_HASH_SHA2_384, AUTH_HMAC_SHA2_384_192 },
+ { IKEV1_HASH_SHA2_512, AUTH_HMAC_SHA2_512_256 },
+};
+
+/**
+ * PRF algorithm mapping
+ */
+static algo_map_t map_prf[] = {
+ { IKEV1_HASH_MD5, PRF_HMAC_MD5 },
+ { IKEV1_HASH_SHA1, PRF_HMAC_SHA1 },
+ { IKEV1_HASH_SHA2_256, PRF_HMAC_SHA2_256 },
+ { IKEV1_HASH_SHA2_384, PRF_HMAC_SHA2_384 },
+ { IKEV1_HASH_SHA2_512, PRF_HMAC_SHA2_512 },
+};
+
+/**
+ * ESP encryption algorithm mapping
+ */
+static algo_map_t map_esp_encr[] = {
+ { IKEV1_ESP_ENCR_DES_IV64, ENCR_DES_IV64 },
+ { IKEV1_ESP_ENCR_DES, ENCR_DES },
+ { IKEV1_ESP_ENCR_3DES, ENCR_3DES },
+ { IKEV1_ESP_ENCR_RC5, ENCR_RC5 },
+ { IKEV1_ESP_ENCR_IDEA, ENCR_IDEA },
+ { IKEV1_ESP_ENCR_CAST, ENCR_CAST },
+ { IKEV1_ESP_ENCR_BLOWFISH, ENCR_BLOWFISH },
+ { IKEV1_ESP_ENCR_3IDEA, ENCR_3IDEA },
+ { IKEV1_ESP_ENCR_DES_IV32, ENCR_DES_IV32 },
+ { IKEV1_ESP_ENCR_NULL, ENCR_NULL },
+ { IKEV1_ESP_ENCR_AES_CBC, ENCR_AES_CBC },
+ { IKEV1_ESP_ENCR_AES_CTR, ENCR_AES_CTR },
+ { IKEV1_ESP_ENCR_AES_CCM_8, ENCR_AES_CCM_ICV8 },
+ { IKEV1_ESP_ENCR_AES_CCM_12, ENCR_AES_CCM_ICV12 },
+ { IKEV1_ESP_ENCR_AES_CCM_16, ENCR_AES_CCM_ICV16 },
+ { IKEV1_ESP_ENCR_AES_GCM_8, ENCR_AES_GCM_ICV8 },
+ { IKEV1_ESP_ENCR_AES_GCM_12, ENCR_AES_GCM_ICV12 },
+ { IKEV1_ESP_ENCR_AES_GCM_16, ENCR_AES_GCM_ICV16 },
+ { IKEV1_ESP_ENCR_CAMELLIA, ENCR_CAMELLIA_CBC },
+ { IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC, ENCR_NULL_AUTH_AES_GMAC },
+ { IKEV1_ESP_ENCR_SERPENT, ENCR_SERPENT_CBC },
+ { IKEV1_ESP_ENCR_TWOFISH, ENCR_TWOFISH_CBC },
+};
+
+/**
+ * ESP authentication algorithm mapping
+ */
+static algo_map_t map_esp_auth[] = {
+ { IKEV1_ESP_AUTH_HMAC_MD5, AUTH_HMAC_MD5_96 },
+ { IKEV1_ESP_AUTH_HMAC_SHA, AUTH_HMAC_SHA1_96 },
+ { IKEV1_ESP_AUTH_DES_MAC, AUTH_DES_MAC },
+ { IKEV1_ESP_AUTH_KPDK, AUTH_KPDK_MD5 },
+ { IKEV1_ESP_AUTH_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_128 },
+ { IKEV1_ESP_AUTH_HMAC_SHA2_384, AUTH_HMAC_SHA2_384_192 },
+ { IKEV1_ESP_AUTH_HMAC_SHA2_512, AUTH_HMAC_SHA2_512_256 },
+ { IKEV1_ESP_AUTH_AES_XCBC_MAC, AUTH_AES_XCBC_96 },
+ { IKEV1_ESP_AUTH_AES_128_GMAC, AUTH_AES_128_GMAC },
+ { IKEV1_ESP_AUTH_AES_192_GMAC, AUTH_AES_192_GMAC },
+ { IKEV1_ESP_AUTH_AES_256_GMAC, AUTH_AES_256_GMAC },
+};
+
+/**
+ * Get IKEv2 algorithm from IKEv1 identifier
+ */
+static u_int16_t get_alg_from_ikev1(transform_type_t type, u_int16_t value)
+{
+ algo_map_t *map;
+ u_int16_t def;
+ int i, count;
+
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ map = map_encr;
+ count = countof(map_encr);
+ def = ENCR_UNDEFINED;
+ break;
+ case INTEGRITY_ALGORITHM:
+ map = map_integ;
+ count = countof(map_integ);
+ def = AUTH_UNDEFINED;
+ break;
+ case PSEUDO_RANDOM_FUNCTION:
+ map = map_prf;
+ count = countof(map_prf);
+ def = PRF_UNDEFINED;
+ break;
+ default:
+ return 0;
+ }
+ for (i = 0; i < count; i++)
+ {
+ if (map[i].ikev1 == value)
+ {
+ return map[i].ikev2;
+ }
+ }
+ return def;
+}
+
+/**
+ * Get IKEv1 algorithm from IKEv2 identifier
+ */
+static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value)
+{
+ algo_map_t *map;
+ int i, count;
+
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ map = map_encr;
+ count = countof(map_encr);
+ break;
+ case INTEGRITY_ALGORITHM:
+ map = map_integ;
+ count = countof(map_integ);
+ break;
+ case PSEUDO_RANDOM_FUNCTION:
+ map = map_prf;
+ count = countof(map_prf);
+ break;
+ default:
+ return 0;
+ }
+ for (i = 0; i < count; i++)
+ {
+ if (map[i].ikev2 == value)
+ {
+ return map[i].ikev1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Get IKEv2 algorithm from IKEv1 ESP transaction ID
+ */
+static u_int16_t get_alg_from_ikev1_transid(transform_type_t type, u_int16_t value)
+{
+ algo_map_t *map;
+ u_int16_t def;
+ int i, count;
+
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ map = map_esp_encr;
+ count = countof(map_esp_encr);
+ def = ENCR_UNDEFINED;
+ break;
+ case INTEGRITY_ALGORITHM:
+ map = map_esp_auth;
+ count = countof(map_esp_auth);
+ def = AUTH_UNDEFINED;
+ break;
+ default:
+ return 0;
+ }
+ for (i = 0; i < count; i++)
+ {
+ if (map[i].ikev1 == value)
+ {
+ return map[i].ikev2;
+ }
+ }
+ return def;
+}
+
+/**
+ * Get IKEv1 ESP transaction ID from IKEv2 identifier
+ */
+static u_int16_t get_ikev1_transid_from_alg(transform_type_t type, u_int16_t value)
+{
+ algo_map_t *map;
+ int i, count;
+
+ switch (type)
+ {
+ case ENCRYPTION_ALGORITHM:
+ map = map_esp_encr;
+ count = countof(map_esp_encr);
+ break;
+ case INTEGRITY_ALGORITHM:
+ map = map_esp_auth;
+ count = countof(map_esp_auth);
+ break;
+ default:
+ return 0;
+ }
+ for (i = 0; i < count; i++)
+ {
+ if (map[i].ikev2 == value)
+ {
+ return map[i].ikev1;
+ }
+ }
+ return 0;
+}
+/**
+ * Get IKEv1 authentication attribute from auth_method_t
+ */
+static u_int16_t get_ikev1_auth(auth_method_t method)
+{
+ switch (method)
+ {
+ case AUTH_RSA:
+ return IKEV1_AUTH_RSA_SIG;
+ case AUTH_DSS:
+ return IKEV1_AUTH_DSS_SIG;
+ case AUTH_XAUTH_INIT_PSK:
+ return IKEV1_AUTH_XAUTH_INIT_PSK;
+ case AUTH_XAUTH_RESP_PSK:
+ return IKEV1_AUTH_XAUTH_RESP_PSK;
+ case AUTH_XAUTH_INIT_RSA:
+ return IKEV1_AUTH_XAUTH_INIT_RSA;
+ case AUTH_XAUTH_RESP_RSA:
+ return IKEV1_AUTH_XAUTH_RESP_RSA;
+ case AUTH_HYBRID_INIT_RSA:
+ return IKEV1_AUTH_HYBRID_INIT_RSA;
+ case AUTH_HYBRID_RESP_RSA:
+ return IKEV1_AUTH_HYBRID_RESP_RSA;
+ case AUTH_ECDSA_256:
+ return IKEV1_AUTH_ECDSA_256;
+ case AUTH_ECDSA_384:
+ return IKEV1_AUTH_ECDSA_384;
+ case AUTH_ECDSA_521:
+ return IKEV1_AUTH_ECDSA_521;
+ case AUTH_PSK:
+ default:
+ return IKEV1_AUTH_PSK;
+ }
+}
+
+/**
+ * Get IKEv1 encapsulation mode
+ */
+static u_int16_t get_ikev1_mode(ipsec_mode_t mode, bool udp)
+{
+ switch (mode)
+ {
+ case MODE_TUNNEL:
+ return udp ? IKEV1_ENCAP_UDP_TUNNEL : IKEV1_ENCAP_TUNNEL;
+ case MODE_TRANSPORT:
+ return udp ? IKEV1_ENCAP_UDP_TRANSPORT : IKEV1_ENCAP_TRANSPORT;
+ default:
+ return IKEV1_ENCAP_TUNNEL;
+ }
+}
+
+/**
+ * Add an IKE transform to a proposal for IKEv1
+ */
+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:
+ 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)
+{
+ transform_attribute_type_t type;
+ transform_attribute_t *tattr;
+ enumerator_t *enumerator;
+ u_int16_t encr, value, key_length = 0;
+
+ enumerator = transform->create_attribute_enumerator(transform);
+ while (enumerator->enumerate(enumerator, &tattr))
+ {
+ type = tattr->get_attribute_type(tattr);
+ value = tattr->get_value(tattr);
+ switch (type)
+ {
+ case TATTR_PH2_KEY_LENGTH:
+ key_length = value;
+ break;
+ case TATTR_PH2_AUTH_ALGORITHM:
+ proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM,
+ get_alg_from_ikev1_transid(INTEGRITY_ALGORITHM,
+ value), 0);
+ break;
+ case TATTR_PH2_GROUP:
+ proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP,
+ value, 0);
+ break;
+ default:
+ break;
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ /* TODO-IKEv1: handle ESN attribute */
+ proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS,
+ NO_EXT_SEQ_NUMBERS, 0);
+ encr = get_alg_from_ikev1_transid(ENCRYPTION_ALGORITHM,
+ transform->get_transform_id(transform));
+ if (encr)
+ {
+ proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr,
+ key_length);
+ }
+}
+
+METHOD(proposal_substructure_t, get_proposals, void,
+ private_proposal_substructure_t *this, linked_list_t *proposals)
+{
+ transform_substructure_t *transform;
+ enumerator_t *enumerator;
+ proposal_t *proposal = NULL;
+ u_int64_t spi = 0;
+
switch (this->spi.len)
{
case 4:
- spi = *((u_int32_t*)this->spi.ptr);
+ spi = *((u_int32_t*)this->spi.ptr);
break;
case 8:
spi = *((u_int64_t*)this->spi.ptr);
break;
default:
- spi = 0;
+ break;
}
- proposal->set_spi(proposal, spi);
- return proposal;
+ enumerator = this->transforms->create_enumerator(this->transforms);
+ while (enumerator->enumerate(enumerator, &transform))
+ {
+ if (!proposal)
+ {
+ proposal = proposal_create(this->protocol_id, this->proposal_number);
+ proposal->set_spi(proposal, spi);
+ proposals->insert_last(proposals, proposal);
+ }
+ if (this->type == PROPOSAL_SUBSTRUCTURE)
+ {
+ add_to_proposal_v2(proposal, transform);
+ }
+ 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;
+ }
+ /* create a new proposal for each transform in IKEv1 */
+ proposal = NULL;
+ }
+ }
+ enumerator->destroy(enumerator);
}
METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*,
@@ -348,11 +977,170 @@ METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*,
return this->transforms->create_enumerator(this->transforms);
}
+/**
+ * Get an attribute from any transform, 0 if not found
+ */
+static u_int64_t get_attr(private_proposal_substructure_t *this,
+ transform_attribute_type_t type)
+{
+ enumerator_t *transforms, *attributes;
+ transform_substructure_t *transform;
+ transform_attribute_t *attr;
+
+ transforms = this->transforms->create_enumerator(this->transforms);
+ while (transforms->enumerate(transforms, &transform))
+ {
+ attributes = transform->create_attribute_enumerator(transform);
+ while (attributes->enumerate(attributes, &attr))
+ {
+ if (attr->get_attribute_type(attr) == type)
+ {
+ attributes->destroy(attributes);
+ transforms->destroy(transforms);
+ return attr->get_value(attr);
+ }
+ }
+ attributes->destroy(attributes);
+ }
+ transforms->destroy(transforms);
+ return 0;
+}
+
+/**
+ * Look up a lifetime duration of a given kind in all transforms
+ */
+static u_int64_t get_life_duration(private_proposal_substructure_t *this,
+ transform_attribute_type_t type_attr, ikev1_life_type_t type,
+ transform_attribute_type_t dur_attr)
+{
+ enumerator_t *transforms, *attributes;
+ transform_substructure_t *transform;
+ transform_attribute_t *attr;
+
+ transforms = this->transforms->create_enumerator(this->transforms);
+ while (transforms->enumerate(transforms, &transform))
+ {
+ attributes = transform->create_attribute_enumerator(transform);
+ while (attributes->enumerate(attributes, &attr))
+ {
+ if (attr->get_attribute_type(attr) == type_attr &&
+ attr->get_value(attr) == type)
+ { /* got type attribute, look for duration following next */
+ while (attributes->enumerate(attributes, &attr))
+ {
+ if (attr->get_attribute_type(attr) == dur_attr)
+ {
+ attributes->destroy(attributes);
+ transforms->destroy(transforms);
+ return attr->get_value(attr);
+ }
+ }
+ }
+ }
+ attributes->destroy(attributes);
+ }
+ transforms->destroy(transforms);
+ return 0;
+}
+
+METHOD(proposal_substructure_t, get_lifetime, u_int32_t,
+ private_proposal_substructure_t *this)
+{
+ u_int32_t duration;
+
+ switch (this->protocol_id)
+ {
+ case PROTO_IKE:
+ return get_life_duration(this, TATTR_PH1_LIFE_TYPE,
+ IKEV1_LIFE_TYPE_SECONDS, TATTR_PH1_LIFE_DURATION);
+ case PROTO_ESP:
+ duration = get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE,
+ IKEV1_LIFE_TYPE_SECONDS, TATTR_PH2_SA_LIFE_DURATION);
+ if (!duration)
+ { /* default to 8 hours, RFC 2407 */
+ return 28800;
+ }
+ return duration;
+ default:
+ return 0;
+ }
+}
+
+METHOD(proposal_substructure_t, get_lifebytes, u_int64_t,
+ private_proposal_substructure_t *this)
+{
+ switch (this->protocol_id)
+ {
+ case PROTO_ESP:
+ return 1000 * get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE,
+ IKEV1_LIFE_TYPE_KILOBYTES, TATTR_PH2_SA_LIFE_DURATION);
+ case PROTO_IKE:
+ default:
+ return 0;
+ }
+}
+
+METHOD(proposal_substructure_t, get_auth_method, auth_method_t,
+ private_proposal_substructure_t *this)
+{
+ switch (get_attr(this, TATTR_PH1_AUTH_METHOD))
+ {
+ case IKEV1_AUTH_PSK:
+ return AUTH_PSK;
+ case IKEV1_AUTH_RSA_SIG:
+ return AUTH_RSA;
+ case IKEV1_AUTH_DSS_SIG:
+ return AUTH_DSS;
+ case IKEV1_AUTH_XAUTH_INIT_PSK:
+ return AUTH_XAUTH_INIT_PSK;
+ case IKEV1_AUTH_XAUTH_RESP_PSK:
+ return AUTH_XAUTH_RESP_PSK;
+ case IKEV1_AUTH_XAUTH_INIT_RSA:
+ return AUTH_XAUTH_INIT_RSA;
+ case IKEV1_AUTH_XAUTH_RESP_RSA:
+ return AUTH_XAUTH_RESP_RSA;
+ case IKEV1_AUTH_HYBRID_INIT_RSA:
+ return AUTH_HYBRID_INIT_RSA;
+ case IKEV1_AUTH_HYBRID_RESP_RSA:
+ return AUTH_HYBRID_RESP_RSA;
+ case IKEV1_AUTH_ECDSA_256:
+ return AUTH_ECDSA_256;
+ case IKEV1_AUTH_ECDSA_384:
+ return AUTH_ECDSA_384;
+ case IKEV1_AUTH_ECDSA_521:
+ return AUTH_ECDSA_521;
+ default:
+ return AUTH_NONE;
+ }
+}
+
+METHOD(proposal_substructure_t, get_encap_mode, ipsec_mode_t,
+ private_proposal_substructure_t *this, bool *udp)
+{
+ *udp = FALSE;
+ switch (get_attr(this, TATTR_PH2_ENCAP_MODE))
+ {
+ case IKEV1_ENCAP_TRANSPORT:
+ return MODE_TRANSPORT;
+ case IKEV1_ENCAP_TUNNEL:
+ return MODE_TUNNEL;
+ case IKEV1_ENCAP_UDP_TRANSPORT:
+ *udp = TRUE;
+ return MODE_TRANSPORT;
+ case IKEV1_ENCAP_UDP_TUNNEL:
+ *udp = TRUE;
+ return MODE_TUNNEL;
+ default:
+ /* default to TUNNEL, RFC 2407 says implementation specific */
+ return MODE_TUNNEL;
+ }
+}
+
METHOD2(payload_t, proposal_substructure_t, destroy, void,
private_proposal_substructure_t *this)
{
this->transforms->destroy_offset(this->transforms,
- offsetof(transform_substructure_t, destroy));
+ offsetof(payload_t, destroy));
chunk_free(&this->spi);
free(this);
}
@@ -360,7 +1148,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;
@@ -369,6 +1157,7 @@ proposal_substructure_t *proposal_substructure_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -380,39 +1169,197 @@ proposal_substructure_t *proposal_substructure_create()
.set_protocol_id = _set_protocol_id,
.get_protocol_id = _get_protocol_id,
.set_is_last_proposal = _set_is_last_proposal,
- .get_proposal = _get_proposal,
+ .get_proposals = _get_proposals,
.create_substructure_enumerator = _create_substructure_enumerator,
.set_spi = _set_spi,
.get_spi = _get_spi,
+ .get_cpi = _get_cpi,
+ .get_lifetime = _get_lifetime,
+ .get_lifebytes = _get_lifebytes,
+ .get_auth_method = _get_auth_method,
+ .get_encap_mode = _get_encap_mode,
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH,
.transforms = linked_list_create(),
+ .type = type,
);
+ compute_length(this);
return &this->public;
}
-/*
- * Described in header.
+/**
+ * Add an IKEv1 IKE proposal to the substructure
*/
-proposal_substructure_t *proposal_substructure_create_from_proposal(
- proposal_t *proposal)
+static void set_from_proposal_v1_ike(private_proposal_substructure_t *this,
+ proposal_t *proposal, u_int32_t lifetime,
+ auth_method_t method, int number)
{
transform_substructure_t *transform;
- private_proposal_substructure_t *this;
u_int16_t alg, key_size;
enumerator_t *enumerator;
- this = (private_proposal_substructure_t*)proposal_substructure_create();
+ transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1,
+ number, IKEV1_TRANSID_KEY_IKE);
+
+ enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM);
+ if (enumerator->enumerate(enumerator, &alg, &key_size))
+ {
+ alg = get_ikev1_from_alg(ENCRYPTION_ALGORITHM, alg);
+ if (alg)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH1_ENCRYPTION_ALGORITHM, alg));
+ if (key_size)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH1_KEY_LENGTH, key_size));
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ /* encode the integrity algorithm as hash and assume use the same PRF */
+ enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM);
+ if (enumerator->enumerate(enumerator, &alg, &key_size))
+ {
+ alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg);
+ if (alg)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH1_HASH_ALGORITHM, alg));
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP);
+ if (enumerator->enumerate(enumerator, &alg, &key_size))
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH1_GROUP, alg));
+ }
+ enumerator->destroy(enumerator);
+
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH1_AUTH_METHOD, get_ikev1_auth(method)));
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH1_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS));
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH1_LIFE_DURATION, lifetime));
+
+ add_transform_substructure(this, transform);
+}
+
+/**
+ * Add an IKEv1 ESP proposal to the substructure
+ */
+static void set_from_proposal_v1_esp(private_proposal_substructure_t *this,
+ proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes,
+ ipsec_mode_t mode, bool udp, int number)
+{
+ transform_substructure_t *transform = NULL;
+ u_int16_t alg, key_size;
+ enumerator_t *enumerator;
+
+ enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM);
+ if (enumerator->enumerate(enumerator, &alg, &key_size))
+ {
+ alg = get_ikev1_transid_from_alg(ENCRYPTION_ALGORITHM, alg);
+ if (alg)
+ {
+ transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1,
+ number, alg);
+ if (key_size)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_KEY_LENGTH, key_size));
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+ if (!transform)
+ {
+ return;
+ }
+
+ enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM);
+ if (enumerator->enumerate(enumerator, &alg, &key_size))
+ {
+ alg = get_ikev1_transid_from_alg(INTEGRITY_ALGORITHM, alg);
+ if (alg)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_AUTH_ALGORITHM, alg));
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP);
+ if (enumerator->enumerate(enumerator, &alg, &key_size))
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_GROUP, alg));
+ }
+ enumerator->destroy(enumerator);
+
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp)));
+ if (lifetime)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS));
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_SA_LIFE_DURATION, lifetime));
+ }
+ if (lifebytes)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES));
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000));
+ }
+
+ add_transform_substructure(this, transform);
+}
+
+/**
+ * Add an IKEv2 proposal to the substructure
+ */
+static void set_from_proposal_v2(private_proposal_substructure_t *this,
+ proposal_t *proposal)
+{
+ transform_substructure_t *transform;
+ u_int16_t alg, key_size;
+ enumerator_t *enumerator;
/* encryption algorithm is only available in ESP */
enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM);
while (enumerator->enumerate(enumerator, &alg, &key_size))
{
- transform = transform_substructure_create_type(ENCRYPTION_ALGORITHM,
- alg, key_size);
+ transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE,
+ ENCRYPTION_ALGORITHM, alg);
+ if (key_size)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE,
+ TATTR_IKEV2_KEY_LENGTH, key_size));
+ }
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
@@ -421,8 +1368,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(TRANSFORM_SUBSTRUCTURE,
+ INTEGRITY_ALGORITHM, alg);
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
@@ -431,8 +1378,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(TRANSFORM_SUBSTRUCTURE,
+ PSEUDO_RANDOM_FUNCTION, alg);
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
@@ -441,8 +1388,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(TRANSFORM_SUBSTRUCTURE,
+ DIFFIE_HELLMAN_GROUP, alg);
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
@@ -451,27 +1398,36 @@ 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(TRANSFORM_SUBSTRUCTURE,
+ EXTENDED_SEQUENCE_NUMBERS, alg);
add_transform_substructure(this, transform);
}
enumerator->destroy(enumerator);
+}
+
+/**
+ * Set SPI and other data from proposal, compute length
+ */
+static void set_data(private_proposal_substructure_t *this, proposal_t *proposal)
+{
+ u_int64_t spi64;
+ u_int32_t spi32;
/* add SPI, if necessary */
switch (proposal->get_protocol(proposal))
{
case PROTO_AH:
case PROTO_ESP:
- this->spi_size = this->spi.len = 4;
- this->spi.ptr = malloc(this->spi_size);
- *((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal);
+ spi32 = proposal->get_spi(proposal);
+ this->spi = chunk_clone(chunk_from_thing(spi32));
+ this->spi_size = this->spi.len;
break;
case PROTO_IKE:
- if (proposal->get_spi(proposal))
+ spi64 = proposal->get_spi(proposal);
+ if (spi64)
{ /* IKE only uses SPIS when rekeying, but on initial setup */
- this->spi_size = this->spi.len = 8;
- this->spi.ptr = malloc(this->spi_size);
- *((u_int64_t*)this->spi.ptr) = proposal->get_spi(proposal);
+ this->spi = chunk_clone(chunk_from_thing(spi64));
+ this->spi_size = this->spi.len;
}
break;
default:
@@ -480,6 +1436,144 @@ proposal_substructure_t *proposal_substructure_create_from_proposal(
this->proposal_number = proposal->get_number(proposal);
this->protocol_id = proposal->get_protocol(proposal);
compute_length(this);
+}
+
+/*
+ * Described in header.
+ */
+proposal_substructure_t *proposal_substructure_create_from_proposal_v2(
+ proposal_t *proposal)
+{
+ private_proposal_substructure_t *this;
+
+ this = (private_proposal_substructure_t*)
+ proposal_substructure_create(SECURITY_ASSOCIATION);
+ set_from_proposal_v2(this, proposal);
+ set_data(this, proposal);
+
+ return &this->public;
+}
+
+/**
+ * See header.
+ */
+proposal_substructure_t *proposal_substructure_create_from_proposal_v1(
+ proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes,
+ auth_method_t auth, ipsec_mode_t mode, bool udp)
+{
+ private_proposal_substructure_t *this;
+
+ this = (private_proposal_substructure_t*)
+ proposal_substructure_create(PROPOSAL_SUBSTRUCTURE_V1);
+ switch (proposal->get_protocol(proposal))
+ {
+ case PROTO_IKE:
+ set_from_proposal_v1_ike(this, proposal, lifetime, auth, 1);
+ break;
+ case PROTO_ESP:
+ set_from_proposal_v1_esp(this, proposal, lifetime,
+ lifebytes, mode, udp, 1);
+ break;
+ default:
+ break;
+ }
+ set_data(this, proposal);
+
+ return &this->public;
+}
+
+/**
+ * See header.
+ */
+proposal_substructure_t *proposal_substructure_create_from_proposals_v1(
+ linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes,
+ auth_method_t auth, ipsec_mode_t mode, bool udp)
+{
+ private_proposal_substructure_t *this = NULL;
+ enumerator_t *enumerator;
+ proposal_t *proposal;
+ int number = 0;
+
+ enumerator = proposals->create_enumerator(proposals);
+ while (enumerator->enumerate(enumerator, &proposal))
+ {
+ if (!this)
+ {
+ this = (private_proposal_substructure_t*)
+ proposal_substructure_create_from_proposal_v1(
+ proposal, lifetime, lifebytes, auth, mode, udp);
+ ++number;
+ }
+ else
+ {
+ switch (proposal->get_protocol(proposal))
+ {
+ case PROTO_IKE:
+ set_from_proposal_v1_ike(this, proposal, lifetime,
+ auth, ++number);
+ break;
+ case PROTO_ESP:
+ set_from_proposal_v1_esp(this, proposal, lifetime,
+ lifebytes, mode, udp, ++number);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ enumerator->destroy(enumerator);
+
+ return &this->public;
+}
+
+/**
+ * See header.
+ */
+proposal_substructure_t *proposal_substructure_create_for_ipcomp_v1(
+ u_int32_t lifetime, u_int64_t lifebytes, u_int16_t cpi,
+ ipsec_mode_t mode, bool udp, u_int8_t proposal_number)
+{
+ private_proposal_substructure_t *this;
+ transform_substructure_t *transform;
+
+
+ this = (private_proposal_substructure_t*)
+ proposal_substructure_create(PROPOSAL_SUBSTRUCTURE_V1);
+
+ /* we currently support DEFLATE only */
+ transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1,
+ 1, IKEV1_IPCOMP_DEFLATE);
+
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp)));
+ if (lifetime)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS));
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_SA_LIFE_DURATION, lifetime));
+ }
+ if (lifebytes)
+ {
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES));
+ transform->add_transform_attribute(transform,
+ transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1,
+ TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000));
+ }
+
+ add_transform_substructure(this, transform);
+
+ this->spi = chunk_clone(chunk_from_thing(cpi));
+ this->spi_size = this->spi.len;
+ this->protocol_id = PROTO_IPCOMP;
+ this->proposal_number = proposal_number;
+
+ compute_length(this);
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h
index d0ba1fd2a..5d42a6116 100644
--- a/src/libcharon/encoding/payloads/proposal_substructure.h
+++ b/src/libcharon/encoding/payloads/proposal_substructure.h
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2006 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -29,17 +30,11 @@ typedef struct proposal_substructure_t proposal_substructure_t;
#include <encoding/payloads/transform_substructure.h>
#include <config/proposal.h>
#include <utils/linked_list.h>
-
+#include <kernel/kernel_ipsec.h>
+#include <sa/authenticator.h>
/**
- * Length of the proposal substructure header (without spi).
- */
-#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 {
@@ -58,7 +53,7 @@ struct proposal_substructure_t {
/**
* get proposal number of current proposal.
*
- * @return proposal number of current proposal substructure.
+ * @return proposal number of current proposal substructure.
*/
u_int8_t (*get_proposal_number) (proposal_substructure_t *this);
@@ -73,7 +68,7 @@ struct proposal_substructure_t {
/**
* get protocol id of current proposal.
*
- * @return protocol id of current proposal substructure.
+ * @return protocol id of current proposal substructure.
*/
u_int8_t (*get_protocol_id) (proposal_substructure_t *this);
@@ -90,7 +85,7 @@ struct proposal_substructure_t {
/**
* Returns the currently set SPI of this proposal.
*
- * @return chunk_t pointing to the value
+ * @return chunk_t pointing to the value
*/
chunk_t (*get_spi) (proposal_substructure_t *this);
@@ -104,11 +99,19 @@ struct proposal_substructure_t {
void (*set_spi) (proposal_substructure_t *this, chunk_t spi);
/**
- * Get a proposal_t from the propsal_substructure_t.
+ * Gets the CPI of the current proposal (IKEv1 only).
+ *
+ * @param cpi the CPI if a supported algorithm is proposed
+ * @return TRUE if a supported algorithm is proposed
+ */
+ bool (*get_cpi) (proposal_substructure_t *this, u_int16_t *cpi);
+
+ /**
+ * Get proposals contained in a propsal_substructure_t.
*
- * @return proposal_t
+ * @param list list to add created proposals to
*/
- proposal_t * (*get_proposal) (proposal_substructure_t *this);
+ void (*get_proposals) (proposal_substructure_t *this, linked_list_t *list);
/**
* Create an enumerator over transform substructures.
@@ -118,6 +121,35 @@ struct proposal_substructure_t {
enumerator_t* (*create_substructure_enumerator)(proposal_substructure_t *this);
/**
+ * Get the (shortest) lifetime of a proposal (IKEv1 only).
+ *
+ * @return lifetime, in seconds
+ */
+ u_int32_t (*get_lifetime)(proposal_substructure_t *this);
+
+ /**
+ * Get the (shortest) life duration of a proposal (IKEv1 only).
+ *
+ * @return life duration, in bytes
+ */
+ u_int64_t (*get_lifebytes)(proposal_substructure_t *this);
+
+ /**
+ * Get the first authentication method from the proposal (IKEv1 only).
+ *
+ * @return auth method, or AUTH_NONE
+ */
+ auth_method_t (*get_auth_method)(proposal_substructure_t *this);
+
+ /**
+ * Get the (first) encapsulation mode from a proposal (IKEv1 only).
+ *
+ * @param udp set to TRUE if UDP encapsulation used
+ * @return ipsec encapsulation mode
+ */
+ ipsec_mode_t (*get_encap_mode)(proposal_substructure_t *this, bool *udp);
+
+ /**
* Destroys an proposal_substructure_t object.
*/
void (*destroy) (proposal_substructure_t *this);
@@ -126,17 +158,63 @@ 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.
+ * Creates an IKEv2 proposal_substructure_t from a proposal_t.
*
- * @param proposal proposal to build a substruct out of it
- * @return proposal_substructure_t object
+ * @param proposal proposal to build a substruct out of it
+ * @return proposal_substructure_t PROPOSAL_SUBSTRUCTURE
*/
-proposal_substructure_t *proposal_substructure_create_from_proposal(
+proposal_substructure_t *proposal_substructure_create_from_proposal_v2(
proposal_t *proposal);
+/**
+ * Creates an IKEv1 proposal_substructure_t from a proposal_t.
+ *
+ * @param proposal proposal to build a substruct out of it
+ * @param lifetime lifetime in seconds
+ * @param lifebytes lifebytes, in bytes
+ * @param auth authentication method to use, or AUTH_NONE
+ * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL
+ * @param udp TRUE to use UDP encapsulation
+ * @return proposal_substructure_t object PROPOSAL_SUBSTRUCTURE_V1
+ */
+proposal_substructure_t *proposal_substructure_create_from_proposal_v1(
+ proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes,
+ auth_method_t auth, ipsec_mode_t mode, bool udp);
+
+/**
+ * Creates an IKEv1 proposal_substructure_t from a list of proposal_t.
+ *
+ * @param proposals list of proposal_t to encode in a substructure
+ * @param lifetime lifetime in seconds
+ * @param lifebytes lifebytes, in bytes
+ * @param auth authentication method to use, or AUTH_NONE
+ * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL
+ * @param udp TRUE to use UDP encapsulation
+ * @return IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1
+ */
+proposal_substructure_t *proposal_substructure_create_from_proposals_v1(
+ linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes,
+ auth_method_t auth, ipsec_mode_t mode, bool udp);
+
+/**
+ * Creates an IKEv1 proposal_substructure_t for IPComp with the given
+ * proposal_number (e.g. of a ESP proposal to bundle them).
+ *
+ * @param lifetime lifetime in seconds
+ * @param lifebytes lifebytes, in bytes
+ * @param cpi the CPI to be used
+ * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL
+ * @param udp TRUE to use UDP encapsulation
+ * @param proposal_number the proposal number of the proposal to be linked
+ * @return IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1
+ */
+proposal_substructure_t *proposal_substructure_create_for_ipcomp_v1(
+ u_int32_t lifetime, u_int64_t lifebytes, u_int16_t cpi,
+ ipsec_mode_t mode, bool udp, u_int8_t proposal_number);
#endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c
index 010f63cfd..adf19aa67 100644
--- a/src/libcharon/encoding/payloads/sa_payload.c
+++ b/src/libcharon/encoding/payloads/sa_payload.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2005-2010 Martin Willi
* Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil
@@ -22,6 +23,8 @@
#include <utils/linked_list.h>
#include <daemon.h>
+/* IKEv1 situation */
+#define SIT_IDENTITY_ONLY 1
typedef struct private_sa_payload_t private_sa_payload_t;
@@ -48,7 +51,7 @@ struct private_sa_payload_t {
/**
* Reserved bits
*/
- bool reserved[7];
+ bool reserved[8];
/**
* Length of this payload.
@@ -58,21 +61,75 @@ struct private_sa_payload_t {
/**
* Proposals in this payload are stored in a linked_list_t.
*/
- linked_list_t * proposals;
+ linked_list_t *proposals;
+
+ /**
+ * Type of this payload, V1 or V2
+ */
+ payload_type_t type;
+
+ /**
+ * IKEv1 DOI
+ */
+ u_int32_t doi;
+
+ /**
+ * IKEv1 situation
+ */
+ u_int32_t situation;
};
/**
- * Encoding rules to parse or generate a IKEv2-SA Payload
- *
- * The defined offsets are the positions in a object of type
- * private_sa_payload_t.
+ * Encoding rules for IKEv1 SA payload
*/
-encoding_rule_t sa_payload_encodings[] = {
+static encoding_rule_t encodings_v1[] = {
+ /* 1 Byte next payload type, stored in the field next_payload */
+ { U_INT_8, offsetof(private_sa_payload_t, next_payload) },
+ /* 8 reserved bits */
+ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) },
+ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) },
+ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) },
+ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[3]) },
+ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[4]) },
+ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[5]) },
+ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) },
+ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[7]) },
+ /* Length of the whole SA payload*/
+ { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) },
+ /* DOI*/
+ { U_INT_32, offsetof(private_sa_payload_t, doi) },
+ /* Situation*/
+ { U_INT_32, offsetof(private_sa_payload_t, situation) },
+ /* Proposals are stored in a proposal substructure list */
+ { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1,
+ offsetof(private_sa_payload_t, proposals) },
+};
+
+/*
+ 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Next Payload ! RESERVED ! Payload Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! DOI !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Situation !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! !
+ ~ <Proposals> ~
+ ! !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
+/**
+ * Encoding rules for IKEv2 SA payload
+ */
+static encoding_rule_t encodings_v2[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_sa_payload_t, next_payload) },
/* the critical bit */
{ FLAG, offsetof(private_sa_payload_t, critical) },
- /* 7 Bit reserved bits, nowhere stored */
+ /* 7 Bit reserved bits */
{ RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) },
{ RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) },
{ RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) },
@@ -82,9 +139,9 @@ encoding_rule_t sa_payload_encodings[] = {
{ RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) },
/* Length of the whole SA payload*/
{ PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) },
- /* Proposals are stored in a proposal substructure,
- offset points to a linked_list_t pointer */
- { PROPOSALS, offsetof(private_sa_payload_t, proposals) },
+ /* Proposals are stored in a proposal substructure list */
+ { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE,
+ offsetof(private_sa_payload_t, proposals) },
};
/*
@@ -102,11 +159,16 @@ encoding_rule_t sa_payload_encodings[] = {
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))
@@ -131,17 +193,32 @@ METHOD(payload_t, verify, status_t,
return status;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_sa_payload_t *this, encoding_rule_t **rules)
+{
+ if (this->type == SECURITY_ASSOCIATION_V1)
+ {
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+ }
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_sa_payload_t *this)
{
- *rules = sa_payload_encodings;
- *rule_count = countof(sa_payload_encodings);
+ if (this->type == SECURITY_ASSOCIATION_V1)
+ {
+ return 12;
+ }
+ return 4;
}
METHOD(payload_t, get_type, payload_type_t,
private_sa_payload_t *this)
{
- return SECURITY_ASSOCIATION;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -163,16 +240,15 @@ static void compute_length(private_sa_payload_t *this)
{
enumerator_t *enumerator;
payload_t *current;
- size_t length = SA_PAYLOAD_HEADER_LENGTH;
+
+ this->payload_length = get_header_length(this);
enumerator = this->proposals->create_enumerator(this->proposals);
while (enumerator->enumerate(enumerator, (void **)&current))
{
- length += current->get_length(current);
+ this->payload_length += current->get_length(current);
}
enumerator->destroy(enumerator);
-
- this->payload_length = length;
}
METHOD(payload_t, get_length, size_t,
@@ -181,14 +257,16 @@ METHOD(payload_t, get_length, size_t,
return this->payload_length;
}
-METHOD(sa_payload_t, add_proposal, void,
- private_sa_payload_t *this, proposal_t *proposal)
+/**
+ * Create a transform substructure from a proposal, add to payload
+ */
+static void add_proposal_v2(private_sa_payload_t *this, proposal_t *proposal)
{
proposal_substructure_t *substruct, *last;
u_int count;
+ substruct = proposal_substructure_create_from_proposal_v2(proposal);
count = this->proposals->get_count(this->proposals);
- substruct = proposal_substructure_create_from_proposal(proposal);
if (count > 0)
{
this->proposals->get_last(this->proposals, (void**)&last);
@@ -215,15 +293,19 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*,
int ignore_struct_number = 0;
enumerator_t *enumerator;
proposal_substructure_t *substruct;
- linked_list_t *list;
- proposal_t *proposal;
+ linked_list_t *substructs, *list;
+
+ 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.
* To handle such structures safely, we just skip proposals with multiple
* protocols.
*/
+ substructs = linked_list_create();
enumerator = this->proposals->create_enumerator(this->proposals);
while (enumerator->enumerate(enumerator, &substruct))
{
@@ -231,22 +313,80 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*,
if (substruct->get_proposal_number(substruct) == struct_number)
{
if (ignore_struct_number < struct_number)
- {
- /* remove an already added, if first of series */
- list->remove_last(list, (void**)&proposal);
- proposal->destroy(proposal);
+ { /* remove an already added, if first of series */
+ substructs->remove_last(substructs, (void**)&substruct);
ignore_struct_number = struct_number;
}
continue;
}
struct_number++;
- proposal = substruct->get_proposal(substruct);
- if (proposal)
+ substructs->insert_last(substructs, substruct);
+ }
+ enumerator->destroy(enumerator);
+
+ /* generate proposals from substructs */
+ list = linked_list_create();
+ enumerator = substructs->create_enumerator(substructs);
+ while (enumerator->enumerate(enumerator, &substruct))
+ {
+ substruct->get_proposals(substruct, list);
+ }
+ enumerator->destroy(enumerator);
+ substructs->destroy(substructs);
+ return list;
+}
+
+METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*,
+ private_sa_payload_t *this, u_int16_t *cpi)
+{
+ int current_proposal = -1, unsupported_proposal = -1;
+ enumerator_t *enumerator;
+ proposal_substructure_t *substruct, *esp = NULL, *ipcomp = NULL;
+ linked_list_t *list;
+
+ /* we currently only support the combination ESP+IPComp, find the first */
+ enumerator = this->proposals->create_enumerator(this->proposals);
+ while (enumerator->enumerate(enumerator, &substruct))
+ {
+ u_int8_t proposal_number = substruct->get_proposal_number(substruct);
+ u_int8_t protocol_id = substruct->get_protocol_id(substruct);
+
+ if (proposal_number == unsupported_proposal)
+ {
+ continue;
+ }
+ if (protocol_id != PROTO_ESP && protocol_id != PROTO_IPCOMP)
+ { /* unsupported combination */
+ esp = ipcomp = NULL;
+ unsupported_proposal = current_proposal;
+ continue;
+ }
+ if (proposal_number != current_proposal)
+ { /* start of a new proposal */
+ if (esp && ipcomp)
+ { /* previous proposal is valid */
+ break;
+ }
+ esp = ipcomp = NULL;
+ current_proposal = proposal_number;
+ }
+ switch (protocol_id)
{
- list->insert_last(list, proposal);
+ case PROTO_ESP:
+ esp = substruct;
+ break;
+ case PROTO_IPCOMP:
+ ipcomp = substruct;
+ break;
}
}
enumerator->destroy(enumerator);
+
+ list = linked_list_create();
+ if (esp && ipcomp && ipcomp->get_cpi(ipcomp, cpi))
+ {
+ esp->get_proposals(esp, list);
+ }
return list;
}
@@ -256,18 +396,86 @@ METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*,
return this->proposals->create_enumerator(this->proposals);
}
+METHOD(sa_payload_t, get_lifetime, u_int32_t,
+ private_sa_payload_t *this)
+{
+ proposal_substructure_t *substruct;
+ enumerator_t *enumerator;
+ u_int32_t lifetime = 0;
+
+ enumerator = this->proposals->create_enumerator(this->proposals);
+ if (enumerator->enumerate(enumerator, &substruct))
+ {
+ lifetime = substruct->get_lifetime(substruct);
+ }
+ enumerator->destroy(enumerator);
+
+ return lifetime;
+}
+
+METHOD(sa_payload_t, get_lifebytes, u_int64_t,
+ private_sa_payload_t *this)
+{
+ proposal_substructure_t *substruct;
+ enumerator_t *enumerator;
+ u_int64_t lifebytes = 0;
+
+ enumerator = this->proposals->create_enumerator(this->proposals);
+ if (enumerator->enumerate(enumerator, &substruct))
+ {
+ lifebytes = substruct->get_lifebytes(substruct);
+ }
+ enumerator->destroy(enumerator);
+
+ return lifebytes;
+}
+
+METHOD(sa_payload_t, get_auth_method, auth_method_t,
+ private_sa_payload_t *this)
+{
+ proposal_substructure_t *substruct;
+ enumerator_t *enumerator;
+ auth_method_t method = AUTH_NONE;
+
+ enumerator = this->proposals->create_enumerator(this->proposals);
+ if (enumerator->enumerate(enumerator, &substruct))
+ {
+ method = substruct->get_auth_method(substruct);
+ }
+ enumerator->destroy(enumerator);
+
+ return method;
+}
+
+METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t,
+ private_sa_payload_t *this, bool *udp)
+{
+ proposal_substructure_t *substruct;
+ enumerator_t *enumerator;
+ ipsec_mode_t mode = MODE_NONE;
+
+ enumerator = this->proposals->create_enumerator(this->proposals);
+ if (enumerator->enumerate(enumerator, &substruct))
+ {
+ mode = substruct->get_encap_mode(substruct, udp);
+ }
+ enumerator->destroy(enumerator);
+
+ return mode;
+}
+
METHOD2(payload_t, sa_payload_t, destroy, void,
private_sa_payload_t *this)
{
this->proposals->destroy_offset(this->proposals,
- offsetof(proposal_substructure_t, destroy));
+ offsetof(payload_t, destroy));
free(this);
}
/*
* Described in header.
*/
-sa_payload_t *sa_payload_create()
+sa_payload_t *sa_payload_create(payload_type_t type)
{
private_sa_payload_t *this;
@@ -276,38 +484,49 @@ sa_payload_t *sa_payload_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
.get_type = _get_type,
.destroy = _destroy,
},
- .add_proposal = _add_proposal,
.get_proposals = _get_proposals,
+ .get_ipcomp_proposals = _get_ipcomp_proposals,
.create_substructure_enumerator = _create_substructure_enumerator,
+ .get_lifetime = _get_lifetime,
+ .get_lifebytes = _get_lifebytes,
+ .get_auth_method = _get_auth_method,
+ .get_encap_mode = _get_encap_mode,
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = SA_PAYLOAD_HEADER_LENGTH,
.proposals = linked_list_create(),
+ .type = type,
+ /* for IKEv1 only */
+ .doi = IKEV1_DOI_IPSEC,
+ .situation = SIT_IDENTITY_ONLY,
);
+
+ compute_length(this);
+
return &this->public;
}
/*
* Described in header.
*/
-sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals)
+sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals)
{
private_sa_payload_t *this;
enumerator_t *enumerator;
proposal_t *proposal;
- this = (private_sa_payload_t*)sa_payload_create();
+ this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION);
enumerator = proposals->create_enumerator(proposals);
while (enumerator->enumerate(enumerator, &proposal))
{
- add_proposal(this, proposal);
+ add_proposal_v2(this, proposal);
}
enumerator->destroy(enumerator);
@@ -317,12 +536,71 @@ sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals)
/*
* Described in header.
*/
-sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal)
+sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal)
+{
+ private_sa_payload_t *this;
+
+ this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION);
+ add_proposal_v2(this, proposal);
+
+ return &this->public;
+
+}
+
+/*
+ * Described in header.
+ */
+sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
+ u_int32_t lifetime, u_int64_t lifebytes,
+ auth_method_t auth, ipsec_mode_t mode, bool udp,
+ u_int16_t cpi)
{
+ proposal_substructure_t *substruct;
private_sa_payload_t *this;
- this = (private_sa_payload_t*)sa_payload_create();
- add_proposal(this, proposal);
+ this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1);
+
+ /* IKEv1 encodes multiple proposals in a single substructure
+ * TODO-IKEv1: Encode ESP+AH proposals in two substructs with same num */
+ substruct = proposal_substructure_create_from_proposals_v1(proposals,
+ lifetime, lifebytes, auth, mode, udp);
+ this->proposals->insert_last(this->proposals, substruct);
+ substruct->set_is_last_proposal(substruct, FALSE);
+ if (cpi)
+ {
+ u_int8_t proposal_number = substruct->get_proposal_number(substruct);
+
+ substruct = proposal_substructure_create_for_ipcomp_v1(lifetime,
+ lifebytes, cpi, mode, udp, proposal_number);
+ this->proposals->insert_last(this->proposals, substruct);
+ substruct->set_is_last_proposal(substruct, FALSE);
+ /* add the proposals again without IPComp */
+ substruct = proposal_substructure_create_from_proposals_v1(proposals,
+ lifetime, lifebytes, auth, mode, udp);
+ substruct->set_proposal_number(substruct, proposal_number + 1);
+ this->proposals->insert_last(this->proposals, substruct);
+ }
+ substruct->set_is_last_proposal(substruct, TRUE);
+ compute_length(this);
+
+ return &this->public;
+}
+
+/*
+ * Described in header.
+ */
+sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal,
+ u_int32_t lifetime, u_int64_t lifebytes,
+ auth_method_t auth, ipsec_mode_t mode, bool udp,
+ u_int16_t cpi)
+{
+ private_sa_payload_t *this;
+ linked_list_t *proposals;
+ proposals = linked_list_create();
+ proposals->insert_last(proposals, proposal);
+ this = (private_sa_payload_t*)sa_payload_create_from_proposals_v1(proposals,
+ lifetime, lifebytes, auth, mode, udp, cpi);
+ proposals->destroy(proposals);
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h
index cc8c481c8..9a88cccd5 100644
--- a/src/libcharon/encoding/payloads/sa_payload.h
+++ b/src/libcharon/encoding/payloads/sa_payload.h
@@ -28,14 +28,11 @@ typedef struct sa_payload_t sa_payload_t;
#include <encoding/payloads/payload.h>
#include <encoding/payloads/proposal_substructure.h>
#include <utils/linked_list.h>
+#include <kernel/kernel_ipsec.h>
+#include <sa/authenticator.h>
/**
- * SA_PAYLOAD length in bytes without any proposal substructure.
- */
-#define SA_PAYLOAD_HEADER_LENGTH 4
-
-/**
- * Class representing an IKEv2-SA Payload.
+ * Class representing an IKEv1 or IKEv2 SA Payload.
*
* The SA Payload format is described in RFC section 3.3.
*/
@@ -49,16 +46,47 @@ struct sa_payload_t {
/**
* Gets the proposals in this payload as a list.
*
- * @return a list containing proposal_t s
+ * @return a list containing proposal_ts
*/
linked_list_t *(*get_proposals) (sa_payload_t *this);
/**
- * Add a child proposal (AH/ESP) to the payload.
+ * Gets the proposals from the first proposal in this payload with IPComp
+ * enabled (IKEv1 only).
+ *
+ * @param cpi the CPI of the first IPComp (sub)proposal
+ * @return a list containing proposal_ts
+ */
+ linked_list_t *(*get_ipcomp_proposals) (sa_payload_t *this, u_int16_t *cpi);
+
+ /**
+ * Get the (shortest) lifetime of a proposal (IKEv1 only).
+ *
+ * @return lifetime, in seconds
+ */
+ u_int32_t (*get_lifetime)(sa_payload_t *this);
+
+ /**
+ * Get the (shortest) life duration of a proposal (IKEv1 only).
+ *
+ * @return life duration, in bytes
+ */
+ u_int64_t (*get_lifebytes)(sa_payload_t *this);
+
+ /**
+ * Get the first authentication method from the proposal (IKEv1 only).
*
- * @param proposal child proposal to add to the payload
+ * @return auth method, or AUTH_NONE
*/
- void (*add_proposal) (sa_payload_t *this, proposal_t *proposal);
+ auth_method_t (*get_auth_method)(sa_payload_t *this);
+
+ /**
+ * Get the (first) encapsulation mode from a proposal (IKEv1 only).
+ *
+ * @param udp set to TRUE if UDP encapsulation used
+ * @return ipsec encapsulation mode
+ */
+ ipsec_mode_t (*get_encap_mode)(sa_payload_t *this, bool *udp);
/**
* Create an enumerator over all proposal substructures.
@@ -76,27 +104,59 @@ struct sa_payload_t {
/**
* Creates an empty sa_payload_t object
*
+ * @param type SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1
* @return created sa_payload_t object
*/
-sa_payload_t *sa_payload_create(void);
+sa_payload_t *sa_payload_create(payload_type_t type);
/**
- * Creates a sa_payload_t object from a list of proposals.
+ * Creates an IKEv2 sa_payload_t object from a list of proposals.
*
* @param proposals list of proposals to build the payload from
* @return sa_payload_t object
*/
-sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals);
+sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals);
/**
- * Creates a sa_payload_t object from a single proposal.
+ * Creates an IKEv2 sa_payload_t object from a single proposal.
*
- * This is only for convenience. Use sa_payload_create_from_proposal_list
- * if you want to add more than one proposal.
+ * @param proposal proposal from which the payload should be built.
+ * @return sa_payload_t object
+ */
+sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal);
+
+/**
+ * Creates an IKEv1 sa_payload_t object from a list of proposals.
+ *
+ * @param proposals list of proposals to build the payload from
+ * @param lifetime lifetime in seconds
+ * @param lifebytes lifebytes, in bytes
+ * @param auth authentication method to use, or AUTH_NONE
+ * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL
+ * @param udp TRUE to use UDP encapsulation
+ * @param cpi CPI in case IPComp should be used
+ * @return sa_payload_t object
+ */
+sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals,
+ u_int32_t lifetime, u_int64_t lifebytes,
+ auth_method_t auth, ipsec_mode_t mode, bool udp,
+ u_int16_t cpi);
+
+/**
+ * Creates an IKEv1 sa_payload_t object from a single proposal.
*
* @param proposal proposal from which the payload should be built.
+ * @param lifetime lifetime in seconds
+ * @param lifebytes lifebytes, in bytes
+ * @param auth authentication method to use, or AUTH_NONE
+ * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL
+ * @param udp TRUE to use UDP encapsulation
+ * @param cpi CPI in case IPComp should be used
* @return sa_payload_t object
*/
-sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal);
+sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal,
+ u_int32_t lifetime, u_int64_t lifebytes,
+ auth_method_t auth, ipsec_mode_t mode, bool udp,
+ u_int16_t cpi);
#endif /** SA_PAYLOAD_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.c b/src/libcharon/encoding/payloads/traffic_selector_substructure.c
index df36e4383..378f5bbc3 100644
--- a/src/libcharon/encoding/payloads/traffic_selector_substructure.c
+++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.c
@@ -74,7 +74,7 @@ struct private_traffic_selector_substructure_t {
* The defined offsets are the positions in a object of type
* private_traffic_selector_substructure_t.
*/
-encoding_rule_t traffic_selector_substructure_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 1 Byte next ts type*/
{ TS_TYPE, offsetof(private_traffic_selector_substructure_t, ts_type) },
/* 1 Byte IP protocol id*/
@@ -148,12 +148,17 @@ METHOD(payload_t, verify, status_t,
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_traffic_selector_substructure_t *this, encoding_rule_t **rules,
- size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_traffic_selector_substructure_t *this, encoding_rule_t **rules)
{
- *rules = traffic_selector_substructure_encodings;
- *rule_count = countof(traffic_selector_substructure_encodings);
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_traffic_selector_substructure_t *this)
+{
+ return 8;
}
METHOD(payload_t, get_type, payload_type_t,
@@ -208,6 +213,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -217,7 +223,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create()
.get_traffic_selector = _get_traffic_selector,
.destroy = _destroy,
},
- .payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH,
+ .payload_length = get_header_length(this),
/* must be set to be valid */
.ts_type = TS_IPV4_ADDR_RANGE,
);
@@ -239,7 +245,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create_from_traff
this->end_port = ts->get_to_port(ts);
this->starting_address = chunk_clone(ts->get_from_address(ts));
this->ending_address = chunk_clone(ts->get_to_address(ts));
- this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH +
+ this->payload_length = get_header_length(this) +
this->ending_address.len + this->starting_address.len;
return &this->public;
diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.h b/src/libcharon/encoding/payloads/traffic_selector_substructure.h
index 0109fd7f5..1ad5fb526 100644
--- a/src/libcharon/encoding/payloads/traffic_selector_substructure.h
+++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.h
@@ -30,11 +30,6 @@ typedef struct traffic_selector_substructure_t traffic_selector_substructure_t;
#include <encoding/payloads/payload.h>
/**
- * Length of a TRAFFIC SELECTOR SUBSTRUCTURE without start and end address.
- */
-#define TRAFFIC_SELECTOR_HEADER_LENGTH 8
-
-/**
* Class representing an IKEv2 TRAFFIC SELECTOR.
*
* The TRAFFIC SELECTOR format is described in RFC section 3.13.1.
diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c
index 7d21258b1..d20f77c59 100644
--- a/src/libcharon/encoding/payloads/transform_attribute.c
+++ b/src/libcharon/encoding/payloads/transform_attribute.c
@@ -17,12 +17,51 @@
#include <string.h>
#include <stddef.h>
+#include <stdint.h>
#include "transform_attribute.h"
#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,30 +96,25 @@ 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) },
+ { ATTRIBUTE_FORMAT, offsetof(private_transform_attribute_t, attribute_format) },
/* type of the attribute as 15 bit unsigned integer */
{ ATTRIBUTE_TYPE, offsetof(private_transform_attribute_t, attribute_type) },
/* Length or value, depending on the attribute format flag */
{ ATTRIBUTE_LENGTH_OR_VALUE,offsetof(private_transform_attribute_t, attribute_length_or_value) },
/* Value of attribute if attribute format flag is zero */
- { ATTRIBUTE_VALUE, offsetof(private_transform_attribute_t, attribute_value) }
+ { ATTRIBUTE_VALUE, offsetof(private_transform_attribute_t, attribute_value) }
};
/*
@@ -101,18 +135,23 @@ METHOD(payload_t, verify, status_t,
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_transform_attribute_t *this, encoding_rule_t **rules,
- size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_transform_attribute_t *this, encoding_rule_t **rules)
{
- *rules = transform_attribute_encodings;
- *rule_count = countof(transform_attribute_encodings);
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_transform_attribute_t *this)
+{
+ return 0;
}
METHOD(payload_t, get_type, payload_type_t,
private_transform_attribute_t *this)
{
- return TRANSFORM_ATTRIBUTE;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -136,31 +175,6 @@ METHOD(payload_t, get_length, size_t,
return this->attribute_length_or_value + 4;
}
-METHOD(transform_attribute_t, set_value_chunk, void,
- private_transform_attribute_t *this, chunk_t value)
-{
- chunk_free(&this->attribute_value);
-
- if (value.len != 2)
- {
- this->attribute_value = chunk_clone(value);
- this->attribute_length_or_value = value.len;
- this->attribute_format = FALSE;
- }
- else
- {
- memcpy(&this->attribute_length_or_value, value.ptr, value.len);
- }
-}
-
-METHOD(transform_attribute_t, set_value, void,
- private_transform_attribute_t *this, u_int16_t value)
-{
- chunk_free(&this->attribute_value);
- this->attribute_length_or_value = value;
- this->attribute_format = TRUE;
-}
-
METHOD(transform_attribute_t, get_value_chunk, chunk_t,
private_transform_attribute_t *this)
{
@@ -171,16 +185,22 @@ METHOD(transform_attribute_t, get_value_chunk, chunk_t,
return this->attribute_value;
}
-METHOD(transform_attribute_t, get_value, u_int16_t,
+METHOD(transform_attribute_t, get_value, u_int64_t,
private_transform_attribute_t *this)
{
- return this->attribute_length_or_value;
-}
+ u_int64_t value = 0;
-METHOD(transform_attribute_t, set_attribute_type, void,
- private_transform_attribute_t *this, u_int16_t type)
-{
- this->attribute_type = type & 0x7FFF;
+ if (this->attribute_format)
+ {
+ return this->attribute_length_or_value;
+ }
+ if (this->attribute_value.len > sizeof(value))
+ {
+ return UINT64_MAX;
+ }
+ memcpy(((char*)&value) + sizeof(value) - this->attribute_value.len,
+ this->attribute_value.ptr, this->attribute_value.len);
+ return untoh64((char*)&value);
}
METHOD(transform_attribute_t, get_attribute_type, u_int16_t,
@@ -189,24 +209,6 @@ METHOD(transform_attribute_t, get_attribute_type, u_int16_t,
return this->attribute_type;
}
-METHOD(transform_attribute_t, clone_, transform_attribute_t*,
- private_transform_attribute_t *this)
-{
- private_transform_attribute_t *new_clone;
-
- new_clone = (private_transform_attribute_t *)transform_attribute_create();
-
- 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;
-
- if (!new_clone->attribute_format)
- {
- new_clone->attribute_value = chunk_clone(this->attribute_value);
- }
- return &new_clone->public;
-}
-
METHOD2(payload_t, transform_attribute_t, destroy, void,
private_transform_attribute_t *this)
{
@@ -217,7 +219,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;
@@ -226,22 +228,20 @@ transform_attribute_t *transform_attribute_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
.get_type = _get_type,
.destroy = _destroy,
},
- .set_value_chunk = _set_value_chunk,
- .set_value = _set_value,
.get_value_chunk = _get_value_chunk,
.get_value = _get_value,
- .set_attribute_type = _set_attribute_type,
.get_attribute_type = _get_attribute_type,
- .clone = _clone_,
.destroy = _destroy,
},
- .attribute_format = TRUE,
+ .attribute_format = FALSE,
+ .type = type,
);
return &this->public;
}
@@ -249,10 +249,33 @@ transform_attribute_t *transform_attribute_create()
/*
* Described in header.
*/
-transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length)
+transform_attribute_t *transform_attribute_create_value(payload_type_t type,
+ transform_attribute_type_t kind, u_int64_t value)
{
- transform_attribute_t *attribute = transform_attribute_create();
- attribute->set_attribute_type(attribute, KEY_LENGTH);
- attribute->set_value(attribute, key_length);
- return attribute;
+ private_transform_attribute_t *this;
+
+ this = (private_transform_attribute_t*)transform_attribute_create(type);
+
+ this->attribute_type = kind & 0x7FFF;
+
+ if (value <= UINT16_MAX)
+ {
+ this->attribute_length_or_value = value;
+ this->attribute_format = TRUE;
+ }
+ else if (value <= UINT32_MAX)
+ {
+ u_int32_t val32;
+
+ val32 = htonl(value);
+ this->attribute_value = chunk_clone(chunk_from_thing(val32));
+ this->attribute_length_or_value = sizeof(val32);
+ }
+ else
+ {
+ htoun64(&value, value);
+ this->attribute_value = chunk_clone(chunk_from_thing(value));
+ this->attribute_length_or_value = sizeof(value);
+ }
+ return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h
index a5fe0154b..23897a50a 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.
*/
@@ -58,7 +98,7 @@ struct transform_attribute_t {
*
* Returned data are not copied.
*
- * @return chunk_t pointing to the value
+ * @return chunk_t pointing to internal value
*/
chunk_t (*get_value_chunk) (transform_attribute_t *this);
@@ -69,30 +109,7 @@ struct transform_attribute_t {
*
* @return value
*/
- u_int16_t (*get_value) (transform_attribute_t *this);
-
- /**
- * Sets the value of the attribute.
- *
- * Value is getting copied.
- *
- * @param value chunk_t pointing to the value to set
- */
- void (*set_value_chunk) (transform_attribute_t *this, chunk_t value);
-
- /**
- * Sets the value of the attribute.
- *
- * @param value value to set
- */
- void (*set_value) (transform_attribute_t *this, u_int16_t value);
-
- /**
- * Sets the type of the attribute.
- *
- * @param type type to set (most significant bit is set to zero)
- */
- void (*set_attribute_type) (transform_attribute_t *this, u_int16_t type);
+ u_int64_t (*get_value) (transform_attribute_t *this);
/**
* get the type of the attribute.
@@ -102,13 +119,6 @@ struct transform_attribute_t {
u_int16_t (*get_attribute_type) (transform_attribute_t *this);
/**
- * Clones an transform_attribute_t object.
- *
- * @return cloned transform_attribute_t object
- */
- transform_attribute_t * (*clone) (transform_attribute_t *this);
-
- /**
* Destroys an transform_attribute_t object.
*/
void (*destroy) (transform_attribute_t *this);
@@ -117,16 +127,20 @@ 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.
+ * Creates a two byte value or a larger attribute for a given attribute kind.
*
- * @param key_length key length in bytes
+ * @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1
+ * @param kind attribute kind
+ * @param value fixed two byte value
* @return transform_attribute_t object
*/
-transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length);
+transform_attribute_t *transform_attribute_create_value(payload_type_t type,
+ transform_attribute_type_t kind, u_int64_t value);
#endif /** TRANSFORM_ATTRIBUTE_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c
index 3f04b3539..a4a920b60 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,72 @@ 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_ton;
+
+ /**
+ * Transform ID, as encoded in IKEv1.
*/
- u_int8_t transform_type;
+ u_int8_t transform_id_v1;
/**
- * Transform ID.
+ * Transform ID, as encoded in IKEv2.
*/
- u_int16_t transform_id;
+ 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 */
+ { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE,
+ 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 */
+ { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1,
+ offsetof(private_transform_substructure_t, attributes) }
};
/*
@@ -97,7 +127,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 +148,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))
{
@@ -151,18 +164,28 @@ METHOD(payload_t, verify, status_t,
return status;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_transform_substructure_t *this, encoding_rule_t **rules,
- size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_transform_substructure_t *this, encoding_rule_t **rules)
{
- *rules = transform_substructure_encodings;
- *rule_count = countof(transform_substructure_encodings);
+ if (this->type == TRANSFORM_SUBSTRUCTURE)
+ {
+ *rules = encodings_v2;
+ return countof(encodings_v2);
+ }
+ *rules = encodings_v1;
+ return countof(encodings_v1);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_transform_substructure_t *this)
+{
+ return 8;
}
METHOD(payload_t, get_type, payload_type_t,
private_transform_substructure_t *this)
{
- return TRANSFORM_SUBSTRUCTURE;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -174,12 +197,12 @@ 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;
- this->transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH;
+ this->transform_length = get_header_length(this);
enumerator = this->attributes->create_enumerator(this->attributes);
while (enumerator->enumerate(enumerator, &attribute))
{
@@ -194,6 +217,13 @@ METHOD(payload_t, get_length, size_t,
return this->transform_length;
}
+METHOD(transform_substructure_t, add_transform_attribute, void,
+ private_transform_substructure_t *this, transform_attribute_t *attribute)
+{
+ this->attributes->insert_last(this->attributes, attribute);
+ compute_length(this);
+}
+
METHOD(transform_substructure_t, set_is_last_transform, void,
private_transform_substructure_t *this, bool is_last)
{
@@ -205,50 +235,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;
@@ -257,21 +277,24 @@ transform_substructure_t *transform_substructure_create()
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
.get_type = _get_type,
.destroy = _destroy,
},
+ .add_transform_attribute = _add_transform_attribute,
.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,
+ .transform_length = get_header_length(this),
.attributes = linked_list_create(),
+ .type = type,
);
return &this->public;
}
@@ -279,20 +302,21 @@ 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)
{
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;
- if (key_length)
+ this->transform_ton = type_or_number;
+ if (type == TRANSFORM_SUBSTRUCTURE)
+ {
+ this->transform_id_v2 = id;
+ }
+ else
{
- this->attributes->insert_last(this->attributes,
- (void*)transform_attribute_create_key_length(key_length));
- compute_length(this);
+ this->transform_id_v1 = id;
}
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/transform_substructure.h b/src/libcharon/encoding/payloads/transform_substructure.h
index 102dbb3d3..947df24f9 100644
--- a/src/libcharon/encoding/payloads/transform_substructure.h
+++ b/src/libcharon/encoding/payloads/transform_substructure.h
@@ -40,14 +40,7 @@ typedef struct transform_substructure_t transform_substructure_t;
#define TRANSFORM_TYPE_VALUE 3
/**
- * Length of the transform substructure header in bytes.
- */
-#define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8
-
-/**
- * Class representing an 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 +68,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 +82,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 +97,20 @@ 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
+ * @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);
#endif /** TRANSFORM_SUBSTRUCTURE_H_ @}*/
diff --git a/src/libcharon/encoding/payloads/ts_payload.c b/src/libcharon/encoding/payloads/ts_payload.c
index 28f760e40..a7678da73 100644
--- a/src/libcharon/encoding/payloads/ts_payload.c
+++ b/src/libcharon/encoding/payloads/ts_payload.c
@@ -81,7 +81,7 @@ struct private_ts_payload_t {
* The defined offsets are the positions in a object of type
* private_ts_payload_t.
*/
-encoding_rule_t ts_payload_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_ts_payload_t, next_payload) },
/* the critical bit */
@@ -102,8 +102,9 @@ encoding_rule_t ts_payload_encodings[] = {
{ RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[0])},
{ RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[1])},
{ RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[2])},
- /* some ts data bytes, length is defined in PAYLOAD_LENGTH */
- { TRAFFIC_SELECTORS,offsetof(private_ts_payload_t, substrs) }
+ /* wrapped list of traffic selectors substructures */
+ { PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE,
+ offsetof(private_ts_payload_t, substrs) },
};
/*
@@ -145,11 +146,17 @@ METHOD(payload_t, verify, status_t,
return status;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_ts_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_ts_payload_t *this, encoding_rule_t **rules)
{
- *rules = ts_payload_encodings;
- *rule_count = countof(ts_payload_encodings);
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_ts_payload_t *this)
+{
+ return 8;
}
METHOD(payload_t, get_type, payload_type_t,
@@ -182,7 +189,7 @@ static void compute_length(private_ts_payload_t *this)
enumerator_t *enumerator;
payload_t *subst;
- this->payload_length = TS_PAYLOAD_HEADER_LENGTH;
+ this->payload_length = get_header_length(this);
this->ts_num = 0;
enumerator = this->substrs->create_enumerator(this->substrs);
while (enumerator->enumerate(enumerator, &subst))
@@ -250,6 +257,7 @@ ts_payload_t *ts_payload_create(bool is_initiator)
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -262,7 +270,7 @@ ts_payload_t *ts_payload_create(bool is_initiator)
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = TS_PAYLOAD_HEADER_LENGTH,
+ .payload_length = get_header_length(this),
.is_initiator = is_initiator,
.substrs = linked_list_create(),
);
diff --git a/src/libcharon/encoding/payloads/ts_payload.h b/src/libcharon/encoding/payloads/ts_payload.h
index 88ca00bc9..5a92655dc 100644
--- a/src/libcharon/encoding/payloads/ts_payload.h
+++ b/src/libcharon/encoding/payloads/ts_payload.h
@@ -31,11 +31,6 @@ typedef struct ts_payload_t ts_payload_t;
#include <encoding/payloads/traffic_selector_substructure.h>
/**
- * Length of a TS payload without the Traffic selectors.
- */
-#define TS_PAYLOAD_HEADER_LENGTH 8
-
-/**
* Class representing an IKEv2 TS payload.
*
* The TS payload format is described in RFC section 3.13.
diff --git a/src/libcharon/encoding/payloads/unknown_payload.c b/src/libcharon/encoding/payloads/unknown_payload.c
index 27af338b3..fe7ced20b 100644
--- a/src/libcharon/encoding/payloads/unknown_payload.c
+++ b/src/libcharon/encoding/payloads/unknown_payload.c
@@ -68,7 +68,7 @@ struct private_unknown_payload_t {
* private_unknown_payload_t.
*
*/
-encoding_rule_t unknown_payload_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_unknown_payload_t, next_payload) },
/* the critical bit */
@@ -84,7 +84,7 @@ encoding_rule_t unknown_payload_encodings[] = {
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_unknown_payload_t, payload_length) },
/* some unknown data bytes, length is defined in PAYLOAD_LENGTH */
- { UNKNOWN_DATA, offsetof(private_unknown_payload_t, data) },
+ { CHUNK_DATA, offsetof(private_unknown_payload_t, data) },
};
/*
@@ -102,18 +102,20 @@ encoding_rule_t unknown_payload_encodings[] = {
METHOD(payload_t, verify, status_t,
private_unknown_payload_t *this)
{
- if (this->payload_length != UNKNOWN_PAYLOAD_HEADER_LENGTH + this->data.len)
- {
- return FAILED;
- }
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_unknown_payload_t *this, encoding_rule_t **rules, size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_unknown_payload_t *this, encoding_rule_t **rules)
{
- *rules = unknown_payload_encodings;
- *rule_count = sizeof(unknown_payload_encodings) / sizeof(encoding_rule_t);
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_unknown_payload_t *this)
+{
+ return 4;
}
METHOD(payload_t, get_payload_type, payload_type_t,
@@ -171,6 +173,7 @@ unknown_payload_t *unknown_payload_create(payload_type_t type)
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -182,7 +185,7 @@ unknown_payload_t *unknown_payload_create(payload_type_t type)
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH,
+ .payload_length = get_header_length(this),
.type = type,
);
@@ -201,7 +204,7 @@ unknown_payload_t *unknown_payload_create_data(payload_type_t type,
this = (private_unknown_payload_t*)unknown_payload_create(type);
this->data = data;
this->critical = critical;
- this->payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH + data.len;
+ this->payload_length = get_header_length(this) + data.len;
return &this->public;
}
diff --git a/src/libcharon/encoding/payloads/unknown_payload.h b/src/libcharon/encoding/payloads/unknown_payload.h
index 5ae85331b..326b550cd 100644
--- a/src/libcharon/encoding/payloads/unknown_payload.h
+++ b/src/libcharon/encoding/payloads/unknown_payload.h
@@ -28,11 +28,6 @@ typedef struct unknown_payload_t unknown_payload_t;
#include <encoding/payloads/payload.h>
/**
- * Header length of the unknown payload.
- */
-#define UNKNOWN_PAYLOAD_HEADER_LENGTH 4
-
-/**
* Payload which can't be processed further.
*
* When the parser finds an unknown payload, he builds an instance of
diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.c b/src/libcharon/encoding/payloads/vendor_id_payload.c
index e9e80e989..0c1df56e2 100644
--- a/src/libcharon/encoding/payloads/vendor_id_payload.c
+++ b/src/libcharon/encoding/payloads/vendor_id_payload.c
@@ -55,6 +55,11 @@ struct private_vendor_id_payload_t {
* The contained data.
*/
chunk_t data;
+
+ /**
+ * Either a IKEv1 or a IKEv2 vendor ID payload
+ */
+ payload_type_t type;
};
/**
@@ -63,7 +68,7 @@ struct private_vendor_id_payload_t {
* The defined offsets are the positions in a object of type
* private_vendor_id_payload_t.
*/
-encoding_rule_t vendor_id_payload_encodings[] = {
+static encoding_rule_t encodings[] = {
/* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_vendor_id_payload_t, next_payload) },
/* the critical bit */
@@ -79,7 +84,7 @@ encoding_rule_t vendor_id_payload_encodings[] = {
/* Length of the whole payload*/
{ PAYLOAD_LENGTH, offsetof(private_vendor_id_payload_t, payload_length)},
/* some vendor_id data bytes, length is defined in PAYLOAD_LENGTH */
- { VID_DATA, offsetof(private_vendor_id_payload_t, data) }
+ { CHUNK_DATA, offsetof(private_vendor_id_payload_t, data) }
};
/*
@@ -100,18 +105,23 @@ METHOD(payload_t, verify, status_t,
return SUCCESS;
}
-METHOD(payload_t, get_encoding_rules, void,
- private_vendor_id_payload_t *this, encoding_rule_t **rules,
- size_t *rule_count)
+METHOD(payload_t, get_encoding_rules, int,
+ private_vendor_id_payload_t *this, encoding_rule_t **rules)
+{
+ *rules = encodings;
+ return countof(encodings);
+}
+
+METHOD(payload_t, get_header_length, int,
+ private_vendor_id_payload_t *this)
{
- *rules = vendor_id_payload_encodings;
- *rule_count = countof(vendor_id_payload_encodings);
+ return 4;
}
METHOD(payload_t, get_type, payload_type_t,
private_vendor_id_payload_t *this)
{
- return VENDOR_ID;
+ return this->type;
}
METHOD(payload_t, get_next_type, payload_type_t,
@@ -148,7 +158,8 @@ METHOD2(payload_t, vendor_id_payload_t, destroy, void,
/*
* Described in header
*/
-vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data)
+vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type,
+ chunk_t data)
{
private_vendor_id_payload_t *this;
@@ -157,6 +168,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data)
.payload_interface = {
.verify = _verify,
.get_encoding_rules = _get_encoding_rules,
+ .get_header_length = _get_header_length,
.get_length = _get_length,
.get_next_type = _get_next_type,
.set_next_type = _set_next_type,
@@ -167,8 +179,9 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data)
.destroy = _destroy,
},
.next_payload = NO_PAYLOAD,
- .payload_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH + data.len,
+ .payload_length = get_header_length(this) + data.len,
.data = data,
+ .type = type,
);
return &this->public;
}
@@ -176,7 +189,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data)
/*
* Described in header
*/
-vendor_id_payload_t *vendor_id_payload_create()
+vendor_id_payload_t *vendor_id_payload_create(payload_type_t type)
{
- return vendor_id_payload_create_data(chunk_empty);
+ return vendor_id_payload_create_data(type, chunk_empty);
}
diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.h b/src/libcharon/encoding/payloads/vendor_id_payload.h
index 4e4e7d8eb..9a814777b 100644
--- a/src/libcharon/encoding/payloads/vendor_id_payload.h
+++ b/src/libcharon/encoding/payloads/vendor_id_payload.h
@@ -28,12 +28,7 @@ typedef struct vendor_id_payload_t vendor_id_payload_t;
#include <encoding/payloads/payload.h>
/**
- * Length of a VENDOR ID payload without the VID data in bytes.
- */
-#define VENDOR_ID_PAYLOAD_HEADER_LENGTH 4
-
-/**
- * Class representing an IKEv2 VENDOR ID payload.
+ * Class representing an IKEv1/IKEv2 VENDOR ID payload.
*
* The VENDOR ID payload format is described in RFC section 3.12.
*/
@@ -58,18 +53,21 @@ struct vendor_id_payload_t {
};
/**
- * Creates an empty Vendor ID payload.
+ * Creates an empty Vendor ID payload for IKEv1 or IKEv2.
*
+ * @@param type VENDOR_ID or VENDOR_ID_V1
* @return vendor ID payload
*/
-vendor_id_payload_t *vendor_id_payload_create();
+vendor_id_payload_t *vendor_id_payload_create(payload_type_t type);
/**
* Creates a vendor ID payload using a chunk of data
*
+ * @param type VENDOR_ID or VENDOR_ID_V1
* @param data data to use in vendor ID payload, gets owned by payload
* @return vendor ID payload
*/
-vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data);
+vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type,
+ chunk_t data);
#endif /** VENDOR_ID_PAYLOAD_H_ @}*/