Use modified encryption payload to encrypt/decrypt complete IKEv1 messages.

This commit is contained in:
Tobias Brunner
2012-03-20 17:30:46 +01:00
parent 0463674971
commit 6f5f8ee4b5
8 changed files with 156 additions and 15 deletions
+1
View File
@@ -449,6 +449,7 @@ METHOD(generator_t, generate_payload, void,
case ADDRESS: case ADDRESS:
case SPI: case SPI:
case CHUNK_DATA: case CHUNK_DATA:
case ENCRYPTED_DATA:
generate_from_chunk(this, rules[i].offset); generate_from_chunk(this, rules[i].offset);
break; break;
case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE: case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE:
+10
View File
@@ -516,6 +516,16 @@ METHOD(parser_t, parse_payload, status_t,
} }
break; 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: case ATTRIBUTE_FORMAT:
{ {
if (!parse_bit(this, rule_number, output + rule->offset)) if (!parse_bit(this, rule_number, output + rule->offset))
+2 -1
View File
@@ -17,7 +17,7 @@
#include "encodings.h" #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_4",
"U_INT_8", "U_INT_8",
"U_INT_16", "U_INT_16",
@@ -38,4 +38,5 @@ ENUM(encoding_type_names, U_INT_4, IKE_SPI,
"ADDRESS", "ADDRESS",
"CHUNK_DATA", "CHUNK_DATA",
"IKE_SPI", "IKE_SPI",
"ENCRYPTED",
); );
@@ -296,6 +296,11 @@ enum encoding_type_t {
*/ */
IKE_SPI, IKE_SPI,
/**
* Representating an encrypted IKEv1 message.
*/
ENCRYPTED_DATA,
/** /**
* Reprensenting a field containing a set of wrapped payloads. * Reprensenting a field containing a set of wrapped payloads.
* *
@@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005-2010 Martin Willi
* Copyright (C) 2010 revosec AG * Copyright (C) 2010 revosec AG
* Copyright (C) 2011 Tobias Brunner
* Copyright (C) 2005 Jan Hutter * Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
@@ -71,6 +72,11 @@ struct private_encryption_payload_t {
* Contained payloads * Contained payloads
*/ */
linked_list_t *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 * The defined offsets are the positions in a object of type
* private_encryption_payload_t. * 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 */ /* 1 Byte next payload type, stored in the field next_payload */
{ U_INT_8, offsetof(private_encryption_payload_t, next_payload) }, { U_INT_8, offsetof(private_encryption_payload_t, next_payload) },
/* Critical and 7 reserved bits, all stored for reconstruction */ /* 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, METHOD(payload_t, verify, status_t,
private_encryption_payload_t *this) private_encryption_payload_t *this)
{ {
@@ -118,20 +147,29 @@ METHOD(payload_t, verify, status_t,
METHOD(payload_t, get_encoding_rules, int, METHOD(payload_t, get_encoding_rules, int,
private_encryption_payload_t *this, encoding_rule_t **rules) private_encryption_payload_t *this, encoding_rule_t **rules)
{ {
*rules = encodings; if (this->type == ENCRYPTED)
return countof(encodings); {
*rules = encodings_v2;
return countof(encodings_v2);
}
*rules = encodings_v1;
return countof(encodings_v1);
} }
METHOD(payload_t, get_header_length, int, METHOD(payload_t, get_header_length, int,
private_encryption_payload_t *this) private_encryption_payload_t *this)
{ {
return 4; if (this->type == ENCRYPTED)
{
return 4;
}
return 0;
} }
METHOD(payload_t, get_type, payload_type_t, METHOD(payload_t, get_type, payload_type_t,
private_encryption_payload_t *this) private_encryption_payload_t *this)
{ {
return ENCRYPTED; return this->type;
} }
METHOD(payload_t, get_next_type, payload_type_t, 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, METHOD(payload_t, set_next_type, void,
private_encryption_payload_t *this, payload_type_t type) 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; 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. * Parse the payloads after decryption.
*/ */
@@ -443,6 +523,36 @@ METHOD(encryption_payload_t, decrypt, status_t,
return parse(this, plain); 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, METHOD(encryption_payload_t, set_transform, void,
private_encryption_payload_t *this, aead_t* aead) private_encryption_payload_t *this, aead_t* aead)
{ {
@@ -460,7 +570,7 @@ METHOD2(payload_t, encryption_payload_t, destroy, void,
/* /*
* Described in header * Described in header
*/ */
encryption_payload_t *encryption_payload_create() encryption_payload_t *encryption_payload_create(payload_type_t type)
{ {
private_encryption_payload_t *this; private_encryption_payload_t *this;
@@ -487,7 +597,14 @@ encryption_payload_t *encryption_payload_create()
.next_payload = NO_PAYLOAD, .next_payload = NO_PAYLOAD,
.payload_length = get_header_length(this), .payload_length = get_header_length(this),
.payloads = linked_list_create(), .payloads = linked_list_create(),
.type = type,
); );
if (type == ENCRYPTED_V1)
{
this->public.encrypt = _encrypt_v1;
this->public.decrypt = _decrypt_v1;
}
return &this->public; return &this->public;
} }
@@ -97,8 +97,9 @@ struct encryption_payload_t {
/** /**
* Creates an empty encryption_payload_t object. * Creates an empty encryption_payload_t object.
* *
* @param type ENCRYPTED or ENCRYPTED_V1
* @return encryption_payload_t object * @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_ @}*/ #endif /** ENCRYPTION_PAYLOAD_H_ @}*/
+2 -1
View File
@@ -220,7 +220,8 @@ payload_t *payload_create(payload_type_t type)
case EXTENSIBLE_AUTHENTICATION: case EXTENSIBLE_AUTHENTICATION:
return (payload_t*)eap_payload_create(); return (payload_t*)eap_payload_create();
case ENCRYPTED: case ENCRYPTED:
return (payload_t*)encryption_payload_create(); case ENCRYPTED_V1:
return (payload_t*)encryption_payload_create(type);
default: default:
return (payload_t*)unknown_payload_create(type); return (payload_t*)unknown_payload_create(type);
} }
+10 -5
View File
@@ -247,6 +247,11 @@ enum payload_type_t {
* CONFIGURATION_ATTRIBUTE, attribute in a configuration payload. * CONFIGURATION_ATTRIBUTE, attribute in a configuration payload.
*/ */
CONFIGURATION_ATTRIBUTE, 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. * Get type of payload.
* *
* @return type of this payload * @return type of this payload
*/ */
payload_type_t (*get_type) (payload_t *this); payload_type_t (*get_type) (payload_t *this);
/** /**
* Get type of next payload or NO_PAYLOAD (0) if this is the last one. * 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); payload_type_t (*get_next_type) (payload_t *this);
/** /**
* Set type of next payload. * 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); void (*set_next_type) (payload_t *this,payload_type_t type);
/** /**
* Get length of payload. * Get length of payload.
* *
* @return length of this payload * @return length of this payload
*/ */
size_t (*get_length) (payload_t *this); size_t (*get_length) (payload_t *this);
/** /**
* Verifies payload structure and makes consistence check. * 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); status_t (*verify) (payload_t *this);