diff options
Diffstat (limited to 'src/libcharon/encoding')
-rw-r--r-- | src/libcharon/encoding/message.c | 16 | ||||
-rw-r--r-- | src/libcharon/encoding/parser.c | 21 | ||||
-rw-r--r-- | src/libcharon/encoding/parser.h | 12 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/delete_payload.c | 15 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/delete_payload.h | 10 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/encrypted_payload.c | 1 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/id_payload.c | 7 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/ke_payload.c | 10 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/ke_payload.h | 2 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/notify_payload.c | 22 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/notify_payload.h | 2 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/payload.c | 62 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/payload.h | 3 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/proposal_substructure.c | 276 |
14 files changed, 265 insertions, 194 deletions
diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index cb6c97f25..0a596ffb0 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -180,6 +180,7 @@ static payload_order_t ike_sa_init_r_order[] = { */ static payload_rule_t ike_auth_i_rules[] = { /* payload type min max encr suff */ + {PLV2_FRAGMENT, 0, 1, TRUE, TRUE}, {PLV2_NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, {PLV2_EAP, 0, 1, TRUE, TRUE}, {PLV2_AUTH, 0, 1, TRUE, TRUE}, @@ -227,6 +228,7 @@ static payload_order_t ike_auth_i_order[] = { {PLV2_NOTIFY, NO_ADDITIONAL_ADDRESSES}, {PLV2_NOTIFY, 0}, {PLV2_VENDOR_ID, 0}, + {PLV2_FRAGMENT, 0}, }; /** @@ -234,6 +236,7 @@ static payload_order_t ike_auth_i_order[] = { */ static payload_rule_t ike_auth_r_rules[] = { /* payload type min max encr suff */ + {PLV2_FRAGMENT, 0, 1, TRUE, TRUE}, {PLV2_NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, {PLV2_EAP, 0, 1, TRUE, TRUE}, {PLV2_AUTH, 0, 1, TRUE, TRUE}, @@ -270,6 +273,7 @@ static payload_order_t ike_auth_r_order[] = { {PLV2_NOTIFY, NO_ADDITIONAL_ADDRESSES}, {PLV2_NOTIFY, 0}, {PLV2_VENDOR_ID, 0}, + {PLV2_FRAGMENT, 0}, }; /** @@ -277,6 +281,7 @@ static payload_order_t ike_auth_r_order[] = { */ static payload_rule_t informational_i_rules[] = { /* payload type min max encr suff */ + {PLV2_FRAGMENT, 0, 1, TRUE, TRUE}, {PLV2_NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, {PLV2_CONFIGURATION, 0, 1, TRUE, FALSE}, {PLV2_DELETE, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, @@ -295,6 +300,7 @@ static payload_order_t informational_i_order[] = { {PLV2_NOTIFY, 0}, {PLV2_DELETE, 0}, {PLV2_CONFIGURATION, 0}, + {PLV2_FRAGMENT, 0}, }; /** @@ -302,6 +308,7 @@ static payload_order_t informational_i_order[] = { */ static payload_rule_t informational_r_rules[] = { /* payload type min max encr suff */ + {PLV2_FRAGMENT, 0, 1, TRUE, TRUE}, {PLV2_NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, {PLV2_CONFIGURATION, 0, 1, TRUE, FALSE}, {PLV2_DELETE, 0, MAX_DELETE_PAYLOADS, TRUE, FALSE}, @@ -320,6 +327,7 @@ static payload_order_t informational_r_order[] = { {PLV2_NOTIFY, 0}, {PLV2_DELETE, 0}, {PLV2_CONFIGURATION, 0}, + {PLV2_FRAGMENT, 0}, }; /** @@ -327,6 +335,7 @@ static payload_order_t informational_r_order[] = { */ static payload_rule_t create_child_sa_i_rules[] = { /* payload type min max encr suff */ + {PLV2_FRAGMENT, 0, 1, TRUE, TRUE}, {PLV2_NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, FALSE}, {PLV2_SECURITY_ASSOCIATION, 1, 1, TRUE, FALSE}, {PLV2_NONCE, 1, 1, TRUE, FALSE}, @@ -353,6 +362,7 @@ static payload_order_t create_child_sa_i_order[] = { {PLV2_TS_INITIATOR, 0}, {PLV2_TS_RESPONDER, 0}, {PLV2_NOTIFY, 0}, + {PLV2_FRAGMENT, 0}, }; /** @@ -360,6 +370,7 @@ static payload_order_t create_child_sa_i_order[] = { */ static payload_rule_t create_child_sa_r_rules[] = { /* payload type min max encr suff */ + {PLV2_FRAGMENT, 0, 1, TRUE, TRUE}, {PLV2_NOTIFY, 0, MAX_NOTIFY_PAYLOADS, TRUE, TRUE}, {PLV2_SECURITY_ASSOCIATION, 1, 1, TRUE, FALSE}, {PLV2_NONCE, 1, 1, TRUE, FALSE}, @@ -386,6 +397,7 @@ static payload_order_t create_child_sa_r_order[] = { {PLV2_TS_RESPONDER, 0}, {PLV2_NOTIFY, ADDITIONAL_TS_POSSIBLE}, {PLV2_NOTIFY, 0}, + {PLV2_FRAGMENT, 0}, }; #ifdef ME @@ -2143,6 +2155,8 @@ METHOD(message_t, parse_header, status_t, } ike_header->destroy(ike_header); + this->parser->set_major_version(this->parser, this->major_version); + 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")); @@ -2463,7 +2477,7 @@ static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) was_encrypted = "encrypted fragment payload"; } - if (payload_is_known(type) && !was_encrypted && + if (payload_is_known(type, this->major_version) && !was_encrypted && !is_connectivity_check(this, payload) && this->exchange_type != AGGRESSIVE) { diff --git a/src/libcharon/encoding/parser.c b/src/libcharon/encoding/parser.c index d6240fde2..f8340367e 100644 --- a/src/libcharon/encoding/parser.c +++ b/src/libcharon/encoding/parser.c @@ -59,6 +59,11 @@ struct private_parser_t { parser_t public; /** + * major IKE version + */ + u_int8_t major_version; + + /** * Current bit for reading in input data. */ u_int8_t bit_pos; @@ -369,7 +374,14 @@ METHOD(parser_t, parse_payload, status_t, encoding_rule_t *rule; /* create instance of the payload to parse */ - pld = payload_create(payload_type); + if (payload_is_known(payload_type, this->major_version)) + { + pld = payload_create(payload_type); + } + else + { + pld = (payload_t*)unknown_payload_create(payload_type); + } DBG2(DBG_ENC, "parsing %N payload, %d bytes left", payload_type_names, payload_type, this->input_roof - this->byte_pos); @@ -629,6 +641,12 @@ METHOD(parser_t, reset_context, void, this->bit_pos = 0; } +METHOD(parser_t, set_major_version, void, + private_parser_t *this, u_int8_t major_version) +{ + this->major_version = major_version; +} + METHOD(parser_t, destroy, void, private_parser_t *this) { @@ -646,6 +664,7 @@ parser_t *parser_create(chunk_t data) .public = { .parse_payload = _parse_payload, .reset_context = _reset_context, + .set_major_version = _set_major_version, .get_remaining_byte_count = _get_remaining_byte_count, .destroy = _destroy, }, diff --git a/src/libcharon/encoding/parser.h b/src/libcharon/encoding/parser.h index 27c5f03fe..5fd3e86ee 100644 --- a/src/libcharon/encoding/parser.h +++ b/src/libcharon/encoding/parser.h @@ -29,7 +29,7 @@ typedef struct parser_t parser_t; #include <encoding/payloads/payload.h> /** - * A parser_t class to parse IKEv2 payloads. + * A parser_t class to parse IKE payloads. * * A parser is used for parsing one chunk of data. Multiple * payloads can be parsed out of the chunk using parse_payload. @@ -50,7 +50,8 @@ struct parser_t { * - SUCCESSFUL if succeeded, * - PARSE_ERROR if corrupted/invalid data found */ - status_t (*parse_payload) (parser_t *this, payload_type_t payload_type, payload_t **payload); + status_t (*parse_payload) (parser_t *this, payload_type_t payload_type, + payload_t **payload); /** * Gets the remaining byte count which is not currently parsed. @@ -63,6 +64,13 @@ struct parser_t { void (*reset_context) (parser_t *this); /** + * Set the major IKE version. + * + * @param major_version the major IKE version + */ + void (*set_major_version) (parser_t *this, u_int8_t major_version); + + /** * Destroys a parser_t object. */ void (*destroy) (parser_t *this); diff --git a/src/libcharon/encoding/payloads/delete_payload.c b/src/libcharon/encoding/payloads/delete_payload.c index c2ab3b951..f11ea485c 100644 --- a/src/libcharon/encoding/payloads/delete_payload.c +++ b/src/libcharon/encoding/payloads/delete_payload.c @@ -1,4 +1,5 @@ /* + * Copyright (C) 2015 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2010 revosec AG * Copyright (C) 2005 Jan Hutter @@ -281,6 +282,19 @@ METHOD(delete_payload_t, set_ike_spi, void, this->payload_length = get_header_length(this) + this->spi_size; } +METHOD(delete_payload_t, get_ike_spi, bool, + private_delete_payload_t *this, u_int64_t *spi_i, u_int64_t *spi_r) +{ + if (this->protocol_id != PROTO_IKE || + this->spis.len < 2 * sizeof(u_int64_t)) + { + return FALSE; + } + memcpy(spi_i, this->spis.ptr, sizeof(u_int64_t)); + memcpy(spi_r, this->spis.ptr + sizeof(u_int64_t), sizeof(u_int64_t)); + return TRUE; +} + /** * SPI enumerator implementation */ @@ -352,6 +366,7 @@ delete_payload_t *delete_payload_create(payload_type_t type, .get_protocol_id = _get_protocol_id, .add_spi = _add_spi, .set_ike_spi = _set_ike_spi, + .get_ike_spi = _get_ike_spi, .create_spi_enumerator = _create_spi_enumerator, .destroy = _destroy, }, diff --git a/src/libcharon/encoding/payloads/delete_payload.h b/src/libcharon/encoding/payloads/delete_payload.h index 46a89eab6..6728718cd 100644 --- a/src/libcharon/encoding/payloads/delete_payload.h +++ b/src/libcharon/encoding/payloads/delete_payload.h @@ -1,4 +1,5 @@ /* + * Copyright (C) 2015 Tobias Brunner * Copyright (C) 2005-2006 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -61,6 +62,15 @@ struct delete_payload_t { void (*set_ike_spi)(delete_payload_t *this, u_int64_t spi_i, u_int64_t spi_r); /** + * Get the IKE SPIs from an IKEv1 delete. + * + * @param spi_i initiator SPI + * @param spi_r responder SPI + * @return TRUE if SPIs extracted successfully + */ + bool (*get_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 diff --git a/src/libcharon/encoding/payloads/encrypted_payload.c b/src/libcharon/encoding/payloads/encrypted_payload.c index 5c574c34d..04372fdf0 100644 --- a/src/libcharon/encoding/payloads/encrypted_payload.c +++ b/src/libcharon/encoding/payloads/encrypted_payload.c @@ -561,6 +561,7 @@ static status_t parse(private_encrypted_payload_t *this, chunk_t plain) payload_type_t type; parser = parser_create(plain); + parser->set_major_version(parser, this->type == PLV1_ENCRYPTED ? 1 : 2); type = this->next_payload; while (type != PL_NONE) { diff --git a/src/libcharon/encoding/payloads/id_payload.c b/src/libcharon/encoding/payloads/id_payload.c index a002a8f21..bb8aab748 100644 --- a/src/libcharon/encoding/payloads/id_payload.c +++ b/src/libcharon/encoding/payloads/id_payload.c @@ -258,17 +258,20 @@ static traffic_selector_t *get_ts_from_range(private_id_payload_t *this, static traffic_selector_t *get_ts_from_subnet(private_id_payload_t *this, ts_type_t type) { + traffic_selector_t *ts; 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); + netmask = chunk_clone(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, + ts = traffic_selector_create_from_bytes(this->protocol_id, type, net, this->port, netmask, this->port ?: 65535); + chunk_free(&netmask); + return ts; } /** diff --git a/src/libcharon/encoding/payloads/ke_payload.c b/src/libcharon/encoding/payloads/ke_payload.c index 4f552d6ac..50fd73f90 100644 --- a/src/libcharon/encoding/payloads/ke_payload.c +++ b/src/libcharon/encoding/payloads/ke_payload.c @@ -247,9 +247,15 @@ ke_payload_t *ke_payload_create(payload_type_t type) 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(type); + private_ke_payload_t *this; + chunk_t value; - dh->get_my_public_value(dh, &this->key_exchange_data); + if (!dh->get_my_public_value(dh, &value)) + { + return NULL; + } + this = (private_ke_payload_t*)ke_payload_create(type); + this->key_exchange_data = value; this->dh_group_number = dh->get_dh_group(dh); this->payload_length += this->key_exchange_data.len; diff --git a/src/libcharon/encoding/payloads/ke_payload.h b/src/libcharon/encoding/payloads/ke_payload.h index dfc6308b4..96c5096a5 100644 --- a/src/libcharon/encoding/payloads/ke_payload.h +++ b/src/libcharon/encoding/payloads/ke_payload.h @@ -73,7 +73,7 @@ ke_payload_t *ke_payload_create(payload_type_t type); * * @param type PLV2_KEY_EXCHANGE or PLV1_KEY_EXCHANGE * @param dh diffie hellman object containing group and key - * @return ke_payload_t object + * @return ke_payload_t object, NULL on error */ ke_payload_t *ke_payload_create_from_diffie_hellman(payload_type_t type, diffie_hellman_t *dh); diff --git a/src/libcharon/encoding/payloads/notify_payload.c b/src/libcharon/encoding/payloads/notify_payload.c index 94723ddd7..f32a1273f 100644 --- a/src/libcharon/encoding/payloads/notify_payload.c +++ b/src/libcharon/encoding/payloads/notify_payload.c @@ -65,7 +65,7 @@ ENUM_NEXT(notify_type_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, CHILD_SA_NOT_ "ME_CONNECT_FAILED"); ENUM_NEXT(notify_type_names, MS_NOTIFY_STATUS, MS_NOTIFY_STATUS, ME_CONNECT_FAILED, "MS_NOTIFY_STATUS"); -ENUM_NEXT(notify_type_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_NOTIFY_STATUS, +ENUM_NEXT(notify_type_names, INITIAL_CONTACT, SIGNATURE_HASH_ALGORITHMS, MS_NOTIFY_STATUS, "INITIAL_CONTACT", "SET_WINDOW_SIZE", "ADDITIONAL_TS_POSSIBLE", @@ -112,8 +112,9 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_NOTIFY "ERX_SUPPORTED", "IFOM_CAPABILITY", "SENDER_REQUEST_ID", - "FRAGMENTATION_SUPPORTED"); -ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, FRAGMENTATION_SUPPORTED, + "FRAGMENTATION_SUPPORTED", + "SIGNATURE_HASH_ALGORITHMS"); +ENUM_NEXT(notify_type_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, SIGNATURE_HASH_ALGORITHMS, "INITIAL_CONTACT"); ENUM_NEXT(notify_type_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1, "DPD_R_U_THERE", @@ -174,7 +175,7 @@ ENUM_NEXT(notify_type_short_names, ME_CONNECT_FAILED, ME_CONNECT_FAILED, CHILD_S "ME_CONN_FAIL"); ENUM_NEXT(notify_type_short_names, MS_NOTIFY_STATUS, MS_NOTIFY_STATUS, ME_CONNECT_FAILED, "MS_STATUS"); -ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_NOTIFY_STATUS, +ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, SIGNATURE_HASH_ALGORITHMS, MS_NOTIFY_STATUS, "INIT_CONTACT", "SET_WINSIZE", "ADD_TS_POSS", @@ -221,8 +222,9 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, FRAGMENTATION_SUPPORTED, MS_ "ERX_SUP", "IFOM_CAP", "SENDER_REQ_ID", - "FRAG_SUP"); -ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, FRAGMENTATION_SUPPORTED, + "FRAG_SUP", + "HASH_ALG"); +ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT_IKEV1, INITIAL_CONTACT_IKEV1, SIGNATURE_HASH_ALGORITHMS, "INITIAL_CONTACT"); ENUM_NEXT(notify_type_short_names, DPD_R_U_THERE, DPD_R_U_THERE_ACK, INITIAL_CONTACT_IKEV1, "DPD", @@ -473,6 +475,14 @@ METHOD(payload_t, verify, status_t, } break; } + case SIGNATURE_HASH_ALGORITHMS: + { + if (this->notify_data.len % 2) + { + bad_length = TRUE; + } + break; + } case AUTH_LIFETIME: { if (this->notify_data.len != 4) diff --git a/src/libcharon/encoding/payloads/notify_payload.h b/src/libcharon/encoding/payloads/notify_payload.h index 25521c2bb..690757383 100644 --- a/src/libcharon/encoding/payloads/notify_payload.h +++ b/src/libcharon/encoding/payloads/notify_payload.h @@ -151,6 +151,8 @@ enum notify_type_t { SENDER_REQUEST_ID = 16429, /* IKEv2 fragmentation supported, RFC 7383 */ FRAGMENTATION_SUPPORTED = 16430, + /* Signature Hash Algorithms, RFC 7427 */ + SIGNATURE_HASH_ALGORITHMS = 16431, /* IKEv1 initial contact */ INITIAL_CONTACT_IKEV1 = 24578, /* IKEv1 DPD */ diff --git a/src/libcharon/encoding/payloads/payload.c b/src/libcharon/encoding/payloads/payload.c index 600b6dd68..a1cd2f945 100644 --- a/src/libcharon/encoding/payloads/payload.c +++ b/src/libcharon/encoding/payloads/payload.c @@ -266,37 +266,51 @@ payload_t *payload_create(payload_type_t type) /** * See header. */ -bool payload_is_known(payload_type_t type) +bool payload_is_known(payload_type_t type, u_int8_t maj_ver) { - if (type == PL_HEADER) + if (type >= PL_HEADER) { return TRUE; } - if (type >= PLV1_SECURITY_ASSOCIATION && type <= PLV1_CONFIGURATION) + switch (maj_ver) { - return TRUE; - } - if (type >= PLV1_NAT_D && type <= PLV1_NAT_OA) - { - return TRUE; - } - if (type >= PLV2_SECURITY_ASSOCIATION && type <= PLV2_EAP) - { - return TRUE; - } - if (type == PLV2_FRAGMENT) - { - return TRUE; - } + case 0: + case IKEV1_MAJOR_VERSION: + if (type >= PLV1_SECURITY_ASSOCIATION && type <= PLV1_CONFIGURATION) + { + return TRUE; + } + if (type >= PLV1_NAT_D && type <= PLV1_NAT_OA) + { + return TRUE; + } + if (type >= PLV1_NAT_D_DRAFT_00_03 && type <= PLV1_FRAGMENT) + { + return TRUE; + } + if (maj_ver) + { + break; + } + /* fall-through */ + case IKEV2_MAJOR_VERSION: + if (type >= PLV2_SECURITY_ASSOCIATION && type <= PLV2_EAP) + { + return TRUE; + } + if (type == PLV2_FRAGMENT) + { + return TRUE; + } #ifdef ME - if (type == PLV2_ID_PEER) - { - return TRUE; - } + if (type == PLV2_ID_PEER) + { + return TRUE; + } #endif - if (type >= PLV1_NAT_D_DRAFT_00_03 && type <= PLV1_FRAGMENT) - { - return TRUE; + break; + default: + break; } return FALSE; } diff --git a/src/libcharon/encoding/payloads/payload.h b/src/libcharon/encoding/payloads/payload.h index 036cd422d..920779bd1 100644 --- a/src/libcharon/encoding/payloads/payload.h +++ b/src/libcharon/encoding/payloads/payload.h @@ -405,9 +405,10 @@ payload_t *payload_create(payload_type_t type); * Check if a specific payload is implemented, or handled as unknown payload. * * @param type type of the payload to check + * @param maj_ver major IKE version (use 0 to skip version check) * @return FALSE if payload type handled as unknown payload */ -bool payload_is_known(payload_type_t type); +bool payload_is_known(payload_type_t type, u_int8_t maj_ver); /** * Get the value field in a payload using encoding rules. diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index 53e8cf3ad..48dcfeb24 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Tobias Brunner + * Copyright (C) 2012-2014 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2005 Jan Hutter * Hochschule fuer Technik Rapperswil @@ -224,26 +224,7 @@ typedef enum { /* 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_transid_t; /** * IKEv1 Transform ID AH authentication algorithm. @@ -264,6 +245,25 @@ typedef enum { } ikev1_ah_transid_t; /** + * IKEv1 authentication algorithm. + */ +typedef enum { + IKEV1_AUTH_HMAC_MD5 = 1, + IKEV1_AUTH_HMAC_SHA = 2, + IKEV1_AUTH_DES_MAC = 3, + IKEV1_AUTH_KPDK = 4, + IKEV1_AUTH_HMAC_SHA2_256 = 5, + IKEV1_AUTH_HMAC_SHA2_384 = 6, + IKEV1_AUTH_HMAC_SHA2_512 = 7, + IKEV1_AUTH_HMAC_RIPEMD = 8, + IKEV1_AUTH_AES_XCBC_MAC = 9, + IKEV1_AUTH_SIG_RSA = 10, + IKEV1_AUTH_AES_128_GMAC = 11, + IKEV1_AUTH_AES_192_GMAC = 12, + IKEV1_AUTH_AES_256_GMAC = 13, +} ikev1_auth_algo_t; + +/** * IKEv1 ESP Encapsulation mode. */ typedef enum { @@ -345,7 +345,7 @@ METHOD(payload_t, verify, status_t, switch (this->protocol_id) { case PROTO_IPCOMP: - if (this->spi.len != 2) + if (this->spi.len != 2 && this->spi.len != 4) { DBG1(DBG_ENC, "invalid CPI length in IPCOMP proposal"); return FAILED; @@ -536,7 +536,7 @@ METHOD(proposal_substructure_t, get_cpi, bool, { if (cpi) { - *cpi = *((u_int16_t*)this->spi.ptr); + *cpi = htons(untoh16(this->spi.ptr + this->spi.len - 2)); } enumerator->destroy(enumerator); return TRUE; @@ -620,7 +620,7 @@ static algo_map_t map_prf[] = { /** * ESP encryption algorithm mapping */ -static algo_map_t map_esp_encr[] = { +static algo_map_t map_esp[] = { { IKEV1_ESP_ENCR_DES_IV64, ENCR_DES_IV64 }, { IKEV1_ESP_ENCR_DES, ENCR_DES }, { IKEV1_ESP_ENCR_3DES, ENCR_3DES }, @@ -646,23 +646,6 @@ static algo_map_t map_esp_encr[] = { }; /** - * 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 }, -}; - -/** * AH authentication algorithm mapping */ static algo_map_t map_ah[] = { @@ -679,34 +662,30 @@ static algo_map_t map_ah[] = { }; /** - * Get IKEv2 algorithm from IKEv1 identifier + * ESP/AH authentication algorithm mapping */ -static u_int16_t get_alg_from_ikev1(transform_type_t type, u_int16_t value) +static algo_map_t map_auth[] = { + { IKEV1_AUTH_HMAC_MD5, AUTH_HMAC_MD5_96 }, + { IKEV1_AUTH_HMAC_SHA, AUTH_HMAC_SHA1_96 }, + { IKEV1_AUTH_DES_MAC, AUTH_DES_MAC }, + { IKEV1_AUTH_KPDK, AUTH_KPDK_MD5 }, + { IKEV1_AUTH_HMAC_SHA2_256, AUTH_HMAC_SHA2_256_128 }, + { IKEV1_AUTH_HMAC_SHA2_384, AUTH_HMAC_SHA2_384_192 }, + { IKEV1_AUTH_HMAC_SHA2_512, AUTH_HMAC_SHA2_512_256 }, + { IKEV1_AUTH_AES_XCBC_MAC, AUTH_AES_XCBC_96 }, + { IKEV1_AUTH_AES_128_GMAC, AUTH_AES_128_GMAC }, + { IKEV1_AUTH_AES_192_GMAC, AUTH_AES_192_GMAC }, + { IKEV1_AUTH_AES_256_GMAC, AUTH_AES_256_GMAC }, +}; + +/** + * Map an IKEv1 to an IKEv2 identifier + */ +static u_int16_t ikev2_from_ikev1(algo_map_t *map, int count, u_int16_t def, + u_int16_t value) { - algo_map_t *map; - u_int16_t def; - int i, count; + int i; - 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) @@ -718,30 +697,12 @@ static u_int16_t get_alg_from_ikev1(transform_type_t type, u_int16_t value) } /** - * Get IKEv1 algorithm from IKEv2 identifier + * Map an IKEv2 to an IKEv1 identifier */ -static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value) +static u_int16_t ikev1_from_ikev2(algo_map_t *map, int count, u_int16_t value) { - algo_map_t *map; - int i, count; + int i; - 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) @@ -753,87 +714,96 @@ static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value) } /** - * Get IKEv2 algorithm from IKEv1 ESP transaction ID + * Get IKEv2 algorithm from IKEv1 identifier */ -static u_int16_t get_alg_from_ikev1_transid(protocol_id_t proto, - transform_type_t type, u_int16_t value) +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_esp_encr; - count = countof(map_esp_encr); - def = ENCR_UNDEFINED; - break; + return ikev2_from_ikev1(map_encr, countof(map_encr), + ENCR_UNDEFINED, value); case INTEGRITY_ALGORITHM: - if (proto == PROTO_ESP) - { - map = map_esp_auth; - count = countof(map_esp_auth); - } - else - { - map = map_ah; - count = countof(map_ah); - } - def = AUTH_UNDEFINED; - break; + return ikev2_from_ikev1(map_integ, countof(map_integ), + AUTH_UNDEFINED, value); + case PSEUDO_RANDOM_FUNCTION: + return ikev2_from_ikev1(map_prf, countof(map_prf), + PRF_UNDEFINED, value); default: return 0; } - for (i = 0; i < count; i++) +} + +/** + * Get IKEv1 algorithm from IKEv2 identifier + */ +static u_int16_t get_ikev1_from_alg(transform_type_t type, u_int16_t value) +{ + switch (type) { - if (map[i].ikev1 == value) - { - return map[i].ikev2; - } + case ENCRYPTION_ALGORITHM: + return ikev1_from_ikev2(map_encr, countof(map_encr), value); + case INTEGRITY_ALGORITHM: + return ikev1_from_ikev2(map_integ, countof(map_integ), value); + case PSEUDO_RANDOM_FUNCTION: + return ikev1_from_ikev2(map_prf, countof(map_prf), value); + default: + return 0; } - return def; } /** - * Get IKEv1 ESP/AH transaction ID from IKEv2 identifier + * Get IKEv2 algorithm from IKEv1 ESP/AH transform ID */ -static u_int16_t get_ikev1_transid_from_alg(protocol_id_t proto, - transform_type_t type, u_int16_t value) +static u_int16_t get_alg_from_ikev1_transid(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; + return ikev2_from_ikev1(map_esp, countof(map_esp), + ENCR_UNDEFINED, value); case INTEGRITY_ALGORITHM: - if (proto == PROTO_ESP) - { - map = map_esp_auth; - count = countof(map_esp_auth); - } - else - { - map = map_ah; - count = countof(map_ah); - } - break; + return ikev2_from_ikev1(map_ah, countof(map_ah), + AUTH_UNDEFINED, value); default: return 0; } - for (i = 0; i < count; i++) +} + +/** + * Get IKEv1 ESP/AH transform ID from IKEv2 identifier + */ +static u_int16_t get_ikev1_transid_from_alg(transform_type_t type, + u_int16_t value) +{ + switch (type) { - if (map[i].ikev2 == value) - { - return map[i].ikev1; - } + case ENCRYPTION_ALGORITHM: + return ikev1_from_ikev2(map_esp, countof(map_esp), value); + case INTEGRITY_ALGORITHM: + return ikev1_from_ikev2(map_ah, countof(map_ah), value); + default: + return 0; } - return 0; } + +/** + * Get IKEv1 authentication algorithm from IKEv2 identifier + */ +static u_int16_t get_alg_from_ikev1_auth(u_int16_t value) +{ + return ikev2_from_ikev1(map_auth, countof(map_auth), AUTH_UNDEFINED, value); +} + +/** + * Get IKEv1 authentication algorithm from IKEv2 identifier + */ +static u_int16_t get_ikev1_auth_from_alg(u_int16_t value) +{ + return ikev1_from_ikev2(map_auth, countof(map_auth), value); +} + /** * Get IKEv1 authentication attribute from auth_method_t */ @@ -971,8 +941,7 @@ static void add_to_proposal_v1(proposal_t *proposal, break; case TATTR_PH2_AUTH_ALGORITHM: proposal->add_algorithm(proposal, INTEGRITY_ALGORITHM, - get_alg_from_ikev1_transid(proto, INTEGRITY_ALGORITHM, - value), 0); + get_alg_from_ikev1_auth(value), 0); break; case TATTR_PH2_GROUP: proposal->add_algorithm(proposal, DIFFIE_HELLMAN_GROUP, @@ -989,7 +958,7 @@ static void add_to_proposal_v1(proposal_t *proposal, NO_EXT_SEQ_NUMBERS, 0); if (proto == PROTO_ESP) { - encr = get_alg_from_ikev1_transid(proto, ENCRYPTION_ALGORITHM, + encr = get_alg_from_ikev1_transid(ENCRYPTION_ALGORITHM, transform->get_transform_id(transform)); if (encr) { @@ -1354,19 +1323,17 @@ static void set_from_proposal_v1(private_proposal_substructure_t *this, ipsec_mode_t mode, encap_t udp, int number) { transform_substructure_t *transform = NULL; - u_int16_t alg, key_size; + u_int16_t alg, transid, key_size; enumerator_t *enumerator; - protocol_id_t proto; - proto = proposal->get_protocol(proposal); enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); if (enumerator->enumerate(enumerator, &alg, &key_size)) { - alg = get_ikev1_transid_from_alg(proto, ENCRYPTION_ALGORITHM, alg); - if (alg) + transid = get_ikev1_transid_from_alg(ENCRYPTION_ALGORITHM, alg); + if (transid) { transform = transform_substructure_create_type( - PLV1_TRANSFORM_SUBSTRUCTURE, number, alg); + PLV1_TRANSFORM_SUBSTRUCTURE, number, transid); if (key_size) { transform->add_transform_attribute(transform, @@ -1380,13 +1347,14 @@ static void set_from_proposal_v1(private_proposal_substructure_t *this, enumerator = proposal->create_enumerator(proposal, INTEGRITY_ALGORITHM); if (enumerator->enumerate(enumerator, &alg, &key_size)) { - alg = get_ikev1_transid_from_alg(proto, INTEGRITY_ALGORITHM, alg); - if (alg) + transid = get_ikev1_transid_from_alg(INTEGRITY_ALGORITHM, alg); + alg = get_ikev1_auth_from_alg(alg); + if (transid && alg) { if (!transform) { transform = transform_substructure_create_type( - PLV1_TRANSFORM_SUBSTRUCTURE, number, alg); + PLV1_TRANSFORM_SUBSTRUCTURE, number, transid); } transform->add_transform_attribute(transform, transform_attribute_create_value(PLV1_TRANSFORM_ATTRIBUTE, |