aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/libcharon/encoding/generator.c1
-rw-r--r--src/libcharon/encoding/parser.c10
-rw-r--r--src/libcharon/encoding/payloads/encodings.c3
-rw-r--r--src/libcharon/encoding/payloads/encodings.h5
-rw-r--r--src/libcharon/encoding/payloads/encryption_payload.c131
-rw-r--r--src/libcharon/encoding/payloads/encryption_payload.h3
-rw-r--r--src/libcharon/encoding/payloads/payload.c3
-rw-r--r--src/libcharon/encoding/payloads/payload.h15
8 files changed, 156 insertions, 15 deletions
diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c
index c6819292a..2c9298e11 100644
--- a/src/libcharon/encoding/generator.c
+++ b/src/libcharon/encoding/generator.c
@@ -449,6 +449,7 @@ METHOD(generator_t, generate_payload, void,
case ADDRESS:
case SPI:
case CHUNK_DATA:
+ case ENCRYPTED_DATA:
generate_from_chunk(this, rules[i].offset);
break;
case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE:
diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c
index 1a7f297da..b93651bbe 100644
--- a/src/libcharon/encoding/parser.c
+++ b/src/libcharon/encoding/parser.c
@@ -516,6 +516,16 @@ METHOD(parser_t, parse_payload, status_t,
}
break;
}
+ case ENCRYPTED_DATA:
+ {
+ if (!parse_chunk(this, rule_number, output + rule->offset,
+ this->input_roof - this->byte_pos))
+ {
+ pld->destroy(pld);
+ return PARSE_ERROR;
+ }
+ break;
+ }
case ATTRIBUTE_FORMAT:
{
if (!parse_bit(this, rule_number, output + rule->offset))
diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c
index 3dc8ee4ec..7306dcf10 100644
--- a/src/libcharon/encoding/payloads/encodings.c
+++ b/src/libcharon/encoding/payloads/encodings.c
@@ -17,7 +17,7 @@
#include "encodings.h"
-ENUM(encoding_type_names, U_INT_4, IKE_SPI,
+ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA,
"U_INT_4",
"U_INT_8",
"U_INT_16",
@@ -38,4 +38,5 @@ ENUM(encoding_type_names, U_INT_4, IKE_SPI,
"ADDRESS",
"CHUNK_DATA",
"IKE_SPI",
+ "ENCRYPTED",
);
diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h
index dde495bc2..124814ff5 100644
--- a/src/libcharon/encoding/payloads/encodings.h
+++ b/src/libcharon/encoding/payloads/encodings.h
@@ -297,6 +297,11 @@ enum encoding_type_t {
IKE_SPI,
/**
+ * 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.
diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c
index bb9969d0b..425e58621 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.
*/
-static encoding_rule_t 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 */
@@ -109,6 +115,29 @@ static encoding_rule_t 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Message Length !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! Encrypted IKE Payloads !
+ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ ! ! Padding (0-255 octets) !
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+*/
+
METHOD(payload_t, verify, status_t,
private_encryption_payload_t *this)
{
@@ -118,20 +147,29 @@ METHOD(payload_t, verify, status_t,
METHOD(payload_t, get_encoding_rules, int,
private_encryption_payload_t *this, encoding_rule_t **rules)
{
- *rules = encodings;
- return countof(encodings);
+ 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)
{
- return 4;
+ 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,
@@ -143,7 +181,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;
}
/**
@@ -340,6 +379,47 @@ METHOD(encryption_payload_t, encrypt, bool,
return TRUE;
}
+METHOD(encryption_payload_t, encrypt_v1, bool,
+ 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");
+ chunk_free(&iv);
+ return FALSE;
+ }
+
+ 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);
+
+ this->aead->encrypt(this->aead, this->encrypted, chunk_empty, iv, NULL);
+ chunk_free(&iv);
+
+ DBG3(DBG_ENC, "encrypted %B", &this->encrypted);
+
+ return TRUE;
+}
+
/**
* Parse the payloads after decryption.
*/
@@ -443,6 +523,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");
+ chunk_free(&iv);
+ 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");
+ chunk_free(&iv);
+ return FAILED;
+ }
+
+ DBG3(DBG_ENC, "decrypting payloads:");
+ DBG3(DBG_ENC, "encrypted %B", &this->encrypted);
+
+ this->aead->decrypt(this->aead, this->encrypted, chunk_empty, iv, NULL);
+ chunk_free(&iv);
+
+ 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)
{
@@ -460,7 +570,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;
@@ -487,7 +597,14 @@ encryption_payload_t *encryption_payload_create()
.next_payload = NO_PAYLOAD,
.payload_length = get_header_length(this),
.payloads = linked_list_create(),
+ .type = type,
);
+ 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 3cdc54b37..60774bde0 100644
--- a/src/libcharon/encoding/payloads/encryption_payload.h
+++ b/src/libcharon/encoding/payloads/encryption_payload.h
@@ -97,8 +97,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/payload.c b/src/libcharon/encoding/payloads/payload.c
index 9dc26773a..2f22503e6 100644
--- a/src/libcharon/encoding/payloads/payload.c
+++ b/src/libcharon/encoding/payloads/payload.c
@@ -220,7 +220,8 @@ payload_t *payload_create(payload_type_t 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);
}
diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h
index 84871cfb6..e4ed76abf 100644
--- a/src/libcharon/encoding/payloads/payload.h
+++ b/src/libcharon/encoding/payloads/payload.h
@@ -247,6 +247,11 @@ enum payload_type_t {
* CONFIGURATION_ATTRIBUTE, attribute in a configuration payload.
*/
CONFIGURATION_ATTRIBUTE,
+
+ /**
+ * This is not really a payload, but rather the complete IKEv1 message.
+ */
+ ENCRYPTED_V1,
};
/**
@@ -286,35 +291,35 @@ struct payload_t {
/**
* 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);