diff options
author | Martin Willi <martin@revosec.ch> | 2010-11-25 12:32:41 +0100 |
---|---|---|
committer | Martin Willi <martin@revosec.ch> | 2011-01-05 16:45:53 +0100 |
commit | 6bd3a1c22050dd4b0ef6fd6edfff3423a87fa377 (patch) | |
tree | 141c3e1f1c0ab9f1f3ab99ecd1eb7a357fc604a5 /src/conftest/hooks | |
parent | 5f15faebc81682a9814bb8e5ae46001de69d4717 (diff) | |
download | strongswan-6bd3a1c22050dd4b0ef6fd6edfff3423a87fa377.tar.bz2 strongswan-6bd3a1c22050dd4b0ef6fd6edfff3423a87fa377.tar.xz |
The set_reserved() hook rebuilds AUTH if it mangles ID payload fields
Diffstat (limited to 'src/conftest/hooks')
-rw-r--r-- | src/conftest/hooks/set_reserved.c | 247 |
1 files changed, 214 insertions, 33 deletions
diff --git a/src/conftest/hooks/set_reserved.c b/src/conftest/hooks/set_reserved.c index 77a605d2a..f0f2b0955 100644 --- a/src/conftest/hooks/set_reserved.c +++ b/src/conftest/hooks/set_reserved.c @@ -16,6 +16,9 @@ #include "hook.h" #include <encoding/payloads/sa_payload.h> +#include <encoding/payloads/nonce_payload.h> +#include <encoding/payloads/auth_payload.h> +#include <encoding/payloads/id_payload.h> typedef struct private_set_reserved_t private_set_reserved_t; @@ -43,9 +46,138 @@ struct private_set_reserved_t { * Hook name */ char *name; + + /** + * Our IKE_SA_INIT data, required to rebuild AUTH + */ + chunk_t ike_init; + + /** + * Received NONCE, required to rebuild AUTH + */ + chunk_t nonce; }; /** + * Rebuild our AUTH data + */ +static bool rebuild_auth(private_set_reserved_t *this, ike_sa_t *ike_sa, + message_t *message) +{ + enumerator_t *enumerator; + chunk_t octets, auth_data; + private_key_t *private; + auth_cfg_t *auth; + payload_t *payload; + auth_payload_t *auth_payload; + auth_method_t auth_method; + signature_scheme_t scheme; + keymat_t *keymat; + identification_t *id; + id_payload_t *id_payload; + char reserved[3]; + u_int8_t *byte; + int i; + + id_payload = (id_payload_t*)message->get_payload(message, + message->get_request(message) ? ID_INITIATOR : ID_RESPONDER); + if (!id_payload) + { + DBG1(DBG_CFG, "ID payload not found to rebuild AUTH"); + return FALSE; + } + id = id_payload->get_identification(id_payload); + for (i = 0; i < countof(reserved); i++) + { + byte = payload_get_field(&id_payload->payload_interface, + RESERVED_BYTE, i); + if (byte) + { + reserved[i] = *byte; + } + } + + auth = auth_cfg_create(); + private = lib->credmgr->get_private(lib->credmgr, KEY_ANY, id, auth); + auth->destroy(auth); + if (private == NULL) + { + DBG1(DBG_CFG, "no private key found for '%Y' to rebuild AUTH", id); + id->destroy(id); + return FALSE; + } + + switch (private->get_type(private)) + { + case KEY_RSA: + scheme = SIGN_RSA_EMSA_PKCS1_SHA1; + auth_method = AUTH_RSA; + break; + case KEY_ECDSA: + /* we try to deduct the signature scheme from the keysize */ + switch (private->get_keysize(private)) + { + case 256: + scheme = SIGN_ECDSA_256; + auth_method = AUTH_ECDSA_256; + break; + case 384: + scheme = SIGN_ECDSA_384; + auth_method = AUTH_ECDSA_384; + break; + case 521: + scheme = SIGN_ECDSA_521; + auth_method = AUTH_ECDSA_521; + break; + default: + DBG1(DBG_CFG, "%d bit ECDSA private key size not supported", + private->get_keysize(private)); + id->destroy(id); + return FALSE; + } + break; + default: + DBG1(DBG_CFG, "private key of type %N not supported", + key_type_names, private->get_type(private)); + id->destroy(id); + return FALSE; + } + keymat = ike_sa->get_keymat(ike_sa); + octets = keymat->get_auth_octets(keymat, FALSE, this->ike_init, + this->nonce, id, reserved); + if (!private->sign(private, scheme, octets, &auth_data)) + { + chunk_free(&octets); + private->destroy(private); + id->destroy(id); + return FALSE; + } + auth_payload = auth_payload_create(); + auth_payload->set_auth_method(auth_payload, auth_method); + auth_payload->set_data(auth_payload, auth_data); + chunk_free(&auth_data); + chunk_free(&octets); + private->destroy(private); + + enumerator = message->create_payload_enumerator(message); + while (enumerator->enumerate(enumerator, &payload)) + { + if (payload->get_type(payload) == AUTHENTICATION) + { + message->remove_payload_at(message, enumerator); + payload->destroy(payload); + } + } + enumerator->destroy(enumerator); + + message->add_payload(message, (payload_t*)auth_payload); + DBG1(DBG_CFG, "rebuilding AUTH payload for '%Y' with %N", + id, auth_method_names, auth_method); + id->destroy(id); + return TRUE; +} + +/** * Set reserved bit of a payload */ static void set_bit(private_set_reserved_t *this, message_t *message, @@ -85,7 +217,7 @@ static void set_bit(private_set_reserved_t *this, message_t *message, * Set reserved byte of a payload */ static void set_byte(private_set_reserved_t *this, message_t *message, - payload_type_t type, u_int nr, u_int8_t byteval) + payload_type_t type, u_int nr, u_int8_t byteval) { enumerator_t *payloads; payload_t *payload; @@ -161,6 +293,60 @@ static void set_byte(private_set_reserved_t *this, message_t *message, } } +/** + * Mangle reserved bits and bytes. Returns TRUE if IKE_AUTH must be rebuilt + */ +static bool set_reserved(private_set_reserved_t *this, message_t *message) +{ + enumerator_t *bits, *bytes, *types; + payload_type_t type; + char *nr, *name; + u_int8_t byteval; + bool rebuild = FALSE; + + types = conftest->test->create_section_enumerator(conftest->test, + "hooks.%s", this->name); + while (types->enumerate(types, &name)) + { + type = atoi(name); + if (!type) + { + type = enum_from_name(payload_type_short_names, name); + if (type == -1) + { + DBG1(DBG_CFG, "invalid payload name '%s'", name); + break; + } + } + nr = conftest->test->get_str(conftest->test, + "hooks.%s.%s.bits", "", this->name, name); + bits = enumerator_create_token(nr, ",", " "); + while (bits->enumerate(bits, &nr)) + { + set_bit(this, message, type, atoi(nr)); + } + bits->destroy(bits); + + nr = conftest->test->get_str(conftest->test, + "hooks.%s.%s.bytes", "", this->name, name); + byteval = conftest->test->get_int(conftest->test, + "hooks.%s.%s.byteval", 255, this->name, name); + bytes = enumerator_create_token(nr, ",", " "); + while (bytes->enumerate(bytes, &nr)) + { + set_byte(this, message, type, atoi(nr), byteval); + } + bytes->destroy(bytes); + if ((this->req && type == ID_INITIATOR) || + (!this->req && type == ID_RESPONDER)) + { + rebuild = TRUE; + } + } + types->destroy(types); + return rebuild; +} + METHOD(listener_t, message, bool, private_set_reserved_t *this, ike_sa_t *ike_sa, message_t *message, bool incoming) @@ -169,46 +355,39 @@ METHOD(listener_t, message, bool, message->get_request(message) == this->req && message->get_message_id(message) == this->id) { - enumerator_t *bits, *bytes, *types; - payload_type_t type; - char *nr, *name; - u_int8_t byteval; - - types = conftest->test->create_section_enumerator(conftest->test, - "hooks.%s", this->name); - while (types->enumerate(types, &name)) + if (set_reserved(this, message)) { - type = atoi(name); - if (!type) + if (message->get_message_id(message) == 1) { - type = enum_from_name(payload_type_short_names, name); - if (type == -1) - { - DBG1(DBG_CFG, "invalid payload name '%s'", name); - break; - } + rebuild_auth(this, ike_sa, message); } - nr = conftest->test->get_str(conftest->test, - "hooks.%s.%s.bits", "", this->name, name); - bits = enumerator_create_token(nr, ",", " "); - while (bits->enumerate(bits, &nr)) + } + } + if (message->get_exchange_type(message) == IKE_SA_INIT) + { + if (incoming) + { + nonce_payload_t *nonce; + + nonce = (nonce_payload_t*)message->get_payload(message, NONCE); + if (nonce) { - set_bit(this, message, type, atoi(nr)); + free(this->nonce.ptr); + this->nonce = nonce->get_nonce(nonce); } - bits->destroy(bits); - - nr = conftest->test->get_str(conftest->test, - "hooks.%s.%s.bytes", "", this->name, name); - byteval = conftest->test->get_int(conftest->test, - "hooks.%s.%s.byteval", 255, this->name, name); - bytes = enumerator_create_token(nr, ",", " "); - while (bytes->enumerate(bytes, &nr)) + } + else + { + packet_t *packet; + + if (message->generate(message, NULL, &packet) == SUCCESS) { - set_byte(this, message, type, atoi(nr), byteval); + free(this->ike_init.ptr); + this->ike_init = chunk_clone(packet->get_data(packet)); + packet->destroy(packet); } - bytes->destroy(bytes); + } - types->destroy(types); } return TRUE; } @@ -216,6 +395,8 @@ METHOD(listener_t, message, bool, METHOD(hook_t, destroy, void, private_set_reserved_t *this) { + free(this->ike_init.ptr); + free(this->nonce.ptr); free(this->name); free(this); } |