summaryrefslogtreecommitdiff
path: root/src/libcharon/encoding/message.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcharon/encoding/message.c')
-rw-r--r--src/libcharon/encoding/message.c174
1 files changed, 130 insertions, 44 deletions
diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c
index d41ad4697..dbef340ab 100644
--- a/src/libcharon/encoding/message.c
+++ b/src/libcharon/encoding/message.c
@@ -131,6 +131,7 @@ static payload_rule_t ike_sa_init_r_rules[] = {
{SECURITY_ASSOCIATION, 1, 1, FALSE, FALSE},
{KEY_EXCHANGE, 1, 1, FALSE, FALSE},
{NONCE, 1, 1, FALSE, FALSE},
+ {CERTIFICATE_REQUEST, 1, 1, FALSE, FALSE},
{VENDOR_ID, 0, 10, FALSE, FALSE},
};
@@ -490,6 +491,21 @@ struct private_message_t {
bool is_request;
/**
+ * Higher version supported?
+ */
+ bool version_flag;
+
+ /**
+ * Reserved bits in IKE header
+ */
+ bool reserved[5];
+
+ /**
+ * Sorting of message disabled?
+ */
+ bool sort_disabled;
+
+ /**
* Message ID of this message.
*/
u_int32_t message_id;
@@ -647,18 +663,35 @@ METHOD(message_t, get_request, bool,
return this->is_request;
}
-/**
- * Is this message in an encoded form?
- */
-static bool is_encoded(private_message_t *this)
+METHOD(message_t, set_version_flag, void,
+ private_message_t *this)
{
- chunk_t data = this->packet->get_data(this->packet);
+ this->version_flag = TRUE;
+}
- if (data.ptr == NULL)
+METHOD(message_t, get_reserved_header_bit, bool,
+ private_message_t *this, u_int nr)
+{
+ if (nr < countof(this->reserved))
{
- return FALSE;
+ return this->reserved[nr];
}
- return TRUE;
+ return FALSE;
+}
+
+METHOD(message_t, set_reserved_header_bit, void,
+ private_message_t *this, u_int nr)
+{
+ if (nr < countof(this->reserved))
+ {
+ this->reserved[nr] = TRUE;
+ }
+}
+
+METHOD(message_t, is_encoded, bool,
+ private_message_t *this)
+{
+ return this->packet->get_data(this->packet).ptr != NULL;
}
METHOD(message_t, add_payload, void,
@@ -732,6 +765,12 @@ METHOD(message_t, create_payload_enumerator, enumerator_t*,
return this->payloads->create_enumerator(this->payloads);
}
+METHOD(message_t, remove_payload_at, void,
+ private_message_t *this, enumerator_t *enumerator)
+{
+ this->payloads->remove_at(this->payloads, enumerator);
+}
+
METHOD(message_t, get_payload, payload_t*,
private_message_t *this, payload_type_t type)
{
@@ -1001,6 +1040,12 @@ static encryption_payload_t* wrap_payloads(private_message_t *this)
return encryption;
}
+METHOD(message_t, disable_sort, void,
+ private_message_t *this)
+{
+ this->sort_disabled = TRUE;
+}
+
METHOD(message_t, generate, status_t,
private_message_t *this, aead_t *aead, packet_t **packet)
{
@@ -1012,12 +1057,8 @@ METHOD(message_t, generate, status_t,
chunk_t chunk;
char str[256];
u_int32_t *lenpos;
-
- if (is_encoded(this))
- { /* already generated, return a new packet clone */
- *packet = this->packet->clone(this->packet);
- return SUCCESS;
- }
+ bool *reserved;
+ int i;
if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED)
{
@@ -1039,7 +1080,10 @@ METHOD(message_t, generate, status_t,
return NOT_SUPPORTED;
}
- order_payloads(this);
+ if (!this->sort_disabled)
+ {
+ order_payloads(this);
+ }
DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str)));
@@ -1053,9 +1097,12 @@ METHOD(message_t, generate, status_t,
}
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->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,
this->ike_sa_id->is_initiator(this->ike_sa_id));
ike_header->set_initiator_spi(ike_header,
@@ -1063,6 +1110,16 @@ METHOD(message_t, generate, status_t,
ike_header->set_responder_spi(ike_header,
this->ike_sa_id->get_responder_spi(this->ike_sa_id));
+ for (i = 0; i < countof(this->reserved); i++)
+ {
+ reserved = payload_get_field(&ike_header->payload_interface,
+ RESERVED_BIT, i);
+ if (reserved)
+ {
+ *reserved = this->reserved[i];
+ }
+ }
+
generator = generator_create();
/* generate all payloads with proper next type */
@@ -1131,6 +1188,8 @@ METHOD(message_t, parse_header, status_t,
{
ike_header_t *ike_header;
status_t status;
+ bool *reserved;
+ int i;
DBG2(DBG_ENC, "parsing header of message");
@@ -1165,7 +1224,15 @@ METHOD(message_t, parse_header, status_t,
this->minor_version = ike_header->get_min_version(ike_header);
this->first_payload = ike_header->payload_interface.get_next_type(
&ike_header->payload_interface);
-
+ for (i = 0; i < countof(this->reserved); i++)
+ {
+ reserved = payload_get_field(&ike_header->payload_interface,
+ RESERVED_BIT, i);
+ if (reserved)
+ {
+ this->reserved[i] = *reserved;
+ }
+ }
DBG2(DBG_ENC, "parsed a %N %s", exchange_type_names, this->exchange_type,
this->is_request ? "request" : "response");
@@ -1182,6 +1249,31 @@ METHOD(message_t, parse_header, status_t,
}
/**
+ * Check if a payload is for a mediation extension connectivity check
+ */
+static bool is_connectivity_check(private_message_t *this, payload_t *payload)
+{
+#ifdef ME
+ if (this->exchange_type == INFORMATIONAL &&
+ payload->get_type(payload) == NOTIFY)
+ {
+ notify_payload_t *notify = (notify_payload_t*)payload;
+
+ switch (notify->get_notify_type(notify))
+ {
+ case ME_CONNECTID:
+ case ME_ENDPOINT:
+ case ME_CONNECTAUTH:
+ return TRUE;
+ default:
+ break;
+ }
+ }
+#endif /* !ME */
+ return FALSE;
+}
+
+/**
* Decrypt payload from the encryption payload
*/
static status_t decrypt_payloads(private_message_t *this, aead_t *aead)
@@ -1252,14 +1344,15 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead)
}
encryption->destroy(encryption);
}
- if (type != UNKNOWN_PAYLOAD && !was_encrypted)
+ if (payload_is_known(type) && !was_encrypted &&
+ !is_connectivity_check(this, payload))
{
rule = get_payload_rule(this, type);
if (!rule || rule->encrypted)
{
DBG1(DBG_ENC, "payload type %N was not encrypted",
payload_type_names, type);
- status = VERIFY_ERROR;
+ status = FAILED;
break;
}
}
@@ -1274,6 +1367,7 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead)
*/
static status_t verify(private_message_t *this)
{
+ bool complete = FALSE;
int i;
DBG2(DBG_ENC, "verifying message structure");
@@ -1291,22 +1385,9 @@ static status_t verify(private_message_t *this)
while (enumerator->enumerate(enumerator, &payload))
{
payload_type_t type;
- unknown_payload_t *unknown;
type = payload->get_type(payload);
- if (type == UNKNOWN_PAYLOAD)
- {
- /* unknown payloads are ignored if they are not critical */
- unknown = (unknown_payload_t*)payload;
- if (unknown->is_critical(unknown))
- {
- DBG1(DBG_ENC, "%N is not supported, but its critical!",
- payload_type_names, type);
- enumerator->destroy(enumerator);
- return NOT_SUPPORTED;
- }
- }
- else if (type == rule->type)
+ if (type == rule->type)
{
found++;
DBG2(DBG_ENC, "found payload of type %N",
@@ -1323,15 +1404,15 @@ static status_t verify(private_message_t *this)
}
enumerator->destroy(enumerator);
- if (found < rule->min_occurence)
+ if (!complete && found < rule->min_occurence)
{
DBG1(DBG_ENC, "payload of type %N not occured %d times (%d)",
payload_type_names, rule->type, rule->min_occurence, found);
return VERIFY_ERROR;
}
- if (rule->sufficient)
+ if (found && rule->sufficient)
{
- return SUCCESS;
+ complete = TRUE;
}
}
return SUCCESS;
@@ -1360,7 +1441,7 @@ METHOD(message_t, parse_body, status_t,
{
DBG1(DBG_ENC, "payload type %N could not be parsed",
payload_type_names, type);
- return PARSE_ERROR;
+ return this->exchange_type == IKE_SA_INIT ? PARSE_ERROR : FAILED;
}
DBG2(DBG_ENC, "verifying payload of type %N", payload_type_names, type);
@@ -1370,7 +1451,7 @@ METHOD(message_t, parse_body, status_t,
DBG1(DBG_ENC, "%N payload verification failed",
payload_type_names, type);
payload->destroy(payload);
- return VERIFY_ERROR;
+ return this->exchange_type == IKE_SA_INIT ? VERIFY_ERROR : FAILED;
}
DBG2(DBG_ENC, "%N payload verified. Adding to payload list",
@@ -1388,14 +1469,11 @@ METHOD(message_t, parse_body, status_t,
type = payload->get_next_type(payload);
}
- if (type == ENCRYPTED)
+ status = decrypt_payloads(this, aead);
+ if (status != SUCCESS)
{
- status = decrypt_payloads(this, aead);
- if (status != SUCCESS)
- {
- DBG1(DBG_ENC, "could not decrypt payloads");
- return status;
- }
+ DBG1(DBG_ENC, "could not decrypt payloads");
+ return status;
}
status = verify(this);
@@ -1443,14 +1521,20 @@ message_t *message_create_from_packet(packet_t *packet)
.get_first_payload_type = _get_first_payload_type,
.set_request = _set_request,
.get_request = _get_request,
+ .set_version_flag = _set_version_flag,
+ .get_reserved_header_bit = _get_reserved_header_bit,
+ .set_reserved_header_bit = _set_reserved_header_bit,
.add_payload = _add_payload,
.add_notify = _add_notify,
+ .disable_sort = _disable_sort,
.generate = _generate,
+ .is_encoded = _is_encoded,
.set_source = _set_source,
.get_source = _get_source,
.set_destination = _set_destination,
.get_destination = _get_destination,
.create_payload_enumerator = _create_payload_enumerator,
+ .remove_payload_at = _remove_payload_at,
.get_payload = _get_payload,
.get_notify = _get_notify,
.parse_header = _parse_header,
@@ -1459,6 +1543,8 @@ message_t *message_create_from_packet(packet_t *packet)
.get_packet_data = _get_packet_data,
.destroy = _destroy,
},
+ .major_version = IKE_MAJOR_VERSION,
+ .minor_version = IKE_MINOR_VERSION,
.exchange_type = EXCHANGE_TYPE_UNDEFINED,
.is_request = TRUE,
.first_payload = NO_PAYLOAD,