diff options
Diffstat (limited to 'src/libcharon/encoding')
54 files changed, 5280 insertions, 1645 deletions
diff --git a/src/libcharon/encoding/generator.c b/src/libcharon/encoding/generator.c index 60fa7e0c4..2dfaf43df 100644 --- a/src/libcharon/encoding/generator.c +++ b/src/libcharon/encoding/generator.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2011 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -108,6 +109,11 @@ struct private_generator_t { * to hold the length of the transform attribute in bytes. */ u_int16_t attribute_length; + + /** + * TRUE, if debug messages should be logged during generation. + */ + bool debug; }; /** @@ -155,8 +161,11 @@ static void make_space_available(private_generator_t *this, int bits) new_buffer_size = old_buffer_size + GENERATOR_DATA_BUFFER_INCREASE_VALUE; out_position_offset = this->out_position - this->buffer; - DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte", - old_buffer_size, new_buffer_size); + if (this->debug) + { + DBG2(DBG_ENC, "increasing gen buffer from %d to %d byte", + old_buffer_size, new_buffer_size); + } this->buffer = realloc(this->buffer,new_buffer_size); this->out_position = (this->buffer + out_position_offset); @@ -205,7 +214,7 @@ static void generate_u_int_type(private_generator_t *this, break; case U_INT_16: case PAYLOAD_LENGTH: - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: number_of_bits = 16; break; case U_INT_32: @@ -244,7 +253,10 @@ static void generate_u_int_type(private_generator_t *this, low = *(this->out_position) & 0x0F; /* high is set, low_val is not changed */ *(this->out_position) = high | low; - DBG3(DBG_ENC, " => %d", *(this->out_position)); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *(this->out_position)); + } /* write position is not changed, just bit position is moved */ this->current_bit = 4; } @@ -255,7 +267,10 @@ static void generate_u_int_type(private_generator_t *this, /* low of current byte in buffer has to be set to the new value*/ low = *((u_int8_t *)(this->data_struct + offset)) & 0x0F; *(this->out_position) = high | low; - DBG3(DBG_ENC, " => %d", *(this->out_position)); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *(this->out_position)); + } this->out_position++; this->current_bit = 0; } @@ -274,7 +289,10 @@ static void generate_u_int_type(private_generator_t *this, { /* 8 bit values are written as they are */ *this->out_position = *((u_int8_t *)(this->data_struct + offset)); - DBG3(DBG_ENC, " => %d", *(this->out_position)); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *(this->out_position)); + } this->out_position++; break; } @@ -299,7 +317,10 @@ static void generate_u_int_type(private_generator_t *this, val |= 0x8000; } val = htons(val); - DBG3(DBG_ENC, " => %d", val); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", val); + } /* write bytes to buffer (set bit is overwritten) */ write_bytes_to_buffer(this, &val, sizeof(u_int16_t)); this->current_bit = 0; @@ -308,17 +329,23 @@ static void generate_u_int_type(private_generator_t *this, } case U_INT_16: case PAYLOAD_LENGTH: - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: { u_int16_t val = htons(*((u_int16_t*)(this->data_struct + offset))); - DBG3(DBG_ENC, " => %b", &val, sizeof(u_int16_t)); + if (this->debug) + { + DBG3(DBG_ENC, " %b", &val, sizeof(u_int16_t)); + } write_bytes_to_buffer(this, &val, sizeof(u_int16_t)); break; } case U_INT_32: { u_int32_t val = htonl(*((u_int32_t*)(this->data_struct + offset))); - DBG3(DBG_ENC, " => %b", &val, sizeof(u_int32_t)); + if (this->debug) + { + DBG3(DBG_ENC, " %b", &val, sizeof(u_int32_t)); + } write_bytes_to_buffer(this, &val, sizeof(u_int32_t)); break; } @@ -327,8 +354,11 @@ static void generate_u_int_type(private_generator_t *this, /* 64 bit are written as-is, no host order conversion */ write_bytes_to_buffer(this, this->data_struct + offset, sizeof(u_int64_t)); - DBG3(DBG_ENC, " => %b", this->data_struct + offset, - sizeof(u_int64_t)); + if (this->debug) + { + DBG3(DBG_ENC, " %b", this->data_struct + offset, + sizeof(u_int64_t)); + } break; } default: @@ -361,7 +391,10 @@ static void generate_flag(private_generator_t *this, u_int32_t offset) } *(this->out_position) = *(this->out_position) | flag; - DBG3(DBG_ENC, " => %d", *this->out_position); + if (this->debug) + { + DBG3(DBG_ENC, " => %d", *this->out_position); + } this->current_bit++; if (this->current_bit >= 8) @@ -380,12 +413,16 @@ static void generate_from_chunk(private_generator_t *this, u_int32_t offset) if (this->current_bit != 0) { - DBG1(DBG_ENC, "can not generate a chunk at Bitpos %d", this->current_bit); + DBG1(DBG_ENC, "can not generate a chunk at bitpos %d", + this->current_bit); return ; } value = (chunk_t *)(this->data_struct + offset); - DBG3(DBG_ENC, " => %B", value); + if (this->debug) + { + DBG3(DBG_ENC, " %B", value); + } write_bytes_to_buffer(this, value->ptr, value->len); } @@ -397,15 +434,17 @@ METHOD(generator_t, get_chunk, chunk_t, *lenpos = (u_int32_t*)(this->buffer + this->header_length_offset); data = chunk_create(this->buffer, get_length(this)); - DBG3(DBG_ENC, "generated data of this generator %B", &data); + if (this->debug) + { + DBG3(DBG_ENC, "generated data of this generator %B", &data); + } return data; } METHOD(generator_t, generate_payload, void, - private_generator_t *this,payload_t *payload) + private_generator_t *this, payload_t *payload) { - int i, offset_start; - size_t rule_count; + int i, offset_start, rule_count; encoding_rule_t *rules; payload_type_t payload_type; @@ -414,17 +453,23 @@ METHOD(generator_t, generate_payload, void, offset_start = this->out_position - this->buffer; - DBG2(DBG_ENC, "generating payload of type %N", - payload_type_names, payload_type); + if (this->debug) + { + DBG2(DBG_ENC, "generating payload of type %N", + payload_type_names, payload_type); + } /* each payload has its own encoding rules */ - payload->get_encoding_rules(payload, &rules, &rule_count); + rule_count = payload->get_encoding_rules(payload, &rules); for (i = 0; i < rule_count;i++) { - DBG2(DBG_ENC, " generating rule %d %N", - i, encoding_type_names, rules[i].type); - switch (rules[i].type) + if (this->debug) + { + DBG2(DBG_ENC, " generating rule %d %N", + i, encoding_type_names, rules[i].type); + } + switch ((int)rules[i].type) { case U_INT_4: case U_INT_8: @@ -436,7 +481,7 @@ METHOD(generator_t, generate_payload, void, case SPI_SIZE: case TS_TYPE: case ATTRIBUTE_TYPE: - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: generate_u_int_type(this, rules[i].type, rules[i].offset); break; case RESERVED_BIT: @@ -449,26 +494,19 @@ METHOD(generator_t, generate_payload, void, break; case ADDRESS: case SPI: - case KEY_EXCHANGE_DATA: - case NOTIFICATION_DATA: - case NONCE_DATA: - case ID_DATA: - case AUTH_DATA: - case CERT_DATA: - case CERTREQ_DATA: - case SPIS: - case CONFIGURATION_ATTRIBUTE_VALUE: - case VID_DATA: - case EAP_DATA: + case CHUNK_DATA: case ENCRYPTED_DATA: - case UNKNOWN_DATA: generate_from_chunk(this, rules[i].offset); break; - case PROPOSALS: - case TRANSFORMS: - case TRANSFORM_ATTRIBUTES: - case CONFIGURATION_ATTRIBUTES: - case TRAFFIC_SELECTORS: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1: + case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE: { linked_list_t *proposals; enumerator_t *enumerator; @@ -507,7 +545,10 @@ METHOD(generator_t, generate_payload, void, { if (!this->attribute_format) { - DBG2(DBG_ENC, "attribute value has not fixed size"); + if (this->debug) + { + DBG2(DBG_ENC, "attribute value has not fixed size"); + } /* the attribute value is generated */ generate_from_chunk(this, rules[i].offset); } @@ -519,11 +560,14 @@ METHOD(generator_t, generate_payload, void, return; } } - DBG2(DBG_ENC, "generating %N payload finished", - payload_type_names, payload_type); - DBG3(DBG_ENC, "generated data for this payload %b", - this->buffer + offset_start, - (u_int)(this->out_position - this->buffer - offset_start)); + if (this->debug) + { + DBG2(DBG_ENC, "generating %N payload finished", + payload_type_names, payload_type); + DBG3(DBG_ENC, "generated data for this payload %b", + this->buffer + offset_start, + (u_int)(this->out_position - this->buffer - offset_start)); + } } METHOD(generator_t, destroy, void, @@ -547,6 +591,7 @@ generator_t *generator_create() .destroy = _destroy, }, .buffer = malloc(GENERATOR_DATA_BUFFER_SIZE), + .debug = TRUE, ); this->out_position = this->buffer; @@ -555,3 +600,14 @@ generator_t *generator_create() return &this->public; } +/* + * Described in header + */ +generator_t *generator_create_no_dbg() +{ + private_generator_t *this = (private_generator_t*)generator_create(); + + this->debug = FALSE; + + return &this->public; +} diff --git a/src/libcharon/encoding/generator.h b/src/libcharon/encoding/generator.h index fe561fdfd..c2c0aad2a 100644 --- a/src/libcharon/encoding/generator.h +++ b/src/libcharon/encoding/generator.h @@ -72,4 +72,12 @@ struct generator_t { */ generator_t *generator_create(void); +/** + * Constructor to create a generator that does not log any debug messages > 1. + * + * @return generator_t object. + */ +generator_t *generator_create_no_dbg(void); + + #endif /** GENERATOR_H_ @}*/ diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 2b5399294..d3b72ea95 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2006-2011 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2010 revosec AG * Copyright (C) 2006 Daniel Roethlisberger @@ -24,37 +24,47 @@ #include <library.h> #include <daemon.h> -#include <sa/ike_sa_id.h> +#include <sa/ikev1/keymat_v1.h> #include <encoding/generator.h> #include <encoding/parser.h> -#include <utils/linked_list.h> #include <encoding/payloads/encodings.h> #include <encoding/payloads/payload.h> +#include <encoding/payloads/hash_payload.h> #include <encoding/payloads/encryption_payload.h> #include <encoding/payloads/unknown_payload.h> #include <encoding/payloads/cp_payload.h> /** - * Max number of notify payloads per IKEv2 Message + * Max number of notify payloads per IKEv2 message */ #define MAX_NOTIFY_PAYLOADS 20 /** - * Max number of delete payloads per IKEv2 Message + * Max number of delete payloads per IKEv2 message */ #define MAX_DELETE_PAYLOADS 20 /** - * Max number of certificate payloads per IKEv2 Message + * Max number of certificate payloads per IKEv2 message */ #define MAX_CERT_PAYLOADS 8 /** - * Max number of Vendor ID payloads per IKEv2 Message + * Max number of vendor ID payloads per IKEv2 message */ #define MAX_VID_PAYLOADS 20 /** + * Max number of certificate request payloads per IKEv1 message + */ +#define MAX_CERTREQ_PAYLOADS 5 + +/** + * Max number of NAT-D payloads per IKEv1 message + */ +#define MAX_NAT_D_PAYLOADS 5 + +/** * A payload rule defines the rules for a payload * in a specific message rule. It defines if and how * many times a payload must/can occur in a message @@ -414,6 +424,273 @@ static payload_order_t me_connect_r_order[] = { }; #endif /* ME */ +#ifdef USE_IKEV1 +/** + * Message rule for ID_PROT from initiator. + */ +static payload_rule_t id_prot_i_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, TRUE, FALSE}, + {CERTIFICATE_V1, 0, 2, TRUE, FALSE}, + {SIGNATURE_V1, 0, 1, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, +}; + +/** + * payload order for ID_PROT from initiator. + */ +static payload_order_t id_prot_i_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {NAT_D_V1, 0}, +}; + +/** + * Message rule for ID_PROT from responder. + */ +static payload_rule_t id_prot_r_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, TRUE, FALSE}, + {CERTIFICATE_V1, 0, 2, TRUE, FALSE}, + {SIGNATURE_V1, 0, 1, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, +}; + +/** + * payload order for ID_PROT from responder. + */ +static payload_order_t id_prot_r_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {NAT_D_V1, 0}, +}; + +/** + * Message rule for AGGRESSIVE from initiator. + */ +static payload_rule_t aggressive_i_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, FALSE, FALSE}, + {CERTIFICATE_V1, 0, 1, TRUE, FALSE}, + {SIGNATURE_V1, 0, 1, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, +}; + +/** + * payload order for AGGRESSIVE from initiator. + */ +static payload_order_t aggressive_i_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {NAT_D_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for AGGRESSIVE from responder. + */ +static payload_rule_t aggressive_r_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 1, FALSE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, FALSE, FALSE}, + {NONCE_V1, 0, 1, FALSE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, FALSE, FALSE}, + {CERTIFICATE_REQUEST_V1, 0, MAX_CERTREQ_PAYLOADS, FALSE, FALSE}, + {NAT_D_V1, 0, MAX_NAT_D_PAYLOADS, FALSE, FALSE}, + {ID_V1, 0, 1, FALSE, FALSE}, + {CERTIFICATE_V1, 0, 1, FALSE, FALSE}, + {SIGNATURE_V1, 0, 1, FALSE, FALSE}, + {HASH_V1, 0, 1, FALSE, FALSE}, +}; + +/** + * payload order for AGGRESSIVE from responder. + */ +static payload_order_t aggressive_r_order[] = { +/* payload type notify type */ + {SECURITY_ASSOCIATION_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {NONCE_V1, 0}, + {ID_V1, 0}, + {CERTIFICATE_V1, 0}, + {NAT_D_V1, 0}, + {SIGNATURE_V1, 0}, + {HASH_V1, 0}, + {CERTIFICATE_REQUEST_V1, 0}, + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for INFORMATIONAL_V1 from initiator. + */ +static payload_rule_t informational_i_rules_v1[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL_V1 from initiator. + */ +static payload_order_t informational_i_order_v1[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {DELETE_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for INFORMATIONAL_V1 from responder. + */ +static payload_rule_t informational_r_rules_v1[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, FALSE, FALSE}, + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {DELETE_V1, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, +}; + +/** + * payload order for INFORMATIONAL_V1 from responder. + */ +static payload_order_t informational_r_order_v1[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {DELETE_V1, 0}, + {VENDOR_ID_V1, 0}, +}; + +/** + * Message rule for QUICK_MODE from initiator. + */ +static payload_rule_t quick_mode_i_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 2, TRUE, FALSE}, + {NONCE_V1, 0, 1, TRUE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE}, + {ID_V1, 0, 2, TRUE, FALSE}, + {NAT_OA_V1, 0, 2, TRUE, FALSE}, +}; + +/** + * payload order for QUICK_MODE from initiator. + */ +static payload_order_t quick_mode_i_order[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {HASH_V1, 0}, + {SECURITY_ASSOCIATION_V1, 0}, + {NONCE_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {ID_V1, 0}, + {NAT_OA_V1, 0}, +}; + +/** + * Message rule for QUICK_MODE from responder. + */ +static payload_rule_t quick_mode_r_rules[] = { +/* payload type min max encr suff */ + {NOTIFY_V1, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, + {VENDOR_ID_V1, 0, MAX_VID_PAYLOADS, TRUE, FALSE}, + {HASH_V1, 0, 1, TRUE, FALSE}, + {SECURITY_ASSOCIATION_V1, 0, 2, TRUE, FALSE}, + {NONCE_V1, 0, 1, TRUE, FALSE}, + {KEY_EXCHANGE_V1, 0, 1, TRUE, FALSE}, + {ID_V1, 0, 2, TRUE, FALSE}, + {NAT_OA_V1, 0, 2, TRUE, FALSE}, +}; + +/** + * payload order for QUICK_MODE from responder. + */ +static payload_order_t quick_mode_r_order[] = { +/* payload type notify type */ + {NOTIFY_V1, 0}, + {VENDOR_ID_V1, 0}, + {HASH_V1, 0}, + {SECURITY_ASSOCIATION_V1, 0}, + {NONCE_V1, 0}, + {KEY_EXCHANGE_V1, 0}, + {ID_V1, 0}, + {NAT_OA_V1, 0}, +}; + +/** + * Message rule for TRANSACTION. + */ +static payload_rule_t transaction_payload_rules_v1[] = { +/* payload type min max encr suff */ + {HASH_V1, 0, 1, TRUE, FALSE}, + {CONFIGURATION_V1, 1, 1, FALSE, FALSE}, +}; + +/** + * Payload order for TRANSACTION. + */ +static payload_order_t transaction_payload_order_v1[] = { +/* payload type notify type */ + {HASH_V1, 0}, + {CONFIGURATION_V1, 0}, +}; + +#endif /* USE_IKEV1 */ + /** * Message rules, defines allowed payloads. */ @@ -460,6 +737,49 @@ static message_rule_t message_rules[] = { countof(me_connect_r_order), me_connect_r_order, }, #endif /* ME */ +#ifdef USE_IKEV1 + {ID_PROT, TRUE, FALSE, + countof(id_prot_i_rules), id_prot_i_rules, + countof(id_prot_i_order), id_prot_i_order, + }, + {ID_PROT, FALSE, FALSE, + countof(id_prot_r_rules), id_prot_r_rules, + countof(id_prot_r_order), id_prot_r_order, + }, + {AGGRESSIVE, TRUE, FALSE, + countof(aggressive_i_rules), aggressive_i_rules, + countof(aggressive_i_order), aggressive_i_order, + }, + {AGGRESSIVE, FALSE, FALSE, + countof(aggressive_r_rules), aggressive_r_rules, + countof(aggressive_r_order), aggressive_r_order, + }, + {INFORMATIONAL_V1, TRUE, TRUE, + countof(informational_i_rules_v1), informational_i_rules_v1, + countof(informational_i_order_v1), informational_i_order_v1, + }, + {INFORMATIONAL_V1, FALSE, TRUE, + countof(informational_r_rules_v1), informational_r_rules_v1, + countof(informational_r_order_v1), informational_r_order_v1, + }, + {QUICK_MODE, TRUE, TRUE, + countof(quick_mode_i_rules), quick_mode_i_rules, + countof(quick_mode_i_order), quick_mode_i_order, + }, + {QUICK_MODE, FALSE, TRUE, + countof(quick_mode_r_rules), quick_mode_r_rules, + countof(quick_mode_r_order), quick_mode_r_order, + }, + {TRANSACTION, TRUE, TRUE, + countof(transaction_payload_rules_v1), transaction_payload_rules_v1, + countof(transaction_payload_order_v1), transaction_payload_order_v1, + }, + {TRANSACTION, FALSE, TRUE, + countof(transaction_payload_rules_v1), transaction_payload_rules_v1, + countof(transaction_payload_order_v1), transaction_payload_order_v1, + }, + /* TODO-IKEv1: define rules for other exchanges */ +#endif /* USE_IKEV1 */ }; @@ -501,6 +821,11 @@ struct private_message_t { bool is_request; /** + * The message is encrypted (IKEv1) + */ + bool is_encrypted; + + /** * Higher version supported? */ bool version_flag; @@ -508,7 +833,7 @@ struct private_message_t { /** * Reserved bits in IKE header */ - bool reserved[5]; + bool reserved[2]; /** * Sorting of message disabled? @@ -739,7 +1064,14 @@ METHOD(message_t, add_notify, void, payload->destroy(payload); } } - notify = notify_payload_create(); + if (this->major_version == IKEV2_MAJOR_VERSION) + { + notify = notify_payload_create(NOTIFY); + } + else + { + notify = notify_payload_create(NOTIFY_V1); + } notify->set_notify_type(notify, type); notify->set_notification_data(notify, data); add_payload(this, (payload_t*)notify); @@ -810,7 +1142,8 @@ METHOD(message_t, get_notify, notify_payload_t*, enumerator = create_payload_enumerator(this); while (enumerator->enumerate(enumerator, &payload)) { - if (payload->get_type(payload) == NOTIFY) + if (payload->get_type(payload) == NOTIFY || + payload->get_type(payload) == NOTIFY_V1) { notify = (notify_payload_t*)payload; if (notify->get_notify_type(notify) == type) @@ -837,7 +1170,7 @@ static char* get_string(private_message_t *this, char *buf, int len) memset(buf, 0, len); len--; - written = snprintf(pos, len, "%N %s %d [", + written = snprintf(pos, len, "%N %s %u [", exchange_type_names, this->exchange_type, this->is_request ? "request" : "response", this->message_id); @@ -859,7 +1192,8 @@ static char* get_string(private_message_t *this, char *buf, int len) } pos += written; len -= written; - if (payload->get_type(payload) == NOTIFY) + if (payload->get_type(payload) == NOTIFY || + payload->get_type(payload) == NOTIFY_V1) { notify_payload_t *notify; notify_type_t type; @@ -1017,7 +1351,7 @@ static void order_payloads(private_message_t *this) } /** - * Wrap payloads in a encryption payload + * Wrap payloads in an encryption payload */ static encryption_payload_t* wrap_payloads(private_message_t *this) { @@ -1033,7 +1367,14 @@ static encryption_payload_t* wrap_payloads(private_message_t *this) payloads->insert_last(payloads, current); } - encryption = encryption_payload_create(); + if (this->is_encrypted) + { + encryption = encryption_payload_create(ENCRYPTED_V1); + } + else + { + encryption = encryption_payload_create(ENCRYPTED); + } while (payloads->remove_first(payloads, (void**)¤t) == SUCCESS) { payload_rule_t *rule; @@ -1046,8 +1387,8 @@ static encryption_payload_t* wrap_payloads(private_message_t *this) { encrypt = rule->encrypted; } - if (encrypt) - { + if (encrypt || this->is_encrypted) + { /* encryption is forced for IKEv1 */ DBG2(DBG_ENC, "insert payload %N to encryption payload", payload_type_names, type); encryption->add_payload(encryption, current); @@ -1071,17 +1412,20 @@ METHOD(message_t, disable_sort, void, } METHOD(message_t, generate, status_t, - private_message_t *this, aead_t *aead, packet_t **packet) + private_message_t *this, keymat_t *keymat, packet_t **packet) { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; generator_t *generator; ike_header_t *ike_header; payload_t *payload, *next; encryption_payload_t *encryption = NULL; + payload_type_t next_type; enumerator_t *enumerator; - chunk_t chunk; + aead_t *aead = NULL; + chunk_t chunk, hash = chunk_empty; char str[BUF_LEN]; u_int32_t *lenpos; - bool *reserved; + bool encrypted = FALSE, *reserved; int i; if (this->exchange_type == EXCHANGE_TYPE_UNDEFINED) @@ -1108,27 +1452,77 @@ METHOD(message_t, generate, status_t, { order_payloads(this); } + if (keymat && keymat->get_version(keymat) == IKEV1) + { + /* get a hash for this message, if any is required */ + if (keymat_v1->get_hash_phase2(keymat_v1, &this->public, &hash)) + { /* insert a HASH payload as first payload */ + hash_payload_t *hash_payload; + + hash_payload = hash_payload_create(HASH_V1); + hash_payload->set_hash(hash_payload, hash); + this->payloads->insert_first(this->payloads, hash_payload); + if (this->exchange_type == INFORMATIONAL_V1) + { + this->is_encrypted = encrypted = TRUE; + } + chunk_free(&hash); + } + } + if (this->major_version == IKEV2_MAJOR_VERSION) + { + encrypted = this->rule->encrypted; + } + else if (!encrypted) + { + /* If at least one payload requires encryption, encrypt the message. + * If no key material is available, the flag will be reset below. */ + enumerator = this->payloads->create_enumerator(this->payloads); + while (enumerator->enumerate(enumerator, (void**)&payload)) + { + payload_rule_t *rule; + + rule = get_payload_rule(this, payload->get_type(payload)); + if (rule && rule->encrypted) + { + this->is_encrypted = encrypted = TRUE; + break; + } + } + enumerator->destroy(enumerator); + } DBG1(DBG_ENC, "generating %s", get_string(this, str, sizeof(str))); - if (aead && this->rule->encrypted) + if (keymat) + { + aead = keymat->get_aead(keymat, FALSE); + } + if (aead && encrypted) { encryption = wrap_payloads(this); } else { DBG2(DBG_ENC, "not encrypting payloads"); + this->is_encrypted = FALSE; } - ike_header = ike_header_create(); - ike_header->set_maj_version(ike_header, this->major_version); - ike_header->set_min_version(ike_header, this->minor_version); + ike_header = ike_header_create_version(this->major_version, + this->minor_version); ike_header->set_exchange_type(ike_header, this->exchange_type); ike_header->set_message_id(ike_header, this->message_id); - ike_header->set_response_flag(ike_header, !this->is_request); - ike_header->set_version_flag(ike_header, this->version_flag); - ike_header->set_initiator_flag(ike_header, + if (this->major_version == IKEV2_MAJOR_VERSION) + { + ike_header->set_response_flag(ike_header, !this->is_request); + ike_header->set_version_flag(ike_header, this->version_flag); + ike_header->set_initiator_flag(ike_header, this->ike_sa_id->is_initiator(this->ike_sa_id)); + } + else + { + ike_header->set_encryption_flag(ike_header, this->is_encrypted); + } 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, @@ -1156,22 +1550,38 @@ METHOD(message_t, generate, status_t, payload = next; } enumerator->destroy(enumerator); - payload->set_next_type(payload, encryption ? ENCRYPTED : NO_PAYLOAD); + if (this->is_encrypted) + { /* for encrypted IKEv1 messages */ + next_type = encryption->payload_interface.get_next_type( + (payload_t*)encryption); + } + else + { + next_type = encryption ? ENCRYPTED : NO_PAYLOAD; + } + payload->set_next_type(payload, next_type); generator->generate_payload(generator, payload); ike_header->destroy(ike_header); if (encryption) - { - u_int32_t *lenpos; - - /* build associated data (without header of encryption payload) */ - chunk = generator->get_chunk(generator, &lenpos); + { /* set_transform() has to be called before get_length() */ encryption->set_transform(encryption, aead); - /* fill in length, including encryption payload */ - htoun32(lenpos, chunk.len + encryption->get_length(encryption)); - + if (this->is_encrypted) + { /* for IKEv1 instead of associated data we provide the IV */ + if (!keymat_v1->get_iv(keymat_v1, this->message_id, &chunk)) + { + generator->destroy(generator); + return FAILED; + } + } + else + { /* build associated data (without header of encryption payload) */ + chunk = generator->get_chunk(generator, &lenpos); + /* fill in length, including encryption payload */ + htoun32(lenpos, chunk.len + encryption->get_length(encryption)); + } this->payloads->insert_last(this->payloads, encryption); - if (!encryption->encrypt(encryption, chunk)) + if (encryption->encrypt(encryption, chunk) != SUCCESS) { generator->destroy(generator); return INVALID_STATE; @@ -1181,8 +1591,22 @@ METHOD(message_t, generate, status_t, chunk = generator->get_chunk(generator, &lenpos); htoun32(lenpos, chunk.len); this->packet->set_data(this->packet, chunk_clone(chunk)); + if (this->is_encrypted) + { + /* update the IV for the next IKEv1 message */ + chunk_t last_block; + size_t bs; + + bs = aead->get_block_size(aead); + last_block = chunk_create(chunk.ptr + chunk.len - bs, bs); + if (!keymat_v1->update_iv(keymat_v1, this->message_id, last_block) || + !keymat_v1->confirm_iv(keymat_v1, this->message_id)) + { + generator->destroy(generator); + return FAILED; + } + } generator->destroy(generator); - *packet = this->packet->clone(this->packet); return SUCCESS; } @@ -1204,7 +1628,7 @@ METHOD(message_t, get_packet_data, chunk_t, { return chunk_empty; } - return chunk_clone(this->packet->get_data(this->packet)); + return this->packet->get_data(this->packet); } METHOD(message_t, parse_header, status_t, @@ -1237,15 +1661,24 @@ METHOD(message_t, parse_header, status_t, } DESTROY_IF(this->ike_sa_id); - this->ike_sa_id = ike_sa_id_create(ike_header->get_initiator_spi(ike_header), + this->ike_sa_id = ike_sa_id_create( + ike_header->get_maj_version(ike_header), + ike_header->get_initiator_spi(ike_header), ike_header->get_responder_spi(ike_header), ike_header->get_initiator_flag(ike_header)); this->exchange_type = ike_header->get_exchange_type(ike_header); this->message_id = ike_header->get_message_id(ike_header); - this->is_request = !ike_header->get_response_flag(ike_header); this->major_version = ike_header->get_maj_version(ike_header); this->minor_version = ike_header->get_min_version(ike_header); + if (this->major_version == IKEV2_MAJOR_VERSION) + { + this->is_request = !ike_header->get_response_flag(ike_header); + } + else + { + this->is_encrypted = ike_header->get_encryption_flag(ike_header); + } this->first_payload = ike_header->payload_interface.get_next_type( &ike_header->payload_interface); for (i = 0; i < countof(this->reserved); i++) @@ -1257,19 +1690,12 @@ METHOD(message_t, parse_header, status_t, this->reserved[i] = *reserved; } } - DBG2(DBG_ENC, "parsed a %N %s", exchange_type_names, this->exchange_type, - this->is_request ? "request" : "response"); - ike_header->destroy(ike_header); - this->rule = get_message_rule(this); - if (!this->rule) - { - DBG1(DBG_ENC, "no message rules specified for a %N %s", - exchange_type_names, this->exchange_type, - this->is_request ? "request" : "response"); - } - return status; + DBG2(DBG_ENC, "parsed a %N %s header", exchange_type_names, + this->exchange_type, this->major_version == IKEV1_MAJOR_VERSION ? + "message" : (this->is_request ? "request" : "response")); + return SUCCESS; } /** @@ -1298,15 +1724,83 @@ static bool is_connectivity_check(private_message_t *this, payload_t *payload) } /** + * Parses and verifies the unencrypted payloads contained in the message + */ +static status_t parse_payloads(private_message_t *this) +{ + payload_type_t type = this->first_payload; + payload_t *payload; + status_t status; + + if (this->is_encrypted) + { /* wrap the whole encrypted IKEv1 message in a special encryption + * payload which is then handled just like a regular payload */ + encryption_payload_t *encryption; + + status = this->parser->parse_payload(this->parser, ENCRYPTED_V1, + (payload_t**)&encryption); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "failed to wrap encrypted IKEv1 message"); + return PARSE_ERROR; + } + encryption->payload_interface.set_next_type((payload_t*)encryption, + this->first_payload); + this->payloads->insert_last(this->payloads, encryption); + return SUCCESS; + } + + while (type != NO_PAYLOAD) + { + DBG2(DBG_ENC, "starting parsing a %N payload", + payload_type_names, type); + + status = this->parser->parse_payload(this->parser, type, &payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "payload type %N could not be parsed", + payload_type_names, type); + return PARSE_ERROR; + } + + DBG2(DBG_ENC, "verifying payload of type %N", payload_type_names, type); + status = payload->verify(payload); + if (status != SUCCESS) + { + DBG1(DBG_ENC, "%N payload verification failed", + payload_type_names, type); + payload->destroy(payload); + return VERIFY_ERROR; + } + + DBG2(DBG_ENC, "%N payload verified. Adding to payload list", + payload_type_names, type); + this->payloads->insert_last(this->payloads, payload); + + /* an encryption payload is the last one, so STOP here. decryption is + * done later */ + if (type == ENCRYPTED) + { + DBG2(DBG_ENC, "%N payload found. Stop parsing", + payload_type_names, type); + break; + } + type = payload->get_next_type(payload); + } + return SUCCESS; +} + +/** * Decrypt payload from the encryption payload */ -static status_t decrypt_payloads(private_message_t *this, aead_t *aead) +static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) { bool was_encrypted = FALSE; payload_t *payload, *previous = NULL; enumerator_t *enumerator; payload_rule_t *rule; payload_type_t type; + aead_t *aead; status_t status = SUCCESS; enumerator = this->payloads->create_enumerator(this->payloads); @@ -1316,11 +1810,12 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead) DBG2(DBG_ENC, "process payload of type %N", payload_type_names, type); - if (type == ENCRYPTED) + if (type == ENCRYPTED || type == ENCRYPTED_V1) { encryption_payload_t *encryption; payload_t *encrypted; chunk_t chunk; + size_t bs; encryption = (encryption_payload_t*)payload; @@ -1332,16 +1827,57 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead) status = VERIFY_ERROR; break; } + if (!keymat) + { + DBG1(DBG_ENC, "found encryption payload, but no keymat"); + status = INVALID_ARG; + break; + } + aead = keymat->get_aead(keymat, TRUE); + if (!aead) + { + DBG1(DBG_ENC, "found encryption payload, but no transform set"); + status = INVALID_ARG; + break; + } + bs = aead->get_block_size(aead); encryption->set_transform(encryption, aead); chunk = this->packet->get_data(this->packet); - if (chunk.len < encryption->get_length(encryption)) + if (chunk.len < encryption->get_length(encryption) || + chunk.len < bs) { DBG1(DBG_ENC, "invalid payload length"); status = VERIFY_ERROR; break; } - chunk.len -= encryption->get_length(encryption); - status = encryption->decrypt(encryption, chunk); + if (keymat->get_version(keymat) == IKEV1) + { /* instead of associated data we provide the IV, we also update + * the IV with the last encrypted block */ + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; + chunk_t iv; + + if (keymat_v1->get_iv(keymat_v1, this->message_id, &iv)) + { + status = encryption->decrypt(encryption, iv); + if (status == SUCCESS) + { + if (!keymat_v1->update_iv(keymat_v1, this->message_id, + chunk_create(chunk.ptr + chunk.len - bs, bs))) + { + status = FAILED; + } + } + } + else + { + status = FAILED; + } + } + else + { + chunk.len -= encryption->get_length(encryption); + status = encryption->decrypt(encryption, chunk); + } if (status != SUCCESS) { break; @@ -1369,7 +1905,8 @@ static status_t decrypt_payloads(private_message_t *this, aead_t *aead) encryption->destroy(encryption); } if (payload_is_known(type) && !was_encrypted && - !is_connectivity_check(this, payload)) + !is_connectivity_check(this, payload) && + this->exchange_type != AGGRESSIVE) { rule = get_payload_rule(this, type); if (!rule || rule->encrypted) @@ -1396,7 +1933,7 @@ static status_t verify(private_message_t *this) DBG2(DBG_ENC, "verifying message structure"); - /* check for payloads with wrong count*/ + /* check for payloads with wrong count */ for (i = 0; i < this->rule->rule_count; i++) { enumerator_t *enumerator; @@ -1443,57 +1980,30 @@ static status_t verify(private_message_t *this) } METHOD(message_t, parse_body, status_t, - private_message_t *this, aead_t *aead) + private_message_t *this, keymat_t *keymat) { status_t status = SUCCESS; - payload_t *payload; - payload_type_t type; char str[BUF_LEN]; - type = this->first_payload; - DBG2(DBG_ENC, "parsing body of message, first payload is %N", - payload_type_names, type); + payload_type_names, this->first_payload); - while (type != NO_PAYLOAD) + this->rule = get_message_rule(this); + if (!this->rule) { - DBG2(DBG_ENC, "starting parsing a %N payload", - payload_type_names, type); - - status = this->parser->parse_payload(this->parser, type, &payload); - if (status != SUCCESS) - { - DBG1(DBG_ENC, "payload type %N could not be parsed", - payload_type_names, type); - return this->exchange_type == IKE_SA_INIT ? PARSE_ERROR : FAILED; - } - - DBG2(DBG_ENC, "verifying payload of type %N", payload_type_names, type); - status = payload->verify(payload); - if (status != SUCCESS) - { - DBG1(DBG_ENC, "%N payload verification failed", - payload_type_names, type); - payload->destroy(payload); - return this->exchange_type == IKE_SA_INIT ? VERIFY_ERROR : FAILED; - } - - DBG2(DBG_ENC, "%N payload verified. Adding to payload list", - payload_type_names, type); - this->payloads->insert_last(this->payloads, payload); + DBG1(DBG_ENC, "no message rules specified for a %N %s", + exchange_type_names, this->exchange_type, + this->is_request ? "request" : "response"); + return NOT_SUPPORTED; + } - /* an encryption payload is the last one, so STOP here. decryption is - * done later */ - if (type == ENCRYPTED) - { - DBG2(DBG_ENC, "%N payload found. Stop parsing", - payload_type_names, type); - break; - } - type = payload->get_next_type(payload); + status = parse_payloads(this); + if (status != SUCCESS) + { /* error is already logged */ + return status; } - status = decrypt_payloads(this, aead); + status = decrypt_payloads(this, keymat); if (status != SUCCESS) { DBG1(DBG_ENC, "could not decrypt payloads"); @@ -1508,6 +2018,50 @@ METHOD(message_t, parse_body, status_t, DBG1(DBG_ENC, "parsed %s", get_string(this, str, sizeof(str))); + if (keymat && keymat->get_version(keymat) == IKEV1) + { + keymat_v1_t *keymat_v1 = (keymat_v1_t*)keymat; + chunk_t hash; + + if (keymat_v1->get_hash_phase2(keymat_v1, &this->public, &hash)) + { + hash_payload_t *hash_payload; + chunk_t other_hash; + + if (this->first_payload != HASH_V1) + { + if (this->exchange_type == INFORMATIONAL_V1) + { + DBG1(DBG_ENC, "ignoring unprotected INFORMATIONAL from %H", + this->packet->get_source(this->packet)); + } + else + { + DBG1(DBG_ENC, "expected HASH payload as first payload"); + } + chunk_free(&hash); + return VERIFY_ERROR; + } + hash_payload = (hash_payload_t*)get_payload(this, HASH_V1); + other_hash = hash_payload->get_hash(hash_payload); + DBG3(DBG_ENC, "HASH received %B\nHASH expected %B", + &other_hash, &hash); + if (!chunk_equals(hash, other_hash)) + { + DBG1(DBG_ENC, "received HASH payload does not match"); + chunk_free(&hash); + return FAILED; + } + chunk_free(&hash); + } + if (this->is_encrypted) + { /* message verified, confirm IV */ + if (!keymat_v1->confirm_iv(keymat_v1, this->message_id)) + { + return FAILED; + } + } + } return SUCCESS; } @@ -1522,7 +2076,7 @@ METHOD(message_t, destroy, void, } /* - * Described in Header-File + * Described in header. */ message_t *message_create_from_packet(packet_t *packet) { @@ -1567,8 +2121,6 @@ message_t *message_create_from_packet(packet_t *packet) .get_packet_data = _get_packet_data, .destroy = _destroy, }, - .major_version = IKE_MAJOR_VERSION, - .minor_version = IKE_MINOR_VERSION, .exchange_type = EXCHANGE_TYPE_UNDEFINED, .is_request = TRUE, .first_payload = NO_PAYLOAD, @@ -1577,14 +2129,18 @@ message_t *message_create_from_packet(packet_t *packet) .parser = parser_create(packet->get_data(packet)), ); - return (&this->public); + return &this->public; } /* - * Described in Header. + * Described in header. */ -message_t *message_create() +message_t *message_create(int major, int minor) { - return message_create_from_packet(packet_create()); -} + message_t *this = message_create_from_packet(packet_create()); + this->set_major_version(this, major); + this->set_minor_version(this, minor); + + return this; +} diff --git a/src/libcharon/encoding/message.h b/src/libcharon/encoding/message.h index 0e78ea436..6d558daf6 100644 --- a/src/libcharon/encoding/message.h +++ b/src/libcharon/encoding/message.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2007 Tobias Brunner + * Copyright (C) 2006-2011 Tobias Brunner * Copyright (C) 2005-2009 Martin Willi * Copyright (C) 2006 Daniel Roethlisberger * Copyright (C) 2005 Jan Hutter @@ -27,15 +27,15 @@ typedef struct message_t message_t; #include <library.h> -#include <sa/ike_sa_id.h> -#include <network/packet.h> #include <encoding/payloads/ike_header.h> #include <encoding/payloads/notify_payload.h> +#include <sa/keymat.h> +#include <sa/ike_sa_id.h> +#include <utils/packet.h> #include <utils/linked_list.h> -#include <crypto/aead.h> /** - * This class is used to represent an IKEv2-Message. + * This class is used to represent an IKE-Message. * * The message handles parsing and generation of payloads * via parser_t/generator_t. Encryption is done transparently @@ -182,7 +182,7 @@ struct message_t { * all payloads to encrypt are added to the encryption payload, which is * always the last one. * - * @param payload payload to append + * @param payload payload to append */ void (*add_payload) (message_t *this, payload_t *payload); @@ -208,14 +208,14 @@ struct message_t { /** * Parses header of message. * - * Begins parisng of a message created via message_create_from_packet(). + * Begins parsing of a message created via message_create_from_packet(). * The parsing context is stored, so a subsequent call to parse_body() * will continue the parsing process. * * @return - * - SUCCESS if header could be parsed + * - SUCCESS if header could be parsed * - PARSE_ERROR if corrupted/invalid data found - * - FAILED if consistence check of header failed + * - FAILED if consistency check of header failed */ status_t (*parse_header) (message_t *this); @@ -228,15 +228,15 @@ struct message_t { * If there are encrypted payloads, they get decrypted and verified using * the given aead transform (if given). * - * @param aead aead transform to verify/decrypt message + * @param keymat keymat to verify/decrypt message * @return - * - SUCCESS if parsing successful + * - SUCCESS if parsing successful * - PARSE_ERROR if message parsing failed - * - VERIFY_ERROR if message verification failed (bad syntax) - * - FAILED if integrity check failed - * - INVALID_STATE if aead not supplied, but needed + * - VERIFY_ERROR if message verification failed (bad syntax) + * - FAILED if integrity check failed + * - INVALID_STATE if aead not supplied, but needed */ - status_t (*parse_body) (message_t *this, aead_t *aead); + status_t (*parse_body) (message_t *this, keymat_t *keymat); /** * Generates the UDP packet of specific message. @@ -247,15 +247,15 @@ struct message_t { * Generation is only done once, multiple calls will just return a copy * of the packet. * - * @param aead aead transform to encrypt/sign message + * @param keymat keymat to encrypt/sign message * @param packet copy of generated packet * @return - * - SUCCESS if packet could be generated - * - INVALID_STATE if exchange type is currently not set - * - NOT_FOUND if no rules found for message generation - * - INVALID_STATE if aead not supplied but needed. + * - SUCCESS if packet could be generated + * - INVALID_STATE if exchange type is currently not set + * - NOT_FOUND if no rules found for message generation + * - INVALID_STATE if aead not supplied but needed. */ - status_t (*generate) (message_t *this, aead_t *aead, packet_t **packet); + status_t (*generate) (message_t *this, keymat_t *keymat, packet_t **packet); /** * Check if the message has already been encoded using generate(). @@ -278,7 +278,7 @@ struct message_t { * Sets the source host informations. * * @warning host_t object is not getting cloned and gets destroyed by - * message_t.destroy or next call of message_t.set_source. + * message_t.destroy or next call of message_t.set_source. * * @param host host_t object representing source host */ @@ -298,7 +298,7 @@ struct message_t { * Sets the destination host informations. * * @warning host_t object is not getting cloned and gets destroyed by - * message_t.destroy or next call of message_t.set_destination. + * message_t.destroy or next call of message_t.set_destination. * * @param host host_t object representing destination host */ @@ -344,9 +344,9 @@ struct message_t { packet_t * (*get_packet) (message_t *this); /** - * Returns a clone of the internal stored packet_t data. + * Returns a chunk pointing to internal packet_t data. * - * @return clone of the internal stored packet_t data. + * @return packet data. */ chunk_t (*get_packet_data) (message_t *this); @@ -357,26 +357,27 @@ struct message_t { }; /** - * Creates an message_t object from a incoming UDP Packet. + * Creates a message_t object from an incoming UDP packet. * * The given packet gets owned by the message. The message is uninitialized, * call parse_header() to populate header fields. * * @param packet packet_t object which is assigned to message - * @return message_t object + * @return message_t object */ -message_t * message_create_from_packet(packet_t *packet); - +message_t *message_create_from_packet(packet_t *packet); /** - * Creates an empty message_t object. + * Creates an empty message_t object for a specific major/minor version. * * - exchange_type is set to NOT_SET * - original_initiator is set to TRUE * - is_request is set to TRUE * - * @return message_t object + * @param major major IKE version of this message + * @param minor minor IKE version of this message + * @return message_t object */ -message_t * message_create(void); +message_t *message_create(int major, int minor); #endif /** MESSAGE_H_ @}*/ diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index e49210309..e4b140c3e 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -137,7 +137,7 @@ static bool parse_uint4(private_parser_t *this, int rule_number, } if (output_pos) { - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hhu", *output_pos); } return TRUE; } @@ -159,7 +159,7 @@ static bool parse_uint8(private_parser_t *this, int rule_number, if (output_pos) { *output_pos = *(this->byte_pos); - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hhu", *output_pos); } this->byte_pos++; return TRUE; @@ -183,7 +183,7 @@ static bool parse_uint15(private_parser_t *this, int rule_number, { memcpy(output_pos, this->byte_pos, sizeof(u_int16_t)); *output_pos = ntohs(*output_pos) & ~0x8000; - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hu", *output_pos); } this->byte_pos += sizeof(u_int16_t); this->bit_pos = 0; @@ -208,7 +208,7 @@ static bool parse_uint16(private_parser_t *this, int rule_number, { memcpy(output_pos, this->byte_pos, sizeof(u_int16_t)); *output_pos = ntohs(*output_pos); - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %hu", *output_pos); } this->byte_pos += sizeof(u_int16_t); return TRUE; @@ -231,7 +231,7 @@ static bool parse_uint32(private_parser_t *this, int rule_number, { memcpy(output_pos, this->byte_pos, sizeof(u_int32_t)); *output_pos = ntohl(*output_pos); - DBG3(DBG_ENC, " => %d", *output_pos); + DBG3(DBG_ENC, " => %u", *output_pos); } this->byte_pos += sizeof(u_int32_t); return TRUE; @@ -254,7 +254,7 @@ static bool parse_bytes(private_parser_t *this, int rule_number, if (output_pos) { memcpy(output_pos, this->byte_pos, bytes); - DBG3(DBG_ENC, " => %b", output_pos, bytes); + DBG3(DBG_ENC, " %b", output_pos, bytes); } this->byte_pos += bytes; return TRUE; @@ -352,7 +352,7 @@ static bool parse_chunk(private_parser_t *this, int rule_number, { *output_pos = chunk_alloc(length); memcpy(output_pos->ptr, this->byte_pos, length); - DBG3(DBG_ENC, " => %b", output_pos->ptr, length); + DBG3(DBG_ENC, " %b", output_pos->ptr, length); } this->byte_pos += length; return TRUE; @@ -363,11 +363,10 @@ METHOD(parser_t, parse_payload, status_t, { payload_t *pld; void *output; - size_t rule_count; - int payload_length = 0, spi_size = 0, attribute_length = 0; + int payload_length = 0, spi_size = 0, attribute_length = 0, header_length; u_int16_t ts_type = 0; bool attribute_format = FALSE; - int rule_number; + int rule_number, rule_count; encoding_rule_t *rule; /* create instance of the payload to parse */ @@ -381,15 +380,17 @@ METHOD(parser_t, parse_payload, status_t, /* base pointer for output, avoids casting in every rule */ output = pld; - /* parse the payload with its own rulse */ - pld->get_encoding_rules(pld, &this->rules, &rule_count); + rule_count = pld->get_encoding_rules(pld, &this->rules); for (rule_number = 0; rule_number < rule_count; rule_number++) { + /* update header length for each rule, as it is dynamic (SPIs) */ + header_length = pld->get_header_length(pld); + rule = &(this->rules[rule_number]); DBG2(DBG_ENC, " parsing rule %d %N", rule_number, encoding_type_names, rule->type); - switch (rule->type) + switch ((int)rule->type) { case U_INT_4: { @@ -457,7 +458,8 @@ METHOD(parser_t, parse_payload, status_t, } /* parsed u_int16 should be aligned */ payload_length = *(u_int16_t*)(output + rule->offset); - if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH) + /* all payloads must have at least 4 bytes header */ + if (payload_length < 4) { pld->destroy(pld); return PARSE_ERROR; @@ -484,49 +486,41 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case PROPOSALS: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE: + case PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE: + case PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE: + case PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE: + case PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1: + case PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE: { - if (payload_length < SA_PAYLOAD_HEADER_LENGTH || + if (payload_length < header_length || !parse_list(this, rule_number, output + rule->offset, - PROPOSAL_SUBSTRUCTURE, - payload_length - SA_PAYLOAD_HEADER_LENGTH)) + rule->type - PAYLOAD_LIST, + payload_length - header_length)) { pld->destroy(pld); return PARSE_ERROR; } break; } - case TRANSFORMS: + case CHUNK_DATA: { - if (payload_length < - spi_size + PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRANSFORM_SUBSTRUCTURE, payload_length - spi_size - - PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case TRANSFORM_ATTRIBUTES: - { - if (payload_length < TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRANSFORM_ATTRIBUTE, - payload_length - TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH)) + if (payload_length < header_length || + !parse_chunk(this, rule_number, output + rule->offset, + payload_length - header_length)) { pld->destroy(pld); return PARSE_ERROR; } break; } - case CONFIGURATION_ATTRIBUTES: + case ENCRYPTED_DATA: { - if (payload_length < CP_PAYLOAD_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - CONFIGURATION_ATTRIBUTE, - payload_length - CP_PAYLOAD_HEADER_LENGTH)) + if (!parse_chunk(this, rule_number, output + rule->offset, + this->input_roof - this->byte_pos)) { pld->destroy(pld); return PARSE_ERROR; @@ -552,7 +546,7 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case CONFIGURATION_ATTRIBUTE_LENGTH: + case ATTRIBUTE_LENGTH: { if (!parse_uint16(this, rule_number, output + rule->offset)) { @@ -583,137 +577,6 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case NONCE_DATA: - { - if (payload_length < NONCE_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - NONCE_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case ID_DATA: - { - if (payload_length < ID_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - ID_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case AUTH_DATA: - { - if (payload_length < AUTH_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - AUTH_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case CERT_DATA: - { - if (payload_length < CERT_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - CERT_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case CERTREQ_DATA: - { - if (payload_length < CERTREQ_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - CERTREQ_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case EAP_DATA: - { - if (payload_length < EAP_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - EAP_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case SPIS: - { - if (payload_length < DELETE_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - DELETE_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case VID_DATA: - { - if (payload_length < VENDOR_ID_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - VENDOR_ID_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case CONFIGURATION_ATTRIBUTE_VALUE: - { - if (!parse_chunk(this, rule_number, output + rule->offset, - attribute_length)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case KEY_EXCHANGE_DATA: - { - if (payload_length < KE_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - KE_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case NOTIFICATION_DATA: - { - if (payload_length < NOTIFY_PAYLOAD_HEADER_LENGTH + spi_size || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - NOTIFY_PAYLOAD_HEADER_LENGTH - spi_size)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case ENCRYPTED_DATA: - { - if (payload_length < ENCRYPTION_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - ENCRYPTION_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } case TS_TYPE: { if (!parse_uint8(this, rule_number, output + rule->offset)) @@ -736,29 +599,6 @@ METHOD(parser_t, parse_payload, status_t, } break; } - case TRAFFIC_SELECTORS: - { - if (payload_length < TS_PAYLOAD_HEADER_LENGTH || - !parse_list(this, rule_number, output + rule->offset, - TRAFFIC_SELECTOR_SUBSTRUCTURE, - payload_length - TS_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } - case UNKNOWN_DATA: - { - if (payload_length < UNKNOWN_PAYLOAD_HEADER_LENGTH || - !parse_chunk(this, rule_number, output + rule->offset, - payload_length - UNKNOWN_PAYLOAD_HEADER_LENGTH)) - { - pld->destroy(pld); - return PARSE_ERROR; - } - break; - } default: { DBG1(DBG_ENC, " no rule to parse rule %d %N", diff --git a/src/libcharon/encoding/payloads/auth_payload.c b/src/libcharon/encoding/payloads/auth_payload.c index cb44a997c..2410a1aaa 100644 --- a/src/libcharon/encoding/payloads/auth_payload.c +++ b/src/libcharon/encoding/payloads/auth_payload.c @@ -74,7 +74,7 @@ struct private_auth_payload_t { * The defined offsets are the positions in a object of type * private_auth_payload_t. */ -encoding_rule_t auth_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_auth_payload_t, next_payload) }, /* the critical bit */ @@ -96,7 +96,7 @@ encoding_rule_t auth_payload_encodings[] = { { RESERVED_BYTE, offsetof(private_auth_payload_t, reserved_byte[1]) }, { RESERVED_BYTE, offsetof(private_auth_payload_t, reserved_byte[2]) }, /* some auth data bytes, length is defined in PAYLOAD_LENGTH */ - { AUTH_DATA, offsetof(private_auth_payload_t, auth_data) } + { CHUNK_DATA, offsetof(private_auth_payload_t, auth_data) } }; /* @@ -119,11 +119,17 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_auth_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_auth_payload_t *this, encoding_rule_t **rules) { - *rules = auth_payload_encodings; - *rule_count = countof(auth_payload_encodings); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_auth_payload_t *this) +{ + return 8; } METHOD(payload_t, get_type, payload_type_t, @@ -167,7 +173,7 @@ METHOD(auth_payload_t, set_data, void, { free(this->auth_data.ptr); this->auth_data = chunk_clone(data); - this->payload_length = AUTH_PAYLOAD_HEADER_LENGTH + this->auth_data.len; + this->payload_length = get_header_length(this) + this->auth_data.len; } METHOD(auth_payload_t, get_data, chunk_t, @@ -195,6 +201,7 @@ auth_payload_t *auth_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -208,7 +215,7 @@ auth_payload_t *auth_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = AUTH_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/auth_payload.h b/src/libcharon/encoding/payloads/auth_payload.h index e4c4e6ae3..b922d12c8 100644 --- a/src/libcharon/encoding/payloads/auth_payload.h +++ b/src/libcharon/encoding/payloads/auth_payload.h @@ -26,12 +26,7 @@ typedef struct auth_payload_t auth_payload_t; #include <library.h> #include <encoding/payloads/payload.h> -#include <sa/authenticators/authenticator.h> - -/** - * Length of a auth payload without the auth data in bytes. - */ -#define AUTH_PAYLOAD_HEADER_LENGTH 8 +#include <sa/authenticator.h> /** * Class representing an IKEv2 AUTH payload. diff --git a/src/libcharon/encoding/payloads/cert_payload.c b/src/libcharon/encoding/payloads/cert_payload.c index c42cec680..3a230b91e 100644 --- a/src/libcharon/encoding/payloads/cert_payload.c +++ b/src/libcharon/encoding/payloads/cert_payload.c @@ -86,6 +86,11 @@ struct private_cert_payload_t { * TRUE if the "Hash and URL" data is invalid */ bool invalid_hash_and_url; + + /** + * The payload type. + */ + payload_type_t type; }; /** @@ -95,7 +100,7 @@ struct private_cert_payload_t { * private_cert_payload_t. * */ -encoding_rule_t cert_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_cert_payload_t, next_payload) }, /* the critical bit */ @@ -113,7 +118,7 @@ encoding_rule_t cert_payload_encodings[] = { /* 1 Byte CERT type*/ { U_INT_8, offsetof(private_cert_payload_t, encoding) }, /* some cert data bytes, length is defined in PAYLOAD_LENGTH */ - { CERT_DATA, offsetof(private_cert_payload_t, data) } + { CHUNK_DATA, offsetof(private_cert_payload_t, data) } }; /* @@ -166,17 +171,23 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_cert_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_cert_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_cert_payload_t *this) { - *rules = cert_payload_encodings; - *rule_count = countof(cert_payload_encodings); + return 5; } METHOD(payload_t, get_type, payload_type_t, private_cert_payload_t *this) { - return CERTIFICATE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -261,7 +272,7 @@ METHOD2(payload_t, cert_payload_t, destroy, void, /* * Described in header */ -cert_payload_t *cert_payload_create() +cert_payload_t *cert_payload_create(payload_type_t type) { private_cert_payload_t *this; @@ -270,6 +281,7 @@ cert_payload_t *cert_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -283,7 +295,8 @@ cert_payload_t *cert_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = CERT_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), + .type = type, ); return &this->public; } @@ -291,10 +304,12 @@ cert_payload_t *cert_payload_create() /* * Described in header */ -cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) +cert_payload_t *cert_payload_create_from_cert(payload_type_t type, + certificate_t *cert) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + private_cert_payload_t *this; + this = (private_cert_payload_t*)cert_payload_create(type); switch (cert->get_type(cert)) { case CERT_X509: @@ -312,7 +327,8 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) free(this); return NULL; } - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + this->payload_length = get_header_length(this) + this->data.len; + return &this->public; } @@ -321,23 +337,29 @@ cert_payload_t *cert_payload_create_from_cert(certificate_t *cert) */ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + private_cert_payload_t *this; + this = (private_cert_payload_t*)cert_payload_create(CERTIFICATE); this->encoding = ENC_X509_HASH_AND_URL; this->data = chunk_cat("cc", hash, chunk_create(url, strlen(url))); - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + this->payload_length = get_header_length(this) + this->data.len; + return &this->public; } /* * Described in header */ -cert_payload_t *cert_payload_create_custom(cert_encoding_t type, chunk_t data) +cert_payload_t *cert_payload_create_custom(payload_type_t type, + cert_encoding_t encoding, chunk_t data) { - private_cert_payload_t *this = (private_cert_payload_t*)cert_payload_create(); + private_cert_payload_t *this; - this->encoding = type; + this = (private_cert_payload_t*)cert_payload_create(type); + this->encoding = encoding; this->data = data; - this->payload_length = CERT_PAYLOAD_HEADER_LENGTH + this->data.len; + this->payload_length = get_header_length(this) + this->data.len; + return &this->public; } + diff --git a/src/libcharon/encoding/payloads/cert_payload.h b/src/libcharon/encoding/payloads/cert_payload.h index 21b503a40..19ed2ccd2 100644 --- a/src/libcharon/encoding/payloads/cert_payload.h +++ b/src/libcharon/encoding/payloads/cert_payload.h @@ -31,11 +31,6 @@ typedef enum cert_encoding_t cert_encoding_t; #include <encoding/payloads/payload.h> /** - * Length of a cert payload without the cert data in bytes. - */ -#define CERT_PAYLOAD_HEADER_LENGTH 5 - -/** * Certifcate encodings, as in RFC4306 */ enum cert_encoding_t { @@ -60,9 +55,7 @@ enum cert_encoding_t { extern enum_name_t *cert_encoding_names; /** - * Class representing an IKEv2 CERT payload. - * - * The CERT payload format is described in RFC section 3.6. + * Class representing an IKEv1/IKEv2 CERT payload. */ struct cert_payload_t { @@ -103,7 +96,6 @@ struct cert_payload_t { */ char *(*get_url)(cert_payload_t *this); - /** * Destroys the cert_payload object. */ @@ -113,23 +105,26 @@ struct cert_payload_t { /** * Creates an empty certificate payload. * + * @param type payload type (for IKEv1 or IKEv2) * @return cert_payload_t object */ -cert_payload_t *cert_payload_create(void); +cert_payload_t *cert_payload_create(payload_type_t type); /** * Creates a certificate payload with an embedded certificate. * + * @param type payload type (for IKEv1 or IKEv2) * @param cert certificate to embed * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_from_cert(certificate_t *cert); +cert_payload_t *cert_payload_create_from_cert(payload_type_t type, + certificate_t *cert); /** - * Creates a certificate payload with hash and URL encoding of a certificate. + * Creates an IKEv2 certificate payload with hash and URL encoding. * * @param hash hash of the DER encoded certificate (get's cloned) - * @param url the URL to locate the certificate (get's cloned) + * @param url URL to the certificate * @return cert_payload_t object */ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url); @@ -137,10 +132,12 @@ cert_payload_t *cert_payload_create_from_hash_and_url(chunk_t hash, char *url); /** * Creates a custom certificate payload using type and associated data. * - * @param type encoding type of certificate + * @param type payload type (for IKEv1 or IKEv2) + * @param encoding encoding type of certificate * @param data associated data (gets owned) * @return cert_payload_t object */ -cert_payload_t *cert_payload_create_custom(cert_encoding_t type, chunk_t data); +cert_payload_t *cert_payload_create_custom(payload_type_t type, + cert_encoding_t encoding, chunk_t data); #endif /** CERT_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/certreq_payload.c b/src/libcharon/encoding/payloads/certreq_payload.c index 02015f273..df5e73b5b 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.c +++ b/src/libcharon/encoding/payloads/certreq_payload.c @@ -64,15 +64,17 @@ struct private_certreq_payload_t { * The contained certreq data value. */ chunk_t data; + + /** + * Payload type CERTIFICATE_REQUEST or CERTIFICATE_REQUEST_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a CERTREQ payload - * - * The defined offsets are the positions in a object of type - * private_certreq_payload_t. + * Encoding rules for CERTREQ payload. */ -encoding_rule_t certreq_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_certreq_payload_t, next_payload) }, /* the critical bit */ @@ -90,7 +92,7 @@ encoding_rule_t certreq_payload_encodings[] = { /* 1 Byte CERTREQ type*/ { U_INT_8, offsetof(private_certreq_payload_t, encoding) }, /* some certreq data bytes, length is defined in PAYLOAD_LENGTH */ - { CERTREQ_DATA, offsetof(private_certreq_payload_t, data) } + { CHUNK_DATA, offsetof(private_certreq_payload_t, data) } }; /* @@ -109,7 +111,8 @@ encoding_rule_t certreq_payload_encodings[] = { METHOD(payload_t, verify, status_t, private_certreq_payload_t *this) { - if (this->encoding == ENC_X509_SIGNATURE) + if (this->type == CERTIFICATE_REQUEST && + this->encoding == ENC_X509_SIGNATURE) { if (this->data.len % HASH_SIZE_SHA1) { @@ -121,17 +124,23 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_certreq_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_certreq_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_certreq_payload_t *this) { - *rules = certreq_payload_encodings; - *rule_count = countof(certreq_payload_encodings); + return 5; } METHOD(payload_t, get_type, payload_type_t, private_certreq_payload_t *this) { - return CERTIFICATE_REQUEST; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -152,6 +161,16 @@ METHOD(payload_t, get_length, size_t, return this->payload_length; } +METHOD(certreq_payload_t, get_dn, identification_t*, + private_certreq_payload_t *this) +{ + if (this->data.len) + { + return identification_create_from_encoding(ID_DER_ASN1_DN, this->data); + } + return NULL; +} + METHOD(certreq_payload_t, add_keyid, void, private_certreq_payload_t *this, chunk_t keyid) { @@ -199,6 +218,10 @@ METHOD(certreq_payload_t, create_keyid_enumerator, enumerator_t*, { keyid_enumerator_t *enumerator; + if (this->type == CERTIFICATE_REQUEST_V1) + { + return enumerator_create_empty(); + } INIT(enumerator, .public = { .enumerate = (void*)_keyid_enumerate, @@ -231,7 +254,7 @@ METHOD2(payload_t, certreq_payload_t, destroy, void, /* * Described in header */ -certreq_payload_t *certreq_payload_create() +certreq_payload_t *certreq_payload_create(payload_type_t type) { private_certreq_payload_t *this; @@ -240,6 +263,7 @@ certreq_payload_t *certreq_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -250,9 +274,11 @@ certreq_payload_t *certreq_payload_create() .get_cert_type = _get_cert_type, .add_keyid = _add_keyid, .destroy = _destroy, + .get_dn = _get_dn, }, .next_payload = NO_PAYLOAD, - .payload_length = CERTREQ_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), + .type = type, ); return &this->public; } @@ -262,8 +288,10 @@ certreq_payload_t *certreq_payload_create() */ certreq_payload_t *certreq_payload_create_type(certificate_type_t type) { - private_certreq_payload_t *this = (private_certreq_payload_t*)certreq_payload_create(); + private_certreq_payload_t *this; + this = (private_certreq_payload_t*) + certreq_payload_create(CERTIFICATE_REQUEST); switch (type) { case CERT_X509: @@ -278,3 +306,19 @@ certreq_payload_t *certreq_payload_create_type(certificate_type_t type) return &this->public; } +/* + * Described in header + */ +certreq_payload_t *certreq_payload_create_dn(identification_t *id) +{ + private_certreq_payload_t *this; + + this = (private_certreq_payload_t*) + certreq_payload_create(CERTIFICATE_REQUEST_V1); + + this->encoding = ENC_X509_SIGNATURE; + this->data = chunk_clone(id->get_encoding(id)); + this->payload_length = get_header_length(this) + this->data.len; + + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/certreq_payload.h b/src/libcharon/encoding/payloads/certreq_payload.h index 914063628..cce71c0ad 100644 --- a/src/libcharon/encoding/payloads/certreq_payload.h +++ b/src/libcharon/encoding/payloads/certreq_payload.h @@ -27,25 +27,20 @@ typedef struct certreq_payload_t certreq_payload_t; #include <library.h> #include <encoding/payloads/payload.h> #include <encoding/payloads/cert_payload.h> +#include <utils/identification.h> /** - * Length of a CERTREQ payload without the CERTREQ data in bytes. - */ -#define CERTREQ_PAYLOAD_HEADER_LENGTH 5 - -/** - * Class representing an IKEv2 CERTREQ payload. - * - * The CERTREQ payload format is described in RFC section 3.7. + * Class representing an IKEv1/IKEv2 CERTREQ payload. */ struct certreq_payload_t { + /** * The payload_t interface. */ payload_t payload_interface; /** - * Create an enumerator over contained keyids. + * Create an enumerator over contained keyids (IKEv2 only). * * @return enumerator over chunk_t's. */ @@ -59,7 +54,7 @@ struct certreq_payload_t { certificate_type_t (*get_cert_type)(certreq_payload_t *this); /** - * Add a certificates keyid to the payload. + * Add a certificates keyid to the payload (IKEv2 only). * * @param keyid keyid of the trusted certifcate * @return @@ -67,6 +62,13 @@ struct certreq_payload_t { void (*add_keyid)(certreq_payload_t *this, chunk_t keyid); /** + * Get the distinguished name of the payload (IKEv1 only). + * + * @return DN as identity, must be destroyed + */ + identification_t* (*get_dn)(certreq_payload_t *this); + + /** * Destroys an certreq_payload_t object. */ void (*destroy) (certreq_payload_t *this); @@ -77,14 +79,22 @@ struct certreq_payload_t { * * @return certreq payload */ -certreq_payload_t *certreq_payload_create(void); +certreq_payload_t *certreq_payload_create(payload_type_t payload_type); /** - * Creates an empty certreq_payload_t for a kind of certificates. + * Creates an empty IKEv2 certreq_payload_t for a kind of certificates. * * @param type type of the added keyids * @return certreq payload */ certreq_payload_t *certreq_payload_create_type(certificate_type_t type); +/** + * Creates a IKEv1 certreq_payload_t for a given distinguished name. + * + * @param id distinguished name, does not get owned + * @return certreq payload + */ +certreq_payload_t *certreq_payload_create_dn(identification_t *id); + #endif /** CERTREQ_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/configuration_attribute.c b/src/libcharon/encoding/payloads/configuration_attribute.c index e608497bd..482eca882 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.c +++ b/src/libcharon/encoding/payloads/configuration_attribute.c @@ -36,41 +36,48 @@ struct private_configuration_attribute_t { configuration_attribute_t public; /** - * Reserved bit + * Value encoded in length field? + */ + bool af_flag; + + /** + * Reserved bit (af_flag in IKEv2) */ bool reserved; /** * Type of the attribute. */ - u_int16_t type; + u_int16_t attr_type; /** - * Length of the attribute. + * Length of the attribute, value if af_flag set. */ - u_int16_t length; + u_int16_t length_or_value; /** * Attribute value as chunk. */ chunk_t value; + + /** + * Payload type, CONFIGURATION_ATTRIBUTE or DATA_ATTRIBUTE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a configuration attribute. - * - * The defined offsets are the positions in a object of type - * private_configuration_attribute_t. + * Encoding rules for a IKEv2 configuration attribute / IKEv1 data attribute */ -encoding_rule_t configuration_attribute_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 reserved bit */ - { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved)}, + { RESERVED_BIT, offsetof(private_configuration_attribute_t, reserved) }, /* type of the attribute as 15 bit unsigned integer */ - { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, type) }, + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, /* Length of attribute value */ - { CONFIGURATION_ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length) }, + { ATTRIBUTE_LENGTH, offsetof(private_configuration_attribute_t, length_or_value)}, /* Value of attribute if attribute format flag is zero */ - { CONFIGURATION_ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) } + { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }, }; /* @@ -85,87 +92,142 @@ encoding_rule_t configuration_attribute_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for a IKEv1 data attribute + */ +static encoding_rule_t encodings_v1[] = { + /* AF Flag */ + { ATTRIBUTE_FORMAT, offsetof(private_configuration_attribute_t, af_flag) }, + /* type of the attribute as 15 bit unsigned integer */ + { ATTRIBUTE_TYPE, offsetof(private_configuration_attribute_t, attr_type) }, + /* Length of attribute value */ + { ATTRIBUTE_LENGTH_OR_VALUE, offsetof(private_configuration_attribute_t, length_or_value)}, + /* Value of attribute if attribute format flag is zero */ + { ATTRIBUTE_VALUE, offsetof(private_configuration_attribute_t, value) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + !F| Attribute Type ! Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + ~ Value ~ + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + METHOD(payload_t, verify, status_t, private_configuration_attribute_t *this) { bool failed = FALSE; - if (this->length != this->value.len) - { - DBG1(DBG_ENC, "invalid attribute length"); - return FAILED; - } - - switch (this->type) + switch (this->attr_type) { - case INTERNAL_IP4_ADDRESS: - case INTERNAL_IP4_NETMASK: - case INTERNAL_IP4_DNS: - case INTERNAL_IP4_NBNS: - case INTERNAL_ADDRESS_EXPIRY: - case INTERNAL_IP4_DHCP: - if (this->length != 0 && this->length != 4) + case INTERNAL_IP4_ADDRESS: + case INTERNAL_IP4_NETMASK: + case INTERNAL_IP4_DNS: + case INTERNAL_IP4_NBNS: + case INTERNAL_ADDRESS_EXPIRY: + case INTERNAL_IP4_DHCP: + if (this->length_or_value != 0 && this->length_or_value != 4) { failed = TRUE; } break; - case INTERNAL_IP4_SUBNET: - if (this->length != 0 && this->length != 8) + case INTERNAL_IP4_SUBNET: + if (this->length_or_value != 0 && this->length_or_value != 8) { failed = TRUE; } break; - case INTERNAL_IP6_ADDRESS: - case INTERNAL_IP6_SUBNET: - if (this->length != 0 && this->length != 17) + case INTERNAL_IP6_ADDRESS: + case INTERNAL_IP6_SUBNET: + if (this->length_or_value != 0 && this->length_or_value != 17) { failed = TRUE; } break; - case INTERNAL_IP6_DNS: - case INTERNAL_IP6_NBNS: - case INTERNAL_IP6_DHCP: - if (this->length != 0 && this->length != 16) + case INTERNAL_IP6_DNS: + case INTERNAL_IP6_NBNS: + case INTERNAL_IP6_DHCP: + if (this->length_or_value != 0 && this->length_or_value != 16) { failed = TRUE; } break; - case SUPPORTED_ATTRIBUTES: - if (this->length % 2) + case SUPPORTED_ATTRIBUTES: + if (this->length_or_value % 2) { failed = TRUE; } break; - case APPLICATION_VERSION: + case APPLICATION_VERSION: + case INTERNAL_IP4_SERVER: + case INTERNAL_IP6_SERVER: + case XAUTH_TYPE: + case XAUTH_USER_NAME: + case XAUTH_USER_PASSWORD: + case XAUTH_PASSCODE: + case XAUTH_MESSAGE: + case XAUTH_CHALLENGE: + case XAUTH_DOMAIN: + case XAUTH_STATUS: + case XAUTH_NEXT_PIN: + case XAUTH_ANSWER: + case UNITY_BANNER: + case UNITY_SAVE_PASSWD: + case UNITY_DEF_DOMAIN: + case UNITY_SPLITDNS_NAME: + case UNITY_SPLIT_INCLUDE: + case UNITY_NATT_PORT: + case UNITY_LOCAL_LAN: + case UNITY_PFS: + case UNITY_FW_TYPE: + case UNITY_BACKUP_SERVERS: + case UNITY_DDNS_HOSTNAME: /* any length acceptable */ break; - default: + default: DBG1(DBG_ENC, "unknown attribute type %N", - configuration_attribute_type_names, this->type); + configuration_attribute_type_names, this->attr_type); break; } if (failed) { DBG1(DBG_ENC, "invalid attribute length %d for %N", - this->length, configuration_attribute_type_names, this->type); + this->length_or_value, configuration_attribute_type_names, + this->attr_type); return FAILED; } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_configuration_attribute_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_configuration_attribute_t *this, encoding_rule_t **rules) +{ + if (this->type == CONFIGURATION_ATTRIBUTE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_configuration_attribute_t *this) { - *rules = configuration_attribute_encodings; - *rule_count = countof(configuration_attribute_encodings); + return 4; } METHOD(payload_t, get_type, payload_type_t, private_configuration_attribute_t *this) { - return CONFIGURATION_ATTRIBUTE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -182,21 +244,35 @@ METHOD(payload_t, set_next_type, void, METHOD(payload_t, get_length, size_t, private_configuration_attribute_t *this) { - return this->value.len + CONFIGURATION_ATTRIBUTE_HEADER_LENGTH; + return get_header_length(this) + this->value.len; } METHOD(configuration_attribute_t, get_cattr_type, configuration_attribute_type_t, private_configuration_attribute_t *this) { - return this->type; + return this->attr_type; } -METHOD(configuration_attribute_t, get_value, chunk_t, +METHOD(configuration_attribute_t, get_chunk, chunk_t, private_configuration_attribute_t *this) { + if (this->af_flag) + { + return chunk_from_thing(this->length_or_value); + } return this->value; } +METHOD(configuration_attribute_t, get_value, u_int16_t, + private_configuration_attribute_t *this) +{ + if (this->af_flag) + { + return this->length_or_value; + } + return 0; +} + METHOD2(payload_t, configuration_attribute_t, destroy, void, private_configuration_attribute_t *this) { @@ -207,7 +283,7 @@ METHOD2(payload_t, configuration_attribute_t, destroy, void, /* * Described in header. */ -configuration_attribute_t *configuration_attribute_create() +configuration_attribute_t *configuration_attribute_create(payload_type_t type) { private_configuration_attribute_t *this; @@ -216,16 +292,19 @@ configuration_attribute_t *configuration_attribute_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, .get_type = _get_type, .destroy = _destroy, }, + .get_chunk = _get_chunk, .get_value = _get_value, .get_type = _get_cattr_type, .destroy = _destroy, }, + .type = type ); return &this->public; } @@ -233,15 +312,33 @@ configuration_attribute_t *configuration_attribute_create() /* * Described in header. */ +configuration_attribute_t *configuration_attribute_create_chunk( + payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk) +{ + private_configuration_attribute_t *this; + + this = (private_configuration_attribute_t*) + configuration_attribute_create(type); + this->attr_type = ((u_int16_t)attr_type) & 0x7FFF; + this->value = chunk_clone(chunk); + this->length_or_value = chunk.len; + + return &this->public; +} + +/* + * Described in header. + */ configuration_attribute_t *configuration_attribute_create_value( - configuration_attribute_type_t type, chunk_t value) + configuration_attribute_type_t attr_type, u_int16_t value) { private_configuration_attribute_t *this; - this = (private_configuration_attribute_t*)configuration_attribute_create(); - this->type = ((u_int16_t)type) & 0x7FFF; - this->value = chunk_clone(value); - this->length = value.len; + this = (private_configuration_attribute_t*) + configuration_attribute_create(CONFIGURATION_ATTRIBUTE_V1); + this->attr_type = ((u_int16_t)attr_type) & 0x7FFF; + this->length_or_value = value; + this->af_flag = TRUE; return &this->public; } diff --git a/src/libcharon/encoding/payloads/configuration_attribute.h b/src/libcharon/encoding/payloads/configuration_attribute.h index 6e4b018bb..ecc0f9c07 100644 --- a/src/libcharon/encoding/payloads/configuration_attribute.h +++ b/src/libcharon/encoding/payloads/configuration_attribute.h @@ -29,14 +29,7 @@ typedef struct configuration_attribute_t configuration_attribute_t; #include <encoding/payloads/payload.h> /** - * Configuration attribute header length in bytes. - */ -#define CONFIGURATION_ATTRIBUTE_HEADER_LENGTH 4 - -/** - * Class representing an IKEv2-CONFIGURATION Attribute. - * - * The CONFIGURATION ATTRIBUTE format is described in RFC section 3.15.1. + * Class representing an IKEv2 configuration attribute / IKEv1 data attribute. */ struct configuration_attribute_t { @@ -53,11 +46,18 @@ struct configuration_attribute_t { configuration_attribute_type_t (*get_type)(configuration_attribute_t *this); /** - * Returns the value of the attribute. + * Returns the value of the attribute as chunk. * * @return chunk_t pointing to the internal value */ - chunk_t (*get_value) (configuration_attribute_t *this); + chunk_t (*get_chunk) (configuration_attribute_t *this); + + /** + * Returns the 2 byte value of the attribute as u_int16. + * + * @return attribute value + */ + u_int16_t (*get_value) (configuration_attribute_t *this); /** * Destroys an configuration_attribute_t object. @@ -68,18 +68,30 @@ struct configuration_attribute_t { /** * Creates an empty configuration attribute. * - * @return created configuration attribute + * @param type CONFIGURATION_ATTRIBUTE or CONFIGURATION_ATTRIBUTE_V1 + * @return created configuration attribute */ -configuration_attribute_t *configuration_attribute_create(); +configuration_attribute_t *configuration_attribute_create(payload_type_t type); /** * Creates a configuration attribute with type and value. * - * @param type type of configuration attribute - * @param value value, gets cloned - * @return created configuration attribute + * @param type CONFIGURATION_ATTRIBUTE or CONFIGURATION_ATTRIBUTE_V1 + * @param attr_type type of configuration attribute + * @param chunk attribute value, gets cloned + * @return created configuration attribute + */ +configuration_attribute_t *configuration_attribute_create_chunk( + payload_type_t type, configuration_attribute_type_t attr_type, chunk_t chunk); + +/** + * Creates a IKEv1 configuration attribute with 2 bytes value (IKEv1 only). + * + * @param attr_type type of configuration attribute + * @param value attribute value, gets cloned + * @return created CONFIGURATION_ATTRIBUTE_V1 configuration attribute */ configuration_attribute_t *configuration_attribute_create_value( - configuration_attribute_type_t type, chunk_t value); + configuration_attribute_type_t attr_type, u_int16_t value); #endif /** CONFIGURATION_ATTRIBUTE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/cp_payload.c b/src/libcharon/encoding/payloads/cp_payload.c index 82e9e51b7..40f6ae48f 100644 --- a/src/libcharon/encoding/payloads/cp_payload.c +++ b/src/libcharon/encoding/payloads/cp_payload.c @@ -44,7 +44,7 @@ struct private_cp_payload_t { /** * Next payload type. */ - u_int8_t next_payload; + u_int8_t next_payload; /** * Critical flag. @@ -67,6 +67,11 @@ struct private_cp_payload_t { u_int16_t payload_length; /** + * Identifier field, IKEv1 only + */ + u_int16_t identifier; + + /** * List of attributes, as configuration_attribute_t */ linked_list_t *attributes; @@ -74,38 +79,40 @@ struct private_cp_payload_t { /** * Config Type. */ - u_int8_t type; + u_int8_t cfg_type; + + /** + * CONFIGURATION or CONFIGURATION_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a IKEv2-CP Payload - * - * The defined offsets are the positions in a object of type - * private_cp_payload_t. + * Encoding rules to for an IKEv2 configuration payload */ -encoding_rule_t cp_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, + { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_cp_payload_t, critical) }, + { FLAG, offsetof(private_cp_payload_t, critical) }, /* 7 Bit reserved bits */ - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) }, - { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, /* Length of the whole CP payload*/ - { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, - /* Proposals are stored in a proposal substructure, - offset points to a linked_list_t pointer */ - { U_INT_8, offsetof(private_cp_payload_t, type) }, + { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, + { U_INT_8, offsetof(private_cp_payload_t, cfg_type) }, /* 3 reserved bytes */ - { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, - { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[1])}, - { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[2])}, - { CONFIGURATION_ATTRIBUTES, offsetof(private_cp_payload_t, attributes) } + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[1])}, + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[2])}, + /* list of configuration attributes in a list */ + { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE, + offsetof(private_cp_payload_t, attributes) }, }; /* @@ -122,6 +129,47 @@ encoding_rule_t cp_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules to for an IKEv1 configuration payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_cp_payload_t, next_payload) }, + /* the critical bit */ + { FLAG, offsetof(private_cp_payload_t, critical) }, + /* 7 Bit reserved bits */ + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[0]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[1]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[2]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[3]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[4]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[5]) }, + { RESERVED_BIT, offsetof(private_cp_payload_t, reserved_bit[6]) }, + /* Length of the whole CP payload*/ + { PAYLOAD_LENGTH, offsetof(private_cp_payload_t, payload_length) }, + { U_INT_8, offsetof(private_cp_payload_t, cfg_type) }, + /* 1 reserved bytes */ + { RESERVED_BYTE, offsetof(private_cp_payload_t, reserved_byte[0])}, + { U_INT_16, offsetof(private_cp_payload_t, identifier)}, + /* list of configuration attributes in a list */ + { PAYLOAD_LIST + CONFIGURATION_ATTRIBUTE_V1, + offsetof(private_cp_payload_t, attributes) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! CFG Type ! RESERVED ! Identifier ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Configuration Attributes ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_cp_payload_t *this) { @@ -142,17 +190,28 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_cp_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_cp_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == CONFIGURATION) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_cp_payload_t *this) { - *rules = cp_payload_encodings; - *rule_count = countof(cp_payload_encodings); + return 8; } METHOD(payload_t, get_type, payload_type_t, private_cp_payload_t *this) { - return CONFIGURATION; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -175,7 +234,7 @@ static void compute_length(private_cp_payload_t *this) enumerator_t *enumerator; payload_t *attribute; - this->payload_length = CP_PAYLOAD_HEADER_LENGTH; + this->payload_length = get_header_length(this); enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attribute)) @@ -207,7 +266,18 @@ METHOD(cp_payload_t, add_attribute, void, METHOD(cp_payload_t, get_config_type, config_type_t, private_cp_payload_t *this) { - return this->type; + return this->cfg_type; +} + +METHOD(cp_payload_t, get_identifier, u_int16_t, + private_cp_payload_t *this) +{ + return this->identifier; +} +METHOD(cp_payload_t, set_identifier, void, + private_cp_payload_t *this, u_int16_t identifier) +{ + this->identifier = identifier; } METHOD2(payload_t, cp_payload_t, destroy, void, @@ -221,7 +291,7 @@ METHOD2(payload_t, cp_payload_t, destroy, void, /* * Described in header. */ -cp_payload_t *cp_payload_create_type(config_type_t type) +cp_payload_t *cp_payload_create_type(payload_type_t type, config_type_t cfg_type) { private_cp_payload_t *this; @@ -230,6 +300,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -239,11 +310,14 @@ cp_payload_t *cp_payload_create_type(config_type_t type) .create_attribute_enumerator = _create_attribute_enumerator, .add_attribute = _add_attribute, .get_type = _get_config_type, + .get_identifier = _get_identifier, + .set_identifier = _set_identifier, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = CP_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .attributes = linked_list_create(), + .cfg_type = cfg_type, .type = type, ); return &this->public; @@ -252,7 +326,7 @@ cp_payload_t *cp_payload_create_type(config_type_t type) /* * Described in header. */ -cp_payload_t *cp_payload_create() +cp_payload_t *cp_payload_create(payload_type_t type) { - return cp_payload_create_type(CFG_REQUEST); + return cp_payload_create_type(type, CFG_REQUEST); } diff --git a/src/libcharon/encoding/payloads/cp_payload.h b/src/libcharon/encoding/payloads/cp_payload.h index afae6091a..5eb1e06a7 100644 --- a/src/libcharon/encoding/payloads/cp_payload.h +++ b/src/libcharon/encoding/payloads/cp_payload.h @@ -31,11 +31,6 @@ typedef struct cp_payload_t cp_payload_t; #include <utils/enumerator.h> /** - * CP_PAYLOAD length in bytes without any proposal substructure. - */ -#define CP_PAYLOAD_HEADER_LENGTH 8 - -/** * Config Type of an Configuration Payload. */ enum config_type_t { @@ -51,9 +46,7 @@ enum config_type_t { extern enum_name_t *config_type_names; /** - * Class representing an IKEv2-CP Payload. - * - * The CP Payload format is described in RFC section 3.15. + * Class representing an IKEv2 configuration / IKEv1 attribute payload. */ struct cp_payload_t { @@ -85,6 +78,20 @@ struct cp_payload_t { config_type_t (*get_type) (cp_payload_t *this); /** + * Set the configuration payload identifier (IKEv1 only). + * + @param identifier identifier to set + */ + void (*set_identifier) (cp_payload_t *this, u_int16_t identifier); + + /** + * Get the configuration payload identifier (IKEv1 only). + * + * @return identifier + */ + u_int16_t (*get_identifier) (cp_payload_t *this); + + /** * Destroys an cp_payload_t object. */ void (*destroy) (cp_payload_t *this); @@ -93,16 +100,18 @@ struct cp_payload_t { /** * Creates an empty configuration payload * - * @return empty configuration payload + * @param type payload type, CONFIGURATION or CONFIGURATION_V1 + * @return empty configuration payload */ -cp_payload_t *cp_payload_create(); +cp_payload_t *cp_payload_create(payload_type_t type); /** * Creates an cp_payload_t with type and value * - * @param config_type type of configuration payload to create - * @return created configuration payload + * @param type payload type, CONFIGURATION or CONFIGURATION_V1 + * @param cfg_type type of configuration payload to create + * @return created configuration payload */ -cp_payload_t *cp_payload_create_type(config_type_t config_type); +cp_payload_t *cp_payload_create_type(payload_type_t type, config_type_t cfg_type); #endif /** CP_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index e6ee07d39..007411f37 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -24,9 +24,9 @@ typedef struct private_delete_payload_t private_delete_payload_t; /** * Private data of an delete_payload_t object. - * */ struct private_delete_payload_t { + /** * Public delete_payload_t interface. */ @@ -45,7 +45,7 @@ struct private_delete_payload_t { /** * reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. @@ -53,6 +53,11 @@ struct private_delete_payload_t { u_int16_t payload_length; /** + * IKEv1 Domain of Interpretation + */ + u_int32_t doi; + + /** * Protocol ID. */ u_int8_t protocol_id; @@ -71,19 +76,21 @@ struct private_delete_payload_t { * The contained SPI's. */ chunk_t spis; + + /** + * Payload type, DELETE or DELETE_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a DELETE payload - * - * The defined offsets are the positions in a object of type - * private_delete_payload_t. + * Encoding rules for an IKEv2 delete payload. */ -encoding_rule_t delete_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, + { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_delete_payload_t, critical) }, + { FLAG, offsetof(private_delete_payload_t, critical) }, /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) }, @@ -98,7 +105,47 @@ encoding_rule_t delete_payload_encodings[] = { { U_INT_8, offsetof(private_delete_payload_t, spi_size) }, { U_INT_16, offsetof(private_delete_payload_t, spi_count) }, /* some delete data bytes, length is defined in PAYLOAD_LENGTH */ - { SPIS, offsetof(private_delete_payload_t, spis) } + { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload !C! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Protocol ID ! SPI Size ! # of SPIs ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Security Parameter Index(es) (SPI) ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Encoding rules for an IKEv1 delete payload. + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_delete_payload_t, next_payload) }, + /* 8 Bit reserved bits */ + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_delete_payload_t, reserved[7]) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_delete_payload_t, payload_length) }, + /* Domain of interpretation */ + { U_INT_32, offsetof(private_delete_payload_t, doi) }, + { U_INT_8, offsetof(private_delete_payload_t, protocol_id) }, + { U_INT_8, offsetof(private_delete_payload_t, spi_size) }, + { U_INT_16, offsetof(private_delete_payload_t, spi_count) }, + /* some delete data bytes, length is defined in PAYLOAD_LENGTH */ + { CHUNK_DATA, offsetof(private_delete_payload_t, spis) }, }; /* @@ -107,6 +154,8 @@ encoding_rule_t delete_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Next Payload !C! RESERVED ! Payload Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! Protocol ID ! SPI Size ! # of SPIs ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! @@ -129,10 +178,19 @@ METHOD(payload_t, verify, status_t, break; case PROTO_IKE: case 0: - /* IKE deletion has no spi assigned! */ - if (this->spi_size != 0) - { - return FAILED; + if (this->type == DELETE) + { /* IKEv2 deletion has no spi assigned! */ + if (this->spi_size != 0) + { + return FAILED; + } + } + else + { /* IKEv1 uses the two concatenated ISAKMP cookies as SPI */ + if (this->spi_size != 16) + { + return FAILED; + } } break; default: @@ -145,17 +203,32 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_delete_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_delete_payload_t *this, encoding_rule_t **rules) { - *rules = delete_payload_encodings; - *rule_count = countof(delete_payload_encodings); + if (this->type == DELETE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_delete_payload_t *this) +{ + if (this->type == DELETE) + { + return 8; + } + return 12; } METHOD(payload_t, get_payload_type, payload_type_t, private_delete_payload_t *this) { - return DELETE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -198,6 +271,16 @@ METHOD(delete_payload_t, add_spi, void, } } +METHOD(delete_payload_t, set_ike_spi, void, + private_delete_payload_t *this, u_int64_t spi_i, u_int64_t spi_r) +{ + free(this->spis.ptr); + this->spis = chunk_cat("cc", chunk_from_thing(spi_i), + chunk_from_thing(spi_r)); + this->spi_count = 1; + this->payload_length = get_header_length(this) + this->spi_size; +} + /** * SPI enumerator implementation */ @@ -249,7 +332,8 @@ METHOD2(payload_t, delete_payload_t, destroy, void, /* * Described in header */ -delete_payload_t *delete_payload_create(protocol_id_t protocol_id) +delete_payload_t *delete_payload_create(payload_type_t type, + protocol_id_t protocol_id) { private_delete_payload_t *this; @@ -258,6 +342,7 @@ delete_payload_t *delete_payload_create(protocol_id_t protocol_id) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -266,13 +351,27 @@ delete_payload_t *delete_payload_create(protocol_id_t protocol_id) }, .get_protocol_id = _get_protocol_id, .add_spi = _add_spi, + .set_ike_spi = _set_ike_spi, .create_spi_enumerator = _create_spi_enumerator, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = DELETE_PAYLOAD_HEADER_LENGTH, .protocol_id = protocol_id, - .spi_size = protocol_id == PROTO_AH || protocol_id == PROTO_ESP ? 4 : 0, + .doi = IKEV1_DOI_IPSEC, + .type = type, ); + this->payload_length = get_header_length(this); + + if (protocol_id == PROTO_IKE) + { + if (type == DELETE_V1) + { + this->spi_size = 16; + } + } + else + { + this->spi_size = 4; + } return &this->public; } diff --git a/src/libcharon/encoding/payloads/delete_payload.h b/src/libcharon/encoding/payloads/delete_payload.h index 026829f97..afce1ecf1 100644 --- a/src/libcharon/encoding/payloads/delete_payload.h +++ b/src/libcharon/encoding/payloads/delete_payload.h @@ -29,14 +29,7 @@ typedef struct delete_payload_t delete_payload_t; #include <encoding/payloads/proposal_substructure.h> /** - * Length of a delete payload without the SPI in bytes. - */ -#define DELETE_PAYLOAD_HEADER_LENGTH 8 - -/** - * Class representing an IKEv2 DELETE payload. - * - * The DELETE payload format is described in RFC section 3.11. + * Class representing an IKEv1 or a IKEv2 DELETE payload. */ struct delete_payload_t { @@ -60,6 +53,14 @@ struct delete_payload_t { void (*add_spi) (delete_payload_t *this, u_int32_t spi); /** + * Set the IKE SPIs for an IKEv1 delete. + * + * @param spi_i initiator SPI + * @param spi_r responder SPI + */ + void (*set_ike_spi)(delete_payload_t *this, u_int64_t spi_i, u_int64_t spi_r); + + /** * Get an enumerator over the SPIs in network order. * * @return enumerator over SPIs, u_int32_t @@ -75,9 +76,11 @@ struct delete_payload_t { /** * Creates an empty delete_payload_t object. * + * @param type DELETE or DELETE_V1 * @param protocol_id protocol, such as AH|ESP * @return delete_payload_t object */ -delete_payload_t *delete_payload_create(protocol_id_t protocol_id); +delete_payload_t *delete_payload_create(payload_type_t type, + protocol_id_t protocol_id); #endif /** DELETE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/eap_payload.c b/src/libcharon/encoding/payloads/eap_payload.c index cacaef222..dd2e25795 100644 --- a/src/libcharon/encoding/payloads/eap_payload.c +++ b/src/libcharon/encoding/payloads/eap_payload.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -19,6 +20,8 @@ #include "eap_payload.h" #include <daemon.h> +#include <eap/eap.h> +#include <bio/bio_writer.h> typedef struct private_eap_payload_t private_eap_payload_t; @@ -65,7 +68,7 @@ struct private_eap_payload_t { * private_eap_payload_t. * */ -static encoding_rule_t eap_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_eap_payload_t, next_payload) }, /* the critical bit */ @@ -81,7 +84,7 @@ static encoding_rule_t eap_payload_encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_eap_payload_t, payload_length) }, /* chunt to data, starting at "code" */ - { EAP_DATA, offsetof(private_eap_payload_t, data) }, + { CHUNK_DATA, offsetof(private_eap_payload_t, data) }, }; /* @@ -143,11 +146,17 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_eap_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_eap_payload_t *this, encoding_rule_t **rules) { - *rules = eap_payload_encodings; - *rule_count = sizeof(eap_payload_encodings) / sizeof(encoding_rule_t); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_eap_payload_t *this) +{ + return 4; } METHOD(payload_t, get_payload_type, payload_type_t, @@ -210,28 +219,93 @@ METHOD(eap_payload_t, get_identifier, u_int8_t, return 0; } +/** + * Get the current type at the given offset into this->data. + * @return the new offset or 0 if failed + */ +static size_t extract_type(private_eap_payload_t *this, size_t offset, + eap_type_t *type, u_int32_t *vendor) +{ + if (this->data.len > offset) + { + *vendor = 0; + *type = this->data.ptr[offset]; + if (*type != EAP_EXPANDED) + { + return offset + 1; + } + if (this->data.len >= offset + 8) + { + *vendor = untoh32(this->data.ptr + offset) & 0x00FFFFFF; + *type = untoh32(this->data.ptr + offset + 4); + return offset + 8; + } + } + return 0; +} + METHOD(eap_payload_t, get_type, eap_type_t, private_eap_payload_t *this, u_int32_t *vendor) { eap_type_t type; *vendor = 0; - if (this->data.len > 4) + if (extract_type(this, 4, &type, vendor)) { - type = this->data.ptr[4]; - if (type != EAP_EXPANDED) - { - return type; - } - if (this->data.len >= 12) - { - *vendor = untoh32(this->data.ptr + 4) & 0x00FFFFFF; - return untoh32(this->data.ptr + 8); - } + return type; } return 0; } +/** + * Type enumerator + */ +typedef struct { + /** public interface */ + enumerator_t public; + /** payload */ + private_eap_payload_t *payload; + /** current offset in the data */ + size_t offset; +} type_enumerator_t; + +METHOD(enumerator_t, enumerate_types, bool, + type_enumerator_t *this, eap_type_t *type, u_int32_t *vendor) +{ + this->offset = extract_type(this->payload, this->offset, type, vendor); + return this->offset; +} + +METHOD(eap_payload_t, get_types, enumerator_t*, + private_eap_payload_t *this) +{ + type_enumerator_t *enumerator; + eap_type_t type; + u_int32_t vendor; + size_t offset; + + offset = extract_type(this, 4, &type, &vendor); + if (offset && type == EAP_NAK) + { + INIT(enumerator, + .public = { + .enumerate = (void*)_enumerate_types, + .destroy = (void*)free, + }, + .payload = this, + .offset = offset, + ); + return &enumerator->public; + } + return enumerator_create_empty(); +} + +METHOD(eap_payload_t, is_expanded, bool, + private_eap_payload_t *this) +{ + return this->data.len > 4 ? this->data.ptr[4] == EAP_EXPANDED : FALSE; +} + METHOD2(payload_t, eap_payload_t, destroy, void, private_eap_payload_t *this) { @@ -251,6 +325,7 @@ eap_payload_t *eap_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -262,10 +337,12 @@ eap_payload_t *eap_payload_create() .get_code = _get_code, .get_identifier = _get_identifier, .get_type = _get_type, + .get_types = _get_types, + .is_expanded = _is_expanded, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = EAP_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), ); return &this->public; } @@ -305,15 +382,81 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier) return eap_payload_create_data(data); } +/** + * Write the given type either expanded or not + */ +static void write_type(bio_writer_t *writer, eap_type_t type, u_int32_t vendor, + bool expanded) +{ + if (expanded) + { + writer->write_uint8(writer, EAP_EXPANDED); + writer->write_uint24(writer, vendor); + writer->write_uint32(writer, type); + } + else + { + writer->write_uint8(writer, type); + } +} + /* * Described in header */ -eap_payload_t *eap_payload_create_nak(u_int8_t identifier) +eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type, + u_int32_t vendor, bool expanded) { - chunk_t data; + enumerator_t *enumerator; + eap_type_t reg_type; + u_int32_t reg_vendor; + bio_writer_t *writer; + chunk_t length, data; + bool added_any = FALSE, found_vendor = FALSE; + eap_payload_t *payload; + + writer = bio_writer_create(12); + writer->write_uint8(writer, EAP_RESPONSE); + writer->write_uint8(writer, identifier); + length = writer->skip(writer, 2); + + write_type(writer, EAP_NAK, 0, expanded); + + enumerator = charon->eap->create_enumerator(charon->eap, EAP_PEER); + while (enumerator->enumerate(enumerator, ®_type, ®_vendor)) + { + if ((type && type != reg_type) || + (type && vendor && vendor != reg_vendor)) + { /* the preferred type is only sent if we actually find it */ + continue; + } + if (!reg_vendor || expanded) + { + write_type(writer, reg_type, reg_vendor, expanded); + added_any = TRUE; + } + else if (reg_vendor) + { /* found vendor specifc method, but this is not an expanded Nak */ + found_vendor = TRUE; + } + } + enumerator->destroy(enumerator); - data = chunk_from_chars(EAP_RESPONSE, identifier, 0, 0, EAP_NAK); - htoun16(data.ptr + 2, data.len); - return eap_payload_create_data(data); + if (found_vendor) + { /* request an expanded authentication type */ + write_type(writer, EAP_EXPANDED, 0, expanded); + added_any = TRUE; + } + if (!added_any) + { /* no methods added */ + write_type(writer, 0, 0, expanded); + } + + /* set length */ + data = writer->get_buf(writer); + htoun16(length.ptr, data.len); + + payload = eap_payload_create_data(data); + writer->destroy(writer); + return payload; } diff --git a/src/libcharon/encoding/payloads/eap_payload.h b/src/libcharon/encoding/payloads/eap_payload.h index 60d9c99d2..e8ed1c5e7 100644 --- a/src/libcharon/encoding/payloads/eap_payload.h +++ b/src/libcharon/encoding/payloads/eap_payload.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -25,13 +26,8 @@ typedef struct eap_payload_t eap_payload_t; #include <library.h> +#include <eap/eap.h> #include <encoding/payloads/payload.h> -#include <sa/authenticators/eap/eap_method.h> - -/** - * Length of a EAP payload without the EAP Message in bytes. - */ -#define EAP_PAYLOAD_HEADER_LENGTH 4 /** * Class representing an IKEv2 EAP payload. @@ -87,6 +83,21 @@ struct eap_payload_t { eap_type_t (*get_type) (eap_payload_t *this, u_int32_t *vendor); /** + * Enumerate the EAP method types contained in an EAP-Nak (i.e. get_type() + * returns EAP_NAK). + * + * @return enumerator over (eap_type_t type, u_int32_t vendor) + */ + enumerator_t* (*get_types) (eap_payload_t *this); + + /** + * Check if the EAP method type is encoded in the Expanded Type format. + * + * @return TRUE if in Expanded Type format + */ + bool (*is_expanded) (eap_payload_t *this); + + /** * Destroys an eap_payload_t object. */ void (*destroy) (eap_payload_t *this); @@ -131,8 +142,12 @@ eap_payload_t *eap_payload_create_code(eap_code_t code, u_int8_t identifier); * Creates an eap_payload_t EAP_RESPONSE containing an EAP_NAK. * * @param identifier EAP identifier to use in payload + * @param type preferred auth type, 0 to send all supported types + * @param vendor vendor identifier for auth type, 0 for default + * @param expanded TRUE to send an expanded Nak * @return eap_payload_t object */ -eap_payload_t *eap_payload_create_nak(u_int8_t identifier); +eap_payload_t *eap_payload_create_nak(u_int8_t identifier, eap_type_t type, + u_int32_t vendor, bool expanded); #endif /** EAP_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/encodings.c b/src/libcharon/encoding/payloads/encodings.c index 85caeda82..62de81120 100644 --- a/src/libcharon/encoding/payloads/encodings.c +++ b/src/libcharon/encoding/payloads/encodings.c @@ -29,30 +29,14 @@ ENUM(encoding_type_names, U_INT_4, ENCRYPTED_DATA, "HEADER_LENGTH", "SPI_SIZE", "SPI", - "KEY_EXCHANGE_DATA", - "NOTIFICATION_DATA", - "PROPOSALS", - "TRANSFORMS", - "TRANSFORM_ATTRIBUTES", - "CONFIGURATION_ATTRIBUTES", - "CONFIGURATION_ATTRIBUTE_VALUE", "ATTRIBUTE_FORMAT", "ATTRIBUTE_TYPE", "ATTRIBUTE_LENGTH_OR_VALUE", - "CONFIGURATION_ATTRIBUTE_LENGTH", + "ATTRIBUTE_LENGTH", "ATTRIBUTE_VALUE", - "TRAFFIC_SELECTORS", "TS_TYPE", "ADDRESS", - "NONCE_DATA", - "ID_DATA", - "AUTH_DATA", - "CERT_DATA", - "CERTREQ_DATA", - "EAP_DATA", - "SPIS", - "VID_DATA", - "UNKNOWN_DATA", + "CHUNK_DATA", "IKE_SPI", "ENCRYPTED_DATA", ); diff --git a/src/libcharon/encoding/payloads/encodings.h b/src/libcharon/encoding/payloads/encodings.h index 52af4a984..54830bc8c 100644 --- a/src/libcharon/encoding/payloads/encodings.h +++ b/src/libcharon/encoding/payloads/encodings.h @@ -187,87 +187,6 @@ enum encoding_type_t { SPI, /** - * Representating a Key Exchange Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - KEY_EXCHANGE_DATA, - - /** - * Representating a Notification field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - spi size - 8) bytes are read and written into the chunk pointing to. - */ - NOTIFICATION_DATA, - - /** - * Representating one or more proposal substructures. - * - * The offset points to a linked_list_t pointer. - * - * When generating the proposal_substructure_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed proposal_substructure_t objects have - * to be stored in the pointed linked_list. - */ - PROPOSALS, - - /** - * Representating one or more transform substructures. - * - * The offset points to a linked_list_t pointer. - * - * When generating the transform_substructure_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed transform_substructure_t objects have - * to be stored in the pointed linked_list. - */ - TRANSFORMS, - - /** - * Representating one or more Attributes of a transform substructure. - * - * The offset points to a linked_list_t pointer. - * - * When generating the transform_attribute_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed transform_attribute_t objects have - * to be stored in the pointed linked_list. - */ - TRANSFORM_ATTRIBUTES, - - /** - * Representating one or more Attributes of a configuration payload. - * - * The offset points to a linked_list_t pointer. - * - * When generating the configuration_attribute_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed configuration_attribute_t objects have - * to be stored in the pointed linked_list. - */ - CONFIGURATION_ATTRIBUTES, - - /** - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - CONFIGURATION_ATTRIBUTE_VALUE, - - /** * Representing a 1 Bit flag specifying the format of a transform attribute. * * When generation, the next bit is set to 1 if the associated value @@ -279,6 +198,7 @@ enum encoding_type_t { * is moved 1 bit forward afterwards. */ ATTRIBUTE_FORMAT, + /** * Representing a 15 Bit unsigned int value used as attribute type * in an attribute transform. @@ -321,7 +241,7 @@ enum encoding_type_t { * The value is written to the associated data struct. * The current read pointer is moved 16 bit forward afterwards. */ - CONFIGURATION_ATTRIBUTE_LENGTH, + ATTRIBUTE_LENGTH, /** * Depending on the field of type ATTRIBUTE_FORMAT @@ -336,19 +256,6 @@ enum encoding_type_t { ATTRIBUTE_VALUE, /** - * Representating one or more Traffic selectors of a TS payload. - * - * The offset points to a linked_list_t pointer. - * - * When generating the traffic_selector_substructure_t objects are stored - * in the pointed linked_list. - * - * When parsing the parsed traffic_selector_substructure_t objects have - * to be stored in the pointed linked_list. - */ - TRAFFIC_SELECTORS, - - /** * Representating a Traffic selector type field. * * When generating it must be changed from host to network order. @@ -375,94 +282,9 @@ enum encoding_type_t { ADDRESS, /** - * Representating a Nonce Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. + * Representing a variable length byte field. */ - NONCE_DATA, - - /** - * Representating a ID Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - ID_DATA, - - /** - * Representating a AUTH Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - AUTH_DATA, - - /** - * Representating a CERT Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to. - */ - CERT_DATA, - - /** - * Representating a CERTREQ Data field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 5) bytes are read and written into the chunk pointing to. - */ - CERTREQ_DATA, - - /** - * Representating an EAP message field. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - EAP_DATA, - - /** - * Representating the SPIS field in a DELETE payload. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 8) bytes are read and written into the chunk pointing to. - */ - SPIS, - - /** - * Representating the VID DATA field in a VENDOR ID payload. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - VID_DATA, - - /** - * Representating the DATA of an unknown payload. - * - * When generating the content of the chunkt pointing to - * is written. - * - * When parsing (Payload Length - 4) bytes are read and written into the chunk pointing to. - */ - UNKNOWN_DATA, + CHUNK_DATA, /** * Representating an IKE_SPI field in an IKEv2 Header. @@ -475,9 +297,20 @@ enum encoding_type_t { IKE_SPI, /** - * Representing the encrypted data body of a encryption payload. + * Representating an encrypted IKEv1 message. */ ENCRYPTED_DATA, + + /** + * Reprensenting a field containing a set of wrapped payloads. + * + * This type is not used directly, but as an offset to the wrapped payloads. + * The type of the wrapped payload is added to this encoding type. + * + * @note As payload types are added to this encoding type, it has + * to be the last in encoding_type_t. + */ + PAYLOAD_LIST = 1000 /* no comma, read above! */ }; /** diff --git a/src/libcharon/encoding/payloads/encryption_payload.c b/src/libcharon/encoding/payloads/encryption_payload.c index e7b8063b7..02e7b8bf3 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.c +++ b/src/libcharon/encoding/payloads/encryption_payload.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2010 revosec AG + * Copyright (C) 2011 Tobias Brunner * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -71,6 +72,11 @@ struct private_encryption_payload_t { * Contained payloads */ linked_list_t *payloads; + + /** + * Type of payload, ENCRYPTED or ENCRYPTED_V1 + */ + payload_type_t type; }; /** @@ -79,7 +85,7 @@ struct private_encryption_payload_t { * The defined offsets are the positions in a object of type * private_encryption_payload_t. */ -encoding_rule_t encryption_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_encryption_payload_t, next_payload) }, /* Critical and 7 reserved bits, all stored for reconstruction */ @@ -87,7 +93,7 @@ encoding_rule_t encryption_payload_encodings[] = { /* Length of the whole encryption payload*/ { PAYLOAD_LENGTH, offsetof(private_encryption_payload_t, payload_length) }, /* encrypted data, stored in a chunk. contains iv, data, padding */ - { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) }, + { CHUNK_DATA, offsetof(private_encryption_payload_t, encrypted) }, }; /* @@ -109,24 +115,59 @@ encoding_rule_t encryption_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules to parse or generate a complete encrypted IKEv1 message. + * + * The defined offsets are the positions in a object of type + * private_encryption_payload_t. + */ +static encoding_rule_t encodings_v1[] = { + /* encrypted data, stored in a chunk */ + { ENCRYPTED_DATA, offsetof(private_encryption_payload_t, encrypted) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Encrypted IKE Payloads ! + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! Padding (0-255 octets) ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_encryption_payload_t *this) { return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_encryption_payload_t *this, encoding_rule_t **rules, - size_t *count) +METHOD(payload_t, get_encoding_rules, int, + private_encryption_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == ENCRYPTED) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_encryption_payload_t *this) { - *rules = encryption_payload_encodings; - *count = countof(encryption_payload_encodings); + if (this->type == ENCRYPTED) + { + return 4; + } + return 0; } METHOD(payload_t, get_type, payload_type_t, private_encryption_payload_t *this) { - return ENCRYPTED; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -138,7 +179,8 @@ METHOD(payload_t, get_next_type, payload_type_t, METHOD(payload_t, set_next_type, void, private_encryption_payload_t *this, payload_type_t type) { - /* the next payload is set during add */ + /* the next payload is set during add, still allow this for IKEv1 */ + this->next_payload = type; } /** @@ -174,7 +216,7 @@ static void compute_length(private_encryption_payload_t *this) length += this->aead->get_icv_size(this->aead); } } - length += ENCRYPTION_PAYLOAD_HEADER_LENGTH; + length += get_header_length(this); this->payload_length = length; } @@ -266,7 +308,7 @@ static chunk_t append_header(private_encryption_payload_t *this, chunk_t assoc) return chunk_cat("cc", assoc, chunk_from_thing(header)); } -METHOD(encryption_payload_t, encrypt, bool, +METHOD(encryption_payload_t, encrypt, status_t, private_encryption_payload_t *this, chunk_t assoc) { chunk_t iv, plain, padding, icv, crypt; @@ -277,14 +319,14 @@ METHOD(encryption_payload_t, encrypt, bool, if (this->aead == NULL) { DBG1(DBG_ENC, "encrypting encryption payload failed, transform missing"); - return FALSE; + return INVALID_STATE; } rng = lib->crypto->create_rng(lib->crypto, RNG_WEAK); if (!rng) { DBG1(DBG_ENC, "encrypting encryption payload failed, no RNG found"); - return FALSE; + return NOT_SUPPORTED; } assoc = append_header(this, assoc); @@ -314,8 +356,14 @@ METHOD(encryption_payload_t, encrypt, bool, crypt = chunk_create(plain.ptr, plain.len + padding.len); generator->destroy(generator); - rng->get_bytes(rng, iv.len, iv.ptr); - rng->get_bytes(rng, padding.len - 1, padding.ptr); + if (!rng->get_bytes(rng, iv.len, iv.ptr) || + !rng->get_bytes(rng, padding.len - 1, padding.ptr)) + { + DBG1(DBG_ENC, "encrypting encryption payload failed, no IV or padding"); + rng->destroy(rng); + free(assoc.ptr); + return FAILED; + } padding.ptr[padding.len - 1] = padding.len - 1; rng->destroy(rng); @@ -325,14 +373,60 @@ METHOD(encryption_payload_t, encrypt, bool, DBG3(DBG_ENC, "padding %B", &padding); DBG3(DBG_ENC, "assoc %B", &assoc); - this->aead->encrypt(this->aead, crypt, assoc, iv, NULL); + if (!this->aead->encrypt(this->aead, crypt, assoc, iv, NULL)) + { + free(assoc.ptr); + return FAILED; + } DBG3(DBG_ENC, "encrypted %B", &crypt); DBG3(DBG_ENC, "ICV %B", &icv); free(assoc.ptr); - return TRUE; + return SUCCESS; +} + +METHOD(encryption_payload_t, encrypt_v1, status_t, + private_encryption_payload_t *this, chunk_t iv) +{ + generator_t *generator; + chunk_t plain, padding; + size_t bs; + + if (this->aead == NULL) + { + DBG1(DBG_ENC, "encryption failed, transform missing"); + return INVALID_STATE; + } + + generator = generator_create(); + plain = generate(this, generator); + bs = this->aead->get_block_size(this->aead); + padding.len = bs - (plain.len % bs); + + /* prepare data to encrypt: + * | plain | padding | */ + free(this->encrypted.ptr); + this->encrypted = chunk_alloc(plain.len + padding.len); + memcpy(this->encrypted.ptr, plain.ptr, plain.len); + plain.ptr = this->encrypted.ptr; + padding.ptr = plain.ptr + plain.len; + memset(padding.ptr, 0, padding.len); + generator->destroy(generator); + + DBG3(DBG_ENC, "encrypting payloads:"); + DBG3(DBG_ENC, "plain %B", &plain); + DBG3(DBG_ENC, "padding %B", &padding); + + if (!this->aead->encrypt(this->aead, this->encrypted, chunk_empty, iv, NULL)) + { + return FAILED; + } + + DBG3(DBG_ENC, "encrypted %B", &this->encrypted); + + return SUCCESS; } /** @@ -349,6 +443,13 @@ static status_t parse(private_encryption_payload_t *this, chunk_t plain) { payload_t *payload; + if (plain.len < 4 || untoh16(plain.ptr + 2) > plain.len) + { + DBG1(DBG_ENC, "invalid %N payload length, decryption failed?", + payload_type_names, type); + parser->destroy(parser); + return PARSE_ERROR; + } if (parser->parse_payload(parser, type, &payload) != SUCCESS) { parser->destroy(parser); @@ -438,6 +539,36 @@ METHOD(encryption_payload_t, decrypt, status_t, return parse(this, plain); } +METHOD(encryption_payload_t, decrypt_v1, status_t, + private_encryption_payload_t *this, chunk_t iv) +{ + if (this->aead == NULL) + { + DBG1(DBG_ENC, "decryption failed, transform missing"); + return INVALID_STATE; + } + + /* data must be a multiple of block size */ + if (iv.len != this->aead->get_block_size(this->aead) || + this->encrypted.len < iv.len || this->encrypted.len % iv.len) + { + DBG1(DBG_ENC, "decryption failed, invalid length"); + return FAILED; + } + + DBG3(DBG_ENC, "decrypting payloads:"); + DBG3(DBG_ENC, "encrypted %B", &this->encrypted); + + if (!this->aead->decrypt(this->aead, this->encrypted, chunk_empty, iv, NULL)) + { + return FAILED; + } + + DBG3(DBG_ENC, "plain %B", &this->encrypted); + + return parse(this, this->encrypted); +} + METHOD(encryption_payload_t, set_transform, void, private_encryption_payload_t *this, aead_t* aead) { @@ -455,7 +586,7 @@ METHOD2(payload_t, encryption_payload_t, destroy, void, /* * Described in header */ -encryption_payload_t *encryption_payload_create() +encryption_payload_t *encryption_payload_create(payload_type_t type) { private_encryption_payload_t *this; @@ -464,6 +595,7 @@ encryption_payload_t *encryption_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -479,9 +611,16 @@ encryption_payload_t *encryption_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = ENCRYPTION_PAYLOAD_HEADER_LENGTH, .payloads = linked_list_create(), + .type = type, ); + this->payload_length = get_header_length(this); + + if (type == ENCRYPTED_V1) + { + this->public.encrypt = _encrypt_v1; + this->public.decrypt = _decrypt_v1; + } return &this->public; } diff --git a/src/libcharon/encoding/payloads/encryption_payload.h b/src/libcharon/encoding/payloads/encryption_payload.h index e99c42fb7..5c6069339 100644 --- a/src/libcharon/encoding/payloads/encryption_payload.h +++ b/src/libcharon/encoding/payloads/encryption_payload.h @@ -30,11 +30,6 @@ typedef struct encryption_payload_t encryption_payload_t; #include <encoding/payloads/payload.h> /** - * Encrpytion payload length in bytes without IV and following data. - */ -#define ENCRYPTION_PAYLOAD_HEADER_LENGTH 4 - -/** * The encryption payload as described in RFC section 3.14. */ struct encryption_payload_t { @@ -77,14 +72,18 @@ struct encryption_payload_t { * Generate, encrypt and sign contained payloads. * * @param assoc associated data - * @return TRUE if encrypted + * @return + * - SUCCESS if encryption successful + * - FAILED if encryption failed + * - INVALID_STATE if aead not supplied, but needed */ - bool (*encrypt) (encryption_payload_t *this, chunk_t assoc); + status_t (*encrypt) (encryption_payload_t *this, chunk_t assoc); /** * Decrypt, verify and parse contained payloads. * * @param assoc associated data + * @return * - SUCCESS if parsing successful * - PARSE_ERROR if sub-payload parsing failed * - VERIFY_ERROR if sub-payload verification failed @@ -102,8 +101,9 @@ struct encryption_payload_t { /** * Creates an empty encryption_payload_t object. * + * @param type ENCRYPTED or ENCRYPTED_V1 * @return encryption_payload_t object */ -encryption_payload_t *encryption_payload_create(void); +encryption_payload_t *encryption_payload_create(payload_type_t type); #endif /** ENCRYPTION_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/endpoint_notify.c b/src/libcharon/encoding/payloads/endpoint_notify.c index 1ead0a052..25fb42acd 100644 --- a/src/libcharon/encoding/payloads/endpoint_notify.c +++ b/src/libcharon/encoding/payloads/endpoint_notify.c @@ -227,7 +227,7 @@ METHOD(endpoint_notify_t, build_notify, notify_payload_t*, chunk_t data; notify_payload_t *notify; - notify = notify_payload_create(); + notify = notify_payload_create(NOTIFY); notify->set_notify_type(notify, ME_ENDPOINT); data = build_notification_data(this); notify->set_notification_data(notify, data); diff --git a/src/libcharon/encoding/payloads/hash_payload.c b/src/libcharon/encoding/payloads/hash_payload.c new file mode 100644 index 000000000..0cf63ba67 --- /dev/null +++ b/src/libcharon/encoding/payloads/hash_payload.c @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <stddef.h> + +#include "hash_payload.h" + +#include <encoding/payloads/encodings.h> + +typedef struct private_hash_payload_t private_hash_payload_t; + +/** + * Private data of an hash_payload_t object. + */ +struct private_hash_payload_t { + + /** + * Public hash_payload_t interface. + */ + hash_payload_t public; + + /** + * Next payload type. + */ + u_int8_t next_payload; + + /** + * Reserved byte + */ + u_int8_t reserved; + + /** + * Length of this payload. + */ + u_int16_t payload_length; + + /** + * The contained hash value. + */ + chunk_t hash; + + /** + * either HASH_V1 or NAT_D_V1 + */ + payload_type_t type; +}; + +/** + * Encoding rules for an IKEv1 hash payload + */ +static encoding_rule_t encodings[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_hash_payload_t, next_payload) }, + { RESERVED_BYTE, offsetof(private_hash_payload_t, reserved) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_hash_payload_t, payload_length) }, + /* Hash Data is from variable size */ + { CHUNK_DATA, offsetof(private_hash_payload_t, hash) }, +}; + +/* + 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 ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Hash Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +METHOD(payload_t, verify, status_t, + private_hash_payload_t *this) +{ + return SUCCESS; +} + +METHOD(payload_t, get_encoding_rules, int, + private_hash_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_hash_payload_t *this) +{ + return 4; +} + +METHOD(payload_t, get_type, payload_type_t, + private_hash_payload_t *this) +{ + return this->type; +} + +METHOD(payload_t, get_next_type, payload_type_t, + private_hash_payload_t *this) +{ + return this->next_payload; +} + +METHOD(payload_t, set_next_type, void, + private_hash_payload_t *this, payload_type_t type) +{ + this->next_payload = type; +} + +METHOD(payload_t, get_length, size_t, + private_hash_payload_t *this) +{ + return this->payload_length; +} + +METHOD(hash_payload_t, set_hash, void, + private_hash_payload_t *this, chunk_t hash) +{ + free(this->hash.ptr); + this->hash = chunk_clone(hash); + this->payload_length = get_header_length(this) + hash.len; +} + +METHOD(hash_payload_t, get_hash, chunk_t, + private_hash_payload_t *this) +{ + return this->hash; +} + +METHOD2(payload_t, hash_payload_t, destroy, void, + private_hash_payload_t *this) +{ + free(this->hash.ptr); + free(this); +} + +/* + * Described in header + */ +hash_payload_t *hash_payload_create(payload_type_t type) +{ + private_hash_payload_t *this; + + INIT(this, + .public = { + .payload_interface = { + .verify = _verify, + .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, + .get_length = _get_length, + .get_next_type = _get_next_type, + .set_next_type = _set_next_type, + .get_type = _get_type, + .destroy = _destroy, + }, + .set_hash = _set_hash, + .get_hash = _get_hash, + .destroy = _destroy, + }, + .next_payload = NO_PAYLOAD, + .payload_length = get_header_length(this), + .type = type, + ); + return &this->public; +} diff --git a/src/libcharon/encoding/payloads/hash_payload.h b/src/libcharon/encoding/payloads/hash_payload.h new file mode 100644 index 000000000..cfe28460c --- /dev/null +++ b/src/libcharon/encoding/payloads/hash_payload.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Martin Willi + * Copyright (C) 2011 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup hash_payload hash_payload + * @{ @ingroup payloads + */ + +#ifndef HASH_PAYLOAD_H_ +#define HASH_PAYLOAD_H_ + +typedef struct hash_payload_t hash_payload_t; + +#include <library.h> +#include <encoding/payloads/payload.h> + +/** + * Object representing an IKEv1 hash payload. + */ +struct hash_payload_t { + + /** + * The payload_t interface. + */ + payload_t payload_interface; + + /** + * Set the hash value. + * + * @param hash chunk containing the hash, will be cloned + */ + void (*set_hash) (hash_payload_t *this, chunk_t hash); + + /** + * Get the hash value. + * + * @return chunkt to internal hash data + */ + chunk_t (*get_hash) (hash_payload_t *this); + + /** + * Destroys an hash_payload_t object. + */ + void (*destroy) (hash_payload_t *this); +}; + +/** + * Creates an empty hash_payload_t object. + * + * @param type either HASH_V1 or NAT_D_V1 + * @return hash_payload_t object + */ +hash_payload_t *hash_payload_create(payload_type_t type); + +#endif /** HASH_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index 3befadfe2..02b07d691 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -1,9 +1,8 @@ /* - * Copyright (C) 2005-2010 Martin Willi + * Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2010 revosec AG - * Copyright (C) 2007 Tobias Brunner + * Copyright (C) 2007-2011 Tobias Brunner * Copyright (C) 2005 Jan Hutter - * * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -28,20 +27,15 @@ typedef struct private_id_payload_t private_id_payload_t; /** * Private data of an id_payload_t object. - * */ struct private_id_payload_t { + /** * Public id_payload_t interface. */ id_payload_t public; /** - * one of ID_INITIATOR, ID_RESPONDER - */ - payload_type_t payload_type; - - /** * Next payload type. */ u_int8_t next_payload; @@ -75,19 +69,31 @@ struct private_id_payload_t { * The contained id data value. */ chunk_t id_data; + + /** + * Tunneled protocol ID for IKEv1 quick modes. + */ + u_int8_t protocol_id; + + /** + * Tunneled port for IKEv1 quick modes. + */ + u_int16_t port; + + /** + * one of ID_INITIATOR, ID_RESPONDER, IDv1 and NAT_OA_V1 + */ + payload_type_t type; }; /** - * Encoding rules to parse or generate a ID payload - * - * The defined offsets are the positions in a object of type - * private_id_payload_t. + * Encoding rules for an IKEv2 ID payload */ -encoding_rule_t id_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_id_payload_t, next_payload) }, + { U_INT_8, offsetof(private_id_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_id_payload_t, critical) }, + { FLAG, offsetof(private_id_payload_t, critical) }, /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[0]) }, { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[1]) }, @@ -97,7 +103,7 @@ encoding_rule_t id_payload_encodings[] = { { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[5]) }, { RESERVED_BIT, offsetof(private_id_payload_t, reserved_bit[6]) }, /* Length of the whole payload*/ - { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) }, + { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) }, /* 1 Byte ID type*/ { U_INT_8, offsetof(private_id_payload_t, id_type) }, /* 3 reserved bytes */ @@ -105,7 +111,7 @@ encoding_rule_t id_payload_encodings[] = { { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[1])}, { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[2])}, /* some id data bytes, length is defined in PAYLOAD_LENGTH */ - { ID_DATA, offsetof(private_id_payload_t, id_data) } + { CHUNK_DATA, offsetof(private_id_payload_t, id_data) }, }; /* @@ -122,29 +128,92 @@ encoding_rule_t id_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for an IKEv1 ID payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_id_payload_t, next_payload) }, + /* Reserved Byte is skipped */ + { RESERVED_BYTE, offsetof(private_id_payload_t, reserved_byte[0])}, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_id_payload_t, payload_length) }, + /* 1 Byte ID type*/ + { U_INT_8, offsetof(private_id_payload_t, id_type) }, + { U_INT_8, offsetof(private_id_payload_t, protocol_id) }, + { U_INT_16, offsetof(private_id_payload_t, port) }, + /* some id data bytes, length is defined in PAYLOAD_LENGTH */ + { CHUNK_DATA, offsetof(private_id_payload_t, id_data) }, +}; + +/* + 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Next Payload ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ID Type ! Protocol ID ! Port | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Identification Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_id_payload_t *this) { - if (this->id_type == 0 || this->id_type == 4) + bool bad_length = FALSE; + + if (this->type == NAT_OA_V1 && + this->id_type != ID_IPV4_ADDR && this->id_type != ID_IPV6_ADDR) + { + DBG1(DBG_ENC, "invalid ID type %N for %N payload", id_type_names, + this->id_type, payload_type_short_names, this->type); + return FAILED; + } + switch (this->id_type) + { + case ID_IPV4_ADDR_RANGE: + case ID_IPV4_ADDR_SUBNET: + bad_length = this->id_data.len != 8; + break; + case ID_IPV6_ADDR_RANGE: + case ID_IPV6_ADDR_SUBNET: + bad_length = this->id_data.len != 32; + break; + } + if (bad_length) { - /* reserved IDs */ - DBG1(DBG_ENC, "received ID with reserved type %d", this->id_type); + DBG1(DBG_ENC, "invalid %N length (%d bytes)", + id_type_names, this->id_type, this->id_data.len); return FAILED; } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_id_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_id_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == ID_V1 || this->type == NAT_OA_V1) + { + *rules = encodings_v1; + return countof(encodings_v1); + } + *rules = encodings_v2; + return countof(encodings_v2); +} + +METHOD(payload_t, get_header_length, int, + private_id_payload_t *this) { - *rules = id_payload_encodings; - *rule_count = countof(id_payload_encodings); + return 8; } METHOD(payload_t, get_type, payload_type_t, private_id_payload_t *this) { - return this->payload_type; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -171,6 +240,102 @@ METHOD(id_payload_t, get_identification, identification_t*, return identification_create_from_encoding(this->id_type, this->id_data); } +/** + * Create a traffic selector from an range ID + */ +static traffic_selector_t *get_ts_from_range(private_id_payload_t *this, + ts_type_t type) +{ + return traffic_selector_create_from_bytes(this->protocol_id, type, + chunk_create(this->id_data.ptr, this->id_data.len / 2), this->port, + chunk_skip(this->id_data, this->id_data.len / 2), this->port ?: 65535); +} + +/** + * Create a traffic selector from an subnet ID + */ +static traffic_selector_t *get_ts_from_subnet(private_id_payload_t *this, + ts_type_t type) +{ + chunk_t net, netmask; + int i; + + net = chunk_create(this->id_data.ptr, this->id_data.len / 2); + netmask = chunk_skip(this->id_data, this->id_data.len / 2); + for (i = 0; i < net.len; i++) + { + netmask.ptr[i] = (netmask.ptr[i] ^ 0xFF) | net.ptr[i]; + } + return traffic_selector_create_from_bytes(this->protocol_id, type, + net, this->port, netmask, this->port ?: 65535); +} + +/** + * Create a traffic selector from an IP ID + */ +static traffic_selector_t *get_ts_from_ip(private_id_payload_t *this, + ts_type_t type) +{ + return traffic_selector_create_from_bytes(this->protocol_id, type, + this->id_data, this->port, this->id_data, this->port ?: 65535); +} + +METHOD(id_payload_t, get_ts, traffic_selector_t*, + private_id_payload_t *this) +{ + switch (this->id_type) + { + case ID_IPV4_ADDR_SUBNET: + if (this->id_data.len == 8) + { + return get_ts_from_subnet(this, TS_IPV4_ADDR_RANGE); + } + break; + case ID_IPV6_ADDR_SUBNET: + if (this->id_data.len == 32) + { + return get_ts_from_subnet(this, TS_IPV6_ADDR_RANGE); + } + break; + case ID_IPV4_ADDR_RANGE: + if (this->id_data.len == 8) + { + return get_ts_from_range(this, TS_IPV4_ADDR_RANGE); + } + break; + case ID_IPV6_ADDR_RANGE: + if (this->id_data.len == 32) + { + return get_ts_from_range(this, TS_IPV6_ADDR_RANGE); + } + break; + case ID_IPV4_ADDR: + if (this->id_data.len == 4) + { + return get_ts_from_ip(this, TS_IPV4_ADDR_RANGE); + } + break; + case ID_IPV6_ADDR: + if (this->id_data.len == 16) + { + return get_ts_from_ip(this, TS_IPV6_ADDR_RANGE); + } + break; + default: + break; + } + return NULL; +} + +METHOD(id_payload_t, get_encoded, chunk_t, + private_id_payload_t *this) +{ + u_int16_t port = htons(this->port); + return chunk_cat("cccc", chunk_from_thing(this->id_type), + chunk_from_thing(this->protocol_id), + chunk_from_thing(port), this->id_data); +} + METHOD2(payload_t, id_payload_t, destroy, void, private_id_payload_t *this) { @@ -181,7 +346,7 @@ METHOD2(payload_t, id_payload_t, destroy, void, /* * Described in header. */ -id_payload_t *id_payload_create(payload_type_t payload_type) +id_payload_t *id_payload_create(payload_type_t type) { private_id_payload_t *this; @@ -190,6 +355,7 @@ id_payload_t *id_payload_create(payload_type_t payload_type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -197,11 +363,13 @@ id_payload_t *id_payload_create(payload_type_t payload_type) .destroy = _destroy, }, .get_identification = _get_identification, + .get_encoded = _get_encoded, + .get_ts = _get_ts, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = ID_PAYLOAD_HEADER_LENGTH, - .payload_type = payload_type, + .payload_length = get_header_length(this), + .type = type, ); return &this->public; } @@ -209,15 +377,89 @@ id_payload_t *id_payload_create(payload_type_t payload_type) /* * Described in header. */ -id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, +id_payload_t *id_payload_create_from_identification(payload_type_t type, identification_t *id) { private_id_payload_t *this; - this = (private_id_payload_t*)id_payload_create(payload_type); + this = (private_id_payload_t*)id_payload_create(type); this->id_data = chunk_clone(id->get_encoding(id)); this->id_type = id->get_type(id); this->payload_length += this->id_data.len; return &this->public; } + +/* + * Described in header. + */ +id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts) +{ + private_id_payload_t *this; + u_int8_t mask; + host_t *net; + + this = (private_id_payload_t*)id_payload_create(ID_V1); + + if (ts->is_host(ts, NULL)) + { + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) + { + this->id_type = ID_IPV4_ADDR; + } + else + { + this->id_type = ID_IPV6_ADDR; + } + this->id_data = chunk_clone(ts->get_from_address(ts)); + } + else if (ts->to_subnet(ts, &net, &mask)) + { + u_int8_t netmask[16], len, byte; + + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) + { + this->id_type = ID_IPV4_ADDR_SUBNET; + len = 4; + } + else + { + this->id_type = ID_IPV6_ADDR_SUBNET; + len = 16; + } + memset(netmask, 0, sizeof(netmask)); + for (byte = 0; byte < sizeof(netmask); byte++) + { + if (mask < 8) + { + netmask[byte] = 0xFF << (8 - mask); + break; + } + netmask[byte] = 0xFF; + mask -= 8; + } + this->id_data = chunk_cat("cc", net->get_address(net), + chunk_create(netmask, len)); + net->destroy(net); + } + else + { + if (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) + { + this->id_type = ID_IPV4_ADDR_RANGE; + } + else + { + this->id_type = ID_IPV6_ADDR_RANGE; + } + this->id_data = chunk_cat("cc", + ts->get_from_address(ts), ts->get_to_address(ts)); + net->destroy(net); + } + this->port = ts->get_from_port(ts); + this->protocol_id = ts->get_protocol(ts); + this->payload_length += this->id_data.len; + + return &this->public; +} + diff --git a/src/libcharon/encoding/payloads/id_payload.h b/src/libcharon/encoding/payloads/id_payload.h index 99831f85f..9a6249429 100644 --- a/src/libcharon/encoding/payloads/id_payload.h +++ b/src/libcharon/encoding/payloads/id_payload.h @@ -28,16 +28,10 @@ typedef struct id_payload_t id_payload_t; #include <library.h> #include <utils/identification.h> #include <encoding/payloads/payload.h> +#include <selectors/traffic_selector.h> /** - * Length of a id payload without the data in bytes. - */ -#define ID_PAYLOAD_HEADER_LENGTH 8 - -/** - * Object representing an IKEv2 ID payload. - * - * The ID payload format is described in RFC section 3.5. + * Object representing an IKEv1 or an IKEv2 ID payload. */ struct id_payload_t { @@ -54,6 +48,20 @@ struct id_payload_t { identification_t *(*get_identification) (id_payload_t *this); /** + * Creates a traffic selector form a ID_ADDR_SUBNET/RANGE identity. + * + * @return traffic selector, NULL on failure + */ + traffic_selector_t* (*get_ts)(id_payload_t *this); + + /** + * Get encoded payload without fixed payload header (used for IKEv1). + * + * @return encoded payload (gets allocated) + */ + chunk_t (*get_encoded)(id_payload_t *this); + + /** * Destroys an id_payload_t object. */ void (*destroy) (id_payload_t *this); @@ -62,19 +70,27 @@ struct id_payload_t { /** * Creates an empty id_payload_t object. * - * @param payload_type one of ID_INITIATOR, ID_RESPONDER - * @return id_payload_t object + * @param type one of ID_INITIATOR, ID_RESPONDER, ID_V1 and NAT_OA_V1 + * @return id_payload_t object */ -id_payload_t *id_payload_create(payload_type_t payload_type); +id_payload_t *id_payload_create(payload_type_t type); /** * Creates an id_payload_t from an existing identification_t object. * - * @param payload_type one of ID_INITIATOR, ID_RESPONDER - * @param identification identification_t object - * @return id_payload_t object + * @param type one of ID_INITIATOR, ID_RESPONDER, ID_V1 and NAT_OA_V1 + * @param id identification_t object + * @return id_payload_t object + */ +id_payload_t *id_payload_create_from_identification(payload_type_t type, + identification_t *id); + +/** + * Create an IKEv1 ID_ADDR_SUBNET/RANGE identity from a traffic selector. + * + * @param ts traffic selector + * @return ID_V1 id_paylad_t object. */ -id_payload_t *id_payload_create_from_identification(payload_type_t payload_type, - identification_t *identification); +id_payload_t *id_payload_create_from_ts(traffic_selector_t *ts); #endif /** ID_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/ike_header.c b/src/libcharon/encoding/payloads/ike_header.c index 24d22f3a1..58b624192 100644 --- a/src/libcharon/encoding/payloads/ike_header.c +++ b/src/libcharon/encoding/payloads/ike_header.c @@ -81,12 +81,27 @@ struct private_ike_header_t { * TRUE, if this is a response, FALSE if its a Request. */ bool response; + + /** + * TRUE, if the packet is encrypted (IKEv1). + */ + bool encryption; + + /** + * TRUE, if the commit flag is set (IKEv1). + */ + bool commit; + + /** + * TRUE, if the auth only flag is set (IKEv1). + */ + bool authonly; } flags; /** * Reserved bits of IKE header */ - bool reserved[5]; + bool reserved[2]; /** * Associated Message-ID. @@ -99,9 +114,15 @@ struct private_ike_header_t { u_int32_t length; }; -ENUM_BEGIN(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, EXCHANGE_TYPE_UNDEFINED, - "EXCHANGE_TYPE_UNDEFINED"); -ENUM_NEXT(exchange_type_names, IKE_SA_INIT, IKE_SESSION_RESUME, EXCHANGE_TYPE_UNDEFINED, +ENUM_BEGIN(exchange_type_names, ID_PROT, TRANSACTION, + "ID_PROT", + "AUTH_ONLY", + "AGGRESSIVE", + "INFORMATIONAL_V1", + "TRANSACTION"); +ENUM_NEXT(exchange_type_names, QUICK_MODE, IKE_SESSION_RESUME, TRANSACTION, + "QUICK_MODE", + "NEW_GROUP_MODE", "IKE_SA_INIT", "IKE_AUTH", "CREATE_CHILD_SA", @@ -110,18 +131,23 @@ ENUM_NEXT(exchange_type_names, IKE_SA_INIT, IKE_SESSION_RESUME, EXCHANGE_TYPE_UN #ifdef ME ENUM_NEXT(exchange_type_names, ME_CONNECT, ME_CONNECT, IKE_SESSION_RESUME, "ME_CONNECT"); -ENUM_END(exchange_type_names, ME_CONNECT); +ENUM_NEXT(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, + EXCHANGE_TYPE_UNDEFINED, ME_CONNECT, + "EXCHANGE_TYPE_UNDEFINED"); #else -ENUM_END(exchange_type_names, IKE_SESSION_RESUME); +ENUM_NEXT(exchange_type_names, EXCHANGE_TYPE_UNDEFINED, + EXCHANGE_TYPE_UNDEFINED, IKE_SESSION_RESUME, + "EXCHANGE_TYPE_UNDEFINED"); #endif /* ME */ +ENUM_END(exchange_type_names, EXCHANGE_TYPE_UNDEFINED); /** - * Encoding rules to parse or generate a IKEv2-Header. + * Encoding rules to parse or generate a IKE-Header. * * The defined offsets are the positions in a object of type * ike_header_t. */ -encoding_rule_t ike_header_encodings[] = { +static encoding_rule_t 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 */ @@ -137,22 +163,20 @@ encoding_rule_t ike_header_encodings[] = { /* 2 Bit reserved bits */ { RESERVED_BIT, offsetof(private_ike_header_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_ike_header_t, reserved[1]) }, - /* 3 Bit flags, stored in the fields response, version and initiator */ + /* 6 flags */ { 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 */ - { RESERVED_BIT, offsetof(private_ike_header_t, reserved[2]) }, - { RESERVED_BIT, offsetof(private_ike_header_t, reserved[3]) }, - { RESERVED_BIT, offsetof(private_ike_header_t, reserved[4]) }, + { FLAG, offsetof(private_ike_header_t, flags.authonly) }, + { FLAG, offsetof(private_ike_header_t, flags.commit) }, + { FLAG, offsetof(private_ike_header_t, flags.encryption)}, /* 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) }, + { HEADER_LENGTH, offsetof(private_ike_header_t, length) } }; - -/* 1 2 3 +/* 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 ! @@ -172,35 +196,67 @@ encoding_rule_t ike_header_encodings[] = { METHOD(payload_t, verify, status_t, private_ike_header_t *this) { - if ((this->exchange_type < IKE_SA_INIT) || - ((this->exchange_type > INFORMATIONAL) + switch (this->exchange_type) + { + case ID_PROT: + case AGGRESSIVE: + if (this->message_id != 0) + { + return FAILED; + } + /* fall */ + case AUTH_ONLY: + case INFORMATIONAL_V1: + case TRANSACTION: + case QUICK_MODE: + case NEW_GROUP_MODE: + if (this->maj_version != IKEV1_MAJOR_VERSION) + { + return FAILED; + } + break; + case IKE_SA_INIT: + case IKE_AUTH: + case CREATE_CHILD_SA: + case INFORMATIONAL: + case IKE_SESSION_RESUME: #ifdef ME - && (this->exchange_type != ME_CONNECT) + case ME_CONNECT: #endif /* ME */ - )) - { - /* unsupported exchange type */ - return FAILED; + if (this->maj_version != IKEV2_MAJOR_VERSION) + { + return FAILED; + } + break; + default: + /* unsupported exchange type */ + return FAILED; } - if (this->initiator_spi == 0 + if (this->initiator_spi == 0) + { #ifdef ME - /* we allow zero spi for INFORMATIONAL exchanges, - * to allow connectivity checks */ - && this->exchange_type != INFORMATIONAL + if (this->exchange_type != INFORMATIONAL) + /* we allow zero spi for INFORMATIONAL exchanges, + * to allow connectivity checks */ #endif /* ME */ - ) - { - /* initiator spi not set */ - return FAILED; + { + return FAILED; + } } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_ike_header_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_ike_header_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_ike_header_t *this) { - *rules = ike_header_encodings; - *rule_count = sizeof(ike_header_encodings) / sizeof(encoding_rule_t); + return IKE_HEADER_LENGTH; } METHOD(payload_t, get_type, payload_type_t, @@ -311,6 +367,43 @@ METHOD(ike_header_t, set_initiator_flag, void, this->flags.initiator = initiator; } +METHOD(ike_header_t, get_encryption_flag, bool, + private_ike_header_t *this) +{ + return this->flags.encryption; +} + +METHOD(ike_header_t, set_encryption_flag, void, + private_ike_header_t *this, bool encryption) +{ + this->flags.encryption = encryption; +} + + +METHOD(ike_header_t, get_commit_flag, bool, + private_ike_header_t *this) +{ + return this->flags.commit; +} + +METHOD(ike_header_t, set_commit_flag, void, + private_ike_header_t *this, bool commit) +{ + this->flags.commit = commit; +} + +METHOD(ike_header_t, get_authonly_flag, bool, + private_ike_header_t *this) +{ + return this->flags.authonly; +} + +METHOD(ike_header_t, set_authonly_flag, void, + private_ike_header_t *this, bool authonly) +{ + this->flags.authonly = authonly; +} + METHOD(ike_header_t, get_exchange_type, u_int8_t, private_ike_header_t *this) { @@ -353,6 +446,7 @@ ike_header_t *ike_header_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -373,21 +467,38 @@ ike_header_t *ike_header_create() .set_version_flag = _set_version_flag, .get_initiator_flag = _get_initiator_flag, .set_initiator_flag = _set_initiator_flag, + .get_encryption_flag = _get_encryption_flag, + .set_encryption_flag = _set_encryption_flag, + .get_commit_flag = _get_commit_flag, + .set_commit_flag = _set_commit_flag, + .get_authonly_flag = _get_authonly_flag, + .set_authonly_flag = _set_authonly_flag, .get_exchange_type = _get_exchange_type, .set_exchange_type = _set_exchange_type, .get_message_id = _get_message_id, .set_message_id = _set_message_id, .destroy = _destroy, }, - .maj_version = IKE_MAJOR_VERSION, - .min_version = IKE_MINOR_VERSION, - .exchange_type = EXCHANGE_TYPE_UNDEFINED, - .flags = { - .initiator = TRUE, - .version = HIGHER_VERSION_SUPPORTED_FLAG, - }, .length = IKE_HEADER_LENGTH, + .exchange_type = EXCHANGE_TYPE_UNDEFINED, ); return &this->public; } + +/* + * Described in header. + */ +ike_header_t *ike_header_create_version(int major, int minor) +{ + ike_header_t *this = ike_header_create(); + + this->set_maj_version(this, major); + this->set_min_version(this, minor); + if (major == IKEV2_MAJOR_VERSION) + { + this->set_initiator_flag(this, TRUE); + } + return this; +} + diff --git a/src/libcharon/encoding/payloads/ike_header.h b/src/libcharon/encoding/payloads/ike_header.h index 5579a4961..e6b7d0dff 100644 --- a/src/libcharon/encoding/payloads/ike_header.h +++ b/src/libcharon/encoding/payloads/ike_header.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2007 Tobias Brunner - * Copyright (C) 2005-2006 Martin Willi + * Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil * @@ -30,19 +30,24 @@ typedef struct ike_header_t ike_header_t; #include <encoding/payloads/payload.h> /** - * Major Version of IKEv2. + * Major Version of IKEv1 we implement. */ -#define IKE_MAJOR_VERSION 2 +#define IKEV1_MAJOR_VERSION 1 /** - * Minor Version of IKEv2. + * Minor Version of IKEv1 we implement. */ -#define IKE_MINOR_VERSION 0 +#define IKEV1_MINOR_VERSION 0 /** - * Flag in IKEv2-Header. Always 0. + * Major Version of IKEv2 we implement. */ -#define HIGHER_VERSION_SUPPORTED_FLAG 0 +#define IKEV2_MAJOR_VERSION 2 + +/** + * Minor Version of IKEv2 we implement. + */ +#define IKEV2_MINOR_VERSION 0 /** * Length of IKE Header in Bytes. @@ -57,9 +62,39 @@ typedef struct ike_header_t ike_header_t; enum exchange_type_t{ /** - * EXCHANGE_TYPE_UNDEFINED. In private space, since not a official message type. + * Identity Protection (Main mode). */ - EXCHANGE_TYPE_UNDEFINED = 255, + ID_PROT = 2, + + /** + * Authentication Only. + */ + AUTH_ONLY = 3, + + /** + * Aggresive (Aggressive mode) + */ + AGGRESSIVE = 4, + + /** + * Informational in IKEv1 + */ + INFORMATIONAL_V1 = 5, + + /** + * Transaction (ISAKMP Cfg Mode "draft-ietf-ipsec-isakmp-mode-cfg-05") + */ + TRANSACTION = 6, + + /** + * Quick Mode + */ + QUICK_MODE = 32, + + /** + * New Group Mode + */ + NEW_GROUP_MODE = 33, /** * IKE_SA_INIT. @@ -77,7 +112,7 @@ enum exchange_type_t{ CREATE_CHILD_SA = 36, /** - * INFORMATIONAL. + * INFORMATIONAL in IKEv2. */ INFORMATIONAL = 37, @@ -85,12 +120,18 @@ enum exchange_type_t{ * IKE_SESSION_RESUME (RFC 5723). */ IKE_SESSION_RESUME = 38, + #ifdef ME /** * ME_CONNECT */ - ME_CONNECT = 240 + ME_CONNECT = 240, #endif /* ME */ + + /** + * Undefined exchange type, in private space. + */ + EXCHANGE_TYPE_UNDEFINED = 255, }; /** @@ -99,12 +140,7 @@ enum exchange_type_t{ extern enum_name_t *exchange_type_names; /** - * An object of this type represents an IKEv2 header and is used to - * generate and parse IKEv2 headers. - * - * The header format of an IKEv2-Message is compatible to the - * ISAKMP-Header format to allow implementations supporting - * both versions of the IKE-protocol. + * An object of this type represents an IKE header of either IKEv1 or IKEv2. */ struct ike_header_t { /** @@ -115,7 +151,7 @@ struct ike_header_t { /** * Get the initiator spi. * - * @return initiator_spi + * @return initiator_spi */ u_int64_t (*get_initiator_spi) (ike_header_t *this); @@ -129,7 +165,7 @@ struct ike_header_t { /** * Get the responder spi. * - * @return responder_spi + * @return responder_spi */ u_int64_t (*get_responder_spi) (ike_header_t *this); @@ -143,7 +179,7 @@ struct ike_header_t { /** * Get the major version. * - * @return major version + * @return major version */ u_int8_t (*get_maj_version) (ike_header_t *this); @@ -157,7 +193,7 @@ struct ike_header_t { /** * Get the minor version. * - * @return minor version + * @return minor version */ u_int8_t (*get_min_version) (ike_header_t *this); @@ -171,7 +207,7 @@ struct ike_header_t { /** * Get the response flag. * - * @return response flag + * @return response flag */ bool (*get_response_flag) (ike_header_t *this); @@ -185,7 +221,7 @@ struct ike_header_t { /** * Get "higher version supported"-flag. * - * @return version flag + * @return version flag */ bool (*get_version_flag) (ike_header_t *this); @@ -199,7 +235,7 @@ struct ike_header_t { /** * Get the initiator flag. * - * @return initiator flag + * @return initiator flag */ bool (*get_initiator_flag) (ike_header_t *this); @@ -211,9 +247,51 @@ struct ike_header_t { void (*set_initiator_flag) (ike_header_t *this, bool initiator); /** + * Get the encryption flag. + * + * @return encryption flag + */ + bool (*get_encryption_flag) (ike_header_t *this); + + /** + * Set the encryption flag. + * + * @param encryption encryption flag + */ + void (*set_encryption_flag) (ike_header_t *this, bool encryption); + + /** + * Get the commit flag. + * + * @return commit flag + */ + bool (*get_commit_flag) (ike_header_t *this); + + /** + * Set the commit flag. + * + * @param commit commit flag + */ + void (*set_commit_flag) (ike_header_t *this, bool commit); + + /** + * Get the authentication only flag. + * + * @return authonly flag + */ + bool (*get_authonly_flag) (ike_header_t *this); + + /** + * Set the authentication only flag. + * + * @param authonly authonly flag + */ + void (*set_authonly_flag) (ike_header_t *this, bool authonly); + + /** * Get the exchange type. * - * @return exchange type + * @return exchange type */ u_int8_t (*get_exchange_type) (ike_header_t *this); @@ -227,7 +305,7 @@ struct ike_header_t { /** * Get the message id. * - * @return message id + * @return message id */ u_int32_t (*get_message_id) (ike_header_t *this); @@ -245,10 +323,17 @@ struct ike_header_t { }; /** - * Create an ike_header_t object + * Create an empty ike_header_t object. * * @return ike_header_t object */ ike_header_t *ike_header_create(void); +/** + * Create an ike_header_t object for a specific major/minor version + * + * @return ike_header_t object + */ +ike_header_t *ike_header_create_version(int major, int minor); + #endif /** IKE_HEADER_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/ke_payload.c b/src/libcharon/encoding/payloads/ke_payload.c index 999d73192..438ea46b9 100644 --- a/src/libcharon/encoding/payloads/ke_payload.c +++ b/src/libcharon/encoding/payloads/ke_payload.c @@ -67,15 +67,17 @@ struct private_ke_payload_t { * Key Exchange Data of this KE payload. */ chunk_t key_exchange_data; + + /** + * Payload type, KEY_EXCHANGE or KEY_EXCHANGE_V1 + */ + payload_type_t type; }; /** - * 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 rules for IKEv2 key exchange payload. */ -encoding_rule_t ke_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_ke_payload_t, next_payload) }, /* the critical bit */ @@ -96,7 +98,7 @@ encoding_rule_t ke_payload_encodings[] = { { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[0])}, { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[1])}, /* Key Exchange Data is from variable size */ - { KEY_EXCHANGE_DATA, offsetof(private_ke_payload_t, key_exchange_data)} + { CHUNK_DATA, offsetof(private_ke_payload_t, key_exchange_data)}, }; /* @@ -113,23 +115,62 @@ encoding_rule_t ke_payload_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_ke_payload_t, next_payload) }, + /* Reserved Byte */ + { RESERVED_BYTE, offsetof(private_ke_payload_t, reserved_byte[0])}, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_ke_payload_t, payload_length) }, + /* Key Exchange Data is from variable size */ + { CHUNK_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 ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Key Exchange Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + + METHOD(payload_t, verify, status_t, private_ke_payload_t *this) { return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_ke_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_ke_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == KEY_EXCHANGE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_ke_payload_t *this) { - *rules = ke_payload_encodings; - *rule_count = countof(ke_payload_encodings); + if (this->type == KEY_EXCHANGE) + { + return 8; + } + return 4; } METHOD(payload_t, get_type, payload_type_t, private_ke_payload_t *this) { - return KEY_EXCHANGE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -172,7 +213,7 @@ METHOD2(payload_t, ke_payload_t, destroy, void, /* * Described in header */ -ke_payload_t *ke_payload_create() +ke_payload_t *ke_payload_create(payload_type_t type) { private_ke_payload_t *this; @@ -181,6 +222,7 @@ ke_payload_t *ke_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -192,22 +234,24 @@ ke_payload_t *ke_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = KE_PAYLOAD_HEADER_LENGTH, .dh_group_number = MODP_NONE, + .type = type, ); + this->payload_length = get_header_length(this); return &this->public; } /* * Described in header */ -ke_payload_t *ke_payload_create_from_diffie_hellman(diffie_hellman_t *dh) +ke_payload_t *ke_payload_create_from_diffie_hellman(payload_type_t type, + diffie_hellman_t *dh) { - private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create(); + private_ke_payload_t *this = (private_ke_payload_t*)ke_payload_create(type); dh->get_my_public_value(dh, &this->key_exchange_data); this->dh_group_number = dh->get_dh_group(dh); - this->payload_length = this->key_exchange_data.len + KE_PAYLOAD_HEADER_LENGTH; + this->payload_length += this->key_exchange_data.len; return &this->public; } diff --git a/src/libcharon/encoding/payloads/ke_payload.h b/src/libcharon/encoding/payloads/ke_payload.h index 65cc11883..5942954d9 100644 --- a/src/libcharon/encoding/payloads/ke_payload.h +++ b/src/libcharon/encoding/payloads/ke_payload.h @@ -31,16 +31,10 @@ typedef struct ke_payload_t ke_payload_t; #include <crypto/diffie_hellman.h> /** - * KE payload length in bytes without any key exchange data. - */ -#define KE_PAYLOAD_HEADER_LENGTH 8 - -/** - * Class representing an IKEv2-KE Payload. - * - * The KE Payload format is described in RFC section 3.4. + * Class representing an IKEv1 or IKEv2 key exchange payload. */ struct ke_payload_t { + /** * The payload_t interface. */ @@ -54,32 +48,34 @@ struct ke_payload_t { chunk_t (*get_key_exchange_data) (ke_payload_t *this); /** - * Gets the Diffie-Hellman Group Number of this KE payload. + * Gets the Diffie-Hellman Group Number of this KE payload (IKEv2 only). * * @return DH Group Number of this payload */ diffie_hellman_group_t (*get_dh_group_number) (ke_payload_t *this); /** - * Destroys an ke_payload_t object. + * Destroys a ke_payload_t object. */ void (*destroy) (ke_payload_t *this); }; /** - * Creates an empty ke_payload_t object + * Creates an empty ke_payload_t object. * - * @return ke_payload_t object + * @param type KEY_EXCHANGE or KEY_EXCHANGE_V1 + * @return ke_payload_t object */ -ke_payload_t *ke_payload_create(void); +ke_payload_t *ke_payload_create(payload_type_t type); /** - * Creates a ke_payload_t from a diffie_hellman_t + * Creates a ke_payload_t from a diffie_hellman_t. * - * @param diffie_hellman diffie hellman object containing group and key - * @return ke_payload_t object + * @param type KEY_EXCHANGE or KEY_EXCHANGE_V1 + * @param dh diffie hellman object containing group and key + * @return ke_payload_t object */ -ke_payload_t *ke_payload_create_from_diffie_hellman( - diffie_hellman_t *diffie_hellman); +ke_payload_t *ke_payload_create_from_diffie_hellman(payload_type_t type, + diffie_hellman_t *dh); #endif /** KE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/nonce_payload.c b/src/libcharon/encoding/payloads/nonce_payload.c index 78000b8c6..3c5eeb535 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.c +++ b/src/libcharon/encoding/payloads/nonce_payload.c @@ -19,6 +19,7 @@ #include "nonce_payload.h" +#include <daemon.h> #include <encoding/payloads/encodings.h> typedef struct private_nonce_payload_t private_nonce_payload_t; @@ -57,6 +58,11 @@ struct private_nonce_payload_t { * The contained nonce value. */ chunk_t nonce; + + /** + * Payload type, NONCE or NONCE_V1 + */ + payload_type_t type; }; /** @@ -65,7 +71,7 @@ struct private_nonce_payload_t { * The defined offsets are the positions in a object of type * private_nonce_payload_t. */ -encoding_rule_t nonce_payload_encodings[] = { +static encoding_rule_t 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 */ @@ -81,7 +87,7 @@ encoding_rule_t nonce_payload_encodings[] = { /* 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) }, + { CHUNK_DATA, offsetof(private_nonce_payload_t, nonce) }, }; /* 1 2 3 @@ -98,24 +104,48 @@ encoding_rule_t nonce_payload_encodings[] = { METHOD(payload_t, verify, status_t, private_nonce_payload_t *this) { - if (this->nonce.len < 16 || this->nonce.len > 256) + bool bad_length = FALSE; + + if (this->nonce.len > 256) + { + bad_length = TRUE; + } + if (this->type == NONCE && + this->nonce.len < 16) + { + bad_length = TRUE; + } + if (this->type == NONCE_V1 && + this->nonce.len < 8) + { + bad_length = TRUE; + } + if (bad_length) { + DBG1(DBG_ENC, "%N payload has invalid length (%d bytes)", + payload_type_names, this->type, this->nonce.len); return FAILED; } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_nonce_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_nonce_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_nonce_payload_t *this) { - *rules = nonce_payload_encodings; - *rule_count = countof(nonce_payload_encodings); + return 4; } METHOD(payload_t, get_type, payload_type_t, private_nonce_payload_t *this) { - return NONCE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -140,7 +170,7 @@ METHOD(nonce_payload_t, set_nonce, void, private_nonce_payload_t *this, chunk_t nonce) { this->nonce = chunk_clone(nonce); - this->payload_length = NONCE_PAYLOAD_HEADER_LENGTH + nonce.len; + this->payload_length = get_header_length(this) + nonce.len; } METHOD(nonce_payload_t, get_nonce, chunk_t, @@ -159,7 +189,7 @@ METHOD2(payload_t, nonce_payload_t, destroy, void, /* * Described in header */ -nonce_payload_t *nonce_payload_create() +nonce_payload_t *nonce_payload_create(payload_type_t type) { private_nonce_payload_t *this; @@ -168,6 +198,7 @@ nonce_payload_t *nonce_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -179,7 +210,8 @@ nonce_payload_t *nonce_payload_create() .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = NONCE_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), + .type = type, ); return &this->public; } diff --git a/src/libcharon/encoding/payloads/nonce_payload.h b/src/libcharon/encoding/payloads/nonce_payload.h index e9212202e..5c47f5f9f 100644 --- a/src/libcharon/encoding/payloads/nonce_payload.h +++ b/src/libcharon/encoding/payloads/nonce_payload.h @@ -33,14 +33,7 @@ typedef struct nonce_payload_t nonce_payload_t; #define NONCE_SIZE 32 /** - * Length of a nonce payload without a nonce in bytes. - */ -#define NONCE_PAYLOAD_HEADER_LENGTH 4 - -/** - * Object representing an IKEv2 Nonce payload. - * - * The Nonce payload format is described in RFC section 3.3. + * Object representing an IKEv1/IKEv2 Nonce payload. */ struct nonce_payload_t { /** @@ -71,8 +64,9 @@ struct nonce_payload_t { /** * Creates an empty nonce_payload_t object * - * @return nonce_payload_t object + * @param type NONCE or NONCE_V1 + * @return nonce_payload_t object */ -nonce_payload_t *nonce_payload_create(void); +nonce_payload_t *nonce_payload_create(payload_type_t type); #endif /** NONCE_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index e03d1af67..d168e1c12 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -36,11 +36,18 @@ ENUM_NEXT(notify_type_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVALID_SYN "INVALID_MESSAGE_ID"); ENUM_NEXT(notify_type_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVALID_SPI"); -ENUM_NEXT(notify_type_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, +ENUM_NEXT(notify_type_names, ATTRIBUTES_NOT_SUPPORTED, NO_PROPOSAL_CHOSEN, INVALID_SPI, + "ATTRIBUTES_NOT_SUPPORTED", "NO_PROPOSAL_CHOSEN"); -ENUM_NEXT(notify_type_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, - "INVALID_KE_PAYLOAD"); -ENUM_NEXT(notify_type_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, +ENUM_NEXT(notify_type_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN, + "PAYLOAD_MALFORMED", + "INVALID_KE_PAYLOAD", + "INVALID_ID_INFORMATION", + "INVALID_CERT_ENCODING", + "INVALID_CERTIFICATE", + "CERT_TYPE_UNSUPPORTED", + "INVALID_CERT_AUTHORITY", + "INVALID_HASH_INFORMATION", "AUTHENTICATION_FAILED"); ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED, "SINGLE_PAIR_REQUIRED", @@ -102,7 +109,14 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, PSK_CONFIRM, MS_NOTIFY_STATUS, "SECURE PASSWORD_METHOD", "PSK_PERSIST", "PSK_CONFIRM"); -ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, PSK_CONFIRM, +ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, PSK_CONFIRM, + "INITIAL_CONTACT"); +ENUM_NEXT(notify_type_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1, + "DPD_R_U_THERE", + "DPD_R_U_THERE_ACK"); +ENUM_NEXT(notify_type_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R_U_THERE_ACK, + "UNITY_LOAD_BALANCE"); +ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE, "USE_BEET_MODE"); ENUM_NEXT(notify_type_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE, "ME_MEDIATION", @@ -127,11 +141,18 @@ ENUM_NEXT(notify_type_short_names, INVALID_MESSAGE_ID, INVALID_MESSAGE_ID, INVAL "INVAL_MID"); ENUM_NEXT(notify_type_short_names, INVALID_SPI, INVALID_SPI, INVALID_MESSAGE_ID, "INVAL_SPI"); -ENUM_NEXT(notify_type_short_names, NO_PROPOSAL_CHOSEN, NO_PROPOSAL_CHOSEN, INVALID_SPI, +ENUM_NEXT(notify_type_short_names, ATTRIBUTES_NOT_SUPPORTED, NO_PROPOSAL_CHOSEN, INVALID_SPI, + "ATTR_UNSUP", "NO_PROP"); -ENUM_NEXT(notify_type_short_names, INVALID_KE_PAYLOAD, INVALID_KE_PAYLOAD, NO_PROPOSAL_CHOSEN, - "INVAL_KE"); -ENUM_NEXT(notify_type_short_names, AUTHENTICATION_FAILED, AUTHENTICATION_FAILED, INVALID_KE_PAYLOAD, +ENUM_NEXT(notify_type_short_names, PAYLOAD_MALFORMED, AUTHENTICATION_FAILED, NO_PROPOSAL_CHOSEN, + "PLD_MAL", + "INVAL_KE", + "INVAL_ID", + "INVAL_CERTEN", + "INVAL_CERT", + "CERT_UNSUP", + "INVAL_CA", + "INVAL_HASH", "AUTH_FAILED"); ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, CHILD_SA_NOT_FOUND, AUTHENTICATION_FAILED, "SINGLE_PAIR", @@ -193,7 +214,14 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, PSK_CONFIRM, MS_NOTIFY_STATU "SEC_PASSWD", "PSK_PST", "PSK_CFM"); -ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, PSK_CONFIRM, +ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, PSK_CONFIRM, + "INITIAL_CONTACT"); +ENUM_NEXT(notify_type_short_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1, + "DPD", + "DPD_ACK"); +ENUM_NEXT(notify_type_short_names, UNITY_LOAD_BALANCE, UNITY_LOAD_BALANCE, DPD_R_U_THERE_ACK, + "UNITY_LB"); +ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, UNITY_LOAD_BALANCE, "BEET_MODE"); ENUM_NEXT(notify_type_short_names, ME_MEDIATION, RADIUS_ATTRIBUTE, USE_BEET_MODE, "ME_MED", @@ -232,7 +260,7 @@ struct private_notify_payload_t { /** * reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. @@ -240,6 +268,11 @@ struct private_notify_payload_t { u_int16_t payload_length; /** + * Domain of interpretation, IKEv1 only. + */ + u_int32_t doi; + + /** * Protocol id. */ u_int8_t protocol_id; @@ -262,40 +295,42 @@ struct private_notify_payload_t { /** * Notification data. */ - chunk_t notification_data; + chunk_t notify_data; + + /** + * Type of payload, NOTIFY or NOTIFY_V1 + */ + payload_type_t type; }; /** - * 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 rules for an IKEv2 notification payload */ -encoding_rule_t notify_payload_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, + { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, /* the critical bit */ - { FLAG, offsetof(private_notify_payload_t, critical) }, + { FLAG, offsetof(private_notify_payload_t, critical) }, /* 7 Bit reserved bits, nowhere stored */ - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) }, - { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) }, /* Length of the whole payload*/ - { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) }, + { 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) }, + { 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) }, + { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) }, /* Notify message type as 16 bit field*/ - { U_INT_16, offsetof(private_notify_payload_t, notify_type) }, + { U_INT_16, offsetof(private_notify_payload_t, notify_type) }, /* SPI as variable length field*/ - { SPI, offsetof(private_notify_payload_t, spi) }, + { SPI, offsetof(private_notify_payload_t, spi) }, /* Key Exchange Data is from variable size */ - { NOTIFICATION_DATA,offsetof(private_notify_payload_t, notification_data) } + { CHUNK_DATA, offsetof(private_notify_payload_t, notify_data) }, }; /* @@ -315,6 +350,57 @@ encoding_rule_t notify_payload_encodings[] = { ! ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encoding rules for an IKEv1 notification payload + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_notify_payload_t, next_payload) }, + /* 8 reserved bits */ + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_notify_payload_t, reserved[7]) }, + /* Length of the whole payload*/ + { PAYLOAD_LENGTH, offsetof(private_notify_payload_t, payload_length) }, + /* DOI as 32 bit field*/ + { U_INT_32, offsetof(private_notify_payload_t, doi) }, + /* Protocol ID as 8 bit field*/ + { U_INT_8, offsetof(private_notify_payload_t, protocol_id) }, + /* SPI Size as 8 bit field*/ + { SPI_SIZE, offsetof(private_notify_payload_t, spi_size) }, + /* Notify message type as 16 bit field*/ + { U_INT_16, offsetof(private_notify_payload_t, notify_type) }, + /* SPI as variable length field*/ + { SPI, offsetof(private_notify_payload_t, spi) }, + /* Key Exchange Data is from variable size */ + { CHUNK_DATA, offsetof(private_notify_payload_t, notify_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 ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Protocol ID ! SPI Size ! Notify Message Type ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Security Parameter Index (SPI) ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ Notification Data ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + METHOD(payload_t, verify, status_t, private_notify_payload_t *this) @@ -337,7 +423,7 @@ METHOD(payload_t, verify, status_t, { case INVALID_KE_PAYLOAD: { - if (this->notification_data.len != 2) + if (this->type == NOTIFY && this->notify_data.len != 2) { bad_length = TRUE; } @@ -347,7 +433,7 @@ METHOD(payload_t, verify, status_t, case NAT_DETECTION_DESTINATION_IP: case ME_CONNECTAUTH: { - if (this->notification_data.len != HASH_SIZE_SHA1) + if (this->notify_data.len != HASH_SIZE_SHA1) { bad_length = TRUE; } @@ -357,7 +443,7 @@ METHOD(payload_t, verify, status_t, case INVALID_MAJOR_VERSION: case NO_PROPOSAL_CHOSEN: { - if (this->notification_data.len != 0) + if (this->type == NOTIFY && this->notify_data.len != 0) { bad_length = TRUE; } @@ -365,7 +451,7 @@ METHOD(payload_t, verify, status_t, } case ADDITIONAL_IP4_ADDRESS: { - if (this->notification_data.len != 4) + if (this->notify_data.len != 4) { bad_length = TRUE; } @@ -373,7 +459,7 @@ METHOD(payload_t, verify, status_t, } case ADDITIONAL_IP6_ADDRESS: { - if (this->notification_data.len != 16) + if (this->notify_data.len != 16) { bad_length = TRUE; } @@ -381,7 +467,7 @@ METHOD(payload_t, verify, status_t, } case AUTH_LIFETIME: { - if (this->notification_data.len != 4) + if (this->notify_data.len != 4) { bad_length = TRUE; } @@ -389,30 +475,37 @@ METHOD(payload_t, verify, status_t, } case IPCOMP_SUPPORTED: { - if (this->notification_data.len != 3) + if (this->notify_data.len != 3) { bad_length = TRUE; } break; } case ME_ENDPOINT: - if (this->notification_data.len != 8 && - this->notification_data.len != 12 && - this->notification_data.len != 24) + if (this->notify_data.len != 8 && + this->notify_data.len != 12 && + this->notify_data.len != 24) { bad_length = TRUE; } break; case ME_CONNECTID: - if (this->notification_data.len < 4 || - this->notification_data.len > 16) + if (this->notify_data.len < 4 || + this->notify_data.len > 16) { bad_length = TRUE; } break; case ME_CONNECTKEY: - if (this->notification_data.len < 16 || - this->notification_data.len > 32) + if (this->notify_data.len < 16 || + this->notify_data.len > 32) + { + bad_length = TRUE; + } + break; + case DPD_R_U_THERE: + case DPD_R_U_THERE_ACK: + if (this->notify_data.len != 4) { bad_length = TRUE; } @@ -425,23 +518,38 @@ METHOD(payload_t, verify, status_t, { DBG1(DBG_ENC, "invalid notify data length for %N (%d)", notify_type_names, this->notify_type, - this->notification_data.len); + this->notify_data.len); return FAILED; } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_notify_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_notify_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == NOTIFY) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_notify_payload_t *this) { - *rules = notify_payload_encodings; - *rule_count = countof(notify_payload_encodings); + if (this->type == NOTIFY) + { + return 8 + this->spi_size; + } + return 12 + this->spi_size; } METHOD(payload_t, get_type, payload_type_t, private_notify_payload_t *this) { - return NOTIFY; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -459,19 +567,9 @@ METHOD(payload_t, set_next_type, void, /** * recompute the payloads length. */ -static void compute_length (private_notify_payload_t *this) +static void compute_length(private_notify_payload_t *this) { - size_t length = NOTIFY_PAYLOAD_HEADER_LENGTH; - - if (this->notification_data.ptr != NULL) - { - length += this->notification_data.len; - } - if (this->spi.ptr != NULL) - { - length += this->spi.len; - } - this->payload_length = length; + this->payload_length = get_header_length(this) + this->notify_data.len; } METHOD(payload_t, get_length, size_t, @@ -539,24 +637,55 @@ METHOD(notify_payload_t, set_spi, void, compute_length(this); } +METHOD(notify_payload_t, get_spi_data, chunk_t, + private_notify_payload_t *this) +{ + switch (this->protocol_id) + { + case PROTO_IKE: + if (this->spi.len == 16) + { + return this->spi; + } + default: + break; + } + return chunk_empty; +} + +METHOD(notify_payload_t, set_spi_data, void, + private_notify_payload_t *this, chunk_t spi) +{ + chunk_free(&this->spi); + switch (this->protocol_id) + { + case PROTO_IKE: + this->spi = chunk_clone(spi); + default: + break; + } + this->spi_size = this->spi.len; + compute_length(this); +} + METHOD(notify_payload_t, get_notification_data, chunk_t, private_notify_payload_t *this) { - return this->notification_data; + return this->notify_data; } METHOD(notify_payload_t, set_notification_data, void, private_notify_payload_t *this, chunk_t data) { - free(this->notification_data.ptr); - this->notification_data = chunk_clone(data); + free(this->notify_data.ptr); + this->notify_data = chunk_clone(data); compute_length(this); } METHOD2(payload_t, notify_payload_t, destroy, void, private_notify_payload_t *this) { - free(this->notification_data.ptr); + free(this->notify_data.ptr); free(this->spi.ptr); free(this); } @@ -564,7 +693,7 @@ METHOD2(payload_t, notify_payload_t, destroy, void, /* * Described in header */ -notify_payload_t *notify_payload_create() +notify_payload_t *notify_payload_create(payload_type_t type) { private_notify_payload_t *this; @@ -573,6 +702,7 @@ notify_payload_t *notify_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -585,13 +715,17 @@ notify_payload_t *notify_payload_create() .set_notify_type = _set_notify_type, .get_spi = _get_spi, .set_spi = _set_spi, + .get_spi_data = _get_spi_data, + .set_spi_data = _set_spi_data, .get_notification_data = _get_notification_data, .set_notification_data = _set_notification_data, .destroy = _destroy, }, + .doi = IKEV1_DOI_IPSEC, .next_payload = NO_PAYLOAD, - .payload_length = NOTIFY_PAYLOAD_HEADER_LENGTH, + .type = type, ); + compute_length(this); return &this->public; } @@ -599,12 +733,12 @@ notify_payload_t *notify_payload_create() * Described in header. */ notify_payload_t *notify_payload_create_from_protocol_and_type( - protocol_id_t protocol_id, notify_type_t notify_type) + payload_type_t type, protocol_id_t protocol, notify_type_t notify) { - notify_payload_t *notify = notify_payload_create(); + notify_payload_t *this = notify_payload_create(type); - notify->set_notify_type(notify, notify_type); - notify->set_protocol_id(notify, protocol_id); + this->set_notify_type(this, notify); + this->set_protocol_id(this, protocol); - return notify; + return this; } diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index ced282700..beec1e233 100644 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -33,25 +33,36 @@ typedef struct notify_payload_t notify_payload_t; #include <utils/linked_list.h> /** - * Notify payload length in bytes without any spi and notification data. - */ -#define NOTIFY_PAYLOAD_HEADER_LENGTH 8 - -/** - * Notify message types. - * - * See IKEv2 RFC 3.10.1. + * Notify message types for IKEv2, and a subset for IKEv1. */ enum notify_type_t { /* notify error messages */ UNSUPPORTED_CRITICAL_PAYLOAD = 1, + /* IKEv1 alias */ + INVALID_PAYLOAD_TYPE = 1, INVALID_IKE_SPI = 4, INVALID_MAJOR_VERSION = 5, INVALID_SYNTAX = 7, + /* IKEv1 alias */ + INVALID_EXCHANGE_TYPE = 7, INVALID_MESSAGE_ID = 9, INVALID_SPI = 11, + /* IKEv1 only */ + ATTRIBUTES_NOT_SUPPORTED = 13, + /* IKEv1 alias */ NO_PROPOSAL_CHOSEN = 14, + /* IKEv1 only */ + PAYLOAD_MALFORMED = 16, INVALID_KE_PAYLOAD = 17, + /* IKEv1 alias */ + INVALID_KEY_INFORMATION = 17, + /* IKEv1 only */ + INVALID_ID_INFORMATION = 18, + INVALID_CERT_ENCODING = 19, + INVALID_CERTIFICATE = 20, + CERT_TYPE_UNSUPPORTED = 21, + INVALID_CERT_AUTHORITY = 22, + INVALID_HASH_INFORMATION = 23, AUTHENTICATION_FAILED = 24, SINGLE_PAIR_REQUIRED = 34, NO_ADDITIONAL_SAS = 35, @@ -132,6 +143,13 @@ enum notify_type_t { /* PACE - draft-kuegler-ipsecme-pace-ikev2 */ PSK_PERSIST = 16425, PSK_CONFIRM = 16426, + /* IKEv1 initial contact */ + INITIAL_CONTACT_IKEV1 = 24578, + /* IKEv1 DPD */ + DPD_R_U_THERE = 36136, + DPD_R_U_THERE_ACK = 36137, + /* IKEv1 Cisco High Availability */ + UNITY_LOAD_BALANCE = 40501, /* BEET mode, not even a draft yet. private use */ USE_BEET_MODE = 40961, /* IKE-ME, private use */ @@ -214,6 +232,24 @@ struct notify_payload_t { void (*set_spi) (notify_payload_t *this, u_int32_t spi); /** + * Returns the currently set spi of this payload. + * + * This is only valid for notifys with protocol ISAKMP + * + * @return SPI value + */ + chunk_t (*get_spi_data) (notify_payload_t *this); + + /** + * Sets the spi of this payload. + * + * This is only valid for notifys with protocol ISAKMP + * + * @param spi SPI value + */ + void (*set_spi_data) (notify_payload_t *this, chunk_t spi); + + /** * Returns the currently set notification data of payload. * * Returned data are not copied. @@ -241,18 +277,20 @@ struct notify_payload_t { /** * Creates an empty notify_payload_t object * + * @param type payload type, NOTIFY or NOTIFY_V1 * @return created notify_payload_t object */ -notify_payload_t *notify_payload_create(void); +notify_payload_t *notify_payload_create(payload_type_t type); /** * Creates an notify_payload_t object of specific type for specific protocol id. * - * @param protocol_id protocol id (IKE, AH or ESP) - * @param type notify type (see notify_type_t) + * @param type payload type, NOTIFY or NOTIFY_V1 + * @param protocol protocol id (IKE, AH or ESP) + * @param notify type of notify * @return notify_payload_t object */ notify_payload_t *notify_payload_create_from_protocol_and_type( - protocol_id_t protocol_id, notify_type_t type); + payload_type_t type, protocol_id_t protocol, notify_type_t notify); #endif /** NOTIFY_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index a2c0a4385..dc158476b 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -20,6 +20,7 @@ #include <encoding/payloads/ike_header.h> #include <encoding/payloads/sa_payload.h> + #include <encoding/payloads/nonce_payload.h> #include <encoding/payloads/id_payload.h> #include <encoding/payloads/ke_payload.h> @@ -34,13 +35,30 @@ #include <encoding/payloads/cp_payload.h> #include <encoding/payloads/configuration_attribute.h> #include <encoding/payloads/eap_payload.h> +#include <encoding/payloads/hash_payload.h> #include <encoding/payloads/unknown_payload.h> - ENUM_BEGIN(payload_type_names, NO_PAYLOAD, NO_PAYLOAD, "NO_PAYLOAD"); -ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, - GENERIC_SECURE_PASSWORD_METHOD, NO_PAYLOAD, +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, NO_PAYLOAD, + "SECURITY_ASSOCIATION_V1", + "PROPOSAL_V1", + "TRANSFORM_V1", + "KEY_EXCHANGE_V1", + "ID_V1", + "CERTIFICATE_V1", + "CERTIFICATE_REQUEST_V1", + "HASH_V1", + "SIGNATURE_V1", + "NONCE_V1", + "NOTIFY_V1", + "DELETE_V1", + "VENDOR_ID_V1", + "CONFIGURATION_V1"); +ENUM_NEXT(payload_type_names, NAT_D_V1, NAT_OA_V1, CONFIGURATION_V1, + "NAT_D_V1", + "NAT_OA_V1"); +ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWORD_METHOD, NAT_OA_V1, "SECURITY_ASSOCIATION", "KEY_EXCHANGE", "ID_INITIATOR", @@ -61,30 +79,56 @@ ENUM_NEXT(payload_type_names, SECURITY_ASSOCIATION, #ifdef ME ENUM_NEXT(payload_type_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD, "ID_PEER"); -ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, +ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, ID_PEER, "HEADER", "PROPOSAL_SUBSTRUCTURE", + "PROPOSAL_SUBSTRUCTURE_V1", "TRANSFORM_SUBSTRUCTURE", + "TRANSFORM_SUBSTRUCTURE_V1", "TRANSFORM_ATTRIBUTE", + "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", - "CONFIGURATION_ATTRIBUTE"); + "CONFIGURATION_ATTRIBUTE", + "CONFIGURATION_ATTRIBUTE_V1", + "ENCRYPTED_V1"); #else -ENUM_NEXT(payload_type_names, HEADER, CONFIGURATION_ATTRIBUTE, - GENERIC_SECURE_PASSWORD_METHOD, +ENUM_NEXT(payload_type_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWORD_METHOD, "HEADER", "PROPOSAL_SUBSTRUCTURE", + "PROPOSAL_SUBSTRUCTURE_V1", "TRANSFORM_SUBSTRUCTURE", + "TRANSFORM_SUBSTRUCTURE_V1", "TRANSFORM_ATTRIBUTE", + "TRANSFORM_ATTRIBUTE_V1", "TRAFFIC_SELECTOR_SUBSTRUCTURE", - "CONFIGURATION_ATTRIBUTE"); + "CONFIGURATION_ATTRIBUTE", + "CONFIGURATION_ATTRIBUTE_V1", + "ENCRYPTED_V1"); #endif /* ME */ -ENUM_END(payload_type_names, CONFIGURATION_ATTRIBUTE); +ENUM_END(payload_type_names, ENCRYPTED_V1); /* short forms of payload names */ ENUM_BEGIN(payload_type_short_names, NO_PAYLOAD, NO_PAYLOAD, "--"); -ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, - GENERIC_SECURE_PASSWORD_METHOD, NO_PAYLOAD, +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION_V1, CONFIGURATION_V1, NO_PAYLOAD, + "SA", + "PROP", + "TRANS", + "KE", + "ID", + "CERT", + "CERTREQ", + "HASH", + "SIG", + "No", + "N", + "D", + "V", + "CP"); +ENUM_NEXT(payload_type_short_names, NAT_D_V1, NAT_OA_V1, CONFIGURATION_V1, + "NAT-D", + "NAT-OA"); +ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, GENERIC_SECURE_PASSWORD_METHOD, NAT_OA_V1, "SA", "KE", "IDi", @@ -106,24 +150,33 @@ ENUM_NEXT(payload_type_short_names, SECURITY_ASSOCIATION, ENUM_NEXT(payload_type_short_names, ID_PEER, ID_PEER, GENERIC_SECURE_PASSWORD_METHOD, "IDp"); -ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, ID_PEER, +ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, ID_PEER, "HDR", "PROP", + "PROP", + "TRANS", "TRANS", "TRANSATTR", + "TRANSATTR", "TSSUB", - "CPATTR"); + "CATTR", + "CATTR", + "E"); #else -ENUM_NEXT(payload_type_short_names, HEADER, CONFIGURATION_ATTRIBUTE, - GENERIC_SECURE_PASSWORD_METHOD, +ENUM_NEXT(payload_type_short_names, HEADER, ENCRYPTED_V1, GENERIC_SECURE_PASSWORD_METHOD, "HDR", "PROP", + "PROP", + "TRANS", "TRANS", "TRANSATTR", + "TRANSATTR", "TSSUB", - "CPATTR"); + "CATTR", + "CATTR", + "E"); #endif /* ME */ -ENUM_END(payload_type_short_names, CONFIGURATION_ATTRIBUTE); +ENUM_END(payload_type_short_names, ENCRYPTED_V1); /* * see header @@ -135,29 +188,36 @@ payload_t *payload_create(payload_type_t type) case HEADER: return (payload_t*)ike_header_create(); case SECURITY_ASSOCIATION: - return (payload_t*)sa_payload_create(); + case SECURITY_ASSOCIATION_V1: + return (payload_t*)sa_payload_create(type); case PROPOSAL_SUBSTRUCTURE: - return (payload_t*)proposal_substructure_create(); + case PROPOSAL_SUBSTRUCTURE_V1: + return (payload_t*)proposal_substructure_create(type); case TRANSFORM_SUBSTRUCTURE: - return (payload_t*)transform_substructure_create(); + case TRANSFORM_SUBSTRUCTURE_V1: + return (payload_t*)transform_substructure_create(type); case TRANSFORM_ATTRIBUTE: - return (payload_t*)transform_attribute_create(); + case TRANSFORM_ATTRIBUTE_V1: + return (payload_t*)transform_attribute_create(type); case NONCE: - return (payload_t*)nonce_payload_create(); + case NONCE_V1: + return (payload_t*)nonce_payload_create(type); case ID_INITIATOR: - return (payload_t*)id_payload_create(ID_INITIATOR); case ID_RESPONDER: - return (payload_t*)id_payload_create(ID_RESPONDER); + case ID_V1: + case NAT_OA_V1: #ifdef ME case ID_PEER: - return (payload_t*)id_payload_create(ID_PEER); #endif /* ME */ + return (payload_t*)id_payload_create(type); case AUTHENTICATION: return (payload_t*)auth_payload_create(); case CERTIFICATE: - return (payload_t*)cert_payload_create(); + case CERTIFICATE_V1: + return (payload_t*)cert_payload_create(type); case CERTIFICATE_REQUEST: - return (payload_t*)certreq_payload_create(); + case CERTIFICATE_REQUEST_V1: + return (payload_t*)certreq_payload_create(type); case TRAFFIC_SELECTOR_SUBSTRUCTURE: return (payload_t*)traffic_selector_substructure_create(); case TRAFFIC_SELECTOR_INITIATOR: @@ -165,21 +225,32 @@ payload_t *payload_create(payload_type_t type) case TRAFFIC_SELECTOR_RESPONDER: return (payload_t*)ts_payload_create(FALSE); case KEY_EXCHANGE: - return (payload_t*)ke_payload_create(); + case KEY_EXCHANGE_V1: + return (payload_t*)ke_payload_create(type); case NOTIFY: - return (payload_t*)notify_payload_create(); + case NOTIFY_V1: + return (payload_t*)notify_payload_create(type); case DELETE: - return (payload_t*)delete_payload_create(0); + case DELETE_V1: + return (payload_t*)delete_payload_create(type, 0); case VENDOR_ID: - return (payload_t*)vendor_id_payload_create(); + case VENDOR_ID_V1: + return (payload_t*)vendor_id_payload_create(type); + case HASH_V1: + case SIGNATURE_V1: + case NAT_D_V1: + return (payload_t*)hash_payload_create(type); case CONFIGURATION: - return (payload_t*)cp_payload_create(); + case CONFIGURATION_V1: + return (payload_t*)cp_payload_create(type); case CONFIGURATION_ATTRIBUTE: - return (payload_t*)configuration_attribute_create(); + case CONFIGURATION_ATTRIBUTE_V1: + return (payload_t*)configuration_attribute_create(type); case EXTENSIBLE_AUTHENTICATION: return (payload_t*)eap_payload_create(); case ENCRYPTED: - return (payload_t*)encryption_payload_create(); + case ENCRYPTED_V1: + return (payload_t*)encryption_payload_create(type); default: return (payload_t*)unknown_payload_create(type); } @@ -190,8 +261,19 @@ payload_t *payload_create(payload_type_t type) */ bool payload_is_known(payload_type_t type) { - if (type == HEADER || - (type >= SECURITY_ASSOCIATION && type <= EXTENSIBLE_AUTHENTICATION)) + if (type == HEADER) + { + return TRUE; + } + if (type >= SECURITY_ASSOCIATION && type <= EXTENSIBLE_AUTHENTICATION) + { + return TRUE; + } + if (type >= SECURITY_ASSOCIATION_V1 && type <= CONFIGURATION_V1) + { + return TRUE; + } + if (type >= NAT_D_V1 && type <= NAT_OA_V1) { return TRUE; } @@ -210,10 +292,9 @@ bool payload_is_known(payload_type_t type) void* payload_get_field(payload_t *payload, encoding_type_t type, u_int skip) { encoding_rule_t *rule; - size_t count; - int i; + int i, count; - payload->get_encoding_rules(payload, &rule, &count); + count = payload->get_encoding_rules(payload, &rule); for (i = 0; i < count; i++) { if (rule[i].type == type && skip-- == 0) diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index a9af29b5b..d5e862601 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -29,14 +29,18 @@ typedef struct payload_t payload_t; #include <library.h> #include <encoding/payloads/encodings.h> +/** + * Domain of interpretation used by IPsec/IKEv1 + */ +#define IKEV1_DOI_IPSEC 1 /** - * Payload-Types of a IKEv2-Message. + * Payload-Types of an IKE message. * * Header and substructures are also defined as * payload types with values from PRIVATE USE space. */ -enum payload_type_t{ +enum payload_type_t { /** * End of payload list in next_payload @@ -46,6 +50,86 @@ enum payload_type_t{ /** * The security association (SA) payload containing proposals. */ + SECURITY_ASSOCIATION_V1 = 1, + + /** + * The proposal payload, containing transforms. + */ + PROPOSAL_V1 = 2, + + /** + * The transform payload. + */ + TRANSFORM_V1 = 3, + + /** + * The key exchange (KE) payload containing diffie-hellman values. + */ + KEY_EXCHANGE_V1 = 4, + + /** + * ID payload. + */ + ID_V1 = 5, + + /** + * Certificate payload with certificates (CERT). + */ + CERTIFICATE_V1 = 6, + + /** + * Certificate request payload. + */ + CERTIFICATE_REQUEST_V1 = 7, + + /** + * Hash payload. + */ + HASH_V1 = 8, + + /** + * Signature payload + */ + SIGNATURE_V1 = 9, + + /** + * Nonce payload. + */ + NONCE_V1 = 10, + + /** + * Notification payload. + */ + NOTIFY_V1 = 11, + + /** + * Delete payload. + */ + DELETE_V1 = 12, + + /** + * Vendor id payload. + */ + VENDOR_ID_V1 = 13, + + /** + * Attribute payload (ISAKMP Mode Config, aka configuration payload. + */ + CONFIGURATION_V1 = 14, + + /** + * NAT discovery payload (NAT-D). + */ + NAT_D_V1 = 20, + + /** + * NAT original address payload (NAT-OA) + */ + NAT_OA_V1 = 21, + + /** + * The security association (SA) payload containing proposals. + */ SECURITY_ASSOCIATION = 33, /** @@ -139,50 +223,60 @@ enum payload_type_t{ /** * Header has a value of PRIVATE USE space. * - * This payload type is not sent over wire and just - * used internally to handle IKEv2-Header like a payload. + * This type and all the following are never sent over wire and are + * used internally only. */ HEADER = 256, /** - * PROPOSAL_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a proposal substructure like a payload. + * PROPOSAL_SUBSTRUCTURE, IKEv2 proposals in a SA payload. */ - PROPOSAL_SUBSTRUCTURE = 257, + PROPOSAL_SUBSTRUCTURE, /** - * TRANSFORM_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform substructure like a payload. + * PROPOSAL_SUBSTRUCTURE_V1, IKEv1 proposals in a SA payload. */ - TRANSFORM_SUBSTRUCTURE = 258, + PROPOSAL_SUBSTRUCTURE_V1, /** - * TRANSFORM_ATTRIBUTE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform attribute like a payload. + * TRANSFORM_SUBSTRUCTURE, IKEv2 transforms in a proposal substructure. */ - TRANSFORM_ATTRIBUTE = 259, + TRANSFORM_SUBSTRUCTURE, /** - * TRAFFIC_SELECTOR_SUBSTRUCTURE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform selector like a payload. + * TRANSFORM_SUBSTRUCTURE_V1, IKEv1 transforms in a proposal substructure. */ - TRAFFIC_SELECTOR_SUBSTRUCTURE = 260, + TRANSFORM_SUBSTRUCTURE_V1, /** - * CONFIGURATION_ATTRIBUTE has a value of PRIVATE USE space. - * - * This payload type is not sent over wire and just - * used internally to handle a transform attribute like a payload. + * TRANSFORM_ATTRIBUTE, IKEv2 attribute in a transform. */ - CONFIGURATION_ATTRIBUTE = 261, + TRANSFORM_ATTRIBUTE, + + /** + * TRANSFORM_ATTRIBUTE_V1, IKEv1 attribute in a transform. + */ + TRANSFORM_ATTRIBUTE_V1, + + /** + * TRAFFIC_SELECTOR_SUBSTRUCTURE, traffic selector in a TS payload. + */ + TRAFFIC_SELECTOR_SUBSTRUCTURE, + + /** + * CONFIGURATION_ATTRIBUTE, IKEv2 attribute in a configuration payload. + */ + CONFIGURATION_ATTRIBUTE, + + /** + * CONFIGURATION_ATTRIBUTE_V1, IKEv1 attribute in a configuration payload. + */ + CONFIGURATION_ATTRIBUTE_V1, + + /** + * This is not really a payload, but rather the complete IKEv1 message. + */ + ENCRYPTED_V1, }; /** @@ -207,43 +301,50 @@ struct payload_t { /** * Get encoding rules for this payload. * - * @param rules location to store pointer of first rule - * @param rule_count location to store number of rules + * @param rules location to store pointer to rules + * @return number of rules + */ + int (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules); + + /** + * Get non-variable header length for a variable length payload. + * + * @return fixed length of the payload */ - void (*get_encoding_rules) (payload_t *this, encoding_rule_t **rules, size_t *rule_count); + int (*get_header_length)(payload_t *this); /** * Get type of payload. * - * @return type of this payload + * @return type of this payload */ payload_type_t (*get_type) (payload_t *this); /** * Get type of next payload or NO_PAYLOAD (0) if this is the last one. * - * @return type of next payload + * @return type of next payload */ payload_type_t (*get_next_type) (payload_t *this); /** * Set type of next payload. * - * @param type type of next payload + * @param type type of next payload */ void (*set_next_type) (payload_t *this,payload_type_t type); /** * Get length of payload. * - * @return length of this payload + * @return length of this payload */ size_t (*get_length) (payload_t *this); /** * Verifies payload structure and makes consistence check. * - * @return SUCCESS, FAILED if consistence not given + * @return SUCCESS, FAILED if consistence not given */ status_t (*verify) (payload_t *this); diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 4753d574d..653f51a46 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -25,7 +26,7 @@ #include <daemon.h> /** - * IKEv1 Value for a proposal payload. + * IKEv2 Value for a proposal payload. */ #define PROPOSAL_TYPE_VALUE 2 @@ -84,16 +85,43 @@ struct private_proposal_substructure_t { /** * Transforms are stored in a linked_list_t. */ - linked_list_t * transforms; + linked_list_t *transforms; + + /** + * Type of this payload, PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 + */ + payload_type_t type; }; /** - * 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 rules for a IKEv1 Proposal substructure. + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, + /* 1 Reserved Byte */ + { RESERVED_BYTE, offsetof(private_proposal_substructure_t, reserved) }, + /* 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 list */ + { PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE_V1, + offsetof(private_proposal_substructure_t, transforms) }, +}; + +/** + * Encoding rules for a IKEv2 Proposal substructure. */ -encoding_rule_t proposal_substructure_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_proposal_substructure_t, next_payload) }, /* 1 Reserved Byte */ @@ -110,9 +138,9 @@ encoding_rule_t proposal_substructure_encodings[] = { { 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) } + /* Transforms are stored in a transform substructure list */ + { PAYLOAD_LIST + TRANSFORM_SUBSTRUCTURE, + offsetof(private_proposal_substructure_t, transforms) }, }; /* @@ -131,6 +159,149 @@ encoding_rule_t proposal_substructure_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ +/** + * Encryption. + */ +typedef enum { + IKEV1_ENCR_DES_CBC = 1, + IKEV1_ENCR_IDEA_CBC = 2, + IKEV1_ENCR_BLOWFISH_CBC = 3, + IKEV1_ENCR_RC5_R16_B64_CBC = 4, + IKEV1_ENCR_3DES_CBC = 5, + IKEV1_ENCR_CAST_CBC = 6, + IKEV1_ENCR_AES_CBC = 7, + IKEV1_ENCR_CAMELLIA_CBC = 8, + /* FreeS/WAN proprietary */ + IKEV1_ENCR_SERPENT_CBC = 65004, + IKEV1_ENCR_TWOFISH_CBC = 65005, +} ikev1_encryption_t; + +/** + * IKEv1 hash. + */ +typedef enum { + IKEV1_HASH_MD5 = 1, + IKEV1_HASH_SHA1 = 2, + IKEV1_HASH_TIGER = 3, + IKEV1_HASH_SHA2_256 = 4, + IKEV1_HASH_SHA2_384 = 5, + IKEV1_HASH_SHA2_512 = 6, +} ikev1_hash_t; + +/** + * IKEv1 Transform ID IKE. + */ +typedef enum { + IKEV1_TRANSID_KEY_IKE = 1, +} ikev1_ike_transid_t; + +/** + * IKEv1 Transform ID ESP encryption algorithm. + */ +typedef enum { + IKEV1_ESP_ENCR_DES_IV64 = 1, + IKEV1_ESP_ENCR_DES = 2, + IKEV1_ESP_ENCR_3DES = 3, + IKEV1_ESP_ENCR_RC5 = 4, + IKEV1_ESP_ENCR_IDEA = 5, + IKEV1_ESP_ENCR_CAST = 6, + IKEV1_ESP_ENCR_BLOWFISH = 7, + IKEV1_ESP_ENCR_3IDEA = 8, + IKEV1_ESP_ENCR_DES_IV32 = 9, + IKEV1_ESP_ENCR_RC4 = 10, + IKEV1_ESP_ENCR_NULL = 11, + IKEV1_ESP_ENCR_AES_CBC = 12, + IKEV1_ESP_ENCR_AES_CTR = 13, + IKEV1_ESP_ENCR_AES_CCM_8 = 14, + IKEV1_ESP_ENCR_AES_CCM_12 = 15, + IKEV1_ESP_ENCR_AES_CCM_16 = 16, + IKEV1_ESP_ENCR_AES_GCM_8 = 18, + IKEV1_ESP_ENCR_AES_GCM_12 = 19, + IKEV1_ESP_ENCR_AES_GCM_16 = 20, + IKEV1_ESP_ENCR_SEED_CBC = 21, + IKEV1_ESP_ENCR_CAMELLIA = 22, + IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC = 23, + /* FreeS/WAN proprietary */ + IKEV1_ESP_ENCR_SERPENT = 252, + IKEV1_ESP_ENCR_TWOFISH = 253, +} ikev1_esp_encr_transid_t; + +/** + * IKEv1 Transform ID ESP authentication algorithm. + */ +typedef enum { + IKEV1_ESP_AUTH_HMAC_MD5 = 1, + IKEV1_ESP_AUTH_HMAC_SHA = 2, + IKEV1_ESP_AUTH_DES_MAC = 3, + IKEV1_ESP_AUTH_KPDK = 4, + IKEV1_ESP_AUTH_HMAC_SHA2_256 = 5, + IKEV1_ESP_AUTH_HMAC_SHA2_384 = 6, + IKEV1_ESP_AUTH_HMAC_SHA2_512 = 7, + IKEV1_ESP_AUTH_HMAC_RIPEMD = 8, + IKEV1_ESP_AUTH_AES_XCBC_MAC = 9, + IKEV1_ESP_AUTH_SIG_RSA = 10, + IKEV1_ESP_AUTH_AES_128_GMAC = 11, + IKEV1_ESP_AUTH_AES_192_GMAC = 12, + IKEV1_ESP_AUTH_AES_256_GMAC = 13, +} ikev1_esp_auth_transid_it; + +/** + * IKEv1 ESP Encapsulation mode. + */ +typedef enum { + IKEV1_ENCAP_TUNNEL = 1, + IKEV1_ENCAP_TRANSPORT = 2, + IKEV1_ENCAP_UDP_TUNNEL = 3, + IKEV1_ENCAP_UDP_TRANSPORT = 4, +} ikev1_esp_encap_t; + +/** + * IKEv1 Life duration types. + */ +typedef enum { + IKEV1_LIFE_TYPE_SECONDS = 1, + IKEV1_LIFE_TYPE_KILOBYTES = 2, +} ikev1_life_type_t; + +/** + * IKEv1 authentication methods + */ +typedef enum { + IKEV1_AUTH_PSK = 1, + IKEV1_AUTH_DSS_SIG = 2, + IKEV1_AUTH_RSA_SIG = 3, + IKEV1_AUTH_RSA_ENC = 4, + IKEV1_AUTH_RSA_ENC_REV = 5, + IKEV1_AUTH_ECDSA_256 = 9, + IKEV1_AUTH_ECDSA_384 = 10, + IKEV1_AUTH_ECDSA_521 = 11, + /* XAuth Modes */ + IKEV1_AUTH_XAUTH_INIT_PSK = 65001, + IKEV1_AUTH_XAUTH_RESP_PSK = 65002, + IKEV1_AUTH_XAUTH_INIT_DSS = 65003, + IKEV1_AUTH_XAUTH_RESP_DSS = 65004, + IKEV1_AUTH_XAUTH_INIT_RSA = 65005, + IKEV1_AUTH_XAUTH_RESP_RSA = 65006, + IKEV1_AUTH_XAUTH_INIT_RSA_ENC = 65007, + IKEV1_AUTH_XAUTH_RESP_RSA_ENC = 65008, + IKEV1_AUTH_XAUTH_INIT_RSA_ENC_REV = 65009, + IKEV1_AUTH_XAUTH_RESP_RSA_ENC_REV = 65010, + /* Hybrid Modes */ + IKEV1_AUTH_HYBRID_INIT_RSA = 64221, + IKEV1_AUTH_HYBRID_RESP_RSA = 64222, + IKEV1_AUTH_HYBRID_INIT_DSS = 64223, + IKEV1_AUTH_HYBRID_RESP_DSS = 64224, +} ikev1_auth_method_t; + +/** + * IKEv1 IPComp transform IDs + */ +typedef enum { + IKEV1_IPCOMP_OUI = 1, + IKEV1_IPCOMP_DEFLATE = 2, + IKEV1_IPCOMP_LZS = 3, +} ikev1_ipcomp_transform_t; + METHOD(payload_t, verify, status_t, private_proposal_substructure_t *this) { @@ -153,12 +324,19 @@ METHOD(payload_t, verify, status_t, switch (this->protocol_id) { + case PROTO_IPCOMP: + if (this->spi.len != 2) + { + DBG1(DBG_ENC, "invalid CPI length in IPCOMP proposal"); + return FAILED; + } + break; case PROTO_AH: case PROTO_ESP: if (this->spi.len != 4) { DBG1(DBG_ENC, "invalid SPI length in %N proposal", - protocol_id_names, this->protocol_id); + protocol_id_names, this->protocol_id); return FAILED; } break; @@ -188,18 +366,28 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_proposal_substructure_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_proposal_substructure_t *this, encoding_rule_t **rules) { - *rules = proposal_substructure_encodings; - *rule_count = countof(proposal_substructure_encodings); + if (this->type == PROPOSAL_SUBSTRUCTURE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_proposal_substructure_t *this) +{ + return 8 + this->spi_size; } METHOD(payload_t, get_type, payload_type_t, private_proposal_substructure_t *this) { - return PROPOSAL_SUBSTRUCTURE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -222,7 +410,7 @@ static void compute_length(private_proposal_substructure_t *this) payload_t *transform; this->transforms_count = 0; - this->proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH + this->spi.len; + this->proposal_length = get_header_length(this); enumerator = this->transforms->create_enumerator(this->transforms); while (enumerator->enumerate(enumerator, &transform)) { @@ -301,45 +489,486 @@ METHOD(proposal_substructure_t, get_spi, chunk_t, return this->spi; } -METHOD(proposal_substructure_t, get_proposal, proposal_t*, - private_proposal_substructure_t *this) +METHOD(proposal_substructure_t, get_cpi, bool, + private_proposal_substructure_t *this, u_int16_t *cpi) { - enumerator_t *enumerator; + transform_substructure_t *transform; - proposal_t *proposal; - u_int64_t spi; + enumerator_t *enumerator; - proposal = proposal_create(this->protocol_id, this->proposal_number); + if (this->protocol_id != PROTO_IPCOMP) + { + return FALSE; + } enumerator = this->transforms->create_enumerator(this->transforms); while (enumerator->enumerate(enumerator, &transform)) { - transform_type_t transform_type; - u_int16_t transform_id; - u_int16_t key_length = 0; + if (transform->get_transform_id(transform) == IKEV1_IPCOMP_DEFLATE) + { + if (cpi) + { + *cpi = *((u_int16_t*)this->spi.ptr); + } + enumerator->destroy(enumerator); + return TRUE; + } + } + enumerator->destroy(enumerator); + return FALSE; +} - transform_type = transform->get_transform_type(transform); - transform_id = transform->get_transform_id(transform); - transform->get_key_length(transform, &key_length); +/** + * Add a transform to a proposal for IKEv2 + */ +static void add_to_proposal_v2(proposal_t *proposal, + transform_substructure_t *transform) +{ + transform_attribute_t *tattr; + enumerator_t *enumerator; + u_int16_t key_length = 0; - proposal->add_algorithm(proposal, transform_type, transform_id, key_length); + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &tattr)) + { + if (tattr->get_attribute_type(tattr) == TATTR_IKEV2_KEY_LENGTH) + { + key_length = tattr->get_value(tattr); + break; + } } enumerator->destroy(enumerator); + proposal->add_algorithm(proposal, + transform->get_transform_type_or_number(transform), + transform->get_transform_id(transform), key_length); +} + +/** + * Map IKEv1 to IKEv2 algorithms + */ +typedef struct { + u_int16_t ikev1; + u_int16_t ikev2; +} algo_map_t; + +/** + * Encryption algorithm mapping + */ +static algo_map_t map_encr[] = { + { IKEV1_ENCR_DES_CBC, ENCR_DES }, + { IKEV1_ENCR_IDEA_CBC, ENCR_IDEA }, + { IKEV1_ENCR_BLOWFISH_CBC, ENCR_BLOWFISH }, + { IKEV1_ENCR_3DES_CBC, ENCR_3DES }, + { IKEV1_ENCR_CAST_CBC, ENCR_CAST }, + { IKEV1_ENCR_AES_CBC, ENCR_AES_CBC }, + { IKEV1_ENCR_CAMELLIA_CBC, ENCR_CAMELLIA_CBC }, + { IKEV1_ENCR_SERPENT_CBC, ENCR_SERPENT_CBC }, + { IKEV1_ENCR_TWOFISH_CBC, ENCR_TWOFISH_CBC }, +}; + +/** + * Integrity algorithm mapping + */ +static algo_map_t map_integ[] = { + { IKEV1_HASH_MD5, AUTH_HMAC_MD5_96 }, + { IKEV1_HASH_SHA1, AUTH_HMAC_SHA1_96 }, + { IKEV1_HASH_SHA2_256, AUTH_HMAC_SHA2_256_128 }, + { IKEV1_HASH_SHA2_384, AUTH_HMAC_SHA2_384_192 }, + { IKEV1_HASH_SHA2_512, AUTH_HMAC_SHA2_512_256 }, +}; + +/** + * PRF algorithm mapping + */ +static algo_map_t map_prf[] = { + { IKEV1_HASH_MD5, PRF_HMAC_MD5 }, + { IKEV1_HASH_SHA1, PRF_HMAC_SHA1 }, + { IKEV1_HASH_SHA2_256, PRF_HMAC_SHA2_256 }, + { IKEV1_HASH_SHA2_384, PRF_HMAC_SHA2_384 }, + { IKEV1_HASH_SHA2_512, PRF_HMAC_SHA2_512 }, +}; + +/** + * ESP encryption algorithm mapping + */ +static algo_map_t map_esp_encr[] = { + { IKEV1_ESP_ENCR_DES_IV64, ENCR_DES_IV64 }, + { IKEV1_ESP_ENCR_DES, ENCR_DES }, + { IKEV1_ESP_ENCR_3DES, ENCR_3DES }, + { IKEV1_ESP_ENCR_RC5, ENCR_RC5 }, + { IKEV1_ESP_ENCR_IDEA, ENCR_IDEA }, + { IKEV1_ESP_ENCR_CAST, ENCR_CAST }, + { IKEV1_ESP_ENCR_BLOWFISH, ENCR_BLOWFISH }, + { IKEV1_ESP_ENCR_3IDEA, ENCR_3IDEA }, + { IKEV1_ESP_ENCR_DES_IV32, ENCR_DES_IV32 }, + { IKEV1_ESP_ENCR_NULL, ENCR_NULL }, + { IKEV1_ESP_ENCR_AES_CBC, ENCR_AES_CBC }, + { IKEV1_ESP_ENCR_AES_CTR, ENCR_AES_CTR }, + { IKEV1_ESP_ENCR_AES_CCM_8, ENCR_AES_CCM_ICV8 }, + { IKEV1_ESP_ENCR_AES_CCM_12, ENCR_AES_CCM_ICV12 }, + { IKEV1_ESP_ENCR_AES_CCM_16, ENCR_AES_CCM_ICV16 }, + { IKEV1_ESP_ENCR_AES_GCM_8, ENCR_AES_GCM_ICV8 }, + { IKEV1_ESP_ENCR_AES_GCM_12, ENCR_AES_GCM_ICV12 }, + { IKEV1_ESP_ENCR_AES_GCM_16, ENCR_AES_GCM_ICV16 }, + { IKEV1_ESP_ENCR_CAMELLIA, ENCR_CAMELLIA_CBC }, + { IKEV1_ESP_ENCR_NULL_AUTH_AES_GMAC, ENCR_NULL_AUTH_AES_GMAC }, + { IKEV1_ESP_ENCR_SERPENT, ENCR_SERPENT_CBC }, + { IKEV1_ESP_ENCR_TWOFISH, ENCR_TWOFISH_CBC }, +}; + +/** + * ESP authentication algorithm mapping + */ +static algo_map_t map_esp_auth[] = { + { IKEV1_ESP_AUTH_HMAC_MD5, AUTH_HMAC_MD5_96 }, + { IKEV1_ESP_AUTH_HMAC_SHA, AUTH_HMAC_SHA1_96 }, + { IKEV1_ESP_AUTH_DES_MAC, AUTH_DES_MAC }, + { IKEV1_ESP_AUTH_KPDK, AUTH_KPDK_MD5 }, + { IKEV1_ESP_AUTH_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_128 }, + { IKEV1_ESP_AUTH_HMAC_SHA2_384, AUTH_HMAC_SHA2_384_192 }, + { IKEV1_ESP_AUTH_HMAC_SHA2_512, AUTH_HMAC_SHA2_512_256 }, + { IKEV1_ESP_AUTH_AES_XCBC_MAC, AUTH_AES_XCBC_96 }, + { IKEV1_ESP_AUTH_AES_128_GMAC, AUTH_AES_128_GMAC }, + { IKEV1_ESP_AUTH_AES_192_GMAC, AUTH_AES_192_GMAC }, + { IKEV1_ESP_AUTH_AES_256_GMAC, AUTH_AES_256_GMAC }, +}; + +/** + * Get IKEv2 algorithm from IKEv1 identifier + */ +static u_int16_t get_alg_from_ikev1(transform_type_t type, u_int16_t value) +{ + algo_map_t *map; + u_int16_t def; + int i, count; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = map_encr; + count = countof(map_encr); + def = ENCR_UNDEFINED; + break; + case INTEGRITY_ALGORITHM: + map = map_integ; + count = countof(map_integ); + def = AUTH_UNDEFINED; + break; + case PSEUDO_RANDOM_FUNCTION: + map = map_prf; + count = countof(map_prf); + def = PRF_UNDEFINED; + break; + default: + return 0; + } + for (i = 0; i < count; i++) + { + if (map[i].ikev1 == value) + { + return map[i].ikev2; + } + } + return def; +} + +/** + * Get IKEv1 algorithm from IKEv2 identifier + */ +static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value) +{ + algo_map_t *map; + int i, count; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = map_encr; + count = countof(map_encr); + break; + case INTEGRITY_ALGORITHM: + map = map_integ; + count = countof(map_integ); + break; + case PSEUDO_RANDOM_FUNCTION: + map = map_prf; + count = countof(map_prf); + break; + default: + return 0; + } + for (i = 0; i < count; i++) + { + if (map[i].ikev2 == value) + { + return map[i].ikev1; + } + } + return 0; +} + +/** + * Get IKEv2 algorithm from IKEv1 ESP transaction ID + */ +static u_int16_t get_alg_from_ikev1_transid(transform_type_t type, u_int16_t value) +{ + algo_map_t *map; + u_int16_t def; + int i, count; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = map_esp_encr; + count = countof(map_esp_encr); + def = ENCR_UNDEFINED; + break; + case INTEGRITY_ALGORITHM: + map = map_esp_auth; + count = countof(map_esp_auth); + def = AUTH_UNDEFINED; + break; + default: + return 0; + } + for (i = 0; i < count; i++) + { + if (map[i].ikev1 == value) + { + return map[i].ikev2; + } + } + return def; +} + +/** + * Get IKEv1 ESP transaction ID from IKEv2 identifier + */ +static u_int16_t get_ikev1_transid_from_alg(transform_type_t type, u_int16_t value) +{ + algo_map_t *map; + int i, count; + + switch (type) + { + case ENCRYPTION_ALGORITHM: + map = map_esp_encr; + count = countof(map_esp_encr); + break; + case INTEGRITY_ALGORITHM: + map = map_esp_auth; + count = countof(map_esp_auth); + break; + default: + return 0; + } + for (i = 0; i < count; i++) + { + if (map[i].ikev2 == value) + { + return map[i].ikev1; + } + } + return 0; +} +/** + * Get IKEv1 authentication attribute from auth_method_t + */ +static u_int16_t get_ikev1_auth(auth_method_t method) +{ + switch (method) + { + case AUTH_RSA: + return IKEV1_AUTH_RSA_SIG; + case AUTH_DSS: + return IKEV1_AUTH_DSS_SIG; + case AUTH_XAUTH_INIT_PSK: + return IKEV1_AUTH_XAUTH_INIT_PSK; + case AUTH_XAUTH_RESP_PSK: + return IKEV1_AUTH_XAUTH_RESP_PSK; + case AUTH_XAUTH_INIT_RSA: + return IKEV1_AUTH_XAUTH_INIT_RSA; + case AUTH_XAUTH_RESP_RSA: + return IKEV1_AUTH_XAUTH_RESP_RSA; + case AUTH_HYBRID_INIT_RSA: + return IKEV1_AUTH_HYBRID_INIT_RSA; + case AUTH_HYBRID_RESP_RSA: + return IKEV1_AUTH_HYBRID_RESP_RSA; + case AUTH_ECDSA_256: + return IKEV1_AUTH_ECDSA_256; + case AUTH_ECDSA_384: + return IKEV1_AUTH_ECDSA_384; + case AUTH_ECDSA_521: + return IKEV1_AUTH_ECDSA_521; + case AUTH_PSK: + default: + return IKEV1_AUTH_PSK; + } +} + +/** + * Get IKEv1 encapsulation mode + */ +static u_int16_t get_ikev1_mode(ipsec_mode_t mode, bool udp) +{ + switch (mode) + { + case MODE_TUNNEL: + return udp ? IKEV1_ENCAP_UDP_TUNNEL : IKEV1_ENCAP_TUNNEL; + case MODE_TRANSPORT: + return udp ? IKEV1_ENCAP_UDP_TRANSPORT : IKEV1_ENCAP_TRANSPORT; + default: + return IKEV1_ENCAP_TUNNEL; + } +} + +/** + * Add an IKE transform to a proposal for IKEv1 + */ +static void add_to_proposal_v1_ike(proposal_t *proposal, + transform_substructure_t *transform) +{ + transform_attribute_type_t type; + transform_attribute_t *tattr; + enumerator_t *enumerator; + u_int16_t value, key_length = 0; + u_int16_t encr = ENCR_UNDEFINED; + + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &tattr)) + { + type = tattr->get_attribute_type(tattr); + value = tattr->get_value(tattr); + switch (type) + { + case TATTR_PH1_ENCRYPTION_ALGORITHM: + encr = get_alg_from_ikev1(ENCRYPTION_ALGORITHM, value); + break; + case TATTR_PH1_KEY_LENGTH: + key_length = value; + break; + case TATTR_PH1_HASH_ALGORITHM: + proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, + get_alg_from_ikev1(INTEGRITY_ALGORITHM, value), 0); + proposal->add_algorithm(proposal, PSEUDO_RANDOM_FUNCTION, + get_alg_from_ikev1(PSEUDO_RANDOM_FUNCTION, value), 0); + break; + case TATTR_PH1_GROUP: + proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + value, 0); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + if (encr != ENCR_UNDEFINED) + { + proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, key_length); + } +} + +/** + * Add an ESP transform to a proposal for IKEv1 + */ +static void add_to_proposal_v1_esp(proposal_t *proposal, + transform_substructure_t *transform) +{ + transform_attribute_type_t type; + transform_attribute_t *tattr; + enumerator_t *enumerator; + u_int16_t encr, value, key_length = 0; + + enumerator = transform->create_attribute_enumerator(transform); + while (enumerator->enumerate(enumerator, &tattr)) + { + type = tattr->get_attribute_type(tattr); + value = tattr->get_value(tattr); + switch (type) + { + case TATTR_PH2_KEY_LENGTH: + key_length = value; + break; + case TATTR_PH2_AUTH_ALGORITHM: + proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, + get_alg_from_ikev1_transid(INTEGRITY_ALGORITHM, + value), 0); + break; + case TATTR_PH2_GROUP: + proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, + value, 0); + break; + default: + break; + } + } + enumerator->destroy(enumerator); + + /* TODO-IKEv1: handle ESN attribute */ + proposal->add_algorithm(proposal, EXTENDED_SEQUENCE_NUMBERS, + NO_EXT_SEQ_NUMBERS, 0); + encr = get_alg_from_ikev1_transid(ENCRYPTION_ALGORITHM, + transform->get_transform_id(transform)); + if (encr) + { + proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, encr, + key_length); + } +} + +METHOD(proposal_substructure_t, get_proposals, void, + private_proposal_substructure_t *this, linked_list_t *proposals) +{ + transform_substructure_t *transform; + enumerator_t *enumerator; + proposal_t *proposal = NULL; + u_int64_t spi = 0; + switch (this->spi.len) { case 4: - spi = *((u_int32_t*)this->spi.ptr); + spi = *((u_int32_t*)this->spi.ptr); break; case 8: spi = *((u_int64_t*)this->spi.ptr); break; default: - spi = 0; + break; } - proposal->set_spi(proposal, spi); - return proposal; + enumerator = this->transforms->create_enumerator(this->transforms); + while (enumerator->enumerate(enumerator, &transform)) + { + if (!proposal) + { + proposal = proposal_create(this->protocol_id, this->proposal_number); + proposal->set_spi(proposal, spi); + proposals->insert_last(proposals, proposal); + } + if (this->type == PROPOSAL_SUBSTRUCTURE) + { + add_to_proposal_v2(proposal, transform); + } + else + { + switch (this->protocol_id) + { + case PROTO_IKE: + add_to_proposal_v1_ike(proposal, transform); + break; + case PROTO_ESP: + add_to_proposal_v1_esp(proposal, transform); + break; + default: + break; + } + /* create a new proposal for each transform in IKEv1 */ + proposal = NULL; + } + } + enumerator->destroy(enumerator); } METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*, @@ -348,11 +977,170 @@ METHOD(proposal_substructure_t, create_substructure_enumerator, enumerator_t*, return this->transforms->create_enumerator(this->transforms); } +/** + * Get an attribute from any transform, 0 if not found + */ +static u_int64_t get_attr(private_proposal_substructure_t *this, + transform_attribute_type_t type) +{ + enumerator_t *transforms, *attributes; + transform_substructure_t *transform; + transform_attribute_t *attr; + + transforms = this->transforms->create_enumerator(this->transforms); + while (transforms->enumerate(transforms, &transform)) + { + attributes = transform->create_attribute_enumerator(transform); + while (attributes->enumerate(attributes, &attr)) + { + if (attr->get_attribute_type(attr) == type) + { + attributes->destroy(attributes); + transforms->destroy(transforms); + return attr->get_value(attr); + } + } + attributes->destroy(attributes); + } + transforms->destroy(transforms); + return 0; +} + +/** + * Look up a lifetime duration of a given kind in all transforms + */ +static u_int64_t get_life_duration(private_proposal_substructure_t *this, + transform_attribute_type_t type_attr, ikev1_life_type_t type, + transform_attribute_type_t dur_attr) +{ + enumerator_t *transforms, *attributes; + transform_substructure_t *transform; + transform_attribute_t *attr; + + transforms = this->transforms->create_enumerator(this->transforms); + while (transforms->enumerate(transforms, &transform)) + { + attributes = transform->create_attribute_enumerator(transform); + while (attributes->enumerate(attributes, &attr)) + { + if (attr->get_attribute_type(attr) == type_attr && + attr->get_value(attr) == type) + { /* got type attribute, look for duration following next */ + while (attributes->enumerate(attributes, &attr)) + { + if (attr->get_attribute_type(attr) == dur_attr) + { + attributes->destroy(attributes); + transforms->destroy(transforms); + return attr->get_value(attr); + } + } + } + } + attributes->destroy(attributes); + } + transforms->destroy(transforms); + return 0; +} + +METHOD(proposal_substructure_t, get_lifetime, u_int32_t, + private_proposal_substructure_t *this) +{ + u_int32_t duration; + + switch (this->protocol_id) + { + case PROTO_IKE: + return get_life_duration(this, TATTR_PH1_LIFE_TYPE, + IKEV1_LIFE_TYPE_SECONDS, TATTR_PH1_LIFE_DURATION); + case PROTO_ESP: + duration = get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE, + IKEV1_LIFE_TYPE_SECONDS, TATTR_PH2_SA_LIFE_DURATION); + if (!duration) + { /* default to 8 hours, RFC 2407 */ + return 28800; + } + return duration; + default: + return 0; + } +} + +METHOD(proposal_substructure_t, get_lifebytes, u_int64_t, + private_proposal_substructure_t *this) +{ + switch (this->protocol_id) + { + case PROTO_ESP: + return 1000 * get_life_duration(this, TATTR_PH2_SA_LIFE_TYPE, + IKEV1_LIFE_TYPE_KILOBYTES, TATTR_PH2_SA_LIFE_DURATION); + case PROTO_IKE: + default: + return 0; + } +} + +METHOD(proposal_substructure_t, get_auth_method, auth_method_t, + private_proposal_substructure_t *this) +{ + switch (get_attr(this, TATTR_PH1_AUTH_METHOD)) + { + case IKEV1_AUTH_PSK: + return AUTH_PSK; + case IKEV1_AUTH_RSA_SIG: + return AUTH_RSA; + case IKEV1_AUTH_DSS_SIG: + return AUTH_DSS; + case IKEV1_AUTH_XAUTH_INIT_PSK: + return AUTH_XAUTH_INIT_PSK; + case IKEV1_AUTH_XAUTH_RESP_PSK: + return AUTH_XAUTH_RESP_PSK; + case IKEV1_AUTH_XAUTH_INIT_RSA: + return AUTH_XAUTH_INIT_RSA; + case IKEV1_AUTH_XAUTH_RESP_RSA: + return AUTH_XAUTH_RESP_RSA; + case IKEV1_AUTH_HYBRID_INIT_RSA: + return AUTH_HYBRID_INIT_RSA; + case IKEV1_AUTH_HYBRID_RESP_RSA: + return AUTH_HYBRID_RESP_RSA; + case IKEV1_AUTH_ECDSA_256: + return AUTH_ECDSA_256; + case IKEV1_AUTH_ECDSA_384: + return AUTH_ECDSA_384; + case IKEV1_AUTH_ECDSA_521: + return AUTH_ECDSA_521; + default: + return AUTH_NONE; + } +} + +METHOD(proposal_substructure_t, get_encap_mode, ipsec_mode_t, + private_proposal_substructure_t *this, bool *udp) +{ + *udp = FALSE; + switch (get_attr(this, TATTR_PH2_ENCAP_MODE)) + { + case IKEV1_ENCAP_TRANSPORT: + return MODE_TRANSPORT; + case IKEV1_ENCAP_TUNNEL: + return MODE_TUNNEL; + case IKEV1_ENCAP_UDP_TRANSPORT: + *udp = TRUE; + return MODE_TRANSPORT; + case IKEV1_ENCAP_UDP_TUNNEL: + *udp = TRUE; + return MODE_TUNNEL; + default: + /* default to TUNNEL, RFC 2407 says implementation specific */ + return MODE_TUNNEL; + } +} + METHOD2(payload_t, proposal_substructure_t, destroy, void, private_proposal_substructure_t *this) { this->transforms->destroy_offset(this->transforms, - offsetof(transform_substructure_t, destroy)); + offsetof(payload_t, destroy)); chunk_free(&this->spi); free(this); } @@ -360,7 +1148,7 @@ METHOD2(payload_t, proposal_substructure_t, destroy, void, /* * Described in header. */ -proposal_substructure_t *proposal_substructure_create() +proposal_substructure_t *proposal_substructure_create(payload_type_t type) { private_proposal_substructure_t *this; @@ -369,6 +1157,7 @@ proposal_substructure_t *proposal_substructure_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -380,39 +1169,197 @@ proposal_substructure_t *proposal_substructure_create() .set_protocol_id = _set_protocol_id, .get_protocol_id = _get_protocol_id, .set_is_last_proposal = _set_is_last_proposal, - .get_proposal = _get_proposal, + .get_proposals = _get_proposals, .create_substructure_enumerator = _create_substructure_enumerator, .set_spi = _set_spi, .get_spi = _get_spi, + .get_cpi = _get_cpi, + .get_lifetime = _get_lifetime, + .get_lifebytes = _get_lifebytes, + .get_auth_method = _get_auth_method, + .get_encap_mode = _get_encap_mode, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .proposal_length = PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH, .transforms = linked_list_create(), + .type = type, ); + compute_length(this); return &this->public; } -/* - * Described in header. +/** + * Add an IKEv1 IKE proposal to the substructure */ -proposal_substructure_t *proposal_substructure_create_from_proposal( - proposal_t *proposal) +static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, + proposal_t *proposal, u_int32_t lifetime, + auth_method_t method, int number) { transform_substructure_t *transform; - private_proposal_substructure_t *this; u_int16_t alg, key_size; enumerator_t *enumerator; - this = (private_proposal_substructure_t*)proposal_substructure_create(); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, + number, IKEV1_TRANSID_KEY_IKE); + + enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_from_alg(ENCRYPTION_ALGORITHM, alg); + if (alg) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_ENCRYPTION_ALGORITHM, alg)); + if (key_size) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_KEY_LENGTH, key_size)); + } + } + } + enumerator->destroy(enumerator); + + /* encode the integrity algorithm as hash and assume use the same PRF */ + enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg); + if (alg) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_HASH_ALGORITHM, alg)); + } + } + enumerator->destroy(enumerator); + + enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_GROUP, alg)); + } + enumerator->destroy(enumerator); + + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_AUTH_METHOD, get_ikev1_auth(method))); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH1_LIFE_DURATION, lifetime)); + + add_transform_substructure(this, transform); +} + +/** + * Add an IKEv1 ESP proposal to the substructure + */ +static void set_from_proposal_v1_esp(private_proposal_substructure_t *this, + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + ipsec_mode_t mode, bool udp, int number) +{ + transform_substructure_t *transform = NULL; + u_int16_t alg, key_size; + enumerator_t *enumerator; + + enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_transid_from_alg(ENCRYPTION_ALGORITHM, alg); + if (alg) + { + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, + number, alg); + if (key_size) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_KEY_LENGTH, key_size)); + } + } + } + enumerator->destroy(enumerator); + if (!transform) + { + return; + } + + enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + alg = get_ikev1_transid_from_alg(INTEGRITY_ALGORITHM, alg); + if (alg) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_AUTH_ALGORITHM, alg)); + } + } + enumerator->destroy(enumerator); + + enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); + if (enumerator->enumerate(enumerator, &alg, &key_size)) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_GROUP, alg)); + } + enumerator->destroy(enumerator); + + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp))); + if (lifetime) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifetime)); + } + if (lifebytes) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000)); + } + + add_transform_substructure(this, transform); +} + +/** + * Add an IKEv2 proposal to the substructure + */ +static void set_from_proposal_v2(private_proposal_substructure_t *this, + proposal_t *proposal) +{ + transform_substructure_t *transform; + u_int16_t alg, key_size; + enumerator_t *enumerator; /* encryption algorithm is only available in ESP */ enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(ENCRYPTION_ALGORITHM, - alg, key_size); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + ENCRYPTION_ALGORITHM, alg); + if (key_size) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE, + TATTR_IKEV2_KEY_LENGTH, key_size)); + } add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -421,8 +1368,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(INTEGRITY_ALGORITHM, - alg, key_size); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + INTEGRITY_ALGORITHM, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -431,8 +1378,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, PSEUDO_RANDOM_FUNCTION); while (enumerator->enumerate(enumerator, &alg, &key_size)) { - transform = transform_substructure_create_type(PSEUDO_RANDOM_FUNCTION, - alg, key_size); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + PSEUDO_RANDOM_FUNCTION, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -441,8 +1388,8 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, DIFFIE_HELLMAN_GROUP); while (enumerator->enumerate(enumerator, &alg, NULL)) { - transform = transform_substructure_create_type(DIFFIE_HELLMAN_GROUP, - alg, 0); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + DIFFIE_HELLMAN_GROUP, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); @@ -451,27 +1398,36 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( enumerator = proposal->create_enumerator(proposal, EXTENDED_SEQUENCE_NUMBERS); while (enumerator->enumerate(enumerator, &alg, NULL)) { - transform = transform_substructure_create_type(EXTENDED_SEQUENCE_NUMBERS, - alg, 0); + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE, + EXTENDED_SEQUENCE_NUMBERS, alg); add_transform_substructure(this, transform); } enumerator->destroy(enumerator); +} + +/** + * Set SPI and other data from proposal, compute length + */ +static void set_data(private_proposal_substructure_t *this, proposal_t *proposal) +{ + u_int64_t spi64; + u_int32_t spi32; /* add SPI, if necessary */ switch (proposal->get_protocol(proposal)) { case PROTO_AH: case PROTO_ESP: - this->spi_size = this->spi.len = 4; - this->spi.ptr = malloc(this->spi_size); - *((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal); + spi32 = proposal->get_spi(proposal); + this->spi = chunk_clone(chunk_from_thing(spi32)); + this->spi_size = this->spi.len; break; case PROTO_IKE: - if (proposal->get_spi(proposal)) + spi64 = proposal->get_spi(proposal); + if (spi64) { /* IKE only uses SPIS when rekeying, but on initial setup */ - this->spi_size = this->spi.len = 8; - this->spi.ptr = malloc(this->spi_size); - *((u_int64_t*)this->spi.ptr) = proposal->get_spi(proposal); + this->spi = chunk_clone(chunk_from_thing(spi64)); + this->spi_size = this->spi.len; } break; default: @@ -480,6 +1436,144 @@ proposal_substructure_t *proposal_substructure_create_from_proposal( this->proposal_number = proposal->get_number(proposal); this->protocol_id = proposal->get_protocol(proposal); compute_length(this); +} + +/* + * Described in header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v2( + proposal_t *proposal) +{ + private_proposal_substructure_t *this; + + this = (private_proposal_substructure_t*) + proposal_substructure_create(SECURITY_ASSOCIATION); + set_from_proposal_v2(this, proposal); + set_data(this, proposal); + + return &this->public; +} + +/** + * See header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v1( + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) +{ + private_proposal_substructure_t *this; + + this = (private_proposal_substructure_t*) + proposal_substructure_create(PROPOSAL_SUBSTRUCTURE_V1); + switch (proposal->get_protocol(proposal)) + { + case PROTO_IKE: + set_from_proposal_v1_ike(this, proposal, lifetime, auth, 1); + break; + case PROTO_ESP: + set_from_proposal_v1_esp(this, proposal, lifetime, + lifebytes, mode, udp, 1); + break; + default: + break; + } + set_data(this, proposal); + + return &this->public; +} + +/** + * See header. + */ +proposal_substructure_t *proposal_substructure_create_from_proposals_v1( + linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp) +{ + private_proposal_substructure_t *this = NULL; + enumerator_t *enumerator; + proposal_t *proposal; + int number = 0; + + enumerator = proposals->create_enumerator(proposals); + while (enumerator->enumerate(enumerator, &proposal)) + { + if (!this) + { + this = (private_proposal_substructure_t*) + proposal_substructure_create_from_proposal_v1( + proposal, lifetime, lifebytes, auth, mode, udp); + ++number; + } + else + { + switch (proposal->get_protocol(proposal)) + { + case PROTO_IKE: + set_from_proposal_v1_ike(this, proposal, lifetime, + auth, ++number); + break; + case PROTO_ESP: + set_from_proposal_v1_esp(this, proposal, lifetime, + lifebytes, mode, udp, ++number); + break; + default: + break; + } + } + } + enumerator->destroy(enumerator); + + return &this->public; +} + +/** + * See header. + */ +proposal_substructure_t *proposal_substructure_create_for_ipcomp_v1( + u_int32_t lifetime, u_int64_t lifebytes, u_int16_t cpi, + ipsec_mode_t mode, bool udp, u_int8_t proposal_number) +{ + private_proposal_substructure_t *this; + transform_substructure_t *transform; + + + this = (private_proposal_substructure_t*) + proposal_substructure_create(PROPOSAL_SUBSTRUCTURE_V1); + + /* we currently support DEFLATE only */ + transform = transform_substructure_create_type(TRANSFORM_SUBSTRUCTURE_V1, + 1, IKEV1_IPCOMP_DEFLATE); + + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_ENCAP_MODE, get_ikev1_mode(mode, udp))); + if (lifetime) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_SECONDS)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifetime)); + } + if (lifebytes) + { + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_TYPE, IKEV1_LIFE_TYPE_KILOBYTES)); + transform->add_transform_attribute(transform, + transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, + TATTR_PH2_SA_LIFE_DURATION, lifebytes / 1000)); + } + + add_transform_substructure(this, transform); + + this->spi = chunk_clone(chunk_from_thing(cpi)); + this->spi_size = this->spi.len; + this->protocol_id = PROTO_IPCOMP; + this->proposal_number = proposal_number; + + compute_length(this); return &this->public; } diff --git a/src/libcharon/encoding/payloads/proposal_substructure.h b/src/libcharon/encoding/payloads/proposal_substructure.h index d0ba1fd2a..5d42a6116 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.h +++ b/src/libcharon/encoding/payloads/proposal_substructure.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -29,17 +30,11 @@ typedef struct proposal_substructure_t proposal_substructure_t; #include <encoding/payloads/transform_substructure.h> #include <config/proposal.h> #include <utils/linked_list.h> - +#include <kernel/kernel_ipsec.h> +#include <sa/authenticator.h> /** - * Length of the proposal substructure header (without spi). - */ -#define PROPOSAL_SUBSTRUCTURE_HEADER_LENGTH 8 - -/** - * Class representing an IKEv2-PROPOSAL SUBSTRUCTURE. - * - * The PROPOSAL SUBSTRUCTURE format is described in RFC section 3.3.1. + * Class representing an IKEv1/IKEv2 proposal substructure. */ struct proposal_substructure_t { @@ -58,7 +53,7 @@ struct proposal_substructure_t { /** * get proposal number of current proposal. * - * @return proposal number of current proposal substructure. + * @return proposal number of current proposal substructure. */ u_int8_t (*get_proposal_number) (proposal_substructure_t *this); @@ -73,7 +68,7 @@ struct proposal_substructure_t { /** * get protocol id of current proposal. * - * @return protocol id of current proposal substructure. + * @return protocol id of current proposal substructure. */ u_int8_t (*get_protocol_id) (proposal_substructure_t *this); @@ -90,7 +85,7 @@ struct proposal_substructure_t { /** * Returns the currently set SPI of this proposal. * - * @return chunk_t pointing to the value + * @return chunk_t pointing to the value */ chunk_t (*get_spi) (proposal_substructure_t *this); @@ -104,11 +99,19 @@ struct proposal_substructure_t { void (*set_spi) (proposal_substructure_t *this, chunk_t spi); /** - * Get a proposal_t from the propsal_substructure_t. + * Gets the CPI of the current proposal (IKEv1 only). + * + * @param cpi the CPI if a supported algorithm is proposed + * @return TRUE if a supported algorithm is proposed + */ + bool (*get_cpi) (proposal_substructure_t *this, u_int16_t *cpi); + + /** + * Get proposals contained in a propsal_substructure_t. * - * @return proposal_t + * @param list list to add created proposals to */ - proposal_t * (*get_proposal) (proposal_substructure_t *this); + void (*get_proposals) (proposal_substructure_t *this, linked_list_t *list); /** * Create an enumerator over transform substructures. @@ -118,6 +121,35 @@ struct proposal_substructure_t { enumerator_t* (*create_substructure_enumerator)(proposal_substructure_t *this); /** + * Get the (shortest) lifetime of a proposal (IKEv1 only). + * + * @return lifetime, in seconds + */ + u_int32_t (*get_lifetime)(proposal_substructure_t *this); + + /** + * Get the (shortest) life duration of a proposal (IKEv1 only). + * + * @return life duration, in bytes + */ + u_int64_t (*get_lifebytes)(proposal_substructure_t *this); + + /** + * Get the first authentication method from the proposal (IKEv1 only). + * + * @return auth method, or AUTH_NONE + */ + auth_method_t (*get_auth_method)(proposal_substructure_t *this); + + /** + * Get the (first) encapsulation mode from a proposal (IKEv1 only). + * + * @param udp set to TRUE if UDP encapsulation used + * @return ipsec encapsulation mode + */ + ipsec_mode_t (*get_encap_mode)(proposal_substructure_t *this, bool *udp); + + /** * Destroys an proposal_substructure_t object. */ void (*destroy) (proposal_substructure_t *this); @@ -126,17 +158,63 @@ struct proposal_substructure_t { /** * Creates an empty proposal_substructure_t object * - * @return proposal_substructure_t object + * @param type PROPOSAL_SUBSTRUCTURE or PROPOSAL_SUBSTRUCTURE_V1 + * @return proposal_substructure_t object */ -proposal_substructure_t *proposal_substructure_create(void); +proposal_substructure_t *proposal_substructure_create(payload_type_t type); /** - * Creates a proposal_substructure_t from a proposal_t. + * Creates an IKEv2 proposal_substructure_t from a proposal_t. * - * @param proposal proposal to build a substruct out of it - * @return proposal_substructure_t object + * @param proposal proposal to build a substruct out of it + * @return proposal_substructure_t PROPOSAL_SUBSTRUCTURE */ -proposal_substructure_t *proposal_substructure_create_from_proposal( +proposal_substructure_t *proposal_substructure_create_from_proposal_v2( proposal_t *proposal); +/** + * Creates an IKEv1 proposal_substructure_t from a proposal_t. + * + * @param proposal proposal to build a substruct out of it + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @return proposal_substructure_t object PROPOSAL_SUBSTRUCTURE_V1 + */ +proposal_substructure_t *proposal_substructure_create_from_proposal_v1( + proposal_t *proposal, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); + +/** + * Creates an IKEv1 proposal_substructure_t from a list of proposal_t. + * + * @param proposals list of proposal_t to encode in a substructure + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @return IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1 + */ +proposal_substructure_t *proposal_substructure_create_from_proposals_v1( + linked_list_t *proposals, u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp); + +/** + * Creates an IKEv1 proposal_substructure_t for IPComp with the given + * proposal_number (e.g. of a ESP proposal to bundle them). + * + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param cpi the CPI to be used + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @param proposal_number the proposal number of the proposal to be linked + * @return IKEv1 proposal_substructure_t PROPOSAL_SUBSTRUCTURE_V1 + */ +proposal_substructure_t *proposal_substructure_create_for_ipcomp_v1( + u_int32_t lifetime, u_int64_t lifebytes, u_int16_t cpi, + ipsec_mode_t mode, bool udp, u_int8_t proposal_number); #endif /** PROPOSAL_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index 010f63cfd..adf19aa67 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2012 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -22,6 +23,8 @@ #include <utils/linked_list.h> #include <daemon.h> +/* IKEv1 situation */ +#define SIT_IDENTITY_ONLY 1 typedef struct private_sa_payload_t private_sa_payload_t; @@ -48,7 +51,7 @@ struct private_sa_payload_t { /** * Reserved bits */ - bool reserved[7]; + bool reserved[8]; /** * Length of this payload. @@ -58,21 +61,75 @@ struct private_sa_payload_t { /** * Proposals in this payload are stored in a linked_list_t. */ - linked_list_t * proposals; + linked_list_t *proposals; + + /** + * Type of this payload, V1 or V2 + */ + payload_type_t type; + + /** + * IKEv1 DOI + */ + u_int32_t doi; + + /** + * IKEv1 situation + */ + u_int32_t situation; }; /** - * 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 rules for IKEv1 SA payload */ -encoding_rule_t sa_payload_encodings[] = { +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_sa_payload_t, next_payload) }, + /* 8 reserved bits */ + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[3]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[4]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[5]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, + { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[7]) }, + /* Length of the whole SA payload*/ + { PAYLOAD_LENGTH, offsetof(private_sa_payload_t, payload_length) }, + /* DOI*/ + { U_INT_32, offsetof(private_sa_payload_t, doi) }, + /* Situation*/ + { U_INT_32, offsetof(private_sa_payload_t, situation) }, + /* Proposals are stored in a proposal substructure list */ + { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE_V1, + 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 ! RESERVED ! Payload Length ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! DOI ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! Situation ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + ! ! + ~ <Proposals> ~ + ! ! + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +*/ + +/** + * Encoding rules for IKEv2 SA payload + */ +static encoding_rule_t encodings_v2[] = { /* 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 */ + /* 7 Bit reserved bits */ { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[0]) }, { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[1]) }, { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[2]) }, @@ -82,9 +139,9 @@ encoding_rule_t sa_payload_encodings[] = { { RESERVED_BIT, offsetof(private_sa_payload_t, reserved[6]) }, /* 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) }, + /* Proposals are stored in a proposal substructure list */ + { PAYLOAD_LIST + PROPOSAL_SUBSTRUCTURE, + offsetof(private_sa_payload_t, proposals) }, }; /* @@ -102,11 +159,16 @@ encoding_rule_t sa_payload_encodings[] = { METHOD(payload_t, verify, status_t, private_sa_payload_t *this) { - int expected_number = 1, current_number; + int expected_number = 0, current_number; status_t status = SUCCESS; enumerator_t *enumerator; proposal_substructure_t *substruct; + if (this->type == SECURITY_ASSOCIATION) + { + expected_number = 1; + } + /* check proposal numbering */ enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, (void**)&substruct)) @@ -131,17 +193,32 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_sa_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_sa_payload_t *this, encoding_rule_t **rules) +{ + if (this->type == SECURITY_ASSOCIATION_V1) + { + *rules = encodings_v1; + return countof(encodings_v1); + } + *rules = encodings_v2; + return countof(encodings_v2); +} + +METHOD(payload_t, get_header_length, int, + private_sa_payload_t *this) { - *rules = sa_payload_encodings; - *rule_count = countof(sa_payload_encodings); + if (this->type == SECURITY_ASSOCIATION_V1) + { + return 12; + } + return 4; } METHOD(payload_t, get_type, payload_type_t, private_sa_payload_t *this) { - return SECURITY_ASSOCIATION; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -163,16 +240,15 @@ static void compute_length(private_sa_payload_t *this) { enumerator_t *enumerator; payload_t *current; - size_t length = SA_PAYLOAD_HEADER_LENGTH; + + this->payload_length = get_header_length(this); enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, (void **)¤t)) { - length += current->get_length(current); + this->payload_length += current->get_length(current); } enumerator->destroy(enumerator); - - this->payload_length = length; } METHOD(payload_t, get_length, size_t, @@ -181,14 +257,16 @@ METHOD(payload_t, get_length, size_t, return this->payload_length; } -METHOD(sa_payload_t, add_proposal, void, - private_sa_payload_t *this, proposal_t *proposal) +/** + * Create a transform substructure from a proposal, add to payload + */ +static void add_proposal_v2(private_sa_payload_t *this, proposal_t *proposal) { proposal_substructure_t *substruct, *last; u_int count; + substruct = proposal_substructure_create_from_proposal_v2(proposal); count = this->proposals->get_count(this->proposals); - substruct = proposal_substructure_create_from_proposal(proposal); if (count > 0) { this->proposals->get_last(this->proposals, (void**)&last); @@ -215,15 +293,19 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*, int ignore_struct_number = 0; enumerator_t *enumerator; proposal_substructure_t *substruct; - linked_list_t *list; - proposal_t *proposal; + linked_list_t *substructs, *list; + + if (this->type == SECURITY_ASSOCIATION_V1) + { /* IKEv1 proposals start with 0 */ + struct_number = ignore_struct_number = -1; + } - list = linked_list_create(); /* we do not support proposals split up to two proposal substructures, as * AH+ESP bundles are not supported in RFC4301 anymore. * To handle such structures safely, we just skip proposals with multiple * protocols. */ + substructs = linked_list_create(); enumerator = this->proposals->create_enumerator(this->proposals); while (enumerator->enumerate(enumerator, &substruct)) { @@ -231,22 +313,80 @@ METHOD(sa_payload_t, get_proposals, linked_list_t*, if (substruct->get_proposal_number(substruct) == struct_number) { if (ignore_struct_number < struct_number) - { - /* remove an already added, if first of series */ - list->remove_last(list, (void**)&proposal); - proposal->destroy(proposal); + { /* remove an already added, if first of series */ + substructs->remove_last(substructs, (void**)&substruct); ignore_struct_number = struct_number; } continue; } struct_number++; - proposal = substruct->get_proposal(substruct); - if (proposal) + substructs->insert_last(substructs, substruct); + } + enumerator->destroy(enumerator); + + /* generate proposals from substructs */ + list = linked_list_create(); + enumerator = substructs->create_enumerator(substructs); + while (enumerator->enumerate(enumerator, &substruct)) + { + substruct->get_proposals(substruct, list); + } + enumerator->destroy(enumerator); + substructs->destroy(substructs); + return list; +} + +METHOD(sa_payload_t, get_ipcomp_proposals, linked_list_t*, + private_sa_payload_t *this, u_int16_t *cpi) +{ + int current_proposal = -1, unsupported_proposal = -1; + enumerator_t *enumerator; + proposal_substructure_t *substruct, *esp = NULL, *ipcomp = NULL; + linked_list_t *list; + + /* we currently only support the combination ESP+IPComp, find the first */ + enumerator = this->proposals->create_enumerator(this->proposals); + while (enumerator->enumerate(enumerator, &substruct)) + { + u_int8_t proposal_number = substruct->get_proposal_number(substruct); + u_int8_t protocol_id = substruct->get_protocol_id(substruct); + + if (proposal_number == unsupported_proposal) + { + continue; + } + if (protocol_id != PROTO_ESP && protocol_id != PROTO_IPCOMP) + { /* unsupported combination */ + esp = ipcomp = NULL; + unsupported_proposal = current_proposal; + continue; + } + if (proposal_number != current_proposal) + { /* start of a new proposal */ + if (esp && ipcomp) + { /* previous proposal is valid */ + break; + } + esp = ipcomp = NULL; + current_proposal = proposal_number; + } + switch (protocol_id) { - list->insert_last(list, proposal); + case PROTO_ESP: + esp = substruct; + break; + case PROTO_IPCOMP: + ipcomp = substruct; + break; } } enumerator->destroy(enumerator); + + list = linked_list_create(); + if (esp && ipcomp && ipcomp->get_cpi(ipcomp, cpi)) + { + esp->get_proposals(esp, list); + } return list; } @@ -256,18 +396,86 @@ METHOD(sa_payload_t, create_substructure_enumerator, enumerator_t*, return this->proposals->create_enumerator(this->proposals); } +METHOD(sa_payload_t, get_lifetime, u_int32_t, + private_sa_payload_t *this) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + u_int32_t lifetime = 0; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + lifetime = substruct->get_lifetime(substruct); + } + enumerator->destroy(enumerator); + + return lifetime; +} + +METHOD(sa_payload_t, get_lifebytes, u_int64_t, + private_sa_payload_t *this) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + u_int64_t lifebytes = 0; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + lifebytes = substruct->get_lifebytes(substruct); + } + enumerator->destroy(enumerator); + + return lifebytes; +} + +METHOD(sa_payload_t, get_auth_method, auth_method_t, + private_sa_payload_t *this) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + auth_method_t method = AUTH_NONE; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + method = substruct->get_auth_method(substruct); + } + enumerator->destroy(enumerator); + + return method; +} + +METHOD(sa_payload_t, get_encap_mode, ipsec_mode_t, + private_sa_payload_t *this, bool *udp) +{ + proposal_substructure_t *substruct; + enumerator_t *enumerator; + ipsec_mode_t mode = MODE_NONE; + + enumerator = this->proposals->create_enumerator(this->proposals); + if (enumerator->enumerate(enumerator, &substruct)) + { + mode = substruct->get_encap_mode(substruct, udp); + } + enumerator->destroy(enumerator); + + return mode; +} + METHOD2(payload_t, sa_payload_t, destroy, void, private_sa_payload_t *this) { this->proposals->destroy_offset(this->proposals, - offsetof(proposal_substructure_t, destroy)); + offsetof(payload_t, destroy)); free(this); } /* * Described in header. */ -sa_payload_t *sa_payload_create() +sa_payload_t *sa_payload_create(payload_type_t type) { private_sa_payload_t *this; @@ -276,38 +484,49 @@ sa_payload_t *sa_payload_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, .get_type = _get_type, .destroy = _destroy, }, - .add_proposal = _add_proposal, .get_proposals = _get_proposals, + .get_ipcomp_proposals = _get_ipcomp_proposals, .create_substructure_enumerator = _create_substructure_enumerator, + .get_lifetime = _get_lifetime, + .get_lifebytes = _get_lifebytes, + .get_auth_method = _get_auth_method, + .get_encap_mode = _get_encap_mode, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = SA_PAYLOAD_HEADER_LENGTH, .proposals = linked_list_create(), + .type = type, + /* for IKEv1 only */ + .doi = IKEV1_DOI_IPSEC, + .situation = SIT_IDENTITY_ONLY, ); + + compute_length(this); + return &this->public; } /* * Described in header. */ -sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals) +sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals) { private_sa_payload_t *this; enumerator_t *enumerator; proposal_t *proposal; - this = (private_sa_payload_t*)sa_payload_create(); + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); enumerator = proposals->create_enumerator(proposals); while (enumerator->enumerate(enumerator, &proposal)) { - add_proposal(this, proposal); + add_proposal_v2(this, proposal); } enumerator->destroy(enumerator); @@ -317,12 +536,71 @@ sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals) /* * Described in header. */ -sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal) +sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal) +{ + private_sa_payload_t *this; + + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION); + add_proposal_v2(this, proposal); + + return &this->public; + +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp, + u_int16_t cpi) { + proposal_substructure_t *substruct; private_sa_payload_t *this; - this = (private_sa_payload_t*)sa_payload_create(); - add_proposal(this, proposal); + this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1); + + /* IKEv1 encodes multiple proposals in a single substructure + * TODO-IKEv1: Encode ESP+AH proposals in two substructs with same num */ + substruct = proposal_substructure_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp); + this->proposals->insert_last(this->proposals, substruct); + substruct->set_is_last_proposal(substruct, FALSE); + if (cpi) + { + u_int8_t proposal_number = substruct->get_proposal_number(substruct); + + substruct = proposal_substructure_create_for_ipcomp_v1(lifetime, + lifebytes, cpi, mode, udp, proposal_number); + this->proposals->insert_last(this->proposals, substruct); + substruct->set_is_last_proposal(substruct, FALSE); + /* add the proposals again without IPComp */ + substruct = proposal_substructure_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp); + substruct->set_proposal_number(substruct, proposal_number + 1); + this->proposals->insert_last(this->proposals, substruct); + } + substruct->set_is_last_proposal(substruct, TRUE); + compute_length(this); + + return &this->public; +} + +/* + * Described in header. + */ +sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp, + u_int16_t cpi) +{ + private_sa_payload_t *this; + linked_list_t *proposals; + proposals = linked_list_create(); + proposals->insert_last(proposals, proposal); + this = (private_sa_payload_t*)sa_payload_create_from_proposals_v1(proposals, + lifetime, lifebytes, auth, mode, udp, cpi); + proposals->destroy(proposals); return &this->public; } diff --git a/src/libcharon/encoding/payloads/sa_payload.h b/src/libcharon/encoding/payloads/sa_payload.h index cc8c481c8..9a88cccd5 100644 --- a/src/libcharon/encoding/payloads/sa_payload.h +++ b/src/libcharon/encoding/payloads/sa_payload.h @@ -28,14 +28,11 @@ typedef struct sa_payload_t sa_payload_t; #include <encoding/payloads/payload.h> #include <encoding/payloads/proposal_substructure.h> #include <utils/linked_list.h> +#include <kernel/kernel_ipsec.h> +#include <sa/authenticator.h> /** - * SA_PAYLOAD length in bytes without any proposal substructure. - */ -#define SA_PAYLOAD_HEADER_LENGTH 4 - -/** - * Class representing an IKEv2-SA Payload. + * Class representing an IKEv1 or IKEv2 SA Payload. * * The SA Payload format is described in RFC section 3.3. */ @@ -49,16 +46,47 @@ struct sa_payload_t { /** * Gets the proposals in this payload as a list. * - * @return a list containing proposal_t s + * @return a list containing proposal_ts */ linked_list_t *(*get_proposals) (sa_payload_t *this); /** - * Add a child proposal (AH/ESP) to the payload. + * Gets the proposals from the first proposal in this payload with IPComp + * enabled (IKEv1 only). + * + * @param cpi the CPI of the first IPComp (sub)proposal + * @return a list containing proposal_ts + */ + linked_list_t *(*get_ipcomp_proposals) (sa_payload_t *this, u_int16_t *cpi); + + /** + * Get the (shortest) lifetime of a proposal (IKEv1 only). + * + * @return lifetime, in seconds + */ + u_int32_t (*get_lifetime)(sa_payload_t *this); + + /** + * Get the (shortest) life duration of a proposal (IKEv1 only). + * + * @return life duration, in bytes + */ + u_int64_t (*get_lifebytes)(sa_payload_t *this); + + /** + * Get the first authentication method from the proposal (IKEv1 only). * - * @param proposal child proposal to add to the payload + * @return auth method, or AUTH_NONE */ - void (*add_proposal) (sa_payload_t *this, proposal_t *proposal); + auth_method_t (*get_auth_method)(sa_payload_t *this); + + /** + * Get the (first) encapsulation mode from a proposal (IKEv1 only). + * + * @param udp set to TRUE if UDP encapsulation used + * @return ipsec encapsulation mode + */ + ipsec_mode_t (*get_encap_mode)(sa_payload_t *this, bool *udp); /** * Create an enumerator over all proposal substructures. @@ -76,27 +104,59 @@ struct sa_payload_t { /** * Creates an empty sa_payload_t object * + * @param type SECURITY_ASSOCIATION or SECURITY_ASSOCIATION_V1 * @return created sa_payload_t object */ -sa_payload_t *sa_payload_create(void); +sa_payload_t *sa_payload_create(payload_type_t type); /** - * Creates a sa_payload_t object from a list of proposals. + * Creates an IKEv2 sa_payload_t object from a list of proposals. * * @param proposals list of proposals to build the payload from * @return sa_payload_t object */ -sa_payload_t *sa_payload_create_from_proposal_list(linked_list_t *proposals); +sa_payload_t *sa_payload_create_from_proposals_v2(linked_list_t *proposals); /** - * Creates a sa_payload_t object from a single proposal. + * Creates an IKEv2 sa_payload_t object from a single proposal. * - * This is only for convenience. Use sa_payload_create_from_proposal_list - * if you want to add more than one proposal. + * @param proposal proposal from which the payload should be built. + * @return sa_payload_t object + */ +sa_payload_t *sa_payload_create_from_proposal_v2(proposal_t *proposal); + +/** + * Creates an IKEv1 sa_payload_t object from a list of proposals. + * + * @param proposals list of proposals to build the payload from + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @param cpi CPI in case IPComp should be used + * @return sa_payload_t object + */ +sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp, + u_int16_t cpi); + +/** + * Creates an IKEv1 sa_payload_t object from a single proposal. * * @param proposal proposal from which the payload should be built. + * @param lifetime lifetime in seconds + * @param lifebytes lifebytes, in bytes + * @param auth authentication method to use, or AUTH_NONE + * @param mode IPsec encapsulation mode, TRANSPORT or TUNNEL + * @param udp TRUE to use UDP encapsulation + * @param cpi CPI in case IPComp should be used * @return sa_payload_t object */ -sa_payload_t *sa_payload_create_from_proposal(proposal_t *proposal); +sa_payload_t *sa_payload_create_from_proposal_v1(proposal_t *proposal, + u_int32_t lifetime, u_int64_t lifebytes, + auth_method_t auth, ipsec_mode_t mode, bool udp, + u_int16_t cpi); #endif /** SA_PAYLOAD_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.c b/src/libcharon/encoding/payloads/traffic_selector_substructure.c index df36e4383..378f5bbc3 100644 --- a/src/libcharon/encoding/payloads/traffic_selector_substructure.c +++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.c @@ -74,7 +74,7 @@ struct private_traffic_selector_substructure_t { * The defined offsets are the positions in a object of type * private_traffic_selector_substructure_t. */ -encoding_rule_t traffic_selector_substructure_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next ts type*/ { TS_TYPE, offsetof(private_traffic_selector_substructure_t, ts_type) }, /* 1 Byte IP protocol id*/ @@ -148,12 +148,17 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_traffic_selector_substructure_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_traffic_selector_substructure_t *this, encoding_rule_t **rules) { - *rules = traffic_selector_substructure_encodings; - *rule_count = countof(traffic_selector_substructure_encodings); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_traffic_selector_substructure_t *this) +{ + return 8; } METHOD(payload_t, get_type, payload_type_t, @@ -208,6 +213,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -217,7 +223,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create() .get_traffic_selector = _get_traffic_selector, .destroy = _destroy, }, - .payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH, + .payload_length = get_header_length(this), /* must be set to be valid */ .ts_type = TS_IPV4_ADDR_RANGE, ); @@ -239,7 +245,7 @@ traffic_selector_substructure_t *traffic_selector_substructure_create_from_traff this->end_port = ts->get_to_port(ts); this->starting_address = chunk_clone(ts->get_from_address(ts)); this->ending_address = chunk_clone(ts->get_to_address(ts)); - this->payload_length = TRAFFIC_SELECTOR_HEADER_LENGTH + + this->payload_length = get_header_length(this) + this->ending_address.len + this->starting_address.len; return &this->public; diff --git a/src/libcharon/encoding/payloads/traffic_selector_substructure.h b/src/libcharon/encoding/payloads/traffic_selector_substructure.h index 0109fd7f5..1ad5fb526 100644 --- a/src/libcharon/encoding/payloads/traffic_selector_substructure.h +++ b/src/libcharon/encoding/payloads/traffic_selector_substructure.h @@ -30,11 +30,6 @@ typedef struct traffic_selector_substructure_t traffic_selector_substructure_t; #include <encoding/payloads/payload.h> /** - * Length of a TRAFFIC SELECTOR SUBSTRUCTURE without start and end address. - */ -#define TRAFFIC_SELECTOR_HEADER_LENGTH 8 - -/** * Class representing an IKEv2 TRAFFIC SELECTOR. * * The TRAFFIC SELECTOR format is described in RFC section 3.13.1. diff --git a/src/libcharon/encoding/payloads/transform_attribute.c b/src/libcharon/encoding/payloads/transform_attribute.c index 7d21258b1..d20f77c59 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.c +++ b/src/libcharon/encoding/payloads/transform_attribute.c @@ -17,12 +17,51 @@ #include <string.h> #include <stddef.h> +#include <stdint.h> #include "transform_attribute.h" #include <encoding/payloads/encodings.h> #include <library.h> +ENUM(tattr_ph1_names, TATTR_PH1_ENCRYPTION_ALGORITHM, TATTR_PH1_GROUP_ORDER, + "ENCRYPTION_ALGORITHM", + "HASH_ALGORITHM", + "AUTH_METHOD", + "GROUP", + "GROUP_TYPE", + "GROUP_PRIME", + "GROUP_GENONE", + "GROUP_GENTWO", + "GROUP_CURVE_A", + "GROUP_CURVE_B", + "LIFE_TYPE", + "LIFE_DURATION", + "PRF", + "KEY_LENGTH", + "FIELD_SIZE", + "GROUP_ORDER", +); + +ENUM(tattr_ph2_names, TATTR_PH2_SA_LIFE_TYPE, TATTR_PH2_EXT_SEQ_NUMBER, + "SA_LIFE_TYPE", + "SA_LIFE_DURATION", + "GROUP", + "ENCAP_MODE", + "AUTH_ALGORITHM", + "KEY_LENGTH", + "KEY_ROUNDS", + "COMP_DICT_SIZE", + "COMP_PRIV_ALGORITHM", + "ECN_TUNNEL", + "EXT_SEQ_NUMBER", +); + +ENUM(tattr_ikev2_names, TATTR_IKEV2_KEY_LENGTH, TATTR_IKEV2_KEY_LENGTH, + "KEY_LENGTH", +); + + typedef struct private_transform_attribute_t private_transform_attribute_t; /** @@ -57,30 +96,25 @@ struct private_transform_attribute_t { * Attribute value as chunk if attribute_format is 0 (FALSE). */ chunk_t attribute_value; -}; - -ENUM_BEGIN(transform_attribute_type_name, ATTRIBUTE_UNDEFINED, ATTRIBUTE_UNDEFINED, - "ATTRIBUTE_UNDEFINED"); -ENUM_NEXT(transform_attribute_type_name, KEY_LENGTH, KEY_LENGTH, ATTRIBUTE_UNDEFINED, - "KEY_LENGTH"); -ENUM_END(transform_attribute_type_name, KEY_LENGTH); + /** + * Payload type, TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 + */ + payload_type_t type; +}; /** - * 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 rules for IKEv1/IKEv2 transform attributes */ -encoding_rule_t transform_attribute_encodings[] = { +static encoding_rule_t encodings[] = { /* Flag defining the format of this payload */ - { ATTRIBUTE_FORMAT, offsetof(private_transform_attribute_t, attribute_format) }, + { 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) } + { ATTRIBUTE_VALUE, offsetof(private_transform_attribute_t, attribute_value) } }; /* @@ -101,18 +135,23 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_transform_attribute_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_transform_attribute_t *this, encoding_rule_t **rules) { - *rules = transform_attribute_encodings; - *rule_count = countof(transform_attribute_encodings); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_transform_attribute_t *this) +{ + return 0; } METHOD(payload_t, get_type, payload_type_t, private_transform_attribute_t *this) { - return TRANSFORM_ATTRIBUTE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -136,31 +175,6 @@ METHOD(payload_t, get_length, size_t, return this->attribute_length_or_value + 4; } -METHOD(transform_attribute_t, set_value_chunk, void, - private_transform_attribute_t *this, chunk_t value) -{ - chunk_free(&this->attribute_value); - - if (value.len != 2) - { - this->attribute_value = chunk_clone(value); - this->attribute_length_or_value = value.len; - this->attribute_format = FALSE; - } - else - { - memcpy(&this->attribute_length_or_value, value.ptr, value.len); - } -} - -METHOD(transform_attribute_t, set_value, void, - private_transform_attribute_t *this, u_int16_t value) -{ - chunk_free(&this->attribute_value); - this->attribute_length_or_value = value; - this->attribute_format = TRUE; -} - METHOD(transform_attribute_t, get_value_chunk, chunk_t, private_transform_attribute_t *this) { @@ -171,16 +185,22 @@ METHOD(transform_attribute_t, get_value_chunk, chunk_t, return this->attribute_value; } -METHOD(transform_attribute_t, get_value, u_int16_t, +METHOD(transform_attribute_t, get_value, u_int64_t, private_transform_attribute_t *this) { - return this->attribute_length_or_value; -} + u_int64_t value = 0; -METHOD(transform_attribute_t, set_attribute_type, void, - private_transform_attribute_t *this, u_int16_t type) -{ - this->attribute_type = type & 0x7FFF; + if (this->attribute_format) + { + return this->attribute_length_or_value; + } + if (this->attribute_value.len > sizeof(value)) + { + return UINT64_MAX; + } + memcpy(((char*)&value) + sizeof(value) - this->attribute_value.len, + this->attribute_value.ptr, this->attribute_value.len); + return untoh64((char*)&value); } METHOD(transform_attribute_t, get_attribute_type, u_int16_t, @@ -189,24 +209,6 @@ METHOD(transform_attribute_t, get_attribute_type, u_int16_t, return this->attribute_type; } -METHOD(transform_attribute_t, clone_, transform_attribute_t*, - private_transform_attribute_t *this) -{ - private_transform_attribute_t *new_clone; - - new_clone = (private_transform_attribute_t *)transform_attribute_create(); - - new_clone->attribute_format = this->attribute_format; - new_clone->attribute_type = this->attribute_type; - new_clone->attribute_length_or_value = this->attribute_length_or_value; - - if (!new_clone->attribute_format) - { - new_clone->attribute_value = chunk_clone(this->attribute_value); - } - return &new_clone->public; -} - METHOD2(payload_t, transform_attribute_t, destroy, void, private_transform_attribute_t *this) { @@ -217,7 +219,7 @@ METHOD2(payload_t, transform_attribute_t, destroy, void, /* * Described in header. */ -transform_attribute_t *transform_attribute_create() +transform_attribute_t *transform_attribute_create(payload_type_t type) { private_transform_attribute_t *this; @@ -226,22 +228,20 @@ transform_attribute_t *transform_attribute_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, .get_type = _get_type, .destroy = _destroy, }, - .set_value_chunk = _set_value_chunk, - .set_value = _set_value, .get_value_chunk = _get_value_chunk, .get_value = _get_value, - .set_attribute_type = _set_attribute_type, .get_attribute_type = _get_attribute_type, - .clone = _clone_, .destroy = _destroy, }, - .attribute_format = TRUE, + .attribute_format = FALSE, + .type = type, ); return &this->public; } @@ -249,10 +249,33 @@ transform_attribute_t *transform_attribute_create() /* * Described in header. */ -transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length) +transform_attribute_t *transform_attribute_create_value(payload_type_t type, + transform_attribute_type_t kind, u_int64_t value) { - transform_attribute_t *attribute = transform_attribute_create(); - attribute->set_attribute_type(attribute, KEY_LENGTH); - attribute->set_value(attribute, key_length); - return attribute; + private_transform_attribute_t *this; + + this = (private_transform_attribute_t*)transform_attribute_create(type); + + this->attribute_type = kind & 0x7FFF; + + if (value <= UINT16_MAX) + { + this->attribute_length_or_value = value; + this->attribute_format = TRUE; + } + else if (value <= UINT32_MAX) + { + u_int32_t val32; + + val32 = htonl(value); + this->attribute_value = chunk_clone(chunk_from_thing(val32)); + this->attribute_length_or_value = sizeof(val32); + } + else + { + htoun64(&value, value); + this->attribute_value = chunk_clone(chunk_from_thing(value)); + this->attribute_length_or_value = sizeof(value); + } + return &this->public; } diff --git a/src/libcharon/encoding/payloads/transform_attribute.h b/src/libcharon/encoding/payloads/transform_attribute.h index a5fe0154b..23897a50a 100644 --- a/src/libcharon/encoding/payloads/transform_attribute.h +++ b/src/libcharon/encoding/payloads/transform_attribute.h @@ -28,26 +28,66 @@ typedef struct transform_attribute_t transform_attribute_t; #include <library.h> #include <encoding/payloads/payload.h> - /** - * Type of the attribute, as in IKEv2 RFC 3.3.5. + * Type of the attribute. */ enum transform_attribute_type_t { - ATTRIBUTE_UNDEFINED = 16384, - KEY_LENGTH = 14 + /** IKEv1 Phase 1 attributes */ + TATTR_PH1_ENCRYPTION_ALGORITHM = 1, + TATTR_PH1_HASH_ALGORITHM = 2, + TATTR_PH1_AUTH_METHOD = 3, + TATTR_PH1_GROUP = 4, + TATTR_PH1_GROUP_TYPE = 5, + TATTR_PH1_GROUP_PRIME = 6, + TATTR_PH1_GROUP_GENONE = 7, + TATTR_PH1_GROUP_GENTWO = 8, + TATTR_PH1_GROUP_CURVE_A = 9, + TATTR_PH1_GROUP_CURVE_B = 10, + TATTR_PH1_LIFE_TYPE = 11, + TATTR_PH1_LIFE_DURATION = 12, + TATTR_PH1_PRF = 13, + TATTR_PH1_KEY_LENGTH = 14, + TATTR_PH1_FIELD_SIZE = 15, + TATTR_PH1_GROUP_ORDER = 16, + /** IKEv1 Phase 2 attributes */ + TATTR_PH2_SA_LIFE_TYPE = 1, + TATTR_PH2_SA_LIFE_DURATION = 2, + TATTR_PH2_GROUP = 3, + TATTR_PH2_ENCAP_MODE = 4, + TATTR_PH2_AUTH_ALGORITHM = 5, + TATTR_PH2_KEY_LENGTH = 6, + TATTR_PH2_KEY_ROUNDS = 7, + TATTR_PH2_COMP_DICT_SIZE = 8, + TATTR_PH2_COMP_PRIV_ALGORITHM = 9, + TATTR_PH2_ECN_TUNNEL = 10, + TATTR_PH2_EXT_SEQ_NUMBER = 11, + /* IKEv2 key length attribute */ + TATTR_IKEV2_KEY_LENGTH = 14, + /* undefined, private use attribute */ + TATTR_UNDEFINED = 16384, }; /** - * enum name for transform_attribute_type_t. + * Enum names for IKEv1 Phase 1 transform_attribute_type_t. */ -extern enum_name_t *transform_attribute_type_names; +extern enum_name_t *tattr_ph1_names; /** - * Class representing an IKEv2- TRANSFORM Attribute. - * - * The TRANSFORM ATTRIBUTE format is described in RFC section 3.3.5. + * Enum names for IKEv1 Phase 2 transform_attribute_type_t. + */ +extern enum_name_t *tattr_ph2_names; + +/** + * Enum names for IKEv2 transform_attribute_type_t. + */ +extern enum_name_t *tattr_ikev2_names; + + +/** + * Class representing an IKEv1/IKEv2 TRANSFORM Attribute. */ struct transform_attribute_t { + /** * The payload_t interface. */ @@ -58,7 +98,7 @@ struct transform_attribute_t { * * Returned data are not copied. * - * @return chunk_t pointing to the value + * @return chunk_t pointing to internal value */ chunk_t (*get_value_chunk) (transform_attribute_t *this); @@ -69,30 +109,7 @@ struct transform_attribute_t { * * @return value */ - u_int16_t (*get_value) (transform_attribute_t *this); - - /** - * Sets the value of the attribute. - * - * Value is getting copied. - * - * @param value chunk_t pointing to the value to set - */ - void (*set_value_chunk) (transform_attribute_t *this, chunk_t value); - - /** - * Sets the value of the attribute. - * - * @param value value to set - */ - void (*set_value) (transform_attribute_t *this, u_int16_t value); - - /** - * Sets the type of the attribute. - * - * @param type type to set (most significant bit is set to zero) - */ - void (*set_attribute_type) (transform_attribute_t *this, u_int16_t type); + u_int64_t (*get_value) (transform_attribute_t *this); /** * get the type of the attribute. @@ -102,13 +119,6 @@ struct transform_attribute_t { u_int16_t (*get_attribute_type) (transform_attribute_t *this); /** - * Clones an transform_attribute_t object. - * - * @return cloned transform_attribute_t object - */ - transform_attribute_t * (*clone) (transform_attribute_t *this); - - /** * Destroys an transform_attribute_t object. */ void (*destroy) (transform_attribute_t *this); @@ -117,16 +127,20 @@ struct transform_attribute_t { /** * Creates an empty transform_attribute_t object. * + * @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 * @return transform_attribute_t object */ -transform_attribute_t *transform_attribute_create(void); +transform_attribute_t *transform_attribute_create(payload_type_t type); /** - * Creates an transform_attribute_t of type KEY_LENGTH. + * Creates a two byte value or a larger attribute for a given attribute kind. * - * @param key_length key length in bytes + * @param type TRANSFORM_ATTRIBUTE or TRANSFORM_ATTRIBUTE_V1 + * @param kind attribute kind + * @param value fixed two byte value * @return transform_attribute_t object */ -transform_attribute_t *transform_attribute_create_key_length(u_int16_t key_length); +transform_attribute_t *transform_attribute_create_value(payload_type_t type, + transform_attribute_type_t kind, u_int64_t value); #endif /** TRANSFORM_ATTRIBUTE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/transform_substructure.c b/src/libcharon/encoding/payloads/transform_substructure.c index 3f04b3539..a4a920b60 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.c +++ b/src/libcharon/encoding/payloads/transform_substructure.c @@ -41,10 +41,11 @@ struct private_transform_substructure_t { * Next payload type. */ u_int8_t next_payload; + /** - * Reserved bytes + * Reserved byte */ - u_int8_t reserved[2]; + u_int8_t reserved[3]; /** * Length of this payload. @@ -52,43 +53,72 @@ struct private_transform_substructure_t { u_int16_t transform_length; /** - * Type of the transform. + * Type or number, Type of the transform in IKEv2, number in IKEv2. + */ + u_int8_t transform_ton; + + /** + * Transform ID, as encoded in IKEv1. */ - u_int8_t transform_type; + u_int8_t transform_id_v1; /** - * Transform ID. + * Transform ID, as encoded in IKEv2. */ - u_int16_t transform_id; + u_int16_t transform_id_v2; /** * Transforms Attributes are stored in a linked_list_t. */ linked_list_t *attributes; + + /** + * Payload type, TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 + */ + payload_type_t type; }; /** - * 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 rules for TRANSFORM_SUBSTRUCTURE */ -encoding_rule_t transform_substructure_encodings[] = { +static encoding_rule_t encodings_v2[] = { /* 1 Byte next payload type, stored in the field next_payload */ - { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, + { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, /* 1 Reserved Byte */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[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) }, + { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, + /* transform type */ + { U_INT_8, offsetof(private_transform_substructure_t, transform_ton) }, + /* transform identifier, as used by IKEv1 */ + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, + /* transform identifier, as used by IKEv2 */ + { U_INT_16, offsetof(private_transform_substructure_t, transform_id_v2) }, + /* Attributes in a transform attribute list */ + { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE, + offsetof(private_transform_substructure_t, attributes) } +}; + +/** + * Encoding rules for TRANSFORM_SUBSTRUCTURE_V1 + */ +static encoding_rule_t encodings_v1[] = { + /* 1 Byte next payload type, stored in the field next_payload */ + { U_INT_8, offsetof(private_transform_substructure_t, next_payload) }, /* 1 Reserved Byte */ - { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, - /* transform 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) } + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[0]) }, + /* Length of the whole transform substructure*/ + { PAYLOAD_LENGTH, offsetof(private_transform_substructure_t, transform_length)}, + /* transform number */ + { U_INT_8, offsetof(private_transform_substructure_t, transform_ton)}, + /* transform identifier, as used by IKEv1 */ + { U_INT_8, offsetof(private_transform_substructure_t, transform_id_v1) }, + /* transform identifier, as used by IKEv2 */ + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[1]) }, + { RESERVED_BYTE, offsetof(private_transform_substructure_t, reserved[2]) }, + /* Attributes in a transform attribute list */ + { PAYLOAD_LIST + TRANSFORM_ATTRIBUTE_V1, + offsetof(private_transform_substructure_t, attributes) } }; /* @@ -97,7 +127,7 @@ encoding_rule_t transform_substructure_encodings[] = { +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! 0 (last) or 3 ! RESERVED ! Transform Length ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - !Transform Type ! RESERVED ! Transform ID ! + ! Tfrm Typ or # ! Tfrm ID IKEv1 ! Transform ID IKEv2 ! +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ ! ! ~ Transform Attributes ~ @@ -118,23 +148,6 @@ METHOD(payload_t, verify, status_t, return FAILED; } - switch (this->transform_type) - { - case ENCRYPTION_ALGORITHM: - case PSEUDO_RANDOM_FUNCTION: - case INTEGRITY_ALGORITHM: - case DIFFIE_HELLMAN_GROUP: - case EXTENDED_SEQUENCE_NUMBERS: - /* we don't check transform ID, we want to reply - * cleanly with NO_PROPOSAL_CHOSEN or so if we don't support it */ - break; - default: - { - DBG1(DBG_ENC, "invalid transform type: %d", this->transform_type); - return FAILED; - } - } - enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attribute)) { @@ -151,18 +164,28 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_transform_substructure_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_transform_substructure_t *this, encoding_rule_t **rules) { - *rules = transform_substructure_encodings; - *rule_count = countof(transform_substructure_encodings); + if (this->type == TRANSFORM_SUBSTRUCTURE) + { + *rules = encodings_v2; + return countof(encodings_v2); + } + *rules = encodings_v1; + return countof(encodings_v1); +} + +METHOD(payload_t, get_header_length, int, + private_transform_substructure_t *this) +{ + return 8; } METHOD(payload_t, get_type, payload_type_t, private_transform_substructure_t *this) { - return TRANSFORM_SUBSTRUCTURE; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -174,12 +197,12 @@ METHOD(payload_t, get_next_type, payload_type_t, /** * recompute the length of the payload. */ -static void compute_length (private_transform_substructure_t *this) +static void compute_length(private_transform_substructure_t *this) { enumerator_t *enumerator; payload_t *attribute; - this->transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH; + this->transform_length = get_header_length(this); enumerator = this->attributes->create_enumerator(this->attributes); while (enumerator->enumerate(enumerator, &attribute)) { @@ -194,6 +217,13 @@ METHOD(payload_t, get_length, size_t, return this->transform_length; } +METHOD(transform_substructure_t, add_transform_attribute, void, + private_transform_substructure_t *this, transform_attribute_t *attribute) +{ + this->attributes->insert_last(this->attributes, attribute); + compute_length(this); +} + METHOD(transform_substructure_t, set_is_last_transform, void, private_transform_substructure_t *this, bool is_last) { @@ -205,50 +235,40 @@ METHOD(payload_t, set_next_type, void, { } -METHOD(transform_substructure_t, get_transform_type, u_int8_t, +METHOD(transform_substructure_t, get_transform_type_or_number, u_int8_t, private_transform_substructure_t *this) { - return this->transform_type; + return this->transform_ton; } METHOD(transform_substructure_t, get_transform_id, u_int16_t, private_transform_substructure_t *this) { - return this->transform_id; + if (this->type == TRANSFORM_SUBSTRUCTURE) + { + return this->transform_id_v2; + } + return this->transform_id_v1; } -METHOD(transform_substructure_t, get_key_length, status_t, - private_transform_substructure_t *this, u_int16_t *key_length) +METHOD(transform_substructure_t, create_attribute_enumerator, enumerator_t*, + private_transform_substructure_t *this) { - enumerator_t *enumerator; - transform_attribute_t *attribute; - - enumerator = this->attributes->create_enumerator(this->attributes); - while (enumerator->enumerate(enumerator, &attribute)) - { - if (attribute->get_attribute_type(attribute) == KEY_LENGTH) - { - *key_length = attribute->get_value(attribute); - enumerator->destroy(enumerator); - return SUCCESS; - } - } - enumerator->destroy(enumerator); - return FAILED; + return this->attributes->create_enumerator(this->attributes); } METHOD2(payload_t, transform_substructure_t, destroy, void, private_transform_substructure_t *this) { this->attributes->destroy_offset(this->attributes, - offsetof(transform_attribute_t, destroy)); + offsetof(payload_t, destroy)); free(this); } /* * Described in header. */ -transform_substructure_t *transform_substructure_create() +transform_substructure_t *transform_substructure_create(payload_type_t type) { private_transform_substructure_t *this; @@ -257,21 +277,24 @@ transform_substructure_t *transform_substructure_create() .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, .get_type = _get_type, .destroy = _destroy, }, + .add_transform_attribute = _add_transform_attribute, .set_is_last_transform = _set_is_last_transform, - .get_transform_type = _get_transform_type, + .get_transform_type_or_number = _get_transform_type_or_number, .get_transform_id = _get_transform_id, - .get_key_length = _get_key_length, + .create_attribute_enumerator = _create_attribute_enumerator, .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .transform_length = TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH, + .transform_length = get_header_length(this), .attributes = linked_list_create(), + .type = type, ); return &this->public; } @@ -279,20 +302,21 @@ transform_substructure_t *transform_substructure_create() /* * Described in header */ -transform_substructure_t *transform_substructure_create_type( - transform_type_t type, u_int16_t id, u_int16_t key_length) +transform_substructure_t *transform_substructure_create_type(payload_type_t type, + u_int8_t type_or_number, u_int16_t id) { private_transform_substructure_t *this; - this = (private_transform_substructure_t*)transform_substructure_create(); + this = (private_transform_substructure_t*)transform_substructure_create(type); - this->transform_type = type; - this->transform_id = id; - if (key_length) + this->transform_ton = type_or_number; + if (type == TRANSFORM_SUBSTRUCTURE) + { + this->transform_id_v2 = id; + } + else { - this->attributes->insert_last(this->attributes, - (void*)transform_attribute_create_key_length(key_length)); - compute_length(this); + this->transform_id_v1 = id; } return &this->public; } diff --git a/src/libcharon/encoding/payloads/transform_substructure.h b/src/libcharon/encoding/payloads/transform_substructure.h index 102dbb3d3..947df24f9 100644 --- a/src/libcharon/encoding/payloads/transform_substructure.h +++ b/src/libcharon/encoding/payloads/transform_substructure.h @@ -40,14 +40,7 @@ typedef struct transform_substructure_t transform_substructure_t; #define TRANSFORM_TYPE_VALUE 3 /** - * Length of the transform substructure header in bytes. - */ -#define TRANSFORM_SUBSTRUCTURE_HEADER_LENGTH 8 - -/** - * Class representing an IKEv2- TRANSFORM SUBSTRUCTURE. - * - * The TRANSFORM SUBSTRUCTURE format is described in RFC section 3.3.2. + * Class representing an IKEv1/IKEv2 transform substructure. */ struct transform_substructure_t { @@ -75,11 +68,11 @@ struct transform_substructure_t { void (*set_is_last_transform) (transform_substructure_t *this, bool is_last); /** - * get transform type of the current transform. + * Get transform type (IKEv2) or the transform number (IKEv1). * * @return Transform type of current transform substructure. */ - u_int8_t (*get_transform_type) (transform_substructure_t *this); + u_int8_t (*get_transform_type_or_number) (transform_substructure_t *this); /** * Get transform id of the current transform. @@ -89,16 +82,11 @@ struct transform_substructure_t { u_int16_t (*get_transform_id) (transform_substructure_t *this); /** - * Get transform id of the current transform. + * Create an enumerator over transform attributes. * - * @param key_length The key length is written to this location - * @return - * - SUCCESS if a key length attribute is contained - * - FAILED if no key length attribute is part of this - * transform or key length uses more then 16 bit! + * @return enumerator over transform_attribute_t* */ - status_t (*get_key_length) (transform_substructure_t *this, - u_int16_t *key_length); + enumerator_t* (*create_attribute_enumerator)(transform_substructure_t *this); /** * Destroys an transform_substructure_t object. @@ -109,19 +97,20 @@ struct transform_substructure_t { /** * Creates an empty transform_substructure_t object. * + * @param type TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 * @return created transform_substructure_t object */ -transform_substructure_t *transform_substructure_create(void); +transform_substructure_t *transform_substructure_create(payload_type_t type); /** * Creates an empty transform_substructure_t object. * - * @param type type of transform to create - * @param id transform id specifc for the transform type - * @param key_length key length for key length attribute, 0 to omit - * @return transform_substructure_t object + * @param type TRANSFORM_SUBSTRUCTURE or TRANSFORM_SUBSTRUCTURE_V1 + * @param type_or_number Type (IKEv2) or number (IKEv1) of transform + * @param id transform id specifc for the transform type + * @return transform_substructure_t object */ -transform_substructure_t *transform_substructure_create_type( - transform_type_t type, u_int16_t id, u_int16_t key_length); +transform_substructure_t *transform_substructure_create_type(payload_type_t type, + u_int8_t type_or_number, u_int16_t id); #endif /** TRANSFORM_SUBSTRUCTURE_H_ @}*/ diff --git a/src/libcharon/encoding/payloads/ts_payload.c b/src/libcharon/encoding/payloads/ts_payload.c index 28f760e40..a7678da73 100644 --- a/src/libcharon/encoding/payloads/ts_payload.c +++ b/src/libcharon/encoding/payloads/ts_payload.c @@ -81,7 +81,7 @@ struct private_ts_payload_t { * The defined offsets are the positions in a object of type * private_ts_payload_t. */ -encoding_rule_t ts_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_ts_payload_t, next_payload) }, /* the critical bit */ @@ -102,8 +102,9 @@ encoding_rule_t ts_payload_encodings[] = { { RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[0])}, { RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[1])}, { RESERVED_BYTE, offsetof(private_ts_payload_t, reserved_byte[2])}, - /* some ts data bytes, length is defined in PAYLOAD_LENGTH */ - { TRAFFIC_SELECTORS,offsetof(private_ts_payload_t, substrs) } + /* wrapped list of traffic selectors substructures */ + { PAYLOAD_LIST + TRAFFIC_SELECTOR_SUBSTRUCTURE, + offsetof(private_ts_payload_t, substrs) }, }; /* @@ -145,11 +146,17 @@ METHOD(payload_t, verify, status_t, return status; } -METHOD(payload_t, get_encoding_rules, void, - private_ts_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_ts_payload_t *this, encoding_rule_t **rules) { - *rules = ts_payload_encodings; - *rule_count = countof(ts_payload_encodings); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_ts_payload_t *this) +{ + return 8; } METHOD(payload_t, get_type, payload_type_t, @@ -182,7 +189,7 @@ static void compute_length(private_ts_payload_t *this) enumerator_t *enumerator; payload_t *subst; - this->payload_length = TS_PAYLOAD_HEADER_LENGTH; + this->payload_length = get_header_length(this); this->ts_num = 0; enumerator = this->substrs->create_enumerator(this->substrs); while (enumerator->enumerate(enumerator, &subst)) @@ -250,6 +257,7 @@ ts_payload_t *ts_payload_create(bool is_initiator) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -262,7 +270,7 @@ ts_payload_t *ts_payload_create(bool is_initiator) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = TS_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .is_initiator = is_initiator, .substrs = linked_list_create(), ); diff --git a/src/libcharon/encoding/payloads/ts_payload.h b/src/libcharon/encoding/payloads/ts_payload.h index 88ca00bc9..5a92655dc 100644 --- a/src/libcharon/encoding/payloads/ts_payload.h +++ b/src/libcharon/encoding/payloads/ts_payload.h @@ -31,11 +31,6 @@ typedef struct ts_payload_t ts_payload_t; #include <encoding/payloads/traffic_selector_substructure.h> /** - * Length of a TS payload without the Traffic selectors. - */ -#define TS_PAYLOAD_HEADER_LENGTH 8 - -/** * Class representing an IKEv2 TS payload. * * The TS payload format is described in RFC section 3.13. diff --git a/src/libcharon/encoding/payloads/unknown_payload.c b/src/libcharon/encoding/payloads/unknown_payload.c index 27af338b3..fe7ced20b 100644 --- a/src/libcharon/encoding/payloads/unknown_payload.c +++ b/src/libcharon/encoding/payloads/unknown_payload.c @@ -68,7 +68,7 @@ struct private_unknown_payload_t { * private_unknown_payload_t. * */ -encoding_rule_t unknown_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_unknown_payload_t, next_payload) }, /* the critical bit */ @@ -84,7 +84,7 @@ encoding_rule_t unknown_payload_encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_unknown_payload_t, payload_length) }, /* some unknown data bytes, length is defined in PAYLOAD_LENGTH */ - { UNKNOWN_DATA, offsetof(private_unknown_payload_t, data) }, + { CHUNK_DATA, offsetof(private_unknown_payload_t, data) }, }; /* @@ -102,18 +102,20 @@ encoding_rule_t unknown_payload_encodings[] = { METHOD(payload_t, verify, status_t, private_unknown_payload_t *this) { - if (this->payload_length != UNKNOWN_PAYLOAD_HEADER_LENGTH + this->data.len) - { - return FAILED; - } return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_unknown_payload_t *this, encoding_rule_t **rules, size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_unknown_payload_t *this, encoding_rule_t **rules) { - *rules = unknown_payload_encodings; - *rule_count = sizeof(unknown_payload_encodings) / sizeof(encoding_rule_t); + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_unknown_payload_t *this) +{ + return 4; } METHOD(payload_t, get_payload_type, payload_type_t, @@ -171,6 +173,7 @@ unknown_payload_t *unknown_payload_create(payload_type_t type) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -182,7 +185,7 @@ unknown_payload_t *unknown_payload_create(payload_type_t type) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH, + .payload_length = get_header_length(this), .type = type, ); @@ -201,7 +204,7 @@ unknown_payload_t *unknown_payload_create_data(payload_type_t type, this = (private_unknown_payload_t*)unknown_payload_create(type); this->data = data; this->critical = critical; - this->payload_length = UNKNOWN_PAYLOAD_HEADER_LENGTH + data.len; + this->payload_length = get_header_length(this) + data.len; return &this->public; } diff --git a/src/libcharon/encoding/payloads/unknown_payload.h b/src/libcharon/encoding/payloads/unknown_payload.h index 5ae85331b..326b550cd 100644 --- a/src/libcharon/encoding/payloads/unknown_payload.h +++ b/src/libcharon/encoding/payloads/unknown_payload.h @@ -28,11 +28,6 @@ typedef struct unknown_payload_t unknown_payload_t; #include <encoding/payloads/payload.h> /** - * Header length of the unknown payload. - */ -#define UNKNOWN_PAYLOAD_HEADER_LENGTH 4 - -/** * Payload which can't be processed further. * * When the parser finds an unknown payload, he builds an instance of diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.c b/src/libcharon/encoding/payloads/vendor_id_payload.c index e9e80e989..0c1df56e2 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.c +++ b/src/libcharon/encoding/payloads/vendor_id_payload.c @@ -55,6 +55,11 @@ struct private_vendor_id_payload_t { * The contained data. */ chunk_t data; + + /** + * Either a IKEv1 or a IKEv2 vendor ID payload + */ + payload_type_t type; }; /** @@ -63,7 +68,7 @@ struct private_vendor_id_payload_t { * The defined offsets are the positions in a object of type * private_vendor_id_payload_t. */ -encoding_rule_t vendor_id_payload_encodings[] = { +static encoding_rule_t encodings[] = { /* 1 Byte next payload type, stored in the field next_payload */ { U_INT_8, offsetof(private_vendor_id_payload_t, next_payload) }, /* the critical bit */ @@ -79,7 +84,7 @@ encoding_rule_t vendor_id_payload_encodings[] = { /* Length of the whole payload*/ { PAYLOAD_LENGTH, offsetof(private_vendor_id_payload_t, payload_length)}, /* some vendor_id data bytes, length is defined in PAYLOAD_LENGTH */ - { VID_DATA, offsetof(private_vendor_id_payload_t, data) } + { CHUNK_DATA, offsetof(private_vendor_id_payload_t, data) } }; /* @@ -100,18 +105,23 @@ METHOD(payload_t, verify, status_t, return SUCCESS; } -METHOD(payload_t, get_encoding_rules, void, - private_vendor_id_payload_t *this, encoding_rule_t **rules, - size_t *rule_count) +METHOD(payload_t, get_encoding_rules, int, + private_vendor_id_payload_t *this, encoding_rule_t **rules) +{ + *rules = encodings; + return countof(encodings); +} + +METHOD(payload_t, get_header_length, int, + private_vendor_id_payload_t *this) { - *rules = vendor_id_payload_encodings; - *rule_count = countof(vendor_id_payload_encodings); + return 4; } METHOD(payload_t, get_type, payload_type_t, private_vendor_id_payload_t *this) { - return VENDOR_ID; + return this->type; } METHOD(payload_t, get_next_type, payload_type_t, @@ -148,7 +158,8 @@ METHOD2(payload_t, vendor_id_payload_t, destroy, void, /* * Described in header */ -vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) +vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type, + chunk_t data) { private_vendor_id_payload_t *this; @@ -157,6 +168,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) .payload_interface = { .verify = _verify, .get_encoding_rules = _get_encoding_rules, + .get_header_length = _get_header_length, .get_length = _get_length, .get_next_type = _get_next_type, .set_next_type = _set_next_type, @@ -167,8 +179,9 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) .destroy = _destroy, }, .next_payload = NO_PAYLOAD, - .payload_length = VENDOR_ID_PAYLOAD_HEADER_LENGTH + data.len, + .payload_length = get_header_length(this) + data.len, .data = data, + .type = type, ); return &this->public; } @@ -176,7 +189,7 @@ vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data) /* * Described in header */ -vendor_id_payload_t *vendor_id_payload_create() +vendor_id_payload_t *vendor_id_payload_create(payload_type_t type) { - return vendor_id_payload_create_data(chunk_empty); + return vendor_id_payload_create_data(type, chunk_empty); } diff --git a/src/libcharon/encoding/payloads/vendor_id_payload.h b/src/libcharon/encoding/payloads/vendor_id_payload.h index 4e4e7d8eb..9a814777b 100644 --- a/src/libcharon/encoding/payloads/vendor_id_payload.h +++ b/src/libcharon/encoding/payloads/vendor_id_payload.h @@ -28,12 +28,7 @@ typedef struct vendor_id_payload_t vendor_id_payload_t; #include <encoding/payloads/payload.h> /** - * Length of a VENDOR ID payload without the VID data in bytes. - */ -#define VENDOR_ID_PAYLOAD_HEADER_LENGTH 4 - -/** - * Class representing an IKEv2 VENDOR ID payload. + * Class representing an IKEv1/IKEv2 VENDOR ID payload. * * The VENDOR ID payload format is described in RFC section 3.12. */ @@ -58,18 +53,21 @@ struct vendor_id_payload_t { }; /** - * Creates an empty Vendor ID payload. + * Creates an empty Vendor ID payload for IKEv1 or IKEv2. * + * @@param type VENDOR_ID or VENDOR_ID_V1 * @return vendor ID payload */ -vendor_id_payload_t *vendor_id_payload_create(); +vendor_id_payload_t *vendor_id_payload_create(payload_type_t type); /** * Creates a vendor ID payload using a chunk of data * + * @param type VENDOR_ID or VENDOR_ID_V1 * @param data data to use in vendor ID payload, gets owned by payload * @return vendor ID payload */ -vendor_id_payload_t *vendor_id_payload_create_data(chunk_t data); +vendor_id_payload_t *vendor_id_payload_create_data(payload_type_t type, + chunk_t data); #endif /** VENDOR_ID_PAYLOAD_H_ @}*/ |