diff options
Diffstat (limited to 'Source/charon/encoding')
26 files changed, 8738 insertions, 0 deletions
diff --git a/Source/charon/encoding/generator.c b/Source/charon/encoding/generator.c new file mode 100644 index 000000000..734c089a0 --- /dev/null +++ b/Source/charon/encoding/generator.c @@ -0,0 +1,1125 @@ +/** + * @file generator.c + * + * @brief Generic generator class used to generate IKEv2-header and payloads. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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 <types.h> +#include <globals.h> +#include <utils/allocator.h> +#include <utils/linked_list.h> +#include <utils/logger_manager.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> + +/** + * Private part of a generator_t object + */ +typedef struct private_generator_s private_generator_t; + +struct private_generator_s { + /** + * Public part of a generator_t object + */ + generator_t public; + + /* private functions and fields */ + + + /** + * Generates a U_INT-Field type and writes it to buffer. + * + * @param this private_generator_t object + * @param int_type type of U_INT field (U_INT_4, U_INT_8, etc.) + * ATTRIBUTE_TYPE is also generated in this function + * @param offset offset of value in data struct + * @param generator_contexts generator_contexts_t object where the context is written or read from + * @return - SUCCESS if succeeded + * - OUT_OF_RES if out of ressources + */ + status_t (*generate_u_int_type) (private_generator_t *this,encoding_type_t int_type,u_int32_t offset); + + /** + * Get size of current buffer in bytes. + * + * @param this private_generator_t object + * @return Size of buffer in bytes + */ + size_t (*get_current_buffer_size) (private_generator_t *this); + + /** + * Get free space of current buffer in bytes. + * + * @param this private_generator_t object + * @return space in buffer in bytes + */ + size_t (*get_current_buffer_space) (private_generator_t *this); + + /** + * Get length of data in buffer (in bytes). + * + * @param this private_generator_t object + * @return length of data in bytes + */ + size_t (*get_current_data_length) (private_generator_t *this); + + /** + * Get current offset in buffer (in bytes). + * + * @param this private_generator_t object + * @return offset in bytes + */ + u_int32_t (*get_current_buffer_offset) (private_generator_t *this); + + /** + * Generates a RESERVED BIT field or a RESERVED BYTE field and writes + * it to the buffer. + * + * @param this private_generator_t object + * @param generator_contexts generator_contexts_t object where the context is written or read from + * @param bits number of bits to generate + * @return - SUCCESS if succeeded + * - OUT_OF_RES if out of ressources + * - FAILED if bit count not supported + */ + status_t (*generate_reserved_field) (private_generator_t *this,int bits); + + /** + * Generates a FLAG field + * + * @param this private_generator_t object + * @param generator_contexts generator_contexts_t object where the context is written or read from + * @param offset offset of flag value in data struct + * @return - SUCCESS if succeeded + * - OUT_OF_RES if out of ressources + */ + status_t (*generate_flag) (private_generator_t *this,u_int32_t offset); + + /** + * Writes the current buffer content into a chunk_t + * + * Memory of specific chunk_t gets allocated. + * + * @param this calling private_generator_t object + * @param data pointer of chunk_t to write to + * @return + * - SUCCESSFUL if succeeded + * - OUT_OF_RES otherwise + */ + status_t (*write_chunk) (private_generator_t *this,chunk_t *data); + + /** + * Generates a bytestream from a chunk_t + * + * @param this private_generator_t object + * @param offset offset of chunk_t value in data struct + * @return - SUCCESS if succeeded + * - OUT_OF_RES if out of ressources + */ + status_t (*generate_from_chunk) (private_generator_t *this,u_int32_t offset); + + /** + * Makes sure enough space is available in buffer to store amount of bits. + * + * If buffer is to small to hold the specific amount of bits it + * is increased using reallocation function of allocator. + * + * @param this calling private_generator_t object + * @param bits number of bits to make available in buffer + * @return + * - SUCCESSFUL if succeeded + * - OUT_OF_RES otherwise + */ + status_t (*make_space_available) (private_generator_t *this,size_t bits); + + /** + * Writes a specific amount of byte into the buffer. + * + * If buffer is to small to hold the specific amount of bytes it + * is increased. + * + * @param this calling private_generator_t object + * @param bytes pointer to bytes to write + * @param number_of_bytes number of bytes to write into buffer + * @return + * - SUCCESSFUL if succeeded + * - OUT_OF_RES otherwise + */ + status_t (*write_bytes_to_buffer) (private_generator_t *this,void * bytes,size_t number_of_bytes); + + + /** + * Writes a specific amount of byte into the buffer at a specific offset. + * + * @warning buffer size is not check to hold the data if offset is to large. + * + * @param this calling private_generator_t object + * @param bytes pointer to bytes to write + * @param number_of_bytes number of bytes to write into buffer + * @param offset offset to write the data into + * @return + * - SUCCESSFUL if succeeded + * - OUT_OF_RES otherwise + */ + status_t (*write_bytes_to_buffer_at_offset) (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset); + + /** + * 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). + */ + size_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; + + /** + * Associated Logger + */ + logger_t *logger; +}; + +/** + * Implements private_generator_t's get_current_buffer_size function. + * See #private_generator_s.get_current_buffer_size. + */ +static size_t get_current_buffer_size (private_generator_t *this) +{ + return ((this->roof_position) - (this->buffer)); +} + +/** + * Implements private_generator_t's get_current_buffer_space function. + * See #private_generator_s.get_current_buffer_space. + */ +static size_t get_current_buffer_space (private_generator_t *this) +{ + /* we know, one byte more */ + size_t space = (this->roof_position) - (this->out_position); + return (space); +} + +/** + * Implements private_generator_t's get_current_buffer_space function. + * See #private_generator_s.get_current_buffer_space. + */ +static size_t get_current_data_length (private_generator_t *this) +{ + return (this->out_position - this->buffer); +} + +/** + * Implements private_generator_t's get_current_buffer_offset function. + * See #private_generator_s.get_current_buffer_offset. + */ +static u_int32_t get_current_buffer_offset (private_generator_t *this) +{ + return (this->out_position - this->buffer); +} + + +/** + * Implements private_generator_t's generate_u_int_type function. + * See #private_generator_s.generate_u_int_type. + */ +static status_t generate_u_int_type (private_generator_t *this,encoding_type_t int_type,u_int32_t offset) +{ + size_t number_of_bits = 0; + status_t status; + + /* find out number of bits of each U_INT type to check for enough space + in buffer */ + switch (int_type) + { + case U_INT_4: + number_of_bits = 4; + break; + case U_INT_8: + number_of_bits = 8; + break; + case U_INT_16: + number_of_bits = 16; + break; + case U_INT_32: + number_of_bits = 32; + break; + case U_INT_64: + number_of_bits = 64; + break; + case ATTRIBUTE_TYPE: + number_of_bits = 15; + break; + case IKE_SPI: + number_of_bits = 64; + break; + + default: + return FAILED; + } + /* U_INT Types of multiple then 8 bits must be aligned */ + if (((number_of_bits % 8) == 0) && (this->current_bit != 0)) + { + this->logger->log(this->logger, ERROR, "U_INT Type %s is not 8 Bit aligned", + mapping_find(encoding_type_m,int_type)); + /* current bit has to be zero for values multiple of 8 bits */ + return FAILED; + } + + /* make sure enough space is available in buffer */ + status = this->make_space_available(this,number_of_bits); + if (status != SUCCESS) + { + return status; + } + /* now handle each u int type differently */ + switch (int_type) + { + case U_INT_4: + { + if (this->current_bit == 0) + { + /* highval of current byte in buffer has to be set to the new value*/ + u_int8_t high_val = *((u_int8_t *)(this->data_struct + offset)) << 4; + /* lowval in buffer is not changed */ + u_int8_t low_val = *(this->out_position) & 0x0F; + /* highval is set, low_val is not changed */ + *(this->out_position) = high_val | low_val; + this->logger->log(this->logger, RAW|MOST, " => 0x%x", *(this->out_position)); + /* write position is not changed, just bit position is moved */ + this->current_bit = 4; + } + else if (this->current_bit == 4) + { + /* highval in buffer is not changed */ + u_int high_val = *(this->out_position) & 0xF0; + /* lowval of current byte in buffer has to be set to the new value*/ + u_int low_val = *((u_int8_t *)(this->data_struct + offset)) & 0x0F; + *(this->out_position) = high_val | low_val; + this->logger->log(this->logger, RAW|MOST, " => 0x%x", *(this->out_position)); + this->out_position++; + this->current_bit = 0; + + } + else + { + this->logger->log(this->logger, ERROR, "U_INT_4 Type is not 4 Bit aligned"); + /* 4 Bit integers must have a 4 bit alignment */ + return FAILED; + }; + break; + } + case U_INT_8: + { + /* 8 bit values are written as they are */ + *this->out_position = *((u_int8_t *)(this->data_struct + offset)); + this->logger->log(this->logger, RAW|MOST, " => 0x%x", *(this->out_position)); + this->out_position++; + break; + + } + case ATTRIBUTE_TYPE: + { + /* attribute type must not change first bit uf current byte ! */ + if (this->current_bit != 1) + { + this->logger->log(this->logger, ERROR, "ATTRIBUTE FORMAT flag is not set"); + /* first bit has to be set! */ + return FAILED; + } + /* get value of attribute format flag */ + u_int8_t attribute_format_flag = *(this->out_position) & 0x80; + /* get attribute type value as 16 bit integer*/ + u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset))); + /* last bit must be unset */ + int16_val = int16_val & 0xFF7F; + + int16_val = int16_val | attribute_format_flag; + this->logger->log(this->logger, RAW|MOST, " => 0x%x", int16_val); + /* write bytes to buffer (set bit is overwritten)*/ + this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t)); + this->current_bit = 0; + break; + + } + case U_INT_16: + { + u_int16_t int16_val = htons(*((u_int16_t*)(this->data_struct + offset))); + this->logger->log_bytes(this->logger, RAW|MOST, " =>", (void*)&int16_val, sizeof(int16_val)); + this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t)); + break; + } + case U_INT_32: + { + u_int32_t int32_val = htonl(*((u_int32_t*)(this->data_struct + offset))); + this->logger->log_bytes(this->logger, RAW|MOST, " =>", (void*)&int32_val, sizeof(int32_val)); + this->write_bytes_to_buffer(this,&int32_val,sizeof(u_int32_t)); + break; + } + case U_INT_64: + { + /* 64 bit integers are written as two 32 bit integers */ + u_int32_t int32_val_low = htonl(*((u_int32_t*)(this->data_struct + offset))); + u_int32_t int32_val_high = htonl(*((u_int32_t*)(this->data_struct + offset) + 1)); + this->logger->log_bytes(this->logger, RAW|MOST, " => (low)", (void*)&int32_val_low, sizeof(int32_val_low)); + this->logger->log_bytes(this->logger, RAW|MOST, " => (high)", (void*)&int32_val_high, sizeof(int32_val_high)); + /* TODO add support for big endian machines */ + this->write_bytes_to_buffer(this,&int32_val_high,sizeof(u_int32_t)); + this->write_bytes_to_buffer(this,&int32_val_low,sizeof(u_int32_t)); + break; + } + + case IKE_SPI: + { + /* 64 bit are written as they come :-) */ + this->write_bytes_to_buffer(this,(this->data_struct + offset),sizeof(u_int64_t)); + this->logger->log_bytes(this->logger, RAW|MOST, " =>", (void*)(this->data_struct + offset), sizeof(u_int64_t)); + break; + } + + default: + this->logger->log(this->logger, ERROR, "U_INT Type %s is not supported", mapping_find(encoding_type_m,int_type)); + return FAILED; + } + return SUCCESS; +} + +/** + * Implements private_generator_t's generate_reserved_field function. + * See #private_generator_s.generate_reserved_field. + */ +static status_t generate_reserved_field(private_generator_t *this,int bits) +{ + status_t status; + + /* only one bit or 8 bit fields are supported */ + if ((bits != 1) && (bits != 8)) + { + this->logger->log(this->logger, ERROR, "Reserved field of %d bits cannot be generated", bits); + return FAILED; + } + /* make sure enough space is available in buffer */ + status = this->make_space_available(this,bits); + if (status != SUCCESS) + { + return status; + } + + if (bits == 1) + { + /* one bit processing */ + 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 + { + /* one byte processing*/ + if (this->current_bit > 0) + { + this->logger->log(this->logger, ERROR, + "Reserved field cannot be written cause allignement of current bit is %d", + this->current_bit); + return FAILED; + } + *(this->out_position) = 0x00; + this->out_position++; + } + + return SUCCESS; + + +} + +/** + * Implements private_generator_t's generate_flag function. + * See #private_generator_s.generate_flag. + */ +static status_t generate_flag (private_generator_t *this,u_int32_t offset) +{ + status_t status; + /* value of current flag */ + u_int8_t flag_value; + /* position of flag in current byte */ + u_int8_t flag; + + /* if the value in the data_struct is TRUE, flag_value is set to 1, 0 otherwise */ + 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 */ + status = this->make_space_available(this,1); + if (status != SUCCESS) + { + return status; + } + if (this->current_bit == 0) + { + /* memory must be zero */ + *(this->out_position) = 0x00; + } + + *(this->out_position) = *(this->out_position) | flag; + + + this->logger->log(this->logger, RAW|MOST, " => 0x0%x", *(this->out_position)); + + this->current_bit++; + if (this->current_bit >= 8) + { + this->current_bit = this->current_bit % 8; + this->out_position++; + } + return SUCCESS; +} + +/** + * Implements private_generator_t's generate_from_chunk function. + * See #private_generator_s.generate_from_chunk. + */ +static status_t generate_from_chunk (private_generator_t *this,u_int32_t offset) +{ + if (this->current_bit != 0) + { + this->logger->log(this->logger, ERROR, "can not generate a chunk at Bitpos %d", this->current_bit); + return FAILED; + } + + /* position in buffer */ + chunk_t *attribute_value = (chunk_t *)(this->data_struct + offset); + + this->logger->log_chunk(this->logger, RAW|MOST, " =>", attribute_value); + + /* use write_bytes_to_buffer function to do the job */ + return this->write_bytes_to_buffer(this,attribute_value->ptr,attribute_value->len); + +} + +/** + * Implements private_generator_t's generator_context_make_space_available function. + * See #private_generator_s.generator_context_make_space_available. + */ +static status_t make_space_available (private_generator_t *this, size_t bits) +{ + while (((this->get_current_buffer_space(this) * 8) - this->current_bit) < bits) + { + /* must increase buffer */ + u_int8_t *new_buffer; + size_t old_buffer_size = this->get_current_buffer_size(this); + size_t new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE; + size_t out_position_offset = ((this->out_position) - (this->buffer)); + + this->logger->log(this->logger, CONTROL|MOST, "increased gen buffer from %d to %d byte", + old_buffer_size, new_buffer_size); + + /* Reallocate space for new buffer */ + new_buffer = allocator_realloc(this->buffer,new_buffer_size); + if (new_buffer == NULL) + { + this->logger->log(this->logger, ERROR, "reallocation of gen buffer failed!!!"); + return OUT_OF_RES; + } + + this->buffer = new_buffer; + + this->out_position = (this->buffer + out_position_offset); + this->roof_position = (this->buffer + new_buffer_size); + } + return SUCCESS; +} + +/** + * Implements private_generator_t's write_bytes_to_buffer function. + * See #private_generator_s.write_bytes_to_buffer. + */ +static status_t write_bytes_to_buffer (private_generator_t *this,void * bytes, size_t number_of_bytes) +{ + int i; + status_t status; + u_int8_t *read_position = (u_int8_t *) bytes; + + status = this->make_space_available(this,number_of_bytes * 8); + if (status != SUCCESS) + { + return status; + } + + for (i = 0; i < number_of_bytes; i++) + { + *(this->out_position) = *(read_position); + read_position++; + this->out_position++; + } + return status; +} + +/** + * Implements private_generator_t's write_bytes_to_buffer_at_offset function. + * See #private_generator_s.write_bytes_to_buffer_at_offset. + */ +static status_t write_bytes_to_buffer_at_offset (private_generator_t *this,void * bytes,size_t number_of_bytes,u_int32_t offset) +{ + int i; + status_t status; + u_int8_t *read_position = (u_int8_t *) bytes; + u_int8_t *write_position; + u_int32_t free_space_after_offset = (this->get_current_buffer_size(this) - offset); + + /* check first if enough space for new data is available */ + if (number_of_bytes > free_space_after_offset) + { + status = this->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++; + } + return SUCCESS; +} + +/** + * Implements generator_t's write_chunk function. + * See #generator_s.write_chunk. + */ +static status_t write_to_chunk (private_generator_t *this,chunk_t *data) +{ + size_t data_length = this->get_current_data_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 int32_val = htonl(header_length_field); + this->write_bytes_to_buffer_at_offset(this,&int32_val,sizeof(u_int32_t),this->header_length_position_offset); + } + + if (this->current_bit > 0) + data_length++; + data->ptr = allocator_alloc(data_length); + if (data->ptr == NULL) + { + data->len = 0; + this->logger->log(this->logger, ERROR, "not enougth ressources to allocate chunk"); + return OUT_OF_RES; + } + memcpy(data->ptr,this->buffer,data_length); + data->len = data_length; + + this->logger->log_chunk(this->logger, RAW, "generated data of this parser", data); + + return SUCCESS; +} + +/** + * Implements generator_t's generate_payload function. + * See #generator_s.generate_payload. + */ +static status_t generate_payload (private_generator_t *this,payload_t *payload) +{ + int i; + status_t status; + this->data_struct = payload; + size_t rule_count; + encoding_rule_t *rules; + payload_type_t payload_type; + u_int8_t *payload_start; + + /* get payload type */ + payload_type = payload->get_type(payload); + /* spi size has to get reseted */ + this->last_spi_size = 0; + + payload_start = this->out_position; + + this->logger->log(this->logger, CONTROL, "generating payload of type %s", + mapping_find(payload_type_m,payload_type)); + + /* each payload has its own encoding rules */ + payload->get_encoding_rules(payload,&rules,&rule_count); + + for (i = 0; i < rule_count;i++) + { + status = SUCCESS; + this->logger->log(this->logger, CONTROL|MORE, " generating rule %d %s", + i, mapping_find(encoding_type_m,rules[i].type)); + switch (rules[i].type) + { + /* all u int values, IKE_SPI and ATTRIBUTE_TYPE are generated in generate_u_int_type */ + case U_INT_4: + case U_INT_8: + case U_INT_16: + case U_INT_32: + case U_INT_64: + case IKE_SPI: + case ATTRIBUTE_TYPE: + { + status = this->generate_u_int_type(this,rules[i].type,rules[i].offset); + break; + } + case RESERVED_BIT: + { + status = this->generate_reserved_field(this,1); + break; + } + case RESERVED_BYTE: + { + status = this->generate_reserved_field(this,8); + break; + } + case FLAG: + { + status = this->generate_flag(this,rules[i].offset); + break; + } + case PAYLOAD_LENGTH: + { + /* position of payload lenght field is temporary stored */ + this->last_payload_length_position_offset = this->get_current_buffer_offset(this); + /* payload length is generated like an U_INT_16 */ + status = this->generate_u_int_type(this,U_INT_16,rules[i].offset); + break; + } + case HEADER_LENGTH: + { + /* position of header length field is temporary stored */ + this->header_length_position_offset = this->get_current_buffer_offset(this); + /* header length is generated like an U_INT_32 */ + status = this->generate_u_int_type(this,U_INT_32,rules[i].offset); + break; + } + case SPI_SIZE: + /* spi size is handled as 8 bit unsigned integer */ + status = this->generate_u_int_type(this,U_INT_8,rules[i].offset); + /* last spi size is temporary stored */ + this->last_spi_size = *((u_int8_t *)(this->data_struct + rules[i].offset)); + break; + case SPI: + { + /* the SPI value is generated from chunk */ + status = this->generate_from_chunk(this,rules[i].offset); + break; + } + case KEY_EXCHANGE_DATA: + { + /* the Key Exchange Data value is generated from chunk */ + status = this->generate_from_chunk(this,rules[i].offset); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "could no write key exchange data from chunk"); + return status; + } + + u_int32_t payload_length_position_offset = this->last_payload_length_position_offset; + /* Length of KE_PAYLOAD is calculated */ + u_int16_t length_of_ke_payload = KE_PAYLOAD_HEADER_LENGTH + ((chunk_t *)(this->data_struct + rules[i].offset))->len; + + u_int16_t int16_val = htons(length_of_ke_payload); + status = this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "could not write payload length into buffer"); + return status; + } + break; + } + case NOTIFICATION_DATA: + { + /* the Notification Data value is generated from chunk */ + status = this->generate_from_chunk(this,rules[i].offset); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not generate notification data from chunk"); + return status; + } + + u_int32_t payload_length_position_offset = this->last_payload_length_position_offset; + /* Length of Notification PAYLOAD is calculated */ + u_int16_t length_of_notify_payload = NOTIFY_PAYLOAD_HEADER_LENGTH + ((chunk_t *)(this->data_struct + rules[i].offset))->len; + length_of_notify_payload += this->last_spi_size; + u_int16_t int16_val = htons(length_of_notify_payload); + + status = this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "could not write payload length into buffer"); + return status; + } + break; + } + case NONCE_DATA: + { + /* the Nonce Data value is generated from chunk */ + status = this->generate_from_chunk(this, rules[i].offset); + + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "could not write nonce data from chunk"); + return status; + } + + u_int32_t payload_length_position_offset = this->last_payload_length_position_offset; + /* Length of nonce PAYLOAD is calculated */ + u_int16_t length_of_nonce_payload = NONCE_PAYLOAD_HEADER_LENGTH + ((chunk_t *)(this->data_struct + rules[i].offset))->len; + u_int16_t int16_val = htons(length_of_nonce_payload); + + status = this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "could not write payload length into buffer"); + return status; + } + break; + } + case PROPOSALS: + { + /* before iterative generate the transforms, store the current payload length position */ + 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; + /* proposals are stored in a linked list and so accessed */ + linked_list_t *proposals = *((linked_list_t **)(this->data_struct + rules[i].offset)); + + linked_list_iterator_t *iterator; + /* create forward iterator */ + status = proposals->create_iterator(proposals,&iterator,TRUE); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "could not create iterator for proposals"); + return status; + } + /* every proposal is processed (iterative call )*/ + while (iterator->has_next(iterator)) + { + payload_t *current_proposal; + u_int32_t before_generate_position_offset; + u_int32_t after_generate_position_offset; + + status = iterator->current(iterator,(void **)¤t_proposal); + if (status != SUCCESS) + { + iterator->destroy(iterator); + return status; + } + before_generate_position_offset = this->get_current_buffer_offset(this); + status = this->public.generate_payload(&(this->public),current_proposal); + after_generate_position_offset = this->get_current_buffer_offset(this); + if (status != SUCCESS) + { + iterator->destroy(iterator); + return status; + } + + /* increase size of transform */ + length_of_sa_payload += (after_generate_position_offset - before_generate_position_offset); + } + iterator->destroy(iterator); + + int16_val = htons(length_of_sa_payload); + status = this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "could not write payload length into buffer"); + return status; + } + break; + } + + case TRANSFORMS: + { + /* before iterative generate the transforms, store the current length position */ + 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)); + linked_list_iterator_t *iterator; + + /* create forward iterator */ + status = transforms->create_iterator(transforms,&iterator,TRUE); + if (status != SUCCESS) + { + return status; + } + while (iterator->has_next(iterator)) + { + payload_t *current_transform; + u_int32_t before_generate_position_offset; + u_int32_t after_generate_position_offset; + + status = iterator->current(iterator,(void **)¤t_transform); + if (status != SUCCESS) + { + iterator->destroy(iterator); + return status; + } + + before_generate_position_offset = this->get_current_buffer_offset(this); + status = this->public.generate_payload(&(this->public),current_transform); + after_generate_position_offset = this->get_current_buffer_offset(this); + if (status != SUCCESS) + { + iterator->destroy(iterator); + return status; + } + + /* increase size of transform */ + length_of_proposal += (after_generate_position_offset - before_generate_position_offset); + } + + iterator->destroy(iterator); + + int16_val = htons(length_of_proposal); + this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),payload_length_position_offset); + + break; + } + case TRANSFORM_ATTRIBUTES: + { + /* before iterative generate the transform attributes, store the current length position */ + 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)); + + linked_list_iterator_t *iterator; + /* create forward iterator */ + status = transform_attributes->create_iterator(transform_attributes,&iterator,TRUE); + if (status != SUCCESS) + { + return status; + } + while (iterator->has_next(iterator)) + { + payload_t *current_attribute; + u_int32_t before_generate_position_offset; + u_int32_t after_generate_position_offset; + + status = iterator->current(iterator,(void **)¤t_attribute); + if (status != SUCCESS) + { + iterator->destroy(iterator); + return status; + } + + before_generate_position_offset = this->get_current_buffer_offset(this); + this->public.generate_payload(&(this->public),current_attribute); + after_generate_position_offset = this->get_current_buffer_offset(this); + + /* increase size of transform */ + length_of_transform += (after_generate_position_offset - before_generate_position_offset); + } + + iterator->destroy(iterator); + + int16_val = htons(length_of_transform); + this->write_bytes_to_buffer_at_offset(this,&int16_val,sizeof(u_int16_t),transform_length_position_offset); + + break; + } + case ATTRIBUTE_FORMAT: + { + status = this->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) + { + status = this->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 + { + status = this->generate_u_int_type(this,U_INT_16,rules[i].offset); +// status = this->write_bytes_to_buffer(this,(this->data_struct + rules[i].offset),2); + } + break; + } + case ATTRIBUTE_VALUE: + { + if (this->attribute_format == FALSE) + { + this->logger->log(this->logger, CONTROL|MOST, "attribute value has not fixed size"); + /* the attribute value is generated */ + status = this->generate_from_chunk(this,rules[i].offset); + } + break; + } + default: + this->logger->log(this->logger, ERROR, "field type %s is not supported", + mapping_find(encoding_type_m,rules[i].type)); + return NOT_SUPPORTED; + } + } + this->logger->log_bytes(this->logger, RAW|MORE, "generated data for this payload", + payload_start, this->out_position-payload_start); + + return status; +} + +/** + * Implements generator_t's destroy function. + * See #generator_s.destroy. + */ +static status_t destroy(private_generator_t *this) +{ + allocator_free(this->buffer); + global_logger_manager->destroy_logger(global_logger_manager,this->logger); + allocator_free(this); + return SUCCESS; +} + +/* + * Described in header + */ +generator_t * generator_create() +{ + private_generator_t *this; + + this = allocator_alloc_thing(private_generator_t); + if (this == NULL) + { + return NULL; + } + + /* initiate public functions */ + this->public.generate_payload = (status_t(*)(generator_t*, payload_t *)) generate_payload; + this->public.destroy = (status_t(*)(generator_t*)) destroy; + this->public.write_to_chunk = (status_t (*) (generator_t *,chunk_t *)) write_to_chunk; + + + /* initiate private functions */ + this->get_current_buffer_size = get_current_buffer_size; + this->get_current_buffer_space = get_current_buffer_space; + this->get_current_data_length = get_current_data_length; + this->get_current_buffer_offset = get_current_buffer_offset; + this->generate_u_int_type = generate_u_int_type; + this->generate_reserved_field = generate_reserved_field; + this->generate_flag = generate_flag; + this->generate_from_chunk = generate_from_chunk; + this->make_space_available = make_space_available; + this->write_bytes_to_buffer = write_bytes_to_buffer; + this->write_bytes_to_buffer_at_offset = write_bytes_to_buffer_at_offset; + + + /* allocate memory for buffer */ + this->buffer = allocator_alloc(GENERATOR_DATA_BUFFER_SIZE); + if (this->buffer == NULL) + { + allocator_free(this); + return NULL; + } + + /* 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->logger = global_logger_manager->create_logger(global_logger_manager,GENERATOR,NULL); + this->logger->disable_level(this->logger, FULL); + this->logger->enable_level(this->logger, CONTROL); + + if (this->logger == NULL) + { + allocator_free(this->buffer); + allocator_free(this); + return NULL; + } + return &(this->public); +} diff --git a/Source/charon/encoding/generator.h b/Source/charon/encoding/generator.h new file mode 100644 index 000000000..312ac0054 --- /dev/null +++ b/Source/charon/encoding/generator.h @@ -0,0 +1,89 @@ +/** + * @file generator.h + * + * @brief Generic generator class used to generate IKEv2-header and payloads. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef GENERATOR_H_ +#define GENERATOR_H_ + +#include <types.h> +#include <encoding/payloads/encodings.h> +#include <encoding/payloads/payload.h> + +/** + * Generating is done in a data buffer. + * This is thehe start size of this buffer in Bytes. + */ +#define GENERATOR_DATA_BUFFER_SIZE 500 + +/** + * Number of bytes to increase the buffer, if it is to small. + */ +#define GENERATOR_DATA_BUFFER_INCREASE_VALUE 500 + +/** + *A generator_t object which generates payloads of specific type. + */ +typedef struct generator_s generator_t; + +struct generator_s { + + /** + * @brief Generates a specific payload from given payload object. + * + * Remember: Header and substructures are also handled as payloads. + * + * @param this generator_t object + * @param[in] payload interface payload_t implementing object + * @return + * - SUCCESSFUL if succeeded + * - OUT_OF_RES if out of ressources + */ + status_t (*generate_payload) (generator_t *this,payload_t *payload); + + /** + * Writes all generated data of current generator context to a chunk + * + * @param this generator_t object + * * @param[out] data chunk to write the data to + * @return + * @return + * - SUCCESSFUL if succeeded + * - OUT_OF_RES otherwise + */ + status_t (*write_to_chunk) (generator_t *this,chunk_t *data); + + /** + * @brief Destroys a generator_t object. + * + * @param this generator_t object + * + * @return always success + */ + status_t (*destroy) (generator_t *this); +}; + +/** + * Constructor to create a generator + * + */ +generator_t * generator_create(); + +#endif /*GENERATOR_H_*/ diff --git a/Source/charon/encoding/message.c b/Source/charon/encoding/message.c new file mode 100644 index 000000000..d32126ec0 --- /dev/null +++ b/Source/charon/encoding/message.c @@ -0,0 +1,877 @@ +/** + * @file message.c + * + * @brief Class message_t. Object of this type represents an IKEv2-Message. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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 "message.h" + +#include <types.h> +#include <globals.h> +#include <ike_sa_id.h> +#include <encoding/generator.h> +#include <encoding/parser.h> +#include <utils/linked_list.h> +#include <utils/allocator.h> +#include <utils/logger_manager.h> +#include <encoding/payloads/encodings.h> +#include <encoding/payloads/payload.h> + + +/** + * Supported payload entry used in message_rule_t + * + */ +typedef struct supported_payload_entry_s supported_payload_entry_t; + +struct supported_payload_entry_s { + /** + * 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; +}; + +/** + * Message Rule used to find out which payloads are supported by each message type + * + */ +typedef struct message_rule_s message_rule_t; + +struct message_rule_s { + /** + * Type of message + */ + exchange_type_t exchange_type; + + /** + * Is message a request or response + */ + bool is_request; + /** + * Number of supported payloads + */ + size_t supported_payloads_count; + /** + * Pointer to first supported payload entry + */ + supported_payload_entry_t *supported_payloads; +}; + +/** + * message rule for ike_sa_init from initiator + */ +static supported_payload_entry_t supported_ike_sa_init_i_payloads[] = +{ + {SECURITY_ASSOCIATION,1,1}, + {KEY_EXCHANGE,1,1}, + {NONCE,1,1}, +}; + +/** + * message rule for ike_sa_init from responder + */ +static supported_payload_entry_t supported_ike_sa_init_r_payloads[] = +{ + {SECURITY_ASSOCIATION,1,1}, + {KEY_EXCHANGE,1,1}, + {NONCE,1,1}, +}; + + +/** + * message rules, defines allowed payloads + */ +static message_rule_t message_rules[] = { + {IKE_SA_INIT,TRUE,(sizeof(supported_ike_sa_init_i_payloads)/sizeof(supported_payload_entry_t)),supported_ike_sa_init_i_payloads}, + {IKE_SA_INIT,FALSE,(sizeof(supported_ike_sa_init_r_payloads)/sizeof(supported_payload_entry_t)),supported_ike_sa_init_r_payloads} +}; + +/** + * Entry for a payload in the internal used linked list + * + */ +typedef struct payload_entry_s payload_entry_t; + +struct payload_entry_s { + /** + * Type of payload + */ + payload_type_t payload_type; + /** + * Data struct holding the data of given payload + */ + void *data_struct; +}; + + +/** + * Private data of an message_t object + */ +typedef struct private_message_s private_message_t; + +struct private_message_s { + + /** + * 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 request. + * FALSE if message is 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; + + /** + * logger for this message + */ + logger_t *logger; + + /** + * Gets a list of supported payloads of this message type + * + * @param this calling object + * @param[out] supported_payloads first entry of supported payloads + * @param[out] supported_payloads_count number of supported payload entries + * + * @return SUCCESS + * NOT_FOUND if no supported payload definition could be found + */ + status_t (*get_supported_payloads) (private_message_t *this, supported_payload_entry_t **supported_payloads,size_t *supported_payloads_count); + +}; + +/** + * Implements private_message_t's get_supported_payloads function. + * See #private_message_t.get_supported_payloads. + */ +status_t get_supported_payloads (private_message_t *this, supported_payload_entry_t **supported_payloads,size_t *supported_payloads_count) +{ + int i; + exchange_type_t exchange_type = this->public.get_exchange_type(&(this->public)); + bool is_request = this->public.get_request(&(this->public)); + + + for (i = 0; i < (sizeof(message_rules) / sizeof(message_rule_t)); i++) + { + if ((exchange_type == message_rules[i].exchange_type) && + (is_request == message_rules[i].is_request)) + { + /* found rule for given exchange_type*/ + *supported_payloads = message_rules[i].supported_payloads; + *supported_payloads_count = message_rules[i].supported_payloads_count; + + return SUCCESS; + } + + + } + *supported_payloads = NULL; + *supported_payloads_count = 0; + return NOT_FOUND; +} + +/** + * Implements message_t's set_ike_sa_id function. + * See #message_s.set_ike_sa_id. + */ +static status_t set_ike_sa_id (private_message_t *this,ike_sa_id_t *ike_sa_id) +{ + status_t status; + status = ike_sa_id->clone(ike_sa_id,&(this->ike_sa_id)); + return status; +} + +/** + * Implements message_t's get_ike_sa_id function. + * See #message_s.get_ike_sa_id. + */ +static status_t get_ike_sa_id (private_message_t *this,ike_sa_id_t **ike_sa_id) +{ + status_t status; + if (this->ike_sa_id == NULL) + { + return FAILED; + } + status = this->ike_sa_id->clone(this->ike_sa_id,ike_sa_id); + return status; +} + + +/** + * Implements message_t's set_message_id function. + * See #message_s.set_message_id. + */ +static status_t set_message_id (private_message_t *this,u_int32_t message_id) +{ + this->message_id = message_id; + return SUCCESS; +} + + +/** + * Implements message_t's set_message_id function. + * See #message_s.set_message_id. + */ +static u_int32_t get_message_id (private_message_t *this) +{ + return this->message_id; +} + +/** + * Implements message_t's get_responder_spi function. + * See #message_s.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)); +} + +/** + * Implements message_t's set_major_version function. + * See #message_s.set_major_version. + */ +static status_t set_major_version (private_message_t *this,u_int8_t major_version) +{ + this->major_version = major_version; + return SUCCESS; +} + + +/** + * Implements message_t's get_major_version function. + * See #message_s.get_major_version. + */ +static u_int8_t get_major_version (private_message_t *this) +{ + return this->major_version; +} + +/** + * Implements message_t's set_minor_version function. + * See #message_s.set_minor_version. + */ +static status_t set_minor_version (private_message_t *this,u_int8_t minor_version) +{ + this->minor_version = minor_version; + return SUCCESS; +} + + +/** + * Implements message_t's get_minor_version function. + * See #message_s.get_minor_version. + */ +static u_int8_t get_minor_version (private_message_t *this) +{ + return this->minor_version; +} + +/** + * Implements message_t's set_exchange_type function. + * See #message_s.set_exchange_type. + */ +static status_t set_exchange_type (private_message_t *this,exchange_type_t exchange_type) +{ + this->exchange_type = exchange_type; + return SUCCESS; +} + + +/** + * Implements message_t's get_exchange_type function. + * See #message_s.get_exchange_type. + */ +static exchange_type_t get_exchange_type (private_message_t *this) +{ + return this->exchange_type; +} + + +/** + * Implements message_t's set_request function. + * See #message_s.set_request. + */ +static status_t set_request (private_message_t *this,bool request) +{ + this->is_request = request; + return SUCCESS; +} + +/** + * Implements message_t's get_request function. + * See #message_s.get_request. + */ +static exchange_type_t get_request (private_message_t *this) +{ + return this->is_request; +} + +static status_t 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) != SUCCESS)) + { + return OUT_OF_RES; + } + + if (this->payloads->insert_last(this->payloads, payload) != SUCCESS) + { + return OUT_OF_RES; + } + if (this->payloads->get_count(this->payloads) == 1) + { + this->first_payload = payload->get_type(payload); + } + else + { + last_payload->set_next_type(last_payload,payload->get_type(payload)); + } + + this->logger->log(this->logger, CONTROL|MORE, "added payload of type %s to message", + mapping_find(payload_type_m, payload->get_type(payload))); + + return SUCCESS; +} + +static status_t set_source(private_message_t *this, host_t *host) +{ + if (this->packet->source != NULL) + { + this->packet->source->destroy(this->packet->source); + } + this->packet->source = host; + return SUCCESS; +} + +static status_t set_destination(private_message_t *this, host_t *host) +{ + if (this->packet->destination != NULL) + { + this->packet->destination->destroy(this->packet->destination); + } + this->packet->destination = host; + return SUCCESS; +} + +static status_t get_source(private_message_t *this, host_t **host) +{ + *host = this->packet->source; + return SUCCESS; +} + +static status_t get_destination(private_message_t *this, host_t **host) +{ + *host = this->packet->destination; + return SUCCESS; +} + + +static status_t get_payload_iterator(private_message_t *this, linked_list_iterator_t **iterator) +{ + return this->payloads->create_iterator(this->payloads, iterator, TRUE); +} + + +/** + * Implements message_t's generate function. + * See #message_s.generate. + */ +static status_t generate(private_message_t *this, packet_t **packet) +{ + generator_t *generator; + ike_header_t *ike_header; + payload_t *payload, *next_payload; + linked_list_iterator_t *iterator; + status_t status; + + + this->logger->log(this->logger, CONTROL, "generating message, contains %d payloads", + this->payloads->get_count(this->payloads)); + + if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED) + { + this->logger->log(this->logger, ERROR, "exchange type is not defined"); + return INVALID_STATE; + } + + if (this->packet->source == NULL || + this->packet->destination == NULL) + { + this->logger->log(this->logger, ERROR, "source/destination not defined"); + return INVALID_STATE; + } + + + ike_header = ike_header_create(); + if (ike_header == NULL) + { + return OUT_OF_RES; + } + + + 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(); + if (generator == NULL) + { + return OUT_OF_RES; + } + + payload = (payload_t*)ike_header; + + if (this->payloads->create_iterator(this->payloads, &iterator, TRUE) != SUCCESS) + { + generator->destroy(generator); + ike_header->destroy(ike_header); + return OUT_OF_RES; + } + while(iterator->has_next(iterator)) + { + iterator->current(iterator, (void**)&next_payload); + payload->set_next_type(payload, next_payload->get_type(next_payload)); + status = generator->generate_payload(generator, payload); + if (status != SUCCESS) + { + generator->destroy(generator); + ike_header->destroy(ike_header); + return status; + } + payload = next_payload; + } + iterator->destroy(iterator); + + payload->set_next_type(payload, NO_PAYLOAD); + status = generator->generate_payload(generator, payload); + if (status != SUCCESS) + { + generator->destroy(generator); + ike_header->destroy(ike_header); + return status; + } + + ike_header->destroy(ike_header); + + + + if (this->packet->data.ptr != NULL) + { + allocator_free(this->packet->data.ptr); + } + + status = generator->write_to_chunk(generator, &(this->packet->data)); + if (status != SUCCESS) + { + generator->destroy(generator); + return status; + } + + this->packet->clone(this->packet, packet); + + generator->destroy(generator); + + + this->logger->log(this->logger, CONTROL, "message generated successfully"); + return SUCCESS; +} + +/** + * Implements message_t's parse_header function. + * See #message_s.parse_header. + */ +static status_t parse_header(private_message_t *this) +{ + ike_header_t *ike_header; + status_t status; + + + this->logger->log(this->logger, CONTROL, "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) + { + this->logger->log(this->logger, ERROR, "Header could not be parsed"); + return status; + + } + + /* verify payload */ + status = ike_header->payload_interface.verify(&(ike_header->payload_interface)); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "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)); + if (this->ike_sa_id == NULL) + { + this->logger->log(this->logger, ERROR, "could not create ike_sa_id object"); + ike_header->destroy(ike_header); + return OUT_OF_RES; + } + 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)); + + + this->logger->log(this->logger, CONTROL, "parsing header successfully"); + + ike_header->destroy(ike_header); + return SUCCESS; +} + +/** + * Implements message_t's parse_body function. + * See #message_s.parse_body. + */ +static status_t parse_body (private_message_t *this) +{ + status_t status = SUCCESS; + int i; + payload_type_t current_payload_type = this->first_payload; + supported_payload_entry_t *supported_payloads; + size_t supported_payloads_count; + + + this->logger->log(this->logger, CONTROL, "parsing body of message"); + + if (this->get_supported_payloads (this, &supported_payloads, &supported_payloads_count) != SUCCESS) + { + this->logger->log(this->logger, ERROR, "could not get supported payloads"); + return FAILED; + } + + while (current_payload_type != NO_PAYLOAD) + { + payload_t *current_payload; + bool supported = FALSE; + + this->logger->log(this->logger, CONTROL|MORE, "start parsing payload of type %s", + mapping_find(payload_type_m, current_payload_type)); + for (i = 0; i < supported_payloads_count;i++) + { + if (supported_payloads[i].payload_type == current_payload_type) + { + supported = TRUE; + break; + } + } + if (!supported && (current_payload_type != NO_PAYLOAD)) + { + /* type not supported */ + status = NOT_SUPPORTED; + this->logger->log(this->logger, ERROR, "payload type %s not supported",mapping_find(payload_type_m,current_payload_type)); + break; + } + + status = this->parser->parse_payload(this->parser,current_payload_type,(payload_t **) ¤t_payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "payload type %s could not be parsed",mapping_find(payload_type_m,current_payload_type)); + break; + } + + status = current_payload->verify(current_payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "payload type %s could not be verified",mapping_find(payload_type_m,current_payload_type)); + status = VERIFY_ERROR; + break; + } + + /* get next payload type */ + current_payload_type = current_payload->get_next_type(current_payload); + + status = this->payloads->insert_last(this->payloads,current_payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not insert current payload to internal list cause of ressource exhausting"); + break; + } + + } + if (status != SUCCESS) + { + /* already parsed payload is destroyed later in destroy call from outside this object */ + } + else + { + linked_list_iterator_t *iterator; + + status = this->payloads->create_iterator(this->payloads,&iterator,TRUE); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not create iterator to check supported payloads"); + return status; + } + + /* check for payloads with wrong count*/ + for (i = 0; i < supported_payloads_count;i++) + { + size_t min_occurence = supported_payloads[i].min_occurence; + size_t max_occurence = supported_payloads[i].max_occurence; + payload_type_t payload_type = supported_payloads[i].payload_type; + size_t found_payloads = 0; + + iterator->reset(iterator); + + while(iterator->has_next(iterator)) + { + payload_t *current_payload; + status = iterator->current(iterator,(void **)¤t_payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, "Could not get payload from internal list"); + iterator->destroy(iterator); + return status; + } + if (current_payload->get_type(current_payload) == payload_type) + { + found_payloads++; + if (found_payloads > max_occurence) + { + this->logger->log(this->logger, ERROR, "Payload of type %s more than %d times (%d) occured in current message", + mapping_find(payload_type_m,current_payload->get_type(current_payload)),max_occurence,found_payloads); + iterator->destroy(iterator); + return NOT_SUPPORTED; + } + } + + } + if (found_payloads < min_occurence) + { + this->logger->log(this->logger, ERROR, "Payload of type %s not occured %d times", + mapping_find(payload_type_m,payload_type),min_occurence); + iterator->destroy(iterator); + return NOT_SUPPORTED; + } + + } + iterator->destroy(iterator); + } + return status; +} + + + +/** + * Implements message_t's destroy function. + * See #message_s.destroy. + */ +static status_t destroy (private_message_t *this) +{ + linked_list_iterator_t *iterator; + + this->packet->destroy(this->packet); + + if (this->ike_sa_id != NULL) + { + this->ike_sa_id->destroy(this->ike_sa_id); + } + + this->payloads->create_iterator(this->payloads, &iterator, TRUE); + while (iterator->has_next(iterator)) + { + payload_t *payload; + iterator->current(iterator, (void**)&payload); + this->logger->log(this->logger, CONTROL|MOST, "Destroying payload of type %s", + mapping_find(payload_type_m, payload->get_type(payload))); + payload->destroy(payload); + } + iterator->destroy(iterator); + this->payloads->destroy(this->payloads); + this->parser->destroy(this->parser); + global_logger_manager->destroy_logger(global_logger_manager, this->logger); + + allocator_free(this); + return SUCCESS; +} + +/* + * Described in Header-File + */ +message_t *message_create_from_packet(packet_t *packet) +{ + private_message_t *this = allocator_alloc_thing(private_message_t); + if (this == NULL) + { + return NULL; + } + + /* public functions */ + this->public.set_major_version = (status_t(*)(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 = (status_t(*)(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 = (status_t(*)(message_t*, u_int32_t))set_message_id; + this->public.get_message_id = (u_int32_t(*)(message_t*))get_message_id; + this->public.get_responder_spi = (u_int64_t(*)(message_t*))get_responder_spi; + this->public.set_ike_sa_id = (status_t(*)(message_t*, ike_sa_id_t *))set_ike_sa_id; + this->public.get_ike_sa_id = (status_t(*)(message_t*, ike_sa_id_t **))get_ike_sa_id; + this->public.set_exchange_type = (status_t(*)(message_t*, exchange_type_t))set_exchange_type; + this->public.get_exchange_type = (exchange_type_t(*)(message_t*))get_exchange_type; + this->public.set_request = (status_t(*)(message_t*, bool))set_request; + this->public.get_request = (bool(*)(message_t*))get_request; + this->public.add_payload = (status_t(*)(message_t*,payload_t*))add_payload; + this->public.generate = (status_t (*) (message_t *, packet_t**)) generate; + this->public.set_source = (status_t (*) (message_t*,host_t*)) set_source; + this->public.get_source = (status_t (*) (message_t*,host_t**)) get_source; + this->public.set_destination = (status_t (*) (message_t*,host_t*)) set_destination; + this->public.get_destination = (status_t (*) (message_t*,host_t**)) get_destination; + this->public.get_payload_iterator = (status_t (*) (message_t *, linked_list_iterator_t **)) get_payload_iterator; + this->public.parse_header = (status_t (*) (message_t *)) parse_header; + this->public.parse_body = (status_t (*) (message_t *)) parse_body; + this->public.destroy = (status_t(*)(message_t*))destroy; + + /* public 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 functions */ + this->get_supported_payloads = get_supported_payloads; + + /* private values */ + if (packet == NULL) + { + packet = packet_create(); + } + if (packet == NULL) + { + allocator_free(this); + return NULL; + } + this->packet = packet; + this->payloads = linked_list_create(); + if (this->payloads == NULL) + { + allocator_free(this); + return NULL; + } + + /* parser is created from data of packet */ + this->parser = parser_create(this->packet->data); + if (this->parser == NULL) + { + this->payloads->destroy(this->payloads); + allocator_free(this); + return NULL; + } + + this->logger = global_logger_manager->create_logger(global_logger_manager, MESSAGE, NULL); + if (this->logger == NULL) + { + this->parser->destroy(this->parser); + this->payloads->destroy(this->payloads); + allocator_free(this); + return NULL; + } + + return (&this->public); +} + +/* + * Described in Header-File + */ +message_t *message_create() +{ + return message_create_from_packet(NULL); +} diff --git a/Source/charon/encoding/message.h b/Source/charon/encoding/message.h new file mode 100644 index 000000000..960be94af --- /dev/null +++ b/Source/charon/encoding/message.h @@ -0,0 +1,280 @@ +/** + * @file message.h + * + * @brief Class message_t. Object of this type represents an IKEv2-Message. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef MESSAGE_H_ +#define MESSAGE_H_ + +#include <types.h> +#include <ike_sa_id.h> +#include <network/packet.h> +#include <encoding/payloads/ike_header.h> +#include <utils/linked_list.h> + + + + +/** + * @brief This class is used to represent an IKEv2-Message. + * + * An IKEv2-Message is either a request or response. + */ +typedef struct message_s message_t; + +struct message_s { + + /** + * @brief Sets the IKE major version of the message. + * + * @param this message_t object + * @param major_version major version to set + * @return SUCCESS + */ + status_t (*set_major_version) (message_t *this,u_int8_t major_version); + + /** + * @brief Gets the IKE major version of the message. + * + * @param this message_t object + * @return major version of the message + */ + u_int8_t (*get_major_version) (message_t *this); + + /** + * @brief Sets the IKE minor version of the message. + * + * @param this message_t object + * @param minor_version minor version to set + * @return SUCCESS + */ + status_t (*set_minor_version) (message_t *this,u_int8_t minor_version); + + /** + * @brief Gets the IKE minor version of the message. + * + * @param this message_t object + * @return minor version of the message + */ + u_int8_t (*get_minor_version) (message_t *this); + + /** + * @brief Sets the Message ID of the message. + * + * @param this message_t object + * @param message_id message_id to set + * @return SUCCESS + */ + status_t (*set_message_id) (message_t *this,u_int32_t message_id); + + /** + * @brief Gets the Message ID of the message. + * + * @param this message_t object + * @return message_id type of the message + */ + u_int32_t (*get_message_id) (message_t *this); + + /** + * @brief Gets the responder SPI of the message. + * + * @param this message_t object + * @return responder spi of the message + */ + u_int64_t (*get_responder_spi) (message_t *this); + + /** + * @brief Sets the IKE_SA ID of the message. + * + * @warning ike_sa_id gets cloned internaly and + * so can be destroyed afterwards. + * + * @param this message_t object + * @param ike_sa_id ike_sa_id to set + * @return + * - SUCCESS + * - OUT_OF_RES + * @return SUCCESS + */ + status_t (*set_ike_sa_id) (message_t *this,ike_sa_id_t * ike_sa_id); + + /** + * @brief Gets the IKE_SA ID of the message. + * + * @warning The returned ike_sa_id is a clone of the internal one. + * So it has to be destroyed by the caller. + * + * @param this message_t object + * @param ike_sa_id pointer to ike_sa_id pointer which will be set + * @return + * - SUCCESS + * - OUT_OF_RES + * - FAILED if no ike_sa_id is set + */ + status_t (*get_ike_sa_id) (message_t *this,ike_sa_id_t **ike_sa_id); + + /** + * @brief Sets the exchange type of the message. + * + * @param this message_t object + * @param exchange_type exchange_type to set + * @return SUCCESS + */ + status_t (*set_exchange_type) (message_t *this,exchange_type_t exchange_type); + + /** + * @brief Gets the exchange type of the message. + * + * @param this message_t object + * @return exchange type of the message + */ + exchange_type_t (*get_exchange_type) (message_t *this); + + /** + * @brief Sets the original initiator flag. + * + * @param this message_t object + * @param original_initiator TRUE if message is from original initiator + * @return SUCCESS + */ + status_t (*set_original_initiator) (message_t *this,bool original_initiator); + + /** + * @brief Gets original initiator flag. + * + * @param this message_t object + * @return TRUE if message is from original initiator, FALSE otherwise + */ + bool (*get_original_initiator) (message_t *this); + + /** + * @brief Sets the request flag. + * + * @param this message_t object + * @param original_initiator TRUE if message is a request, FALSE if it is a reply + * @return SUCCESS + */ + status_t (*set_request) (message_t *this,bool request); + + /** + * @brief Gets request flag. + * + * @param this message_t object + * @return TRUE if message is a request, FALSE if it is a reply + */ + bool (*get_request) (message_t *this); + + /** + * @brief Append a payload to the message. + * + * @param this message_t object + * @param payload payload to append + * @return + * - SUCCESS or + * - OUT_OF_RES + */ + status_t (*add_payload) (message_t *this, payload_t *payload); + + /** + * @brief Parses header of message + * + * @param this message_t object + * @return + * - SUCCESS if header could be parsed + * - OUT_OF_RES if out of ressources + * - PARSE_ERROR if corrupted/invalid data found + * - FAILED if consistence check of header failed + */ + status_t (*parse_header) (message_t *this); + + /** + * @brief Parses body of message + * + * @param this message_t object + * @return + * - SUCCESS if header could be parsed + * - NOT_SUPPORTED if unsupported payload are contained in body + * - OUT_OF_RES if out of ressources + * - FAILED if message type is not suppported! + * - PARSE_ERROR if corrupted/invalid data found + * - VERIFY_ERROR if verification of some payload failed + */ + status_t (*parse_body) (message_t *this); + + /** + * @brief Generates the UDP packet of specific message + * + * @param this message_t object + * @return + * - SUCCESS if packet could be generated + * - EXCHANGE_TYPE_NOT_SET if exchange type is currently not set + * .... + */ + status_t (*generate) (message_t *this, packet_t **packet); + status_t (*get_source) (message_t *this, host_t **host); + status_t (*set_source) (message_t *this, host_t *host); + status_t (*get_destination) (message_t *this, host_t **host); + status_t (*set_destination) (message_t *this, host_t *host); + status_t (*get_payload_iterator) (message_t *this, linked_list_iterator_t **iterator); + + /** + * @brief Destroys a message and all including objects + * + * @param this message_t object + * @return SUCCESS + */ + status_t (*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. + * + * @warning Packet is not parsed in here! + * + * - exchange_type is set to NOT_SET + * - original_initiator is set to TRUE + * - is_request is set to TRUE + * + * @param packet packet_t object which is assigned to message + * + * @return + * - created message_t object + * - NULL if out of ressources + */ +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 + * - created message_t object + * - NULL if out of ressources + */ +message_t * message_create(); + +#endif /*MESSAGE_H_*/ diff --git a/Source/charon/encoding/parser.c b/Source/charon/encoding/parser.c new file mode 100644 index 000000000..cf7d0b8ee --- /dev/null +++ b/Source/charon/encoding/parser.c @@ -0,0 +1,923 @@ +/** + * @file parser.c + * + * @brief Generic parser class used to parse IKEv2-Header and Payload + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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 "parser.h" + +#include <types.h> +#include <definitions.h> +#include <globals.h> +#include <utils/allocator.h> +#include <utils/logger.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/notify_payload.h> + + + +/** + * @private data stored in a context + * + * contains pointers and counters to store current state + */ +typedef struct private_parser_s private_parser_t; + +struct private_parser_s { + /** + * Public members, see parser_t + */ + parser_t public; + + /** + * @brief parse a 4-Bit unsigned integer from the current parsing position. + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer where to write the parsed result + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_uint4) (private_parser_t *this, int rule_number, u_int8_t *output_pos); + + /** + * @brief parse a 8-Bit unsigned integer from the current parsing position. + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer where to write the parsed result + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_uint8) (private_parser_t *this, int rule_number, u_int8_t *output_pos); + + /** + * @brief parse a 15-Bit unsigned integer from the current parsing position. + * + * This is a special case used for ATTRIBUTE_TYPE. + * Big-/Little-endian conversion is done here. + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer where to write the parsed result + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_uint15) (private_parser_t *this, int rule_number, u_int16_t *output_pos); + + /** + * @brief parse a 16-Bit unsigned integer from the current parsing position. + * + * Big-/Little-endian conversion is done here. + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer where to write the parsed result + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_uint16) (private_parser_t *this, int rule_number, u_int16_t *output_pos); + + /** + * @brief parse a 32-Bit unsigned integer from the current parsing position. + * + * Big-/Little-endian conversion is done here. + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer where to write the parsed result + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_uint32) (private_parser_t *this, int rule_number, u_int32_t *output_pos); + + /** + * @brief parse a 64-Bit unsigned integer from the current parsing position. + * + * @todo add support for big-endian machines. + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer where to write the parsed result + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_uint64) (private_parser_t *this, int rule_number, u_int64_t *output_pos); + + /** + * @brief parse a given amount of bytes and writes them to a specific location + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer where to write the parsed result + * @param bytes number of bytes to parse + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_bytes) (private_parser_t *this, int rule_number, u_int8_t *output_pos,size_t bytes); + + /** + * @brief parse a single Bit from the current parsing position + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer where to write the parsed result + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_bit) (private_parser_t *this, int rule_number, bool *output_pos); + + /** + * @brief parse substructures in a list + * + * This function calls the parser recursivly to parse contained substructures + * in a linked_list_t. The list must already be created. Payload defines + * the type of the substructures. parsing is continued until the specified length + * is completely parsed. + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer of a linked_list where substructures are added + * @param payload_type type of the contained substructures to parse + * @param length number of bytes to parse in this list + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_list) (private_parser_t *this, int rule_number, linked_list_t **output_pos, payload_type_t payload_ype, size_t length); + + /** + * @brief parse data from current parsing position in a chunk. + * + * This function clones length number of bytes to output_pos, without + * modifiyng them. Space will be allocated and must be freed by caller. + * + * @param this parser object + * @param rule_number number of current rule + * @param[out] output_pos pointer of a chunk which will point to the allocated data + * @param length number of bytes to clone + * @return + * - SUCCESS or + * - PARSE_ERROR when not successful + */ + status_t (*parse_chunk) (private_parser_t *this, int rule_number, chunk_t *output_pos, size_t length); + + /** + * 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; + + /** + * logger object + */ + logger_t *logger; +}; + +/** + * implementation of private_parser_t.parse_uint4 + */ +static status_t 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) + { + this->logger->log(this->logger, ERROR, " not enough input to parse rule %d %s", + rule_number, mapping_find(encoding_type_m, + this->rules[rule_number].type)); + return PARSE_ERROR; + } + switch (this->bit_pos) + { + case 0: + /* caller interested in result ? */ + if (output_pos != NULL) + { + *output_pos = *(this->byte_pos) >> 4; + } + this->bit_pos = 4; + break; + case 4: + /* caller interested in result ? */ + if (output_pos != NULL) + { + *output_pos = *(this->byte_pos) & 0x0F; + } + this->bit_pos = 0; + this->byte_pos++; + break; + default: + this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d", + rule_number, mapping_find(encoding_type_m, + this->rules[rule_number].type), this->bit_pos); + return PARSE_ERROR; + } + + if (output_pos != NULL) + { + this->logger->log(this->logger, RAW|MOST, " => %d", *output_pos); + } + + + return SUCCESS; +} + +/** + * implementation of private_parser_t.parse_uint8 + */ +static status_t 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) + { + this->logger->log(this->logger, ERROR, " not enough input to parse rule %d %s", + rule_number, mapping_find(encoding_type_m, + this->rules[rule_number].type)); + return PARSE_ERROR; + } + if (this->bit_pos) + { + this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d", + rule_number, mapping_find(encoding_type_m, + this->rules[rule_number].type), this->bit_pos); + return PARSE_ERROR; + } + + /* caller interested in result ? */ + if (output_pos != NULL) + { + *output_pos = *(this->byte_pos); + this->logger->log(this->logger, RAW|MOST, " => %d", *output_pos); + } + this->byte_pos++; + + + + return SUCCESS; +} + +/** + * implementation of private_parser_t.parse_uint15 + */ +static status_t 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) + { + this->logger->log(this->logger, ERROR, " not enough input to parse rule %d %s", + rule_number, mapping_find(encoding_type_m, + this->rules[rule_number].type)); + return PARSE_ERROR; + } + if (this->bit_pos != 1) + { + this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type), + this->bit_pos); + return PARSE_ERROR; + } + /* caller interested in result ? */ + if (output_pos != NULL) + { + *output_pos = ntohs(*((u_int16_t*)this->byte_pos)) & ~0x8000; + this->logger->log(this->logger, RAW|MOST, " => %d", *output_pos); + } + this->byte_pos += 2; + this->bit_pos = 0; + + + + return SUCCESS; +} + +/** + * implementation of private_parser_t.parse_uint16 + */ +static status_t 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) + { + this->logger->log(this->logger, ERROR, " not enough input to parse rule %d %s", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type)); + return PARSE_ERROR; + } + if (this->bit_pos) + { + this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type), + this->bit_pos); + return PARSE_ERROR; + } + /* caller interested in result ? */ + if (output_pos != NULL) + { + *output_pos = ntohs(*((u_int16_t*)this->byte_pos)); + + this->logger->log(this->logger, RAW|MOST, " => %d", *output_pos); + } + this->byte_pos += 2; + + + return SUCCESS; +} +/** + * implementation of private_parser_t.parse_uint32 + */ +static status_t 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) + { + this->logger->log(this->logger, ERROR, " not enough input to parse rule %d %s", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type)); + return PARSE_ERROR; + } + if (this->bit_pos) + { + this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type), + this->bit_pos); + return PARSE_ERROR; + } + /* caller interested in result ? */ + if (output_pos != NULL) + { + *output_pos = ntohl(*((u_int32_t*)this->byte_pos)); + + this->logger->log(this->logger, RAW|MOST, " => %d", *output_pos); + } + this->byte_pos += 4; + + + return SUCCESS; +} + +/** + * implementation of private_parser_t.parse_uint64 + */ +static status_t parse_uint64(private_parser_t *this, int rule_number, u_int64_t *output_pos) +{ + if (this->byte_pos + sizeof(u_int64_t) > this->input_roof) + { + this->logger->log(this->logger, ERROR, " not enough input to parse rule %d %s", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type)); + return PARSE_ERROR; + } + if (this->bit_pos) + { + this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type), + this->bit_pos); + return PARSE_ERROR; + } + /* caller interested in result ? */ + if (output_pos != NULL) + { + /* assuming little endian host order */ + *(output_pos + 1) = ntohl(*((u_int32_t*)this->byte_pos)); + *output_pos = ntohl(*(((u_int32_t*)this->byte_pos) + 1)); + + this->logger->log_bytes(this->logger, RAW|MOST, " =>", (void*)output_pos, 8); + } + this->byte_pos += 8; + + + + return SUCCESS; +} + +static status_t parse_bytes (private_parser_t *this, int rule_number, u_int8_t *output_pos,size_t bytes) +{ + if (this->byte_pos + bytes > this->input_roof) + { + this->logger->log(this->logger, ERROR, " not enough input to parse rule %d %s", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type)); + return PARSE_ERROR; + } + if (this->bit_pos) + { + this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type), + this->bit_pos); + return PARSE_ERROR; + } + + /* caller interested in result ? */ + if (output_pos != NULL) + { + memcpy(output_pos,this->byte_pos,bytes); + + this->logger->log_bytes(this->logger, RAW|MOST, " =>", (void*)output_pos, bytes); + } + this->byte_pos += bytes; + + return SUCCESS; +} + +/** + * implementation of private_parser_t.parse_bit + */ +static status_t parse_bit(private_parser_t *this, int rule_number, bool *output_pos) +{ + if (this->byte_pos + sizeof(u_int8_t) > this->input_roof) + { + this->logger->log(this->logger, ERROR, " not enough input to parse rule %d %s", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type)); + return PARSE_ERROR; + } + /* caller interested in result ? */ + if (output_pos != NULL) + { + 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; + } + + this->logger->log(this->logger, RAW|MOST, " => %d", *output_pos); + } + this->bit_pos = (this->bit_pos + 1) % 8; + if (this->bit_pos == 0) + { + this->byte_pos++; + } + + + return SUCCESS; +} + +/** + * implementation of private_parser_t.parse_list + */ +static status_t parse_list(private_parser_t *this, int rule_number, linked_list_t **output_pos, payload_type_t payload_type, size_t length) +{ + linked_list_t * list = *output_pos; + + if (length < 0) + { + this->logger->log(this->logger, ERROR, " invalid length for rule %d %s", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type)); + return PARSE_ERROR; + } + + if (this->bit_pos) + { + this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type), this->bit_pos); + return PARSE_ERROR; + } + + while (length > 0) + { + u_int8_t *pos_before = this->byte_pos; + payload_t *payload; + status_t status; + this->logger->log(this->logger, CONTROL|MORE, " %d bytes left, parsing recursivly %s", + length, mapping_find(payload_type_m, payload_type)); + status = this->public.parse_payload((parser_t*)this, payload_type, &payload); + if (status != SUCCESS) + { + this->logger->log(this->logger, ERROR, " parsing of a %s substructure failed", + mapping_find(payload_type_m, payload_type)); + return status; + } + list->insert_last(list, payload); + length -= this->byte_pos - pos_before; + } + *output_pos = list; + return SUCCESS; +} + +/** + * implementation of private_parser_t.parse_chunk + */ +static status_t parse_chunk(private_parser_t *this, int rule_number, chunk_t *output_pos, size_t length) +{ + if (this->byte_pos + length > this->input_roof) + { + this->logger->log(this->logger, ERROR, " not enough input (%d bytes) to parse rule %d %s", + length, rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type)); + return PARSE_ERROR; + } + if (this->bit_pos) + { + this->logger->log(this->logger, ERROR, " found rule %d %s on bitpos %d", + rule_number, mapping_find(encoding_type_m, this->rules[rule_number].type), this->bit_pos); + return PARSE_ERROR; + } + if (output_pos != NULL) + { + output_pos->len = length; + output_pos->ptr = allocator_alloc(length); + if (output_pos->ptr == NULL) + { + this->logger->log(this->logger, ERROR, " allocation of chunk (%d bytes) failed", length); + return OUT_OF_RES; + } + memcpy(output_pos->ptr, this->byte_pos, length); + } + this->byte_pos += length; + this->logger->log_bytes(this->logger, RAW|MOST, " =>", (void*)output_pos->ptr, length); + + return SUCCESS; +} + +/** + * implementation of parser_context_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, payload_length, spi_size, attribute_length; + bool attribute_format; + int rule_number; + encoding_rule_t *rule; + + this->logger->log(this->logger, CONTROL, "parsing %s payload, %d bytes left", + mapping_find(payload_type_m, payload_type), + this->input_roof-this->byte_pos); + + this->logger->log_bytes(this->logger, RAW, "parsing payload from", this->byte_pos, + this->input_roof-this->byte_pos); + + /* ok, do the parsing */ + pld = payload_create(payload_type); + if (pld == NULL) + { + this->logger->log(this->logger, ERROR, " payload %s not supported", mapping_find(payload_type_m, payload_type)); + return NOT_SUPPORTED; + } + /* base pointer for output, avoids casting in every rule */ + output = pld; + + pld->get_encoding_rules(pld, &(this->rules), &rule_count); + + for (rule_number = 0; rule_number < rule_count; rule_number++) + { + rule = &(this->rules[rule_number]); + this->logger->log(this->logger, CONTROL|MORE, " parsing rule %d %s", + rule_number, mapping_find(encoding_type_m, rule->type)); + switch (rule->type) + { + case U_INT_4: + { + if (this->parse_uint4(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case U_INT_8: + { + if (this->parse_uint8(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case U_INT_16: + { + if (this->parse_uint16(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case U_INT_32: + { + if (this->parse_uint32(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case U_INT_64: + { + if (this->parse_uint64(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case IKE_SPI: + { + if (this->parse_bytes(this, rule_number, output + rule->offset,8) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case RESERVED_BIT: + { + if (this->parse_bit(this, rule_number, NULL) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case RESERVED_BYTE: + { + if (this->parse_uint8(this, rule_number, NULL) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case FLAG: + { + if (this->parse_bit(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case PAYLOAD_LENGTH: + { + if (this->parse_uint16(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + payload_length = *(u_int16_t*)(output + rule->offset); + break; + } + case HEADER_LENGTH: + { + if (this->parse_uint32(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case SPI_SIZE: + { + if (this->parse_uint8(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + spi_size = *(u_int8_t*)(output + rule->offset); + break; + } + case SPI: + { + if (this->parse_chunk(this, rule_number, output + rule->offset, spi_size) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case PROPOSALS: + { + size_t proposals_length = payload_length - SA_PAYLOAD_HEADER_LENGTH; + if (this->parse_list(this, rule_number, output + rule->offset, PROPOSAL_SUBSTRUCTURE, proposals_length) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case TRANSFORMS: + { + size_t transforms_length = payload_length - spi_size - PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH; + if (this->parse_list(this, rule_number, output + rule->offset, TRANSFORM_SUBSTRUCTURE, transforms_length) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case TRANSFORM_ATTRIBUTES: + { + size_t transform_a_length = payload_length - TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH; + if (this->parse_list(this, rule_number, output + rule->offset, TRANSFORM_ATTRIBUTE, transform_a_length) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case ATTRIBUTE_FORMAT: + { + if (this->parse_bit(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + attribute_format = *(bool*)(output + rule->offset); + break; + } + case ATTRIBUTE_TYPE: + { + if (this->parse_uint15(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + attribute_format = *(bool*)(output + rule->offset); + break; + } + case ATTRIBUTE_LENGTH_OR_VALUE: + { + if (this->parse_uint16(this, rule_number, output + rule->offset) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + attribute_length = *(u_int16_t*)(output + rule->offset); + break; + } + case ATTRIBUTE_VALUE: + { + if (attribute_format == FALSE) + { + if (this->parse_chunk(this, rule_number, output + rule->offset, attribute_length) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + } + break; + } + case NONCE_DATA: + { + size_t nonce_length = payload_length - NONCE_PAYLOAD_HEADER_LENGTH; + if (this->parse_chunk(this, rule_number, output + rule->offset, nonce_length) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case KEY_EXCHANGE_DATA: + { + size_t keydata_length = payload_length - KE_PAYLOAD_HEADER_LENGTH; + if (this->parse_chunk(this, rule_number, output + rule->offset, keydata_length) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + case NOTIFICATION_DATA: + { + size_t notify_length = payload_length - NOTIFY_PAYLOAD_HEADER_LENGTH - spi_size; + if (this->parse_chunk(this, rule_number, output + rule->offset, notify_length) != SUCCESS) + { + pld->destroy(pld); + return PARSE_ERROR; + } + break; + } + default: + { + this->logger->log(this->logger, ERROR, " no rule to parse rule %d %s (%d)", rule_number, mapping_find(encoding_type_m, rule->type), rule->type); + pld->destroy(pld); + return PARSE_ERROR; + } + } + /* process next rulue */ + rule++; + } + + *payload = pld; + + this->logger->log(this->logger, CONTROL, "parsing %s successful", mapping_find(payload_type_m, payload_type)); + return SUCCESS; +} + +/** + * implementation of parser_t.reset_context + */ +static status_t reset_context (private_parser_t *this) +{ + this->byte_pos = this->input; + this->bit_pos = 0; + return SUCCESS; +} + +/** + * implementation of parser_t.destroy + */ +static status_t destroy(private_parser_t *this) +{ + global_logger_manager->destroy_logger(global_logger_manager,this->logger); + allocator_free(this); + + return SUCCESS; +} + +/* + * see header file + */ +parser_t *parser_create(chunk_t data) +{ + private_parser_t *this = allocator_alloc_thing(private_parser_t); + + if (this == NULL) + { + return NULL; + } + + this->logger = global_logger_manager->create_logger(global_logger_manager, PARSER, NULL); + this->logger->disable_level(this->logger, FULL); + this->logger->enable_level(this->logger, CONTROL); + + + if (this->logger == NULL) + { + global_logger_manager->destroy_logger(global_logger_manager, this->logger); + allocator_free(this); + return NULL; + } + + this->public.parse_payload = (status_t(*)(parser_t*,payload_type_t,payload_t**)) parse_payload; + this->public.reset_context = (status_t(*)(parser_t*)) reset_context; + this->public.destroy = (status_t(*)(parser_t*)) destroy; + + + this->parse_uint4 = parse_uint4; + this->parse_uint8 = parse_uint8; + this->parse_uint15 = parse_uint15; + this->parse_uint16 = parse_uint16; + this->parse_uint32 = parse_uint32; + this->parse_uint64 = parse_uint64; + this->parse_bytes = parse_bytes; + this->parse_bit = parse_bit; + this->parse_list = parse_list; + this->parse_chunk = parse_chunk; + + this->input = data.ptr; + this->byte_pos = data.ptr; + this->bit_pos = 0; + this->input_roof = data.ptr + data.len; + + return (parser_t*)this; +} + diff --git a/Source/charon/encoding/parser.h b/Source/charon/encoding/parser.h new file mode 100644 index 000000000..9a99fabb4 --- /dev/null +++ b/Source/charon/encoding/parser.h @@ -0,0 +1,88 @@ +/** + * @file parser.h + * + * @brief Generic parser class used to parse IKEv2-Header and Payload + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef PARSER_H_ +#define PARSER_H_ + +#include <types.h> +#include <encoding/payloads/encodings.h> +#include <encoding/payloads/payload.h> + + +/** + * @brief A parser_t object which parses 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. + */ +typedef struct parser_s parser_t; + +struct parser_s { + + /** + * @brief parses the next payload + * + * @warning caller is responsible for freeing allocated payload + * + * Rules for parsing are described in the payload definition. + * + * @param this parser Object + * @param payload_type payload type to parse + * @param[out] payload pointer where parsed payload was allocated + * @return + * - SUCCESSFUL if succeeded, + * - NOT_SUPPORTED if payload_type is not supported + * - OUT_OF_RES if out of ressources + * - PARSE_ERROR if corrupted/invalid data found + */ + status_t (*parse_payload) (parser_t *this, payload_type_t payload_type, payload_t **payload); + + /** + * @brief Resets the current parser context + * + * @param parser parser object + * @return + * - SUCCESSFUL in any case + */ + status_t (*reset_context) (parser_t *this); + + /** + * @brief Destroys a parser object + * + * @param parser parser object + * @return + * - SUCCESSFUL in any case + */ + status_t (*destroy) (parser_t *this); +}; + +/** + * @brief Constructor to create a parser + * + * @param data chunk of data to parse with this parser object + * @return the parser, or NULL if failed + * + */ +parser_t *parser_create(chunk_t data); + +#endif /*PARSER_H_*/ diff --git a/Source/charon/encoding/payloads/encodings.c b/Source/charon/encoding/payloads/encodings.c new file mode 100644 index 000000000..4747ddc22 --- /dev/null +++ b/Source/charon/encoding/payloads/encodings.c @@ -0,0 +1,54 @@ +/** + * @file encodings.c + * + * @brief Type definitions for parser and generator, + * also payload types are defined here. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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" + + +mapping_t encoding_type_m[] = { + {U_INT_4, "U_INT_4"}, + {U_INT_8, "U_INT_8"}, + {U_INT_16, "U_INT_16"}, + {U_INT_32, "U_INT_32"}, + {U_INT_64, "U_INT_64"}, + {IKE_SPI, "IKE_SPI"}, + {RESERVED_BIT, "RESERVED_BIT"}, + {RESERVED_BYTE, "RESERVED_BYTE"}, + {FLAG, "FLAG"}, + {PAYLOAD_LENGTH, "PAYLOAD_LENGTH"}, + {HEADER_LENGTH, "HEADER_LENGTH"}, + {SPI_SIZE, "SPI_SIZE"}, + {SPI, "SPI"}, + {KEY_EXCHANGE_DATA, "KEY_EXCHANGE_DATA"}, + {NOTIFICATION_DATA, "NOTIFICATION_DATA"}, + {PROPOSALS, "PROPOSALS"}, + {TRANSFORMS, "TRANSFORMS"}, + {TRANSFORM_ATTRIBUTES, "TRANSFORM_ATTRIBUTES"}, + {ATTRIBUTE_FORMAT, "ATTRIBUTE_FORMAT"}, + {ATTRIBUTE_TYPE, "ATTRIBUTE_TYPE"}, + {ATTRIBUTE_LENGTH_OR_VALUE, "ATTRIBUTE_LENGTH_OR_VALUE"}, + {ATTRIBUTE_VALUE, "ATTRIBUTE_VALUE"}, + {NONCE_DATA, "NONCE_DATA"}, + {MAPPING_END, NULL} +}; + diff --git a/Source/charon/encoding/payloads/encodings.h b/Source/charon/encoding/payloads/encodings.h new file mode 100644 index 000000000..1401ea798 --- /dev/null +++ b/Source/charon/encoding/payloads/encodings.h @@ -0,0 +1,359 @@ +/** + * @file encodings.h + * + * @brief Type definitions for parser and generator, + * also payload types are 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 RFC for mor informations. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef ENCODINGS_H_ +#define ENCODINGS_H_ + +#include <types.h> +#include <definitions.h> + + +/** + * @brief 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. + */ +typedef enum encoding_type_e encoding_type_t; + +enum encoding_type_e{ + /** + * 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, + /** + * Representing a 64 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 64 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 64 bit forward afterwards. + */ + U_INT_64, + /** + * @brief 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, + /** + * @brief 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, + /** + * 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, + + /* + * 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 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 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 +}; + +/** + * mappings to map encoding_type_t's to strings + */ +extern mapping_t encoding_type_m[]; + +/** + * 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. + * + * For examples see directory encodings/. + * + * This rules are used by parser and generator. + */ +typedef struct encoding_rule_s encoding_rule_t; + +struct encoding_rule_s{ + /** + * 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/Source/charon/encoding/payloads/ike_header.c b/Source/charon/encoding/payloads/ike_header.c new file mode 100644 index 000000000..1f1c34253 --- /dev/null +++ b/Source/charon/encoding/payloads/ike_header.c @@ -0,0 +1,446 @@ +/** + * @file ike_header.c + * + * @brief Declaration of the class ike_header_t. + * + * An object of this type represents an ike header and is used to + * generate and parse ike headers. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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> +#include <utils/allocator.h> + +typedef struct private_ike_header_s private_ike_header_t; + +struct private_ike_header_s { + /** + * 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; +}; + +/** + * mappings used to get strings for exchange_type_t + */ +mapping_t exchange_type_m[] = { + {EXCHANGE_TYPE_UNDEFINED, "EXCHANGE_TYPE_UNDEFINED"}, + {IKE_SA_INIT, "IKE_SA_INIT"}, + {IKE_AUTH, "IKE_AUTH"}, + {CREATE_CHILD_SA, "CREATE_CHILD_SA"}, + {INFORMATIONAL, "INFORMATIONAL"} +}; + + +/** + * 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + +/** + * Implements payload_t's verify function. + * See #payload_s.verify for description. + */ +static status_t verify(private_ike_header_t *this) +{ + if ((this->exchange_type < IKE_SA_INIT) || (this->exchange_type > INFORMATIONAL)) + { + /* unsupported exchange type */ + return FAILED; + } + if (this->initiator_spi == 0) + { + /* initiator spi not set */ + return FAILED; + } + + if ((this->responder_spi == 0) && (!this->flags.initiator)) + { + /* must be original initiator*/ + return FAILED; + } + + if ((this->responder_spi == 0) && (this->flags.response)) + { + /* must be request*/ + return FAILED; + } + + /* verification of version is not done in here */ + + return SUCCESS; +} + +/** + * Implements payload_t's set_next_type function. + * See #payload_s.set_next_type for description. + */ +static status_t set_next_type(payload_t *this,payload_type_t type) +{ + ((private_ike_header_t *)this)->next_payload = type; + return SUCCESS; +} +/** + * Implements ike_header_t's get_initiator_spi fuction. + * See #ike_header_t.get_initiator_spi for description. + */ +static u_int64_t get_initiator_spi(private_ike_header_t *this) +{ + return this->initiator_spi; +} + +/** + * Implements ike_header_t's set_initiator_spi fuction. + * See #ike_header_t.set_initiator_spi for description. + */ +static void set_initiator_spi(private_ike_header_t *this, u_int64_t initiator_spi) +{ + this->initiator_spi = initiator_spi; +} + +/** + * Implements ike_header_t's get_responder_spi fuction. + * See #ike_header_t.get_responder_spi for description. + */ +static u_int64_t get_responder_spi(private_ike_header_t *this) +{ + return this->responder_spi; +} + +/** + * Implements ike_header_t's set_responder_spi fuction. + * See #ike_header_t.set_responder_spi for description. + */ +static void set_responder_spi(private_ike_header_t *this, u_int64_t responder_spi) +{ + this->responder_spi = responder_spi; +} + +/** + * Implements ike_header_t's get_maj_version fuction. + * See #ike_header_t.get_maj_version for description. + */ +static u_int8_t get_maj_version(private_ike_header_t *this) +{ + return this->maj_version; +} + +/** + * Implements ike_header_t's get_min_version fuction. + * See #ike_header_t.get_min_version for description. + */ +static u_int8_t get_min_version(private_ike_header_t *this) +{ + return this->min_version; +} + +/** + * Implements ike_header_t's get_response_flag fuction. + * See #ike_header_t.get_response_flag for description. + */ +static bool get_response_flag(private_ike_header_t *this) +{ + return this->flags.response; +} + +/** + * Implements ike_header_t's set_response_flag fuction. + * See #ike_header_t.set_response_flag for description. + */ +static void set_response_flag(private_ike_header_t *this, bool response) +{ + this->flags.response = response; +} + +/** + * Implements ike_header_t's get_version_flag fuction. + * See #ike_header_t.get_version_flag for description. + */ +static bool get_version_flag(private_ike_header_t *this) +{ + return this->flags.version; +} + +/** + * Implements ike_header_t's get_initiator_flag fuction. + * See #ike_header_t.get_initiator_flag for description. + */ +static bool get_initiator_flag(private_ike_header_t *this) +{ + return this->flags.initiator; +} + +/** + * Implements ike_header_t's set_initiator_flag fuction. + * See #ike_header_t.set_initiator_flag for description. + */ +static void set_initiator_flag(private_ike_header_t *this, bool initiator) +{ + this->flags.initiator = initiator; +} + +/** + * Implements ike_header_t's get_exchange_type function + * See #ike_header_t.get_exchange_type for description. + */ +static u_int8_t get_exchange_type(private_ike_header_t *this) +{ + return this->exchange_type; +} + +/** + * Implements ike_header_t's set_exchange_type function. + * See #ike_header_t.set_exchange_type for description. + */ +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; +} + +/** + * Implements ike_header_t's set_message_id function. + * See #ike_header_t.set_message_id for description. + */ +static void set_message_id(private_ike_header_t *this, u_int32_t message_id) +{ + this->message_id = message_id; +} + +/** + * Implements payload_t's and ike_header_t's destroy function. + * See #payload_s.destroy or ike_header_s.destroy for description. + */ +static status_t destroy(ike_header_t *this) +{ + allocator_free(this); + + return SUCCESS; +} + +/** + * Implements payload_t's get_encoding_rules function. + * See #payload_s.get_encoding_rules for description. + */ +static status_t 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); + + return SUCCESS; +} + +/** + * Implements payload_t's get_type function. + * See #payload_s.get_type for description. + */ +static payload_type_t get_type(payload_t *this) +{ + return HEADER; +} + +/** + * Implements payload_t's get_next_type function. + * See #payload_s.get_next_type for description. + */ +static payload_type_t get_next_type(payload_t *this) +{ + return (((private_ike_header_t*)this)->next_payload); +} + +/** + * Implements payload_t's get_length function. + * See #payload_s.get_length for description. + */ +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 = allocator_alloc_thing(private_ike_header_t); + if (this == NULL) + { + return NULL; + } + + 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 = (status_t (*) (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/Source/charon/encoding/payloads/ike_header.h b/Source/charon/encoding/payloads/ike_header.h new file mode 100644 index 000000000..ce52b55df --- /dev/null +++ b/Source/charon/encoding/payloads/ike_header.h @@ -0,0 +1,242 @@ +/** + * @file ike_header.h + * + * @brief Declaration of the class ike_header_t. + * + * An object of this type represents an ike header and is used to + * generate and parse ike headers. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef IKE_HEADER_H_ +#define IKE_HEADER_H_ + +#include <types.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 + +/** + * @brief Different types of IKE-Exchanges. + * + * See RFC for different types. + */ +typedef enum exchange_type_e exchange_type_t; + +enum exchange_type_e{ + + /** + * EXCHANGE_TYPE_UNDEFINED, not a official message type :-) + */ + EXCHANGE_TYPE_UNDEFINED = 240, + /** + * IKE_SA_INIT + */ + IKE_SA_INIT = 34, + /** + * IKE_AUTH + */ + IKE_AUTH = 35, + /** + * CREATE_CHILD_SA + */ + CREATE_CHILD_SA = 36, + /** + * INFORMATIONAL + */ + INFORMATIONAL = 37 +}; + +extern mapping_t exchange_type_m[]; + +/** + * Object representing an IKEv2-Header + * + * The header format of an IKEv2-Message is compatible to the + * ISAKMP-Header format to allow implementations supporting + * both versions of the IKE-protocol. + * + */ +typedef struct ike_header_s ike_header_t; + +struct ike_header_s { + /** + * implements payload_t interface + */ + payload_t payload_interface; + + /** + * @brief get the initiator spi + * + * @param this ike_header_t object + * @return initiator_spi + */ + u_int64_t (*get_initiator_spi) (ike_header_t *this); + + /** + * @brief set the initiator spi + * + * @param this ike_header_t object + * @param initiator_spi initiator_spi + */ + void (*set_initiator_spi) (ike_header_t *this, u_int64_t initiator_spi); + + /** + * @brief get the responder spi + * + * @param this ike_header_t object + * @return responder_spi + */ + u_int64_t (*get_responder_spi) (ike_header_t *this); + + /** + * @brief set the responder spi + * + * @param this ike_header_t object + * @param responder_spi responder_spi + */ + void (*set_responder_spi) (ike_header_t *this, u_int64_t responder_spi); + + /** + * @brief get the major version + * + * @param this ike_header_t object + * @return major version + */ + u_int8_t (*get_maj_version) (ike_header_t *this); + + /** + * @brief get the mainor version + * + * @param this ike_header_t object + * @return minor version + */ + u_int8_t (*get_min_version) (ike_header_t *this); + + /** + * @brief get the response flag + * + * @param this ike_header_t object + * @return response flag + */ + bool (*get_response_flag) (ike_header_t *this); + + /** + * @brief Set the response flag + * + * @param this ike_header_t object + * @param response response flag + * + */ + void (*set_response_flag) (ike_header_t *this, bool response); + /** + * @brief get "higher version supported"-flag + * + * @param this ike_header_t object + * @return version flag + */ + bool (*get_version_flag) (ike_header_t *this); + + /** + * @brief get the initiator flag + * + * @param this ike_header_t object + * @return initiator flag + */ + bool (*get_initiator_flag) (ike_header_t *this); + + /** + * @brief Set the initiator flag + * + * @param this ike_header_t object + * @param initiator initiator flag + * + */ + void (*set_initiator_flag) (ike_header_t *this, bool initiator); + + /** + * @brief get the exchange type + * + * @param this ike_header_t object + * @return exchange type + */ + u_int8_t (*get_exchange_type) (ike_header_t *this); + + /** + * @brief set the exchange type + * + * @param this ike_header_t object + * @param exchange_type exchange type + */ + void (*set_exchange_type) (ike_header_t *this, u_int8_t exchange_type); + + /** + * @brief get the message id + * + * @param this ike_header_t object + * @return message id + */ + u_int32_t (*get_message_id) (ike_header_t *this); + + /** + * @brief set the message id + * + * @param this ike_header_t object + * @param initiator_spi message id + */ + void (*set_message_id) (ike_header_t *this, u_int32_t message_id); + + /** + * @brief Destroys a ike_header_t object. + * + * @param this ike_header_t object to destroy + * @return + * SUCCESS in any case + */ + status_t (*destroy) (ike_header_t *this); +}; + +/** + * @brief Create an ike_header_t object + * + * @return + * - created ike_header, or + * - NULL if failed + */ + +ike_header_t *ike_header_create(); + +#endif /*IKE_HEADER_H_*/ diff --git a/Source/charon/encoding/payloads/ke_payload.c b/Source/charon/encoding/payloads/ke_payload.c new file mode 100644 index 000000000..478519634 --- /dev/null +++ b/Source/charon/encoding/payloads/ke_payload.c @@ -0,0 +1,319 @@ +/** + * @file ke_payload.c + * + * @brief Declaration of the class ke_payload_t. + * + * An object of this type represents an IKEv2 KE-Payload. + * + * See section 3.4 of RFC for details of this payload type. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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 "ke_payload.h" + +#include <encoding/payloads/encodings.h> +#include <utils/allocator.h> + + +/** + * Private data of an ke_payload_t Object + * + */ +typedef struct private_ke_payload_s private_ke_payload_t; + +struct private_ke_payload_s { + /** + * 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 + */ + diffie_hellman_group_t dh_group_number; + + /** + * Key Exchange Data of this KE payload + */ + chunk_t key_exchange_data; + + /** + * @brief Computes the length of this payload. + * + * @param this calling private_ke_payload_t object + * @return + * SUCCESS in any case + */ + status_t (*compute_length) (private_ke_payload_t *this); +}; + +/** + * 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 ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implements payload_t's verify function. + * See #payload_s.verify for description. + */ +static status_t verify(private_ke_payload_t *this) +{ + if (this->critical) + { + /* critical bit is set! */ + return FAILED; + } + + /* dh group is not verified in here */ + return SUCCESS; +} + +/** + * Implements payload_t's and ke_payload_t's destroy function. + * See #payload_s.destroy or ke_payload_s.destroy for description. + */ +static status_t destroy(private_ke_payload_t *this) +{ + if (this->key_exchange_data.ptr != NULL) + { + allocator_free(this->key_exchange_data.ptr); + } + allocator_free(this); + return SUCCESS; +} + +/** + * Implements payload_t's get_encoding_rules function. + * See #payload_s.get_encoding_rules for description. + */ +static status_t 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); + + return SUCCESS; +} + +/** + * Implements payload_t's get_type function. + * See #payload_s.get_type for description. + */ +static payload_type_t get_type(private_ke_payload_t *this) +{ + return KEY_EXCHANGE; +} + +/** + * Implements payload_t's get_next_type function. + * See #payload_s.get_next_type for description. + */ +static payload_type_t get_next_type(private_ke_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implements payload_t's set_next_type function. + * See #payload_s.set_next_type for description. + */ +static status_t set_next_type(private_ke_payload_t *this,payload_type_t type) +{ + this->next_payload = type; + return SUCCESS; +} + +/** + * Implements payload_t's get_length function. + * See #payload_s.get_length for description. + */ +static size_t get_length(private_ke_payload_t *this) +{ + this->compute_length(this); + return this->payload_length; +} + +/** + * Implements private_ke_payload_t's compute_length function. + * See #private_ke_payload_s.compute_length for description. + */ +static status_t 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; + + return SUCCESS; +} + + +/** + * Implements ke_payload_t's get_key_exchange_data function. + * See #ke_payload_t.get_key_exchange_data for description. + */ +chunk_t get_key_exchange_data(private_ke_payload_t *this) +{ + return (this->key_exchange_data); +} + +/** + * Implements ke_payload_t's set_key_exchange_data function. + * See #ke_payload_t.set_key_exchange_data for description. + */ +status_t 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 */ + allocator_free(this->key_exchange_data.ptr); + this->key_exchange_data.ptr = NULL; + this->key_exchange_data.len = 0; + + } + + this->key_exchange_data.ptr = allocator_clone_bytes(key_exchange_data.ptr,key_exchange_data.len); + if (this->key_exchange_data.ptr == NULL) + { + return OUT_OF_RES; + } + this->key_exchange_data.len = key_exchange_data.len; + this->compute_length(this); + + return SUCCESS; +} + +/** + * Implements ke_payload_t's get_dh_group_number function. + * See #ke_payload_t.get_dh_group_number for description. + */ +diffie_hellman_group_t get_dh_group_number(private_ke_payload_t *this) +{ + return this->dh_group_number; +} + +/** + * Implements ke_payload_t's set_dh_group_number function. + * See #ke_payload_t.set_dh_group_number for description. + */ +status_t set_dh_group_number(private_ke_payload_t *this, diffie_hellman_group_t dh_group_number) +{ + this->dh_group_number = dh_group_number; + return SUCCESS; +} + +/* + * Described in header + */ +ke_payload_t *ke_payload_create() +{ + private_ke_payload_t *this = allocator_alloc_thing(private_ke_payload_t); + if (this == NULL) + { + return NULL; + } + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (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 =(status_t (*) (ke_payload_t *,diffie_hellman_group_t)) set_dh_group_number; + this->public.destroy = (status_t (*) (ke_payload_t *)) destroy; + + /* private functions */ + this->compute_length = compute_length; + + /* set default values of the fields */ + this->critical = KE_PAYLOAD_CRITICAL_FLAG; + this->next_payload = NO_PAYLOAD; + this->payload_length = KE_PAYLOAD_HEADER_LENGTH; + this->key_exchange_data.ptr = NULL; + this->key_exchange_data.len = 0; + this->dh_group_number = 0; + + return (&(this->public)); +} diff --git a/Source/charon/encoding/payloads/ke_payload.h b/Source/charon/encoding/payloads/ke_payload.h new file mode 100644 index 000000000..8855941f1 --- /dev/null +++ b/Source/charon/encoding/payloads/ke_payload.h @@ -0,0 +1,120 @@ +/** + * @file ke_payload.h + * + * @brief Declaration of the class ke_payload_t. + * + * An object of this type represents an IKEv2 KE-Payload. + * + * See section 3.4 of RFC for details of this payload type. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef KE_PAYLOAD_H_ +#define KE_PAYLOAD_H_ + +#include <types.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/transform_substructure.h> +#include <utils/linked_list.h> + +/** + * Critical flag must not be set + */ +#define KE_PAYLOAD_CRITICAL_FLAG FALSE; + +/** + * KE payload length in bytes without any key exchange data + */ +#define KE_PAYLOAD_HEADER_LENGTH 8 + +/** + * Object representing an IKEv2-KE Payload + * + * The KE Payload format is described in RFC section 3.4. + * + */ +typedef struct ke_payload_s ke_payload_t; + +struct ke_payload_s { + /** + * implements payload_t interface + */ + payload_t payload_interface; + + /** + * @brief Returns the currently set key exchange data of this KE payload. + * + * @warning Returned data are not copied. + * + * @param this calling ke_payload_t object + * @return chunk_t pointing to the value + */ + chunk_t (*get_key_exchange_data) (ke_payload_t *this); + + /** + * @brief Sets the key exchange data of this KE payload. + * + * @warning Value is getting copied. + * + * @param this calling ke_payload_t object + * @param key_exchange_data chunk_t pointing to the value to set + * @return + * - SUCCESS or + * - OUT_OF_RES + */ + status_t (*set_key_exchange_data) (ke_payload_t *this, chunk_t key_exchange_data); + + /** + * @brief Gets the Diffie-Hellman Group Number of this KE payload. + * + * @param this calling ke_payload_t object + * @return DH Group Number of this payload + */ + diffie_hellman_group_t (*get_dh_group_number) (ke_payload_t *this); + + /** + * @brief Sets the Diffie-Hellman Group Number of this KE payload. + * + * @param this calling ke_payload_t object + * @param dh_group_number DH Group to set + * @return SUCCESS + */ + status_t (*set_dh_group_number) (ke_payload_t *this, diffie_hellman_group_t dh_group_number); + + /** + * @brief Destroys an ke_payload_t object. + * + * @param this ke_payload_t object to destroy + * @return + * SUCCESS in any case + */ + status_t (*destroy) (ke_payload_t *this); +}; + +/** + * @brief Creates an empty ke_payload_t object + * + * @return + * - created ke_payload_t object, or + * - NULL if failed + */ + +ke_payload_t *ke_payload_create(); + + +#endif /*KE_PAYLOAD_H_*/ diff --git a/Source/charon/encoding/payloads/nonce_payload.c b/Source/charon/encoding/payloads/nonce_payload.c new file mode 100644 index 000000000..fa3730e2f --- /dev/null +++ b/Source/charon/encoding/payloads/nonce_payload.c @@ -0,0 +1,271 @@ +/** + * @file nonce_payload.h + * + * @brief Declaration of the class nonce_payload_t. + * + * An object of this type represents an IKEv2 Nonce-Payload. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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> +#include <utils/allocator.h> + + + +/** + * Private data of an nonce_payload_t' Object + * + */ +typedef struct private_nonce_payload_s private_nonce_payload_t; + +struct private_nonce_payload_s { + /** + * 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; + + /** + * @brief Computes the length of this payload. + * + * @param this calling private_nonce_payload_t object + * @return + * SUCCESS in any case + */ + status_t (*compute_length) (private_nonce_payload_t *this); +}; + +/** + * 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 ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implements payload_t's verify function. + * See #payload_s.verify for description. + */ +static status_t verify(private_nonce_payload_t *this) +{ + if (this->critical) + { + /* critical bit is set! */ + return FAILED; + } + if ((this->nonce.len < 16) || ((this->nonce.len > 256))) + { + /* nonce length is wrong */ + return FAILED; + } + + return SUCCESS; +} + +/** + * Implements nonce_payload_t's set_nonce function. + * See #nonce_payload_t.set_nonce for description. + */ +static status_t set_nonce(private_nonce_payload_t *this, chunk_t nonce) +{ + if (nonce.len >= 16 && nonce.len <= 256) + { + + this->nonce.ptr = allocator_clone_bytes(nonce.ptr, nonce.len); + if (this->nonce.ptr == NULL) + { + return OUT_OF_RES; + } + this->nonce.len = nonce.len; + this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + nonce.len; + return SUCCESS; + } + return INVALID_ARG; +} + +/** + * Implements nonce_payload_t's get_nonce function. + * See #nonce_payload_t.get_nonce for description. + */ +static status_t get_nonce(private_nonce_payload_t *this, chunk_t *nonce) +{ + nonce->ptr = allocator_clone_bytes(this->nonce.ptr,this->nonce.len); + if (nonce->ptr == NULL) + { + return OUT_OF_RES; + } + nonce->len = this->nonce.len; + return SUCCESS; +} + + +/** + * Implements payload_t's get_encoding_rules function. + * See #payload_s.get_encoding_rules for description. + */ +static status_t 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); + + return SUCCESS; +} + +/** + * Implements payload_t's get_type function. + * See #payload_s.get_type for description. + */ +static payload_type_t get_type(private_nonce_payload_t *this) +{ + return NONCE; +} + +/** + * Implements payload_t's get_next_type function. + * See #payload_s.get_next_type for description. + */ +static payload_type_t get_next_type(private_nonce_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implements payload_t's set_next_type function. + * See #payload_s.set_next_type for description. + */ +static status_t set_next_type(private_nonce_payload_t *this,payload_type_t type) +{ + this->next_payload = type; + return SUCCESS; +} + +/** + * Implements payload_t's get_length function. + * See #payload_s.get_length for description. + */ +static size_t get_length(private_nonce_payload_t *this) +{ + this->compute_length(this); + return this->payload_length; +} + +/** + * Implements payload_t's and nonce_payload_t's destroy function. + * See #payload_s.destroy or nonce_payload_s.destroy for description. + */ +static status_t destroy(private_nonce_payload_t *this) +{ + if (this->nonce.ptr != NULL) + { + allocator_free(this->nonce.ptr); + } + + allocator_free(this); + return SUCCESS; +} + +/* + * Described in header + */ +nonce_payload_t *nonce_payload_create() +{ + private_nonce_payload_t *this = allocator_alloc_thing(private_nonce_payload_t); + if (this == NULL) + { + return NULL; + } + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (payload_t *))destroy; + + /* public functions */ + this->public.destroy = (status_t (*) (nonce_payload_t *)) destroy; + this->public.set_nonce = (status_t (*) (nonce_payload_t *,chunk_t)) set_nonce; + this->public.get_nonce = (status_t (*) (nonce_payload_t *,chunk_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/Source/charon/encoding/payloads/nonce_payload.h b/Source/charon/encoding/payloads/nonce_payload.h new file mode 100644 index 000000000..7768fa990 --- /dev/null +++ b/Source/charon/encoding/payloads/nonce_payload.h @@ -0,0 +1,93 @@ +/** + * @file nonce_payload.h + * + * @brief Declaration of the class nonce_payload_t. + * + * An object of this type represents an IKEv2 Nonce-Payload. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef NONCE_PAYLOAD_H_ +#define NONCE_PAYLOAD_H_ + +#include <types.h> +#include <encoding/payloads/payload.h> + +/** + * length of a nonce payload without a nonce in int + */ +#define NONCE_PAYLOAD_HEADER_LENGTH 4 + +/** + * Object representing an IKEv2 Nonce payload + * + * The Nonce payload format is described in draft section 3.3. + * + */ +typedef struct nonce_payload_s nonce_payload_t; + +struct nonce_payload_s { + /** + * implements payload_t interface + */ + payload_t payload_interface; + + /** + * @brief Set the nonce value. + * + * The nonce must have length between 16 and 256 bytes + * + * @param this calling nonce_payload_t object + * @param nonce chunk containing the nonce, will be cloned + * @return + * - SUCCESS or + * - INVALID_ARG, if nonce has an invalid size + */ + status_t (*set_nonce) (nonce_payload_t *this, chunk_t nonce); + + /** + * @brief Get the nonce value. + * + * @param this calling nonce_payload_t object + * @param[out] nonce chunk where nonce data is located (cloned) + * @return SUCCESS in any case + */ + status_t (*get_nonce) (nonce_payload_t *this, chunk_t *nonce); + + /** + * @brief Destroys an nonce_payload_t object. + * + * @param this nonce_payload_t object to destroy + * @return + * SUCCESS in any case + */ + status_t (*destroy) (nonce_payload_t *this); +}; + +/** + * @brief Creates an empty nonce_payload_t object + * + * @return + * - created nonce_payload_t object, or + * - NULL if failed + */ + +nonce_payload_t *nonce_payload_create(); + + +#endif /*NONCE_PAYLOAD_H_*/ diff --git a/Source/charon/encoding/payloads/notify_payload.c b/Source/charon/encoding/payloads/notify_payload.c new file mode 100644 index 000000000..adcde11a2 --- /dev/null +++ b/Source/charon/encoding/payloads/notify_payload.c @@ -0,0 +1,419 @@ +/** + * @file notify_payload.c + * + * @brief Declaration of the class notify_payload_t. + * + * An object of this type represents an IKEv2 Notify-Payload. + * + * See section 3.10 of Draft for details of this payload type. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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 "notify_payload.h" + +#include <encoding/payloads/encodings.h> +#include <utils/allocator.h> + +/** + * Private data of an notify_payload_t Object + * + */ +typedef struct private_notify_payload_s private_notify_payload_t; + +struct private_notify_payload_s { + /** + * 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_message_type; + + /** + * Security parameter index (spi) + */ + chunk_t spi; + + /** + * Notification data + */ + chunk_t notification_data; + + /** + * @brief Computes the length of this payload. + * + * @param this calling private_ke_payload_t object + * @return + * SUCCESS in any case + */ + status_t (*compute_length) (private_notify_payload_t *this); +}; + +/** + * 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_message_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 ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implements payload_t's verify function. + * See #payload_s.verify for description. + */ +static status_t verify(private_notify_payload_t *this) +{ + if (this->critical) + { + /* critical bit is set! */ + return FAILED; + } + if (this->protocol_id > 3) + { + /* reserved for future use */ + return FAILED; + } + + /* notify message types and data is not getting checked in here */ + + return SUCCESS; +} + +/** + * Implements payload_t's get_encoding_rules function. + * See #payload_s.get_encoding_rules for description. + */ +static status_t 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); + return SUCCESS; +} + +/** + * Implements payload_t's get_type function. + * See #payload_s.get_type for description. + */ +static payload_type_t get_type(private_notify_payload_t *this) +{ + return KEY_EXCHANGE; +} + +/** + * Implements payload_t's get_next_type function. + * See #payload_s.get_next_type for description. + */ +static payload_type_t get_next_type(private_notify_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implements payload_t's set_next_type function. + * See #payload_s.set_next_type for description. + */ +static status_t set_next_type(private_notify_payload_t *this,payload_type_t type) +{ + this->next_payload = type; + return SUCCESS; +} + +/** + * Implements payload_t's get_length function. + * See #payload_s.get_length for description. + */ +static size_t get_length(private_notify_payload_t *this) +{ + this->compute_length(this); + return this->payload_length; +} + +/** + * Implements private_ke_payload_t's compute_length function. + * See #private_ke_payload_s.compute_length for description. + */ +static status_t 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; + + return SUCCESS; +} + + +/** + * Implements notify_payload_t's get_protocol_id function. + * See #notify_payload_s.get_protocol_id for description. + */ +u_int8_t get_protocol_id(private_notify_payload_t *this) +{ + return this->protocol_id; +} + +/** + * Implements notify_payload_t's set_protocol_id function. + * See #notify_payload_s.set_protocol_id for description. + */ +status_t set_protocol_id(private_notify_payload_t *this, u_int8_t protocol_id) +{ + this->protocol_id = protocol_id; + return SUCCESS; +} + +/** + * Implements notify_payload_t's get_notification_data function. + * See #notify_payload_s.get_notification_data for description. + */ +u_int16_t get_notify_message_type(private_notify_payload_t *this) +{ + return this->notify_message_type; +} + +/** + * Implements notify_payload_t's get_notification_data function. + * See #notify_payload_s.get_notification_data for description. + */ +status_t set_notify_message_type(private_notify_payload_t *this, u_int16_t notify_message_type) +{ + this->notify_message_type = notify_message_type; + return SUCCESS; +} + +/** + * Implements notify_payload_t's get_spi function. + * See #notify_payload_s.get_spi for description. + */ +chunk_t get_spi(private_notify_payload_t *this) +{ + return (this->spi); +} + +/** + * Implements notify_payload_t's set_spi function. + * See #notify_payload_s.set_spi for description. + */ +status_t set_spi(private_notify_payload_t *this, chunk_t spi) +{ + /* destroy existing data first */ + if (this->spi.ptr != NULL) + { + /* free existing value */ + allocator_free(this->spi.ptr); + this->spi.ptr = NULL; + this->spi.len = 0; + + } + + this->spi.ptr = allocator_clone_bytes(spi.ptr,spi.len); + if (this->spi.ptr == NULL) + { + return OUT_OF_RES; + } + this->spi.len = spi.len; + this->spi_size = spi.len; + this->compute_length(this); + + return SUCCESS; +} + + +/** + * Implements notify_payload_t's get_notification_data function. + * See #notify_payload_s.get_notification_data for description. + */ +chunk_t get_notification_data(private_notify_payload_t *this) +{ + return (this->notification_data); +} + +/** + * Implements notify_payload_t's get_notification_data function. + * See #notify_payload_s.get_notification_data for description. + */ +status_t set_notification_data(private_notify_payload_t *this, chunk_t notification_data) +{ + /* destroy existing data first */ + if (this->notification_data.ptr != NULL) + { + /* free existing value */ + allocator_free(this->notification_data.ptr); + this->notification_data.ptr = NULL; + this->notification_data.len = 0; + + } + + this->notification_data.ptr = allocator_clone_bytes(notification_data.ptr,notification_data.len); + if (this->notification_data.ptr == NULL) + { + return OUT_OF_RES; + } + this->notification_data.len = notification_data.len; + this->compute_length(this); + + return SUCCESS; +} + +/** + * Implements payload_t's and notify_payload_t's destroy function. + * See #payload_s.destroy or notify_payload_s.destroy for description. + */ +static status_t destroy(private_notify_payload_t *this) +{ + if (this->notification_data.ptr != NULL) + { + allocator_free(this->notification_data.ptr); + } + if (this->spi.ptr != NULL) + { + allocator_free(this->spi.ptr); + } + + allocator_free(this); + return SUCCESS; +} + +/* + * Described in header + */ +notify_payload_t *notify_payload_create() +{ + private_notify_payload_t *this = allocator_alloc_thing(private_notify_payload_t); + if (this == NULL) + { + return NULL; + } + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (payload_t *))destroy; + + /* public functions */ + this->public.get_protocol_id = (u_int8_t (*) (notify_payload_t *)) get_protocol_id; + this->public.set_protocol_id = (status_t (*) (notify_payload_t *,u_int8_t)) set_protocol_id; + this->public.get_notify_message_type = (u_int16_t (*) (notify_payload_t *)) get_notify_message_type; + this->public.set_notify_message_type = (status_t (*) (notify_payload_t *,u_int16_t)) set_notify_message_type; + this->public.get_spi = (chunk_t (*) (notify_payload_t *)) get_spi; + this->public.set_spi = (status_t (*) (notify_payload_t *,chunk_t)) set_spi; + this->public.get_notification_data = (chunk_t (*) (notify_payload_t *)) get_notification_data; + this->public.set_notification_data = (status_t (*) (notify_payload_t *,chunk_t)) set_notification_data; + this->public.destroy = (status_t (*) (notify_payload_t *)) destroy; + + /* private functions */ + this->compute_length = compute_length; + + /* set default values of the fields */ + this->critical = NOTIFY_PAYLOAD_CRITICAL_FLAG; + this->next_payload = NO_PAYLOAD; + this->payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH; + this->protocol_id = 0; + this->notify_message_type = 0; + this->spi.ptr = NULL; + this->spi.len = 0; + this->notification_data.ptr = NULL; + this->notification_data.len = 0; + + return (&(this->public)); +} + diff --git a/Source/charon/encoding/payloads/notify_payload.h b/Source/charon/encoding/payloads/notify_payload.h new file mode 100644 index 000000000..cf4235fc3 --- /dev/null +++ b/Source/charon/encoding/payloads/notify_payload.h @@ -0,0 +1,159 @@ +/** + * @file notify_payload.h + * + * @brief Declaration of the class notify_payload_t. + * + * An object of this type represents an IKEv2 Notify-Payload. + * + * See section 3.10 of Draft for details of this payload type. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + + +#ifndef NOTIFY_PAYLOAD_H_ +#define NOTIFY_PAYLOAD_H_ + +#include <types.h> +#include <encoding/payloads/payload.h> +#include <utils/linked_list.h> + +/** + * Critical flag must not be set + */ +#define NOTIFY_PAYLOAD_CRITICAL_FLAG FALSE; + +/** + * Notify payload length in bytes without any spi and notification data + */ +#define NOTIFY_PAYLOAD_HEADER_LENGTH 8 + +/** + * Object representing an IKEv2-Notify Payload + * + * The Notify Payload format is described in Draft section 3.10. + * + */ +typedef struct notify_payload_s notify_payload_t; + +struct notify_payload_s { + /** + * implements payload_t interface + */ + payload_t payload_interface; + + /** + * @brief Gets the protocol id of this payload. + * + * @param this calling notify_payload_t object + * @return protocol id of this payload + */ + u_int8_t (*get_protocol_id) (notify_payload_t *this); + + /** + * @brief Sets the protocol id of this payload. + * + * @param this calling notify_payload_t object + * @param protocol_id protocol id to set + * @return SUCCESS + */ + status_t (*set_protocol_id) (notify_payload_t *this, u_int8_t protocol_id); + + /** + * @brief Gets the notify message type of this payload. + * + * @param this calling notify_payload_t object + * @return notify message type of this payload + */ + u_int16_t (*get_notify_message_type) (notify_payload_t *this); + + /** + * @brief Sets notify message type of this payload. + * + * @param this calling notify_payload_t object + * @param notify_message_type notify message type to set + * @return SUCCESS + */ + status_t (*set_notify_message_type) (notify_payload_t *this, u_int16_t notify_message_type); + + /** + * @brief Returns the currently set spi of this payload. + * + * @warning Returned data are not copied. + * + * @param this calling notify_payload_t object + * @return chunk_t pointing to the value + */ + chunk_t (*get_spi) (notify_payload_t *this); + + /** + * @brief Sets the spi of this payload. + * + * @warning Value is getting copied. + * + * @param this calling notify_payload_t object + * @param spi chunk_t pointing to the value to set + * @return + * - SUCCESS or + * - OUT_OF_RES + */ + status_t (*set_spi) (notify_payload_t *this, chunk_t spi); + + /** + * @brief Returns the currently set notification data of payload. + * + * @warning Returned data are not copied. + * + * @param this calling notify_payload_t object + * @return chunk_t pointing to the value + */ + chunk_t (*get_notification_data) (notify_payload_t *this); + + /** + * @brief Sets the notification data of this payload. + * + * @warning Value is getting copied. + * + * @param this calling notify_payload_t object + * @param notification_data chunk_t pointing to the value to set + * @return + * - SUCCESS or + * - OUT_OF_RES + */ + status_t (*set_notification_data) (notify_payload_t *this, chunk_t notification_data); + + /** + * @brief Destroys an notify_payload_t object. + * + * @param this notify_payload_t object to destroy + * @return + * SUCCESS in any case + */ + status_t (*destroy) (notify_payload_t *this); +}; + +/** + * @brief Creates an empty notify_payload_t object + * + * @return + * - created notify_payload_t object, or + * - NULL if failed + */ +notify_payload_t *notify_payload_create(); + + +#endif /*NOTIFY_PAYLOAD_H_*/ diff --git a/Source/charon/encoding/payloads/payload.c b/Source/charon/encoding/payloads/payload.c new file mode 100644 index 000000000..a2333f6af --- /dev/null +++ b/Source/charon/encoding/payloads/payload.c @@ -0,0 +1,92 @@ +/** + * @file payload.c + * + * @brief Generic payload interface + * + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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/ke_payload.h> +#include <encoding/payloads/notify_payload.h> + + + + + +/* + * build the mappings for payload_type_t + */ +mapping_t payload_type_m[] = { + {NO_PAYLOAD, "NO_PAYLOAD"}, + {SECURITY_ASSOCIATION, "SECURITY_ASSOCIATION"}, + {KEY_EXCHANGE, "KEY_EXCHANGE"}, + {ID_INITIATOR, "ID_INITIATOR"}, + {ID_RESPONDER, "ID_RESPONDER"}, + {CERTIFICATE, "CERTIFICATE"}, + {CERTIFICATE_REQUEST, "CERTIFICATE_REQUEST"}, + {AUTHENTICATION, "AUTHENTICATION"}, + {NONCE, "NONCE"}, + {NOTIFY, "NOTIFY"}, + {DELETE, "DELETE"}, + {VENDOR_ID, "VENDOR_ID"}, + {TRAFFIC_SELECTOR_INITIATOR, "TRAFFIC_SELECTOR_INITIATOR"}, + {TRAFFIC_SELECTOR_RESPONDER, "TRAFFIC_SELECTOR_RESPONDER"}, + {ENCRYPTED, "ENCRYPTED"}, + {CONFIGURATION, "CONFIGURATION"}, + {EXTENSIBLE_AUTHENTICATION, "EXTENSIBLE_AUTHENTICATION"}, + {HEADER, "HEADER"}, + {PROPOSAL_SUBSTRUCTURE, "PROPOSAL_SUBSTRUCTURE"}, + {TRANSFORM_SUBSTRUCTURE, "TRANSFORM_SUBSTRUCTURE"}, + {TRANSFORM_ATTRIBUTE, "TRANSFORM_ATTRIBUTE"}, + {MAPPING_END, NULL} +}; + +/* + * 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 KEY_EXCHANGE: + return (payload_t*)ke_payload_create(); + case NOTIFY: + return (payload_t*)notify_payload_create(); + default: + return NULL; + } +} + diff --git a/Source/charon/encoding/payloads/payload.h b/Source/charon/encoding/payloads/payload.h new file mode 100644 index 000000000..9d8b753cb --- /dev/null +++ b/Source/charon/encoding/payloads/payload.h @@ -0,0 +1,240 @@ +/** + * @file payload.h + * + * @brief Generic payload interface + * + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef PAYLOAD_H_ +#define PAYLOAD_H_ + +#include <types.h> +#include <definitions.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. + */ +typedef enum payload_type_e payload_type_t; + +enum payload_type_e{ + + /** + * NO_PAYLOAD + */ + NO_PAYLOAD = 0, + + /** + * SA + */ + SECURITY_ASSOCIATION = 33, + /** + * KE + */ + KEY_EXCHANGE = 34, + /** + * IDi + */ + ID_INITIATOR = 35, + /** + * IDr + */ + ID_RESPONDER = 36, + /** + * CERT + */ + CERTIFICATE = 37, + /** + * CERTREQ + */ + CERTIFICATE_REQUEST = 38, + /** + * AUTH + */ + AUTHENTICATION = 39, + /** + * Ni, Nr + */ + NONCE = 40, + /** + * N + */ + NOTIFY = 41, + /** + * D + */ + DELETE = 42, + /** + * V + */ + VENDOR_ID = 43, + /** + * TSi + */ + TRAFFIC_SELECTOR_INITIATOR = 44, + /** + * TSr + */ + TRAFFIC_SELECTOR_RESPONDER = 45, + /** + * E + */ + ENCRYPTED = 46, + /** + * CP + */ + CONFIGURATION = 47, + /** + * EAP + */ + EXTENSIBLE_AUTHENTICATION = 48, + + /** + * Header has a value of PRIVATE USE space + * + * This payload type is not send 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 send 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 send 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 send over wire and just + * used internally to handle a transform attribute like a payload. + */ + TRANSFORM_ATTRIBUTE = 143, +}; + + +/* + * build string mapping array for payload_type_t + */ +extern mapping_t payload_type_m[]; + + +/** + * @brief Generic interface for all payload types (inclusive + * header and substructures) + * + * + */ +typedef struct payload_s payload_t; + +struct payload_s { + /** + * @brief Destroys a payload and all included substructures. + * + * @param this payload to destroy + * @return + * SUCCESS in any case + */ + status_t (*destroy) (payload_t *this); + + /** + * @brief Get encoding rules for this payload + * + * @param this calling object + * @param[out] rules location to store pointer of first rule + * @param[out] rule_count location to store number of rules + * @return + * SUCCESS in any case + */ + status_t (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules, size_t *rule_count); + + /** + * @brief get type of payload + * + * @param this calling object + * @return type of this payload + */ + payload_type_t (*get_type) (payload_t *this); + + /** + * @brief get type of next payload or zero if this is the last one + * + * @param this calling object + * @return type of next payload + */ + payload_type_t (*get_next_type) (payload_t *this); + + /** + * @brief set type of next payload + * + * @param this calling object + * @param type type of next payload + * @return SUCCESS in any case + */ + status_t (*set_next_type) (payload_t *this,payload_type_t type); + + /** + * @brief get length of payload + * + * @param this calling object + * @return length of this payload + */ + size_t (*get_length) (payload_t *this); + + /** + * @brief Verifies payload structure and makes consistence check + * + * @param this calling object + * @return + * - SUCCESS + * - FAILED if consistence not given + */ + status_t (*verify) (payload_t *this); +}; + +/** + * @brief Create an empty payload. + * + * Useful for the parser, who wants a generic constructor for all payloads. + * It supports all payload_t methods. + * + * @param type type of the payload to create + * @return + * - created payload, or + * - NULL if failed + */ + +payload_t *payload_create(payload_type_t type); + +#endif /*PAYLOAD_H_*/ diff --git a/Source/charon/encoding/payloads/proposal_substructure.c b/Source/charon/encoding/payloads/proposal_substructure.c new file mode 100644 index 000000000..b53633fb5 --- /dev/null +++ b/Source/charon/encoding/payloads/proposal_substructure.c @@ -0,0 +1,512 @@ +/** + * @file proposal_substructure.h + * + * @brief Declaration of the class proposal_substructure_t. + * + * An object of this type represents an IKEv2 PROPOSAL Substructure and contains transforms. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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 "proposal_substructure.h" + +#include <encoding/payloads/encodings.h> +#include <encoding/payloads/transform_substructure.h> +#include <types.h> +#include <utils/allocator.h> +#include <utils/linked_list.h> + +/** + * Private data of an proposal_substructure_t' Object + * + */ +typedef struct private_proposal_substructure_s private_proposal_substructure_t; + +struct private_proposal_substructure_s { + /** + * 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; + + /** + * @brief Computes the length of this substructure. + * + * @param this calling private_proposal_substructure_t object + * @return + * SUCCESS in any case + */ + status_t (*compute_length) (private_proposal_substructure_t *this); +}; + +/** + * 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> ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implements payload_t's verify function. + * See #payload_s.verify for description. + */ +static status_t verify(private_proposal_substructure_t *this) +{ + if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != PROPOSAL_SUBSTRUCTURE)) + { + /* must be 0 or 2 */ + return FAILED; + } + if (this->transforms_count != this->transforms->get_count(this->transforms)) + { + /* must be the same! */ + return FAILED; + } + + if (this->protocol_id > 4) + { + /* reserved are not supported */ + return FAILED; + } + + /* proposal number is checked in SA payload */ + return SUCCESS; +} + +/** + * Implements payload_t's get_encoding_rules function. + * See #payload_s.get_encoding_rules for description. + */ +static status_t 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); + + return SUCCESS; +} + +/** + * Implements payload_t's get_type function. + * See #payload_s.get_type for description. + */ +static payload_type_t get_type(private_proposal_substructure_t *this) +{ + return PROPOSAL_SUBSTRUCTURE; +} + +/** + * Implements payload_t's get_next_type function. + * See #payload_s.get_next_type for description. + */ +static payload_type_t get_next_type(private_proposal_substructure_t *this) +{ + return (this->next_payload); +} + +/** + * Implements payload_t's set_next_type function. + * See #payload_s.set_next_type for description. + */ +static status_t set_next_type(private_proposal_substructure_t *this,payload_type_t type) +{ + return SUCCESS; +} + +/** + * Implements payload_t's get_length function. + * See #payload_s.get_length for description. + */ +static size_t get_length(private_proposal_substructure_t *this) +{ + return this->proposal_length; +} + +/** + * Implements proposal_substructure_t's create_transform_substructure_iterator function. + * See #proposal_substructure_s.create_transform_substructure_iterator for description. + */ +static status_t create_transform_substructure_iterator (private_proposal_substructure_t *this,linked_list_iterator_t **iterator,bool forward) +{ + return (this->transforms->create_iterator(this->transforms,iterator,forward)); +} + +/** + * Implements proposal_substructure_t's add_transform_substructure function. + * See #proposal_substructure_s.add_transform_substructure for description. + */ +static status_t 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); + + status = this->transforms->insert_last(this->transforms,(void *) transform); + this->compute_length(this); + return status; +} + +/** + * Implements proposal_substructure_t's set_proposal_number function. + * See #proposal_substructure_s.set_proposal_number for description. + */ +static status_t set_proposal_number(private_proposal_substructure_t *this,u_int8_t proposal_number) +{ + this->proposal_number = proposal_number; + return SUCCESS; +} + +/** + * Implements proposal_substructure_t's get_proposal_number function. + * See #proposal_substructure_s.get_proposal_number for description. + */ +static u_int8_t get_proposal_number (private_proposal_substructure_t *this) +{ + return (this->proposal_number); +} + +/** + * Implements proposal_substructure_t's set_protocol_id function. + * See #proposal_substructure_s.set_protocol_id for description. + */ +static status_t set_protocol_id(private_proposal_substructure_t *this,u_int8_t protocol_id) +{ + this->protocol_id = protocol_id; + return SUCCESS; +} + +/** + * Implements proposal_substructure_t's get_protocol_id function. + * See #proposal_substructure_s.get_protocol_id for description. + */ +static u_int8_t get_protocol_id (private_proposal_substructure_t *this) +{ + return (this->protocol_id); +} + + +/** + * Implements proposal_substructure_t's set_spi function. + * See #proposal_substructure_s.set_spi for description. + */ +static status_t set_spi (private_proposal_substructure_t *this, chunk_t spi) +{ + /* first delete already set spi value */ + if (this->spi.ptr != NULL) + { + allocator_free(this->spi.ptr); + this->spi.ptr = NULL; + this->spi.len = 0; + this->compute_length(this); + } + + this->spi.ptr = allocator_clone_bytes(spi.ptr,spi.len); + if (this->spi.ptr == NULL) + { + return OUT_OF_RES; + } + this->spi.len = spi.len; + this->spi_size = spi.len; + this->compute_length(this); + + return SUCCESS; +} + +/** + * Implements proposal_substructure_t's get_spi function. + * See #proposal_substructure_s.get_spi for description. + */ +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; +} + +/** + * Implements private_proposal_substructure_t's compute_length function. + * See #private_proposal_substructure_s.compute_length for description. + */ +static status_t compute_length (private_proposal_substructure_t *this) +{ + linked_list_iterator_t *iterator; + status_t status; + size_t transforms_count = 0; + size_t length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH; + status = this->transforms->create_iterator(this->transforms,&iterator,TRUE); + if (status != SUCCESS) + { + return length; + } + while (iterator->has_next(iterator)) + { + payload_t * current_transform; + iterator->current(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; + + return SUCCESS; +} + +/** + * Implements proposal_substructure_t's clone function. + * See #proposal_substructure_s.clone for description. + */ +static status_t clone(private_proposal_substructure_t *this, private_proposal_substructure_t **clone) +{ + private_proposal_substructure_t * new_clone; + linked_list_iterator_t *transforms; + status_t status; + + new_clone = (private_proposal_substructure_t *) proposal_substructure_create(); + + new_clone->next_payload = this->next_payload; + new_clone->proposal_number = this->proposal_number; + new_clone->protocol_id = this->protocol_id; + new_clone->spi_size = this->spi_size; + if (this->spi.ptr != NULL) + { + new_clone->spi.ptr = allocator_clone_bytes(this->spi.ptr,this->spi.len); + if (new_clone->spi.ptr == NULL) + { + new_clone->public.destroy(&(new_clone->public)); + return OUT_OF_RES; + } + new_clone->spi.len = this->spi.len; + } + + status = this->transforms->create_iterator(this->transforms,&transforms,FALSE); + if (status != SUCCESS) + { + new_clone->public.destroy(&(new_clone->public)); + return status; + } + + while (transforms->has_next(transforms)) + { + transform_substructure_t *current_transform; + transform_substructure_t *current_transform_clone; + status = transforms->current(transforms,(void **) ¤t_transform); + if (status != SUCCESS) + { + transforms->destroy(transforms); + new_clone->public.destroy(&(new_clone->public)); + return status; + } + status = current_transform->clone(current_transform,¤t_transform_clone); + if (status != SUCCESS) + { + transforms->destroy(transforms); + new_clone->public.destroy(&(new_clone->public)); + return status; + } + + status = new_clone->public.add_transform_substructure(&(new_clone->public),current_transform_clone); + if (status != SUCCESS) + { + transforms->destroy(transforms); + current_transform_clone->destroy(current_transform_clone); + new_clone->public.destroy(&(new_clone->public)); + return status; + } + } + + transforms->destroy(transforms); + + *clone = new_clone; + + return SUCCESS; +} + +/** + * Implements payload_t's and proposal_substructure_t's destroy function. + * See #payload_s.destroy or proposal_substructure_s.destroy for description. + */ +static status_t destroy(private_proposal_substructure_t *this) +{ + /* all proposals are getting destroyed */ + while (this->transforms->get_count(this->transforms) > 0) + { + transform_substructure_t *current_transform; + if (this->transforms->remove_last(this->transforms,(void **)¤t_transform) != SUCCESS) + { + break; + } + current_transform->destroy(current_transform); + } + this->transforms->destroy(this->transforms); + + if (this->spi.ptr != NULL) + { + allocator_free(this->spi.ptr); + } + + allocator_free(this); + + return SUCCESS; +} + +/* + * Described in header + */ +proposal_substructure_t *proposal_substructure_create() +{ + private_proposal_substructure_t *this = allocator_alloc_thing(private_proposal_substructure_t); + if (this == NULL) + { + return NULL; + } + + /* interface functions */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (payload_t *))destroy; + + /* public functions */ + this->public.create_transform_substructure_iterator = (status_t (*) (proposal_substructure_t *,linked_list_iterator_t **,bool)) create_transform_substructure_iterator; + this->public.add_transform_substructure = (status_t (*) (proposal_substructure_t *,transform_substructure_t *)) add_transform_substructure; + this->public.set_proposal_number = (status_t (*) (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 = (status_t (*) (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_spi = (status_t (*) (proposal_substructure_t *,chunk_t))set_spi; + this->public.get_spi = (chunk_t (*) (proposal_substructure_t *)) get_spi; + this->public.clone = (status_t (*) (proposal_substructure_t *, proposal_substructure_t **)) clone; + this->public.destroy = (status_t (*) (proposal_substructure_t *)) destroy; + + /* private functions */ + this->compute_length = compute_length; + + /* 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(); + + if (this->transforms == NULL) + { + allocator_free(this); + return NULL; + } + return (&(this->public)); +} diff --git a/Source/charon/encoding/payloads/proposal_substructure.h b/Source/charon/encoding/payloads/proposal_substructure.h new file mode 100644 index 000000000..1da42d10d --- /dev/null +++ b/Source/charon/encoding/payloads/proposal_substructure.h @@ -0,0 +1,186 @@ +/** + * @file proposal_substructure.h + * + * @brief Declaration of the class proposal_substructure_t. + * + * An object of this type represents an IKEv2 PROPOSAL Substructure and contains transforms. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef PROPOSAL_SUBSTRUCTURE_H_ +#define PROPOSAL_SUBSTRUCTURE_H_ + +#include <types.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/transform_substructure.h> +#include <utils/linked_list.h> + +/** + * Length of the proposal substructure header + * (without spi) + */ +#define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8 + + +/** + * Protocol ID of a proposal + */ +typedef enum protocol_id_e protocol_id_t; + +enum protocol_id_e { + UNDEFINED_PROTOCOL_ID = 201, + IKE = 1, + AH = 2, + ESP = 3, +}; + +/** + * Object representing an IKEv2- PROPOSAL SUBSTRUCTURE + * + * The PROPOSAL SUBSTRUCTURE format is described in RFC section 3.3.1. + * + */ +typedef struct proposal_substructure_s proposal_substructure_t; + +struct proposal_substructure_s { + /** + * implements payload_t interface + */ + payload_t payload_interface; + + /** + * @brief Creates an iterator of stored transform_substructure_t objects. + * + * @warning The created iterator has to get destroyed by the caller! + * When deleting any transform over this iterator, call + * get_size to make sure the length and number values are ok. + * + * @param this calling proposal_substructure_t object + * @param iterator the created iterator is stored at the pointed pointer + * @param[in] forward iterator direction (TRUE: front to end) + * @return + * - SUCCESS or + * - OUT_OF_RES if iterator could not be created + */ + status_t (*create_transform_substructure_iterator) (proposal_substructure_t *this,linked_list_iterator_t **iterator, bool forward); + + /** + * @brief Adds a transform_substructure_t object to this object. + * + * @warning The added transform_substructure_t object is + * getting destroyed in destroy function of proposal_substructure_t. + * + * @param this calling proposal_substructure_t object + * @param transform transform_substructure_t object to add + * @return - SUCCESS if succeeded + * - FAILED otherwise + */ + status_t (*add_transform_substructure) (proposal_substructure_t *this,transform_substructure_t *transform); + + /** + * @brief Sets the proposal number of current proposal. + * + * @param this calling proposal_substructure_t object + * @param id proposal number to set + * @return - SUCCESS + */ + status_t (*set_proposal_number) (proposal_substructure_t *this,u_int8_t proposal_number); + + /** + * @brief get proposal number of current proposal. + * + * @param this calling proposal_substructure_t object + * @return proposal number of current proposal substructure. + */ + u_int8_t (*get_proposal_number) (proposal_substructure_t *this); + + /** + * @brief Sets the protocol id of current proposal. + * + * @param this calling proposal_substructure_t object + * @param id protocol id to set + * @return - SUCCESS + */ + status_t (*set_protocol_id) (proposal_substructure_t *this,u_int8_t protocol_id); + + /** + * @brief get protocol id of current proposal. + * + * @param this calling proposal_substructure_t object + * @return protocol id of current proposal substructure. + */ + u_int8_t (*get_protocol_id) (proposal_substructure_t *this); + + + /** + * @brief Returns the currently set SPI of this proposal. + * + * @warning Returned data are not copied + * + * @param this calling proposal_substructure_t object + * @return chunk_t pointing to the value + */ + chunk_t (*get_spi) (proposal_substructure_t *this); + + /** + * @brief Sets the SPI of the current proposal. + * + * @warning SPI is getting copied + * + * @param this calling proposal_substructure_t object + * @param spi chunk_t pointing to the value to set + * @return + * - SUCCESS or + * - OUT_OF_RES + */ + status_t (*set_spi) (proposal_substructure_t *this, chunk_t spi); + + /** + * @brief Clones an proposal_substructure_t object. + * + * @param this proposal_substructure_t object to clone + * @param clone cloned object will be written there + * @return + * - SUCCESS + * - OUT_OF_RES + */ + status_t (*clone) (proposal_substructure_t *this,proposal_substructure_t **clone); + + /** + * @brief Destroys an proposal_substructure_t object. + * + * @param this proposal_substructure_t object to destroy + * @return + * SUCCESS in any case + */ + status_t (*destroy) (proposal_substructure_t *this); +}; + +/** + * @brief Creates an empty proposal_substructure_t object + * + * @return + * - created proposal_substructure_t object, or + * - NULL if failed + */ + +proposal_substructure_t *proposal_substructure_create(); + + + +#endif /*PROPOSAL_SUBSTRUCTURE_H_*/ diff --git a/Source/charon/encoding/payloads/sa_payload.c b/Source/charon/encoding/payloads/sa_payload.c new file mode 100644 index 000000000..83eb62acd --- /dev/null +++ b/Source/charon/encoding/payloads/sa_payload.c @@ -0,0 +1,343 @@ +/** + * @file sa_payload.c + * + * @brief Declaration of the class sa_payload_t. + * + * An object of this type represents an IKEv2 SA-Payload and contains proposal + * substructures. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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 "sa_payload.h" + +#include <encoding/payloads/encodings.h> +#include <utils/allocator.h> +#include <utils/linked_list.h> + + +/** + * Private data of an sa_payload_t' Object + * + */ +typedef struct private_sa_payload_s private_sa_payload_t; + +struct private_sa_payload_s { + /** + * 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; + + /** + * @brief Computes the length of this payload. + * + * @param this calling private_sa_payload_t object + * @return + * SUCCESS in any case + */ + status_t (*compute_length) (private_sa_payload_t *this); +}; + +/** + * 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> ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implements payload_t's verify function. + * See #payload_s.verify for description. + */ +static status_t verify(private_sa_payload_t *this) +{ + int proposal_number = 1; + status_t status; + linked_list_iterator_t *iterator; + bool first = TRUE; + + if (this->critical) + { + /* critical bit set! */ + return FAILED; + } + + /* check proposal numbering */ + status = this->proposals->create_iterator(this->proposals,&iterator,TRUE); + if (status != SUCCESS) + { + return status; + } + + while(iterator->has_next(iterator)) + { + proposal_substructure_t *current_proposal; + status = iterator->current(iterator,(void **)¤t_proposal); + { + break; + } + if (current_proposal->get_proposal_number(current_proposal) > proposal_number) + { + if (first) + { + /* first number must be 1 */ + status = FAILED; + break; + } + + if (current_proposal->get_proposal_number(current_proposal) != (proposal_number + 1)) + { + /* must be only one more then previous proposal */ + status = FAILED; + break; + } + } + else if (current_proposal->get_proposal_number(current_proposal) < proposal_number) + { + iterator->destroy(iterator); + /* must not be smaller then proceeding one */ + status = FAILED; + break; + } + first = FALSE; + } + + iterator->destroy(iterator); + return status; +} + + +/** + * Implements payload_t's and sa_payload_t's destroy function. + * See #payload_s.destroy or sa_payload_s.destroy for description. + */ +static status_t destroy(private_sa_payload_t *this) +{ + /* all proposals are getting destroyed */ + while (this->proposals->get_count(this->proposals) > 0) + { + proposal_substructure_t *current_proposal; + if (this->proposals->remove_last(this->proposals,(void **)¤t_proposal) != SUCCESS) + { + break; + } + current_proposal->destroy(current_proposal); + } + this->proposals->destroy(this->proposals); + + allocator_free(this); + + return SUCCESS; +} + +/** + * Implements payload_t's get_encoding_rules function. + * See #payload_s.get_encoding_rules for description. + */ +static status_t 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); + + return SUCCESS; +} + +/** + * Implements payload_t's get_type function. + * See #payload_s.get_type for description. + */ +static payload_type_t get_type(private_sa_payload_t *this) +{ + return SECURITY_ASSOCIATION; +} + +/** + * Implements payload_t's get_next_type function. + * See #payload_s.get_next_type for description. + */ +static payload_type_t get_next_type(private_sa_payload_t *this) +{ + return (this->next_payload); +} + +/** + * Implements payload_t's set_next_type function. + * See #payload_s.set_next_type for description. + */ +static status_t set_next_type(private_sa_payload_t *this,payload_type_t type) +{ + this->next_payload = type; + return SUCCESS; +} + +/** + * Implements payload_t's get_length function. + * See #payload_s.get_length for description. + */ +static size_t get_length(private_sa_payload_t *this) +{ + this->compute_length(this); + return this->payload_length; +} + +/** + * Implements sa_payload_t's create_proposal_substructure_iterator function. + * See #sa_payload_s.create_proposal_substructure_iterator for description. + */ +static status_t create_proposal_substructure_iterator (private_sa_payload_t *this,linked_list_iterator_t **iterator,bool forward) +{ + return (this->proposals->create_iterator(this->proposals,iterator,forward)); +} + +/** + * Implements sa_payload_t's add_proposal_substructure function. + * See #sa_payload_s.add_proposal_substructure for description. + */ +static status_t add_proposal_substructure (private_sa_payload_t *this,proposal_substructure_t *proposal) +{ + status_t status; + status = this->proposals->insert_last(this->proposals,(void *) proposal); + this->compute_length(this); + return status; +} + +/** + * Implements private_sa_payload_t's compute_length function. + * See #private_sa_payload_s.compute_length for description. + */ +static status_t compute_length (private_sa_payload_t *this) +{ + linked_list_iterator_t *iterator; + status_t status; + size_t length = SA_PAYLOAD_HEADER_LENGTH; + status = this->proposals->create_iterator(this->proposals,&iterator,TRUE); + if (status != SUCCESS) + { + return length; + } + while (iterator->has_next(iterator)) + { + payload_t *current_proposal; + iterator->current(iterator,(void **) ¤t_proposal); + length += current_proposal->get_length(current_proposal); + } + iterator->destroy(iterator); + + this->payload_length = length; + + return SUCCESS; +} + +/* + * Described in header + */ +sa_payload_t *sa_payload_create() +{ + private_sa_payload_t *this = allocator_alloc_thing(private_sa_payload_t); + if (this == NULL) + { + return NULL; + } + + /* public interface */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (payload_t *))destroy; + + /* public functions */ + this->public.create_proposal_substructure_iterator = (status_t (*) (sa_payload_t *,linked_list_iterator_t **,bool)) create_proposal_substructure_iterator; + this->public.add_proposal_substructure = (status_t (*) (sa_payload_t *,proposal_substructure_t *)) add_proposal_substructure; + this->public.destroy = (status_t (*) (sa_payload_t *)) destroy; + + /* private functions */ + this->compute_length = compute_length; + + /* set default values of the fields */ + this->critical = SA_PAYLOAD_CRITICAL_FLAG; + this->next_payload = NO_PAYLOAD; + this->payload_length = SA_PAYLOAD_HEADER_LENGTH; + + this->proposals = linked_list_create(); + + if (this->proposals == NULL) + { + allocator_free(this); + return NULL; + } + return (&(this->public)); +} + + diff --git a/Source/charon/encoding/payloads/sa_payload.h b/Source/charon/encoding/payloads/sa_payload.h new file mode 100644 index 000000000..f13282de9 --- /dev/null +++ b/Source/charon/encoding/payloads/sa_payload.h @@ -0,0 +1,110 @@ +/** + * @file sa_payload.h + * + * @brief Declaration of the class sa_payload_t. + * + * An object of this type represents an IKEv2 SA-Payload and contains proposal + * substructures. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef SA_PAYLOAD_H_ +#define SA_PAYLOAD_H_ + +#include <types.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/proposal_substructure.h> +#include <utils/linked_list.h> + +/** + * Critical flag must not be set + */ +#define SA_PAYLOAD_CRITICAL_FLAG FALSE; + +/** + * SA_PAYLOAD length in bytes without any proposal substructure + */ +#define SA_PAYLOAD_HEADER_LENGTH 4 + +/** + * Object representing an IKEv2-SA Payload + * + * The SA Payload format is described in RFC section 3.3. + * + */ +typedef struct sa_payload_s sa_payload_t; + +struct sa_payload_s { + /** + * implements payload_t interface + */ + payload_t payload_interface; + + /** + * @brief Creates an iterator of stored proposal_substructure_t objects. + * + * @warning The created iterator has to get destroyed by the caller! + * + * @warning When deleting an proposal using this iterator, + * the length of this transform substructure has to be refreshed + * by calling get_length()! + * + * @param this calling sa_payload_t object + * @param iterator the created iterator is stored at the pointed pointer + * @param[in] forward iterator direction (TRUE: front to end) + * @return + * - SUCCESS or + * - OUT_OF_RES if iterator could not be created + */ + status_t (*create_proposal_substructure_iterator) (sa_payload_t *this,linked_list_iterator_t **iterator, bool forward); + + /** + * @brief Adds a proposal_substructure_t object to this object. + * + * @warning The added proposal_substructure_t object is + * getting destroyed in destroy function of sa_payload_t. + * + * @param this calling sa_payload_t object + * @param proposal proposal_substructure_t object to add + * @return - SUCCESS if succeeded + * - FAILED otherwise + */ + status_t (*add_proposal_substructure) (sa_payload_t *this,proposal_substructure_t *proposal); + + /** + * @brief Destroys an sa_payload_t object. + * + * @param this sa_payload_t object to destroy + * @return + * SUCCESS in any case + */ + status_t (*destroy) (sa_payload_t *this); +}; + +/** + * @brief Creates an empty sa_payload_t object + * + * @return + * - created sa_payload_t object, or + * - NULL if failed + */ + +sa_payload_t *sa_payload_create(); + + +#endif /*SA_PAYLOAD_H_*/ diff --git a/Source/charon/encoding/payloads/transform_attribute.c b/Source/charon/encoding/payloads/transform_attribute.c new file mode 100644 index 000000000..9aed1e332 --- /dev/null +++ b/Source/charon/encoding/payloads/transform_attribute.c @@ -0,0 +1,363 @@ +/** + * @file transform_attribute.c + * + * @brief Declaration of the class transform_attribute_t. + * + * An object of this type represents an IKEv2 TRANSFORM attribute. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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 "transform_attribute.h" + +#include <encoding/payloads/encodings.h> +#include <types.h> +#include <utils/allocator.h> + +/** + * Private data of an transform_attribute_t Object + * + */ +typedef struct private_transform_attribute_s private_transform_attribute_t; + +struct private_transform_attribute_s { + /** + * 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; +}; + + + +/** + * string mappings for transform_attribute_type_t + */ +mapping_t transform_attribute_type_m[] = { + {ATTRIBUTE_UNDEFINED, "ATTRIBUTE_UNDEFINED"}, + {KEY_LENGTH, "KEY_LENGTH"}, + {MAPPING_END, NULL} +}; + +/** + * 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 ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Implements payload_t's verify function. + * See #payload_s.verify for description. + */ +static status_t verify(private_transform_attribute_t *this) +{ + if (this->attribute_type != KEY_LENGTH) + { + return FAILED; + } + + return SUCCESS; +} + +/** + * Implements payload_t's get_encoding_rules function. + * See #payload_s.get_encoding_rules for description. + */ +static status_t 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); + + return SUCCESS; +} + +/** + * Implements payload_t's get_type function. + * See #payload_s.get_type for description. + */ +static payload_type_t get_type(private_transform_attribute_t *this) +{ + return TRANSFORM_ATTRIBUTE; +} + +/** + * Implements payload_t's get_next_type function. + * See #payload_s.get_next_type for description. + */ +static payload_type_t get_next_type(private_transform_attribute_t *this) +{ + return (NO_PAYLOAD); +} + +/** + * Implements payload_t's set_next_type function. + * See #payload_s.set_next_type for description. + */ +static status_t set_next_type(private_transform_attribute_t *this,payload_type_t type) +{ + return SUCCESS; +} + +/** + * Implements payload_t's get_length function. + * See #payload_s.get_length for description. + */ +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); +} +/** + * Implements transform_attribute_t's set_value function. + * See #transform_attribute_s.set_value for description. + */ +static status_t set_value_chunk(private_transform_attribute_t *this, chunk_t value) +{ + if (this->attribute_value.ptr != NULL) + { + /* free existing value */ + allocator_free(this->attribute_value.ptr); + this->attribute_value.ptr = NULL; + this->attribute_value.len = 0; + + } + + if (value.len > 2) + { + this->attribute_value.ptr = allocator_clone_bytes(value.ptr,value.len); + if (this->attribute_value.ptr == NULL) + { + return OUT_OF_RES; + } + 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); + } + return SUCCESS; +} + +/** + * Implements transform_attribute_t's set_value function. + * See #transform_attribute_s.set_value for description. + */ +static status_t set_value(private_transform_attribute_t *this, u_int16_t value) +{ + if (this->attribute_value.ptr != NULL) + { + /* free existing value */ + allocator_free(this->attribute_value.ptr); + this->attribute_value.ptr = NULL; + this->attribute_value.len = 0; + + } + this->attribute_length_or_value = value; + return SUCCESS; +} + +/** + * Implements transform_attribute_t's get_value_chunk function. + * See #transform_attribute_s.get_value_chunk for description. + */ +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; +} + +/** + * Implements transform_attribute_t's get_value function. + * See #transform_attribute_s.get_value for description. + */ +static u_int16_t get_value (private_transform_attribute_t *this) +{ + return this->attribute_length_or_value; +} + + +/** + * Implements transform_attribute_t's set_attribute_type function. + * See #transform_attribute_s.set_attribute_type for description. + */ +static status_t set_attribute_type (private_transform_attribute_t *this, u_int16_t type) +{ + this->attribute_type = type & 0x7FFF; + return SUCCESS; +} + +/** + * Implements transform_attribute_t's get_attribute_type function. + * See #transform_attribute_s.get_attribute_type for description. + */ +static u_int16_t get_attribute_type (private_transform_attribute_t *this) +{ + return this->attribute_type; +} + +/** + * Implements transform_attribute_t's clone function. + * See transform_attribute_s.clone for description. + */ +static status_t clone(private_transform_attribute_t *this,transform_attribute_t **clone) +{ + 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 = allocator_clone_bytes(this->attribute_value.ptr,this->attribute_value.len); + new_clone->attribute_value.len = this->attribute_value.len; + if (new_clone->attribute_value.ptr == NULL) + { + new_clone->public.destroy(&(new_clone->public)); + return OUT_OF_RES; + } + } + + *clone = (transform_attribute_t *) new_clone; + return SUCCESS; +} + +/** + * Implements payload_t's and transform_attribute_t's destroy function. + * See #payload_s.destroy or transform_attribute_s.destroy for description. + */ +static status_t destroy(private_transform_attribute_t *this) +{ + if (this->attribute_value.ptr != NULL) + { + allocator_free(this->attribute_value.ptr); + } + allocator_free(this); + + return SUCCESS; +} + +/* + * Described in header + */ +transform_attribute_t *transform_attribute_create() +{ + private_transform_attribute_t *this = allocator_alloc_thing(private_transform_attribute_t); + if (this == NULL) + { + return NULL; + } + + /* payload interface */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (payload_t *))destroy; + + /* public functions */ + this->public.set_value_chunk = (status_t (*) (transform_attribute_t *,chunk_t)) set_value_chunk; + this->public.set_value = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (transform_attribute_t *,transform_attribute_t **)) clone; + this->public.destroy = (status_t (*) (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)); +} + diff --git a/Source/charon/encoding/payloads/transform_attribute.h b/Source/charon/encoding/payloads/transform_attribute.h new file mode 100644 index 000000000..7cc72f207 --- /dev/null +++ b/Source/charon/encoding/payloads/transform_attribute.h @@ -0,0 +1,153 @@ +/** + * @file transform_attribute.h + * + * @brief Declaration of the class transform_attribute_t. + * + * An object of this type represents an IKEv2 TRANSFORM attribute. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef TRANSFORM_ATTRIBUTE_H_ +#define TRANSFORM_ATTRIBUTE_H_ + +#include <types.h> +#include <encoding/payloads/payload.h> + + +/** + * Type of the attribute, as in IKEv2 draft 3.3.5 + */ +typedef enum transform_attribute_type_e transform_attribute_type_t; + +enum transform_attribute_type_e { + ATTRIBUTE_UNDEFINED = 16384, + KEY_LENGTH = 14 +}; + +/** + * string mappings for transform_attribute_type_t + */ +extern mapping_t transform_attribute_type_m[]; + +/** + * Object representing an IKEv2- TRANSFORM Attribute + * + * The TRANSFORM ATTRIBUTE format is described in RFC section 3.3.5. + * + */ +typedef struct transform_attribute_s transform_attribute_t; + +struct transform_attribute_s { + /** + * implements payload_t interface + */ + payload_t payload_interface; + + /** + * @brief Returns the currently set value of the attribute + * + * @warning Returned data are not copied + * + * @param this calling transform_attribute_t object + * @return chunk_t pointing to the value + */ + chunk_t (*get_value_chunk) (transform_attribute_t *this); + + /** + * @brief Returns the currently set value of the attribute + * + * @warning Returned data are not copied + * + * @param this calling transform_attribute_t object + * @return value + */ + u_int16_t (*get_value) (transform_attribute_t *this); + + /** + * @brief Sets the value of the attribute. + * + * @warning Value is getting copied + * + * @param this calling transform_attribute_t object + * @param value chunk_t pointing to the value to set + * @return + * - SUCCESS or + * - OUT_OF_RES + */ + status_t (*set_value_chunk) (transform_attribute_t *this, chunk_t value); + + /** + * @brief Sets the value of the attribute. + * + * @param this calling transform_attribute_t object + * @param value value to set + * @return + * - SUCCESS or + * - OUT_OF_RES + */ + status_t (*set_value) (transform_attribute_t *this, u_int16_t value); + + /** + * @brief Sets the type of the attribute. + * + * @param this calling transform_attribute_t object + * @param type type to set (most significant bit is set to zero) + * @return SUCCESS + */ + status_t (*set_attribute_type) (transform_attribute_t *this, u_int16_t type); + + /** + * @brief get the type of the attribute. + * + * @param this calling transform_attribute_t object + * @return type of the value + */ + u_int16_t (*get_attribute_type) (transform_attribute_t *this); + + /** + * @brief Clones an transform_attribute_t object. + * + * @param this transform_attribute_t object to clone + * @param clone the new clone will be written there + * @return + * - OUT_OF_RES + * - SUCCESS + */ + status_t (*clone) (transform_attribute_t *this,transform_attribute_t **clone); + + /** + * @brief Destroys an transform_attribute_t object. + * + * @param this transform_attribute_t object to destroy + * @return + * SUCCESS in any case + */ + status_t (*destroy) (transform_attribute_t *this); +}; + +/** + * @brief Creates an empty transform_attribute_t object + * + * @return + * - created transform_attribute_t object, or + * - NULL if failed + */ + +transform_attribute_t *transform_attribute_create(); + +#endif /*TRANSFORM_ATTRIBUTE_H_*/ diff --git a/Source/charon/encoding/payloads/transform_substructure.c b/Source/charon/encoding/payloads/transform_substructure.c new file mode 100644 index 000000000..d44d4c4f8 --- /dev/null +++ b/Source/charon/encoding/payloads/transform_substructure.c @@ -0,0 +1,577 @@ +/** + * @file transform_substructure.h + * + * @brief Declaration of the class transform_substructure_t. + * + * An object of this type represents an IKEv2 TRANSFORM Substructure and contains Attributes. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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 "transform_substructure.h" + +#include <encoding/payloads/transform_attribute.h> +#include <encoding/payloads/encodings.h> +#include <types.h> +#include <utils/allocator.h> +#include <utils/linked_list.h> + +/** + * Private data of an transform_substructure_t' Object + * + */ +typedef struct private_transform_substructure_s private_transform_substructure_t; + +struct private_transform_substructure_s { + /** + * 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; + + /** + * @brief Computes the length of this substructure. + * + * @param this calling private_transform_substructure_t object + * @return + * SUCCESS in any case + */ + status_t (*compute_length) (private_transform_substructure_t *this); +}; + + +/** + * string mappings for transform_type_t + */ +mapping_t transform_type_m[] = { + {UNDEFINED_TRANSFORM_TYPE, "UNDEFINED_TRANSFORM_TYPE"}, + {ENCRYPTION_ALGORITHM, "ENCRYPTION_ALGORITHM"}, + {PSEUDO_RANDOM_FUNCTION, "PSEUDO_RANDOM_FUNCTION"}, + {INTEGRITIY_ALGORITHM, "INTEGRITIY_ALGORITHM"}, + {DIFFIE_HELLMAN_GROUP, "DIFFIE_HELLMAN_GROUP"}, + {EXTENDED_SEQUENCE_NUNBERS, "EXTENDED_SEQUENCE_NUNBERS"}, + {MAPPING_END, NULL} +}; + + +/** + * string mappings for encryption_algorithm_t + */ +mapping_t encryption_algorithm_m[] = { + {ENCR_UNDEFINED, "ENCR_UNDEFINED"}, + {ENCR_DES_IV64, "ENCR_DES_IV64"}, + {ENCR_DES, "ENCR_DES"}, + {ENCR_3DES, "ENCR_3DES"}, + {ENCR_RC5, "ENCR_RC5"}, + {ENCR_IDEA, "ENCR_IDEA"}, + {ENCR_CAST, "ENCR_CAST"}, + {ENCR_BLOWFISH, "ENCR_BLOWFISH"}, + {ENCR_3IDEA, "ENCR_3IDEA"}, + {ENCR_DES_IV32, "ENCR_DES_IV32"}, + {ENCR_NULL, "ENCR_NULL"}, + {ENCR_AES_CBC, "ENCR_AES_CBC"}, + {ENCR_AES_CTR, "ENCR_AES_CTR"}, + {MAPPING_END, NULL} +}; + +/** + * string mappings for encryption_algorithm_t + */ +mapping_t pseudo_random_function_m[] = { + {PRF_UNDEFINED, "PRF_UNDEFINED"}, + {PRF_HMAC_MD5, "PRF_HMAC_MD5"}, + {PRF_HMAC_SHA1, "PRF_HMAC_SHA1"}, + {PRF_HMAC_TIGER, "PRF_HMAC_TIGER"}, + {PRF_AES128_CBC, "PRF_AES128_CBC"}, + {MAPPING_END, NULL} +}; + +/** + * string mappings for integrity_algorithm_t + */ +mapping_t integrity_algorithm_m[] = { + {AUTH_UNDEFINED, "AUTH_UNDEFINED"}, + {AUTH_HMAC_MD5_96, "AUTH_HMAC_MD5_96"}, + {AUTH_HMAC_SHA1_96, "AUTH_HMAC_SHA1_96"}, + {AUTH_DES_MAC, "AUTH_DES_MAC"}, + {AUTH_KPDK_MD5, "AUTH_KPDK_MD5"}, + {AUTH_AES_XCBC_96, "AUTH_AES_XCBC_96"}, + {MAPPING_END, NULL} +}; + +/** + * string mappings for diffie_hellman_group_t + */ +mapping_t diffie_hellman_group_m[] = { + {MODP_UNDEFINED, "MODP_UNDEFINED"}, + {MODP_768_BIT, "MODP_768_BIT"}, + {MODP_1024_BIT, "MODP_1024_BIT"}, + {MODP_1536_BIT, "MODP_1536_BIT"}, + {MODP_2048_BIT, "MODP_2048_BIT"}, + {MODP_3072_BIT, "MODP_3072_BIT"}, + {MODP_4096_BIT, "MODP_4096_BIT"}, + {MODP_6144_BIT, "MODP_6144_BIT"}, + {MODP_8192_BIT, "MODP_8192_BIT"}, + {MAPPING_END, NULL} +}; + +/** + * string mappings for extended_sequence_numbers_t + */ +mapping_t extended_sequence_numbers_m[] = { + {NO_EXT_SEQ_NUMBERS, "NO_EXT_SEQ_NUMBERS"}, + {EXT_SEQ_NUMBERS, "EXT_SEQ_NUMBERS"}, + {MAPPING_END, NULL} +}; + +/** + * 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 ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + +/** + * Implements payload_t's verify function. + * See #payload_s.verify for description. + */ +static status_t verify(private_transform_substructure_t *this) +{ + if ((this->next_payload != NO_PAYLOAD) && (this->next_payload != TRANSFORM_SUBSTRUCTURE)) + { + /* must be 0 or 3 */ + return FAILED; + } + + switch (this->transform_type) + { + case ENCRYPTION_ALGORITHM: + { + if ((this->transform_id < ENCR_DES_IV64) || (this->transform_id > ENCR_AES_CTR)) + { + return FAILED; + } + break; + } + case PSEUDO_RANDOM_FUNCTION: + { + if ((this->transform_id < PRF_HMAC_MD5) || (this->transform_id > PRF_AES128_CBC)) + { + return FAILED; + } + break; + } + case INTEGRITIY_ALGORITHM: + { + if ((this->transform_id < AUTH_HMAC_MD5_96) || (this->transform_id > AUTH_AES_XCBC_96)) + { + return FAILED; + } + break; + } + case DIFFIE_HELLMAN_GROUP: + { + switch (this->transform_id) + { + case MODP_768_BIT: + case MODP_1024_BIT: + case MODP_1536_BIT: + case MODP_2048_BIT: + case MODP_3072_BIT: + case MODP_4096_BIT: + case MODP_6144_BIT: + case MODP_8192_BIT: + { + break; + } + default: + { + return FAILED; + } + } + + + break; + } + case EXTENDED_SEQUENCE_NUNBERS: + { + if ((this->transform_id != NO_EXT_SEQ_NUMBERS) && (this->transform_id != EXT_SEQ_NUMBERS)) + { + return FAILED; + } + break; + } + default: + { + /* not a supported transform type! */ + return FAILED; + } + } + + /* proposal number is checked in SA payload */ + return SUCCESS; +} + +/** + * Implements payload_t's get_encoding_rules function. + * See #payload_s.get_encoding_rules for description. + */ +static status_t 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); + + return SUCCESS; +} + +/** + * Implements payload_t's get_type function. + * See #payload_s.get_type for description. + */ +static payload_type_t get_type(private_transform_substructure_t *this) +{ + return TRANSFORM_SUBSTRUCTURE; +} + +/** + * Implements payload_t's get_next_type function. + * See #payload_s.get_next_type for description. + */ +static payload_type_t get_next_type(private_transform_substructure_t *this) +{ + return (this->next_payload); +} + +/** + * Implements payload_t's get_length function. + * See #payload_s.get_length for description. + */ +static size_t get_length(private_transform_substructure_t *this) +{ + this->compute_length(this); + + return this->transform_length; +} + +/** + * Implements transform_substructure_t's create_transform_attribute_iterator function. + * See #transform_substructure_s.create_transform_attribute_iterator for description. + */ +static status_t create_transform_attribute_iterator (private_transform_substructure_t *this,linked_list_iterator_t **iterator,bool forward) +{ + return (this->attributes->create_iterator(this->attributes,iterator,forward)); +} + +/** + * Implements transform_substructure_t's add_transform_attribute function. + * See #transform_substructure_s.add_transform_attribute for description. + */ +static status_t add_transform_attribute (private_transform_substructure_t *this,transform_attribute_t *attribute) +{ + status_t status; + status = this->attributes->insert_last(this->attributes,(void *) attribute); + this->compute_length(this); + return status; +} + +/** + * Implements transform_substructure_t's set_is_last_transform function. + * See #transform_substructure_s.set_is_last_transform for description. + */ +static status_t set_is_last_transform (private_transform_substructure_t *this, bool is_last) +{ + this->next_payload = (is_last) ? 0: TRANSFORM_TYPE_VALUE; + return SUCCESS; +} + +/** + * Implements transform_substructure_t's get_is_last_transform function. + * See #transform_substructure_s.get_is_last_transform for description. + */ +static bool get_is_last_transform (private_transform_substructure_t *this) +{ + return ((this->next_payload == TRANSFORM_TYPE_VALUE) ? FALSE : TRUE); +} + +/** + * Implements payload_t's set_next_type function. + * See #payload_s.set_next_type for description. + */ +static status_t set_next_type(private_transform_substructure_t *this,payload_type_t type) +{ + return SUCCESS; +} + +/** + * Implements transform_substructure_t's set_transform_type function. + * See #transform_substructure_s.set_transform_type for description. + */ +static status_t set_transform_type (private_transform_substructure_t *this,u_int8_t type) +{ + this->transform_type = type; + return SUCCESS; +} + +/** + * Implements transform_substructure_t's get_transform_type function. + * See #transform_substructure_s.get_transform_type for description. + */ +static u_int8_t get_transform_type (private_transform_substructure_t *this) +{ + return this->transform_type; +} + +/** + * Implements transform_substructure_t's set_transform_id function. + * See #transform_substructure_s.set_transform_id for description. + */ +static status_t set_transform_id (private_transform_substructure_t *this,u_int16_t id) +{ + this->transform_id = id; + return SUCCESS; +} + +/** + * Implements transform_substructure_t's get_transform_id function. + * See #transform_substructure_s.get_transform_id for description. + */ +static u_int16_t get_transform_id (private_transform_substructure_t *this) +{ + return this->transform_id; +} + +/** + * Implements private_transform_substructure_t's compute_length function. + * See #private_transform_substructure_s.compute_length for description. + */ +static status_t compute_length (private_transform_substructure_t *this) +{ + linked_list_iterator_t *iterator; + status_t status; + size_t length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH; + status = this->attributes->create_iterator(this->attributes,&iterator,TRUE); + if (status != SUCCESS) + { + return length; + } + while (iterator->has_next(iterator)) + { + payload_t * current_attribute; + iterator->current(iterator,(void **) ¤t_attribute); + length += current_attribute->get_length(current_attribute); + } + iterator->destroy(iterator); + + this->transform_length = length; + + return SUCCESS; +} + +/** + * Implements transform_substructure_t's clone function. + * See transform_substructure_s.clone for description. + */ +static status_t clone(private_transform_substructure_t *this,transform_substructure_t **clone) +{ + private_transform_substructure_t *new_clone; + linked_list_iterator_t *attributes; + status_t status; + + new_clone = (private_transform_substructure_t *) transform_substructure_create(); + + new_clone->next_payload = this->next_payload; + new_clone->transform_type = this->transform_type; + new_clone->transform_id = this->transform_id; + + status = this->attributes->create_iterator(this->attributes,&attributes,FALSE); + if (status != SUCCESS) + { + new_clone->public.destroy(&(new_clone->public)); + return status; + } + + while (attributes->has_next(attributes)) + { + transform_attribute_t *current_attribute; + transform_attribute_t *current_attribute_clone; + status = attributes->current(attributes,(void **) ¤t_attribute); + if (status != SUCCESS) + { + attributes->destroy(attributes); + new_clone->public.destroy(&(new_clone->public)); + return status; + } + status = current_attribute->clone(current_attribute,¤t_attribute_clone); + if (status != SUCCESS) + { + attributes->destroy(attributes); + new_clone->public.destroy(&(new_clone->public)); + return status; + } + + status = new_clone->public.add_transform_attribute(&(new_clone->public),current_attribute_clone); + if (status != SUCCESS) + { + attributes->destroy(attributes); + current_attribute_clone->destroy(current_attribute_clone); + new_clone->public.destroy(&(new_clone->public)); + return status; + } + } + + attributes->destroy(attributes); + + *clone = &(new_clone->public); + return SUCCESS; +} + + +/** + * Implements payload_t's and transform_substructure_t's destroy function. + * See #payload_s.destroy or transform_substructure_s.destroy for description. + */ +static status_t destroy(private_transform_substructure_t *this) +{ + /* all proposals are getting destroyed */ + while (this->attributes->get_count(this->attributes) > 0) + { + transform_attribute_t *current_attribute; + if (this->attributes->remove_last(this->attributes,(void **)¤t_attribute) != SUCCESS) + { + break; + } + current_attribute->destroy(current_attribute); + } + this->attributes->destroy(this->attributes); + + allocator_free(this); + + return SUCCESS; +} + +/* + * Described in header + */ +transform_substructure_t *transform_substructure_create() +{ + private_transform_substructure_t *this = allocator_alloc_thing(private_transform_substructure_t); + if (this == NULL) + { + return NULL; + } + + /* payload interface */ + this->public.payload_interface.verify = (status_t (*) (payload_t *))verify; + this->public.payload_interface.get_encoding_rules = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (payload_t *))destroy; + + /* public functions */ + this->public.create_transform_attribute_iterator = (status_t (*) (transform_substructure_t *,linked_list_iterator_t **,bool)) create_transform_attribute_iterator; + this->public.add_transform_attribute = (status_t (*) (transform_substructure_t *,transform_attribute_t *)) add_transform_attribute; + this->public.set_is_last_transform = (status_t (*) (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 = (status_t (*) (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 = (status_t (*) (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.clone = (status_t (*) (transform_substructure_t *,transform_substructure_t **)) clone; + this->public.destroy = (status_t (*) (transform_substructure_t *)) destroy; + + /* private functions */ + this->compute_length = compute_length; + + /* 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(); + + if (this->attributes == NULL) + { + allocator_free(this); + return NULL; + } + return (&(this->public)); +} diff --git a/Source/charon/encoding/payloads/transform_substructure.h b/Source/charon/encoding/payloads/transform_substructure.h new file mode 100644 index 000000000..1be66597e --- /dev/null +++ b/Source/charon/encoding/payloads/transform_substructure.h @@ -0,0 +1,298 @@ +/** + * @file transform_substructure.h + * + * @brief Declaration of the class transform_substructure_t. + * + * An object of this type represents an IKEv2 TRANSFORM Substructure and contains Attributes. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * 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. + */ + +#ifndef TRANSFORM_SUBSTRUCTURE_H_ +#define TRANSFORM_SUBSTRUCTURE_H_ + +#include <types.h> +#include <definitions.h> +#include <encoding/payloads/payload.h> +#include <encoding/payloads/transform_attribute.h> +#include <utils/linked_list.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 + + +/** + * Type of a transform, as in IKEv2 draft 3.3.2 + */ +typedef enum transform_type_e transform_type_t; + +enum transform_type_e { + UNDEFINED_TRANSFORM_TYPE = 241, + ENCRYPTION_ALGORITHM = 1, + PSEUDO_RANDOM_FUNCTION = 2, + INTEGRITIY_ALGORITHM = 3, + DIFFIE_HELLMAN_GROUP = 4, + EXTENDED_SEQUENCE_NUNBERS = 5 +}; + +/** + * string mappings for transform_type_t + */ +extern mapping_t transform_type_m[]; + +/** + * Encryption algorithm, as in IKEv2 draft 3.3.2 + */ +typedef enum encryption_algorithm_e encryption_algorithm_t; + +enum encryption_algorithm_e { + ENCR_UNDEFINED = 1024, + ENCR_DES_IV64 = 1, + ENCR_DES = 2, + ENCR_3DES = 3, + ENCR_RC5 = 4, + ENCR_IDEA = 5, + ENCR_CAST = 6, + ENCR_BLOWFISH = 7, + ENCR_3IDEA = 8, + ENCR_DES_IV32 = 9, + RESERVED = 10, + ENCR_NULL = 11, + ENCR_AES_CBC = 12, + ENCR_AES_CTR = 13 +}; + +/** + * string mappings for encryption_algorithm_t + */ +extern mapping_t encryption_algorithm_m[]; + +/** + * Pseudo random function, as in IKEv2 draft 3.3.2 + */ +typedef enum pseudo_random_function_e pseudo_random_function_t; + +enum pseudo_random_function_e { + PRF_UNDEFINED = 1024, + PRF_HMAC_MD5 = 1, + PRF_HMAC_SHA1 = 2, + PRF_HMAC_TIGER = 3, + PRF_AES128_CBC = 4 +}; + +/** + * string mappings for encryption_algorithm_t + */ +extern mapping_t pseudo_random_function_m[]; + +/** + * Integrity algorithm, as in IKEv2 draft 3.3.2 + */ +typedef enum integrity_algorithm_e integrity_algorithm_t; + +enum integrity_algorithm_e { + AUTH_UNDEFINED = 1024, + AUTH_HMAC_MD5_96 = 1, + AUTH_HMAC_SHA1_96 = 2, + AUTH_DES_MAC = 3, + AUTH_KPDK_MD5 = 4, + AUTH_AES_XCBC_96 = 5 +}; + +/** + * string mappings for integrity_algorithm_t + */ +extern mapping_t integrity_algorithm_m[]; + + +/** + * Diffie-Hellman group, as in IKEv2 draft 3.3.2 and RFC 3526 + */ +typedef enum diffie_hellman_group_e diffie_hellman_group_t; + +enum diffie_hellman_group_e { + MODP_UNDEFINED = 1024, + MODP_768_BIT = 1, + MODP_1024_BIT = 2, + MODP_1536_BIT = 5, + MODP_2048_BIT = 14, + MODP_3072_BIT = 15, + MODP_4096_BIT = 16, + MODP_6144_BIT = 17, + MODP_8192_BIT = 18 +}; + +/** + * string mappings for diffie_hellman_group_t + */ +extern mapping_t diffie_hellman_group_m[]; + +/** + * Extended sequence numbers, as in IKEv2 draft 3.3.2 + */ +typedef enum extended_sequence_numbers_e extended_sequence_numbers_t; + +enum extended_sequence_numbers_e { + NO_EXT_SEQ_NUMBERS = 0, + EXT_SEQ_NUMBERS = 1 +}; + +/** + * string mappings for extended_sequence_numbers_t + */ +extern mapping_t extended_sequence_numbers_m[]; + +/** + * Object representing an IKEv2- TRANSFORM SUBSTRUCTURE + * + * The TRANSFORM SUBSTRUCTURE format is described in RFC section 3.3.2. + * + */ +typedef struct transform_substructure_s transform_substructure_t; + +struct transform_substructure_s { + /** + * implements payload_t interface + */ + payload_t payload_interface; + + /** + * @brief Creates an iterator of stored transform_attribute_t objects. + * + * @warning The created iterator has to get destroyed by the caller! + * + * @warning When deleting an transform attribute using this iterator, + * the length of this transform substructure has to be refreshed + * by calling get_length()! + * + * @param this calling transform_substructure_t object + * @param iterator the created iterator is stored at the pointed pointer + * @param[in] forward iterator direction (TRUE: front to end) + * @return + * - SUCCESS or + * - OUT_OF_RES if iterator could not be created + */ + status_t (*create_transform_attribute_iterator) (transform_substructure_t *this,linked_list_iterator_t **iterator, bool forward); + + /** + * @brief Adds a transform_attribute_t object to this object. + * + * @warning The added proposal_substructure_t object is + * getting destroyed in destroy function of transform_substructure_t. + * + * @param this calling transform_substructure_t object + * @param proposal transform_attribute_t object to add + * @return - SUCCESS if succeeded + * - FAILED otherwise + */ + status_t (*add_transform_attribute) (transform_substructure_t *this,transform_attribute_t *attribute); + + /** + * @brief Sets the next_payload field of this substructure + * + * If this is the last transform, next payload field is set to 0, + * otherwise to 3 (payload type of transform in IKEv1) + * + * @param this calling transform_substructure_t object + * @param is_last When TRUE, next payload field is set to 0, otherwise to 3 + * @return - SUCCESS + */ + status_t (*set_is_last_transform) (transform_substructure_t *this, bool is_last); + + /** + * @brief Checks if this is the last transform. + * + * @param this calling transform_substructure_t object + * @return TRUE if this is the last Transform, FALSE otherwise + */ + bool (*get_is_last_transform) (transform_substructure_t *this); + + /** + * @brief Sets transform type of the current transform substructure. + * + * @param this calling transform_substructure_t object + * @param type type value to set + * @return - SUCCESS + */ + status_t (*set_transform_type) (transform_substructure_t *this,u_int8_t type); + + /** + * @brief get transform type of the current transform. + * + * @param this calling transform_substructure_t object + * @return Transform type of current transform substructure. + */ + u_int8_t (*get_transform_type) (transform_substructure_t *this); + + /** + * @brief Sets transform id of the current transform substructure. + * + * @param this calling transform_substructure_t object + * @param id transform id to set + * @return - SUCCESS + */ + status_t (*set_transform_id) (transform_substructure_t *this,u_int16_t id); + + /** + * @brief get transform id of the current transform. + * + * @param this calling transform_substructure_t object + * @return Transform id of current transform substructure. + */ + u_int16_t (*get_transform_id) (transform_substructure_t *this); + + /** + * @brief Clones an transform_substructure_t object. + * + * @param this transform_substructure_t object to clone + * @param clone pointer to a transform_substructure_t object pointer + * where the new object is stored to. + * @return + * - OUT_OF_RES + * - SUCCESS in any case + */ + status_t (*clone) (transform_substructure_t *this,transform_substructure_t **clone); + + /** + * @brief Destroys an transform_substructure_t object. + * + * @param this transform_substructure_t object to destroy + * @return + * SUCCESS in any case + */ + status_t (*destroy) (transform_substructure_t *this); +}; + +/** + * @brief Creates an empty transform_substructure_t object + * + * @return + * - created transform_substructure_t object, or + * - NULL if failed + */ + +transform_substructure_t *transform_substructure_create(); + +#endif /*TRANSFORM_SUBSTRUCTURE_H_*/ |