diff options
Diffstat (limited to 'src/libcharon/encoding')
-rw-r--r-- | src/libcharon/encoding/message.c | 188 | ||||
-rw-r--r-- | src/libcharon/encoding/message.h | 10 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/proposal_substructure.c | 6 | ||||
-rw-r--r-- | src/libcharon/encoding/payloads/sa_payload.c | 5 |
4 files changed, 119 insertions, 90 deletions
diff --git a/src/libcharon/encoding/message.c b/src/libcharon/encoding/message.c index 749c326a5..9bb8e5145 100644 --- a/src/libcharon/encoding/message.c +++ b/src/libcharon/encoding/message.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2011 Tobias Brunner + * Copyright (C) 2006-2013 Tobias Brunner * Copyright (C) 2005-2010 Martin Willi * Copyright (C) 2010 revosec AG * Copyright (C) 2006 Daniel Roethlisberger @@ -1409,7 +1409,7 @@ static encryption_payload_t* wrap_payloads(private_message_t *this) } if (encrypt || this->is_encrypted) { /* encryption is forced for IKEv1 */ - DBG2(DBG_ENC, "insert payload %N to encryption payload", + DBG2(DBG_ENC, "insert payload %N into encrypted payload", payload_type_names, type); encryption->add_payload(encryption, current); } @@ -1799,15 +1799,15 @@ static status_t parse_payloads(private_message_t *this) return VERIFY_ERROR; } - DBG2(DBG_ENC, "%N payload verified. Adding to payload list", + 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 + /* an encrypted payload is the last one, so STOP here. decryption is * done later */ if (type == ENCRYPTED) { - DBG2(DBG_ENC, "%N payload found. Stop parsing", + DBG2(DBG_ENC, "%N payload found, stop parsing", payload_type_names, type); break; } @@ -1817,17 +1817,101 @@ static status_t parse_payloads(private_message_t *this) } /** + * Decrypt an encrypted payload and extract all contained payloads. + */ +static status_t decrypt_and_extract(private_message_t *this, keymat_t *keymat, + payload_t *previous, encryption_payload_t *encryption) +{ + payload_t *encrypted; + payload_type_t type; + chunk_t chunk; + aead_t *aead; + size_t bs; + status_t status = SUCCESS; + + if (!keymat) + { + DBG1(DBG_ENC, "found encrypted payload, but no keymat"); + return INVALID_ARG; + } + aead = keymat->get_aead(keymat, TRUE); + if (!aead) + { + DBG1(DBG_ENC, "found encrypted payload, but no transform set"); + return INVALID_ARG; + } + 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) || + chunk.len < bs) + { + DBG1(DBG_ENC, "invalid payload length"); + return VERIFY_ERROR; + } + 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) + { + return status; + } + + while ((encrypted = encryption->remove_payload(encryption))) + { + type = encrypted->get_type(encrypted); + if (previous) + { + previous->set_next_type(previous, type); + } + else + { + this->first_payload = type; + } + DBG2(DBG_ENC, "insert decrypted payload of type %N at end of list", + payload_type_names, type); + this->payloads->insert_last(this->payloads, encrypted); + previous = encrypted; + } + return SUCCESS; +} + +/** * Decrypt payload from the encryption payload */ 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; + bool was_encrypted = FALSE; enumerator = this->payloads->create_enumerator(this->payloads); while (enumerator->enumerate(enumerator, &payload)) @@ -1839,97 +1923,35 @@ static status_t decrypt_payloads(private_message_t *this, keymat_t *keymat) if (type == ENCRYPTED || type == ENCRYPTED_V1) { encryption_payload_t *encryption; - payload_t *encrypted; - chunk_t chunk; - size_t bs; - - encryption = (encryption_payload_t*)payload; - DBG2(DBG_ENC, "found an encryption payload"); - - if (this->payloads->has_more(this->payloads, enumerator)) + if (was_encrypted) { - DBG1(DBG_ENC, "encrypted payload is not last payload"); + DBG1(DBG_ENC, "encrypted payload can't contain other payloads " + "of type %N", payload_type_names, type); 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) || - chunk.len < bs) + + DBG2(DBG_ENC, "found an encrypted payload"); + encryption = (encryption_payload_t*)payload; + this->payloads->remove_at(this->payloads, enumerator); + + if (enumerator->enumerate(enumerator, NULL)) { - DBG1(DBG_ENC, "invalid payload length"); + DBG1(DBG_ENC, "encrypted payload is not last payload"); + encryption->destroy(encryption); status = VERIFY_ERROR; break; } - 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); - } + status = decrypt_and_extract(this, keymat, previous, encryption); + encryption->destroy(encryption); if (status != SUCCESS) { break; } - was_encrypted = TRUE; - this->payloads->remove_at(this->payloads, enumerator); - - while ((encrypted = encryption->remove_payload(encryption))) - { - type = encrypted->get_type(encrypted); - if (previous) - { - previous->set_next_type(previous, type); - } - else - { - this->first_payload = type; - } - DBG2(DBG_ENC, "insert decrypted payload of type " - "%N at end of list", payload_type_names, type); - this->payloads->insert_last(this->payloads, encrypted); - previous = encrypted; - } - encryption->destroy(encryption); } + if (payload_is_known(type) && !was_encrypted && !is_connectivity_check(this, payload) && this->exchange_type != AGGRESSIVE) diff --git a/src/libcharon/encoding/message.h b/src/libcharon/encoding/message.h index 2c11e4581..7631a7c3a 100644 --- a/src/libcharon/encoding/message.h +++ b/src/libcharon/encoding/message.h @@ -49,7 +49,7 @@ struct message_t { * * @param major_version major version to set */ - void (*set_major_version) (message_t *this,u_int8_t major_version); + void (*set_major_version) (message_t *this, u_int8_t major_version); /** * Gets the IKE major version of the message. @@ -63,7 +63,7 @@ struct message_t { * * @param minor_version minor version to set */ - void (*set_minor_version) (message_t *this,u_int8_t minor_version); + void (*set_minor_version) (message_t *this, u_int8_t minor_version); /** * Gets the IKE minor version of the message. @@ -77,7 +77,7 @@ struct message_t { * * @param message_id message_id to set */ - void (*set_message_id) (message_t *this,u_int32_t message_id); + void (*set_message_id) (message_t *this, u_int32_t message_id); /** * Gets the Message ID of the message. @@ -107,7 +107,7 @@ struct message_t { * * @param ike_sa_id ike_sa_id to set */ - void (*set_ike_sa_id) (message_t *this, ike_sa_id_t * ike_sa_id); + void (*set_ike_sa_id) (message_t *this, ike_sa_id_t *ike_sa_id); /** * Gets the IKE_SA ID of the message. @@ -123,7 +123,7 @@ struct message_t { * * @param exchange_type exchange_type to set */ - void (*set_exchange_type) (message_t *this,exchange_type_t exchange_type); + void (*set_exchange_type) (message_t *this, exchange_type_t exchange_type); /** * Gets the exchange type of the message. diff --git a/src/libcharon/encoding/payloads/proposal_substructure.c b/src/libcharon/encoding/payloads/proposal_substructure.c index ae0fce991..3cf22aefd 100644 --- a/src/libcharon/encoding/payloads/proposal_substructure.c +++ b/src/libcharon/encoding/payloads/proposal_substructure.c @@ -1224,7 +1224,7 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, number, IKEV1_TRANSID_KEY_IKE); enumerator = proposal->create_enumerator(proposal, ENCRYPTION_ALGORITHM); - if (enumerator->enumerate(enumerator, &alg, &key_size)) + while (enumerator->enumerate(enumerator, &alg, &key_size)) { alg = get_ikev1_from_alg(ENCRYPTION_ALGORITHM, alg); if (alg) @@ -1238,13 +1238,14 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH1_KEY_LENGTH, key_size)); } + break; } } 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)) + while (enumerator->enumerate(enumerator, &alg, &key_size)) { alg = get_ikev1_from_alg(INTEGRITY_ALGORITHM, alg); if (alg) @@ -1252,6 +1253,7 @@ static void set_from_proposal_v1_ike(private_proposal_substructure_t *this, transform->add_transform_attribute(transform, transform_attribute_create_value(TRANSFORM_ATTRIBUTE_V1, TATTR_PH1_HASH_ALGORITHM, alg)); + break; } } enumerator->destroy(enumerator); diff --git a/src/libcharon/encoding/payloads/sa_payload.c b/src/libcharon/encoding/payloads/sa_payload.c index a588d4e97..613412014 100644 --- a/src/libcharon/encoding/payloads/sa_payload.c +++ b/src/libcharon/encoding/payloads/sa_payload.c @@ -560,6 +560,11 @@ sa_payload_t *sa_payload_create_from_proposals_v1(linked_list_t *proposals, this = (private_sa_payload_t*)sa_payload_create(SECURITY_ASSOCIATION_V1); + if (!proposals || !proposals->get_count(proposals)) + { + return &this->public; + } + /* 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, |