diff options
Diffstat (limited to 'src/libcharon/encoding')
54 files changed, 15478 insertions, 0 deletions
diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c new file mode 100644 index 000000000..6485da492 --- /dev/null +++ b/src/libcharon/encoding/generator.c @@ -0,0 +1,888 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 <stdlib.h> +#include <string.h> +#include <arpa/inet.h> +#include <stdio.h> + +#include "generator.h" + +#include <library.h> +#include <daemon.h> +#include <utils/linked_list.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/proposal_substructure.h> +#include <encoding/payloads/transform_substructure.h> +#include <encoding/payloads/sa_payload.h> +#include <encoding/payloads/ke_payload.h> +#include <encoding/payloads/notify_payload.h> +#include <encoding/payloads/nonce_payload.h> +#include <encoding/payloads/id_payload.h> +#include <encoding/payloads/auth_payload.h> +#include <encoding/payloads/cert_payload.h> +#include <encoding/payloads/certreq_payload.h> +#include <encoding/payloads/ts_payload.h> +#include <encoding/payloads/delete_payload.h> +#include <encoding/payloads/vendor_id_payload.h> +#include <encoding/payloads/cp_payload.h> +#include <encoding/payloads/configuration_attribute.h> +#include <encoding/payloads/eap_payload.h> + + +typedef struct private_generator_t private_generator_t; + +/** + * Private part of a generator_t object. + */ +struct private_generator_t { + /** + * Public part of a generator_t object. + */ + generator_t public; + + /** + * Buffer used to generate the data into. + */ + u_int8_t *buffer; + + /** + * Current write position in buffer (one byte aligned). + */ + u_int8_t *out_position; + + /** + * Position of last byte in buffer. + */ + u_int8_t *roof_position; + + /** + * Current bit writing to in current byte (between 0 and 7). + */ + u_int8_t current_bit; + + /** + * Associated data struct to read informations from. + */ + void *data_struct; + + /* + * Last payload length position offset in the buffer. + */ + u_int32_t last_payload_length_position_offset; + + /** + * Offset of the header length field in the buffer. + */ + u_int32_t header_length_position_offset; + + /** + * Last SPI size. + */ + u_int8_t last_spi_size; + + /** + * Attribute format of the last generated transform attribute. + * + * Used to check if a variable value field is used or not for + * the transform attribute value. + */ + bool attribute_format; + + /** + * Depending on the value of attribute_format this field is used + * to hold the length of the transform attribute in bytes. + */ + u_int16_t attribute_length; +}; + +/** + * Get size of current buffer in bytes. + */ +static int get_size(private_generator_t *this) +{ + return this->roof_position - this->buffer; +} + +/** + * Get free space of current buffer in bytes. + */ +static int get_space(private_generator_t *this) +{ + return this->roof_position - this->out_position; +} + +/** + * Get length of data in buffer (in bytes). + */ +static int get_length(private_generator_t *this) +{ + return this->out_position - this->buffer; +} + +/** + * Get current offset in buffer (in bytes). + */ +static u_int32_t get_offset(private_generator_t *this) +{ + return this->out_position - this->buffer; +} + +/** + * Makes sure enough space is available in buffer to store amount of bits. + */ +static void make_space_available(private_generator_t *this, int bits) +{ + while ((get_space(this) * 8 - this->current_bit) < bits) + { + int old_buffer_size, new_buffer_size, out_position_offset; + + old_buffer_size = get_size(this); + 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); + + this->buffer = realloc(this->buffer,new_buffer_size); + this->out_position = (this->buffer + out_position_offset); + this->roof_position = (this->buffer + new_buffer_size); + } +} + +/** + * Writes a specific amount of byte into the buffer. + */ +static void write_bytes_to_buffer(private_generator_t *this, void *bytes, + int number_of_bytes) +{ + int i; + u_int8_t *read_position = (u_int8_t *)bytes; + + make_space_available(this, number_of_bytes * 8); + + for (i = 0; i < number_of_bytes; i++) + { + *(this->out_position) = *(read_position); + read_position++; + this->out_position++; + } +} + +/** + * Writes a specific amount of byte into the buffer at a specific offset. + */ +static void write_bytes_to_buffer_at_offset(private_generator_t *this, + void *bytes, int number_of_bytes, u_int32_t offset) +{ + int i; + u_int8_t *read_position = (u_int8_t *)bytes; + u_int8_t *write_position; + u_int32_t free_space_after_offset = get_size(this) - offset; + + /* check first if enough space for new data is available */ + if (number_of_bytes > free_space_after_offset) + { + make_space_available(this, + (number_of_bytes - free_space_after_offset) * 8); + } + + write_position = this->buffer + offset; + for (i = 0; i < number_of_bytes; i++) + { + *write_position = *read_position; + read_position++; + write_position++; + } +} + +/** + * Generates a U_INT-Field type and writes it to buffer. + */ +static void generate_u_int_type(private_generator_t *this, + encoding_type_t int_type,u_int32_t offset) +{ + int number_of_bits = 0; + + /* find out number of bits of each U_INT type to check for enough space */ + switch (int_type) + { + case U_INT_4: + number_of_bits = 4; + break; + case TS_TYPE: + case U_INT_8: + number_of_bits = 8; + break; + case U_INT_16: + case CONFIGURATION_ATTRIBUTE_LENGTH: + number_of_bits = 16; + break; + case U_INT_32: + number_of_bits = 32; + break; + case ATTRIBUTE_TYPE: + number_of_bits = 15; + break; + case IKE_SPI: + number_of_bits = 64; + break; + default: + DBG1(DBG_ENC, "U_INT Type %N is not supported", + encoding_type_names, int_type); + return; + } + if ((number_of_bits % 8) == 0 && this->current_bit != 0) + { + DBG1(DBG_ENC, "U_INT Type %N is not 8 Bit aligned", + encoding_type_names, int_type); + return; + } + + make_space_available(this, number_of_bits); + switch (int_type) + { + case U_INT_4: + { + u_int8_t high, low; + + if (this->current_bit == 0) + { + /* high of current byte in buffer has to be set to the new value*/ + high = *((u_int8_t *)(this->data_struct + offset)) << 4; + /* low in buffer is not changed */ + 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)); + /* write position is not changed, just bit position is moved */ + this->current_bit = 4; + } + else if (this->current_bit == 4) + { + /* high in buffer is not changed */ + high = *(this->out_position) & 0xF0; + /* 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)); + this->out_position++; + this->current_bit = 0; + } + else + { + DBG1(DBG_ENC, "U_INT_4 Type is not 4 Bit aligned"); + /* 4 Bit integers must have a 4 bit alignment */ + return; + } + break; + } + case TS_TYPE: + case U_INT_8: + { + /* 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)); + this->out_position++; + break; + } + case ATTRIBUTE_TYPE: + { + u_int8_t attribute_format_flag; + u_int16_t val; + + /* attribute type must not change first bit of current byte */ + if (this->current_bit != 1) + { + DBG1(DBG_ENC, "ATTRIBUTE FORMAT flag is not set"); + return; + } + attribute_format_flag = *(this->out_position) & 0x80; + /* get attribute type value as 16 bit integer*/ + val = *((u_int16_t*)(this->data_struct + offset)); + /* unset most significant bit */ + val &= 0x7FFF; + if (attribute_format_flag) + { + val |= 0x8000; + } + val = htons(val); + 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; + break; + + } + case U_INT_16: + case CONFIGURATION_ATTRIBUTE_LENGTH: + { + u_int16_t val = htons(*((u_int16_t*)(this->data_struct + offset))); + 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)); + write_bytes_to_buffer(this, &val, sizeof(u_int32_t)); + break; + } + case IKE_SPI: + { + /* 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)); + break; + } + default: + { + DBG1(DBG_ENC, "U_INT Type %N is not supported", + encoding_type_names, int_type); + return; + } + } +} + +/** + * Generate a reserved bit or byte + */ +static void generate_reserved_field(private_generator_t *this, int bits) +{ + /* only one bit or 8 bit fields are supported */ + if (bits != 1 && bits != 8) + { + DBG1(DBG_ENC, "reserved field of %d bits cannot be generated", bits); + return ; + } + make_space_available(this, bits); + + if (bits == 1) + { + u_int8_t reserved_bit = ~(1 << (7 - this->current_bit)); + + *(this->out_position) = *(this->out_position) & reserved_bit; + if (this->current_bit == 0) + { + /* memory must be zero */ + *(this->out_position) = 0x00; + } + this->current_bit++; + if (this->current_bit >= 8) + { + this->current_bit = this->current_bit % 8; + this->out_position++; + } + } + else + { + if (this->current_bit > 0) + { + DBG1(DBG_ENC, "reserved field cannot be written cause " + "alignement of current bit is %d", this->current_bit); + return; + } + *(this->out_position) = 0x00; + this->out_position++; + } +} + +/** + * Generate a FLAG filed + */ +static void generate_flag(private_generator_t *this, u_int32_t offset) +{ + u_int8_t flag_value; + u_int8_t flag; + + flag_value = (*((bool *) (this->data_struct + offset))) ? 1 : 0; + /* get flag position */ + flag = (flag_value << (7 - this->current_bit)); + + /* make sure one bit is available in buffer */ + make_space_available(this, 1); + if (this->current_bit == 0) + { + /* memory must be zero */ + *(this->out_position) = 0x00; + } + + *(this->out_position) = *(this->out_position) | flag; + DBG3(DBG_ENC, " => %d", *this->out_position); + + this->current_bit++; + if (this->current_bit >= 8) + { + this->current_bit = this->current_bit % 8; + this->out_position++; + } +} + +/** + * Generates a bytestream from a chunk_t. + */ +static void generate_from_chunk(private_generator_t *this, u_int32_t offset) +{ + chunk_t *value; + + if (this->current_bit != 0) + { + 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); + + write_bytes_to_buffer(this, value->ptr, value->len); +} + +/** + * Implementation of private_generator_t.write_to_chunk. + */ +static void write_to_chunk(private_generator_t *this,chunk_t *data) +{ + int data_length = get_length(this); + u_int32_t header_length_field = data_length; + + /* write length into header length field */ + if (this->header_length_position_offset > 0) + { + u_int32_t val = htonl(header_length_field); + write_bytes_to_buffer_at_offset(this, &val, sizeof(u_int32_t), + this->header_length_position_offset); + } + + if (this->current_bit > 0) + { + data_length++; + } + *data = chunk_alloc(data_length); + memcpy(data->ptr, this->buffer, data_length); + + DBG3(DBG_ENC, "generated data of this generator %B", data); +} + +/** + * Implementation of private_generator_t.generate_payload. + */ +static void generate_payload (private_generator_t *this,payload_t *payload) +{ + int i, offset_start; + size_t rule_count; + encoding_rule_t *rules; + payload_type_t payload_type; + + this->data_struct = payload; + payload_type = payload->get_type(payload); + /* spi size has to get reseted */ + this->last_spi_size = 0; + + offset_start = this->out_position - this->buffer; + + 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); + + 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) + { + case U_INT_4: + case U_INT_8: + case U_INT_16: + case U_INT_32: + case IKE_SPI: + case TS_TYPE: + case ATTRIBUTE_TYPE: + case CONFIGURATION_ATTRIBUTE_LENGTH: + { + generate_u_int_type(this, rules[i].type, rules[i].offset); + break; + } + case RESERVED_BIT: + { + generate_reserved_field(this, 1); + break; + } + case RESERVED_BYTE: + { + generate_reserved_field(this, 8); + break; + } + case FLAG: + { + generate_flag(this, rules[i].offset); + break; + } + case PAYLOAD_LENGTH: + { + this->last_payload_length_position_offset = get_offset(this); + generate_u_int_type(this, U_INT_16,rules[i].offset); + break; + } + case HEADER_LENGTH: + { + this->header_length_position_offset = get_offset(this); + generate_u_int_type(this ,U_INT_32, rules[i].offset); + break; + } + case SPI_SIZE: + generate_u_int_type(this, U_INT_8, rules[i].offset); + this->last_spi_size = *((u_int8_t *)(this->data_struct + + rules[i].offset)); + break; + case ADDRESS: + { + generate_from_chunk(this, rules[i].offset); + break; + } + case SPI: + { + generate_from_chunk(this, rules[i].offset); + break; + } + 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: + { + u_int32_t payload_length_position_offset; + u_int16_t length_of_payload; + u_int16_t header_length = 0; + u_int16_t length_in_network_order; + + switch(rules[i].type) + { + case KEY_EXCHANGE_DATA: + header_length = KE_PAYLOAD_HEADER_LENGTH; + break; + case NOTIFICATION_DATA: + header_length = NOTIFY_PAYLOAD_HEADER_LENGTH + + this->last_spi_size; + break; + case NONCE_DATA: + header_length = NONCE_PAYLOAD_HEADER_LENGTH; + break; + case ID_DATA: + header_length = ID_PAYLOAD_HEADER_LENGTH; + break; + case AUTH_DATA: + header_length = AUTH_PAYLOAD_HEADER_LENGTH; + break; + case CERT_DATA: + header_length = CERT_PAYLOAD_HEADER_LENGTH; + break; + case CERTREQ_DATA: + header_length = CERTREQ_PAYLOAD_HEADER_LENGTH; + break; + case SPIS: + header_length = DELETE_PAYLOAD_HEADER_LENGTH; + break; + case VID_DATA: + header_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH; + break; + case CONFIGURATION_ATTRIBUTE_VALUE: + header_length = CONFIGURATION_ATTRIBUTE_HEADER_LENGTH; + break; + case EAP_DATA: + header_length = EAP_PAYLOAD_HEADER_LENGTH; + break; + default: + break; + } + generate_from_chunk(this, rules[i].offset); + + payload_length_position_offset = + this->last_payload_length_position_offset; + + length_of_payload = header_length + + ((chunk_t *)(this->data_struct + rules[i].offset))->len; + + length_in_network_order = htons(length_of_payload); + write_bytes_to_buffer_at_offset(this, &length_in_network_order, + sizeof(u_int16_t), payload_length_position_offset); + break; + } + case PROPOSALS: + { + u_int32_t payload_length_position_offset = + this->last_payload_length_position_offset; + /* Length of SA_PAYLOAD is calculated */ + u_int16_t length_of_sa_payload = SA_PAYLOAD_HEADER_LENGTH; + u_int16_t int16_val; + linked_list_t *proposals = *((linked_list_t **) + (this->data_struct + rules[i].offset)); + iterator_t *iterator; + payload_t *current_proposal; + + iterator = proposals->create_iterator(proposals,TRUE); + while (iterator->iterate(iterator, (void**)¤t_proposal)) + { + u_int32_t before_generate_position_offset; + u_int32_t after_generate_position_offset; + + before_generate_position_offset = get_offset(this); + generate_payload(this, current_proposal); + after_generate_position_offset = get_offset(this); + length_of_sa_payload += (after_generate_position_offset - + before_generate_position_offset); + } + iterator->destroy(iterator); + + int16_val = htons(length_of_sa_payload); + write_bytes_to_buffer_at_offset(this, &int16_val, + sizeof(u_int16_t),payload_length_position_offset); + break; + } + case TRANSFORMS: + { + u_int32_t payload_length_position_offset = + this->last_payload_length_position_offset; + u_int16_t length_of_proposal = + PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH + this->last_spi_size; + u_int16_t int16_val; + linked_list_t *transforms = *((linked_list_t **) + (this->data_struct + rules[i].offset)); + iterator_t *iterator; + payload_t *current_transform; + + iterator = transforms->create_iterator(transforms,TRUE); + while (iterator->iterate(iterator, (void**)¤t_transform)) + { + u_int32_t before_generate_position_offset; + u_int32_t after_generate_position_offset; + + before_generate_position_offset = get_offset(this); + generate_payload(this, current_transform); + after_generate_position_offset = get_offset(this); + + length_of_proposal += (after_generate_position_offset - + before_generate_position_offset); + } + iterator->destroy(iterator); + + int16_val = htons(length_of_proposal); + write_bytes_to_buffer_at_offset(this, &int16_val, + sizeof(u_int16_t), payload_length_position_offset); + break; + } + case TRANSFORM_ATTRIBUTES: + { + u_int32_t transform_length_position_offset = + this->last_payload_length_position_offset; + u_int16_t length_of_transform = + TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH; + u_int16_t int16_val; + linked_list_t *transform_attributes =*((linked_list_t **) + (this->data_struct + rules[i].offset)); + iterator_t *iterator; + payload_t *current_attribute; + + iterator = transform_attributes->create_iterator( + transform_attributes, TRUE); + while (iterator->iterate(iterator, (void**)¤t_attribute)) + { + u_int32_t before_generate_position_offset; + u_int32_t after_generate_position_offset; + + before_generate_position_offset = get_offset(this); + generate_payload(this, current_attribute); + after_generate_position_offset = get_offset(this); + + length_of_transform += (after_generate_position_offset - + before_generate_position_offset); + } + + iterator->destroy(iterator); + + int16_val = htons(length_of_transform); + write_bytes_to_buffer_at_offset(this, &int16_val, + sizeof(u_int16_t),transform_length_position_offset); + break; + } + case CONFIGURATION_ATTRIBUTES: + { + u_int32_t configurations_length_position_offset = + this->last_payload_length_position_offset; + u_int16_t length_of_configurations = CP_PAYLOAD_HEADER_LENGTH; + u_int16_t int16_val; + linked_list_t *configuration_attributes = *((linked_list_t **) + (this->data_struct + rules[i].offset)); + iterator_t *iterator; + payload_t *current_attribute; + + iterator = configuration_attributes->create_iterator( + configuration_attributes,TRUE); + while (iterator->iterate(iterator, (void**)¤t_attribute)) + { + u_int32_t before_generate_position_offset; + u_int32_t after_generate_position_offset; + + before_generate_position_offset = get_offset(this); + generate_payload(this, current_attribute); + after_generate_position_offset = get_offset(this); + + length_of_configurations += after_generate_position_offset - + before_generate_position_offset; + } + + iterator->destroy(iterator); + + int16_val = htons(length_of_configurations); + write_bytes_to_buffer_at_offset(this, &int16_val, + sizeof(u_int16_t),configurations_length_position_offset); + break; + } + case ATTRIBUTE_FORMAT: + { + generate_flag(this, rules[i].offset); + /* Attribute format is a flag which is stored in context*/ + this->attribute_format = + *((bool *)(this->data_struct + rules[i].offset)); + break; + } + + case ATTRIBUTE_LENGTH_OR_VALUE: + { + if (this->attribute_format == FALSE) + { + generate_u_int_type(this, U_INT_16, rules[i].offset); + /* this field hold the length of the attribute */ + this->attribute_length = + *((u_int16_t *)(this->data_struct + rules[i].offset)); + } + else + { + generate_u_int_type(this, U_INT_16, rules[i].offset); + } + break; + } + case ATTRIBUTE_VALUE: + { + if (this->attribute_format == FALSE) + { + DBG2(DBG_ENC, "attribute value has not fixed size"); + /* the attribute value is generated */ + generate_from_chunk(this, rules[i].offset); + } + break; + } + case TRAFFIC_SELECTORS: + { + u_int32_t payload_length_position_offset = + this->last_payload_length_position_offset; + u_int16_t length_of_ts_payload = TS_PAYLOAD_HEADER_LENGTH; + u_int16_t int16_val; + linked_list_t *traffic_selectors = *((linked_list_t **) + (this->data_struct + rules[i].offset)); + iterator_t *iterator; + payload_t *current_tss; + + iterator = traffic_selectors->create_iterator( + traffic_selectors,TRUE); + while (iterator->iterate(iterator, (void **)¤t_tss)) + { + u_int32_t before_generate_position_offset; + u_int32_t after_generate_position_offset; + + before_generate_position_offset = get_offset(this); + generate_payload(this, current_tss); + after_generate_position_offset = get_offset(this); + + length_of_ts_payload += (after_generate_position_offset - + before_generate_position_offset); + } + iterator->destroy(iterator); + + int16_val = htons(length_of_ts_payload); + write_bytes_to_buffer_at_offset(this, &int16_val, + sizeof(u_int16_t),payload_length_position_offset); + break; + } + + case ENCRYPTED_DATA: + { + generate_from_chunk(this, rules[i].offset); + break; + } + default: + DBG1(DBG_ENC, "field type %N is not supported", + encoding_type_names, rules[i].type); + 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, + this->out_position - this->buffer - offset_start); +} + +/** + * Implementation of generator_t.destroy. + */ +static status_t destroy(private_generator_t *this) +{ + free(this->buffer); + free(this); + return SUCCESS; +} + +/* + * Described in header + */ +generator_t *generator_create() +{ + private_generator_t *this; + + this = malloc_thing(private_generator_t); + + /* initiate public functions */ + this->public.generate_payload = (void(*)(generator_t*, payload_t *))generate_payload; + this->public.destroy = (void(*)(generator_t*)) destroy; + this->public.write_to_chunk = (void (*) (generator_t *,chunk_t *))write_to_chunk; + + /* allocate memory for buffer */ + this->buffer = malloc(GENERATOR_DATA_BUFFER_SIZE); + + /* initiate private variables */ + this->out_position = this->buffer; + this->roof_position = this->buffer + GENERATOR_DATA_BUFFER_SIZE; + this->data_struct = NULL; + this->current_bit = 0; + this->last_payload_length_position_offset = 0; + this->header_length_position_offset = 0; + this->attribute_format = FALSE; + this->attribute_length = 0; + + return &(this->public); +} + diff --git a/src/libcharon/encoding/generator.h b/src/libcharon/encoding/generator.h new file mode 100644 index 000000000..2221c84af --- /dev/null +++ b/src/libcharon/encoding/generator.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 generator generator + * @{ @ingroup encoding + */ + +#ifndef GENERATOR_H_ +#define GENERATOR_H_ + +typedef struct generator_t generator_t; + +#include <library.h> +#include <encoding/payloads/encodings.h> +#include <encoding/payloads/payload.h> + +/** + * Generating is done in a data buffer. + * This is the start size of this buffer in bytes. + */ +#define GENERATOR_DATA_BUFFER_SIZE 500 + +/** + * Number of bytes to increase the buffer, if it is too small. + */ +#define GENERATOR_DATA_BUFFER_INCREASE_VALUE 500 + + +/** + * A generator_t class used to generate IKEv2 payloads. + * + * After creation, multiple payloads can be generated with the generate_payload + * method. The generated bytes are appended. After all payloads are added, + * the write_to_chunk method writes out all generated data since + * the creation of the generator. After that, the generator must be destroyed. + * The generater uses a set of encoding rules, which it can get from + * the supplied payload. With this rules, the generater can generate + * the payload and all substructures automatically. + */ +struct generator_t { + + /** + * Generates a specific payload from given payload object. + * + * Remember: Header and substructures are also handled as payloads. + * + * @param payload interface payload_t implementing object + */ + void (*generate_payload) (generator_t *this,payload_t *payload); + + /** + * Writes all generated data of the generator to a chunk. + * + * @param data chunk to write the data to + */ + void (*write_to_chunk) (generator_t *this,chunk_t *data); + + /** + * Destroys a generator_t object. + */ + void (*destroy) (generator_t *this); +}; + +/** + * Constructor to create a generator. + * + * @return generator_t object. + */ +generator_t *generator_create(void); + +#endif /** GENERATOR_H_ @}*/ diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c new file mode 100644 index 000000000..acfc0fd44 --- /dev/null +++ b/src/libcharon/encoding/message.c @@ -0,0 +1,1723 @@ +/* + * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2006 Daniel Roethlisberger + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 <stdlib.h> +#include <string.h> + +#include "message.h" + +#include <library.h> +#include <daemon.h> +#include <sa/ike_sa_id.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/encryption_payload.h> +#include <encoding/payloads/unknown_payload.h> + +/** + * Max number of notify payloads per IKEv2 Message + */ +#define MAX_NOTIFY_PAYLOADS 20 + +/** + * Max number of delete payloads per IKEv2 Message + */ +#define MAX_DELETE_PAYLOADS 20 + + +typedef struct payload_rule_t payload_rule_t; + +/** + * 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 + * and if it must be encrypted. + */ +struct payload_rule_t { + /** + * Payload type. + */ + payload_type_t payload_type; + + /** + * Minimal occurence of this payload. + */ + size_t min_occurence; + + /** + * Max occurence of this payload. + */ + size_t max_occurence; + + /** + * TRUE if payload must be encrypted + */ + bool encrypted; + + /** + * If this payload occurs, the message rule is + * fullfilled in any case. This applies e.g. to + * notify_payloads. + */ + bool sufficient; +}; + +typedef struct payload_order_t payload_order_t; + +/** + * payload ordering structure allows us to reorder payloads according to RFC. + */ +struct payload_order_t { + + /** + * payload type + */ + payload_type_t type; + + /** + * notify type, if payload == NOTIFY + */ + notify_type_t notify; +}; + + +typedef struct message_rule_t message_rule_t; + +/** + * A message rule defines the kind of a message, + * if it has encrypted contents and a list + * of payload ordering rules and payload parsing rules. + */ +struct message_rule_t { + /** + * Type of message. + */ + exchange_type_t exchange_type; + + /** + * Is message a request or response. + */ + bool is_request; + + /** + * Message contains encrypted content. + */ + bool encrypted_content; + + /** + * Number of payload rules which will follow + */ + int payload_rule_count; + + /** + * Pointer to first payload rule + */ + payload_rule_t *payload_rules; + + /** + * Number of payload order rules + */ + int payload_order_count; + + /** + * payload ordering rules + */ + payload_order_t *payload_order; +}; + +/** + * Message rule for IKE_SA_INIT from initiator. + */ +static payload_rule_t ike_sa_init_i_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION, 1, 1, FALSE, FALSE}, + {KEY_EXCHANGE, 1, 1, FALSE, FALSE}, + {NONCE, 1, 1, FALSE, FALSE}, + {VENDOR_ID, 0, 10, FALSE, FALSE}, +}; + +/** + * payload order for IKE_SA_INIT initiator + */ +static payload_order_t ike_sa_init_i_payload_order[] = { +/* payload type notify type */ + {NOTIFY, COOKIE}, + {SECURITY_ASSOCIATION, 0}, + {KEY_EXCHANGE, 0}, + {NONCE, 0}, + {NOTIFY, NAT_DETECTION_SOURCE_IP}, + {NOTIFY, NAT_DETECTION_DESTINATION_IP}, + {NOTIFY, 0}, + {VENDOR_ID, 0}, +}; + +/** + * Message rule for IKE_SA_INIT from responder. + */ +static payload_rule_t ike_sa_init_r_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, FALSE, TRUE}, + {SECURITY_ASSOCIATION, 1, 1, FALSE, FALSE}, + {KEY_EXCHANGE, 1, 1, FALSE, FALSE}, + {NONCE, 1, 1, FALSE, FALSE}, + {VENDOR_ID, 0, 10, FALSE, FALSE}, +}; + +/** + * payload order for IKE_SA_INIT responder + */ +static payload_order_t ike_sa_init_r_payload_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION, 0}, + {KEY_EXCHANGE, 0}, + {NONCE, 0}, + {NOTIFY, NAT_DETECTION_SOURCE_IP}, + {NOTIFY, NAT_DETECTION_DESTINATION_IP}, + {NOTIFY, HTTP_CERT_LOOKUP_SUPPORTED}, + {CERTIFICATE_REQUEST, 0}, + {NOTIFY, 0}, + {VENDOR_ID, 0}, +}; + +/** + * Message rule for IKE_AUTH from initiator. + */ +static payload_rule_t ike_auth_i_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {EXTENSIBLE_AUTHENTICATION, 0, 1, TRUE, TRUE}, + {AUTHENTICATION, 0, 1, TRUE, TRUE}, + {ID_INITIATOR, 0, 1, TRUE, FALSE}, + {CERTIFICATE, 0, 4, TRUE, FALSE}, + {CERTIFICATE_REQUEST, 0, 1, TRUE, FALSE}, + {ID_RESPONDER, 0, 1, TRUE, FALSE}, +#ifdef ME + {SECURITY_ASSOCIATION, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, +#else + {SECURITY_ASSOCIATION, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, +#endif /* ME */ + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for IKE_AUTH initiator + */ +static payload_order_t ike_auth_i_payload_order[] = { +/* payload type notify type */ + {ID_INITIATOR, 0}, + {CERTIFICATE, 0}, + {NOTIFY, INITIAL_CONTACT}, + {NOTIFY, HTTP_CERT_LOOKUP_SUPPORTED}, + {CERTIFICATE_REQUEST, 0}, + {ID_RESPONDER, 0}, + {AUTHENTICATION, 0}, + {EXTENSIBLE_AUTHENTICATION, 0}, + {CONFIGURATION, 0}, + {NOTIFY, IPCOMP_SUPPORTED}, + {NOTIFY, USE_TRANSPORT_MODE}, + {NOTIFY, ESP_TFC_PADDING_NOT_SUPPORTED}, + {NOTIFY, NON_FIRST_FRAGMENTS_ALSO}, + {SECURITY_ASSOCIATION, 0}, + {TRAFFIC_SELECTOR_INITIATOR, 0}, + {TRAFFIC_SELECTOR_RESPONDER, 0}, + {NOTIFY, MOBIKE_SUPPORTED}, + {NOTIFY, ADDITIONAL_IP4_ADDRESS}, + {NOTIFY, ADDITIONAL_IP6_ADDRESS}, + {NOTIFY, NO_ADDITIONAL_ADDRESSES}, + {NOTIFY, 0}, + {VENDOR_ID, 0}, +}; + +/** + * Message rule for IKE_AUTH from responder. + */ +static payload_rule_t ike_auth_r_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, + {EXTENSIBLE_AUTHENTICATION, 0, 1, TRUE, TRUE}, + {AUTHENTICATION, 0, 1, TRUE, TRUE}, + {CERTIFICATE, 0, 4, TRUE, FALSE}, + {ID_RESPONDER, 0, 1, TRUE, FALSE}, + {SECURITY_ASSOCIATION, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for IKE_AUTH responder + */ +static payload_order_t ike_auth_r_payload_order[] = { +/* payload type notify type */ + {ID_RESPONDER, 0}, + {CERTIFICATE, 0}, + {AUTHENTICATION, 0}, + {EXTENSIBLE_AUTHENTICATION, 0}, + {CONFIGURATION, 0}, + {NOTIFY, IPCOMP_SUPPORTED}, + {NOTIFY, USE_TRANSPORT_MODE}, + {NOTIFY, ESP_TFC_PADDING_NOT_SUPPORTED}, + {NOTIFY, NON_FIRST_FRAGMENTS_ALSO}, + {SECURITY_ASSOCIATION, 0}, + {TRAFFIC_SELECTOR_INITIATOR, 0}, + {TRAFFIC_SELECTOR_RESPONDER, 0}, + {NOTIFY, AUTH_LIFETIME}, + {NOTIFY, MOBIKE_SUPPORTED}, + {NOTIFY, ADDITIONAL_IP4_ADDRESS}, + {NOTIFY, ADDITIONAL_IP6_ADDRESS}, + {NOTIFY, NO_ADDITIONAL_ADDRESSES}, + {NOTIFY, 0}, + {VENDOR_ID, 0}, +}; + +/** + * Message rule for INFORMATIONAL from initiator. + */ +static payload_rule_t informational_i_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {DELETE, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL initiator + */ +static payload_order_t informational_i_payload_order[] = { +/* payload type notify type */ + {NOTIFY, UPDATE_SA_ADDRESSES}, + {NOTIFY, NAT_DETECTION_SOURCE_IP}, + {NOTIFY, NAT_DETECTION_DESTINATION_IP}, + {NOTIFY, COOKIE2}, + {NOTIFY, 0}, + {DELETE, 0}, + {CONFIGURATION, 0}, +}; + +/** + * Message rule for INFORMATIONAL from responder. + */ +static payload_rule_t informational_r_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {DELETE, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL responder + */ +static payload_order_t informational_r_payload_order[] = { +/* payload type notify type */ + {NOTIFY, UPDATE_SA_ADDRESSES}, + {NOTIFY, NAT_DETECTION_SOURCE_IP}, + {NOTIFY, NAT_DETECTION_DESTINATION_IP}, + {NOTIFY, COOKIE2}, + {NOTIFY, 0}, + {DELETE, 0}, + {CONFIGURATION, 0}, +}; + +/** + * Message rule for CREATE_CHILD_SA from initiator. + */ +static payload_rule_t create_child_sa_i_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {SECURITY_ASSOCIATION, 1, 1, TRUE, FALSE}, + {NONCE, 1, 1, TRUE, FALSE}, + {KEY_EXCHANGE, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for CREATE_CHILD_SA from initiator. + */ +static payload_order_t create_child_sa_i_payload_order[] = { +/* payload type notify type */ + {NOTIFY, REKEY_SA}, + {NOTIFY, IPCOMP_SUPPORTED}, + {NOTIFY, USE_TRANSPORT_MODE}, + {NOTIFY, ESP_TFC_PADDING_NOT_SUPPORTED}, + {NOTIFY, NON_FIRST_FRAGMENTS_ALSO}, + {SECURITY_ASSOCIATION, 0}, + {NONCE, 0}, + {KEY_EXCHANGE, 0}, + {TRAFFIC_SELECTOR_INITIATOR, 0}, + {TRAFFIC_SELECTOR_RESPONDER, 0}, + {NOTIFY, 0}, +}; + +/** + * Message rule for CREATE_CHILD_SA from responder. + */ +static payload_rule_t create_child_sa_r_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, + {SECURITY_ASSOCIATION, 1, 1, TRUE, FALSE}, + {NONCE, 1, 1, TRUE, FALSE}, + {KEY_EXCHANGE, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_INITIATOR, 0, 1, TRUE, FALSE}, + {TRAFFIC_SELECTOR_RESPONDER, 0, 1, TRUE, FALSE}, + {CONFIGURATION, 0, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE}, +}; + +/** + * payload order for CREATE_CHILD_SA from responder. + */ +static payload_order_t create_child_sa_r_payload_order[] = { +/* payload type notify type */ + {NOTIFY, IPCOMP_SUPPORTED}, + {NOTIFY, USE_TRANSPORT_MODE}, + {NOTIFY, ESP_TFC_PADDING_NOT_SUPPORTED}, + {NOTIFY, NON_FIRST_FRAGMENTS_ALSO}, + {SECURITY_ASSOCIATION, 0}, + {NONCE, 0}, + {KEY_EXCHANGE, 0}, + {TRAFFIC_SELECTOR_INITIATOR, 0}, + {TRAFFIC_SELECTOR_RESPONDER, 0}, + {NOTIFY, ADDITIONAL_TS_POSSIBLE}, + {NOTIFY, 0}, +}; + +#ifdef ME +/** + * Message rule for ME_CONNECT from initiator. + */ +static payload_rule_t me_connect_i_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, + {ID_PEER, 1, 1, TRUE, FALSE}, + {VENDOR_ID, 0, 10, TRUE, FALSE} +}; + +/** + * payload order for ME_CONNECT from initiator. + */ +static payload_order_t me_connect_i_payload_order[] = { +/* payload type notify type */ + {NOTIFY, 0}, + {ID_PEER, 0}, + {VENDOR_ID, 0}, +}; + +/** + * Message rule for ME_CONNECT from responder. + */ +static payload_rule_t me_connect_r_payload_rules[] = { +/* payload type min max encr suff */ + {NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, + {VENDOR_ID, 0, 10, TRUE, FALSE} +}; + +/** + * payload order for ME_CONNECT from responder. + */ +static payload_order_t me_connect_r_payload_order[] = { +/* payload type notify type */ + {NOTIFY, 0}, + {VENDOR_ID, 0}, +}; +#endif /* ME */ + +/** + * Message rules, defines allowed payloads. + */ +static message_rule_t message_rules[] = { + {IKE_SA_INIT, TRUE, FALSE, + (sizeof(ike_sa_init_i_payload_rules)/sizeof(payload_rule_t)), + ike_sa_init_i_payload_rules, + (sizeof(ike_sa_init_i_payload_order)/sizeof(payload_order_t)), + ike_sa_init_i_payload_order, + }, + {IKE_SA_INIT, FALSE, FALSE, + (sizeof(ike_sa_init_r_payload_rules)/sizeof(payload_rule_t)), + ike_sa_init_r_payload_rules, + (sizeof(ike_sa_init_r_payload_order)/sizeof(payload_order_t)), + ike_sa_init_r_payload_order, + }, + {IKE_AUTH, TRUE, TRUE, + (sizeof(ike_auth_i_payload_rules)/sizeof(payload_rule_t)), + ike_auth_i_payload_rules, + (sizeof(ike_auth_i_payload_order)/sizeof(payload_order_t)), + ike_auth_i_payload_order, + }, + {IKE_AUTH, FALSE, TRUE, + (sizeof(ike_auth_r_payload_rules)/sizeof(payload_rule_t)), + ike_auth_r_payload_rules, + (sizeof(ike_auth_r_payload_order)/sizeof(payload_order_t)), + ike_auth_r_payload_order, + }, + {INFORMATIONAL, TRUE, TRUE, + (sizeof(informational_i_payload_rules)/sizeof(payload_rule_t)), + informational_i_payload_rules, + (sizeof(informational_i_payload_order)/sizeof(payload_order_t)), + informational_i_payload_order, + }, + {INFORMATIONAL, FALSE, TRUE, + (sizeof(informational_r_payload_rules)/sizeof(payload_rule_t)), + informational_r_payload_rules, + (sizeof(informational_r_payload_order)/sizeof(payload_order_t)), + informational_r_payload_order, + }, + {CREATE_CHILD_SA, TRUE, TRUE, + (sizeof(create_child_sa_i_payload_rules)/sizeof(payload_rule_t)), + create_child_sa_i_payload_rules, + (sizeof(create_child_sa_i_payload_order)/sizeof(payload_order_t)), + create_child_sa_i_payload_order, + }, + {CREATE_CHILD_SA, FALSE, TRUE, + (sizeof(create_child_sa_r_payload_rules)/sizeof(payload_rule_t)), + create_child_sa_r_payload_rules, + (sizeof(create_child_sa_r_payload_order)/sizeof(payload_order_t)), + create_child_sa_r_payload_order, + }, +#ifdef ME + {ME_CONNECT, TRUE, TRUE, + (sizeof(me_connect_i_payload_rules)/sizeof(payload_rule_t)), + me_connect_i_payload_rules, + (sizeof(me_connect_i_payload_order)/sizeof(payload_order_t)), + me_connect_i_payload_order, + }, + {ME_CONNECT, FALSE, TRUE, + (sizeof(me_connect_r_payload_rules)/sizeof(payload_rule_t)), + me_connect_r_payload_rules, + (sizeof(me_connect_r_payload_order)/sizeof(payload_order_t)), + me_connect_r_payload_order, + }, +#endif /* ME */ +}; + + +typedef struct private_message_t private_message_t; + +/** + * Private data of an message_t object. + */ +struct private_message_t { + + /** + * Public part of a message_t object. + */ + message_t public; + + /** + * Minor version of message. + */ + u_int8_t major_version; + + /** + * Major version of message. + */ + u_int8_t minor_version; + + /** + * First Payload in message. + */ + payload_type_t first_payload; + + /** + * Assigned exchange type. + */ + exchange_type_t exchange_type; + + /** + * TRUE if message is a request, FALSE if a reply. + */ + bool is_request; + + /** + * Message ID of this message. + */ + u_int32_t message_id; + + /** + * ID of assigned IKE_SA. + */ + ike_sa_id_t *ike_sa_id; + + /** + * Assigned UDP packet, stores incoming packet or last generated one. + */ + packet_t *packet; + + /** + * Linked List where payload data are stored in. + */ + linked_list_t *payloads; + + /** + * Assigned parser to parse Header and Body of this message. + */ + parser_t *parser; + + /** + * The message rule for this message instance + */ + message_rule_t *message_rule; +}; + +/** + * Implementation of private_message_t.set_message_rule. + */ +static status_t set_message_rule(private_message_t *this) +{ + int i; + + for (i = 0; i < (sizeof(message_rules) / sizeof(message_rule_t)); i++) + { + if ((this->exchange_type == message_rules[i].exchange_type) && + (this->is_request == message_rules[i].is_request)) + { + /* found rule for given exchange_type*/ + this->message_rule = &(message_rules[i]); + return SUCCESS; + } + } + this->message_rule = NULL; + return NOT_FOUND; +} + +/** + * Implementation of private_message_t.get_payload_rule. + */ +static status_t get_payload_rule(private_message_t *this, + payload_type_t payload_type, payload_rule_t **payload_rule) +{ + int i; + + for (i = 0; i < this->message_rule->payload_rule_count;i++) + { + if (this->message_rule->payload_rules[i].payload_type == payload_type) + { + *payload_rule = &(this->message_rule->payload_rules[i]); + return SUCCESS; + } + } + + *payload_rule = NULL; + return NOT_FOUND; +} + +/** + * Implementation of message_t.set_ike_sa_id. + */ +static void set_ike_sa_id(private_message_t *this,ike_sa_id_t *ike_sa_id) +{ + DESTROY_IF(this->ike_sa_id); + this->ike_sa_id = ike_sa_id->clone(ike_sa_id); +} + +/** + * Implementation of message_t.get_ike_sa_id. + */ +static ike_sa_id_t* get_ike_sa_id(private_message_t *this) +{ + return this->ike_sa_id; +} + +/** + * Implementation of message_t.set_message_id. + */ +static void set_message_id(private_message_t *this,u_int32_t message_id) +{ + this->message_id = message_id; +} + +/** + * Implementation of message_t.get_message_id. + */ +static u_int32_t get_message_id(private_message_t *this) +{ + return this->message_id; +} + +/** + * Implementation of message_t.get_initiator_spi. + */ +static u_int64_t get_initiator_spi(private_message_t *this) +{ + return (this->ike_sa_id->get_initiator_spi(this->ike_sa_id)); +} + +/** + * Implementation of message_t.get_responder_spi. + */ +static u_int64_t get_responder_spi(private_message_t *this) +{ + return (this->ike_sa_id->get_responder_spi(this->ike_sa_id)); +} + +/** + * Implementation of message_t.set_major_version. + */ +static void set_major_version(private_message_t *this,u_int8_t major_version) +{ + this->major_version = major_version; +} + +/** + * Implementation of message_t.set_major_version. + */ +static u_int8_t get_major_version(private_message_t *this) +{ + return this->major_version; +} + +/** + * Implementation of message_t.set_minor_version. + */ +static void set_minor_version(private_message_t *this,u_int8_t minor_version) +{ + this->minor_version = minor_version; +} + +/** + * Implementation of message_t.get_minor_version. + */ +static u_int8_t get_minor_version(private_message_t *this) +{ + return this->minor_version; +} + +/** + * Implementation of message_t.set_exchange_type. + */ +static void set_exchange_type(private_message_t *this, + exchange_type_t exchange_type) +{ + this->exchange_type = exchange_type; +} + +/** + * Implementation of message_t.get_exchange_type. + */ +static exchange_type_t get_exchange_type(private_message_t *this) +{ + return this->exchange_type; +} + +/** + * Implementation of message_t.get_first_payload_type. + */ +static payload_type_t get_first_payload_type(private_message_t *this) +{ + return this->first_payload; +} + +/** + * Implementation of message_t.set_request. + */ +static void set_request(private_message_t *this, bool request) +{ + this->is_request = request; +} + +/** + * Implementation of message_t.get_request. + */ +static exchange_type_t get_request(private_message_t *this) +{ + return this->is_request; +} + +/** + * Is this message in an encoded form? + */ +static bool is_encoded(private_message_t *this) +{ + chunk_t data = this->packet->get_data(this->packet); + + if (data.ptr == NULL) + { + return FALSE; + } + return TRUE; +} + +/** + * Implementation of message_t.add_payload. + */ +static void add_payload(private_message_t *this, payload_t *payload) +{ + payload_t *last_payload; + + if (this->payloads->get_count(this->payloads) > 0) + { + this->payloads->get_last(this->payloads, (void **)&last_payload); + last_payload->set_next_type(last_payload, payload->get_type(payload)); + } + else + { + this->first_payload = payload->get_type(payload); + } + payload->set_next_type(payload, NO_PAYLOAD); + this->payloads->insert_last(this->payloads, payload); + + DBG2(DBG_ENC ,"added payload of type %N to message", + payload_type_names, payload->get_type(payload)); +} + +/** + * Implementation of message_t.add_notify. + */ +static void add_notify(private_message_t *this, bool flush, notify_type_t type, + chunk_t data) +{ + notify_payload_t *notify; + payload_t *payload; + + if (flush) + { + while (this->payloads->remove_last(this->payloads, + (void**)&payload) == SUCCESS) + { + payload->destroy(payload); + } + } + notify = notify_payload_create(); + notify->set_notify_type(notify, type); + notify->set_notification_data(notify, data); + add_payload(this, (payload_t*)notify); +} + +/** + * Implementation of message_t.set_source. + */ +static void set_source(private_message_t *this, host_t *host) +{ + this->packet->set_source(this->packet, host); +} + +/** + * Implementation of message_t.set_destination. + */ +static void set_destination(private_message_t *this, host_t *host) +{ + this->packet->set_destination(this->packet, host); +} + +/** + * Implementation of message_t.get_source. + */ +static host_t* get_source(private_message_t *this) +{ + return this->packet->get_source(this->packet); +} + +/** + * Implementation of message_t.get_destination. + */ +static host_t * get_destination(private_message_t *this) +{ + return this->packet->get_destination(this->packet); +} + +/** + * Implementation of message_t.create_payload_enumerator. + */ +static enumerator_t *create_payload_enumerator(private_message_t *this) +{ + return this->payloads->create_enumerator(this->payloads); +} + +/** + * Implementation of message_t.get_payload. + */ +static payload_t *get_payload(private_message_t *this, payload_type_t type) +{ + payload_t *current, *found = NULL; + enumerator_t *enumerator; + + enumerator = create_payload_enumerator(this); + while (enumerator->enumerate(enumerator, ¤t)) + { + if (current->get_type(current) == type) + { + found = current; + break; + } + } + enumerator->destroy(enumerator); + return found; +} + +/** + * Implementation of message_t.get_notify + */ +static notify_payload_t* get_notify(private_message_t *this, notify_type_t type) +{ + enumerator_t *enumerator; + notify_payload_t *notify = NULL; + payload_t *payload; + + enumerator = create_payload_enumerator(this); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == NOTIFY) + { + notify = (notify_payload_t*)payload; + if (notify->get_notify_type(notify) == type) + { + break; + } + notify = NULL; + } + } + enumerator->destroy(enumerator); + return notify; +} + +/** + * get a string representation of the message + */ +static char* get_string(private_message_t *this, char *buf, int len) +{ + enumerator_t *enumerator; + payload_t *payload; + int written; + char *pos = buf; + + memset(buf, 0, len); + len--; + + written = snprintf(pos, len, "%N %s %d [", + exchange_type_names, this->exchange_type, + this->is_request ? "request" : "response", + this->message_id); + if (written >= len || written < 0) + { + return ""; + } + pos += written; + len -= written; + + enumerator = create_payload_enumerator(this); + while (enumerator->enumerate(enumerator, &payload)) + { + written = snprintf(pos, len, " %N", payload_type_short_names, + payload->get_type(payload)); + if (written >= len || written < 0) + { + return buf; + } + pos += written; + len -= written; + if (payload->get_type(payload) == NOTIFY) + { + notify_payload_t *notify = (notify_payload_t*)payload; + written = snprintf(pos, len, "(%N)", notify_type_short_names, + notify->get_notify_type(notify)); + if (written >= len || written < 0) + { + return buf; + } + pos += written; + len -= written; + } + if (payload->get_type(payload) == EXTENSIBLE_AUTHENTICATION) + { + eap_payload_t *eap = (eap_payload_t*)payload; + u_int32_t vendor; + eap_type_t type; + char method[64] = ""; + + type = eap->get_type(eap, &vendor); + if (type) + { + if (vendor) + { + snprintf(method, sizeof(method), "/%d-%d", type, vendor); + } + else + { + snprintf(method, sizeof(method), "/%N", + eap_type_short_names, type); + } + } + written = snprintf(pos, len, "/%N%s", eap_code_short_names, + eap->get_code(eap), method); + if (written >= len || written < 0) + { + return buf; + } + pos += written; + len -= written; + } + } + enumerator->destroy(enumerator); + + /* remove last space */ + snprintf(pos, len, " ]"); + return buf; +} + +/** + * reorder payloads depending on reordering rules + */ +static void order_payloads(private_message_t *this) +{ + linked_list_t *list; + payload_t *payload; + int i; + + /* move to temp list */ + list = linked_list_create(); + while (this->payloads->remove_last(this->payloads, + (void**)&payload) == SUCCESS) + { + list->insert_first(list, payload); + } + /* for each rule, ... */ + for (i = 0; i < this->message_rule->payload_order_count; i++) + { + enumerator_t *enumerator; + notify_payload_t *notify; + payload_order_t order = this->message_rule->payload_order[i]; + + /* ... find all payload ... */ + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &payload)) + { + /* ... with that type ... */ + if (payload->get_type(payload) == order.type) + { + notify = (notify_payload_t*)payload; + + /**... and check notify for type. */ + if (order.type != NOTIFY || order.notify == 0 || + order.notify == notify->get_notify_type(notify)) + { + list->remove_at(list, enumerator); + add_payload(this, payload); + } + } + } + enumerator->destroy(enumerator); + } + /* append all payloads without a rule to the end */ + while (list->remove_last(list, (void**)&payload) == SUCCESS) + { + /* do not complain about payloads in private use space */ + if (payload->get_type(payload) < 128) + { + DBG1(DBG_ENC, "payload %N has no ordering rule in %N %s", + payload_type_names, payload->get_type(payload), + exchange_type_names, this->message_rule->exchange_type, + this->message_rule->is_request ? "request" : "response"); + } + add_payload(this, payload); + } + list->destroy(list); +} + +/** + * Implementation of private_message_t.encrypt_payloads. + */ +static status_t encrypt_payloads(private_message_t *this, + crypter_t *crypter, signer_t* signer) +{ + encryption_payload_t *encryption; + linked_list_t *payloads; + payload_t *current; + status_t status; + + if (!this->message_rule->encrypted_content) + { + DBG2(DBG_ENC, "message doesn't have to be encrypted"); + /* message contains no content to encrypt */ + return SUCCESS; + } + + if (!crypter || !signer) + { + DBG2(DBG_ENC, "no crypter or signer specified, do not encrypt message"); + /* message contains no content to encrypt */ + return SUCCESS; + } + + DBG2(DBG_ENC, "copy all payloads to a temporary list"); + payloads = linked_list_create(); + + /* first copy all payloads in a temporary list */ + while (this->payloads->get_count(this->payloads) > 0) + { + this->payloads->remove_first(this->payloads, (void**)¤t); + payloads->insert_last(payloads, current); + } + + encryption = encryption_payload_create(); + + DBG2(DBG_ENC, "check each payloads if they have to get encrypted"); + while (payloads->get_count(payloads) > 0) + { + payload_rule_t *rule; + payload_type_t type; + bool to_encrypt = TRUE; + + payloads->remove_first(payloads, (void**)¤t); + + type = current->get_type(current); + if (get_payload_rule(this, type, &rule) == SUCCESS) + { + to_encrypt = rule->encrypted; + } + if (to_encrypt) + { + DBG2(DBG_ENC, "insert payload %N to encryption payload", + payload_type_names, current->get_type(current)); + encryption->add_payload(encryption, current); + } + else + { + DBG2(DBG_ENC, "insert payload %N unencrypted", + payload_type_names, current->get_type(current)); + add_payload(this, (payload_t*)current); + } + } + + DBG2(DBG_ENC, "encrypting encryption payload"); + encryption->set_transforms(encryption, crypter, signer); + status = encryption->encrypt(encryption); + DBG2(DBG_ENC, "add encrypted payload to payload list"); + add_payload(this, (payload_t*)encryption); + + payloads->destroy(payloads); + + return status; +} + +/** + * Implementation of message_t.generate. + */ +static status_t generate(private_message_t *this, crypter_t *crypter, + signer_t* signer, packet_t **packet) +{ + generator_t *generator; + ike_header_t *ike_header; + payload_t *payload, *next_payload; + enumerator_t *enumerator; + status_t status; + chunk_t packet_data; + char str[256]; + + if (is_encoded(this)) + { + /* already generated, return a new packet clone */ + *packet = this->packet->clone(this->packet); + return SUCCESS; + } + + if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED) + { + DBG1(DBG_ENC, "exchange type is not defined"); + return INVALID_STATE; + } + + if (this->packet->get_source(this->packet) == NULL || + this->packet->get_destination(this->packet) == NULL) + { + DBG1(DBG_ENC, "%s not defined", + !this->packet->get_source(this->packet) ? "source" : "destination"); + return INVALID_STATE; + } + + /* set the rules for this messge */ + status = set_message_rule(this); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "no message rules specified for this message type"); + return NOT_SUPPORTED; + } + + order_payloads(this); + + DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); + + /* going to encrypt all content which have to be encrypted */ + status = encrypt_payloads(this, crypter, signer); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "payload encryption failed"); + return status; + } + + /* build ike header */ + ike_header = ike_header_create(); + + 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_initiator_flag(ike_header, + this->ike_sa_id->is_initiator(this->ike_sa_id)); + 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, + this->ike_sa_id->get_responder_spi(this->ike_sa_id)); + + generator = generator_create(); + + payload = (payload_t*)ike_header; + + /* generate every payload expect last one, this is done later*/ + enumerator = create_payload_enumerator(this); + while (enumerator->enumerate(enumerator, &next_payload)) + { + payload->set_next_type(payload, next_payload->get_type(next_payload)); + generator->generate_payload(generator, payload); + payload = next_payload; + } + enumerator->destroy(enumerator); + + /* last payload has no next payload*/ + payload->set_next_type(payload, NO_PAYLOAD); + + generator->generate_payload(generator, payload); + + ike_header->destroy(ike_header); + + /* build packet */ + generator->write_to_chunk(generator, &packet_data); + generator->destroy(generator); + + /* if last payload is of type encrypted, integrity checksum if necessary */ + if (payload->get_type(payload) == ENCRYPTED) + { + DBG2(DBG_ENC, "build signature on whole message"); + encryption_payload_t *encryption_payload = (encryption_payload_t*)payload; + status = encryption_payload->build_signature(encryption_payload, packet_data); + if (status != SUCCESS) + { + return status; + } + } + + this->packet->set_data(this->packet, packet_data); + + /* clone packet for caller */ + *packet = this->packet->clone(this->packet); + + DBG2(DBG_ENC, "message generated successfully"); + return SUCCESS; +} + +/** + * Implementation of message_t.get_packet. + */ +static packet_t *get_packet(private_message_t *this) +{ + if (this->packet == NULL) + { + return NULL; + } + return this->packet->clone(this->packet); +} + +/** + * Implementation of message_t.get_packet_data. + */ +static chunk_t get_packet_data(private_message_t *this) +{ + if (this->packet == NULL) + { + return chunk_empty; + } + return chunk_clone(this->packet->get_data(this->packet)); +} + +/** + * Implementation of message_t.parse_header. + */ +static status_t parse_header(private_message_t *this) +{ + ike_header_t *ike_header; + status_t status; + + DBG2(DBG_ENC, "parsing header of message"); + + this->parser->reset_context(this->parser); + status = this->parser->parse_payload(this->parser, HEADER, + (payload_t**)&ike_header); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "header could not be parsed"); + return status; + + } + + /* verify payload */ + status = ike_header->payload_interface.verify( + &ike_header->payload_interface); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "header verification failed"); + ike_header->destroy(ike_header); + return status; + } + + if (this->ike_sa_id != NULL) + { + this->ike_sa_id->destroy(this->ike_sa_id); + } + + this->ike_sa_id = ike_sa_id_create(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); + this->first_payload = ike_header->payload_interface.get_next_type( + &ike_header->payload_interface); + + DBG2(DBG_ENC, "parsed a %N %s", exchange_type_names, this->exchange_type, + this->is_request ? "request" : "response"); + + ike_header->destroy(ike_header); + + /* get the rules for this messge */ + status = set_message_rule(this); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "no message rules specified for a %N %s", + exchange_type_names, this->exchange_type, + this->is_request ? "request" : "response"); + } + + return status; +} + +/** + * Implementation of private_message_t.decrypt_and_verify_payloads. + */ +static status_t decrypt_payloads(private_message_t *this, crypter_t *crypter, + signer_t* signer) +{ + bool current_payload_was_encrypted = FALSE; + payload_t *previous_payload = NULL; + int payload_number = 1; + iterator_t *iterator; + payload_t *current_payload; + status_t status; + + iterator = this->payloads->create_iterator(this->payloads,TRUE); + + /* process each payload and decrypt a encryption payload */ + while(iterator->iterate(iterator, (void**)¤t_payload)) + { + payload_rule_t *payload_rule; + payload_type_t current_payload_type; + + /* needed to check */ + current_payload_type = current_payload->get_type(current_payload); + + DBG2(DBG_ENC, "process payload of type %N", + payload_type_names, current_payload_type); + + if (current_payload_type == ENCRYPTED) + { + encryption_payload_t *encryption_payload; + payload_t *current_encrypted_payload; + + encryption_payload = (encryption_payload_t*)current_payload; + + DBG2(DBG_ENC, "found an encryption payload"); + + if (payload_number != this->payloads->get_count(this->payloads)) + { + /* encrypted payload is not last one */ + DBG1(DBG_ENC, "encrypted payload is not last payload"); + iterator->destroy(iterator); + return VERIFY_ERROR; + } + /* decrypt */ + encryption_payload->set_transforms(encryption_payload, + crypter, signer); + DBG2(DBG_ENC, "verify signature of encryption payload"); + status = encryption_payload->verify_signature(encryption_payload, + this->packet->get_data(this->packet)); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "encryption payload signature invalid"); + iterator->destroy(iterator); + return FAILED; + } + DBG2(DBG_ENC, "decrypting content of encryption payload"); + status = encryption_payload->decrypt(encryption_payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "encrypted payload could not be decrypted and parsed"); + iterator->destroy(iterator); + return PARSE_ERROR; + } + + /* needed later to find out if a payload was encrypted */ + current_payload_was_encrypted = TRUE; + + /* check if there are payloads contained in the encryption payload */ + if (encryption_payload->get_payload_count(encryption_payload) == 0) + { + DBG2(DBG_ENC, "encrypted payload is empty"); + /* remove the encryption payload, is not needed anymore */ + iterator->remove(iterator); + /* encrypted payload contains no other payload */ + current_payload_type = NO_PAYLOAD; + } + else + { + /* encryption_payload is replaced with first payload contained + * in encryption_payload */ + encryption_payload->remove_first_payload(encryption_payload, + ¤t_encrypted_payload); + iterator->replace(iterator, NULL, + (void *)current_encrypted_payload); + current_payload_type = current_encrypted_payload->get_type( + current_encrypted_payload); + } + + /* is the current paylad the first in the message? */ + if (previous_payload == NULL) + { + /* yes, set the first payload type of the message to the + * current type */ + this->first_payload = current_payload_type; + } + else + { + /* no, set the next_type of the previous payload to the + * current type */ + previous_payload->set_next_type(previous_payload, + current_payload_type); + } + + /* all encrypted payloads are added to the payload list */ + while (encryption_payload->get_payload_count(encryption_payload) > 0) + { + encryption_payload->remove_first_payload(encryption_payload, + ¤t_encrypted_payload); + DBG2(DBG_ENC, "insert unencrypted payload of type " + "%N at end of list", payload_type_names, + current_encrypted_payload->get_type( + current_encrypted_payload)); + this->payloads->insert_last(this->payloads, + current_encrypted_payload); + } + + /* encryption payload is processed, payloads are moved. Destroy it. */ + encryption_payload->destroy(encryption_payload); + } + + /* we allow unknown payloads of any type and don't bother if it was + * encrypted. Not our problem. */ + if (current_payload_type != UNKNOWN_PAYLOAD && + current_payload_type != NO_PAYLOAD) + { + /* get the ruleset for found payload */ + status = get_payload_rule(this, current_payload_type, &payload_rule); + if (status != SUCCESS) + { + /* payload is not allowed */ + DBG1(DBG_ENC, "payload type %N not allowed", + payload_type_names, current_payload_type); + iterator->destroy(iterator); + return VERIFY_ERROR; + } + + /* check if the payload was encrypted, and if it should been have + * encrypted */ + if (payload_rule->encrypted != current_payload_was_encrypted) + { + /* payload was not encrypted, but should have been. + * or vice-versa */ + DBG1(DBG_ENC, "payload type %N should be %s!", + payload_type_names, current_payload_type, + (payload_rule->encrypted) ? "encrypted" : "not encrypted"); + iterator->destroy(iterator); + return VERIFY_ERROR; + } + } + /* advance to the next payload */ + payload_number++; + /* is stored to set next payload in case of found encryption payload */ + previous_payload = current_payload; + } + iterator->destroy(iterator); + return SUCCESS; +} + +/** + * Implementation of private_message_t.verify. + */ +static status_t verify(private_message_t *this) +{ + int i; + enumerator_t *enumerator; + payload_t *current_payload; + size_t total_found_payloads = 0; + + DBG2(DBG_ENC, "verifying message structure"); + + /* check for payloads with wrong count*/ + for (i = 0; i < this->message_rule->payload_rule_count; i++) + { + size_t found_payloads = 0; + payload_rule_t *rule; + + rule = &this->message_rule->payload_rules[i]; + enumerator = create_payload_enumerator(this); + + /* check all payloads for specific rule */ + while (enumerator->enumerate(enumerator, ¤t_payload)) + { + payload_type_t current_payload_type; + unknown_payload_t *unknown_payload; + + current_payload_type = current_payload->get_type(current_payload); + if (current_payload_type == UNKNOWN_PAYLOAD) + { + /* unknown payloads are ignored, IF they are not critical */ + unknown_payload = (unknown_payload_t*)current_payload; + if (unknown_payload->is_critical(unknown_payload)) + { + DBG1(DBG_ENC, "%N is not supported, but its critical!", + payload_type_names, current_payload_type); + enumerator->destroy(enumerator); + return NOT_SUPPORTED; + } + } + else if (current_payload_type == rule->payload_type) + { + found_payloads++; + total_found_payloads++; + DBG2(DBG_ENC, "found payload of type %N", payload_type_names, + rule->payload_type); + + /* as soon as ohe payload occures more then specified, + * the verification fails */ + if (found_payloads > + rule->max_occurence) + { + DBG1(DBG_ENC, "payload of type %N more than %d times (%d) " + "occured in current message", payload_type_names, + current_payload_type, rule->max_occurence, + found_payloads); + enumerator->destroy(enumerator); + return VERIFY_ERROR; + } + } + } + enumerator->destroy(enumerator); + + if (found_payloads < rule->min_occurence) + { + DBG1(DBG_ENC, "payload of type %N not occured %d times (%d)", + payload_type_names, rule->payload_type, rule->min_occurence, + found_payloads); + return VERIFY_ERROR; + } + if (rule->sufficient) + { + return SUCCESS; + } + } + return SUCCESS; +} + +/** + * Implementation of message_t.parse_body. + */ +static status_t parse_body(private_message_t *this, crypter_t *crypter, + signer_t *signer) +{ + status_t status = SUCCESS; + payload_type_t current_payload_type; + char str[256]; + + current_payload_type = this->first_payload; + + DBG2(DBG_ENC, "parsing body of message, first payload is %N", + payload_type_names, current_payload_type); + + /* parse payload for payload, while there are more available */ + while ((current_payload_type != NO_PAYLOAD)) + { + payload_t *current_payload; + + DBG2(DBG_ENC, "starting parsing a %N payload", + payload_type_names, current_payload_type); + + /* parse current payload */ + status = this->parser->parse_payload(this->parser, current_payload_type, + (payload_t**)¤t_payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "payload type %N could not be parsed", + payload_type_names, current_payload_type); + return PARSE_ERROR; + } + + DBG2(DBG_ENC, "verifying payload of type %N", + payload_type_names, current_payload_type); + + /* verify it, stop parsig if its invalid */ + status = current_payload->verify(current_payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "%N payload verification failed", + payload_type_names, current_payload_type); + current_payload->destroy(current_payload); + return VERIFY_ERROR; + } + + DBG2(DBG_ENC, "%N payload verified. Adding to payload list", + payload_type_names, current_payload_type); + this->payloads->insert_last(this->payloads,current_payload); + + /* an encryption payload is the last one, so STOP here. decryption is + * done later */ + if (current_payload_type == ENCRYPTED) + { + DBG2(DBG_ENC, "%N payload found. Stop parsing", + payload_type_names, current_payload_type); + break; + } + + /* get next payload type */ + current_payload_type = current_payload->get_next_type(current_payload); + } + + if (current_payload_type == ENCRYPTED) + { + status = decrypt_payloads(this,crypter,signer); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "could not decrypt payloads"); + return status; + } + } + + status = verify(this); + if (status != SUCCESS) + { + return status; + } + + DBG1(DBG_ENC, "parsed %s", get_string(this, str, sizeof(str))); + + return SUCCESS; +} + +/** + * Implementation of message_t.destroy. + */ +static void destroy (private_message_t *this) +{ + DESTROY_IF(this->ike_sa_id); + this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy)); + this->packet->destroy(this->packet); + this->parser->destroy(this->parser); + free(this); +} + +/* + * Described in Header-File + */ +message_t *message_create_from_packet(packet_t *packet) +{ + private_message_t *this = malloc_thing(private_message_t); + + /* public functions */ + this->public.set_major_version = (void(*)(message_t*, u_int8_t))set_major_version; + this->public.get_major_version = (u_int8_t(*)(message_t*))get_major_version; + this->public.set_minor_version = (void(*)(message_t*, u_int8_t))set_minor_version; + this->public.get_minor_version = (u_int8_t(*)(message_t*))get_minor_version; + this->public.set_message_id = (void(*)(message_t*, u_int32_t))set_message_id; + this->public.get_message_id = (u_int32_t(*)(message_t*))get_message_id; + this->public.get_initiator_spi = (u_int64_t(*)(message_t*))get_initiator_spi; + this->public.get_responder_spi = (u_int64_t(*)(message_t*))get_responder_spi; + this->public.set_ike_sa_id = (void(*)(message_t*, ike_sa_id_t *))set_ike_sa_id; + this->public.get_ike_sa_id = (ike_sa_id_t*(*)(message_t*))get_ike_sa_id; + this->public.set_exchange_type = (void(*)(message_t*, exchange_type_t))set_exchange_type; + this->public.get_exchange_type = (exchange_type_t(*)(message_t*))get_exchange_type; + this->public.get_first_payload_type = (payload_type_t(*)(message_t*))get_first_payload_type; + this->public.set_request = (void(*)(message_t*, bool))set_request; + this->public.get_request = (bool(*)(message_t*))get_request; + this->public.add_payload = (void(*)(message_t*,payload_t*))add_payload; + this->public.add_notify = (void(*)(message_t*,bool,notify_type_t,chunk_t))add_notify; + this->public.generate = (status_t (*) (message_t *,crypter_t*,signer_t*,packet_t**)) generate; + this->public.set_source = (void (*) (message_t*,host_t*)) set_source; + this->public.get_source = (host_t * (*) (message_t*)) get_source; + this->public.set_destination = (void (*) (message_t*,host_t*)) set_destination; + this->public.get_destination = (host_t * (*) (message_t*)) get_destination; + this->public.create_payload_enumerator = (enumerator_t * (*) (message_t *)) create_payload_enumerator; + this->public.get_payload = (payload_t * (*) (message_t *, payload_type_t)) get_payload; + this->public.get_notify = (notify_payload_t*(*)(message_t*, notify_type_t type))get_notify; + this->public.parse_header = (status_t (*) (message_t *)) parse_header; + this->public.parse_body = (status_t (*) (message_t *,crypter_t*,signer_t*)) parse_body; + this->public.get_packet = (packet_t * (*) (message_t*)) get_packet; + this->public.get_packet_data = (chunk_t (*) (message_t *this)) get_packet_data; + this->public.destroy = (void(*)(message_t*))destroy; + + /* private values */ + this->exchange_type = EXCHANGE_TYPE_UNDEFINED; + this->is_request = TRUE; + this->ike_sa_id = NULL; + this->first_payload = NO_PAYLOAD; + this->message_id = 0; + + /* private values */ + if (packet == NULL) + { + packet = packet_create(); + } + this->message_rule = NULL; + this->packet = packet; + this->payloads = linked_list_create(); + + /* parser is created from data of packet */ + this->parser = parser_create(this->packet->get_data(this->packet)); + + return (&this->public); +} + +/* + * Described in Header. + */ +message_t *message_create() +{ + return message_create_from_packet(NULL); +} + diff --git a/src/libcharon/encoding/message.h b/src/libcharon/encoding/message.h new file mode 100644 index 000000000..2c7718f49 --- /dev/null +++ b/src/libcharon/encoding/message.h @@ -0,0 +1,359 @@ +/* + * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2006 Daniel Roethlisberger + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 message message + * @{ @ingroup encoding + */ + +#ifndef MESSAGE_H_ +#define MESSAGE_H_ + +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 <utils/linked_list.h> +#include <crypto/crypters/crypter.h> +#include <crypto/signers/signer.h> + +/** + * This class is used to represent an IKEv2-Message. + * + * The message handles parsing and generation of payloads + * via parser_t/generator_t. Encryption is done transparently + * via the encryption_payload_t. A set of rules for messages + * and payloads does check parsed messages. + */ +struct message_t { + + /** + * Sets the IKE major version of the message. + * + * @param major_version major version to set + */ + void (*set_major_version) (message_t *this,u_int8_t major_version); + + /** + * Gets the IKE major version of the message. + * + * @return major version of the message + */ + u_int8_t (*get_major_version) (message_t *this); + + /** + * Sets the IKE minor version of the message. + * + * @param minor_version minor version to set + */ + void (*set_minor_version) (message_t *this,u_int8_t minor_version); + + /** + * Gets the IKE minor version of the message. + * + * @return minor version of the message + */ + u_int8_t (*get_minor_version) (message_t *this); + + /** + * Sets the Message ID of the message. + * + * @param message_id message_id to set + */ + void (*set_message_id) (message_t *this,u_int32_t message_id); + + /** + * Gets the Message ID of the message. + * + * @return message_id type of the message + */ + u_int32_t (*get_message_id) (message_t *this); + + /** + * Gets the initiator SPI of the message. + * + * @return initiator spi of the message + */ + u_int64_t (*get_initiator_spi) (message_t *this); + + /** + * Gets the responder SPI of the message. + * + * @return responder spi of the message + */ + u_int64_t (*get_responder_spi) (message_t *this); + + /** + * Sets the IKE_SA ID of the message. + * + * ike_sa_id gets cloned. + * + * @param ike_sa_id ike_sa_id to set + */ + void (*set_ike_sa_id) (message_t *this, ike_sa_id_t * ike_sa_id); + + /** + * Gets the IKE_SA ID of the message. + * + * The ike_sa_id points to the message internal id, do not modify. + * + * @return ike_sa_id of message + */ + ike_sa_id_t *(*get_ike_sa_id) (message_t *this); + + /** + * Sets the exchange type of the message. + * + * @param exchange_type exchange_type to set + */ + void (*set_exchange_type) (message_t *this,exchange_type_t exchange_type); + + /** + * Gets the exchange type of the message. + * + * @return exchange type of the message + */ + exchange_type_t (*get_exchange_type) (message_t *this); + + /** + * Gets the payload type of the first payload. + * + * @return payload type of the first payload + */ + payload_type_t (*get_first_payload_type) (message_t *this); + + /** + * Sets the request flag. + * + * @param request TRUE if message is a request, FALSE if it is a reply + */ + void (*set_request) (message_t *this, bool request); + + /** + * Gets request flag. + * + * @return TRUE if message is a request, FALSE if it is a reply + */ + bool (*get_request) (message_t *this); + + /** + * Append a payload to the message. + * + * If the payload must be encrypted is not specified here. Encryption + * of payloads is evaluated via internal rules for the messages and + * is done before generation. The order of payloads may change, since + * all payloads to encrypt are added to the encryption payload, which is + * always the last one. + * + * @param payload payload to append + */ + void (*add_payload) (message_t *this, payload_t *payload); + + /** + * Build a notify payload and add it to the message. + * + * This is a helper method to create notify messages or add + * notify payload to messages. The flush parameter specifies if existing + * payloads should get removed before appending the notify. + * + * @param flush TRUE to remove existing payloads + * @param type type of the notify + * @param data a chunk of data to add to the notify, gets cloned + */ + void (*add_notify) (message_t *this, bool flush, notify_type_t type, + chunk_t data); + + /** + * Parses header of message. + * + * Begins parisng 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 + * - PARSE_ERROR if corrupted/invalid data found + * - FAILED if consistence check of header failed + */ + status_t (*parse_header) (message_t *this); + + /** + * Parses body of message. + * + * The body gets not only parsed, but rather it gets verified. + * All payloads are verified if they are allowed to exist in the message + * of this type and if their own structure is ok. + * If there are encrypted payloads, they get decrypted via the supplied + * crypter. Also the message integrity gets verified with the supplied + * signer. + * Crypter/signer can be omitted (by passing NULL) when no encryption + * payload is expected. + * + * @param crypter crypter to decrypt encryption payloads + * @param signer signer to verifiy a message with an encryption payload + * @return + * - SUCCESS if parsing successful + * - NOT_SUPPORTED if ciritcal unknown payloads found + * - NOT_SUPPORTED if message type is not supported! + * - PARSE_ERROR if message parsing failed + * - VERIFY_ERROR if message verification failed (bad syntax) + * - FAILED if integrity check failed + * - INVALID_STATE if crypter/signer not supplied, but needed + */ + status_t (*parse_body) (message_t *this, crypter_t *crypter, signer_t *signer); + + /** + * Generates the UDP packet of specific message. + * + * Payloads which must be encrypted are generated first and added to + * an encryption payload. This encryption payload will get encrypted via + * the supplied crypter. Then all other payloads and the header get generated. + * After that, the checksum is added to the encryption payload over the full + * message. + * Crypter/signer can be omitted (by passing NULL) when no encryption + * payload is expected. + * Generation is only done once, multiple calls will just return a packet copy. + * + * @param crypter crypter to use when a payload must be encrypted + * @param signer signer to build a mac + * @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 crypter/signer not supplied but needed. + */ + status_t (*generate) (message_t *this, crypter_t *crypter, signer_t *signer, packet_t **packet); + + /** + * Gets the source host informations. + * + * @warning Returned host_t object is not getting cloned, + * do not destroy nor modify. + * + * @return host_t object representing source host + */ + host_t * (*get_source) (message_t *this); + + /** + * 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. + * + * @param host host_t object representing source host + */ + void (*set_source) (message_t *this, host_t *host); + + /** + * Gets the destination host informations. + * + * @warning Returned host_t object is not getting cloned, + * do not destroy nor modify. + * + * @return host_t object representing destination host + */ + host_t * (*get_destination) (message_t *this); + + /** + * 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. + * + * @param host host_t object representing destination host + */ + void (*set_destination) (message_t *this, host_t *host); + + /** + * Create an enumerator over all payloads. + * + * @return enumerator over payload_t + */ + enumerator_t * (*create_payload_enumerator) (message_t *this); + + /** + * Find a payload of a specific type. + * + * Returns the first occurance. + * + * @param type type of the payload to find + * @return payload, or NULL if no such payload found + */ + payload_t* (*get_payload) (message_t *this, payload_type_t type); + + /** + * Get the first notify payload of a specific type. + * + * @param type type of notification payload + * @return notify payload, NULL if no such notify found + */ + notify_payload_t* (*get_notify)(message_t *this, notify_type_t type); + + /** + * Returns a clone of the internal stored packet_t object. + * + * @return packet_t object as clone of internal one + */ + packet_t * (*get_packet) (message_t *this); + + /** + * Returns a clone of the internal stored packet_t data. + * + * @return clone of the internal stored packet_t data. + */ + chunk_t (*get_packet_data) (message_t *this); + + /** + * Destroys a message and all including objects. + */ + void (*destroy) (message_t *this); +}; + +/** + * Creates an message_t object from a incoming UDP Packet. + * + * @warning the given packet_t object is not copied and gets + * destroyed in message_t's destroy call. + * + * - exchange_type is set to NOT_SET + * - original_initiator is set to TRUE + * - is_request is set to TRUE + * Call message_t.parse_header afterwards. + * + * @param packet packet_t object which is assigned to message + * @return message_t object + */ +message_t * message_create_from_packet(packet_t *packet); + + +/** + * Creates an empty message_t object. + * + * - exchange_type is set to NOT_SET + * - original_initiator is set to TRUE + * - is_request is set to TRUE + * + * @return message_t object + */ +message_t * message_create(void); + +#endif /** MESSAGE_H_ @}*/ diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c new file mode 100644 index 000000000..9aa34b1bc --- /dev/null +++ b/src/libcharon/encoding/parser.c @@ -0,0 +1,862 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 <stdlib.h> +#include <arpa/inet.h> +#include <string.h> + +#include "parser.h" + +#include <library.h> +#include <daemon.h> +#include <utils/linked_list.h> +#include <encoding/payloads/encodings.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/sa_payload.h> +#include <encoding/payloads/proposal_substructure.h> +#include <encoding/payloads/transform_substructure.h> +#include <encoding/payloads/transform_attribute.h> +#include <encoding/payloads/ke_payload.h> +#include <encoding/payloads/nonce_payload.h> +#include <encoding/payloads/id_payload.h> +#include <encoding/payloads/notify_payload.h> +#include <encoding/payloads/encryption_payload.h> +#include <encoding/payloads/auth_payload.h> +#include <encoding/payloads/cert_payload.h> +#include <encoding/payloads/certreq_payload.h> +#include <encoding/payloads/ts_payload.h> +#include <encoding/payloads/delete_payload.h> +#include <encoding/payloads/vendor_id_payload.h> +#include <encoding/payloads/cp_payload.h> +#include <encoding/payloads/configuration_attribute.h> +#include <encoding/payloads/eap_payload.h> +#include <encoding/payloads/unknown_payload.h> + + +typedef struct private_parser_t private_parser_t; + +/** + * Private data stored in a context. + * + * Contains pointers and counters to store current state. + */ +struct private_parser_t { + /** + * Public members, see parser_t. + */ + parser_t public; + + /** + * Current bit for reading in input data. + */ + u_int8_t bit_pos; + + /** + * Current byte for reading in input data. + */ + u_int8_t *byte_pos; + + /** + * Input data to parse. + */ + u_int8_t *input; + + /** + * Roof of input, used for length-checking. + */ + u_int8_t *input_roof; + + /** + * Set of encoding rules for this parsing session. + */ + encoding_rule_t *rules; +}; + +/** + * Forward declaration + */ +static status_t parse_payload(private_parser_t *this, + payload_type_t payload_type, payload_t **payload); + +/** + * Log invalid length error + */ +static bool short_input(private_parser_t *this, int number) +{ + DBG1(DBG_ENC, " not enough input to parse rule %d %N", + number, encoding_type_names, this->rules[number].type); + return FALSE; +} + +/** + * Log unaligned rules + */ +static bool bad_bitpos(private_parser_t *this, int number) +{ + DBG1(DBG_ENC, " found rule %d %N on bitpos %d", + number, encoding_type_names, this->rules[number].type, this->bit_pos); + return FALSE; +} + +/** + * Parse a 4-Bit unsigned integer from the current parsing position. + */ +static bool parse_uint4(private_parser_t *this, int rule_number, + u_int8_t *output_pos) +{ + if (this->byte_pos + sizeof(u_int8_t) > this->input_roof) + { + return short_input(this, rule_number); + } + switch (this->bit_pos) + { + case 0: + if (output_pos) + { + *output_pos = *(this->byte_pos) >> 4; + } + this->bit_pos = 4; + break; + case 4: + if (output_pos) + { + *output_pos = *(this->byte_pos) & 0x0F; + } + this->bit_pos = 0; + this->byte_pos++; + break; + default: + return bad_bitpos(this, rule_number); + } + if (output_pos) + { + DBG3(DBG_ENC, " => %d", *output_pos); + } + return TRUE; +} + +/** + * Parse a 8-Bit unsigned integer from the current parsing position. + */ +static bool parse_uint8(private_parser_t *this, int rule_number, + u_int8_t *output_pos) +{ + if (this->byte_pos + sizeof(u_int8_t) > this->input_roof) + { + return short_input(this, rule_number); + } + if (this->bit_pos) + { + return bad_bitpos(this, rule_number); + } + if (output_pos) + { + *output_pos = *(this->byte_pos); + DBG3(DBG_ENC, " => %d", *output_pos); + } + this->byte_pos++; + return TRUE; +} + +/** + * Parse a 15-Bit unsigned integer from the current parsing position. + */ +static bool parse_uint15(private_parser_t *this, int rule_number, + u_int16_t *output_pos) +{ + if (this->byte_pos + sizeof(u_int16_t) > this->input_roof) + { + return short_input(this, rule_number); + } + if (this->bit_pos != 1) + { + return bad_bitpos(this, rule_number); + } + if (output_pos) + { + memcpy(output_pos, this->byte_pos, sizeof(u_int16_t)); + *output_pos = ntohs(*output_pos) & ~0x8000; + DBG3(DBG_ENC, " => %d", *output_pos); + } + this->byte_pos += sizeof(u_int16_t); + this->bit_pos = 0; + return TRUE; +} + +/** + * Parse a 16-Bit unsigned integer from the current parsing position. + */ +static bool parse_uint16(private_parser_t *this, int rule_number, + u_int16_t *output_pos) +{ + if (this->byte_pos + sizeof(u_int16_t) > this->input_roof) + { + return short_input(this, rule_number); + } + if (this->bit_pos) + { + return bad_bitpos(this, rule_number); + } + if (output_pos) + { + memcpy(output_pos, this->byte_pos, sizeof(u_int16_t)); + *output_pos = ntohs(*output_pos); + DBG3(DBG_ENC, " => %d", *output_pos); + } + this->byte_pos += sizeof(u_int16_t); + return TRUE; +} +/** + * Parse a 32-Bit unsigned integer from the current parsing position. + */ +static bool parse_uint32(private_parser_t *this, int rule_number, + u_int32_t *output_pos) +{ + if (this->byte_pos + sizeof(u_int32_t) > this->input_roof) + { + return short_input(this, rule_number); + } + if (this->bit_pos) + { + return bad_bitpos(this, rule_number); + } + if (output_pos) + { + memcpy(output_pos, this->byte_pos, sizeof(u_int32_t)); + *output_pos = ntohl(*output_pos); + DBG3(DBG_ENC, " => %d", *output_pos); + } + this->byte_pos += sizeof(u_int32_t); + return TRUE; +} + +/** + * Parse a given amount of bytes and writes them to a specific location + */ +static bool parse_bytes(private_parser_t *this, int rule_number, + u_int8_t *output_pos, int bytes) +{ + if (this->byte_pos + bytes > this->input_roof) + { + return short_input(this, rule_number); + } + if (this->bit_pos) + { + return bad_bitpos(this, rule_number); + } + if (output_pos) + { + memcpy(output_pos, this->byte_pos, bytes); + DBG3(DBG_ENC, " => %b", output_pos, bytes); + } + this->byte_pos += bytes; + return TRUE; +} + +/** + * Parse a single Bit from the current parsing position + */ +static bool parse_bit(private_parser_t *this, int rule_number, + bool *output_pos) +{ + if (this->byte_pos + sizeof(u_int8_t) > this->input_roof) + { + return short_input(this, rule_number); + } + if (output_pos) + { + u_int8_t mask; + mask = 0x01 << (7 - this->bit_pos); + *output_pos = *this->byte_pos & mask; + + if (*output_pos) + { /* set to a "clean", comparable true */ + *output_pos = TRUE; + } + DBG3(DBG_ENC, " => %d", *output_pos); + } + this->bit_pos = (this->bit_pos + 1) % 8; + if (this->bit_pos == 0) + { + this->byte_pos++; + } + return TRUE; +} + +/** + * Parse substructures in a list. + */ +static bool parse_list(private_parser_t *this, int rule_number, + linked_list_t **output_pos, payload_type_t payload_type, int length) +{ + linked_list_t *list = *output_pos; + + if (length < 0) + { + return short_input(this, rule_number); + } + if (this->bit_pos) + { + return bad_bitpos(this, rule_number); + } + while (length > 0) + { + u_int8_t *pos_before = this->byte_pos; + payload_t *payload; + + DBG2(DBG_ENC, " %d bytes left, parsing recursively %N", + length, payload_type_names, payload_type); + + if (parse_payload(this, payload_type, &payload) != SUCCESS) + { + DBG1(DBG_ENC, " parsing of a %N substructure failed", + payload_type_names, payload_type); + return FALSE; + } + list->insert_last(list, payload); + length -= this->byte_pos - pos_before; + } + if (length != 0) + { /* must yield exactly to zero */ + DBG1(DBG_ENC, " length of %N substructure list invalid", + payload_type_names, payload_type); + return FALSE; + } + *output_pos = list; + return TRUE; +} + +/** + * Parse data from current parsing position in a chunk. + */ +static bool parse_chunk(private_parser_t *this, int rule_number, + chunk_t *output_pos, int length) +{ + if (this->byte_pos + length > this->input_roof) + { + return short_input(this, rule_number); + } + if (this->bit_pos) + { + return bad_bitpos(this, rule_number); + } + if (output_pos) + { + *output_pos = chunk_alloc(length); + memcpy(output_pos->ptr, this->byte_pos, length); + DBG3(DBG_ENC, " => %b", output_pos->ptr, length); + } + this->byte_pos += length; + return TRUE; +} + +/** + * Implementation of parser_t.parse_payload. + */ +static status_t parse_payload(private_parser_t *this, + payload_type_t payload_type, payload_t **payload) +{ + payload_t *pld; + void *output; + size_t rule_count; + int payload_length = 0, spi_size = 0, attribute_length = 0; + u_int16_t ts_type = 0; + bool attribute_format = FALSE; + int rule_number; + encoding_rule_t *rule; + + /* create instance of the payload to parse */ + pld = payload_create(payload_type); + + DBG2(DBG_ENC, "parsing %N payload, %d bytes left", + payload_type_names, payload_type, this->input_roof - this->byte_pos); + + DBG3(DBG_ENC, "parsing payload from %b", + this->byte_pos, this->input_roof - this->byte_pos); + + if (pld->get_type(pld) == UNKNOWN_PAYLOAD) + { + DBG1(DBG_ENC, " payload type %d is unknown, handling as %N", + payload_type, payload_type_names, UNKNOWN_PAYLOAD); + } + + /* 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); + for (rule_number = 0; rule_number < rule_count; rule_number++) + { + rule = &(this->rules[rule_number]); + DBG2(DBG_ENC, " parsing rule %d %N", + rule_number, encoding_type_names, rule->type); + switch (rule->type) + { + case U_INT_4: + { + if (!parse_uint4(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case U_INT_8: + { + if (!parse_uint8(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case U_INT_16: + { + if (!parse_uint16(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case U_INT_32: + { + if (!parse_uint32(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case IKE_SPI: + { + if (!parse_bytes(this, rule_number, output + rule->offset, 8)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case RESERVED_BIT: + { + if (!parse_bit(this, rule_number, NULL)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case RESERVED_BYTE: + { + if (!parse_uint8(this, rule_number, NULL)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case FLAG: + { + if (!parse_bit(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case PAYLOAD_LENGTH: + { + if (!parse_uint16(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + /* parsed u_int16 should be aligned */ + payload_length = *(u_int16_t*)(output + rule->offset); + if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case HEADER_LENGTH: + { + if (!parse_uint32(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case SPI_SIZE: + { + if (!parse_uint8(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + spi_size = *(u_int8_t*)(output + rule->offset); + break; + } + case SPI: + { + if (!parse_chunk(this, rule_number, output + rule->offset, + spi_size)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case PROPOSALS: + { + if (payload_length < SA_PAYLOAD_HEADER_LENGTH || + !parse_list(this, rule_number, output + rule->offset, + PROPOSAL_SUBSTRUCTURE, + payload_length - SA_PAYLOAD_HEADER_LENGTH)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case TRANSFORMS: + { + 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)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case CONFIGURATION_ATTRIBUTES: + { + if (payload_length < CP_PAYLOAD_HEADER_LENGTH || + !parse_list(this, rule_number, output + rule->offset, + CONFIGURATION_ATTRIBUTE, + payload_length - CP_PAYLOAD_HEADER_LENGTH)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case ATTRIBUTE_FORMAT: + { + if (!parse_bit(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + attribute_format = *(bool*)(output + rule->offset); + break; + } + case ATTRIBUTE_TYPE: + { + if (!parse_uint15(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case CONFIGURATION_ATTRIBUTE_LENGTH: + { + if (!parse_uint16(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + attribute_length = *(u_int16_t*)(output + rule->offset); + break; + } + case ATTRIBUTE_LENGTH_OR_VALUE: + { + if (!parse_uint16(this, rule_number, output + rule->offset)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + attribute_length = *(u_int16_t*)(output + rule->offset); + break; + } + case ATTRIBUTE_VALUE: + { + if (attribute_format == FALSE && + !parse_chunk(this, rule_number, output + rule->offset, + attribute_length)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + 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)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + ts_type = *(u_int8_t*)(output + rule->offset); + break; + } + case ADDRESS: + { + int address_length = (ts_type == TS_IPV4_ADDR_RANGE) ? 4 : 16; + + if (!parse_chunk(this, rule_number, output + rule->offset, + address_length)) + { + pld->destroy(pld); + return PARSE_ERROR; + } + 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", + rule_number, encoding_type_names, rule->type); + pld->destroy(pld); + return PARSE_ERROR; + } + } + /* process next rulue */ + rule++; + } + + *payload = pld; + DBG2(DBG_ENC, "parsing %N payload finished", + payload_type_names, payload_type); + return SUCCESS; +} + +/** + * Implementation of parser_t.get_remaining_byte_count. + */ +static int get_remaining_byte_count (private_parser_t *this) +{ + return this->input_roof - this->byte_pos; +} + +/** + * Implementation of parser_t.reset_context. + */ +static void reset_context (private_parser_t *this) +{ + this->byte_pos = this->input; + this->bit_pos = 0; +} + +/** + * Implementation of parser_t.destroy. + */ +static void destroy(private_parser_t *this) +{ + free(this); +} + +/* + * Described in header. + */ +parser_t *parser_create(chunk_t data) +{ + private_parser_t *this = malloc_thing(private_parser_t); + + this->public.parse_payload = (status_t(*)(parser_t*,payload_type_t,payload_t**))parse_payload; + this->public.reset_context = (void(*)(parser_t*)) reset_context; + this->public.get_remaining_byte_count = (int (*) (parser_t *))get_remaining_byte_count; + this->public.destroy = (void(*)(parser_t*)) destroy; + + this->input = data.ptr; + this->byte_pos = data.ptr; + this->bit_pos = 0; + this->input_roof = data.ptr + data.len; + + return &this->public; +} + diff --git a/src/libcharon/encoding/parser.h b/src/libcharon/encoding/parser.h new file mode 100644 index 000000000..27c5f03fe --- /dev/null +++ b/src/libcharon/encoding/parser.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 parser parser + * @{ @ingroup encoding + */ + +#ifndef PARSER_H_ +#define PARSER_H_ + +typedef struct parser_t parser_t; + +#include <library.h> +#include <encoding/payloads/encodings.h> +#include <encoding/payloads/payload.h> + +/** + * A parser_t class to parse IKEv2 payloads. + * + * A parser is used for parsing one chunk of data. Multiple + * payloads can be parsed out of the chunk using parse_payload. + * The parser remains the state until destroyed. + */ +struct parser_t { + + /** + * Parses the next payload. + * + * @warning Caller is responsible for freeing allocated payload. + * + * Rules for parsing are described in the payload definition. + * + * @param payload_type payload type to parse + * @param payload pointer where parsed payload was allocated + * @return + * - SUCCESSFUL if succeeded, + * - PARSE_ERROR if corrupted/invalid data found + */ + status_t (*parse_payload) (parser_t *this, payload_type_t payload_type, payload_t **payload); + + /** + * Gets the remaining byte count which is not currently parsed. + */ + int (*get_remaining_byte_count) (parser_t *this); + + /** + * Resets the current parser context. + */ + void (*reset_context) (parser_t *this); + + /** + * Destroys a parser_t object. + */ + void (*destroy) (parser_t *this); +}; + +/** + * Constructor to create a parser_t object. + * + * @param data chunk of data to parse with this parser_t object + * @return parser_t object + */ +parser_t *parser_create(chunk_t data); + +#endif /** PARSER_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/auth_payload.c b/src/libcharon/encoding/payloads/auth_payload.c new file mode 100644 index 000000000..d31208abb --- /dev/null +++ b/src/libcharon/encoding/payloads/auth_payload.c @@ -0,0 +1,259 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "auth_payload.h" + +#include <encoding/payloads/encodings.h> + + +typedef struct private_auth_payload_t private_auth_payload_t; + +/** + * Private data of an auth_payload_t object. + * + */ +struct private_auth_payload_t { + + /** + * Public auth_payload_t interface. + */ + auth_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Method of the AUTH Data. + */ + u_int8_t auth_method; + + /** + * The contained auth data value. + */ + chunk_t auth_data; +}; + +/** + * Encoding rules to parse or generate a AUTH payload + * + * The defined offsets are the positions in a object of type + * private_auth_payload_t. + */ +encoding_rule_t auth_payload_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 */ + { FLAG, offsetof(private_auth_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_auth_payload_t, payload_length)}, + /* 1 Byte AUTH type*/ + { U_INT_8, offsetof(private_auth_payload_t, auth_method) }, + /* 3 reserved bytes */ + { RESERVED_BYTE, 0 }, + { RESERVED_BYTE, 0 }, + { RESERVED_BYTE, 0 }, + /* some auth data bytes, length is defined in PAYLOAD_LENGTH */ + { AUTH_DATA, offsetof(private_auth_payload_t, auth_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 !C! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Auth Method ! RESERVED ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Authentication Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_auth_payload_t *this) +{ + if (this->auth_method == 0 || + (this->auth_method >= 4 && this->auth_method <= 8) || + (this->auth_method >= 12 && this->auth_method <= 200)) + { + /* reserved IDs */ + return FAILED; + } + return SUCCESS; +} + +/** + * Implementation of auth_payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_auth_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = auth_payload_encodings; + *rule_count = sizeof(auth_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_payload_type(private_auth_payload_t *this) +{ + return AUTHENTICATION; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_auth_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_auth_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_auth_payload_t *this) +{ + return this->payload_length; +} + +/** + * Implementation of auth_payload_t.set_auth_method. + */ +static void set_auth_method (private_auth_payload_t *this, auth_method_t method) +{ + this->auth_method = method; +} + +/** + * Implementation of auth_payload_t.get_auth_method. + */ +static auth_method_t get_auth_method (private_auth_payload_t *this) +{ + return (this->auth_method); +} + +/** + * Implementation of auth_payload_t.set_data. + */ +static void set_data (private_auth_payload_t *this, chunk_t data) +{ + if (this->auth_data.ptr != NULL) + { + chunk_free(&(this->auth_data)); + } + this->auth_data.ptr = clalloc(data.ptr,data.len); + this->auth_data.len = data.len; + this->payload_length = AUTH_PAYLOAD_HEADER_LENGTH + this->auth_data.len; +} + +/** + * Implementation of auth_payload_t.get_data. + */ +static chunk_t get_data (private_auth_payload_t *this) +{ + return (this->auth_data); +} + +/** + * Implementation of auth_payload_t.get_data_clone. + */ +static chunk_t get_data_clone (private_auth_payload_t *this) +{ + chunk_t cloned_data; + if (this->auth_data.ptr == NULL) + { + return (this->auth_data); + } + cloned_data.ptr = clalloc(this->auth_data.ptr,this->auth_data.len); + cloned_data.len = this->auth_data.len; + return cloned_data; +} + +/** + * Implementation of payload_t.destroy and auth_payload_t.destroy. + */ +static void destroy(private_auth_payload_t *this) +{ + if (this->auth_data.ptr != NULL) + { + chunk_free(&(this->auth_data)); + } + + free(this); +} + +/* + * Described in header + */ +auth_payload_t *auth_payload_create() +{ + private_auth_payload_t *this = malloc_thing(private_auth_payload_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.destroy = (void (*) (auth_payload_t *)) destroy; + this->public.set_auth_method = (void (*) (auth_payload_t *,auth_method_t)) set_auth_method; + this->public.get_auth_method = (auth_method_t (*) (auth_payload_t *)) get_auth_method; + this->public.set_data = (void (*) (auth_payload_t *,chunk_t)) set_data; + this->public.get_data_clone = (chunk_t (*) (auth_payload_t *)) get_data_clone; + this->public.get_data = (chunk_t (*) (auth_payload_t *)) get_data; + + /* private variables */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length =AUTH_PAYLOAD_HEADER_LENGTH; + this->auth_data = chunk_empty; + + return (&(this->public)); +} diff --git a/src/libcharon/encoding/payloads/auth_payload.h b/src/libcharon/encoding/payloads/auth_payload.h new file mode 100644 index 000000000..37ee149db --- /dev/null +++ b/src/libcharon/encoding/payloads/auth_payload.h @@ -0,0 +1,102 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 auth_payload auth_payload + * @{ @ingroup payloads + */ + +#ifndef AUTH_PAYLOAD_H_ +#define AUTH_PAYLOAD_H_ + +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 + +/** + * Class representing an IKEv2 AUTH payload. + * + * The AUTH payload format is described in RFC section 3.8. + */ +struct auth_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Set the AUTH method. + * + * @param method auth_method_t to use + */ + void (*set_auth_method) (auth_payload_t *this, auth_method_t method); + + /** + * Get the AUTH method. + * + * @return auth_method_t used + */ + auth_method_t (*get_auth_method) (auth_payload_t *this); + + /** + * Set the AUTH data. + * + * Data gets cloned. + * + * @param data AUTH data as chunk_t + */ + void (*set_data) (auth_payload_t *this, chunk_t data); + + /** + * Get the AUTH data. + * + * Returned data are a copy of the internal one. + * + * @return AUTH data as chunk_t + */ + chunk_t (*get_data_clone) (auth_payload_t *this); + + /** + * Get the AUTH data. + * + * Returned data are NOT copied + * + * @return AUTH data as chunk_t + */ + chunk_t (*get_data) (auth_payload_t *this); + + /** + * Destroys an auth_payload_t object. + */ + void (*destroy) (auth_payload_t *this); +}; + +/** + * Creates an empty auth_payload_t object. + * + * @return auth_payload_t object + */ +auth_payload_t *auth_payload_create(void); + +#endif /** AUTH_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c new file mode 100644 index 000000000..6dd3141f0 --- /dev/null +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 <ctype.h> + +#include <daemon.h> + +#include "cert_payload.h" + +ENUM(cert_encoding_names, ENC_PKCS7_WRAPPED_X509, ENC_OCSP_CONTENT, + "ENC_PKCS7_WRAPPED_X509", + "ENC_PGP", + "ENC_DNS_SIGNED_KEY", + "ENC_X509_SIGNATURE", + "ENC_X509_KEY_EXCHANGE", + "ENC_KERBEROS_TOKENS", + "ENC_CRL", + "ENC_ARL", + "ENC_SPKI", + "ENC_X509_ATTRIBUTE", + "ENC_RAW_RSA_KEY", + "ENC_X509_HASH_AND_URL", + "ENC_X509_HASH_AND_URL_BUNDLE", + "ENC_OCSP_CONTENT", +); + +typedef struct private_cert_payload_t private_cert_payload_t; + +/** + * Private data of an cert_payload_t object. + * + */ +struct private_cert_payload_t { + /** + * Public cert_payload_t interface. + */ + cert_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Encoding of the CERT Data. + */ + u_int8_t encoding; + + /** + * The contained cert data value. + */ + chunk_t data; + + /** + * TRUE if the "Hash and URL" data is invalid + */ + bool invalid_hash_and_url; +}; + +/** + * Encoding rules to parse or generate a CERT payload + * + * The defined offsets are the positions in a object of type + * private_cert_payload_t. + * + */ +encoding_rule_t cert_payload_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 */ + { FLAG, offsetof(private_cert_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_cert_payload_t, payload_length)}, + /* 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) } +}; + +/* + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Cert Encoding ! ! + +-+-+-+-+-+-+-+-+ ! + ~ Certificate Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_cert_payload_t *this) +{ + if (this->encoding == ENC_X509_HASH_AND_URL || + this->encoding == ENC_X509_HASH_AND_URL_BUNDLE) + { + /* coarse verification of "Hash and URL" encoded certificates */ + if (this->data.len <= 20) + { + DBG1(DBG_ENC, "invalid payload length for hash-and-url (%d), ignore", + this->data.len); + this->invalid_hash_and_url = TRUE; + return SUCCESS; + } + + int i = 20; /* skipping the hash */ + for (; i < this->data.len; ++i) + { + if (this->data.ptr[i] == '\0') + { + /* null terminated, fine */ + return SUCCESS; + } + else if (!isprint(this->data.ptr[i])) + { + DBG1(DBG_ENC, "non printable characters in url of hash-and-url" + " encoded certificate payload, ignore"); + this->invalid_hash_and_url = TRUE; + return SUCCESS; + } + } + + /* URL is not null terminated, correct that */ + chunk_t data = chunk_alloc(this->data.len + 1); + memcpy(data.ptr, this->data.ptr, this->data.len); + data.ptr[this->data.len] = '\0'; + chunk_free(&this->data); + this->data = data; + } + return SUCCESS; +} + +/** + * Implementation of cert_payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_cert_payload_t *this, + encoding_rule_t **rules, size_t *rule_count) +{ + *rules = cert_payload_encodings; + *rule_count = sizeof(cert_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_payload_type(private_cert_payload_t *this) +{ + return CERTIFICATE; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_cert_payload_t *this) +{ + return this->next_payload; +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_cert_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_cert_payload_t *this) +{ + return this->payload_length; +} + +/** + * Implementation of cert_payload_t.get_cert_encoding. + */ +static cert_encoding_t get_cert_encoding(private_cert_payload_t *this) +{ + return this->encoding; +} + +/** + * Implementation of cert_payload_t.get_cert. + */ +static certificate_t *get_cert(private_cert_payload_t *this) +{ + if (this->encoding != ENC_X509_SIGNATURE) + { + return NULL; + } + return lib->creds->create(lib->creds, CRED_CERTIFICATE, CERT_X509, + BUILD_BLOB_ASN1_DER, this->data, + BUILD_END); +} + +/** + * Implementation of cert_payload_t.get_hash. + */ +static chunk_t get_hash(private_cert_payload_t *this) +{ + chunk_t hash = chunk_empty; + if ((this->encoding != ENC_X509_HASH_AND_URL && + this->encoding != ENC_X509_HASH_AND_URL_BUNDLE) || + this->invalid_hash_and_url) + { + return hash; + } + hash.ptr = this->data.ptr; + hash.len = 20; + return hash; +} + +/** + * Implementation of cert_payload_t.get_url. + */ +static char *get_url(private_cert_payload_t *this) +{ + if ((this->encoding != ENC_X509_HASH_AND_URL && + this->encoding != ENC_X509_HASH_AND_URL_BUNDLE) || + this->invalid_hash_and_url) + { + return NULL; + } + return (char*)this->data.ptr + 20; +} + +/** + * Implementation of payload_t.destroy and cert_payload_t.destroy. + */ +static void destroy(private_cert_payload_t *this) +{ + chunk_free(&this->data); + free(this); +} + +/* + * Described in header + */ +cert_payload_t *cert_payload_create() +{ + private_cert_payload_t *this = malloc_thing(private_cert_payload_t); + + this->public.payload_interface.verify = (status_t (*) (payload_t*))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t*,encoding_rule_t**, size_t*))get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t*))get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t*))get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t*,payload_type_t))set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t*))get_payload_type; + this->public.payload_interface.destroy = (void (*) (payload_t*))destroy; + + this->public.destroy = (void (*) (cert_payload_t*))destroy; + this->public.get_cert = (certificate_t* (*) (cert_payload_t*))get_cert; + this->public.get_cert_encoding = (cert_encoding_t (*) (cert_payload_t*))get_cert_encoding; + this->public.get_hash = (chunk_t (*) (cert_payload_t*))get_hash; + this->public.get_url = (char* (*) (cert_payload_t*))get_url; + + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = CERT_PAYLOAD_HEADER_LENGTH; + this->data = chunk_empty; + this->encoding = 0; + this->invalid_hash_and_url = FALSE; + + return &this->public; +} + +/* + * Described in header + */ +cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) +{ + private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + + switch (cert->get_type(cert)) + { + case CERT_X509: + this->encoding = ENC_X509_SIGNATURE; + break; + default: + DBG1(DBG_ENC, "embedding %N certificate in payload failed", + certificate_type_names, cert->get_type(cert)); + free(this); + return NULL; + } + this->data = cert->get_encoding(cert); + this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + return &this->public; +} + +/* + * Described in header + */ +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(); + + 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; + return &this->public; +} + diff --git a/src/libcharon/encoding/payloads/cert_payload.h b/src/libcharon/encoding/payloads/cert_payload.h new file mode 100644 index 000000000..aa1c7bf5a --- /dev/null +++ b/src/libcharon/encoding/payloads/cert_payload.h @@ -0,0 +1,137 @@ +/* + * Copyright (C) 2008 Tobias Brunner + * Copyright (C) 2005-2007 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 cert_payload cert_payload + * @{ @ingroup payloads + */ + +#ifndef CERT_PAYLOAD_H_ +#define CERT_PAYLOAD_H_ + +typedef struct cert_payload_t cert_payload_t; +typedef enum cert_encoding_t cert_encoding_t; + +#include <library.h> +#include <credentials/certificates/certificate.h> +#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 { + ENC_PKCS7_WRAPPED_X509 = 1, + ENC_PGP = 2, + ENC_DNS_SIGNED_KEY = 3, + ENC_X509_SIGNATURE = 4, + ENC_KERBEROS_TOKEN = 6, + ENC_CRL = 7, + ENC_ARL = 8, + ENC_SPKI = 9, + ENC_X509_ATTRIBUTE = 10, + ENC_RAW_RSA_KEY = 11, + ENC_X509_HASH_AND_URL = 12, + ENC_X509_HASH_AND_URL_BUNDLE = 13, + ENC_OCSP_CONTENT = 14, /* from RFC 4806 */ +}; + +/** + * Enum names for 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. + */ +struct cert_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the playoads encoded certifcate. + * + * @return certifcate copy + */ + certificate_t *(*get_cert)(cert_payload_t *this); + + /** + * Get the encoding of the certificate. + * + * @return encoding + */ + cert_encoding_t (*get_cert_encoding)(cert_payload_t *this); + + /** + * Get the hash if this is a hash and URL encoded certificate. + * + * This function returns internal data, do not free. + * + * @return hash + */ + chunk_t (*get_hash)(cert_payload_t *this); + + /** + * Get the URL if this is a hash and URL encoded certificate. + * + * This function returns internal data, do not free. + * + * @return url + */ + char *(*get_url)(cert_payload_t *this); + + + /** + * Destroys the cert_payload object. + */ + void (*destroy) (cert_payload_t *this); +}; + +/** + * Creates an empty certificate payload. + * + * @return cert_payload_t object + */ +cert_payload_t *cert_payload_create(void); + +/** + * Creates a certificate payload with an embedded certificate. + * + * @param cert certificate to embed + * @return cert_payload_t object + */ +cert_payload_t *cert_payload_create_from_cert(certificate_t *cert); + +/** + * Creates a certificate payload with hash and URL encoding of a certificate. + * + * @param hash hash of the DER encoded certificate (get's cloned) + * @param url the URL to locate the certificate (get's cloned) + * @return cert_payload_t object + */ +cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url); + +#endif /** CERT_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c new file mode 100644 index 000000000..9ff0bdde0 --- /dev/null +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 <daemon.h> +#include <crypto/hashers/hasher.h> +#include <encoding/payloads/cert_payload.h> + +#include "certreq_payload.h" + + +typedef struct private_certreq_payload_t private_certreq_payload_t; + +/** + * Private data of an certreq_payload_t object. + * + */ +struct private_certreq_payload_t { + /** + * Public certreq_payload_t interface. + */ + certreq_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Encoding of the CERT Data. + */ + u_int8_t encoding; + + /** + * The contained certreq data value. + */ + chunk_t data; +}; + +/** + * 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_rule_t certreq_payload_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 */ + { FLAG, offsetof(private_certreq_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_certreq_payload_t, payload_length) }, + /* 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) } +}; + +/* + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Cert Encoding ! ! + +-+-+-+-+-+-+-+-+ ! + ~ Certification Authority ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_certreq_payload_t *this) +{ + if (this->encoding == ENC_X509_SIGNATURE) + { + if (this->data.len < HASH_SIZE_SHA1 || + this->data.len % HASH_SIZE_SHA1) + { + DBG1(DBG_ENC, "invalid X509 hash length (%d) in certreq", + this->data.len); + return FAILED; + } + } + return SUCCESS; +} + +/** + * Implementation of certreq_payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_certreq_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = certreq_payload_encodings; + *rule_count = sizeof(certreq_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_payload_type(private_certreq_payload_t *this) +{ + return CERTIFICATE_REQUEST; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_certreq_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_certreq_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_certreq_payload_t *this) +{ + return this->payload_length; +} + +/** + * Implementation of certreq_payload_t.add_keyid. + */ +static void add_keyid(private_certreq_payload_t *this, chunk_t keyid) +{ + this->data = chunk_cat("mc", this->data, keyid); + this->payload_length += keyid.len; +} + +typedef struct keyid_enumerator_t keyid_enumerator_t; + +/** + * enumerator to enumerate keyids + */ +struct keyid_enumerator_t { + enumerator_t public; + chunk_t full; + u_char *pos; +}; + +/** + * enumerate function for keyid_enumerator + */ +static bool keyid_enumerate(keyid_enumerator_t *this, chunk_t *chunk) +{ + if (this->pos == NULL) + { + this->pos = this->full.ptr; + } + else + { + this->pos += HASH_SIZE_SHA1; + if (this->pos > (this->full.ptr + this->full.len - HASH_SIZE_SHA1)) + { + this->pos = NULL; + } + } + if (this->pos) + { + chunk->ptr = this->pos; + chunk->len = HASH_SIZE_SHA1; + return TRUE; + } + return FALSE; +} + +/** + * Implementation of certreq_payload_t.create_keyid_enumerator. + */ +static enumerator_t* create_keyid_enumerator(private_certreq_payload_t *this) +{ + keyid_enumerator_t *enumerator = malloc_thing(keyid_enumerator_t); + enumerator->public.enumerate = (void*)keyid_enumerate; + enumerator->public.destroy = (void*)free; + enumerator->full = this->data; + enumerator->pos = NULL; + return &enumerator->public; +} + +/** + * Implementation of certreq_payload_t.get_cert_type. + */ +static certificate_type_t get_cert_type(private_certreq_payload_t *this) +{ + switch (this->encoding) + { + case ENC_X509_SIGNATURE: + return CERT_X509; + default: + return CERT_ANY; + } +} + +/** + * Implementation of payload_t.destroy and certreq_payload_t.destroy. + */ +static void destroy(private_certreq_payload_t *this) +{ + chunk_free(&this->data); + free(this); +} + +/* + * Described in header + */ +certreq_payload_t *certreq_payload_create() +{ + private_certreq_payload_t *this = malloc_thing(private_certreq_payload_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t*))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t*,encoding_rule_t**,size_t*))get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t*))get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t*))get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t*,payload_type_t))set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t*))get_payload_type; + this->public.payload_interface.destroy = (void (*) (payload_t*))destroy; + + /* public functions */ + this->public.destroy = (void (*) (certreq_payload_t*)) destroy; + this->public.create_keyid_enumerator = (enumerator_t*(*)(certreq_payload_t*))create_keyid_enumerator; + this->public.get_cert_type = (certificate_type_t(*)(certreq_payload_t*))get_cert_type; + this->public.add_keyid = (void(*)(certreq_payload_t*, chunk_t keyid))add_keyid; + + /* private variables */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = CERTREQ_PAYLOAD_HEADER_LENGTH; + this->data = chunk_empty; + this->encoding = 0; + + return &this->public; +} + +/* + * Described in header + */ +certreq_payload_t *certreq_payload_create_type(certificate_type_t type) +{ + private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create(); + + switch (type) + { + case CERT_X509: + this->encoding = ENC_X509_SIGNATURE; + break; + default: + DBG1(DBG_ENC, "certificate type %N not supported in requests", + certificate_type_names, type); + free(this); + return NULL; + } + return &this->public; +} + diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h new file mode 100644 index 000000000..914063628 --- /dev/null +++ b/src/libcharon/encoding/payloads/certreq_payload.h @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 certreq_payload certreq_payload + * @{ @ingroup payloads + */ + +#ifndef CERTREQ_PAYLOAD_H_ +#define CERTREQ_PAYLOAD_H_ + +typedef struct certreq_payload_t certreq_payload_t; + +#include <library.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/cert_payload.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. + */ +struct certreq_payload_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Create an enumerator over contained keyids. + * + * @return enumerator over chunk_t's. + */ + enumerator_t* (*create_keyid_enumerator)(certreq_payload_t *this); + + /** + * Get the type of contained certificate keyids. + * + * @return certificate keyid type + */ + certificate_type_t (*get_cert_type)(certreq_payload_t *this); + + /** + * Add a certificates keyid to the payload. + * + * @param keyid keyid of the trusted certifcate + * @return + */ + void (*add_keyid)(certreq_payload_t *this, chunk_t keyid); + + /** + * Destroys an certreq_payload_t object. + */ + void (*destroy) (certreq_payload_t *this); +}; + +/** + * Creates an empty certreq_payload_t object. + * + * @return certreq payload + */ +certreq_payload_t *certreq_payload_create(void); + +/** + * Creates an empty 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); + +#endif /** CERTREQ_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c new file mode 100644 index 000000000..9094fd44d --- /dev/null +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -0,0 +1,264 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "configuration_attribute.h" + +#include <encoding/payloads/encodings.h> +#include <library.h> +#include <daemon.h> + + +typedef struct private_configuration_attribute_t private_configuration_attribute_t; + +/** + * Private data of an configuration_attribute_t object. + * + */ +struct private_configuration_attribute_t { + /** + * Public configuration_attribute_t interface. + */ + configuration_attribute_t public; + + /** + * Type of the attribute. + */ + u_int16_t type; + + /** + * Length of the attribute. + */ + u_int16_t length; + + /** + * Attribute value as chunk. + */ + chunk_t value; +}; + +/** + * 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_rule_t configuration_attribute_encodings[] = { + + { RESERVED_BIT, 0 }, + /* type of the attribute as 15 bit unsigned integer */ + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, type) }, + /* Length of attribute value */ + { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length) }, + /* Value of attribute if attribute format flag is zero */ + { CONFIGURATION_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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + !R| Attribute Type ! Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + ~ Value ~ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(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) + { + 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) + { + failed = TRUE; + } + break; + case INTERNAL_IP4_SUBNET: + if (this->length != 0 && this->length != 8) + { + failed = TRUE; + } + break; + case INTERNAL_IP6_ADDRESS: + case INTERNAL_IP6_SUBNET: + if (this->length != 0 && this->length != 17) + { + failed = TRUE; + } + break; + case INTERNAL_IP6_DNS: + case INTERNAL_IP6_NBNS: + case INTERNAL_IP6_DHCP: + if (this->length != 0 && this->length != 16) + { + failed = TRUE; + } + break; + case SUPPORTED_ATTRIBUTES: + if (this->length % 2) + { + failed = TRUE; + } + break; + case APPLICATION_VERSION: + /* any length acceptable */ + break; + default: + DBG1(DBG_ENC, "unknown attribute type %N", + configuration_attribute_type_names, this->type); + break; + } + + if (failed) + { + DBG1(DBG_ENC, "invalid attribute length %d for %N", + this->length, configuration_attribute_type_names, this->type); + return FAILED; + } + return SUCCESS; +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_configuration_attribute_t *this, + encoding_rule_t **rules, size_t *rule_count) +{ + *rules = configuration_attribute_encodings; + *rule_count = sizeof(configuration_attribute_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_configuration_attribute_t *this) +{ + return CONFIGURATION_ATTRIBUTE; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_configuration_attribute_t *this) +{ + return NO_PAYLOAD; +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_configuration_attribute_t *this, + payload_type_t type) +{ +} + +/** + * Implementation of configuration_attribute_t.get_length. + */ +static size_t get_length(private_configuration_attribute_t *this) +{ + return this->value.len + CONFIGURATION_ATTRIBUTE_HEADER_LENGTH; +} + +/** + * Implementation of configuration_attribute_t.get_type. + */ +static configuration_attribute_type_t get_configuration_attribute_type( + private_configuration_attribute_t *this) +{ + return this->type; +} + +/** + * Implementation of configuration_attribute_t.get_value. + */ +static chunk_t get_value(private_configuration_attribute_t *this) +{ + return this->value; +} + +/** + * Implementation of configuration_attribute_t.destroy and payload_t.destroy. + */ +static void destroy(private_configuration_attribute_t *this) +{ + free(this->value.ptr); + free(this); +} + +/* + * Described in header. + */ +configuration_attribute_t *configuration_attribute_create() +{ + private_configuration_attribute_t *this; + + this = malloc_thing(private_configuration_attribute_t); + this->public.payload_interface.verify = (status_t(*)(payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void(*)(payload_t *, encoding_rule_t **, size_t *) )get_encoding_rules; + this->public.payload_interface.get_length = (size_t(*)(payload_t *))get_length; + this->public.payload_interface.get_next_type = (payload_type_t(*)(payload_t *))get_next_type; + this->public.payload_interface.set_next_type = (void(*)(payload_t *,payload_type_t))set_next_type; + this->public.payload_interface.get_type = (payload_type_t(*)(payload_t *))get_type; + this->public.payload_interface.destroy = (void(*)(payload_t*))destroy; + + this->public.get_value = (chunk_t(*)(configuration_attribute_t *))get_value; + this->public.get_type = (configuration_attribute_type_t(*)(configuration_attribute_t *))get_configuration_attribute_type; + this->public.destroy = (void (*)(configuration_attribute_t*))destroy; + + this->type = 0; + this->value = chunk_empty; + this->length = 0; + + return &this->public; +} + +/* + * Described in header. + */ +configuration_attribute_t *configuration_attribute_create_value( + configuration_attribute_type_t type, chunk_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; + + return &this->public; +} + diff --git a/src/libcharon/encoding/payloads/configuration_attribute.h b/src/libcharon/encoding/payloads/configuration_attribute.h new file mode 100644 index 000000000..6e4b018bb --- /dev/null +++ b/src/libcharon/encoding/payloads/configuration_attribute.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 configuration_attribute configuration_attribute + * @{ @ingroup payloads + */ + +#ifndef CONFIGURATION_ATTRIBUTE_H_ +#define CONFIGURATION_ATTRIBUTE_H_ + +typedef struct configuration_attribute_t configuration_attribute_t; + +#include <library.h> +#include <attributes/attributes.h> +#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. + */ +struct configuration_attribute_t { + + /** + * Implements payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the type of the attribute. + * + * @return type of the configuration attribute + */ + configuration_attribute_type_t (*get_type)(configuration_attribute_t *this); + + /** + * Returns the value of the attribute. + * + * @return chunk_t pointing to the internal value + */ + chunk_t (*get_value) (configuration_attribute_t *this); + + /** + * Destroys an configuration_attribute_t object. + */ + void (*destroy) (configuration_attribute_t *this); +}; + +/** + * Creates an empty configuration attribute. + * + * @return created configuration attribute + */ +configuration_attribute_t *configuration_attribute_create(); + +/** + * Creates a configuration attribute with type and value. + * + * @param type type of configuration attribute + * @param value value, gets cloned + * @return created configuration attribute + */ +configuration_attribute_t *configuration_attribute_create_value( + configuration_attribute_type_t type, chunk_t value); + +#endif /** CONFIGURATION_ATTRIBUTE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c new file mode 100644 index 000000000..f0a26eee2 --- /dev/null +++ b/src/libcharon/encoding/payloads/cp_payload.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "cp_payload.h" + +#include <encoding/payloads/encodings.h> +#include <utils/linked_list.h> + +ENUM(config_type_names, CFG_REQUEST, CFG_ACK, + "CFG_REQUEST", + "CFG_REPLY", + "CFG_SET", + "CFG_ACK", +); + +typedef struct private_cp_payload_t private_cp_payload_t; + +/** + * Private data of an cp_payload_t object. + * + */ +struct private_cp_payload_t { + /** + * Public cp_payload_t interface. + */ + cp_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * List of attributes, as configuration_attribute_t + */ + linked_list_t *attributes; + + /** + * Config Type. + */ + u_int8_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_rule_t cp_payload_encodings[] = { + /* 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, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* 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) }, + { RESERVED_BYTE,0 }, + { RESERVED_BYTE,0 }, + { RESERVED_BYTE,0 }, + { CONFIGURATION_ATTRIBUTES, 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 !C! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! CFG Type ! RESERVED ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Configuration Attributes ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_cp_payload_t *this) +{ + status_t status = SUCCESS; + enumerator_t *enumerator; + payload_t *attribute; + + enumerator = this->attributes->create_enumerator(this->attributes); + while (enumerator->enumerate(enumerator, &attribute)) + { + status = attribute->verify(attribute); + if (status != SUCCESS) + { + break; + } + } + enumerator->destroy(enumerator); + return status; +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_cp_payload_t *this, + encoding_rule_t **rules, size_t *rule_count) +{ + *rules = cp_payload_encodings; + *rule_count = sizeof(cp_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_cp_payload_t *this) +{ + return CONFIGURATION; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_cp_payload_t *this) +{ + return this->next_payload; +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_cp_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * recompute the length of the payload. + */ +static void compute_length(private_cp_payload_t *this) +{ + enumerator_t *enumerator; + payload_t *attribute; + + this->payload_length = CP_PAYLOAD_HEADER_LENGTH; + + enumerator = this->attributes->create_enumerator(this->attributes); + while (enumerator->enumerate(enumerator, &attribute)) + { + this->payload_length += attribute->get_length(attribute); + } + enumerator->destroy(enumerator); +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_cp_payload_t *this) +{ + return this->payload_length; +} + +/** + * Implementation of cp_payload_t.create_attribute_enumerator. + */ +static enumerator_t *create_attribute_enumerator(private_cp_payload_t *this) +{ + return this->attributes->create_enumerator(this->attributes); +} + +/** + * Implementation of cp_payload_t.add_attribute. + */ +static void add_attribute(private_cp_payload_t *this, + configuration_attribute_t *attribute) +{ + this->attributes->insert_last(this->attributes, attribute); + compute_length(this); +} + +/** + * Implementation of cp_payload_t.get_type. + */ +static config_type_t get_config_type(private_cp_payload_t *this) +{ + return this->type; +} + +/** + * Implementation of payload_t.destroy and cp_payload_t.destroy. + */ +static void destroy(private_cp_payload_t *this) +{ + this->attributes->destroy_offset(this->attributes, + offsetof(configuration_attribute_t, destroy)); + free(this); +} + +/* + * Described in header. + */ +cp_payload_t *cp_payload_create() +{ + private_cp_payload_t *this = malloc_thing(private_cp_payload_t); + + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + this->public.create_attribute_enumerator = (enumerator_t*(*)(cp_payload_t *))create_attribute_enumerator; + this->public.add_attribute = (void (*) (cp_payload_t *,configuration_attribute_t*))add_attribute; + this->public.get_type = (config_type_t (*) (cp_payload_t *))get_config_type; + this->public.destroy = (void (*)(cp_payload_t *))destroy; + + /* set default values of the fields */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = CP_PAYLOAD_HEADER_LENGTH; + this->attributes = linked_list_create(); + this->type = CFG_REQUEST; + + return &this->public; +} + +/* + * Described in header. + */ +cp_payload_t *cp_payload_create_type(config_type_t type) +{ + private_cp_payload_t *this = (private_cp_payload_t*)cp_payload_create(); + + this->type = type; + + return &this->public; +} + diff --git a/src/libcharon/encoding/payloads/cp_payload.h b/src/libcharon/encoding/payloads/cp_payload.h new file mode 100644 index 000000000..7dcf58f7e --- /dev/null +++ b/src/libcharon/encoding/payloads/cp_payload.h @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 cp_payload cp_payload + * @{ @ingroup payloads + */ + +#ifndef CP_PAYLOAD_H_ +#define CP_PAYLOAD_H_ + +typedef enum config_type_t config_type_t; +typedef struct cp_payload_t cp_payload_t; + +#include <library.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/configuration_attribute.h> +#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 { + CFG_REQUEST = 1, + CFG_REPLY = 2, + CFG_SET = 3, + CFG_ACK = 4, +}; + +/** + * enum name for 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. + */ +struct cp_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Creates an iterator of stored configuration_attribute_t objects. + * + * @return enumerator over configration_attribute_T + */ + enumerator_t *(*create_attribute_enumerator) (cp_payload_t *this); + + /** + * Adds a configuration attribute to the configuration payload. + * + * @param attribute attribute to add + */ + void (*add_attribute)(cp_payload_t *this, + configuration_attribute_t *attribute); + + /** + * Get the configuration payload type. + * + * @return type of configuration payload + */ + config_type_t (*get_type) (cp_payload_t *this); + + /** + * Destroys an cp_payload_t object. + */ + void (*destroy) (cp_payload_t *this); +}; + +/** + * Creates an empty configuration payload + * + * @return empty configuration payload + */ +cp_payload_t *cp_payload_create(); + +/** + * Creates an cp_payload_t with type and value + * + * @param config_type type of configuration payload to create + * @return created configuration payload + */ +cp_payload_t *cp_payload_create_type(config_type_t config_type); + +#endif /** CP_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c new file mode 100644 index 000000000..97b4743b2 --- /dev/null +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -0,0 +1,292 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "delete_payload.h" + + +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. + */ + delete_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Protocol ID. + */ + u_int8_t protocol_id; + + /** + * SPI Size. + */ + u_int8_t spi_size; + + /** + * Number of SPI's. + */ + u_int16_t spi_count; + + /** + * The contained SPI's. + */ + chunk_t spis; + + /** + * List containing u_int32_t spis + */ + linked_list_t *spi_list; +}; + +/** + * 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_rule_t delete_payload_encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, + /* the critical bit */ + { FLAG, offsetof(private_delete_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length)}, + { 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 */ + { SPIS, 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) ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_delete_payload_t *this) +{ + switch (this->protocol_id) + { + case PROTO_AH: + case PROTO_ESP: + if (this->spi_size != 4) + { + return FAILED; + } + break; + case PROTO_IKE: + case 0: + /* IKE deletion has no spi assigned! */ + if (this->spi_size != 0) + { + return FAILED; + } + break; + default: + return FAILED; + } + if (this->spis.len != (this->spi_count * this->spi_size)) + { + return FAILED; + } + return SUCCESS; +} + +/** + * Implementation of delete_payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_delete_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = delete_payload_encodings; + *rule_count = sizeof(delete_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_payload_type(private_delete_payload_t *this) +{ + return DELETE; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_delete_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_delete_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_delete_payload_t *this) +{ + return this->payload_length; +} + +/** + * Implementation of delete_payload_t.get_protocol_id. + */ +static protocol_id_t get_protocol_id (private_delete_payload_t *this) +{ + return (this->protocol_id); +} + +/** + * Implementation of delete_payload_t.add_spi. + */ +static void add_spi(private_delete_payload_t *this, u_int32_t spi) +{ + /* only add SPIs if AH|ESP, ignore others */ + if (this->protocol_id == PROTO_AH || this->protocol_id == PROTO_ESP) + { + this->spi_count += 1; + this->spis.len += this->spi_size; + this->spis.ptr = realloc(this->spis.ptr, this->spis.len); + *(u_int32_t*)(this->spis.ptr + (this->spis.len / this->spi_size - 1)) = spi; + if (this->spi_list) + { + /* reset SPI iterator list */ + this->spi_list->destroy(this->spi_list); + this->spi_list = NULL; + } + } +} + +/** + * Implementation of delete_payload_t.create_spi_iterator. + */ +static iterator_t* create_spi_iterator(private_delete_payload_t *this) +{ + int i; + + if (this->spi_list == NULL) + { + this->spi_list = linked_list_create(); + /* only parse SPIs if AH|ESP */ + if (this->protocol_id == PROTO_AH || this->protocol_id == PROTO_ESP) + { + for (i = 0; i < this->spi_count; i++) + { + this->spi_list->insert_last(this->spi_list, this->spis.ptr + i * + this->spi_size); + } + } + } + return this->spi_list->create_iterator(this->spi_list, TRUE); +} + +/** + * Implementation of payload_t.destroy and delete_payload_t.destroy. + */ +static void destroy(private_delete_payload_t *this) +{ + if (this->spis.ptr != NULL) + { + chunk_free(&this->spis); + } + if (this->spi_list) + { + this->spi_list->destroy(this->spi_list); + } + free(this); +} + +/* + * Described in header + */ +delete_payload_t *delete_payload_create(protocol_id_t protocol_id) +{ + private_delete_payload_t *this = malloc_thing(private_delete_payload_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.destroy = (void (*) (delete_payload_t *)) destroy; + this->public.get_protocol_id = (protocol_id_t (*) (delete_payload_t *)) get_protocol_id; + this->public.add_spi = (void (*) (delete_payload_t *,u_int32_t))add_spi; + this->public.create_spi_iterator = (iterator_t* (*) (delete_payload_t *)) create_spi_iterator; + + /* private variables */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = DELETE_PAYLOAD_HEADER_LENGTH; + this->protocol_id = protocol_id; + this->spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0; + this->spi_count = 0; + this->spis = chunk_empty; + this->spi_list = NULL; + + return (&this->public); +} diff --git a/src/libcharon/encoding/payloads/delete_payload.h b/src/libcharon/encoding/payloads/delete_payload.h new file mode 100644 index 000000000..3b62c1af1 --- /dev/null +++ b/src/libcharon/encoding/payloads/delete_payload.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 delete_payload delete_payload + * @{ @ingroup payloads + */ + +#ifndef DELETE_PAYLOAD_H_ +#define DELETE_PAYLOAD_H_ + +typedef struct delete_payload_t delete_payload_t; + +#include <library.h> +#include <encoding/payloads/payload.h> +#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. + */ +struct delete_payload_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the protocol ID. + * + * @return protocol ID + */ + protocol_id_t (*get_protocol_id) (delete_payload_t *this); + + /** + * Add an SPI to the list of deleted SAs. + * + * @param spi spi to add + */ + void (*add_spi) (delete_payload_t *this, u_int32_t spi); + + /** + * Get an iterator over the SPIs. + * + * The iterate() function returns a pointer to a u_int32_t SPI. + * + * @return iterator over SPIs + */ + iterator_t *(*create_spi_iterator) (delete_payload_t *this); + + /** + * Destroys an delete_payload_t object. + */ + void (*destroy) (delete_payload_t *this); +}; + +/** + * Creates an empty delete_payload_t object. + * + * @param protocol_id protocol, such as AH|ESP + * @return delete_payload_t object + */ +delete_payload_t *delete_payload_create(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 new file mode 100644 index 000000000..21f34a642 --- /dev/null +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -0,0 +1,302 @@ +/* + * Copyright (C) 2005-2010 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "eap_payload.h" + +#include <daemon.h> + +typedef struct private_eap_payload_t private_eap_payload_t; + +/** + * Private data of an eap_payload_t object. + * + */ +struct private_eap_payload_t { + /** + * Public eap_payload_t interface. + */ + eap_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * EAP message data, if available + */ + chunk_t data; +}; + +/** + * Encoding rules to parse or generate a EAP payload. + * + * The defined offsets are the positions in a object of type + * private_eap_payload_t. + * + */ +static encoding_rule_t eap_payload_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 */ + { FLAG, offsetof(private_eap_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* 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) }, +}; + +/* + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Code ! Identifier ! Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Type ! Type_Data... + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- +*/ + +METHOD(payload_t, verify, status_t, + private_eap_payload_t *this) +{ + u_int16_t length; + u_int8_t code; + + if (this->data.len < 4) + { + DBG1(DBG_ENC, "EAP payloads EAP message too short (%d)", this->data.len); + return FAILED; + } + length = untoh16(this->data.ptr + 2); + if (this->data.len != length) + { + DBG1(DBG_ENC, "EAP payload length (%d) does not match contained " + "message length (%d)", this->data.len, length); + return FAILED; + } + code = this->data.ptr[0]; + switch (code) + { + case EAP_REQUEST: + case EAP_RESPONSE: + { + if (this->data.len < 4) + { + DBG1(DBG_ENC, "EAP Request/Response does not have any data"); + return FAILED; + } + break; + } + case EAP_SUCCESS: + case EAP_FAILURE: + { + if (this->data.len != 4) + { + DBG1(DBG_ENC, "EAP Success/Failure has data"); + return FAILED; + } + break; + } + default: + return FAILED; + } + return SUCCESS; +} + +METHOD(payload_t, get_encoding_rules, void, + private_eap_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = eap_payload_encodings; + *rule_count = sizeof(eap_payload_encodings) / sizeof(encoding_rule_t); +} + +METHOD(payload_t, get_payload_type, payload_type_t, + private_eap_payload_t *this) +{ + return EXTENSIBLE_AUTHENTICATION; +} + +METHOD(payload_t, get_next_type, payload_type_t, + private_eap_payload_t *this) +{ + return (this->next_payload); +} + +METHOD(payload_t, set_next_type, void, + private_eap_payload_t *this, payload_type_t type) +{ + this->next_payload = type; +} + +METHOD(payload_t, get_length, size_t, + private_eap_payload_t *this) +{ + return this->payload_length; +} + +METHOD(eap_payload_t, get_data, chunk_t, + private_eap_payload_t *this) +{ + return this->data; +} + +METHOD(eap_payload_t, set_data, void, + private_eap_payload_t *this, chunk_t data) +{ + free(this->data.ptr); + this->data = chunk_clone(data); + this->payload_length = this->data.len + 4; +} + +METHOD(eap_payload_t, get_code, eap_code_t, + private_eap_payload_t *this) +{ + if (this->data.len > 0) + { + return this->data.ptr[0]; + } + /* should not happen, as it is verified */ + return 0; +} + +METHOD(eap_payload_t, get_identifier, u_int8_t, + private_eap_payload_t *this) +{ + if (this->data.len > 1) + { + return this->data.ptr[1]; + } + /* should not happen, as it is verified */ + 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) + { + 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 0; +} + +METHOD2(payload_t, eap_payload_t, destroy, void, + private_eap_payload_t *this) +{ + chunk_free(&this->data); + free(this); +} + +/* + * Described in header + */ +eap_payload_t *eap_payload_create() +{ + private_eap_payload_t *this; + + INIT(this, + .public = { + .payload_interface = { + .verify = _verify, + .get_encoding_rules = _get_encoding_rules, + .get_length = _get_length, + .get_next_type = _get_next_type, + .set_next_type = _set_next_type, + .get_type = _get_payload_type, + .destroy = _destroy, + }, + .get_data = _get_data, + .set_data = _set_data, + .get_code = _get_code, + .get_identifier = _get_identifier, + .get_type = _get_type, + .destroy = _destroy, + }, + .next_payload = NO_PAYLOAD, + .payload_length = EAP_PAYLOAD_HEADER_LENGTH, + ); + return &this->public; +} + +/* + * Described in header + */ +eap_payload_t *eap_payload_create_data(chunk_t data) +{ + eap_payload_t *this = eap_payload_create(); + + this->set_data(this, data); + return this; +} + +/* + * Described in header + */ +eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier) +{ + chunk_t data; + + data = chunk_from_chars(code, identifier, 0, 0); + htoun16(data.ptr + 2, data.len); + return eap_payload_create_data(data); +} + +/* + * Described in header + */ +eap_payload_t *eap_payload_create_nak(u_int8_t identifier) +{ + chunk_t data; + + data = chunk_from_chars(EAP_RESPONSE, identifier, 0, 0, EAP_NAK); + htoun16(data.ptr + 2, data.len); + return eap_payload_create_data(data); +} + diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h new file mode 100644 index 000000000..0bde4b15e --- /dev/null +++ b/src/libcharon/encoding/payloads/eap_payload.h @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 eap_payload eap_payload + * @{ @ingroup payloads + */ + +#ifndef EAP_PAYLOAD_H_ +#define EAP_PAYLOAD_H_ + +typedef struct eap_payload_t eap_payload_t; + +#include <library.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. + * + * The EAP payload format is described in RFC section 3.16. + */ +struct eap_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Set the contained EAP data. + * + * This contains the FULL EAP message starting with "code". + * Chunk gets cloned. + * + * @param message EAP data + */ + void (*set_data) (eap_payload_t *this, chunk_t data); + + /** + * Get the contained EAP data. + * + * This contains the FULL EAP message starting with "code". + * + * @return EAP data (pointer to internal data) + */ + chunk_t (*get_data) (eap_payload_t *this); + + /** + * Get the EAP code. + * + * @return EAP message as chunk_t + */ + eap_code_t (*get_code) (eap_payload_t *this); + + /** + * Get the EAP identifier. + * + * @return unique identifier + */ + u_int8_t (*get_identifier) (eap_payload_t *this); + + /** + * Get the EAP method type. + * + * @param vendor pointer receiving vendor identifier + * @return EAP method type, vendor specific if vendor != 0 + */ + eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor); + + /** + * Destroys an eap_payload_t object. + */ + void (*destroy) (eap_payload_t *this); +}; + +/** + * Creates an empty eap_payload_t object. + * + * @return eap_payload_t object + */ +eap_payload_t *eap_payload_create(void); + +/** + * Creates an eap_payload_t object with data. + * + * @return eap_payload_t object + */ +eap_payload_t *eap_payload_create_data(chunk_t data); + +/** + * Creates an eap_payload_t object with a code. + * + * Could should be either EAP_SUCCESS/EAP_FAILURE, use + * constructor above otherwise. + * + * @param code EAP status code + * @param identifier EAP identifier to use in payload + * @return eap_payload_t object + */ +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 + * @return eap_payload_t object + */ +eap_payload_t *eap_payload_create_nak(u_int8_t identifier); + +#endif /** EAP_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c new file mode 100644 index 000000000..85caeda82 --- /dev/null +++ b/src/libcharon/encoding/payloads/encodings.c @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "encodings.h" + +ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, + "U_INT_4", + "U_INT_8", + "U_INT_16", + "U_INT_32", + "RESERVED_BIT", + "RESERVED_BYTE", + "FLAG", + "PAYLOAD_LENGTH", + "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_VALUE", + "TRAFFIC_SELECTORS", + "TS_TYPE", + "ADDRESS", + "NONCE_DATA", + "ID_DATA", + "AUTH_DATA", + "CERT_DATA", + "CERTREQ_DATA", + "EAP_DATA", + "SPIS", + "VID_DATA", + "UNKNOWN_DATA", + "IKE_SPI", + "ENCRYPTED_DATA", +); diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h new file mode 100644 index 000000000..52af4a984 --- /dev/null +++ b/src/libcharon/encoding/payloads/encodings.h @@ -0,0 +1,515 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 encodings encodings + * @{ @ingroup payloads + */ + +#ifndef ENCODINGS_H_ +#define ENCODINGS_H_ + +typedef enum encoding_type_t encoding_type_t; +typedef struct encoding_rule_t encoding_rule_t; + +#include <library.h> + +/** + * All different kinds of encoding types. + * + * Each field of an IKEv2-Message (in header or payload) + * which has to be parsed or generated differently has its own + * type defined here. + * + * Header is parsed like a payload and gets its one payload_id + * from PRIVATE USE space. Also the substructures + * of specific payload types get their own payload_id + * from PRIVATE_USE space. See IKEv2-Draft for more informations. + */ +enum encoding_type_t { + + /** + * Representing a 4 Bit unsigned int value. + * + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 4 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 4 bit forward afterwards. + */ + U_INT_4, + + /** + * Representing a 8 Bit unsigned int value. + * + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 8 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 8 bit forward afterwards. + */ + U_INT_8, + + /** + * Representing a 16 Bit unsigned int value. + * + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 16 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 16 bit forward afterwards. + */ + U_INT_16, + + /** + * Representing a 32 Bit unsigned int value. + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 32 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 32 bit forward afterwards. + */ + U_INT_32, + + /** + * represents a RESERVED_BIT used in FLAG-Bytes. + * + * When generating, the next bit is set to zero and the current write + * position is moved one bit forward. + * No value is read from the associated data struct. + * The current write position is moved 1 bit forward afterwards. + * + * When parsing, the current read pointer is moved one bit forward. + * No value is written to the associated data struct. + * The current read pointer is moved 1 bit forward afterwards. + */ + RESERVED_BIT, + + /** + * represents a RESERVED_BYTE. + * + * When generating, the next byte is set to zero and the current write + * position is moved one byte forward. + * No value is read from the associated data struct. + * The current write position is moved 1 byte forward afterwards. + * + * When parsing, the current read pointer is moved one byte forward. + * No value is written to the associated data struct. + * The current read pointer is moved 1 byte forward afterwards. + */ + RESERVED_BYTE, + + /** + * Representing a 1 Bit flag. + * + * When generation, the next bit is set to 1 if the associated value + * in the data struct is TRUE, 0 otherwise. The current write position + * is moved 1 bit forward afterwards. + * + * When parsing, the next bit is read and stored in the associated data + * struct. 0 means FALSE, 1 means TRUE, The current read pointer + * is moved 1 bit forward afterwards + */ + FLAG, + + /** + * Representating a length field of a payload. + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 16 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 16 bit forward afterwards. + */ + PAYLOAD_LENGTH, + + /** + * Representating a length field of a header. + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 32 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 32 bit forward afterwards. + */ + HEADER_LENGTH, + + /** + * Representating a spi size field. + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 8 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 8 bit forward afterwards. + */ + SPI_SIZE, + + /** + * Representating a spi field. + * + * When generating the content of the chunkt pointing to + * is written. + * + * When parsing SPI_SIZE bytes are read and written into the chunk pointing to. + */ + 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 + * in the data struct is TRUE, 0 otherwise. The current write position + * is moved 1 bit forward afterwards. + * + * When parsing, the next bit is read and stored in the associated data + * struct. 0 means FALSE, 1 means TRUE, The current read pointer + * is moved 1 bit forward afterwards. + */ + ATTRIBUTE_FORMAT, + /** + * Representing a 15 Bit unsigned int value used as attribute type + * in an attribute transform. + * + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 15 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 15 bit forward afterwards. + */ + ATTRIBUTE_TYPE, + + /** + * Depending on the field of type ATTRIBUTE_FORMAT + * this field contains the length or the value of an transform attribute. + * Its stored in a 16 unsigned integer field. + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 16 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 16 bit forward afterwards. + */ + ATTRIBUTE_LENGTH_OR_VALUE, + + /** + * This field contains the length or the value of an configuration attribute. + * Its stored in a 16 unsigned integer field. + * + * When generating it must be changed from host to network order. + * The value is read from the associated data struct. + * The current write position is moved 16 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 16 bit forward afterwards. + */ + CONFIGURATION_ATTRIBUTE_LENGTH, + + /** + * Depending on the field of type ATTRIBUTE_FORMAT + * this field is available or missing and so parsed/generated + * or not parsed/not generated. + * + * When generating the content of the chunkt pointing to + * is written. + * + * When parsing SPI_SIZE bytes are read and written into the chunk pointing to. + */ + 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. + * The value is read from the associated data struct. + * The current write position is moved 16 bit forward afterwards. + * + * When parsing it must be changed from network to host order. + * The value is written to the associated data struct. + * The current read pointer is moved 16 bit forward afterwards. + */ + TS_TYPE, + + /** + * Representating an address field in a traffic selector. + * + * Depending on the last field of type TS_TYPE + * this field is either 4 or 16 byte long. + * + * When generating the content of the chunkt pointing to + * is written. + * + * When parsing 4 or 16 bytes are read and written into the chunk pointing to. + */ + 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. + */ + 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, + + /** + * Representating an IKE_SPI field in an IKEv2 Header. + * + * When generating the value of the u_int64_t pointing to + * is written (host and networ order is not changed). + * + * When parsing 8 bytes are read and written into the u_int64_t pointing to. + */ + IKE_SPI, + + /** + * Representing the encrypted data body of a encryption payload. + */ + ENCRYPTED_DATA, +}; + +/** + * enum name for encoding_type_t + */ +extern enum_name_t *encoding_type_names; + +/** + * Rule how to en-/decode a payload field. + * + * An encoding rule is a mapping of a specific encoding type to + * a location in the data struct where the current field is stored to + * or read from. + * This rules are used by parser and generator. + */ +struct encoding_rule_t { + + /** + * Encoding type. + */ + encoding_type_t type; + + /** + * Offset in the data struct. + * + * When parsing, data are written to this offset of the + * data struct. + * + * When generating, data are read from this offset in the + * data struct. + */ + u_int32_t offset; +}; + +#endif /** ENCODINGS_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c new file mode 100644 index 000000000..2adbb88b9 --- /dev/null +++ b/src/libcharon/encoding/payloads/encryption_payload.c @@ -0,0 +1,619 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 <string.h> + +#include "encryption_payload.h" + +#include <daemon.h> +#include <encoding/payloads/encodings.h> +#include <utils/linked_list.h> +#include <encoding/generator.h> +#include <encoding/parser.h> +#include <utils/iterator.h> +#include <crypto/signers/signer.h> + + +typedef struct private_encryption_payload_t private_encryption_payload_t; + +/** + * Private data of an encryption_payload_t' Object. + * + */ +struct private_encryption_payload_t { + + /** + * Public encryption_payload_t interface. + */ + encryption_payload_t public; + + /** + * There is no next payload for an encryption payload, + * since encryption payload MUST be the last one. + * next_payload means here the first payload of the + * contained, encrypted payload. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload + */ + u_int16_t payload_length; + + /** + * Chunk containing the iv, data, padding, + * and (an eventually not calculated) signature. + */ + chunk_t encrypted; + + /** + * Chunk containing the data in decrypted (unpadded) form. + */ + chunk_t decrypted; + + /** + * Signer set by set_signer. + */ + signer_t *signer; + + /** + * Crypter, supplied by encrypt/decrypt + */ + crypter_t *crypter; + + /** + * Contained payloads of this encrpytion_payload. + */ + linked_list_t *payloads; +}; + +/** + * Encoding rules to parse or generate a IKEv2-Encryption Payload. + * + * The defined offsets are the positions in a object of type + * private_encryption_payload_t. + * + */ +encoding_rule_t encryption_payload_encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_encryption_payload_t, next_payload) }, + /* the critical bit */ + { FLAG, offsetof(private_encryption_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* 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) }, +}; + +/* + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Initialization Vector ! + ! (length is block size for encryption algorithm) ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Encrypted IKE Payloads ! + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! Padding (0-255 octets) ! + +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+ + ! ! Pad Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ~ Integrity Checksum Data ~ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_encryption_payload_t *this) +{ + return SUCCESS; +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_encryption_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = encryption_payload_encodings; + *rule_count = sizeof(encryption_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_encryption_payload_t *this) +{ + return ENCRYPTED; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_encryption_payload_t *this) +{ + /* returns first contained payload here */ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_encryption_payload_t *this, payload_type_t type) +{ + /* set next type is not allowed, since this payload MUST be the last one + * and so nothing is done in here*/ +} + +/** + * (re-)compute the lenght of the whole payload + */ +static void compute_length(private_encryption_payload_t *this) +{ + iterator_t *iterator; + payload_t *current_payload; + size_t block_size, length = 0; + iterator = this->payloads->create_iterator(this->payloads, TRUE); + + /* count payload length */ + while (iterator->iterate(iterator, (void **) ¤t_payload)) + { + length += current_payload->get_length(current_payload); + } + iterator->destroy(iterator); + + if (this->crypter && this->signer) + { + /* append one byte for padding length */ + length++; + /* append padding */ + block_size = this->crypter->get_block_size(this->crypter); + length += block_size - length % block_size; + /* add iv */ + length += block_size; + /* add signature */ + length += this->signer->get_block_size(this->signer); + } + length += ENCRYPTION_PAYLOAD_HEADER_LENGTH; + this->payload_length = length; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_encryption_payload_t *this) +{ + compute_length(this); + return this->payload_length; +} + +/** + * Implementation of payload_t.create_payload_iterator. + */ +static iterator_t *create_payload_iterator (private_encryption_payload_t *this, bool forward) +{ + return (this->payloads->create_iterator(this->payloads, forward)); +} + +/** + * Implementation of payload_t.add_payload. + */ +static void add_payload(private_encryption_payload_t *this, payload_t *payload) +{ + payload_t *last_payload; + if (this->payloads->get_count(this->payloads) > 0) + { + this->payloads->get_last(this->payloads,(void **) &last_payload); + last_payload->set_next_type(last_payload, payload->get_type(payload)); + } + else + { + this->next_payload = payload->get_type(payload); + } + payload->set_next_type(payload, NO_PAYLOAD); + this->payloads->insert_last(this->payloads, (void*)payload); + compute_length(this); +} + +/** + * Implementation of encryption_payload_t.remove_first_payload. + */ +static status_t remove_first_payload(private_encryption_payload_t *this, payload_t **payload) +{ + return this->payloads->remove_first(this->payloads, (void**)payload); +} + +/** + * Implementation of encryption_payload_t.get_payload_count. + */ +static size_t get_payload_count(private_encryption_payload_t *this) +{ + return this->payloads->get_count(this->payloads); +} + +/** + * Generate payload before encryption. + */ +static void generate(private_encryption_payload_t *this) +{ + payload_t *current_payload, *next_payload; + generator_t *generator; + iterator_t *iterator; + + /* recalculate length before generating */ + compute_length(this); + + /* create iterator */ + iterator = this->payloads->create_iterator(this->payloads, TRUE); + + /* get first payload */ + if (iterator->iterate(iterator, (void**)¤t_payload)) + { + this->next_payload = current_payload->get_type(current_payload); + } + else + { + /* no paylads? */ + DBG2(DBG_ENC, "generating contained payloads, but none available"); + free(this->decrypted.ptr); + this->decrypted = chunk_empty; + iterator->destroy(iterator); + return; + } + + generator = generator_create(); + + /* build all payload, except last */ + while(iterator->iterate(iterator, (void**)&next_payload)) + { + current_payload->set_next_type(current_payload, next_payload->get_type(next_payload)); + generator->generate_payload(generator, current_payload); + current_payload = next_payload; + } + iterator->destroy(iterator); + + /* build last payload */ + current_payload->set_next_type(current_payload, NO_PAYLOAD); + generator->generate_payload(generator, current_payload); + + /* free already generated data */ + free(this->decrypted.ptr); + + generator->write_to_chunk(generator, &(this->decrypted)); + generator->destroy(generator); + DBG2(DBG_ENC, "successfully generated content in encryption payload"); +} + +/** + * Implementation of encryption_payload_t.encrypt. + */ +static status_t encrypt(private_encryption_payload_t *this) +{ + chunk_t iv, padding, to_crypt, result; + rng_t *rng; + size_t block_size; + + if (this->signer == NULL || this->crypter == NULL) + { + DBG1(DBG_ENC, "could not encrypt, signer/crypter not set"); + return INVALID_STATE; + } + + /* for random data in iv and padding */ + rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); + if (!rng) + { + DBG1(DBG_ENC, "could not encrypt, no RNG found"); + return FAILED; + } + /* build payload chunk */ + generate(this); + + DBG2(DBG_ENC, "encrypting payloads"); + DBG3(DBG_ENC, "data to encrypt %B", &this->decrypted); + + /* build padding */ + block_size = this->crypter->get_block_size(this->crypter); + padding.len = block_size - ((this->decrypted.len + 1) % block_size); + rng->allocate_bytes(rng, padding.len, &padding); + + /* concatenate payload data, padding, padding len */ + to_crypt.len = this->decrypted.len + padding.len + 1; + to_crypt.ptr = malloc(to_crypt.len); + + memcpy(to_crypt.ptr, this->decrypted.ptr, this->decrypted.len); + memcpy(to_crypt.ptr + this->decrypted.len, padding.ptr, padding.len); + *(to_crypt.ptr + to_crypt.len - 1) = padding.len; + + /* build iv */ + iv.len = block_size; + rng->allocate_bytes(rng, iv.len, &iv); + rng->destroy(rng); + + DBG3(DBG_ENC, "data before encryption with padding %B", &to_crypt); + + /* encrypt to_crypt chunk */ + free(this->encrypted.ptr); + this->crypter->encrypt(this->crypter, to_crypt, iv, &result); + free(padding.ptr); + free(to_crypt.ptr); + + DBG3(DBG_ENC, "data after encryption %B", &result); + + /* build encrypted result with iv and signature */ + this->encrypted.len = iv.len + result.len + this->signer->get_block_size(this->signer); + free(this->encrypted.ptr); + this->encrypted.ptr = malloc(this->encrypted.len); + + /* fill in result, signature is left out */ + memcpy(this->encrypted.ptr, iv.ptr, iv.len); + memcpy(this->encrypted.ptr + iv.len, result.ptr, result.len); + + free(result.ptr); + free(iv.ptr); + DBG3(DBG_ENC, "data after encryption with IV and (invalid) signature %B", + &this->encrypted); + + return SUCCESS; +} + +/** + * Parse the payloads after decryption. + */ +static status_t parse(private_encryption_payload_t *this) +{ + parser_t *parser; + status_t status; + payload_type_t current_payload_type; + + /* build a parser on the decrypted data */ + parser = parser_create(this->decrypted); + + current_payload_type = this->next_payload; + /* parse all payloads */ + while (current_payload_type != NO_PAYLOAD) + { + payload_t *current_payload; + + status = parser->parse_payload(parser, current_payload_type, (payload_t**)¤t_payload); + if (status != SUCCESS) + { + parser->destroy(parser); + return PARSE_ERROR; + } + + status = current_payload->verify(current_payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "%N verification failed", + payload_type_names, current_payload->get_type(current_payload)); + current_payload->destroy(current_payload); + parser->destroy(parser); + return VERIFY_ERROR; + } + + /* get next payload type */ + current_payload_type = current_payload->get_next_type(current_payload); + + this->payloads->insert_last(this->payloads,current_payload); + } + parser->destroy(parser); + DBG2(DBG_ENC, "succesfully parsed content of encryption payload"); + return SUCCESS; +} + +/** + * Implementation of encryption_payload_t.encrypt. + */ +static status_t decrypt(private_encryption_payload_t *this) +{ + chunk_t iv, concatenated; + u_int8_t padding_length; + + DBG2(DBG_ENC, "decrypting encryption payload"); + DBG3(DBG_ENC, "data before decryption with IV and (invalid) signature %B", + &this->encrypted); + + if (this->signer == NULL || this->crypter == NULL) + { + DBG1(DBG_ENC, "could not decrypt, no crypter/signer set"); + return INVALID_STATE; + } + + /* get IV */ + iv.len = this->crypter->get_block_size(this->crypter); + + iv.ptr = this->encrypted.ptr; + + /* point concatenated to data + padding + padding_length*/ + concatenated.ptr = this->encrypted.ptr + iv.len; + concatenated.len = this->encrypted.len - iv.len - + this->signer->get_block_size(this->signer); + + /* concatenated must be a multiple of block_size of crypter */ + if (concatenated.len < iv.len || concatenated.len % iv.len) + { + DBG1(DBG_ENC, "could not decrypt, invalid input"); + return FAILED; + } + + /* free previus data, if any */ + free(this->decrypted.ptr); + + DBG3(DBG_ENC, "data before decryption %B", &concatenated); + + this->crypter->decrypt(this->crypter, concatenated, iv, &this->decrypted); + + DBG3(DBG_ENC, "data after decryption with padding %B", &this->decrypted); + + /* get padding length, sits just bevore signature */ + padding_length = *(this->decrypted.ptr + this->decrypted.len - 1); + /* add one byte to the padding length, since the padding_length field is + * not included */ + padding_length++; + + /* check size again */ + if (padding_length > concatenated.len || padding_length > this->decrypted.len) + { + DBG1(DBG_ENC, "decryption failed, invalid padding length found. Invalid key?"); + /* decryption failed :-/ */ + return FAILED; + } + this->decrypted.len -= padding_length; + + /* free padding */ + this->decrypted.ptr = realloc(this->decrypted.ptr, this->decrypted.len); + DBG3(DBG_ENC, "data after decryption without padding %B", &this->decrypted); + DBG2(DBG_ENC, "decryption successful, trying to parse content"); + return parse(this); +} + +/** + * Implementation of encryption_payload_t.set_transforms. + */ +static void set_transforms(private_encryption_payload_t *this, crypter_t* crypter, signer_t* signer) +{ + this->signer = signer; + this->crypter = crypter; +} + +/** + * Implementation of encryption_payload_t.build_signature. + */ +static status_t build_signature(private_encryption_payload_t *this, chunk_t data) +{ + chunk_t data_without_sig = data; + chunk_t sig; + + if (this->signer == NULL) + { + DBG1(DBG_ENC, "unable to build signature, no signer set"); + return INVALID_STATE; + } + + sig.len = this->signer->get_block_size(this->signer); + data_without_sig.len -= sig.len; + sig.ptr = data.ptr + data_without_sig.len; + DBG2(DBG_ENC, "building signature"); + this->signer->get_signature(this->signer, data_without_sig, sig.ptr); + return SUCCESS; +} + +/** + * Implementation of encryption_payload_t.verify_signature. + */ +static status_t verify_signature(private_encryption_payload_t *this, chunk_t data) +{ + chunk_t sig, data_without_sig; + bool valid; + + if (this->signer == NULL) + { + DBG1(DBG_ENC, "unable to verify signature, no signer set"); + return INVALID_STATE; + } + /* find signature in data chunk */ + sig.len = this->signer->get_block_size(this->signer); + if (data.len <= sig.len) + { + DBG1(DBG_ENC, "unable to verify signature, invalid input"); + return FAILED; + } + sig.ptr = data.ptr + data.len - sig.len; + + /* verify it */ + data_without_sig.len = data.len - sig.len; + data_without_sig.ptr = data.ptr; + valid = this->signer->verify_signature(this->signer, data_without_sig, sig); + + if (!valid) + { + DBG1(DBG_ENC, "signature verification failed"); + return FAILED; + } + + DBG2(DBG_ENC, "signature verification successful"); + return SUCCESS; +} + +/** + * Implementation of payload_t.destroy. + */ +static void destroy(private_encryption_payload_t *this) +{ + this->payloads->destroy_offset(this->payloads, offsetof(payload_t, destroy)); + free(this->encrypted.ptr); + free(this->decrypted.ptr); + free(this); +} + +/* + * Described in header + */ +encryption_payload_t *encryption_payload_create() +{ + private_encryption_payload_t *this = malloc_thing(private_encryption_payload_t); + + /* payload_t interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.create_payload_iterator = (iterator_t * (*) (encryption_payload_t *,bool)) create_payload_iterator; + this->public.add_payload = (void (*) (encryption_payload_t *,payload_t *)) add_payload; + this->public.remove_first_payload = (status_t (*)(encryption_payload_t*, payload_t **)) remove_first_payload; + this->public.get_payload_count = (size_t (*)(encryption_payload_t*)) get_payload_count; + + this->public.encrypt = (status_t (*) (encryption_payload_t *)) encrypt; + this->public.decrypt = (status_t (*) (encryption_payload_t *)) decrypt; + this->public.set_transforms = (void (*) (encryption_payload_t*,crypter_t*,signer_t*)) set_transforms; + this->public.build_signature = (status_t (*) (encryption_payload_t*, chunk_t)) build_signature; + this->public.verify_signature = (status_t (*) (encryption_payload_t*, chunk_t)) verify_signature; + this->public.destroy = (void (*) (encryption_payload_t *)) destroy; + + /* set default values of the fields */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = ENCRYPTION_PAYLOAD_HEADER_LENGTH; + this->encrypted = chunk_empty; + this->decrypted = chunk_empty; + this->signer = NULL; + this->crypter = NULL; + this->payloads = linked_list_create(); + + return (&(this->public)); +} diff --git a/src/libcharon/encoding/payloads/encryption_payload.h b/src/libcharon/encoding/payloads/encryption_payload.h new file mode 100644 index 000000000..ac5326b87 --- /dev/null +++ b/src/libcharon/encoding/payloads/encryption_payload.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 encryption_payload encryption_payload + * @{ @ingroup payloads + */ + +#ifndef ENCRYPTION_PAYLOAD_H_ +#define ENCRYPTION_PAYLOAD_H_ + +typedef struct encryption_payload_t encryption_payload_t; + +#include <library.h> +#include <crypto/crypters/crypter.h> +#include <crypto/signers/signer.h> +#include <encoding/payloads/payload.h> +#include <utils/linked_list.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. + * + * Before any crypt/decrypt/sign/verify operation can occur, + * the transforms must be set. After that, a parsed encryption payload + * can be decrypted, which also will parse the contained payloads. + * Encryption is done the same way, added payloads will get generated + * and then encrypted. + * For signature building, there is the FULL packet needed. Meaning it + * must be builded after generation of all payloads and the encryption + * of the encryption payload. + * Signature verificatin is done before decryption. + */ +struct encryption_payload_t { + /** + * Implements payload_t interface. + */ + payload_t payload_interface; + + /** + * Creates an iterator for all contained payloads. + * + * iterator_t object has to get destroyed by the caller. + * + * @param forward iterator direction (TRUE: front to end) + * return created iterator_t object + */ + iterator_t *(*create_payload_iterator) (encryption_payload_t *this, bool forward); + + /** + * Adds a payload to this encryption payload. + * + * @param payload payload_t object to add + */ + void (*add_payload) (encryption_payload_t *this, payload_t *payload); + + /** + * Reove the last payload in the contained payload list. + * + * @param payload removed payload + * @return + * - SUCCESS, or + * - NOT_FOUND if list empty + */ + status_t (*remove_first_payload) (encryption_payload_t *this, payload_t **payload); + + /** + * Get the number of payloads. + * + * @return number of contained payloads + */ + size_t (*get_payload_count) (encryption_payload_t *this); + + /** + * Set transforms to use. + * + * To decryption, encryption, signature building and verifying, + * the payload needs a crypter and a signer object. + * + * @warning Do NOT call this function again after encryption, since + * the signer must be the same while encrypting and signature building! + * + * @param crypter crypter_t to use for data de-/encryption + * @param signer signer_t to use for data signing/verifying + */ + void (*set_transforms) (encryption_payload_t *this, crypter_t *crypter, signer_t *signer); + + /** + * Generate and encrypt contained payloads. + * + * This function generates the content for added payloads + * and encrypts them. Signature is not built, since we need + * additional data (the full message). + * + * @return SUCCESS, or INVALID_STATE if transforms not set + */ + status_t (*encrypt) (encryption_payload_t *this); + + /** + * Decrypt and parse contained payloads. + * + * This function decrypts the contained data. After, + * the payloads are parsed internally and are accessible + * via the iterator. + * + * @return + * - SUCCESS, or + * - INVALID_STATE if transforms not set, or + * - FAILED if data is invalid + */ + status_t (*decrypt) (encryption_payload_t *this); + + /** + * Build the signature. + * + * The signature is built over the FULL message, so the header + * and every payload (inclusive this one) must already be generated. + * The generated message is supplied via the data paramater. + * + * @param data chunk contains the already generated message + * @return + * - SUCCESS, or + * - INVALID_STATE if transforms not set + */ + status_t (*build_signature) (encryption_payload_t *this, chunk_t data); + + /** + * Verify the signature. + * + * Since the signature is built over the full message, we need + * this data to do the verification. The message data + * is supplied via the data argument. + * + * @param data chunk contains the message + * @return + * - SUCCESS, or + * - FAILED if signature invalid, or + * - INVALID_STATE if transforms not set + */ + status_t (*verify_signature) (encryption_payload_t *this, chunk_t data); + + /** + * Destroys an encryption_payload_t object. + */ + void (*destroy) (encryption_payload_t *this); +}; + +/** + * Creates an empty encryption_payload_t object. + * + * @return encryption_payload_t object + */ +encryption_payload_t *encryption_payload_create(void); + +#endif /** ENCRYPTION_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/endpoint_notify.c b/src/libcharon/encoding/payloads/endpoint_notify.c new file mode 100644 index 000000000..faec1ea71 --- /dev/null +++ b/src/libcharon/encoding/payloads/endpoint_notify.c @@ -0,0 +1,422 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 "endpoint_notify.h" + +#include <math.h> + +#include <daemon.h> + +typedef struct private_endpoint_notify_t private_endpoint_notify_t; + +/** + * Private data of an notify_payload_t object. + */ +struct private_endpoint_notify_t { + /** + * Public endpoint_notify_t interface. + */ + endpoint_notify_t public; + + /** + * Priority + */ + u_int32_t priority; + + /** + * Family + */ + me_endpoint_family_t family; + + /** + * Endpoint type + */ + me_endpoint_type_t type; + + /** + * Endpoint + */ + host_t *endpoint; + + /** + * Base (used for server reflexive endpoints) + */ + host_t *base; +}; + +/* Notification 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Priority ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Family ! Type ! Port ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! IP Address (variable) ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +ENUM(me_endpoint_type_names, HOST, RELAYED, + "HOST", + "PEER_REFLEXIVE", + "SERVER_REFLEXIVE", + "RELAYED" +); + +/** + * Helper functions to parse integer values + */ +static status_t parse_uint8(u_int8_t **cur, u_int8_t *top, u_int8_t *val) +{ + if (*cur + sizeof(u_int8_t) > top) + { + return FAILED; + } + *val = *(u_int8_t*)*cur; + *cur += sizeof(u_int8_t); + return SUCCESS; +} + +static status_t parse_uint16(u_int8_t **cur, u_int8_t *top, u_int16_t *val) +{ + if (*cur + sizeof(u_int16_t) > top) + { + return FAILED; + } + *val = ntohs(*(u_int16_t*)*cur); + *cur += sizeof(u_int16_t); + return SUCCESS; +} + +static status_t parse_uint32(u_int8_t **cur, u_int8_t *top, u_int32_t *val) +{ + if (*cur + sizeof(u_int32_t) > top) + { + return FAILED; + } + *val = ntohl(*(u_int32_t*)*cur); + *cur += sizeof(u_int32_t); + return SUCCESS; +} + +/** + * Parses the notification data of a ME_ENDPOINT notify + */ +static status_t parse_notification_data(private_endpoint_notify_t *this, chunk_t data) +{ + u_int8_t family, type, addr_family; + u_int16_t port; + chunk_t addr; + u_int8_t *cur = data.ptr; + u_int8_t *top = data.ptr + data.len; + + DBG3(DBG_IKE, "me_endpoint_data %B", &data); + + if (parse_uint32(&cur, top, &this->priority) != SUCCESS) + { + DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid priority"); + return FAILED; + } + + if (parse_uint8(&cur, top, &family) != SUCCESS || family >= MAX_FAMILY) + { + DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid family"); + return FAILED; + } + this->family = (me_endpoint_family_t)family; + + if (parse_uint8(&cur, top, &type) != SUCCESS || + type == NO_TYPE || type >= MAX_TYPE) + { + DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid type"); + return FAILED; + } + this->type = (me_endpoint_type_t)type; + + addr_family = AF_INET; + addr.len = 4; + + switch(this->family) + { + case IPv6: + addr_family = AF_INET6; + addr.len = 16; + /* fall-through */ + case IPv4: + if (parse_uint16(&cur, top, &port) != SUCCESS) + { + DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid port"); + return FAILED; + } + + if (cur + addr.len > top) + { + DBG1(DBG_IKE, "failed to parse ME_ENDPOINT: invalid IP address"); + return FAILED; + } + + addr.ptr = cur; + this->endpoint = host_create_from_chunk(addr_family, addr, port); + break; + case NO_FAMILY: + default: + this->endpoint = NULL; + break; + } + return SUCCESS; +} + + +/** + * Generates the notification data of a ME_ENDPOINT notify + */ +static chunk_t build_notification_data(private_endpoint_notify_t *this) +{ + chunk_t prio_chunk, family_chunk, type_chunk, port_chunk, addr_chunk; + chunk_t data; + u_int32_t prio; + u_int16_t port; + u_int8_t family, type; + + prio = htonl(this->priority); + prio_chunk = chunk_from_thing(prio); + family = this->family; + family_chunk = chunk_from_thing(family); + type = this->type; + type_chunk = chunk_from_thing(type); + + if (this->endpoint) + { + port = htons(this->endpoint->get_port(this->endpoint)); + addr_chunk = this->endpoint->get_address(this->endpoint); + } + else + { + port = 0; + addr_chunk = chunk_empty; + } + port_chunk = chunk_from_thing(port); + + /* data = prio | family | type | port | addr */ + data = chunk_cat("ccccc", prio_chunk, family_chunk, type_chunk, + port_chunk, addr_chunk); + DBG3(DBG_IKE, "me_endpoint_data %B", &data); + return data; +} + +/** + * Implementation of endpoint_notify_t.build_notify + */ +static notify_payload_t *build_notify(private_endpoint_notify_t *this) +{ + chunk_t data; + notify_payload_t *notify; + + notify = notify_payload_create(); + notify->set_notify_type(notify, ME_ENDPOINT); + data = build_notification_data(this); + notify->set_notification_data(notify, data); + chunk_free(&data); + + return notify; +} + +/** + * Implementation of endpoint_notify_t.get_priority. + */ +static u_int32_t get_priority(private_endpoint_notify_t *this) +{ + return this->priority; +} + +/** + * Implementation of endpoint_notify_t.set_priority. + */ +static void set_priority(private_endpoint_notify_t *this, u_int32_t priority) +{ + this->priority = priority; +} + +/** + * Implementation of endpoint_notify_t.get_type. + */ +static me_endpoint_type_t get_type(private_endpoint_notify_t *this) +{ + return this->type; +} + +/** + * Implementation of endpoint_notify_t.get_family. + */ +static me_endpoint_family_t get_family(private_endpoint_notify_t *this) +{ + return this->family; +} + +/** + * Implementation of endpoint_notify_t.get_host. + */ +static host_t *get_host(private_endpoint_notify_t *this) +{ + return this->endpoint; +} + +/** + * Implementation of endpoint_notify_t.get_base. + */ +static host_t *get_base(private_endpoint_notify_t *this) +{ + return (!this->base) ? this->endpoint : this->base; +} + +/** + * Implementation of endpoint_notify_t.clone. + */ +static endpoint_notify_t *_clone(private_endpoint_notify_t *this) +{ + private_endpoint_notify_t *clone = (private_endpoint_notify_t*)endpoint_notify_create(); + + clone->priority = this->priority; + clone->type = this->type; + clone->family = this->family; + if (this->endpoint) + { + clone->endpoint = this->endpoint->clone(this->endpoint); + } + + if (this->base) + { + clone->base = this->base->clone(this->base); + } + + return &clone->public; +} + +/** + * Implementation of endpoint_notify_t.destroy. + */ +static status_t destroy(private_endpoint_notify_t *this) +{ + DESTROY_IF(this->endpoint); + DESTROY_IF(this->base); + free(this); + return SUCCESS; +} + +/* + * Described in header + */ +endpoint_notify_t *endpoint_notify_create() +{ + private_endpoint_notify_t *this = malloc_thing(private_endpoint_notify_t); + + /* public functions */ + this->public.get_priority = (u_int32_t (*) (endpoint_notify_t *)) get_priority; + this->public.set_priority = (void (*) (endpoint_notify_t *, u_int32_t)) set_priority; + this->public.get_type = (me_endpoint_type_t (*) (endpoint_notify_t *)) get_type; + this->public.get_family = (me_endpoint_family_t (*) (endpoint_notify_t *)) get_family; + this->public.get_host = (host_t *(*) (endpoint_notify_t *)) get_host; + this->public.get_base = (host_t *(*) (endpoint_notify_t *)) get_base; + this->public.build_notify = (notify_payload_t *(*) (endpoint_notify_t *)) build_notify; + this->public.clone = (endpoint_notify_t *(*) (endpoint_notify_t *)) _clone; + this->public.destroy = (void (*) (endpoint_notify_t *)) destroy; + + /* set default values of the fields */ + this->priority = 0; + this->family = NO_FAMILY; + this->type = NO_TYPE; + this->endpoint = NULL; + this->base = NULL; + + return &this->public; +} + +/** + * Described in header + */ +endpoint_notify_t *endpoint_notify_create_from_host(me_endpoint_type_t type, host_t *host, host_t *base) +{ + private_endpoint_notify_t *this = (private_endpoint_notify_t*)endpoint_notify_create(); + + this->type = type; + + switch(type) + { + case HOST: + this->priority = pow(2, 16) * ME_PRIO_HOST; + break; + case PEER_REFLEXIVE: + this->priority = pow(2, 16) * ME_PRIO_PEER; + break; + case SERVER_REFLEXIVE: + this->priority = pow(2, 16) * ME_PRIO_SERVER; + break; + case RELAYED: + default: + this->priority = pow(2, 16) * ME_PRIO_RELAY; + break; + } + + /* FIXME: if there is more than one ip address we should vary this priority */ + this->priority += 65535; + + if (!host) + { + return &this->public; + } + + switch(host->get_family(host)) + { + case AF_INET: + this->family = IPv4; + break; + case AF_INET6: + this->family = IPv6; + break; + default: + /* unsupported family type, we do not set the host + * (family is set to NO_FAMILY) */ + return &this->public; + } + + this->endpoint = host->clone(host); + + if (base) + { + this->base = base->clone(base); + } + + return &this->public; +} + +/** + * Described in header + */ +endpoint_notify_t *endpoint_notify_create_from_payload(notify_payload_t *notify) +{ + if (notify->get_notify_type(notify) != ME_ENDPOINT) + { + return NULL; + } + + private_endpoint_notify_t *this = (private_endpoint_notify_t*)endpoint_notify_create(); + chunk_t data = notify->get_notification_data(notify); + if (parse_notification_data(this, data) != SUCCESS) + { + destroy(this); + return NULL; + } + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/endpoint_notify.h b/src/libcharon/encoding/payloads/endpoint_notify.h new file mode 100644 index 000000000..120eef49a --- /dev/null +++ b/src/libcharon/encoding/payloads/endpoint_notify.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * + * 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 endpoint_notify endpoint_notify + * @{ @ingroup payloads + */ + +#ifndef ENDPOINT_NOTIFY_H_ +#define ENDPOINT_NOTIFY_H_ + +#define ME_PRIO_HOST 255 +#define ME_PRIO_PEER 128 +#define ME_PRIO_SERVER 64 +#define ME_PRIO_RELAY 0 + +typedef enum me_endpoint_family_t me_endpoint_family_t; +typedef enum me_endpoint_type_t me_endpoint_type_t; +typedef struct endpoint_notify_t endpoint_notify_t; + +#include <encoding/payloads/notify_payload.h> + +/** + * ME endpoint families. + */ +enum me_endpoint_family_t { + + NO_FAMILY = 0, + + IPv4 = 1, + + IPv6 = 2, + + MAX_FAMILY = 3 + +}; + +/** + * ME endpoint types. + */ +enum me_endpoint_type_t { + + NO_TYPE = 0, + + HOST = 1, + + PEER_REFLEXIVE = 2, + + SERVER_REFLEXIVE = 3, + + RELAYED = 4, + + MAX_TYPE = 5 + +}; + +/** + * enum name for me_endpoint_type_t. + */ +extern enum_name_t *me_endpoint_type_names; + +/** + * Class representing a ME_ENDPOINT Notify payload. In fact it's not + * the notify per se, but the notification data of that notify that is + * handled with this class. + */ +struct endpoint_notify_t { + /** + * Returns the priority of this endpoint. + * + * @return priority + */ + u_int32_t (*get_priority) (endpoint_notify_t *this); + + /** + * Sets the priority of this endpoint. + * + * @param priority priority + */ + void (*set_priority) (endpoint_notify_t *this, u_int32_t priority); + + /** + * Returns the endpoint type of this endpoint. + * + * @return endpoint type + */ + me_endpoint_type_t (*get_type) (endpoint_notify_t *this); + + /** + * Returns the endpoint family of this endpoint. + * + * @return endpoint family + */ + me_endpoint_family_t (*get_family) (endpoint_notify_t *this); + + /** + * Returns the host of this endpoint. + * + * @return host + */ + host_t *(*get_host) (endpoint_notify_t *this); + + /** + * Returns the base of this endpoint. + * + * If this is not a SERVER_REFLEXIVE endpoint, the returned host is the same + * as the one returned by get_host. + * + * @return host + */ + host_t *(*get_base) (endpoint_notify_t *this); + + /** + * Generates a notification payload from this endpoint. + * + * @return built notify_payload_t + */ + notify_payload_t *(*build_notify) (endpoint_notify_t *this); + + /** + * Clones an endpoint_notify_t object. + * + * @return cloned object + */ + endpoint_notify_t *(*clone) (endpoint_notify_t *this); + + /** + * Destroys an endpoint_notify_t object. + */ + void (*destroy) (endpoint_notify_t *this); +}; + +/** + * Creates an empty endpoint_notify_t object. + * + * @return created endpoint_notify_t object + */ +endpoint_notify_t *endpoint_notify_create(void); + + +/** + * Creates an endpoint_notify_t object from a host. + * + * @param type the endpoint type + * @param host host to base the notify on (gets cloned) + * @param base base of the endpoint, applies only to reflexive endpoints (gets cloned) + * @return created endpoint_notify_t object + */ +endpoint_notify_t *endpoint_notify_create_from_host(me_endpoint_type_t type, + host_t *host, host_t *base); + +/** + * Creates an endpoint_notify_t object from a notify payload. + * + * @param notify the notify payload + * @return - created endpoint_notify_t object + * - NULL if invalid payload + */ +endpoint_notify_t *endpoint_notify_create_from_payload(notify_payload_t *notify); + +#endif /** ENDPOINT_NOTIFY_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c new file mode 100644 index 000000000..4158c3e07 --- /dev/null +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -0,0 +1,293 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * + * Hochschule fuer Technik Rapperswil + * + * 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 "id_payload.h" + +#include <daemon.h> +#include <encoding/payloads/encodings.h> + +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; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Type of the ID Data. + */ + u_int8_t id_type; + + /** + * The contained id data value. + */ + chunk_t id_data; +}; + +/** + * 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_rule_t id_payload_encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_id_payload_t, next_payload) }, + /* the critical bit */ + { FLAG, offsetof(private_id_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 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) }, + /* 3 reserved bytes */ + { RESERVED_BYTE, 0 }, + { RESERVED_BYTE, 0 }, + { RESERVED_BYTE, 0 }, + /* some id data bytes, length is defined in PAYLOAD_LENGTH */ + { ID_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 !C! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ID Type ! RESERVED | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Identification Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_id_payload_t *this) +{ + if ((this->id_type == 0) || + (this->id_type == 4) || + ((this->id_type >= 6) && (this->id_type <= 8)) || + ((this->id_type >= 12) && (this->id_type <= 200))) + { + /* reserved IDs */ + DBG1(DBG_ENC, "received ID with reserved type %d", this->id_type); + return FAILED; + } + + return SUCCESS; +} + +/** + * Implementation of id_payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_id_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = id_payload_encodings; + *rule_count = sizeof(id_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_payload_type(private_id_payload_t *this) +{ + return this->payload_type; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_id_payload_t *this) +{ + return this->next_payload; +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_id_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_id_payload_t *this) +{ + return this->payload_length; +} + +/** + * Implementation of id_payload_t.set_type. + */ +static void set_id_type (private_id_payload_t *this, id_type_t type) +{ + this->id_type = type; +} + +/** + * Implementation of id_payload_t.get_id_type. + */ +static id_type_t get_id_type (private_id_payload_t *this) +{ + return (this->id_type); +} + +/** + * Implementation of id_payload_t.set_data. + */ +static void set_data (private_id_payload_t *this, chunk_t data) +{ + if (this->id_data.ptr != NULL) + { + chunk_free(&(this->id_data)); + } + this->id_data.ptr = clalloc(data.ptr,data.len); + this->id_data.len = data.len; + this->payload_length = ID_PAYLOAD_HEADER_LENGTH + this->id_data.len; +} + + +/** + * Implementation of id_payload_t.get_data_clone. + */ +static chunk_t get_data (private_id_payload_t *this) +{ + return (this->id_data); +} + +/** + * Implementation of id_payload_t.get_data_clone. + */ +static chunk_t get_data_clone (private_id_payload_t *this) +{ + chunk_t cloned_data; + if (this->id_data.ptr == NULL) + { + return (this->id_data); + } + cloned_data.ptr = clalloc(this->id_data.ptr,this->id_data.len); + cloned_data.len = this->id_data.len; + return cloned_data; +} + +/** + * Implementation of id_payload_t.get_identification. + */ +static identification_t *get_identification (private_id_payload_t *this) +{ + return identification_create_from_encoding(this->id_type,this->id_data); +} + +/** + * Implementation of payload_t.destroy and id_payload_t.destroy. + */ +static void destroy(private_id_payload_t *this) +{ + if (this->id_data.ptr != NULL) + { + chunk_free(&(this->id_data)); + } + free(this); +} + +/* + * Described in header. + */ +id_payload_t *id_payload_create(payload_type_t payload_type) +{ + private_id_payload_t *this = malloc_thing(private_id_payload_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.destroy = (void (*) (id_payload_t *)) destroy; + this->public.set_id_type = (void (*) (id_payload_t *,id_type_t)) set_id_type; + this->public.get_id_type = (id_type_t (*) (id_payload_t *)) get_id_type; + this->public.set_data = (void (*) (id_payload_t *,chunk_t)) set_data; + this->public.get_data = (chunk_t (*) (id_payload_t *)) get_data; + this->public.get_data_clone = (chunk_t (*) (id_payload_t *)) get_data_clone; + + this->public.get_identification = (identification_t * (*) (id_payload_t *this)) get_identification; + + /* private variables */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length =ID_PAYLOAD_HEADER_LENGTH; + this->id_data = chunk_empty; + this->payload_type = payload_type; + + return (&(this->public)); +} + +/* + * Described in header. + */ +id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, identification_t *identification) +{ + id_payload_t *this= id_payload_create(payload_type); + this->set_data(this,identification->get_encoding(identification)); + this->set_id_type(this,identification->get_type(identification)); + return this; +} diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h new file mode 100644 index 000000000..5502dc961 --- /dev/null +++ b/src/libcharon/encoding/payloads/id_payload.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 id_payload id_payload + * @{ @ingroup payloads + */ + +#ifndef ID_PAYLOAD_H_ +#define ID_PAYLOAD_H_ + +typedef struct id_payload_t id_payload_t; + +#include <library.h> +#include <utils/identification.h> +#include <encoding/payloads/payload.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. + */ +struct id_payload_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Set the ID type. + * + * @param type Type of ID + */ + void (*set_id_type) (id_payload_t *this, id_type_t type); + + /** + * Get the ID type. + * + * @return type of the ID + */ + id_type_t (*get_id_type) (id_payload_t *this); + + /** + * Set the ID data. + * + * Data are getting cloned. + * + * @param data ID data as chunk_t + */ + void (*set_data) (id_payload_t *this, chunk_t data); + + /** + * Get the ID data. + * + * Returned data are a copy of the internal one + * + * @return ID data as chunk_t + */ + chunk_t (*get_data_clone) (id_payload_t *this); + + /** + * Get the ID data. + * + * Returned data are NOT copied. + * + * @return ID data as chunk_t + */ + chunk_t (*get_data) (id_payload_t *this); + + /** + * Creates an identification object of this id payload. + * + * Returned object has to get destroyed by the caller. + * + * @return identification_t object + */ + identification_t *(*get_identification) (id_payload_t *this); + + /** + * Destroys an id_payload_t object. + */ + void (*destroy) (id_payload_t *this); +}; + +/** + * Creates an empty id_payload_t object. + * + * @param payload_type one of ID_INITIATOR, ID_RESPONDER + * @return id_payload_t object + */ +id_payload_t *id_payload_create(payload_type_t payload_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 + */ +id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, + identification_t *identification); + +#endif /** ID_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/ike_header.c b/src/libcharon/encoding/payloads/ike_header.c new file mode 100644 index 000000000..735f01304 --- /dev/null +++ b/src/libcharon/encoding/payloads/ike_header.c @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/* offsetof macro */ +#include <stddef.h> + +#include "ike_header.h" + +#include <encoding/payloads/encodings.h> + + +typedef struct private_ike_header_t private_ike_header_t; + +/** + * Private data of an ike_header_t object. + */ +struct private_ike_header_t { + /** + * Public interface. + */ + ike_header_t public; + + /** + * SPI of the initiator. + */ + u_int64_t initiator_spi; + + /** + * SPI of the responder. + */ + u_int64_t responder_spi; + + /** + * Next payload type. + */ + u_int8_t next_payload; + /** + * IKE major version. + */ + u_int8_t maj_version; + + /** + * IKE minor version. + */ + u_int8_t min_version; + + /** + * Exchange type . + */ + u_int8_t exchange_type; + + /** + * Flags of the Message. + */ + struct { + /** + * Sender is initiator of the associated IKE_SA_INIT-Exchange. + */ + bool initiator; + + /** + * Is protocol supporting higher version? + */ + bool version; + + /** + * TRUE, if this is a response, FALSE if its a Request. + */ + bool response; + } flags; + + /** + * Associated Message-ID. + */ + u_int32_t message_id; + + /** + * Length of the whole IKEv2-Message (header and all payloads). + */ + 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, INFORMATIONAL, EXCHANGE_TYPE_UNDEFINED, + "IKE_SA_INIT", + "IKE_AUTH", + "CREATE_CHILD_SA", + "INFORMATIONAL"); +#ifdef ME +ENUM_NEXT(exchange_type_names, ME_CONNECT, ME_CONNECT, INFORMATIONAL, + "ME_CONNECT"); +ENUM_END(exchange_type_names, ME_CONNECT); +#else +ENUM_END(exchange_type_names, INFORMATIONAL); +#endif /* ME */ + +/** + * Encoding rules to parse or generate a IKEv2-Header. + * + * The defined offsets are the positions in a object of type + * ike_header_t. + */ +encoding_rule_t ike_header_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 */ + { IKE_SPI, offsetof(private_ike_header_t, responder_spi) }, + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_ike_header_t, next_payload) }, + /* 4 Bit major version, stored in the field maj_version */ + { U_INT_4, offsetof(private_ike_header_t, maj_version) }, + /* 4 Bit minor version, stored in the field min_version */ + { U_INT_4, offsetof(private_ike_header_t, min_version) }, + /* 8 Bit for the exchange type */ + { U_INT_8, offsetof(private_ike_header_t, exchange_type) }, + /* 2 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* 3 Bit flags, stored in the fields response, version and initiator */ + { 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, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* 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) } +}; + + +/* 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 ! + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! IKE_SA Responder's SPI ! + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! MjVer ! MnVer ! Exchange Type ! Flags ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Message ID ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_ike_header_t *this) +{ + if ((this->exchange_type < IKE_SA_INIT) || + ((this->exchange_type > INFORMATIONAL) +#ifdef ME + && (this->exchange_type != ME_CONNECT) +#endif /* ME */ + )) + { + /* unsupported exchange type */ + return FAILED; + } + + if (this->initiator_spi == 0 +#ifdef ME + /* we allow zero spi for INFORMATIONAL exchanges, + * to allow connectivity checks */ + && this->exchange_type != INFORMATIONAL +#endif /* ME */ + ) + { + /* initiator spi not set */ + return FAILED; + } + + /* verification of version is not done in here */ + + return SUCCESS; +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(payload_t *this,payload_type_t type) +{ + ((private_ike_header_t *)this)->next_payload = type; +} +/** + * Implementation of ike_header_t.get_initiator_spi. + */ +static u_int64_t get_initiator_spi(private_ike_header_t *this) +{ + return this->initiator_spi; +} + +/** + * Implementation of ike_header_t.set_initiator_spi. + */ +static void set_initiator_spi(private_ike_header_t *this, u_int64_t initiator_spi) +{ + this->initiator_spi = initiator_spi; +} + +/** + * Implementation of ike_header_t.get_responder_spi. + */ +static u_int64_t get_responder_spi(private_ike_header_t *this) +{ + return this->responder_spi; +} + +/** + * Implementation of ike_header_t.set_responder_spi. + */ +static void set_responder_spi(private_ike_header_t *this, u_int64_t responder_spi) +{ + this->responder_spi = responder_spi; +} + +/** + * Implementation of ike_header_t.get_maj_version. + */ +static u_int8_t get_maj_version(private_ike_header_t *this) +{ + return this->maj_version; +} + +/** + * Implementation of ike_header_t.get_min_version. + */ +static u_int8_t get_min_version(private_ike_header_t *this) +{ + return this->min_version; +} + +/** + * Implementation of ike_header_t.get_response_flag. + */ +static bool get_response_flag(private_ike_header_t *this) +{ + return this->flags.response; +} + +/** + * Implementation of ike_header_t.set_response_flag. + */ +static void set_response_flag(private_ike_header_t *this, bool response) +{ + this->flags.response = response; +} + +/** + * Implementation of ike_header_t.get_version_flag. + */ +static bool get_version_flag(private_ike_header_t *this) +{ + return this->flags.version; +} + +/** + * Implementation of ike_header_t.get_initiator_flag. + */ +static bool get_initiator_flag(private_ike_header_t *this) +{ + return this->flags.initiator; +} + +/** + * Implementation of ike_header_t.set_initiator_flag. + */ +static void set_initiator_flag(private_ike_header_t *this, bool initiator) +{ + this->flags.initiator = initiator; +} + +/** + * Implementation of ike_header_t.get_exchange_type. + */ +static u_int8_t get_exchange_type(private_ike_header_t *this) +{ + return this->exchange_type; +} + +/** + * Implementation of ike_header_t.set_exchange_type. + */ +static void set_exchange_type(private_ike_header_t *this, u_int8_t exchange_type) +{ + this->exchange_type = exchange_type; +} + +/** + * Implements ike_header_t's get_message_id function. + * See #ike_header_t.get_message_id for description. + */ +static u_int32_t get_message_id(private_ike_header_t *this) +{ + return this->message_id; +} + +/** + * Implementation of ike_header_t.set_message_id. + */ +static void set_message_id(private_ike_header_t *this, u_int32_t message_id) +{ + this->message_id = message_id; +} + +/** + * Implementation of ike_header_t.destroy and payload_t.destroy. + */ +static void destroy(ike_header_t *this) +{ + free(this); +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = ike_header_encodings; + *rule_count = sizeof(ike_header_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(payload_t *this) +{ + return HEADER; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(payload_t *this) +{ + return (((private_ike_header_t*)this)->next_payload); +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(payload_t *this) +{ + return (((private_ike_header_t*)this)->length); +} + +/* + * Described in header. + */ +ike_header_t *ike_header_create() +{ + private_ike_header_t *this = malloc_thing(private_ike_header_t); + + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = get_encoding_rules; + this->public.payload_interface.get_length = get_length; + this->public.payload_interface.get_next_type = get_next_type; + this->public.payload_interface.set_next_type = set_next_type; + this->public.payload_interface.get_type = get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + this->public.destroy = destroy; + + this->public.get_initiator_spi = (u_int64_t (*) (ike_header_t*))get_initiator_spi; + this->public.set_initiator_spi = (void (*) (ike_header_t*,u_int64_t))set_initiator_spi; + this->public.get_responder_spi = (u_int64_t (*) (ike_header_t*))get_responder_spi; + this->public.set_responder_spi = (void (*) (ike_header_t *,u_int64_t))set_responder_spi; + this->public.get_maj_version = (u_int8_t (*) (ike_header_t*))get_maj_version; + this->public.get_min_version = (u_int8_t (*) (ike_header_t*))get_min_version; + this->public.get_response_flag = (bool (*) (ike_header_t*))get_response_flag; + this->public.set_response_flag = (void (*) (ike_header_t*,bool))set_response_flag; + this->public.get_version_flag = (bool (*) (ike_header_t*))get_version_flag; + this->public.get_initiator_flag = (bool (*) (ike_header_t*))get_initiator_flag; + this->public.set_initiator_flag = (void (*) (ike_header_t*,bool))set_initiator_flag; + this->public.get_exchange_type = (u_int8_t (*) (ike_header_t*))get_exchange_type; + this->public.set_exchange_type = (void (*) (ike_header_t*,u_int8_t))set_exchange_type; + this->public.get_message_id = (u_int32_t (*) (ike_header_t*))get_message_id; + this->public.set_message_id = (void (*) (ike_header_t*,u_int32_t))set_message_id; + + /* set default values of the fields */ + this->initiator_spi = 0; + this->responder_spi = 0; + this->next_payload = 0; + this->maj_version = IKE_MAJOR_VERSION; + this->min_version = IKE_MINOR_VERSION; + this->exchange_type = EXCHANGE_TYPE_UNDEFINED; + this->flags.initiator = TRUE; + this->flags.version = HIGHER_VERSION_SUPPORTED_FLAG; + this->flags.response = FALSE; + this->message_id = 0; + this->length = IKE_HEADER_LENGTH; + + return (ike_header_t*)this; +} diff --git a/src/libcharon/encoding/payloads/ike_header.h b/src/libcharon/encoding/payloads/ike_header.h new file mode 100644 index 000000000..e63e8bf06 --- /dev/null +++ b/src/libcharon/encoding/payloads/ike_header.h @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 ike_header ike_header + * @{ @ingroup payloads + */ + +#ifndef IKE_HEADER_H_ +#define IKE_HEADER_H_ + +typedef enum exchange_type_t exchange_type_t; +typedef struct ike_header_t ike_header_t; + +#include <library.h> +#include <encoding/payloads/payload.h> + +/** + * Major Version of IKEv2. + */ +#define IKE_MAJOR_VERSION 2 + +/** + * Minor Version of IKEv2. + */ +#define IKE_MINOR_VERSION 0 + +/** + * Flag in IKEv2-Header. Always 0. + */ +#define HIGHER_VERSION_SUPPORTED_FLAG 0 + +/** + * Length of IKE Header in Bytes. + */ +#define IKE_HEADER_LENGTH 28 + +/** + * Different types of IKE-Exchanges. + * + * See RFC for different types. + */ +enum exchange_type_t{ + + /** + * EXCHANGE_TYPE_UNDEFINED. In private space, since not a official message type. + */ + EXCHANGE_TYPE_UNDEFINED = 255, + + /** + * IKE_SA_INIT. + */ + IKE_SA_INIT = 34, + + /** + * IKE_AUTH. + */ + IKE_AUTH = 35, + + /** + * CREATE_CHILD_SA. + */ + CREATE_CHILD_SA = 36, + + /** + * INFORMATIONAL. + */ + INFORMATIONAL = 37, +#ifdef ME + /** + * ME_CONNECT + */ + ME_CONNECT = 240 +#endif /* ME */ +}; + +/** + * enum name for 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. + */ +struct ike_header_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the initiator spi. + * + * @return initiator_spi + */ + u_int64_t (*get_initiator_spi) (ike_header_t *this); + + /** + * Set the initiator spi. + * + * @param initiator_spi initiator_spi + */ + void (*set_initiator_spi) (ike_header_t *this, u_int64_t initiator_spi); + + /** + * Get the responder spi. + * + * @return responder_spi + */ + u_int64_t (*get_responder_spi) (ike_header_t *this); + + /** + * Set the responder spi. + * + * @param responder_spi responder_spi + */ + void (*set_responder_spi) (ike_header_t *this, u_int64_t responder_spi); + + /** + * Get the major version. + * + * @return major version + */ + u_int8_t (*get_maj_version) (ike_header_t *this); + + /** + * Get the minor version. + * + * @return minor version + */ + u_int8_t (*get_min_version) (ike_header_t *this); + + /** + * Get the response flag. + * + * @return response flag + */ + bool (*get_response_flag) (ike_header_t *this); + + /** + * Set the response flag- + * + * @param response response flag + */ + void (*set_response_flag) (ike_header_t *this, bool response); + /** + * Get "higher version supported"-flag. + * + * @return version flag + */ + bool (*get_version_flag) (ike_header_t *this); + + /** + * Get the initiator flag. + * + * @return initiator flag + */ + bool (*get_initiator_flag) (ike_header_t *this); + + /** + * Set the initiator flag. + * + * @param initiator initiator flag + */ + void (*set_initiator_flag) (ike_header_t *this, bool initiator); + + /** + * Get the exchange type. + * + * @return exchange type + */ + u_int8_t (*get_exchange_type) (ike_header_t *this); + + /** + * Set the exchange type. + * + * @param exchange_type exchange type + */ + void (*set_exchange_type) (ike_header_t *this, u_int8_t exchange_type); + + /** + * Get the message id. + * + * @return message id + */ + u_int32_t (*get_message_id) (ike_header_t *this); + + /** + * Set the message id. + * + * @param initiator_spi message id + */ + void (*set_message_id) (ike_header_t *this, u_int32_t message_id); + + /** + * Destroys a ike_header_t object. + */ + void (*destroy) (ike_header_t *this); +}; + +/** + * Create an ike_header_t object + * + * @return ike_header_t object + */ +ike_header_t *ike_header_create(void); + +#endif /** IKE_HEADER_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/ke_payload.c b/src/libcharon/encoding/payloads/ke_payload.c new file mode 100644 index 000000000..1bc79f084 --- /dev/null +++ b/src/libcharon/encoding/payloads/ke_payload.c @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "ke_payload.h" + +#include <encoding/payloads/encodings.h> + + +typedef struct private_ke_payload_t private_ke_payload_t; + +/** + * Private data of an ke_payload_t object. + * + */ +struct private_ke_payload_t { + /** + * Public ke_payload_t interface. + */ + ke_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * DH Group Number. + */ + u_int16_t dh_group_number; + + /** + * Key Exchange Data of this KE payload. + */ + chunk_t key_exchange_data; +}; + +/** + * 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_rule_t ke_payload_encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_ke_payload_t, next_payload) }, + /* the critical bit */ + { FLAG, offsetof(private_ke_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_ke_payload_t, payload_length) }, + /* DH Group number as 16 bit field*/ + { U_INT_16, offsetof(private_ke_payload_t, dh_group_number) }, + { RESERVED_BYTE, 0 }, + { RESERVED_BYTE, 0 }, + /* Key Exchange Data is from variable size */ + { KEY_EXCHANGE_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 !C! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DH Group # ! RESERVED ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Key Exchange Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_ke_payload_t *this) +{ + /* dh group is not verified in here */ + return SUCCESS; +} + +/** + * Implementation of payload_t.destroy. + */ +static void destroy(private_ke_payload_t *this) +{ + if (this->key_exchange_data.ptr != NULL) + { + free(this->key_exchange_data.ptr); + } + free(this); +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_ke_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = ke_payload_encodings; + *rule_count = sizeof(ke_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_ke_payload_t *this) +{ + return KEY_EXCHANGE; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_ke_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_ke_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * recompute the length of the payload. + */ +static void compute_length(private_ke_payload_t *this) +{ + size_t length = KE_PAYLOAD_HEADER_LENGTH; + if (this->key_exchange_data.ptr != NULL) + { + length += this->key_exchange_data.len; + } + this->payload_length = length; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_ke_payload_t *this) +{ + compute_length(this); + return this->payload_length; +} + +/** + * Implementation of ke_payload_t.get_key_exchange_data. + */ +static chunk_t get_key_exchange_data(private_ke_payload_t *this) +{ + return (this->key_exchange_data); +} + +/** + * Implementation of ke_payload_t.set_key_exchange_data. + */ +static void set_key_exchange_data(private_ke_payload_t *this, chunk_t key_exchange_data) +{ + /* destroy existing data first */ + if (this->key_exchange_data.ptr != NULL) + { + /* free existing value */ + free(this->key_exchange_data.ptr); + this->key_exchange_data.ptr = NULL; + this->key_exchange_data.len = 0; + + } + + this->key_exchange_data = chunk_clone(key_exchange_data); + compute_length(this); +} + +/** + * Implementation of ke_payload_t.get_dh_group_number. + */ +static diffie_hellman_group_t get_dh_group_number(private_ke_payload_t *this) +{ + return this->dh_group_number; +} + +/** + * Implementation of ke_payload_t.set_dh_group_number. + */ +static void set_dh_group_number(private_ke_payload_t *this, diffie_hellman_group_t dh_group_number) +{ + this->dh_group_number = dh_group_number; +} + +/* + * Described in header + */ +ke_payload_t *ke_payload_create() +{ + private_ke_payload_t *this = malloc_thing(private_ke_payload_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.get_key_exchange_data = (chunk_t (*) (ke_payload_t *)) get_key_exchange_data; + this->public.set_key_exchange_data = (void (*) (ke_payload_t *,chunk_t)) set_key_exchange_data; + this->public.get_dh_group_number = (diffie_hellman_group_t (*) (ke_payload_t *)) get_dh_group_number; + this->public.set_dh_group_number =(void (*) (ke_payload_t *,diffie_hellman_group_t)) set_dh_group_number; + this->public.destroy = (void (*) (ke_payload_t *)) destroy; + + /* set default values of the fields */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = KE_PAYLOAD_HEADER_LENGTH; + this->key_exchange_data = chunk_empty; + this->dh_group_number = MODP_NONE; + + return &this->public; +} + +/* + * Described in header + */ +ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *dh) +{ + private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create(); + + dh->get_my_public_value(dh, &this->key_exchange_data); + this->dh_group_number = dh->get_dh_group(dh); + compute_length(this); + + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/ke_payload.h b/src/libcharon/encoding/payloads/ke_payload.h new file mode 100644 index 000000000..3ca05009e --- /dev/null +++ b/src/libcharon/encoding/payloads/ke_payload.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 ke_payload ke_payload + * @{ @ingroup payloads + */ + +#ifndef KE_PAYLOAD_H_ +#define KE_PAYLOAD_H_ + +typedef struct ke_payload_t ke_payload_t; + +#include <library.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/transform_substructure.h> +#include <utils/linked_list.h> +#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. + */ +struct ke_payload_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Returns the currently set key exchange data of this KE payload. + * + * @warning Returned data are not copied. + * + * @return chunk_t pointing to the value + */ + chunk_t (*get_key_exchange_data) (ke_payload_t *this); + + /** + * Sets the key exchange data of this KE payload. + * + * Value is getting copied. + * + * @param key_exchange_data chunk_t pointing to the value to set + */ + void (*set_key_exchange_data) (ke_payload_t *this, chunk_t key_exchange_data); + + /** + * Gets the Diffie-Hellman Group Number of this KE payload. + * + * @return DH Group Number of this payload + */ + diffie_hellman_group_t (*get_dh_group_number) (ke_payload_t *this); + + /** + * Sets the Diffie-Hellman Group Number of this KE payload. + * + * @param dh_group_number DH Group to set + */ + void (*set_dh_group_number) (ke_payload_t *this, + diffie_hellman_group_t dh_group_number); + + /** + * Destroys an ke_payload_t object. + */ + void (*destroy) (ke_payload_t *this); +}; + +/** + * Creates an empty ke_payload_t object + * + * @return ke_payload_t object + */ +ke_payload_t *ke_payload_create(void); + +/** + * 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 + */ +ke_payload_t *ke_payload_create_from_diffie_hellman( + diffie_hellman_t *diffie_hellman); + +#endif /** KE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/nonce_payload.c b/src/libcharon/encoding/payloads/nonce_payload.c new file mode 100644 index 000000000..4ad5ce9dd --- /dev/null +++ b/src/libcharon/encoding/payloads/nonce_payload.c @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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. + */ + +/* offsetof macro */ +#include <stddef.h> + +#include "nonce_payload.h" + +#include <encoding/payloads/encodings.h> + + +typedef struct private_nonce_payload_t private_nonce_payload_t; + +/** + * Private data of an nonce_payload_t object. + * + */ +struct private_nonce_payload_t { + /** + * Public nonce_payload_t interface. + */ + nonce_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * The contained nonce value. + */ + chunk_t nonce; +}; + +/** + * Encoding rules to parse or generate a nonce payload + * + * The defined offsets are the positions in a object of type + * private_nonce_payload_t. + * + */ +encoding_rule_t nonce_payload_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 */ + { FLAG, offsetof(private_nonce_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* 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) } +}; + +/* 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Nonce Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_nonce_payload_t *this) +{ + if ((this->nonce.len < 16) || ((this->nonce.len > 256))) + { + /* nonce length is wrong */ + return FAILED; + } + + return SUCCESS; +} + +/** + * Implementation of nonce_payload_t.set_nonce. + */ +static status_t set_nonce(private_nonce_payload_t *this, chunk_t nonce) +{ + this->nonce.ptr = clalloc(nonce.ptr, nonce.len); + this->nonce.len = nonce.len; + this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + nonce.len; + return SUCCESS; +} + +/** + * Implementation of nonce_payload_t.get_nonce. + */ +static chunk_t get_nonce(private_nonce_payload_t *this) +{ + chunk_t nonce; + nonce.ptr = clalloc(this->nonce.ptr,this->nonce.len); + nonce.len = this->nonce.len; + return nonce; +} + +/** + * Implementation of nonce_payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_nonce_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = nonce_payload_encodings; + *rule_count = sizeof(nonce_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_nonce_payload_t *this) +{ + return NONCE; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_nonce_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_nonce_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * recompute the length of the payload. + */ +static void compute_length(private_nonce_payload_t *this) +{ + this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + this->nonce.len; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_nonce_payload_t *this) +{ + compute_length(this); + return this->payload_length; +} + +/** + * Implementation of payload_t.destroy and nonce_payload_t.destroy. + */ +static void destroy(private_nonce_payload_t *this) +{ + if (this->nonce.ptr != NULL) + { + free(this->nonce.ptr); + } + + free(this); +} + +/* + * Described in header + */ +nonce_payload_t *nonce_payload_create() +{ + private_nonce_payload_t *this = malloc_thing(private_nonce_payload_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.destroy = (void (*) (nonce_payload_t *)) destroy; + this->public.set_nonce = (void (*) (nonce_payload_t *,chunk_t)) set_nonce; + this->public.get_nonce = (chunk_t (*) (nonce_payload_t *)) get_nonce; + + /* private variables */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH; + this->nonce.ptr = NULL; + this->nonce.len = 0; + + return (&(this->public)); +} + + diff --git a/src/libcharon/encoding/payloads/nonce_payload.h b/src/libcharon/encoding/payloads/nonce_payload.h new file mode 100644 index 000000000..e9212202e --- /dev/null +++ b/src/libcharon/encoding/payloads/nonce_payload.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 nonce_payload nonce_payload + * @{ @ingroup payloads + */ + +#ifndef NONCE_PAYLOAD_H_ +#define NONCE_PAYLOAD_H_ + +typedef struct nonce_payload_t nonce_payload_t; + +#include <library.h> +#include <encoding/payloads/payload.h> + +/** + * Nonce size in bytes for nonces sending to other peer. + */ +#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. + */ +struct nonce_payload_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Set the nonce value. + * + * @param nonce chunk containing the nonce, will be cloned + */ + void (*set_nonce) (nonce_payload_t *this, chunk_t nonce); + + /** + * Get the nonce value. + * + * @return a chunk containing the cloned nonce + */ + chunk_t (*get_nonce) (nonce_payload_t *this); + + /** + * Destroys an nonce_payload_t object. + */ + void (*destroy) (nonce_payload_t *this); +}; + +/** + * Creates an empty nonce_payload_t object + * + * @return nonce_payload_t object + */ +nonce_payload_t *nonce_payload_create(void); + +#endif /** NONCE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c new file mode 100644 index 000000000..469698ef5 --- /dev/null +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -0,0 +1,617 @@ +/* + * Copyright (C) 2006-2008 Tobias Brunner + * Copyright (C) 2006 Daniel Roethlisberger + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "notify_payload.h" + +#include <daemon.h> +#include <encoding/payloads/encodings.h> +#include <crypto/hashers/hasher.h> + +ENUM_BEGIN(notify_type_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD, + "UNSUPPORTED_CRITICAL_PAYLOAD"); +ENUM_NEXT(notify_type_names, INVALID_IKE_SPI, INVALID_MAJOR_VERSION, UNSUPPORTED_CRITICAL_PAYLOAD, + "INVALID_IKE_SPI", + "INVALID_MAJOR_VERSION"); +ENUM_NEXT(notify_type_names, INVALID_SYNTAX, INVALID_SYNTAX, INVALID_MAJOR_VERSION, + "INVALID_SYNTAX"); +ENUM_NEXT(notify_type_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYNTAX, + "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, + "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, + "AUTHENTICATION_FAILED"); +ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, USE_ASSIGNED_HoA, AUTHENTICATION_FAILED, + "SINGLE_PAIR_REQUIRED", + "NO_ADDITIONAL_SAS", + "INTERNAL_ADDRESS_FAILURE", + "FAILED_CP_REQUIRED", + "TS_UNACCEPTABLE", + "INVALID_SELECTORS", + "UNACCEPTABLE_ADDRESSES", + "UNEXPECTED_NAT_DETECTED", + "USE_ASSIGNED_HoA"); +ENUM_NEXT(notify_type_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, USE_ASSIGNED_HoA, + "ME_CONNECT_FAILED"); +ENUM_NEXT(notify_type_names, INITIAL_CONTACT, LINK_ID, ME_CONNECT_FAILED, + "INITIAL_CONTACT", + "SET_WINDOW_SIZE", + "ADDITIONAL_TS_POSSIBLE", + "IPCOMP_SUPPORTED", + "NAT_DETECTION_SOURCE_IP", + "NAT_DETECTION_DESTINATION_IP", + "COOKIE", + "USE_TRANSPORT_MODE", + "HTTP_CERT_LOOKUP_SUPPORTED", + "REKEY_SA", + "ESP_TFC_PADDING_NOT_SUPPORTED", + "NON_FIRST_FRAGMENTS_ALSO", + "MOBIKE_SUPPORTED", + "ADDITIONAL_IP4_ADDRESS", + "ADDITIONAL_IP6_ADDRESS", + "NO_ADDITIONAL_ADDRESSES", + "UPDATE_SA_ADDRESSES", + "COOKIE2", + "NO_NATS_ALLOWED", + "AUTH_LIFETIME", + "MULTIPLE_AUTH_SUPPORTED", + "ANOTHER_AUTH_FOLLOWS", + "REDIRECT_SUPPORTED", + "REDIRECT", + "REDIRECTED_FROM", + "TICKET_LT_OPAQUE", + "TICKET_REQUEST", + "TICKET_ACK", + "TICKET_NACK", + "TICKET_OPAQUE", + "LINK_ID"); +ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, LINK_ID, + "EAP_ONLY_AUTHENTICATION"); +ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION, + "USE_BEET_MODE"); +ENUM_NEXT(notify_type_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE, + "ME_MEDIATION", + "ME_ENDPOINT", + "ME_CALLBACK", + "ME_CONNECTID", + "ME_CONNECTKEY", + "ME_CONNECTAUTH", + "ME_RESPONSE"); +ENUM_END(notify_type_names, ME_RESPONSE); + + +ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD, + "CRIT"); +ENUM_NEXT(notify_type_short_names, INVALID_IKE_SPI, INVALID_MAJOR_VERSION, UNSUPPORTED_CRITICAL_PAYLOAD, + "INVAL_IKE_SPI", + "INVAL_MAJOR"); +ENUM_NEXT(notify_type_short_names, INVALID_SYNTAX, INVALID_SYNTAX, INVALID_MAJOR_VERSION, + "INVAL_SYN"); +ENUM_NEXT(notify_type_short_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYNTAX, + "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, + "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, + "AUTH_FAILED"); +ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, USE_ASSIGNED_HoA, AUTHENTICATION_FAILED, + "SINGLE_PAIR", + "NO_ADD_SAS", + "INT_ADDR_FAIL", + "FAIL_CP_REQ", + "TS_UNACCEPT", + "INVAL_SEL", + "UNACCEPT_ADDR", + "UNEXPECT_NAT", + "ASSIGNED_HoA"); +ENUM_NEXT(notify_type_short_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, USE_ASSIGNED_HoA, + "ME_CONN_FAIL"); +ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, LINK_ID, ME_CONNECT_FAILED, + "INIT_CONTACT", + "SET_WINSIZE", + "ADD_TS_POSS", + "IPCOMP_SUPP", + "NATD_S_IP", + "NATD_D_IP", + "COOKIE", + "USE_TRANSP", + "HTTP_CERT_LOOK", + "REKEY_SA", + "ESP_TFC_PAD_N", + "NON_FIRST_FRAG", + "MOBIKE_SUP", + "ADD_4_ADDR", + "ADD_6_ADDR", + "NO_ADD_ADDR", + "UPD_SA_ADDR", + "COOKIE2", + "NO_NATS", + "AUTH_LFT", + "MULT_AUTH", + "AUTH_FOLLOWS", + "REDIR_SUP", + "REDIR", + "REDIR_FROM", + "TKT_LT_OPAK", + "TKT_REQ", + "TKT_ACK", + "TKT_NACK", + "TKT_OPAK", + "LINK_ID"); +ENUM_NEXT(notify_type_short_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, LINK_ID, + "EAP_ONLY"); +ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION, + "BEET_MODE"); +ENUM_NEXT(notify_type_short_names, ME_MEDIATION, ME_RESPONSE, USE_BEET_MODE, + "ME_MED", + "ME_EP", + "ME_CB", + "ME_CID", + "ME_CKEY", + "ME_CAUTH", + "ME_R"); +ENUM_END(notify_type_short_names, ME_RESPONSE); + + +typedef struct private_notify_payload_t private_notify_payload_t; + +/** + * Private data of an notify_payload_t object. + * + */ +struct private_notify_payload_t { + /** + * Public notify_payload_t interface. + */ + notify_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Protocol id. + */ + u_int8_t protocol_id; + + /** + * Spi size. + */ + u_int8_t spi_size; + + /** + * Notify message type. + */ + u_int16_t notify_type; + + /** + * Security parameter index (spi). + */ + chunk_t spi; + + /** + * Notification data. + */ + chunk_t notification_data; +}; + +/** + * 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_rule_t notify_payload_encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, + /* the critical bit */ + { FLAG, offsetof(private_notify_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* Length of the whole payload*/ + { 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) }, + /* 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 */ + { NOTIFICATION_DATA, offsetof(private_notify_payload_t, notification_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 !C! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Protocol ID ! SPI Size ! Notify Message Type ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Security Parameter Index (SPI) ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Notification Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_notify_payload_t *this) +{ + bool bad_length = FALSE; + + switch (this->protocol_id) + { + case PROTO_NONE: + case PROTO_IKE: + case PROTO_AH: + case PROTO_ESP: + break; + default: + DBG1(DBG_ENC, "Unknown protocol (%d)", this->protocol_id); + return FAILED; + } + + switch (this->notify_type) + { + case INVALID_KE_PAYLOAD: + { + if (this->notification_data.len != 2) + { + bad_length = TRUE; + } + break; + } + case NAT_DETECTION_SOURCE_IP: + case NAT_DETECTION_DESTINATION_IP: + case ME_CONNECTAUTH: + { + if (this->notification_data.len != HASH_SIZE_SHA1) + { + bad_length = TRUE; + } + break; + } + case INVALID_SYNTAX: + case INVALID_MAJOR_VERSION: + case NO_PROPOSAL_CHOSEN: + { + if (this->notification_data.len != 0) + { + bad_length = TRUE; + } + break; + } + case ADDITIONAL_IP4_ADDRESS: + { + if (this->notification_data.len != 4) + { + bad_length = TRUE; + } + break; + } + case ADDITIONAL_IP6_ADDRESS: + { + if (this->notification_data.len != 16) + { + bad_length = TRUE; + } + break; + } + case AUTH_LIFETIME: + { + if (this->notification_data.len != 4) + { + bad_length = TRUE; + } + break; + } + case IPCOMP_SUPPORTED: + { + if (this->notification_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) + { + bad_length = TRUE; + } + break; + case ME_CONNECTID: + if (this->notification_data.len < 4 || + this->notification_data.len > 16) + { + bad_length = TRUE; + } + break; + case ME_CONNECTKEY: + if (this->notification_data.len < 16 || + this->notification_data.len > 32) + { + bad_length = TRUE; + } + break; + default: + /* TODO: verify */ + break; + } + if (bad_length) + { + DBG1(DBG_ENC, "invalid notify data length for %N (%d)", + notify_type_names, this->notify_type, + this->notification_data.len); + return FAILED; + } + return SUCCESS; +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_notify_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = notify_payload_encodings; + *rule_count = sizeof(notify_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_notify_payload_t *this) +{ + return NOTIFY; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_notify_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_notify_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * recompute the payloads length. + */ +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; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_notify_payload_t *this) +{ + compute_length(this); + return this->payload_length; +} + +/** + * Implementation of notify_payload_t.get_protocol_id. + */ +static u_int8_t get_protocol_id(private_notify_payload_t *this) +{ + return this->protocol_id; +} + +/** + * Implementation of notify_payload_t.set_protocol_id. + */ +static void set_protocol_id(private_notify_payload_t *this, u_int8_t protocol_id) +{ + this->protocol_id = protocol_id; +} + +/** + * Implementation of notify_payload_t.get_notify_type. + */ +static notify_type_t get_notify_type(private_notify_payload_t *this) +{ + return this->notify_type; +} + +/** + * Implementation of notify_payload_t.set_notify_type. + */ +static void set_notify_type(private_notify_payload_t *this, u_int16_t notify_type) +{ + this->notify_type = notify_type; +} + +/** + * Implementation of notify_payload_t.get_spi. + */ +static u_int32_t get_spi(private_notify_payload_t *this) +{ + switch (this->protocol_id) + { + case PROTO_AH: + case PROTO_ESP: + if (this->spi.len == 4) + { + return *((u_int32_t*)this->spi.ptr); + } + default: + break; + } + return 0; +} + +/** + * Implementation of notify_payload_t.set_spi. + */ +static void set_spi(private_notify_payload_t *this, u_int32_t spi) +{ + chunk_free(&this->spi); + switch (this->protocol_id) + { + case PROTO_AH: + case PROTO_ESP: + this->spi = chunk_alloc(4); + *((u_int32_t*)this->spi.ptr) = spi; + break; + default: + break; + } + this->spi_size = this->spi.len; + compute_length(this); +} + +/** + * Implementation of notify_payload_t.get_notification_data. + */ +static chunk_t get_notification_data(private_notify_payload_t *this) +{ + return (this->notification_data); +} + +/** + * Implementation of notify_payload_t.set_notification_data. + */ +static status_t set_notification_data(private_notify_payload_t *this, chunk_t notification_data) +{ + chunk_free(&this->notification_data); + if (notification_data.len > 0) + { + this->notification_data = chunk_clone(notification_data); + } + compute_length(this); + return SUCCESS; +} + +/** + * Implementation of notify_payload_t.destroy and notify_payload_t.destroy. + */ +static status_t destroy(private_notify_payload_t *this) +{ + chunk_free(&this->notification_data); + chunk_free(&this->spi); + free(this); + return SUCCESS; +} + +/* + * Described in header + */ +notify_payload_t *notify_payload_create() +{ + private_notify_payload_t *this = malloc_thing(private_notify_payload_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.get_protocol_id = (u_int8_t (*) (notify_payload_t *)) get_protocol_id; + this->public.set_protocol_id = (void (*) (notify_payload_t *,u_int8_t)) set_protocol_id; + this->public.get_notify_type = (notify_type_t (*) (notify_payload_t *)) get_notify_type; + this->public.set_notify_type = (void (*) (notify_payload_t *,notify_type_t)) set_notify_type; + this->public.get_spi = (u_int32_t (*) (notify_payload_t *)) get_spi; + this->public.set_spi = (void (*) (notify_payload_t *,u_int32_t)) set_spi; + this->public.get_notification_data = (chunk_t (*) (notify_payload_t *)) get_notification_data; + this->public.set_notification_data = (void (*) (notify_payload_t *,chunk_t)) set_notification_data; + this->public.destroy = (void (*) (notify_payload_t *)) destroy; + + /* set default values of the fields */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH; + this->protocol_id = 0; + this->notify_type = 0; + this->spi.ptr = NULL; + this->spi.len = 0; + this->spi_size = 0; + this->notification_data.ptr = NULL; + this->notification_data.len = 0; + + return &this->public; +} + +/* + * Described in header. + */ +notify_payload_t *notify_payload_create_from_protocol_and_type(protocol_id_t protocol_id, notify_type_t notify_type) +{ + notify_payload_t *notify = notify_payload_create(); + + notify->set_notify_type(notify,notify_type); + notify->set_protocol_id(notify,protocol_id); + + return notify; +} diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h new file mode 100644 index 000000000..0e1bc23b8 --- /dev/null +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -0,0 +1,232 @@ +/* + * Copyright (C) 2006-2008 Tobias Brunner + * Copyright (C) 2006 Daniel Roethlisberger + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 notify_payload notify_payload + * @{ @ingroup payloads + */ + +#ifndef NOTIFY_PAYLOAD_H_ +#define NOTIFY_PAYLOAD_H_ + +typedef enum notify_type_t notify_type_t; +typedef struct notify_payload_t notify_payload_t; + +#include <library.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/proposal_substructure.h> +#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. + */ +enum notify_type_t { + /* notify error messages */ + UNSUPPORTED_CRITICAL_PAYLOAD = 1, + INVALID_IKE_SPI = 4, + INVALID_MAJOR_VERSION = 5, + INVALID_SYNTAX = 7, + INVALID_MESSAGE_ID = 9, + INVALID_SPI = 11, + NO_PROPOSAL_CHOSEN = 14, + INVALID_KE_PAYLOAD = 17, + AUTHENTICATION_FAILED = 24, + SINGLE_PAIR_REQUIRED = 34, + NO_ADDITIONAL_SAS = 35, + INTERNAL_ADDRESS_FAILURE = 36, + FAILED_CP_REQUIRED = 37, + TS_UNACCEPTABLE = 38, + INVALID_SELECTORS = 39, + /* mobile extension, RFC 4555 */ + UNACCEPTABLE_ADDRESSES = 40, + UNEXPECTED_NAT_DETECTED = 41, + /* mobile IPv6 bootstrapping, RFC 5026 */ + USE_ASSIGNED_HoA = 42, + + /* IKE-ME, private use */ + ME_CONNECT_FAILED = 8192, + + /* notify status messages */ + INITIAL_CONTACT = 16384, + SET_WINDOW_SIZE = 16385, + ADDITIONAL_TS_POSSIBLE = 16386, + IPCOMP_SUPPORTED = 16387, + NAT_DETECTION_SOURCE_IP = 16388, + NAT_DETECTION_DESTINATION_IP = 16389, + COOKIE = 16390, + USE_TRANSPORT_MODE = 16391, + HTTP_CERT_LOOKUP_SUPPORTED = 16392, + REKEY_SA = 16393, + ESP_TFC_PADDING_NOT_SUPPORTED = 16394, + NON_FIRST_FRAGMENTS_ALSO = 16395, + /* mobike extension, RFC4555 */ + MOBIKE_SUPPORTED = 16396, + ADDITIONAL_IP4_ADDRESS = 16397, + ADDITIONAL_IP6_ADDRESS = 16398, + NO_ADDITIONAL_ADDRESSES = 16399, + UPDATE_SA_ADDRESSES = 16400, + COOKIE2 = 16401, + NO_NATS_ALLOWED = 16402, + /* repeated authentication extension, RFC4478 */ + AUTH_LIFETIME = 16403, + /* multiple authentication exchanges, RFC 4739 */ + MULTIPLE_AUTH_SUPPORTED = 16404, + ANOTHER_AUTH_FOLLOWS = 16405, + /* redirect mechanism, RFC 5685 */ + REDIRECT_SUPPORTED = 16406, + REDIRECT = 16407, + REDIRECTED_FROM = 16408, + /* draft-ietf-ipsecme-ikev2-resumption, assigned by IANA */ + TICKET_LT_OPAQUE = 16409, + TICKET_REQUEST = 16410, + TICKET_ACK = 16411, + TICKET_NACK = 16412, + TICKET_OPAQUE = 16413, + LINK_ID = 16414, + + /* draft-eronen-ipsec-ikev2-eap-auth, not assigned by IANA yet */ + EAP_ONLY_AUTHENTICATION = 40960, + /* BEET mode, not even a draft yet. private use */ + USE_BEET_MODE = 40961, + /* IKE-ME, private use */ + ME_MEDIATION = 40962, + ME_ENDPOINT = 40963, + ME_CALLBACK = 40964, + ME_CONNECTID = 40965, + ME_CONNECTKEY = 40966, + ME_CONNECTAUTH = 40967, + ME_RESPONSE = 40968 +}; + +/** + * enum name for notify_type_t. + */ +extern enum_name_t *notify_type_names; + +/** + * enum name for notify_type_t (shorter strings). + */ +extern enum_name_t *notify_type_short_names; + +/** + * Class representing an IKEv2-Notify Payload. + * + * The Notify Payload format is described in Draft section 3.10. + */ +struct notify_payload_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Gets the protocol id of this payload. + * + * @return protocol id of this payload + */ + u_int8_t (*get_protocol_id) (notify_payload_t *this); + + /** + * Sets the protocol id of this payload. + * + * @param protocol_id protocol id to set + */ + void (*set_protocol_id) (notify_payload_t *this, u_int8_t protocol_id); + + /** + * Gets the notify message type of this payload. + * + * @return notify message type of this payload + */ + notify_type_t (*get_notify_type) (notify_payload_t *this); + + /** + * Sets notify message type of this payload. + * + * @param type notify message type to set + */ + void (*set_notify_type) (notify_payload_t *this, notify_type_t type); + + /** + * Returns the currently set spi of this payload. + * + * This is only valid for notifys with protocol AH|ESP + * + * @return SPI value + */ + u_int32_t (*get_spi) (notify_payload_t *this); + + /** + * Sets the spi of this payload. + * + * This is only valid for notifys with protocol AH|ESP + * + * @param spi SPI value + */ + void (*set_spi) (notify_payload_t *this, u_int32_t spi); + + /** + * Returns the currently set notification data of payload. + * + * Returned data are not copied. + * + * @return chunk_t pointing to the value + */ + chunk_t (*get_notification_data) (notify_payload_t *this); + + /** + * Sets the notification data of this payload. + * + * @warning Value is getting copied. + * + * @param notification_data chunk_t pointing to the value to set + */ + void (*set_notification_data) (notify_payload_t *this, + chunk_t notification_data); + + /** + * Destroys an notify_payload_t object. + */ + void (*destroy) (notify_payload_t *this); +}; + +/** + * Creates an empty notify_payload_t object + * + * @return created notify_payload_t object + */ +notify_payload_t *notify_payload_create(void); + +/** + * 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) + * @return notify_payload_t object + */ +notify_payload_t *notify_payload_create_from_protocol_and_type( + protocol_id_t protocol_id, notify_type_t type); + +#endif /** NOTIFY_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c new file mode 100644 index 000000000..1cee6d2aa --- /dev/null +++ b/src/libcharon/encoding/payloads/payload.c @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "payload.h" + +#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> +#include <encoding/payloads/notify_payload.h> +#include <encoding/payloads/auth_payload.h> +#include <encoding/payloads/cert_payload.h> +#include <encoding/payloads/certreq_payload.h> +#include <encoding/payloads/encryption_payload.h> +#include <encoding/payloads/ts_payload.h> +#include <encoding/payloads/delete_payload.h> +#include <encoding/payloads/vendor_id_payload.h> +#include <encoding/payloads/cp_payload.h> +#include <encoding/payloads/configuration_attribute.h> +#include <encoding/payloads/eap_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, EXTENSIBLE_AUTHENTICATION, NO_PAYLOAD, + "SECURITY_ASSOCIATION", + "KEY_EXCHANGE", + "ID_INITIATOR", + "ID_RESPONDER", + "CERTIFICATE", + "CERTIFICATE_REQUEST", + "AUTHENTICATION", + "NONCE", + "NOTIFY", + "DELETE", + "VENDOR_ID", + "TRAFFIC_SELECTOR_INITIATOR", + "TRAFFIC_SELECTOR_RESPONDER", + "ENCRYPTED", + "CONFIGURATION", + "EXTENSIBLE_AUTHENTICATION"); +#ifdef ME +ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, + "ID_PEER"); +ENUM_NEXT(payload_type_names, HEADER, UNKNOWN_PAYLOAD, ID_PEER, + "HEADER", + "PROPOSAL_SUBSTRUCTURE", + "TRANSFORM_SUBSTRUCTURE", + "TRANSFORM_ATTRIBUTE", + "TRAFFIC_SELECTOR_SUBSTRUCTURE", + "CONFIGURATION_ATTRIBUTE", + "UNKNOWN_PAYLOAD"); +#else +ENUM_NEXT(payload_type_names, HEADER, UNKNOWN_PAYLOAD, EXTENSIBLE_AUTHENTICATION, + "HEADER", + "PROPOSAL_SUBSTRUCTURE", + "TRANSFORM_SUBSTRUCTURE", + "TRANSFORM_ATTRIBUTE", + "TRAFFIC_SELECTOR_SUBSTRUCTURE", + "CONFIGURATION_ATTRIBUTE", + "UNKNOWN_PAYLOAD"); +#endif /* ME */ +ENUM_END(payload_type_names, UNKNOWN_PAYLOAD); + +/* short forms of payload names */ +ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD, + "--"); +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, EXTENSIBLE_AUTHENTICATION, NO_PAYLOAD, + "SA", + "KE", + "IDi", + "IDr", + "CERT", + "CERTREQ", + "AUTH", + "No", + "N", + "D", + "V", + "TSi", + "TSr", + "E", + "CP", + "EAP"); +#ifdef ME +ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, EXTENSIBLE_AUTHENTICATION, + "IDp"); +ENUM_NEXT(payload_type_short_names, HEADER, UNKNOWN_PAYLOAD, ID_PEER, + "HDR", + "PROP", + "TRANS", + "TRANSATTR", + "TSSUB", + "CPATTR", + "??"); +#else +ENUM_NEXT(payload_type_short_names, HEADER, UNKNOWN_PAYLOAD, EXTENSIBLE_AUTHENTICATION, + "HDR", + "PROP", + "TRANS", + "TRANSATTR", + "TSSUB", + "CPATTR", + "??"); +#endif /* ME */ +ENUM_END(payload_type_short_names, UNKNOWN_PAYLOAD); + +/* + * see header + */ +payload_t *payload_create(payload_type_t type) +{ + switch (type) + { + case HEADER: + return (payload_t*)ike_header_create(); + case SECURITY_ASSOCIATION: + return (payload_t*)sa_payload_create(); + case PROPOSAL_SUBSTRUCTURE: + return (payload_t*)proposal_substructure_create(); + case TRANSFORM_SUBSTRUCTURE: + return (payload_t*)transform_substructure_create(); + case TRANSFORM_ATTRIBUTE: + return (payload_t*)transform_attribute_create(); + case NONCE: + return (payload_t*)nonce_payload_create(); + case ID_INITIATOR: + return (payload_t*)id_payload_create(ID_INITIATOR); + case ID_RESPONDER: + return (payload_t*)id_payload_create(ID_RESPONDER); +#ifdef ME + case ID_PEER: + return (payload_t*)id_payload_create(ID_PEER); +#endif /* ME */ + case AUTHENTICATION: + return (payload_t*)auth_payload_create(); + case CERTIFICATE: + return (payload_t*)cert_payload_create(); + case CERTIFICATE_REQUEST: + return (payload_t*)certreq_payload_create(); + case TRAFFIC_SELECTOR_SUBSTRUCTURE: + return (payload_t*)traffic_selector_substructure_create(); + case TRAFFIC_SELECTOR_INITIATOR: + return (payload_t*)ts_payload_create(TRUE); + case TRAFFIC_SELECTOR_RESPONDER: + return (payload_t*)ts_payload_create(FALSE); + case KEY_EXCHANGE: + return (payload_t*)ke_payload_create(); + case NOTIFY: + return (payload_t*)notify_payload_create(); + case DELETE: + return (payload_t*)delete_payload_create(0); + case VENDOR_ID: + return (payload_t*)vendor_id_payload_create(); + case CONFIGURATION: + return (payload_t*)cp_payload_create(); + case CONFIGURATION_ATTRIBUTE: + return (payload_t*)configuration_attribute_create(); + case EXTENSIBLE_AUTHENTICATION: + return (payload_t*)eap_payload_create(); + case ENCRYPTED: + return (payload_t*)encryption_payload_create(); + default: + return (payload_t*)unknown_payload_create(); + } +} + diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h new file mode 100644 index 000000000..2e783cb30 --- /dev/null +++ b/src/libcharon/encoding/payloads/payload.h @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 payload payload + * @{ @ingroup payloads + */ + +#ifndef PAYLOAD_H_ +#define PAYLOAD_H_ + +typedef enum payload_type_t payload_type_t; +typedef struct payload_t payload_t; + +#include <library.h> +#include <encoding/payloads/encodings.h> + + +/** + * Payload-Types of a IKEv2-Message. + * + * Header and substructures are also defined as + * payload types with values from PRIVATE USE space. + */ +enum payload_type_t{ + + /** + * End of payload list in next_payload + */ + NO_PAYLOAD = 0, + + /** + * The security association (SA) payload containing proposals. + */ + SECURITY_ASSOCIATION = 33, + + /** + * The key exchange (KE) payload containing diffie-hellman values. + */ + KEY_EXCHANGE = 34, + + /** + * Identification for the original initiator (IDi). + */ + ID_INITIATOR = 35, + + /** + * Identification for the original responder (IDr). + */ + ID_RESPONDER = 36, + + /** + * Certificate payload with certificates (CERT). + */ + CERTIFICATE = 37, + + /** + * Certificate request payload (CERTREQ). + */ + CERTIFICATE_REQUEST = 38, + + /** + * Authentication payload contains auth data (AUTH). + */ + AUTHENTICATION = 39, + + /** + * Nonces, for initator and responder (Ni, Nr, N) + */ + NONCE = 40, + + /** + * Notify paylaod (N). + */ + NOTIFY = 41, + + /** + * Delete payload (D) + */ + DELETE = 42, + + /** + * Vendor id paylpoad (V). + */ + VENDOR_ID = 43, + + /** + * Traffic selector for the original initiator (TSi). + */ + TRAFFIC_SELECTOR_INITIATOR = 44, + + /** + * Traffic selector for the original responser (TSr). + */ + TRAFFIC_SELECTOR_RESPONDER = 45, + + /** + * Encryption payload, contains other payloads (E). + */ + ENCRYPTED = 46, + + /** + * Configuration payload (CP). + */ + CONFIGURATION = 47, + + /** + * Extensible authentication payload (EAP). + */ + EXTENSIBLE_AUTHENTICATION = 48, + +#ifdef ME + /** + * Identification payload for peers has a value from + * the PRIVATE USE space. + */ + ID_PEER = 128, +#endif /* ME */ + + /** + * 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. + */ + HEADER = 140, + + /** + * 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 = 141, + + /** + * 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. + */ + TRANSFORM_SUBSTRUCTURE = 142, + + /** + * 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_ATTRIBUTE = 143, + + /** + * 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. + */ + TRAFFIC_SELECTOR_SUBSTRUCTURE = 144, + + /** + * 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. + */ + CONFIGURATION_ATTRIBUTE = 145, + + /** + * A unknown payload has a value of PRIVATE USE space. + * + * This payload type is not sent over wire and just + * used internally to handle a unknown payload. + */ + UNKNOWN_PAYLOAD = 146, +}; + + +/** + * enum names for payload_type_t. + */ +extern enum_name_t *payload_type_names; + +/** + * enum names for payload_type_t in a short form. + */ +extern enum_name_t *payload_type_short_names; + +/** + * Generic interface for all payload types (incl.header and substructures). + * + * To handle all kinds of payloads on a generic way, this interface must + * be implemented by every payload. This allows parser_t/generator_t a simple + * handling of all payloads. + */ +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 + */ + void (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules, size_t *rule_count); + + /** + * Get type of 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 + */ + payload_type_t (*get_next_type) (payload_t *this); + + /** + * Set 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 + */ + size_t (*get_length) (payload_t *this); + + /** + * Verifies payload structure and makes consistence check. + * + * @return SUCCESS, FAILED if consistence not given + */ + status_t (*verify) (payload_t *this); + + /** + * Destroys a payload and all included substructures. + */ + void (*destroy) (payload_t *this); +}; + +/** + * Create an empty payload. + * + * Useful for the parser, who wants a generic constructor for all payloads. + * It supports all payload_t methods. If a payload type is not known, + * an unknwon_paylod is created with the chunk of data in it. + * + * @param type type of the payload to create + * @return payload_t object + */ +payload_t *payload_create(payload_type_t type); + +#endif /** PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c new file mode 100644 index 000000000..c93f73a68 --- /dev/null +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -0,0 +1,598 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "proposal_substructure.h" + +#include <encoding/payloads/encodings.h> +#include <encoding/payloads/transform_substructure.h> +#include <library.h> +#include <utils/linked_list.h> +#include <daemon.h> + + +/** + * IKEv1 Value for a proposal payload. + */ +#define PROPOSAL_TYPE_VALUE 2 + + +typedef struct private_proposal_substructure_t private_proposal_substructure_t; + +/** + * Private data of an proposal_substructure_t object. + * + */ +struct private_proposal_substructure_t { + /** + * Public proposal_substructure_t interface. + */ + proposal_substructure_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Length of this payload. + */ + u_int16_t proposal_length; + + /** + * Proposal number. + */ + u_int8_t proposal_number; + + /** + * Protocol ID. + */ + u_int8_t protocol_id; + + /** + * SPI size of the following SPI. + */ + u_int8_t spi_size; + + /** + * Number of transforms. + */ + u_int8_t transforms_count; + + /** + * SPI is stored as chunk. + */ + chunk_t spi; + + /** + * Transforms are stored in a linked_list_t. + */ + linked_list_t * transforms; +}; + +/** + * 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_rule_t proposal_substructure_encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, + /* Reserved Byte is skipped */ + { RESERVED_BYTE, 0 }, + /* Length of the whole proposal substructure payload*/ + { PAYLOAD_LENGTH, offsetof(private_proposal_substructure_t, proposal_length) }, + /* proposal number is a number of 8 bit */ + { U_INT_8, offsetof(private_proposal_substructure_t, proposal_number) }, + /* protocol ID is a number of 8 bit */ + { U_INT_8, offsetof(private_proposal_substructure_t, protocol_id) }, + /* SPI Size has its own type */ + { SPI_SIZE, offsetof(private_proposal_substructure_t, spi_size) }, + /* Number of transforms is a number of 8 bit */ + { U_INT_8, offsetof(private_proposal_substructure_t, transforms_count) }, + /* SPI is a chunk of variable size*/ + { SPI, offsetof(private_proposal_substructure_t, spi) }, + /* Transforms are stored in a transform substructure, + offset points to a linked_list_t pointer */ + { TRANSFORMS, offsetof(private_proposal_substructure_t, transforms) } +}; + +/* + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! 0 (last) or 2 ! RESERVED ! Proposal Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Proposal # ! Protocol ID ! SPI Size !# of Transforms! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ~ SPI (variable) ~ + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ <Transforms> ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_proposal_substructure_t *this) +{ + status_t status = SUCCESS; + iterator_t *iterator; + payload_t *current_transform; + + if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != 2)) + { + /* must be 0 or 2 */ + DBG1(DBG_ENC, "inconsistent next payload"); + return FAILED; + } + if (this->transforms_count != this->transforms->get_count(this->transforms)) + { + /* must be the same! */ + DBG1(DBG_ENC, "transform count invalid"); + return FAILED; + } + + switch (this->protocol_id) + { + 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); + return FAILED; + } + break; + case PROTO_IKE: + if (this->spi.len != 0 && this->spi.len != 8) + { + DBG1(DBG_ENC, "invalid SPI length in IKE proposal"); + return FAILED; + } + break; + default: + DBG1(DBG_ENC, "invalid proposal protocol (%d)", this->protocol_id); + return FAILED; + } + if ((this->protocol_id == 0) || (this->protocol_id >= 4)) + { + /* reserved are not supported */ + DBG1(DBG_ENC, "invalid protocol"); + return FAILED; + } + + iterator = this->transforms->create_iterator(this->transforms,TRUE); + while(iterator->iterate(iterator, (void**)¤t_transform)) + { + status = current_transform->verify(current_transform); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "TRANSFORM_SUBSTRUCTURE verification failed"); + break; + } + } + iterator->destroy(iterator); + + /* proposal number is checked in SA payload */ + return status; +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_proposal_substructure_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = proposal_substructure_encodings; + *rule_count = sizeof(proposal_substructure_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_proposal_substructure_t *this) +{ + return PROPOSAL_SUBSTRUCTURE; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_proposal_substructure_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_proposal_substructure_t *this,payload_type_t type) +{ +} + +/** + * (re-)compute the length of the payload. + */ +static void compute_length(private_proposal_substructure_t *this) +{ + iterator_t *iterator; + payload_t *current_transform; + size_t transforms_count = 0; + size_t length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH; + + iterator = this->transforms->create_iterator(this->transforms,TRUE); + while (iterator->iterate(iterator, (void**)¤t_transform)) + { + length += current_transform->get_length(current_transform); + transforms_count++; + } + iterator->destroy(iterator); + + length += this->spi.len; + this->transforms_count = transforms_count; + this->proposal_length = length; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_proposal_substructure_t *this) +{ + compute_length(this); + return this->proposal_length; +} + +/** + * Implementation of proposal_substructure_t.create_transform_substructure_iterator. + */ +static iterator_t *create_transform_substructure_iterator (private_proposal_substructure_t *this,bool forward) +{ + return (this->transforms->create_iterator(this->transforms,forward)); +} + +/** + * Implementation of proposal_substructure_t.add_transform_substructure. + */ +static void add_transform_substructure (private_proposal_substructure_t *this,transform_substructure_t *transform) +{ + status_t status; + if (this->transforms->get_count(this->transforms) > 0) + { + transform_substructure_t *last_transform; + status = this->transforms->get_last(this->transforms,(void **) &last_transform); + /* last transform is now not anymore last one */ + last_transform->set_is_last_transform(last_transform,FALSE); + + } + transform->set_is_last_transform(transform,TRUE); + + this->transforms->insert_last(this->transforms,(void *) transform); + compute_length(this); +} + +/** + * Implementation of proposal_substructure_t.proposal_substructure_t. + */ +static void set_is_last_proposal (private_proposal_substructure_t *this, bool is_last) +{ + this->next_payload = (is_last) ? 0: PROPOSAL_TYPE_VALUE; +} + +/** + * Implementation of proposal_substructure_t.set_proposal_number. + */ +static void set_proposal_number(private_proposal_substructure_t *this,u_int8_t proposal_number) +{ + this->proposal_number = proposal_number; +} + +/** + * Implementation of proposal_substructure_t.get_proposal_number. + */ +static u_int8_t get_proposal_number (private_proposal_substructure_t *this) +{ + return (this->proposal_number); +} + +/** + * Implementation of proposal_substructure_t.set_protocol_id. + */ +static void set_protocol_id(private_proposal_substructure_t *this,u_int8_t protocol_id) +{ + this->protocol_id = protocol_id; +} + +/** + * Implementation of proposal_substructure_t.get_protocol_id. + */ +static u_int8_t get_protocol_id(private_proposal_substructure_t *this) +{ + return (this->protocol_id); +} + +/** + * Implementation of proposal_substructure_t.set_spi. + */ +static void set_spi(private_proposal_substructure_t *this, chunk_t spi) +{ + /* first delete already set spi value */ + if (this->spi.ptr != NULL) + { + free(this->spi.ptr); + this->spi.ptr = NULL; + this->spi.len = 0; + compute_length(this); + } + + this->spi.ptr = clalloc(spi.ptr,spi.len); + this->spi.len = spi.len; + this->spi_size = spi.len; + compute_length(this); +} + +/** + * Implementation of proposal_substructure_t.get_spi. + */ +static chunk_t get_spi(private_proposal_substructure_t *this) +{ + chunk_t spi; + spi.ptr = this->spi.ptr; + spi.len = this->spi.len; + + return spi; +} + +/** + * Implementation of proposal_substructure_t.get_transform_count. + */ +static size_t get_transform_count (private_proposal_substructure_t *this) +{ + return this->transforms->get_count(this->transforms); +} + +/** + * Implementation of proposal_substructure_t.get_spi_size. + */ +static size_t get_spi_size (private_proposal_substructure_t *this) +{ + return this->spi.len; +} + +/** + * Implementation of proposal_substructure_t.get_proposal. + */ +proposal_t* get_proposal(private_proposal_substructure_t *this) +{ + iterator_t *iterator; + transform_substructure_t *transform; + proposal_t *proposal; + u_int64_t spi; + + proposal = proposal_create(this->protocol_id); + + iterator = this->transforms->create_iterator(this->transforms, TRUE); + while (iterator->iterate(iterator, (void**)&transform)) + { + transform_type_t transform_type; + u_int16_t transform_id; + u_int16_t key_length = 0; + + transform_type = transform->get_transform_type(transform); + transform_id = transform->get_transform_id(transform); + transform->get_key_length(transform, &key_length); + + proposal->add_algorithm(proposal, transform_type, transform_id, key_length); + } + iterator->destroy(iterator); + + switch (this->spi.len) + { + case 4: + spi = *((u_int32_t*)this->spi.ptr); + break; + case 8: + spi = *((u_int64_t*)this->spi.ptr); + break; + default: + spi = 0; + } + proposal->set_spi(proposal, spi); + + return proposal; +} + +/** + * Implementation of proposal_substructure_t.clone. + */ +static private_proposal_substructure_t* clone_(private_proposal_substructure_t *this) +{ + private_proposal_substructure_t *clone; + iterator_t *transforms; + transform_substructure_t *current_transform; + + clone = (private_proposal_substructure_t *) proposal_substructure_create(); + clone->next_payload = this->next_payload; + clone->proposal_number = this->proposal_number; + clone->protocol_id = this->protocol_id; + clone->spi_size = this->spi_size; + if (this->spi.ptr != NULL) + { + clone->spi.ptr = clalloc(this->spi.ptr,this->spi.len); + clone->spi.len = this->spi.len; + } + + transforms = this->transforms->create_iterator(this->transforms,FALSE); + while (transforms->iterate(transforms, (void**)¤t_transform)) + { + current_transform = current_transform->clone(current_transform); + clone->public.add_transform_substructure(&clone->public, current_transform); + } + transforms->destroy(transforms); + + return clone; +} + +/** + * Implements payload_t's and proposal_substructure_t's destroy function. + * See #payload_s.destroy or proposal_substructure_s.destroy for description. + */ +static void destroy(private_proposal_substructure_t *this) +{ + this->transforms->destroy_offset(this->transforms, + offsetof(transform_substructure_t, destroy)); + chunk_free(&this->spi); + free(this); +} + +/* + * Described in header. + */ +proposal_substructure_t *proposal_substructure_create() +{ + private_proposal_substructure_t *this = malloc_thing(private_proposal_substructure_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + + /* public functions */ + this->public.create_transform_substructure_iterator = (iterator_t* (*) (proposal_substructure_t *,bool)) create_transform_substructure_iterator; + this->public.add_transform_substructure = (void (*) (proposal_substructure_t *,transform_substructure_t *)) add_transform_substructure; + this->public.set_proposal_number = (void (*) (proposal_substructure_t *,u_int8_t))set_proposal_number; + this->public.get_proposal_number = (u_int8_t (*) (proposal_substructure_t *)) get_proposal_number; + this->public.set_protocol_id = (void (*) (proposal_substructure_t *,u_int8_t))set_protocol_id; + this->public.get_protocol_id = (u_int8_t (*) (proposal_substructure_t *)) get_protocol_id; + this->public.set_is_last_proposal = (void (*) (proposal_substructure_t *,bool)) set_is_last_proposal; + this->public.get_proposal = (proposal_t* (*) (proposal_substructure_t*))get_proposal; + this->public.set_spi = (void (*) (proposal_substructure_t *,chunk_t))set_spi; + this->public.get_spi = (chunk_t (*) (proposal_substructure_t *)) get_spi; + this->public.get_transform_count = (size_t (*) (proposal_substructure_t *)) get_transform_count; + this->public.get_spi_size = (size_t (*) (proposal_substructure_t *)) get_spi_size; + this->public.clone = (proposal_substructure_t * (*) (proposal_substructure_t *)) clone_; + this->public.destroy = (void (*) (proposal_substructure_t *)) destroy; + + /* set default values of the fields */ + this->next_payload = NO_PAYLOAD; + this->proposal_length = 0; + this->proposal_number = 0; + this->protocol_id = 0; + this->transforms_count = 0; + this->spi_size = 0; + this->spi.ptr = NULL; + this->spi.len = 0; + + this->transforms = linked_list_create(); + + return (&(this->public)); +} + +/* + * Described in header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposal(proposal_t *proposal) +{ + 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(); + + /* encryption algorithm is only availble 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); + add_transform_substructure(this, transform); + } + enumerator->destroy(enumerator); + + /* integrity algorithms */ + enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); + while (enumerator->enumerate(enumerator, &alg, &key_size)) + { + transform = transform_substructure_create_type(INTEGRITY_ALGORITHM, + alg, key_size); + add_transform_substructure(this, transform); + } + enumerator->destroy(enumerator); + + /* prf algorithms */ + 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); + add_transform_substructure(this, transform); + } + enumerator->destroy(enumerator); + + /* dh groups */ + enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); + while (enumerator->enumerate(enumerator, &alg, NULL)) + { + transform = transform_substructure_create_type(DIFFIE_HELLMAN_GROUP, + alg, 0); + add_transform_substructure(this, transform); + } + enumerator->destroy(enumerator); + + /* extended sequence numbers */ + enumerator = proposal->create_enumerator(proposal, EXTENDED_SEQUENCE_NUMBERS); + while (enumerator->enumerate(enumerator, &alg, NULL)) + { + transform = transform_substructure_create_type(EXTENDED_SEQUENCE_NUMBERS, + alg, 0); + add_transform_substructure(this, transform); + } + enumerator->destroy(enumerator); + + /* 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); + break; + case PROTO_IKE: + if (proposal->get_spi(proposal)) + { /* 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); + } + break; + default: + break; + } + this->proposal_number = 0; + this->protocol_id = proposal->get_protocol(proposal); + + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h new file mode 100644 index 000000000..4934802af --- /dev/null +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 proposal_substructure proposal_substructure + * @{ @ingroup payloads + */ + +#ifndef PROPOSAL_SUBSTRUCTURE_H_ +#define PROPOSAL_SUBSTRUCTURE_H_ + +typedef struct proposal_substructure_t proposal_substructure_t; + +#include <library.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/transform_substructure.h> +#include <config/proposal.h> +#include <utils/linked_list.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. + */ +struct proposal_substructure_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Creates an iterator of stored transform_substructure_t objects. + * + * @param forward iterator direction (TRUE: front to end) + * @return created iterator_t object + */ + iterator_t *(*create_transform_substructure_iterator) ( + proposal_substructure_t *this, bool forward); + + /** + * Adds a transform_substructure_t object to this object. + * + * @param transform transform_substructure_t object to add + */ + void (*add_transform_substructure) (proposal_substructure_t *this, + transform_substructure_t *transform); + + /** + * Sets the proposal number of current proposal. + * + * @param id proposal number to set + */ + void (*set_proposal_number) (proposal_substructure_t *this, + u_int8_t proposal_number); + + /** + * get proposal number of current proposal. + * + * @return proposal number of current proposal substructure. + */ + u_int8_t (*get_proposal_number) (proposal_substructure_t *this); + + /** + * get the number of transforms in current proposal. + * + * @return transform count in current proposal + */ + size_t (*get_transform_count) (proposal_substructure_t *this); + + /** + * get size of the set spi in bytes. + * + * @return size of the spi in bytes + */ + size_t (*get_spi_size) (proposal_substructure_t *this); + + /** + * Sets the protocol id of current proposal. + * + * @param id protocol id to set + */ + void (*set_protocol_id) (proposal_substructure_t *this, + u_int8_t protocol_id); + + /** + * get protocol id of current proposal. + * + * @return protocol id of current proposal substructure. + */ + u_int8_t (*get_protocol_id) (proposal_substructure_t *this); + + /** + * Sets the next_payload field of this substructure + * + * If this is the last proposal, next payload field is set to 0, + * otherwise to 2 + * + * @param is_last When TRUE, next payload field is set to 0, otherwise to 2 + */ + void (*set_is_last_proposal) (proposal_substructure_t *this, bool is_last); + + /** + * Returns the currently set SPI of this proposal. + * + * @return chunk_t pointing to the value + */ + chunk_t (*get_spi) (proposal_substructure_t *this); + + /** + * Sets the SPI of the current proposal. + * + * @warning SPI is getting copied + * + * @param spi chunk_t pointing to the value to set + */ + void (*set_spi) (proposal_substructure_t *this, chunk_t spi); + + /** + * Get a proposal_t from the propsal_substructure_t. + * + * @return proposal_t + */ + proposal_t * (*get_proposal) (proposal_substructure_t *this); + + /** + * Clones an proposal_substructure_t object. + * + * @return cloned object + */ + proposal_substructure_t* (*clone) (proposal_substructure_t *this); + + /** + * Destroys an proposal_substructure_t object. + */ + void (*destroy) (proposal_substructure_t *this); +}; + +/** + * Creates an empty proposal_substructure_t object + * + * @return proposal_substructure_t object + */ +proposal_substructure_t *proposal_substructure_create(void); + +/** + * Creates a proposal_substructure_t from a proposal_t. + * + * @param proposal proposal to build a substruct out of it + * @return proposal_substructure_t object + */ +proposal_substructure_t *proposal_substructure_create_from_proposal( + proposal_t *proposal); + +#endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c new file mode 100644 index 000000000..187a8fee0 --- /dev/null +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "sa_payload.h" + +#include <encoding/payloads/encodings.h> +#include <utils/linked_list.h> +#include <daemon.h> + + +typedef struct private_sa_payload_t private_sa_payload_t; + +/** + * Private data of an sa_payload_t object. + * + */ +struct private_sa_payload_t { + /** + * Public sa_payload_t interface. + */ + sa_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Proposals in this payload are stored in a linked_list_t. + */ + linked_list_t * proposals; +}; + +/** + * 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_rule_t sa_payload_encodings[] = { + /* 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 */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* 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) } +}; + +/* + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ <Proposals> ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_sa_payload_t *this) +{ + int expected_number = 1, current_number; + status_t status = SUCCESS; + iterator_t *iterator; + proposal_substructure_t *current_proposal; + bool first = TRUE; + + /* check proposal numbering */ + iterator = this->proposals->create_iterator(this->proposals,TRUE); + + while(iterator->iterate(iterator, (void**)¤t_proposal)) + { + current_number = current_proposal->get_proposal_number(current_proposal); + if (current_number < expected_number) + { + if (current_number != (expected_number + 1)) + { + DBG1(DBG_ENC, "proposal number is %d, expected %d or %d", + current_number, expected_number, expected_number + 1); + status = FAILED; + break; + } + } + else if (current_number < expected_number) + { + /* must not be smaller then proceeding one */ + DBG1(DBG_ENC, "proposal number smaller than that of previous proposal"); + status = FAILED; + break; + } + + status = current_proposal->payload_interface.verify(&(current_proposal->payload_interface)); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "PROPOSAL_SUBSTRUCTURE verification failed"); + break; + } + first = FALSE; + expected_number = current_number; + } + + iterator->destroy(iterator); + return status; +} + + +/** + * Implementation of payload_t.destroy and sa_payload_t.destroy. + */ +static status_t destroy(private_sa_payload_t *this) +{ + this->proposals->destroy_offset(this->proposals, + offsetof(proposal_substructure_t, destroy)); + free(this); + return SUCCESS; +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = sa_payload_encodings; + *rule_count = sizeof(sa_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_sa_payload_t *this) +{ + return SECURITY_ASSOCIATION; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_sa_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_sa_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * recompute length of the payload. + */ +static void compute_length (private_sa_payload_t *this) +{ + iterator_t *iterator; + payload_t *current_proposal; + size_t length = SA_PAYLOAD_HEADER_LENGTH; + + iterator = this->proposals->create_iterator(this->proposals,TRUE); + while (iterator->iterate(iterator, (void **)¤t_proposal)) + { + length += current_proposal->get_length(current_proposal); + } + iterator->destroy(iterator); + + this->payload_length = length; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_sa_payload_t *this) +{ + compute_length(this); + return this->payload_length; +} + +/** + * Implementation of sa_payload_t.create_proposal_substructure_iterator. + */ +static iterator_t *create_proposal_substructure_iterator (private_sa_payload_t *this,bool forward) +{ + return this->proposals->create_iterator(this->proposals,forward); +} + +/** + * Implementation of sa_payload_t.add_proposal_substructure. + */ +static void add_proposal_substructure(private_sa_payload_t *this,proposal_substructure_t *proposal) +{ + status_t status; + u_int proposal_count = this->proposals->get_count(this->proposals); + + if (proposal_count > 0) + { + proposal_substructure_t *last_proposal; + status = this->proposals->get_last(this->proposals,(void **) &last_proposal); + /* last transform is now not anymore last one */ + last_proposal->set_is_last_proposal(last_proposal, FALSE); + } + proposal->set_is_last_proposal(proposal, TRUE); + proposal->set_proposal_number(proposal, proposal_count + 1); + this->proposals->insert_last(this->proposals,(void *) proposal); + compute_length(this); +} + +/** + * Implementation of sa_payload_t.add_proposal. + */ +static void add_proposal(private_sa_payload_t *this, proposal_t *proposal) +{ + proposal_substructure_t *substructure; + + substructure = proposal_substructure_create_from_proposal(proposal); + add_proposal_substructure(this, substructure); +} + +/** + * Implementation of sa_payload_t.get_proposals. + */ +static linked_list_t *get_proposals(private_sa_payload_t *this) +{ + int struct_number = 0; + int ignore_struct_number = 0; + iterator_t *iterator; + proposal_substructure_t *proposal_struct; + linked_list_t *proposal_list; + + /* this list will hold our proposals */ + proposal_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. + */ + iterator = this->proposals->create_iterator(this->proposals, TRUE); + while (iterator->iterate(iterator, (void **)&proposal_struct)) + { + proposal_t *proposal; + + /* check if a proposal has a single protocol */ + if (proposal_struct->get_proposal_number(proposal_struct) == struct_number) + { + if (ignore_struct_number < struct_number) + { + /* remova an already added, if first of series */ + proposal_list->remove_last(proposal_list, (void**)&proposal); + proposal->destroy(proposal); + ignore_struct_number = struct_number; + } + continue; + } + struct_number++; + proposal = proposal_struct->get_proposal(proposal_struct); + if (proposal) + { + proposal_list->insert_last(proposal_list, proposal); + } + } + iterator->destroy(iterator); + return proposal_list; +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create() +{ + private_sa_payload_t *this = malloc_thing(private_sa_payload_t); + + /* public interface */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.create_proposal_substructure_iterator = (iterator_t* (*) (sa_payload_t *,bool)) create_proposal_substructure_iterator; + this->public.add_proposal_substructure = (void (*) (sa_payload_t *,proposal_substructure_t *)) add_proposal_substructure; + this->public.add_proposal = (void (*) (sa_payload_t*,proposal_t*))add_proposal; + this->public.get_proposals = (linked_list_t* (*) (sa_payload_t *)) get_proposals; + this->public.destroy = (void (*) (sa_payload_t *)) destroy; + + /* set default values of the fields */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = SA_PAYLOAD_HEADER_LENGTH; + this->proposals = linked_list_create(); + return &this->public; +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals) +{ + iterator_t *iterator; + proposal_t *proposal; + sa_payload_t *sa_payload = sa_payload_create(); + + /* add every payload from the list */ + iterator = proposals->create_iterator(proposals, TRUE); + while (iterator->iterate(iterator, (void**)&proposal)) + { + add_proposal((private_sa_payload_t*)sa_payload, proposal); + } + iterator->destroy(iterator); + + return sa_payload; +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal) +{ + sa_payload_t *sa_payload = sa_payload_create(); + + add_proposal((private_sa_payload_t*)sa_payload, proposal); + + return sa_payload; +} diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h new file mode 100644 index 000000000..25f5a2407 --- /dev/null +++ b/src/libcharon/encoding/payloads/sa_payload.h @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 sa_payload sa_payload + * @{ @ingroup payloads + */ + +#ifndef SA_PAYLOAD_H_ +#define SA_PAYLOAD_H_ + +typedef struct sa_payload_t sa_payload_t; + +#include <library.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/proposal_substructure.h> +#include <utils/linked_list.h> + +/** + * SA_PAYLOAD length in bytes without any proposal substructure. + */ +#define SA_PAYLOAD_HEADER_LENGTH 4 + +/** + * Class representing an IKEv2-SA Payload. + * + * The SA Payload format is described in RFC section 3.3. + */ +struct sa_payload_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Creates an iterator of stored proposal_substructure_t objects. + * + * When deleting an proposal using this iterator, + * the length of this transform substructure has to be refreshed + * by calling get_length()! + * + * @param forward iterator direction (TRUE: front to end) + * @return created iterator_t object + */ + iterator_t *(*create_proposal_substructure_iterator) (sa_payload_t *this, + bool forward); + + /** + * Adds a proposal_substructure_t object to this object. + * + * @param proposal proposal_substructure_t object to add + */ + void (*add_proposal_substructure) (sa_payload_t *this, + proposal_substructure_t *proposal); + + /** + * Gets the proposals in this payload as a list. + * + * @return a list containing proposal_t s + */ + linked_list_t *(*get_proposals) (sa_payload_t *this); + + /** + * Add a child proposal (AH/ESP) to the payload. + * + * @param proposal child proposal to add to the payload + */ + void (*add_proposal) (sa_payload_t *this, proposal_t *proposal); + + /** + * Destroys an sa_payload_t object. + */ + void (*destroy) (sa_payload_t *this); +}; + +/** + * Creates an empty sa_payload_t object + * + * @return created sa_payload_t object + */ +sa_payload_t *sa_payload_create(void); + +/** + * Creates a 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); + +/** + * Creates a 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(proposal_t *proposal); + +#endif /** SA_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.c b/src/libcharon/encoding/payloads/traffic_selector_substructure.c new file mode 100644 index 000000000..f24857591 --- /dev/null +++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.c @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "traffic_selector_substructure.h" + +#include <encoding/payloads/encodings.h> +#include <utils/linked_list.h> + + +typedef struct private_traffic_selector_substructure_t private_traffic_selector_substructure_t; + +/** + * Private data of an traffic_selector_substructure_t object. + * + */ +struct private_traffic_selector_substructure_t { + /** + * Public traffic_selector_substructure_t interface. + */ + traffic_selector_substructure_t public; + + /** + * Type of traffic selector. + */ + u_int8_t ts_type; + + /** + * IP Protocol ID. + */ + u_int8_t ip_protocol_id; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Start port number. + */ + u_int16_t start_port; + + /** + * End port number. + */ + u_int16_t end_port; + + /** + * Starting address. + */ + chunk_t starting_address; + + /** + * Ending address. + */ + chunk_t ending_address; +}; + +/** + * Encoding rules to parse or generate a TS payload + * + * The defined offsets are the positions in a object of type + * private_traffic_selector_substructure_t. + * + */ +encoding_rule_t traffic_selector_substructure_encodings[] = { + /* 1 Byte next ts type*/ + { TS_TYPE, offsetof(private_traffic_selector_substructure_t, ts_type) }, + /* 1 Byte IP protocol id*/ + { U_INT_8, offsetof(private_traffic_selector_substructure_t, ip_protocol_id) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_traffic_selector_substructure_t, payload_length) }, + /* 2 Byte start port*/ + { U_INT_16, offsetof(private_traffic_selector_substructure_t, start_port) }, + /* 2 Byte end port*/ + { U_INT_16, offsetof(private_traffic_selector_substructure_t, end_port) }, + /* starting address is either 4 or 16 byte */ + { ADDRESS, offsetof(private_traffic_selector_substructure_t, starting_address) }, + /* ending address is either 4 or 16 byte */ + { ADDRESS, offsetof(private_traffic_selector_substructure_t, ending_address) } + +}; + +/* + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! TS Type !IP Protocol ID*| Selector Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Start Port* | End Port* | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Starting Address* ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Ending Address* ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_traffic_selector_substructure_t *this) +{ + if (this->start_port > this->end_port) + { + return FAILED; + } + switch (this->ts_type) + { + case TS_IPV4_ADDR_RANGE: + { + if ((this->starting_address.len != 4) || + (this->ending_address.len != 4)) + { + /* ipv4 address must be 4 bytes long */ + return FAILED; + } + break; + } + case TS_IPV6_ADDR_RANGE: + { + if ((this->starting_address.len != 16) || + (this->ending_address.len != 16)) + { + /* ipv6 address must be 16 bytes long */ + return FAILED; + } + break; + } + default: + { + /* not supported ts type */ + return FAILED; + } + } + + return SUCCESS; +} + +/** + * Implementation of traffic_selector_substructure_t.get_encoding_rules. + */ +static void get_encoding_rules(private_traffic_selector_substructure_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = traffic_selector_substructure_encodings; + *rule_count = sizeof(traffic_selector_substructure_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_payload_type(private_traffic_selector_substructure_t *this) +{ + return TRAFFIC_SELECTOR_SUBSTRUCTURE; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_traffic_selector_substructure_t *this) +{ + return 0; +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_traffic_selector_substructure_t *this,payload_type_t type) +{ + +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_traffic_selector_substructure_t *this) +{ + return this->payload_length; +} + +/** + * Implementation of traffic_selector_substructure_t.get_traffic_selector. + */ +static traffic_selector_t *get_traffic_selector(private_traffic_selector_substructure_t *this) +{ + traffic_selector_t *ts; + ts = traffic_selector_create_from_bytes(this->ip_protocol_id, this->ts_type, + this->starting_address, this->start_port, + this->ending_address, this->end_port); + return ts; +} + +/** + * recompute length field of the payload + */ +void compute_length(private_traffic_selector_substructure_t *this) +{ + this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH + + this->ending_address.len + this->starting_address.len; +} + +/** + * Implementation of payload_t.destroy and traffic_selector_substructure_t.destroy. + */ +static void destroy(private_traffic_selector_substructure_t *this) +{ + free(this->starting_address.ptr); + free(this->ending_address.ptr); + free(this); +} + +/* + * Described in header + */ +traffic_selector_substructure_t *traffic_selector_substructure_create() +{ + private_traffic_selector_substructure_t *this = malloc_thing(private_traffic_selector_substructure_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.get_traffic_selector = (traffic_selector_t* (*)(traffic_selector_substructure_t*))get_traffic_selector; + this->public.destroy = (void (*) (traffic_selector_substructure_t *)) destroy; + + /* private variables */ + this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH; + this->start_port = 0; + this->end_port = 0; + this->starting_address = chunk_empty; + this->ending_address = chunk_empty; + this->ip_protocol_id = 0; + /* must be set to be valid */ + this->ts_type = TS_IPV4_ADDR_RANGE; + + return (&(this->public)); +} + +/* + * Described in header + */ +traffic_selector_substructure_t *traffic_selector_substructure_create_from_traffic_selector(traffic_selector_t *traffic_selector) +{ + private_traffic_selector_substructure_t *this = (private_traffic_selector_substructure_t*)traffic_selector_substructure_create(); + this->ts_type = traffic_selector->get_type(traffic_selector); + this->ip_protocol_id = traffic_selector->get_protocol(traffic_selector); + this->start_port = traffic_selector->get_from_port(traffic_selector); + this->end_port = traffic_selector->get_to_port(traffic_selector); + this->starting_address = chunk_clone(traffic_selector->get_from_address(traffic_selector)); + this->ending_address = chunk_clone(traffic_selector->get_to_address(traffic_selector)); + + compute_length(this); + + return &(this->public); +} diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.h b/src/libcharon/encoding/payloads/traffic_selector_substructure.h new file mode 100644 index 000000000..0109fd7f5 --- /dev/null +++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.h @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 traffic_selector_substructure traffic_selector_substructure + * @{ @ingroup payloads + */ + +#ifndef TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ +#define TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ + +typedef struct traffic_selector_substructure_t traffic_selector_substructure_t; + +#include <library.h> +#include <utils/host.h> +#include <selectors/traffic_selector.h> +#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. + */ +struct traffic_selector_substructure_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the type of Traffic selector. + * + * @return type of traffic selector + * + */ + ts_type_t (*get_ts_type) (traffic_selector_substructure_t *this); + + /** + * Set the type of Traffic selector. + * + * @param ts_type type of traffic selector + */ + void (*set_ts_type) (traffic_selector_substructure_t *this, + ts_type_t ts_type); + + /** + * Get the IP protocol ID of Traffic selector. + * + * @return type of traffic selector + * + */ + u_int8_t (*get_protocol_id) (traffic_selector_substructure_t *this); + + /** + * Set the IP protocol ID of Traffic selector + * + * @param protocol_id protocol ID of traffic selector + */ + void (*set_protocol_id) (traffic_selector_substructure_t *this, + u_int8_t protocol_id); + + /** + * Get the start port and address as host_t object. + * + * Returned host_t object has to get destroyed by the caller. + * + * @return start host as host_t object + * + */ + host_t *(*get_start_host) (traffic_selector_substructure_t *this); + + /** + * Set the start port and address as host_t object. + * + * @param start_host start host as host_t object + */ + void (*set_start_host) (traffic_selector_substructure_t *this, + host_t *start_host); + + /** + * Get the end port and address as host_t object. + * + * Returned host_t object has to get destroyed by the caller. + * + * @return end host as host_t object + * + */ + host_t *(*get_end_host) (traffic_selector_substructure_t *this); + + /** + * Set the end port and address as host_t object. + * + * @param end_host end host as host_t object + */ + void (*set_end_host) (traffic_selector_substructure_t *this, + host_t *end_host); + + /** + * Get a traffic_selector_t from this substructure. + * + * @warning traffic_selector_t must be destroyed after usage. + * + * @return contained traffic_selector_t + */ + traffic_selector_t *(*get_traffic_selector) ( + traffic_selector_substructure_t *this); + + /** + * Destroys an traffic_selector_substructure_t object. + */ + void (*destroy) (traffic_selector_substructure_t *this); +}; + +/** + * Creates an empty traffic_selector_substructure_t object. + * + * TS type is set to default TS_IPV4_ADDR_RANGE! + * + * @return traffic_selector_substructure_t object + */ +traffic_selector_substructure_t *traffic_selector_substructure_create(void); + +/** + * Creates an initialized traffif selector substructure using + * the values from a traffic_selector_t. + * + * @param traffic_selector traffic_selector_t to use for initialization + * @return traffic_selector_substructure_t object + */ +traffic_selector_substructure_t *traffic_selector_substructure_create_from_traffic_selector( + traffic_selector_t *traffic_selector); + +#endif /** TRAFFIC_SELECTOR_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c new file mode 100644 index 000000000..8bf2ddef4 --- /dev/null +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -0,0 +1,325 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 <string.h> +#include <stddef.h> + +#include "transform_attribute.h" + +#include <encoding/payloads/encodings.h> +#include <library.h> + +typedef struct private_transform_attribute_t private_transform_attribute_t; + +/** + * Private data of an transform_attribute_t object. + * + */ +struct private_transform_attribute_t { + /** + * Public transform_attribute_t interface. + */ + transform_attribute_t public; + + /** + * Attribute Format Flag. + * + * - TRUE means value is stored in attribute_length_or_value + * - FALSE means value is stored in attribute_value + */ + bool attribute_format; + + /** + * Type of the attribute. + */ + u_int16_t attribute_type; + + /** + * Attribute Length if attribute_format is 0, attribute Value otherwise. + */ + u_int16_t attribute_length_or_value; + + /** + * 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); + +/** + * 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_rule_t transform_attribute_encodings[] = { + /* Flag defining the format of this payload */ + { 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) } +}; + +/* + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + !A! Attribute Type ! AF=0 Attribute Length ! + !F! ! AF=1 Attribute Value ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! AF=0 Attribute Value ! + ! AF=1 Not Transmitted ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_transform_attribute_t *this) +{ + if (this->attribute_type != KEY_LENGTH) + { + return FAILED; + } + + return SUCCESS; +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_transform_attribute_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = transform_attribute_encodings; + *rule_count = sizeof(transform_attribute_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_transform_attribute_t *this) +{ + return TRANSFORM_ATTRIBUTE; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_transform_attribute_t *this) +{ + return (NO_PAYLOAD); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_transform_attribute_t *this,payload_type_t type) +{ +} + +/** + * Implementation of transform_attribute_t.get_length. + */ +static size_t get_length(private_transform_attribute_t *this) +{ + if (this->attribute_format == TRUE) + { + /*Attribute size is only 4 byte */ + return 4; + } + return (this->attribute_length_or_value + 4); +} + +/** + * Implementation of transform_attribute_t.set_value_chunk. + */ +static void set_value_chunk(private_transform_attribute_t *this, chunk_t value) +{ + if (this->attribute_value.ptr != NULL) + { + /* free existing value */ + free(this->attribute_value.ptr); + this->attribute_value.ptr = NULL; + this->attribute_value.len = 0; + + } + + if (value.len > 2) + { + this->attribute_value.ptr = clalloc(value.ptr,value.len); + this->attribute_value.len = value.len; + this->attribute_length_or_value = value.len; + /* attribute has not a fixed length */ + this->attribute_format = FALSE; + } + else + { + memcpy(&(this->attribute_length_or_value),value.ptr,value.len); + } +} + +/** + * Implementation of transform_attribute_t.set_value. + */ +static void set_value(private_transform_attribute_t *this, u_int16_t value) +{ + if (this->attribute_value.ptr != NULL) + { + /* free existing value */ + free(this->attribute_value.ptr); + this->attribute_value.ptr = NULL; + this->attribute_value.len = 0; + + } + this->attribute_length_or_value = value; +} + +/** + * Implementation of transform_attribute_t.get_value_chunk. + */ +static chunk_t get_value_chunk (private_transform_attribute_t *this) +{ + chunk_t value; + + if (this->attribute_format == FALSE) + { + value.ptr = this->attribute_value.ptr; + value.len = this->attribute_value.len; + } + else + { + value.ptr = (void *) &(this->attribute_length_or_value); + value.len = 2; + } + + return value; +} + +/** + * Implementation of transform_attribute_t.get_value. + */ +static u_int16_t get_value (private_transform_attribute_t *this) +{ + return this->attribute_length_or_value; +} + + +/** + * Implementation of transform_attribute_t.set_attribute_type. + */ +static void set_attribute_type (private_transform_attribute_t *this, u_int16_t type) +{ + this->attribute_type = type & 0x7FFF; +} + +/** + * Implementation of transform_attribute_t.get_attribute_type. + */ +static u_int16_t get_attribute_type (private_transform_attribute_t *this) +{ + return this->attribute_type; +} + +/** + * Implementation of transform_attribute_t.clone. + */ +static transform_attribute_t * _clone(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.ptr = clalloc(this->attribute_value.ptr,this->attribute_value.len); + new_clone->attribute_value.len = this->attribute_value.len; + } + + return (transform_attribute_t *) new_clone; +} + +/** + * Implementation of transform_attribute_t.destroy and payload_t.destroy. + */ +static void destroy(private_transform_attribute_t *this) +{ + if (this->attribute_value.ptr != NULL) + { + free(this->attribute_value.ptr); + } + free(this); +} + +/* + * Described in header. + */ +transform_attribute_t *transform_attribute_create() +{ + private_transform_attribute_t *this = malloc_thing(private_transform_attribute_t); + + /* payload interface */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.set_value_chunk = (void (*) (transform_attribute_t *,chunk_t)) set_value_chunk; + this->public.set_value = (void (*) (transform_attribute_t *,u_int16_t)) set_value; + this->public.get_value_chunk = (chunk_t (*) (transform_attribute_t *)) get_value_chunk; + this->public.get_value = (u_int16_t (*) (transform_attribute_t *)) get_value; + this->public.set_attribute_type = (void (*) (transform_attribute_t *,u_int16_t type)) set_attribute_type; + this->public.get_attribute_type = (u_int16_t (*) (transform_attribute_t *)) get_attribute_type; + this->public.clone = (transform_attribute_t * (*) (transform_attribute_t *)) _clone; + this->public.destroy = (void (*) (transform_attribute_t *)) destroy; + + /* set default values of the fields */ + this->attribute_format = TRUE; + this->attribute_type = 0; + this->attribute_length_or_value = 0; + this->attribute_value.ptr = NULL; + this->attribute_value.len = 0; + + return (&(this->public)); +} + +/* + * Described in header. + */ +transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length) +{ + transform_attribute_t *attribute = transform_attribute_create(); + attribute->set_attribute_type(attribute,KEY_LENGTH); + attribute->set_value(attribute,key_length); + return attribute; +} diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h new file mode 100644 index 000000000..a5fe0154b --- /dev/null +++ b/src/libcharon/encoding/payloads/transform_attribute.h @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 transform_attribute transform_attribute + * @{ @ingroup payloads + */ + +#ifndef TRANSFORM_ATTRIBUTE_H_ +#define TRANSFORM_ATTRIBUTE_H_ + +typedef enum transform_attribute_type_t transform_attribute_type_t; +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. + */ +enum transform_attribute_type_t { + ATTRIBUTE_UNDEFINED = 16384, + KEY_LENGTH = 14 +}; + +/** + * enum name for transform_attribute_type_t. + */ +extern enum_name_t *transform_attribute_type_names; + +/** + * Class representing an IKEv2- TRANSFORM Attribute. + * + * The TRANSFORM ATTRIBUTE format is described in RFC section 3.3.5. + */ +struct transform_attribute_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Returns the currently set value of the attribute. + * + * Returned data are not copied. + * + * @return chunk_t pointing to the value + */ + chunk_t (*get_value_chunk) (transform_attribute_t *this); + + /** + * Returns the currently set value of the attribute. + * + * Returned data are not copied. + * + * @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); + + /** + * get the type of the attribute. + * + * @return type of the value + */ + 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); +}; + +/** + * Creates an empty transform_attribute_t object. + * + * @return transform_attribute_t object + */ +transform_attribute_t *transform_attribute_create(void); + +/** + * Creates an transform_attribute_t of type KEY_LENGTH. + * + * @param key_length key length in bytes + * @return transform_attribute_t object + */ +transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length); + +#endif /** TRANSFORM_ATTRIBUTE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c new file mode 100644 index 000000000..c94f6c1a2 --- /dev/null +++ b/src/libcharon/encoding/payloads/transform_substructure.c @@ -0,0 +1,402 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "transform_substructure.h" + +#include <encoding/payloads/transform_attribute.h> +#include <encoding/payloads/encodings.h> +#include <library.h> +#include <utils/linked_list.h> +#include <daemon.h> + + +typedef struct private_transform_substructure_t private_transform_substructure_t; + +/** + * Private data of an transform_substructure_t object. + * + */ +struct private_transform_substructure_t { + /** + * Public transform_substructure_t interface. + */ + transform_substructure_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + + /** + * Length of this payload. + */ + u_int16_t transform_length; + + + /** + * Type of the transform. + */ + u_int8_t transform_type; + + /** + * Transform ID. + */ + u_int16_t transform_id; + + /** + * Transforms Attributes are stored in a linked_list_t. + */ + linked_list_t *attributes; +}; + + +/** + * 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_rule_t transform_substructure_encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, + /* Reserved Byte is skipped */ + { RESERVED_BYTE, 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) }, + /* Reserved Byte is skipped */ + { RESERVED_BYTE, 0 }, + /* tranform 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) } +}; + +/* + 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 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! 0 (last) or 3 ! RESERVED ! Transform Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + !Transform Type ! RESERVED ! Transform ID ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Transform Attributes ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_transform_substructure_t *this) +{ + status_t status = SUCCESS; + iterator_t *iterator; + payload_t *current_attributes; + + if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != 3)) + { + /* must be 0 or 3 */ + DBG1(DBG_ENC, "inconsistent next payload"); + 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; + } + } + iterator = this->attributes->create_iterator(this->attributes,TRUE); + + while(iterator->iterate(iterator, (void**)¤t_attributes)) + { + status = current_attributes->verify(current_attributes); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "TRANSFORM_ATTRIBUTE verification failed"); + } + } + iterator->destroy(iterator); + + /* proposal number is checked in SA payload */ + return status; +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_transform_substructure_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = transform_substructure_encodings; + *rule_count = sizeof(transform_substructure_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_type(private_transform_substructure_t *this) +{ + return TRANSFORM_SUBSTRUCTURE; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_transform_substructure_t *this) +{ + return (this->next_payload); +} + +/** + * recompute the length of the payload. + */ +static void compute_length (private_transform_substructure_t *this) +{ + iterator_t *iterator; + payload_t *current_attribute; + size_t length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH; + + iterator = this->attributes->create_iterator(this->attributes,TRUE); + while (iterator->iterate(iterator, (void**)¤t_attribute)) + { + length += current_attribute->get_length(current_attribute); + } + iterator->destroy(iterator); + + this->transform_length = length; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_transform_substructure_t *this) +{ + compute_length(this); + return this->transform_length; +} + +/** + * Implementation of transform_substructure_t.create_transform_attribute_iterator. + */ +static iterator_t *create_transform_attribute_iterator (private_transform_substructure_t *this,bool forward) +{ + return this->attributes->create_iterator(this->attributes,forward); +} + +/** + * Implementation of transform_substructure_t.add_transform_attribute. + */ +static void add_transform_attribute (private_transform_substructure_t *this,transform_attribute_t *attribute) +{ + this->attributes->insert_last(this->attributes,(void *) attribute); + compute_length(this); +} + +/** + * Implementation of transform_substructure_t.set_is_last_transform. + */ +static void set_is_last_transform (private_transform_substructure_t *this, bool is_last) +{ + this->next_payload = (is_last) ? 0: TRANSFORM_TYPE_VALUE; +} + +/** + * Implementation of transform_substructure_t.get_is_last_transform. + */ +static bool get_is_last_transform (private_transform_substructure_t *this) +{ + return ((this->next_payload == TRANSFORM_TYPE_VALUE) ? FALSE : TRUE); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_transform_substructure_t *this,payload_type_t type) +{ +} + +/** + * Implementation of transform_substructure_t.set_transform_type. + */ +static void set_transform_type (private_transform_substructure_t *this,u_int8_t type) +{ + this->transform_type = type; +} + +/** + * Implementation of transform_substructure_t.get_transform_type. + */ +static u_int8_t get_transform_type (private_transform_substructure_t *this) +{ + return this->transform_type; +} + +/** + * Implementation of transform_substructure_t.set_transform_id. + */ +static void set_transform_id (private_transform_substructure_t *this,u_int16_t id) +{ + this->transform_id = id; +} + +/** + * Implementation of transform_substructure_t.get_transform_id. + */ +static u_int16_t get_transform_id (private_transform_substructure_t *this) +{ + return this->transform_id; +} + +/** + * Implementation of transform_substructure_t.clone. + */ +static transform_substructure_t *clone_(private_transform_substructure_t *this) +{ + private_transform_substructure_t *clone; + iterator_t *attributes; + transform_attribute_t *current_attribute; + + clone = (private_transform_substructure_t *) transform_substructure_create(); + clone->next_payload = this->next_payload; + clone->transform_type = this->transform_type; + clone->transform_id = this->transform_id; + + attributes = this->attributes->create_iterator(this->attributes, FALSE); + while (attributes->iterate(attributes, (void**)¤t_attribute)) + { + current_attribute = current_attribute->clone(current_attribute); + clone->public.add_transform_attribute(&clone->public, current_attribute); + } + attributes->destroy(attributes); + + return &clone->public; +} + + +/** + * Implementation of transform_substructure_t.get_key_length. + */ +static status_t get_key_length(private_transform_substructure_t *this, u_int16_t *key_length) +{ + iterator_t *attributes; + transform_attribute_t *current_attribute; + + attributes = this->attributes->create_iterator(this->attributes, TRUE); + while (attributes->iterate(attributes, (void**)¤t_attribute)) + { + if (current_attribute->get_attribute_type(current_attribute) == KEY_LENGTH) + { + *key_length = current_attribute->get_value(current_attribute); + attributes->destroy(attributes); + return SUCCESS; + } + } + attributes->destroy(attributes); + return FAILED; +} + + +/** + * Implementation of transform_substructure_t.destroy and payload_t.destroy. + */ +static void destroy(private_transform_substructure_t *this) +{ + this->attributes->destroy_offset(this->attributes, + offsetof(transform_attribute_t, destroy)); + free(this); +} + +/* + * Described in header. + */ +transform_substructure_t *transform_substructure_create() +{ + private_transform_substructure_t *this = malloc_thing(private_transform_substructure_t); + + /* payload interface */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.create_transform_attribute_iterator = (iterator_t * (*) (transform_substructure_t *,bool)) create_transform_attribute_iterator; + this->public.add_transform_attribute = (void (*) (transform_substructure_t *,transform_attribute_t *)) add_transform_attribute; + this->public.set_is_last_transform = (void (*) (transform_substructure_t *,bool)) set_is_last_transform; + this->public.get_is_last_transform = (bool (*) (transform_substructure_t *)) get_is_last_transform; + this->public.set_transform_type = (void (*) (transform_substructure_t *,u_int8_t)) set_transform_type; + this->public.get_transform_type = (u_int8_t (*) (transform_substructure_t *)) get_transform_type; + this->public.set_transform_id = (void (*) (transform_substructure_t *,u_int16_t)) set_transform_id; + this->public.get_transform_id = (u_int16_t (*) (transform_substructure_t *)) get_transform_id; + this->public.get_key_length = (status_t (*) (transform_substructure_t *,u_int16_t *)) get_key_length; + this->public.clone = (transform_substructure_t* (*) (transform_substructure_t *)) clone_; + this->public.destroy = (void (*) (transform_substructure_t *)) destroy; + + /* set default values of the fields */ + this->next_payload = NO_PAYLOAD; + this->transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH; + this->transform_id = 0; + this->transform_type = 0; + this->attributes = linked_list_create(); + + return (&(this->public)); +} + +/* + * Described in header + */ +transform_substructure_t *transform_substructure_create_type( + transform_type_t transform_type, + u_int16_t transform_id, u_int16_t key_length) +{ + transform_substructure_t *transform = transform_substructure_create(); + + transform->set_transform_type(transform,transform_type); + transform->set_transform_id(transform,transform_id); + + if (key_length) + { + transform_attribute_t *attribute; + + attribute = transform_attribute_create_key_length(key_length); + transform->add_transform_attribute(transform, attribute); + + } + return transform; +} + diff --git a/src/libcharon/encoding/payloads/transform_substructure.h b/src/libcharon/encoding/payloads/transform_substructure.h new file mode 100644 index 000000000..5d31f8c0a --- /dev/null +++ b/src/libcharon/encoding/payloads/transform_substructure.h @@ -0,0 +1,174 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 transform_substructure transform_substructure + * @{ @ingroup payloads + */ + +#ifndef TRANSFORM_SUBSTRUCTURE_H_ +#define TRANSFORM_SUBSTRUCTURE_H_ + +typedef struct transform_substructure_t transform_substructure_t; + +#include <library.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/transform_attribute.h> +#include <utils/linked_list.h> +#include <crypto/diffie_hellman.h> +#include <crypto/signers/signer.h> +#include <crypto/prfs/prf.h> +#include <crypto/crypters/crypter.h> +#include <config/proposal.h> + + +/** + * IKEv1 Value for a transform payload. + */ +#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. + */ +struct transform_substructure_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Creates an iterator of stored transform_attribute_t objects. + * + * When deleting an transform attribute using this iterator, + * the length of this transform substructure has to be refreshed + * by calling get_length(). + * + * @param forward iterator direction (TRUE: front to end) + * @return created iterator_t object. + */ + iterator_t * (*create_transform_attribute_iterator) ( + transform_substructure_t *this, bool forward); + + /** + * Adds a transform_attribute_t object to this object. + * + * @param proposal transform_attribute_t object to add + */ + void (*add_transform_attribute) (transform_substructure_t *this, + transform_attribute_t *attribute); + + /** + * Sets the next_payload field of this substructure + * + * If this is the last transform, next payload field is set to 0, + * otherwise to 3 + * + * @param is_last When TRUE, next payload field is set to 0, otherwise to 3 + */ + void (*set_is_last_transform) (transform_substructure_t *this, bool is_last); + + /** + * Checks if this is the last transform. + * + * @return TRUE if this is the last Transform, FALSE otherwise + */ + bool (*get_is_last_transform) (transform_substructure_t *this); + + /** + * Sets transform type of the current transform substructure. + * + * @param type type value to set + */ + void (*set_transform_type) (transform_substructure_t *this, u_int8_t type); + + /** + * get transform type of the current transform. + * + * @return Transform type of current transform substructure. + */ + u_int8_t (*get_transform_type) (transform_substructure_t *this); + + /** + * Sets transform id of the current transform substructure. + * + * @param id transform id to set + */ + void (*set_transform_id) (transform_substructure_t *this, u_int16_t id); + + /** + * get transform id of the current transform. + * + * @return Transform id of current transform substructure. + */ + u_int16_t (*get_transform_id) (transform_substructure_t *this); + + /** + * get transform id of the current transform. + * + * @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! + */ + status_t (*get_key_length) (transform_substructure_t *this, + u_int16_t *key_length); + + /** + * Clones an transform_substructure_t object. + * + * @return cloned transform_substructure_t object + */ + transform_substructure_t* (*clone) (transform_substructure_t *this); + + /** + * Destroys an transform_substructure_t object. + */ + void (*destroy) (transform_substructure_t *this); +}; + +/** + * Creates an empty transform_substructure_t object. + * + * @return created transform_substructure_t object + */ +transform_substructure_t *transform_substructure_create(void); + +/** + * Creates an empty transform_substructure_t object. + * + * The key length is used for the transport types ENCRYPTION_ALGORITHM, + * PSEUDO_RANDOM_FUNCTION, INTEGRITY_ALGORITHM. For all + * other transport types the key_length parameter is not used + * + * @param transform_type type of transform to create + * @param transform_id transform id specifying the specific algorithm of a transform type + * @param key_length Key length for key lenght attribute + * @return transform_substructure_t object + */ +transform_substructure_t *transform_substructure_create_type( + transform_type_t transform_type, u_int16_t transform_id, + u_int16_t key_length); + +#endif /** TRANSFORM_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/ts_payload.c b/src/libcharon/encoding/payloads/ts_payload.c new file mode 100644 index 000000000..6bf3e4293 --- /dev/null +++ b/src/libcharon/encoding/payloads/ts_payload.c @@ -0,0 +1,334 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "ts_payload.h" + +#include <encoding/payloads/encodings.h> +#include <utils/linked_list.h> + +typedef struct private_ts_payload_t private_ts_payload_t; + +/** + * Private data of an ts_payload_t object. + * + */ +struct private_ts_payload_t { + /** + * Public ts_payload_t interface. + */ + ts_payload_t public; + + /** + * TRUE if this TS payload is of type TSi, FALSE for TSr. + */ + bool is_initiator; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * Number of traffic selectors + */ + u_int8_t number_of_traffic_selectors; + + /** + * Contains the traffic selectors of type traffic_selector_substructure_t. + */ + linked_list_t *traffic_selectors; +}; + +/** + * Encoding rules to parse or generate a TS payload + * + * The defined offsets are the positions in a object of type + * private_ts_payload_t. + * + */ +encoding_rule_t ts_payload_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 */ + { FLAG, offsetof(private_ts_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_ts_payload_t, payload_length)}, + /* 1 Byte TS type*/ + { U_INT_8, offsetof(private_ts_payload_t, number_of_traffic_selectors) }, + /* 3 reserved bytes */ + { RESERVED_BYTE, 0 }, + { RESERVED_BYTE, 0 }, + { RESERVED_BYTE, 0 }, + /* some ts data bytes, length is defined in PAYLOAD_LENGTH */ + { TRAFFIC_SELECTORS, offsetof(private_ts_payload_t, traffic_selectors) } +}; + +/* + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Number of TSs ! RESERVED ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ <Traffic Selectors> ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_ts_payload_t *this) +{ + iterator_t *iterator; + payload_t *current_traffic_selector; + status_t status = SUCCESS; + + if (this->number_of_traffic_selectors != (this->traffic_selectors->get_count(this->traffic_selectors))) + { + /* must be the same */ + return FAILED; + } + + iterator = this->traffic_selectors->create_iterator(this->traffic_selectors,TRUE); + while(iterator->iterate(iterator, (void**)¤t_traffic_selector)) + { + status = current_traffic_selector->verify(current_traffic_selector); + if (status != SUCCESS) + { + break; + } + } + iterator->destroy(iterator); + + return status; +} + +/** + * Implementation of ts_payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_ts_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = ts_payload_encodings; + *rule_count = sizeof(ts_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_payload_type(private_ts_payload_t *this) +{ + if (this->is_initiator) + { + return TRAFFIC_SELECTOR_INITIATOR; + } + else + { + return TRAFFIC_SELECTOR_RESPONDER; + } +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_ts_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_ts_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * recompute the length of the payload. + */ +static void compute_length (private_ts_payload_t *this) +{ + iterator_t *iterator; + size_t ts_count = 0; + size_t length = TS_PAYLOAD_HEADER_LENGTH; + payload_t *current_traffic_selector; + + iterator = this->traffic_selectors->create_iterator(this->traffic_selectors,TRUE); + while (iterator->iterate(iterator, (void**)¤t_traffic_selector)) + { + length += current_traffic_selector->get_length(current_traffic_selector); + ts_count++; + } + iterator->destroy(iterator); + + this->number_of_traffic_selectors= ts_count; + this->payload_length = length; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_ts_payload_t *this) +{ + compute_length(this); + return this->payload_length; +} + +/** + * Implementation of ts_payload_t.get_initiator. + */ +static bool get_initiator (private_ts_payload_t *this) +{ + return (this->is_initiator); +} + +/** + * Implementation of ts_payload_t.set_initiator. + */ +static void set_initiator (private_ts_payload_t *this,bool is_initiator) +{ + this->is_initiator = is_initiator; +} + +/** + * Implementation of ts_payload_t.add_traffic_selector_substructure. + */ +static void add_traffic_selector_substructure (private_ts_payload_t *this,traffic_selector_substructure_t *traffic_selector) +{ + this->traffic_selectors->insert_last(this->traffic_selectors,traffic_selector); + this->number_of_traffic_selectors = this->traffic_selectors->get_count(this->traffic_selectors); +} + +/** + * Implementation of ts_payload_t.create_traffic_selector_substructure_iterator. + */ +static iterator_t * create_traffic_selector_substructure_iterator (private_ts_payload_t *this, bool forward) +{ + return this->traffic_selectors->create_iterator(this->traffic_selectors,forward); +} + +/** + * Implementation of ts_payload_t.get_traffic_selectors. + */ +static linked_list_t *get_traffic_selectors(private_ts_payload_t *this) +{ + traffic_selector_t *ts; + iterator_t *iterator; + traffic_selector_substructure_t *ts_substructure; + linked_list_t *ts_list = linked_list_create(); + + iterator = this->traffic_selectors->create_iterator(this->traffic_selectors, TRUE); + while (iterator->iterate(iterator, (void**)&ts_substructure)) + { + ts = ts_substructure->get_traffic_selector(ts_substructure); + ts_list->insert_last(ts_list, (void*)ts); + } + iterator->destroy(iterator); + + return ts_list; +} + +/** + * Implementation of payload_t.destroy and ts_payload_t.destroy. + */ +static void destroy(private_ts_payload_t *this) +{ + this->traffic_selectors->destroy_offset(this->traffic_selectors, + offsetof(payload_t, destroy)); + free(this); +} + +/* + * Described in header + */ +ts_payload_t *ts_payload_create(bool is_initiator) +{ + private_ts_payload_t *this = malloc_thing(private_ts_payload_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.destroy = (void (*) (ts_payload_t *)) destroy; + this->public.get_initiator = (bool (*) (ts_payload_t *)) get_initiator; + this->public.set_initiator = (void (*) (ts_payload_t *,bool)) set_initiator; + this->public.add_traffic_selector_substructure = (void (*) (ts_payload_t *,traffic_selector_substructure_t *)) add_traffic_selector_substructure; + this->public.create_traffic_selector_substructure_iterator = (iterator_t* (*) (ts_payload_t *,bool)) create_traffic_selector_substructure_iterator; + this->public.get_traffic_selectors = (linked_list_t *(*) (ts_payload_t *)) get_traffic_selectors; + + /* private variables */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length =TS_PAYLOAD_HEADER_LENGTH; + this->is_initiator = is_initiator; + this->number_of_traffic_selectors = 0; + this->traffic_selectors = linked_list_create(); + + return &(this->public); +} + +/* + * Described in header + */ +ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, linked_list_t *traffic_selectors) +{ + iterator_t *iterator; + traffic_selector_t *ts; + traffic_selector_substructure_t *ts_substructure; + private_ts_payload_t *this; + + this = (private_ts_payload_t*)ts_payload_create(is_initiator); + + iterator = traffic_selectors->create_iterator(traffic_selectors, TRUE); + while (iterator->iterate(iterator, (void**)&ts)) + { + ts_substructure = traffic_selector_substructure_create_from_traffic_selector(ts); + this->public.add_traffic_selector_substructure(&(this->public), ts_substructure); + } + iterator->destroy(iterator); + + return &(this->public); +} + diff --git a/src/libcharon/encoding/payloads/ts_payload.h b/src/libcharon/encoding/payloads/ts_payload.h new file mode 100644 index 000000000..d322ff1a8 --- /dev/null +++ b/src/libcharon/encoding/payloads/ts_payload.h @@ -0,0 +1,127 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 ts_payload ts_payload + * @{ @ingroup payloads + */ + + +#ifndef TS_PAYLOAD_H_ +#define TS_PAYLOAD_H_ + +typedef struct ts_payload_t ts_payload_t; + +#include <library.h> +#include <utils/linked_list.h> +#include <selectors/traffic_selector.h> +#include <encoding/payloads/payload.h> +#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. + */ +struct ts_payload_t { + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the type of TSpayload (TSi or TSr). + * + * @return + * - TRUE if this payload is of type TSi + * - FALSE if this payload is of type TSr + */ + bool (*get_initiator) (ts_payload_t *this); + + /** + * Set the type of TS payload (TSi or TSr). + * + * @param is_initiator + * - TRUE if this payload is of type TSi + * - FALSE if this payload is of type TSr + */ + void (*set_initiator) (ts_payload_t *this,bool is_initiator); + + /** + * Adds a traffic_selector_substructure_t object to this object. + * + * @param traffic_selector traffic_selector_substructure_t object to add + */ + void (*add_traffic_selector_substructure) (ts_payload_t *this, + traffic_selector_substructure_t *traffic_selector); + + /** + * Creates an iterator of stored traffic_selector_substructure_t objects. + * + * When removing an traffic_selector_substructure_t object + * using this iterator, the length of this payload + * has to get refreshed by calling payload_t.get_length! + * + * @param forward iterator direction (TRUE: front to end) + * @return created iterator_t object + */ + iterator_t *(*create_traffic_selector_substructure_iterator) ( + ts_payload_t *this, bool forward); + + /** + * Get a list of nested traffic selectors as traffic_selector_t. + * + * Resulting list and its traffic selectors must be destroyed after usage + * + * @return list of traffic selectors + */ + linked_list_t *(*get_traffic_selectors) (ts_payload_t *this); + + /** + * Destroys an ts_payload_t object. + */ + void (*destroy) (ts_payload_t *this); +}; + +/** + * Creates an empty ts_payload_t object. + * + * @param is_initiator + * - TRUE if this payload is of type TSi + * - FALSE if this payload is of type TSr + * @return ts_payload_t object + */ +ts_payload_t *ts_payload_create(bool is_initiator); + +/** + * Creates ts_payload with a list of traffic_selector_t + * + * @param is_initiator + * - TRUE if this payload is of type TSi + * - FALSE if this payload is of type TSr + * @param traffic_selectors list of traffic selectors to include + * @return ts_payload_t object + */ +ts_payload_t *ts_payload_create_from_traffic_selectors(bool is_initiator, + linked_list_t *traffic_selectors); + +#endif /** TS_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/unknown_payload.c b/src/libcharon/encoding/payloads/unknown_payload.c new file mode 100644 index 000000000..dd5547dc3 --- /dev/null +++ b/src/libcharon/encoding/payloads/unknown_payload.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "unknown_payload.h" + + + +typedef struct private_unknown_payload_t private_unknown_payload_t; + +/** + * Private data of an unknown_payload_t object. + */ +struct private_unknown_payload_t { + + /** + * Public unknown_payload_t interface. + */ + unknown_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * The contained data. + */ + chunk_t data; +}; + +/** + * Encoding rules to parse an payload which is not further specified. + * + * The defined offsets are the positions in a object of type + * private_unknown_payload_t. + * + */ +encoding_rule_t unknown_payload_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 */ + { FLAG, offsetof(private_unknown_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* 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) } +}; + +/* + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Data of any type ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_unknown_payload_t *this) +{ + /* can't do any checks, so we assume its good */ + return SUCCESS; +} + +/** + * Implementation of payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_unknown_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +{ + *rules = unknown_payload_encodings; + *rule_count = sizeof(unknown_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_payload_type(private_unknown_payload_t *this) +{ + return UNKNOWN_PAYLOAD; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_unknown_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_unknown_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_unknown_payload_t *this) +{ + return this->payload_length; +} + +/** + * Implementation of unknown_payload_t.get_data. + */ +static bool is_critical(private_unknown_payload_t *this) +{ + return this->critical; +} + +/** + * Implementation of unknown_payload_t.get_data. + */ +static chunk_t get_data (private_unknown_payload_t *this) +{ + return (this->data); +} + +/** + * Implementation of payload_t.destroy and unknown_payload_t.destroy. + */ +static void destroy(private_unknown_payload_t *this) +{ + if (this->data.ptr != NULL) + { + chunk_free(&(this->data)); + } + + free(this); +} + +/* + * Described in header + */ +unknown_payload_t *unknown_payload_create() +{ + private_unknown_payload_t *this = malloc_thing(private_unknown_payload_t); + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + + /* public functions */ + this->public.destroy = (void (*) (unknown_payload_t *)) destroy; + this->public.is_critical = (bool (*) (unknown_payload_t *)) is_critical; + this->public.get_data = (chunk_t (*) (unknown_payload_t *)) get_data; + + /* private variables */ + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH; + this->data = chunk_empty; + + return (&(this->public)); +} diff --git a/src/libcharon/encoding/payloads/unknown_payload.h b/src/libcharon/encoding/payloads/unknown_payload.h new file mode 100644 index 000000000..c761ed2b6 --- /dev/null +++ b/src/libcharon/encoding/payloads/unknown_payload.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 unknown_payload unknown_payload + * @{ @ingroup payloads + */ + +#ifndef UNKNOWN_PAYLOAD_H_ +#define UNKNOWN_PAYLOAD_H_ + +typedef struct unknown_payload_t unknown_payload_t; + +#include <library.h> +#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 + * this class. This allows further processing of this payload, such as + * a check for the critical bit in the header. + */ +struct unknown_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the raw data of this payload, without + * the generic payload header. + * + * Returned data are NOT copied and must not be freed. + * + * @return data as chunk_t + */ + chunk_t (*get_data) (unknown_payload_t *this); + + /** + * Get the critical flag. + * + * @return TRUE if payload is critical, FALSE if not + */ + bool (*is_critical) (unknown_payload_t *this); + + /** + * Destroys an unknown_payload_t object. + */ + void (*destroy) (unknown_payload_t *this); +}; + +/** + * Creates an empty unknown_payload_t object. + * + * @return unknown_payload_t object + */ +unknown_payload_t *unknown_payload_create(void); + +#endif /** UNKNOWN_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.c b/src/libcharon/encoding/payloads/vendor_id_payload.c new file mode 100644 index 000000000..bf33d2418 --- /dev/null +++ b/src/libcharon/encoding/payloads/vendor_id_payload.c @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 "vendor_id_payload.h" + +typedef struct private_vendor_id_payload_t private_vendor_id_payload_t; + +/** + * Private data of an vendor_id_payload_t object. + */ +struct private_vendor_id_payload_t { + + /** + * Public vendor_id_payload_t interface. + */ + vendor_id_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Critical flag. + */ + bool critical; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * The contained data. + */ + chunk_t data; +}; + +/** + * Encoding rules to parse or generate a VENDOR ID payload + * + * The defined offsets are the positions in a object of type + * private_vendor_id_payload_t. + */ +encoding_rule_t vendor_id_payload_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 */ + { FLAG, offsetof(private_vendor_id_payload_t, critical) }, + /* 7 Bit reserved bits, nowhere stored */ + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + { RESERVED_BIT, 0 }, + /* 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) } +}; + +/* + 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + ! + ~ VID Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implementation of payload_t.verify. + */ +static status_t verify(private_vendor_id_payload_t *this) +{ + return SUCCESS; +} + +/** + * Implementation of vendor_id_payload_t.get_encoding_rules. + */ +static void get_encoding_rules(private_vendor_id_payload_t *this, + encoding_rule_t **rules, size_t *rule_count) +{ + *rules = vendor_id_payload_encodings; + *rule_count = sizeof(vendor_id_payload_encodings) / sizeof(encoding_rule_t); +} + +/** + * Implementation of payload_t.get_type. + */ +static payload_type_t get_payload_type(private_vendor_id_payload_t *this) +{ + return VENDOR_ID; +} + +/** + * Implementation of payload_t.get_next_type. + */ +static payload_type_t get_next_type(private_vendor_id_payload_t *this) +{ + return this->next_payload; +} + +/** + * Implementation of payload_t.set_next_type. + */ +static void set_next_type(private_vendor_id_payload_t *this,payload_type_t type) +{ + this->next_payload = type; +} + +/** + * Implementation of payload_t.get_length. + */ +static size_t get_length(private_vendor_id_payload_t *this) +{ + return this->payload_length; +} + +/** + * Implementation of vendor_id_payload_t.get_data. + */ +static chunk_t get_data(private_vendor_id_payload_t *this) +{ + return this->data; +} + +/** + * Implementation of payload_t.destroy and vendor_id_payload_t.destroy. + */ +static void destroy(private_vendor_id_payload_t *this) +{ + free(this->data.ptr); + free(this); +} + +/* + * Described in header + */ +vendor_id_payload_t *vendor_id_payload_create() +{ + private_vendor_id_payload_t *this = malloc_thing(private_vendor_id_payload_t); + + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (void (*) (payload_t *, encoding_rule_t **, size_t *) ) get_encoding_rules; + this->public.payload_interface.get_length = (size_t (*) (payload_t *)) get_length; + this->public.payload_interface.get_next_type = (payload_type_t (*) (payload_t *)) get_next_type; + this->public.payload_interface.set_next_type = (void (*) (payload_t *,payload_type_t)) set_next_type; + this->public.payload_interface.get_type = (payload_type_t (*) (payload_t *)) get_payload_type; + this->public.payload_interface.destroy = (void (*) (payload_t *))destroy; + this->public.get_data = (chunk_t (*) (vendor_id_payload_t *)) get_data; + + this->critical = FALSE; + this->next_payload = NO_PAYLOAD; + this->payload_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH; + this->data = chunk_empty; + + return &this->public; +} + +/* + * Described in header + */ +vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) +{ + private_vendor_id_payload_t *this; + + this = (private_vendor_id_payload_t*)vendor_id_payload_create(); + this->payload_length += data.len; + this->data = data; + + return &this->public; +} + diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.h b/src/libcharon/encoding/payloads/vendor_id_payload.h new file mode 100644 index 000000000..241535cac --- /dev/null +++ b/src/libcharon/encoding/payloads/vendor_id_payload.h @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2005-2009 Martin Willi + * Copyright (C) 2005 Jan Hutter + * Hochschule fuer Technik Rapperswil + * + * 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 vendor_id_payload vendor_id_payload + * @{ @ingroup payloads + */ + +#ifndef VENDOR_ID_PAYLOAD_H_ +#define VENDOR_ID_PAYLOAD_H_ + +typedef struct vendor_id_payload_t vendor_id_payload_t; + +#include <library.h> +#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. + * + * The VENDOR ID payload format is described in RFC section 3.12. + */ +struct vendor_id_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Get the VID data. + * + * @return VID data, pointing to an internal chunk_t + */ + chunk_t (*get_data)(vendor_id_payload_t *this); +}; + +/** + * Creates an empty Vendor ID payload. + * + * @return vendor ID payload + */ +vendor_id_payload_t *vendor_id_payload_create(); + +/** + * Creates a vendor ID payload using a chunk of data + * + * @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); + +#endif /** VENDOR_ID_PAYLOAD_H_ @}*/ |