diff options
author | Martin Willi <martin@strongswan.org> | 2006-02-16 09:55:07 +0000 |
---|---|---|
committer | Martin Willi <martin@strongswan.org> | 2006-02-16 09:55:07 +0000 |
commit | 30b5b412da849251d6000c2dc52731af3e5409b8 (patch) | |
tree | feb29be853a779cd1202a013ba0dc674e4c0f4fc /Source/charon | |
parent | ce461bbd13c5ea6a94ba0b34cbb4d1be8159b67e (diff) | |
download | strongswan-30b5b412da849251d6000c2dc52731af3e5409b8.tar.bz2 strongswan-30b5b412da849251d6000c2dc52731af3e5409b8.tar.xz |
- installing of child sa works
- need correct IP adresses to actually use IPsec
Diffstat (limited to 'Source/charon')
23 files changed, 766 insertions, 273 deletions
diff --git a/Source/charon/config/configuration_manager.c b/Source/charon/config/configuration_manager.c index adbd0ddee..07eaf53e2 100644 --- a/Source/charon/config/configuration_manager.c +++ b/Source/charon/config/configuration_manager.c @@ -285,10 +285,8 @@ static void load_default_config (private_configuration_manager_t *this) /* IKE proposals for alice */ proposal = proposal_create(1); proposal->add_algorithm(proposal, IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); - POS; - proposal->add_algorithm(proposal, IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 16); - POS; - proposal->add_algorithm(proposal, IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 16); + proposal->add_algorithm(proposal, IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); + proposal->add_algorithm(proposal, IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0); proposal->add_algorithm(proposal, IKE, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); proposal->add_algorithm(proposal, IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); init_config_a->add_proposal(init_config_a, proposal); @@ -296,8 +294,8 @@ static void load_default_config (private_configuration_manager_t *this) /* IKE proposals for bob */ proposal = proposal_create(1); proposal->add_algorithm(proposal, IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); - proposal->add_algorithm(proposal, IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 16); - proposal->add_algorithm(proposal, IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 16); + proposal->add_algorithm(proposal, IKE, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); + proposal->add_algorithm(proposal, IKE, PSEUDO_RANDOM_FUNCTION, PRF_HMAC_MD5, 0); proposal->add_algorithm(proposal, IKE, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); init_config_b->add_proposal(init_config_b, proposal); @@ -322,16 +320,17 @@ static void load_default_config (private_configuration_manager_t *this) /* child proposal for alice */ proposal = proposal_create(1); - proposal->add_algorithm(proposal, AH, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20); - proposal->add_algorithm(proposal, AH, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20); - proposal->add_algorithm(proposal, AH, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); - proposal->add_algorithm(proposal, AH, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); - proposal->add_algorithm(proposal, AH, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); +// proposal->add_algorithm(proposal, AH, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); +// proposal->add_algorithm(proposal, AH, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); +// proposal->add_algorithm(proposal, AH, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); +// proposal->add_algorithm(proposal, AH, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); +// proposal->add_algorithm(proposal, AH, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); proposal->add_algorithm(proposal, ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); - proposal->add_algorithm(proposal, ESP, ENCRYPTION_ALGORITHM, ENCR_3DES, 32); - proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20); - proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20); + proposal->add_algorithm(proposal, ESP, ENCRYPTION_ALGORITHM, ENCR_3DES, 0); + proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); + proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); + proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_2048_BIT, 0); proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); proposal->add_algorithm(proposal, ESP, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); @@ -340,12 +339,14 @@ static void load_default_config (private_configuration_manager_t *this) /* child proposal for bob */ proposal = proposal_create(1); - proposal->add_algorithm(proposal, AH, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 20); - proposal->add_algorithm(proposal, AH, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); - proposal->add_algorithm(proposal, AH, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); +// proposal->add_algorithm(proposal, AH, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); +// proposal->add_algorithm(proposal, AH, INTEGRITY_ALGORITHM, AUTH_AES_XCBC_96, 0); +// proposal->add_algorithm(proposal, AH, INTEGRITY_ALGORITHM, AUTH_DES_MAC, 0); +// proposal->add_algorithm(proposal, AH, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); +// proposal->add_algorithm(proposal, AH, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); proposal->add_algorithm(proposal, ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); - proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 20); + proposal->add_algorithm(proposal, ESP, INTEGRITY_ALGORITHM, AUTH_HMAC_MD5_96, 0); proposal->add_algorithm(proposal, ESP, DIFFIE_HELLMAN_GROUP, MODP_1024_BIT, 0); proposal->add_algorithm(proposal, ESP, EXTENDED_SEQUENCE_NUMBERS, NO_EXT_SEQ_NUMBERS, 0); diff --git a/Source/charon/config/proposal.c b/Source/charon/config/proposal.c index 528cf9808..a547583d9 100644 --- a/Source/charon/config/proposal.c +++ b/Source/charon/config/proposal.c @@ -339,6 +339,7 @@ static proposal_t *select_proposal(private_proposal_t *this, private_proposal_t protocol_proposal_t *this_prop, *other_prop; protocol_id_t proto; bool add; + u_int64_t spi; /* empty proposal? no match */ if (this->protocol_proposals->get_count(this->protocol_proposals) == 0 || @@ -443,6 +444,19 @@ static proposal_t *select_proposal(private_proposal_t *this, private_proposal_t } } iterator->destroy(iterator); + + /* apply spis from "other" */ + spi = other->public.get_spi(&(other->public), AH); + if (spi) + { + selected->set_spi(selected, AH, spi); + } + spi = other->public.get_spi(&(other->public), ESP); + if (spi) + { + selected->set_spi(selected, ESP, spi); + } + /* everything matched, return new proposal */ return selected; } @@ -487,7 +501,7 @@ static void set_spi(private_proposal_t *this, protocol_id_t proto, u_int64_t spi protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE); if (proto_proposal) { - if (proto == IKE) + if (proto == AH || proto == ESP) { *((u_int32_t*)proto_proposal->spi.ptr) = (u_int32_t)spi; } @@ -495,7 +509,6 @@ static void set_spi(private_proposal_t *this, protocol_id_t proto, u_int64_t spi { *((u_int64_t*)proto_proposal->spi.ptr) = spi; } - } } @@ -507,7 +520,7 @@ static u_int64_t get_spi(private_proposal_t *this, protocol_id_t proto) protocol_proposal_t *proto_proposal = get_protocol_proposal(this, proto, FALSE); if (proto_proposal) { - if (proto == IKE) + if (proto == AH || proto == ESP) { return (u_int64_t)*((u_int32_t*)proto_proposal->spi.ptr); } diff --git a/Source/charon/encoding/generator.c b/Source/charon/encoding/generator.c index a036b8ed4..ff72190dd 100644 --- a/Source/charon/encoding/generator.c +++ b/Source/charon/encoding/generator.c @@ -341,7 +341,7 @@ static void generate_u_int_type (private_generator_t *this,encoding_type_t int_t u_int8_t low_val = *(this->out_position) & 0x0F; /* highval is set, low_val is not changed */ *(this->out_position) = high_val | low_val; - this->logger->log(this->logger, RAW|LEVEL2, " => 0x%x", *(this->out_position)); + this->logger->log(this->logger, RAW|LEVEL2, " => %d", *(this->out_position)); /* write position is not changed, just bit position is moved */ this->current_bit = 4; } @@ -352,7 +352,7 @@ static void generate_u_int_type (private_generator_t *this,encoding_type_t int_t /* lowval of current byte in buffer has to be set to the new value*/ u_int low_val = *((u_int8_t *)(this->data_struct + offset)) & 0x0F; *(this->out_position) = high_val | low_val; - this->logger->log(this->logger, RAW|LEVEL2, " => 0x%x", *(this->out_position)); + this->logger->log(this->logger, RAW|LEVEL2, " => %d", *(this->out_position)); this->out_position++; this->current_bit = 0; @@ -370,7 +370,7 @@ static void generate_u_int_type (private_generator_t *this,encoding_type_t int_t { /* 8 bit values are written as they are */ *this->out_position = *((u_int8_t *)(this->data_struct + offset)); - this->logger->log(this->logger, RAW|LEVEL2, " => 0x%x", *(this->out_position)); + this->logger->log(this->logger, RAW|LEVEL2, " => %d", *(this->out_position)); this->out_position++; break; @@ -392,7 +392,7 @@ static void generate_u_int_type (private_generator_t *this,encoding_type_t int_t int16_val = int16_val & 0xFF7F; int16_val = int16_val | attribute_format_flag; - this->logger->log(this->logger, RAW|LEVEL2, " => 0x%x", int16_val); + this->logger->log(this->logger, RAW|LEVEL2, " => %d", int16_val); /* write bytes to buffer (set bit is overwritten)*/ this->write_bytes_to_buffer(this,&int16_val,sizeof(u_int16_t)); this->current_bit = 0; @@ -516,7 +516,7 @@ static void generate_flag (private_generator_t *this,u_int32_t offset) *(this->out_position) = *(this->out_position) | flag; - this->logger->log(this->logger, RAW|LEVEL2, " => 0x0%x", *(this->out_position)); + this->logger->log(this->logger, RAW|LEVEL2, " => %d", *(this->out_position)); this->current_bit++; if (this->current_bit >= 8) @@ -1017,6 +1017,8 @@ static void generate_payload (private_generator_t *this,payload_t *payload) return; } } + this->logger->log(this->logger, CONTROL|LEVEL2, "generating %s payload finished.", + mapping_find(payload_type_m, payload_type)); this->logger->log_bytes(this->logger, RAW|LEVEL3, "generated data for this payload", payload_start, this->out_position-payload_start); } diff --git a/Source/charon/encoding/payloads/encryption_payload.c b/Source/charon/encoding/payloads/encryption_payload.c index bd720ea4f..8cbf5566c 100644 --- a/Source/charon/encoding/payloads/encryption_payload.c +++ b/Source/charon/encoding/payloads/encryption_payload.c @@ -289,6 +289,7 @@ static status_t encrypt(private_encryption_payload_t *this) this->generate(this); this->logger->log(this->logger, CONTROL|LEVEL2, "encrypting payloads"); + this->logger->log_chunk(this->logger, RAW|LEVEL2, "data to encrypt", &this->decrypted); /* build padding */ block_size = this->crypter->get_block_size(this->crypter); @@ -307,6 +308,8 @@ static status_t encrypt(private_encryption_payload_t *this) iv.len = block_size; randomizer->allocate_pseudo_random_bytes(randomizer, iv.len, &iv); randomizer->destroy(randomizer); + + this->logger->log_chunk(this->logger, RAW|LEVEL2, "data before encryption with padding", &to_crypt); /* encrypt to_crypt chunk */ allocator_free(this->encrypted.ptr); @@ -319,6 +322,8 @@ static status_t encrypt(private_encryption_payload_t *this) allocator_free(iv.ptr); return status; } + this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after encryption", &result); + /* build encrypted result with iv and signature */ this->encrypted.len = iv.len + result.len + this->signer->get_block_size(this->signer); @@ -331,6 +336,8 @@ static status_t encrypt(private_encryption_payload_t *this) allocator_free(result.ptr); allocator_free(iv.ptr); + this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after encryption with IV and (invalid) signature", &this->encrypted); + return SUCCESS; } @@ -345,6 +352,8 @@ static status_t decrypt(private_encryption_payload_t *this) this->logger->log(this->logger, CONTROL|LEVEL2, "decrypting encryption payload"); + this->logger->log_chunk(this->logger, RAW|LEVEL2, "data before decryption with IV and (invalid) signature", &this->encrypted); + if (this->signer == NULL || this->crypter == NULL) { @@ -373,12 +382,16 @@ static status_t decrypt(private_encryption_payload_t *this) /* free previus data, if any */ allocator_free(this->decrypted.ptr); + this->logger->log_chunk(this->logger, RAW|LEVEL2, "data before decryption", &concatenated); + status = this->crypter->decrypt(this->crypter, concatenated, iv, &(this->decrypted)); if (status != SUCCESS) { this->logger->log(this->logger, ERROR|LEVEL1, "could not decrypt, decryption failed"); return FAILED; } + this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after decryption with padding", &this->decrypted); + /* get padding length, sits just bevore signature */ padding_length = *(this->decrypted.ptr + this->decrypted.len - 1); @@ -396,6 +409,7 @@ static status_t decrypt(private_encryption_payload_t *this) /* free padding */ this->decrypted.ptr = allocator_realloc(this->decrypted.ptr, this->decrypted.len); + this->logger->log_chunk(this->logger, RAW|LEVEL2, "data after decryption without padding", &this->decrypted); this->logger->log(this->logger, CONTROL|LEVEL2, "decryption successful, trying to parse content"); return (this->parse(this)); } diff --git a/Source/charon/encoding/payloads/proposal_substructure.c b/Source/charon/encoding/payloads/proposal_substructure.c index 2cf96fbb6..922dde40d 100644 --- a/Source/charon/encoding/payloads/proposal_substructure.c +++ b/Source/charon/encoding/payloads/proposal_substructure.c @@ -226,6 +226,7 @@ static void set_next_type(private_proposal_substructure_t *this,payload_type_t t */ static size_t get_length(private_proposal_substructure_t *this) { + this->compute_length(this); return this->proposal_length; } @@ -384,9 +385,8 @@ static void compute_length (private_proposal_substructure_t *this) iterator->destroy(iterator); length += this->spi.len; - this->transforms_count= transforms_count; - this->proposal_length = length; - + this->transforms_count = transforms_count; + this->proposal_length = length; } /** @@ -411,8 +411,8 @@ static size_t get_spi_size (private_proposal_substructure_t *this) void add_to_proposal(private_proposal_substructure_t *this, proposal_t *proposal) { iterator_t *iterator = this->transforms->create_iterator(this->transforms, TRUE); + u_int32_t spi; - proposal->set_spi(proposal, this->protocol_id, *((u_int32_t*)this->spi.ptr)); while (iterator->has_next(iterator)) { @@ -430,6 +430,10 @@ void add_to_proposal(private_proposal_substructure_t *this, proposal_t *proposal proposal->add_algorithm(proposal, this->protocol_id, transform_type, transform_id, key_length); } iterator->destroy(iterator); + + spi = *((u_int32_t*)this->spi.ptr); + + proposal->set_spi(proposal, this->protocol_id, spi); } /** @@ -561,14 +565,6 @@ proposal_substructure_t *proposal_substructure_create_from_proposal(proposal_t * algorithm_t *algo; transform_substructure_t *transform; - /* take over general infos */ - this->spi_size = proto == IKE ? 8 : 4; - this->spi.len = this->spi_size; - this->spi.ptr = allocator_alloc(this->spi_size); - *((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal, proto); - this->proposal_number = proposal->get_number(proposal); - this->protocol_id = proto; - /* encryption algorithm is only availble in ESP */ iterator = proposal->create_algorithm_iterator(proposal, proto, ENCRYPTION_ALGORITHM); while (iterator->has_next(iterator)) @@ -623,5 +619,13 @@ proposal_substructure_t *proposal_substructure_create_from_proposal(proposal_t * } iterator->destroy(iterator); + /* take over general infos */ + this->spi_size = proto == IKE ? 8 : 4; + this->spi.len = this->spi_size; + this->spi.ptr = allocator_alloc(this->spi_size); + *((u_int32_t*)this->spi.ptr) = proposal->get_spi(proposal, proto); + this->proposal_number = proposal->get_number(proposal); + this->protocol_id = proto; + return &(this->public); } diff --git a/Source/charon/encoding/payloads/transform_substructure.c b/Source/charon/encoding/payloads/transform_substructure.c index e2f368fd8..9b0bbf4ed 100644 --- a/Source/charon/encoding/payloads/transform_substructure.c +++ b/Source/charon/encoding/payloads/transform_substructure.c @@ -343,7 +343,6 @@ static void compute_length (private_transform_substructure_t *this) iterator->destroy(iterator); this->transform_length = length; - } /** @@ -476,20 +475,13 @@ transform_substructure_t *transform_substructure_create_type(transform_type_t tr transform->set_transform_type(transform,transform_type); transform->set_transform_id(transform,transform_id); - switch (transform_type) + /* a keylength attribute is only created for AES encryption */ + if (transform_type == ENCRYPTION_ALGORITHM && + transform_id == ENCR_AES_CBC) { - case ENCRYPTION_ALGORITHM: - case PSEUDO_RANDOM_FUNCTION: - case INTEGRITY_ALGORITHM: - { - transform_attribute_t *attribute = transform_attribute_create_key_length(key_length); - transform->add_transform_attribute(transform,attribute); - break; - } - default: - { - /* no keylength attribute is created */ - } - } + transform_attribute_t *attribute = transform_attribute_create_key_length(key_length); + transform->add_transform_attribute(transform,attribute); + } + return transform; } diff --git a/Source/charon/sa/child_sa.c b/Source/charon/sa/child_sa.c index 2c4624310..6754e8022 100644 --- a/Source/charon/sa/child_sa.c +++ b/Source/charon/sa/child_sa.c @@ -39,14 +39,29 @@ struct private_child_sa_t { child_sa_t public; /** - * CHILD_SAs own logger + * IP of this peer */ - logger_t *logger; + host_t *me; /** - * Protocols used in this SA + * IP of other peer */ - protocol_id_t protocols[2]; + host_t *other; + + /** + * Security parameter index for AH protocol, 0 if not used + */ + u_int32_t ah_spi; + + /** + * Security parameter index for ESP protocol, 0 if not used + */ + u_int32_t esp_spi; + + /** + * CHILD_SAs own logger + */ + logger_t *logger; }; @@ -59,65 +74,271 @@ static u_int32_t get_spi(private_child_sa_t *this) } /** - * Implementation of child_sa_t.destroy. + * Implements child_sa_t.alloc */ -static void destroy(private_child_sa_t *this) +static status_t alloc(private_child_sa_t *this, linked_list_t *proposals) { - charon->logger_manager->destroy_logger(charon->logger_manager, this->logger); - allocator_free(this); + protocol_id_t protocols[2]; + iterator_t *iterator; + proposal_t *proposal; + status_t status; + u_int i; + + /* iterator through proposals */ + iterator = proposals->create_iterator(proposals, TRUE); + while(iterator->has_next(iterator)) + { + iterator->current(iterator, (void**)&proposal); + proposal->get_protocols(proposal, protocols); + + /* check all protocols */ + for (i = 0; i<2; i++) + { + switch (protocols[i]) + { + case AH: + /* do we already have an spi for AH?*/ + if (this->ah_spi == 0) + { + /* nope, get one */ + status = charon->kernel_interface->get_spi( + charon->kernel_interface, + this->me, this->other, + AH, FALSE, + &(this->ah_spi)); + } + /* update proposal */ + proposal->set_spi(proposal, AH, (u_int64_t)this->ah_spi); + break; + case ESP: + /* do we already have an spi for ESP?*/ + if (this->esp_spi == 0) + { + /* nope, get one */ + status = charon->kernel_interface->get_spi( + charon->kernel_interface, + this->me, this->other, + ESP, FALSE, + &(this->esp_spi)); + } + /* update proposal */ + proposal->set_spi(proposal, ESP, (u_int64_t)this->esp_spi); + break; + default: + break; + } + if (status != SUCCESS) + { + iterator->destroy(iterator); + return FAILED; + } + } + } + iterator->destroy(iterator); + return SUCCESS; } -/* - * Described in header. - */ -child_sa_t * child_sa_create(proposal_t *proposal, prf_plus_t *prf_plus) +static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus, bool mine) { - private_child_sa_t *this = allocator_alloc_thing(private_child_sa_t); + protocol_id_t protocols[2]; + u_int32_t spi; + encryption_algorithm_t enc_algo; + integrity_algorithm_t int_algo; + chunk_t enc_key, int_key; + algorithm_t *algo; + crypter_t *crypter; + signer_t *signer; + size_t key_size; + host_t *src; + host_t *dst; + status_t status; u_int i; - - /* public functions */ - this->public.get_spi = (u_int32_t(*)(child_sa_t*))get_spi; - this->public.destroy = (void(*)(child_sa_t*))destroy; - - /* private data */ - this->logger = charon->logger_manager->create_logger(charon->logger_manager, CHILD_SA, NULL); - proposal->get_protocols(proposal, this->protocols); - /* derive keys */ + /* we must assign the roles to correctly set up the SAs */ + if (mine) + { + src = this->me; + dst = this->other; + } + else + { + dst = this->me; + src = this->other; + } + + proposal->get_protocols(proposal, protocols); + /* derive keys in order as protocols appear */ for (i = 0; i<2; i++) { - if (this->protocols[i] != UNDEFINED_PROTOCOL_ID) + if (protocols[i] != UNDEFINED_PROTOCOL_ID) { - algorithm_t *algo; - chunk_t key; - /* get encryption key */ - if (proposal->get_algorithm(proposal, this->protocols[i], ENCRYPTION_ALGORITHM, &algo)) + /* now we have to decide which spi to use. Use self allocated, if "mine", + * or the one in the proposal, if not "mine" (others). */ + if (mine) + { + if (protocols[i] == AH) + { + spi = this->ah_spi; + } + else + { + spi = this->esp_spi; + } + } + else /* use proposals spi */ + { + spi = proposal->get_spi(proposal, protocols[i]); + } + + /* derive encryption key first */ + if (proposal->get_algorithm(proposal, protocols[i], ENCRYPTION_ALGORITHM, &algo)) { - this->logger->log(this->logger, CONTROL|LEVEL1, "%s: using %s %s, ", - mapping_find(protocol_id_m, this->protocols[i]), + enc_algo = algo->algorithm; + this->logger->log(this->logger, CONTROL|LEVEL1, "%s for %s: using %s %s, ", + mapping_find(protocol_id_m, protocols[i]), + mine ? "me" : "other", mapping_find(transform_type_m, ENCRYPTION_ALGORITHM), - mapping_find(encryption_algorithm_m, algo->algorithm)); + mapping_find(encryption_algorithm_m, enc_algo)); - prf_plus->allocate_bytes(prf_plus, algo->key_size, &key); - this->logger->log_chunk(this->logger, PRIVATE, "key:", &key); - allocator_free_chunk(&key); + /* we must create a (unused) crypter, since its the only way to get the size + * of the key. This is not so nice, since charon must support all algorithms + * the kernel supports... + * TODO: build something of a encryption algorithm lookup function + */ + crypter = crypter_create(enc_algo, algo->key_size); + key_size = crypter->get_key_size(crypter); + crypter->destroy(crypter); + prf_plus->allocate_bytes(prf_plus, key_size, &enc_key); + this->logger->log_chunk(this->logger, PRIVATE, "key:", &enc_key); + } + else + { + enc_algo = ENCR_UNDEFINED; } - /* get integrity key */ - if (proposal->get_algorithm(proposal, this->protocols[i], INTEGRITY_ALGORITHM, &algo)) + /* derive integrity key */ + if (proposal->get_algorithm(proposal, protocols[i], INTEGRITY_ALGORITHM, &algo)) { - this->logger->log(this->logger, CONTROL|LEVEL1, "%s: using %s %s,", - mapping_find(protocol_id_m, this->protocols[i]), + int_algo = algo->algorithm; + this->logger->log(this->logger, CONTROL|LEVEL1, "%s for %s: using %s %s,", + mapping_find(protocol_id_m, protocols[i]), + mine ? "me" : "other", mapping_find(transform_type_m, INTEGRITY_ALGORITHM), mapping_find(integrity_algorithm_m, algo->algorithm)); - prf_plus->allocate_bytes(prf_plus, algo->key_size, &key); - this->logger->log_chunk(this->logger, PRIVATE, "key:", &key); - allocator_free_chunk(&key); + signer = signer_create(int_algo); + key_size = signer->get_key_size(signer); + signer->destroy(signer); + prf_plus->allocate_bytes(prf_plus, key_size, &int_key); + this->logger->log_chunk(this->logger, PRIVATE, "key:", &int_key); + } + else + { + int_algo = AUTH_UNDEFINED; + } + /* send keys down to kernel */ + this->logger->log(this->logger, CONTROL|LEVEL1, + "installing 0x%.8x for %s, src %s dst %s", + ntohl(spi), mapping_find(protocol_id_m, protocols[i]), + src->get_address(src), dst->get_address(dst)); + status = charon->kernel_interface->add_sa(charon->kernel_interface, + src, dst, + spi, protocols[i], FALSE, + enc_algo, enc_key, + int_algo, int_key, mine); + /* clean up for next round */ + if (enc_algo != ENCR_UNDEFINED) + { + allocator_free_chunk(&enc_key); } + if (int_algo != AUTH_UNDEFINED) + { + allocator_free_chunk(&int_key); + } + + if (status != SUCCESS) + { + return FAILED; + } + } } + return SUCCESS; +} + +static status_t add(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus) +{ + linked_list_t *list; + + /* install others (initiators) SAs*/ + if (install(this, proposal, prf_plus, FALSE) != SUCCESS) + { + return FAILED; + } + + /* get SPIs for our SAs */ + list = linked_list_create(); + list->insert_last(list, proposal); + if (alloc(this, list) != SUCCESS) + { + list->destroy(list); + return FAILED; + } + list->destroy(list); + + /* install our (responders) SAs */ + if (install(this, proposal, prf_plus, TRUE) != SUCCESS) + { + return FAILED; + } + return SUCCESS; +} + +static status_t update(private_child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus) +{ + /* install our (initator) SAs */ + if (install(this, proposal, prf_plus, TRUE) != SUCCESS) + { + return FAILED; + } + /* install his (responder) SAs */ + if (install(this, proposal, prf_plus, FALSE) != SUCCESS) + { + return FAILED; + } + return SUCCESS; +} + +/** + * Implementation of child_sa_t.destroy. + */ +static void destroy(private_child_sa_t *this) +{ + charon->logger_manager->destroy_logger(charon->logger_manager, this->logger); + allocator_free(this); +} + +/* + * Described in header. + */ +child_sa_t * child_sa_create(host_t *me, host_t* other) +{ + private_child_sa_t *this = allocator_alloc_thing(private_child_sa_t); + + /* public functions */ + this->public.get_spi = (u_int32_t(*)(child_sa_t*))get_spi; + this->public.alloc = (status_t(*)(child_sa_t*,linked_list_t*))alloc; + this->public.add = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))add; + this->public.update = (status_t(*)(child_sa_t*,proposal_t*,prf_plus_t*))update; + this->public.destroy = (void(*)(child_sa_t*))destroy; + + /* private data */ + this->logger = charon->logger_manager->create_logger(charon->logger_manager, CHILD_SA, NULL); + this->me = me; + this->other = other; + this->ah_spi = 0; + this->esp_spi = 0; return (&this->public); } diff --git a/Source/charon/sa/child_sa.h b/Source/charon/sa/child_sa.h index bde032b74..260c4f29c 100644 --- a/Source/charon/sa/child_sa.h +++ b/Source/charon/sa/child_sa.h @@ -50,6 +50,11 @@ struct child_sa_t { * @return 4 Byte SPI value */ u_int32_t (*get_spi) (child_sa_t *this); + + + status_t (*alloc)(child_sa_t *this, linked_list_t* proposals); + status_t (*add)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus); + status_t (*update)(child_sa_t *this, proposal_t *proposal, prf_plus_t *prf_plus); /** * @brief Destroys a child_sa. @@ -67,6 +72,6 @@ struct child_sa_t { * @return child_sa_t object * @ingroup sa */ -child_sa_t * child_sa_create(proposal_t *proposal, prf_plus_t *prf_plus); +child_sa_t * child_sa_create(host_t *me, host_t *other); #endif /*_CHILD_SA_H_*/ diff --git a/Source/charon/sa/ike_sa.c b/Source/charon/sa/ike_sa.c index ac617faef..55c03ef92 100644 --- a/Source/charon/sa/ike_sa.c +++ b/Source/charon/sa/ike_sa.c @@ -417,7 +417,7 @@ status_t retransmit_request (private_ike_sa_t *this, u_int32_t message_id) */ static void set_new_state (private_ike_sa_t *this, state_t *state) { - this->logger->log(this->logger, CONTROL, "Change current state %s to %s", + this->logger->log(this->logger, CONTROL, "statechange: %s => %s", mapping_find(ike_sa_state_m,this->current_state->get_state(this->current_state)), mapping_find(ike_sa_state_m,state->get_state(state))); this->current_state = state; @@ -964,6 +964,14 @@ static ike_sa_state_t get_state (private_ike_sa_t *this) } /** + * Implementation of protected_ike_sa_t.get_state. + */ +static void add_child_sa (private_ike_sa_t *this, child_sa_t *child_sa) +{ + this->child_sas->insert_last(this->child_sas, child_sa); +} + +/** * Implementation of protected_ike_sa_t.reset_message_buffers. */ static void reset_message_buffers (private_ike_sa_t *this) @@ -1008,21 +1016,17 @@ static void create_delete_established_ike_sa_job (private_ike_sa_t *this,u_int32 */ static void destroy (private_ike_sa_t *this) { + child_sa_t *child_sa; + this->logger->log(this->logger, CONTROL|LEVEL2, "Going to destroy IKE SA %llu:%llu, role %s", this->ike_sa_id->get_initiator_spi(this->ike_sa_id), this->ike_sa_id->get_responder_spi(this->ike_sa_id), this->ike_sa_id->is_initiator(this->ike_sa_id) ? "initiator" : "responder"); /* destroy child sa's */ - this->logger->log(this->logger, CONTROL | LEVEL3, "Destroy all child_sa's"); - while (this->child_sas->get_count(this->child_sas) > 0) + while (this->child_sas->remove_last(this->child_sas, (void**)&child_sa) == SUCCESS) { - void *child_sa; - if (this->child_sas->remove_first(this->child_sas, &child_sa) != SUCCESS) - { - break; - } - /* destroy child sa */ + child_sa->destroy(child_sa); } this->child_sas->destroy(this->child_sas); @@ -1134,7 +1138,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->protected.get_child_prf = (prf_t *(*) (protected_ike_sa_t *)) get_child_prf; this->protected.get_prf_auth_i = (prf_t *(*) (protected_ike_sa_t *)) get_prf_auth_i; this->protected.get_prf_auth_r = (prf_t *(*) (protected_ike_sa_t *)) get_prf_auth_r; - this->protected.get_logger = (logger_t *(*) (protected_ike_sa_t *)) get_logger; + this->protected.add_child_sa = (void (*) (protected_ike_sa_t*,child_sa_t*)) add_child_sa; + this->protected.get_logger = (logger_t *(*) (protected_ike_sa_t *)) get_logger; this->protected.set_init_config = (void (*) (protected_ike_sa_t *,init_config_t *)) set_init_config; this->protected.get_init_config = (init_config_t *(*) (protected_ike_sa_t *)) get_init_config; this->protected.set_sa_config = (void (*) (protected_ike_sa_t *,sa_config_t *)) set_sa_config; diff --git a/Source/charon/sa/ike_sa.h b/Source/charon/sa/ike_sa.h index f5591a00b..b15a8eaab 100644 --- a/Source/charon/sa/ike_sa.h +++ b/Source/charon/sa/ike_sa.h @@ -27,10 +27,11 @@ #include <encoding/message.h> #include <encoding/payloads/proposal_substructure.h> #include <sa/ike_sa_id.h> +#include <sa/child_sa.h> +#include <sa/states/state.h> #include <config/configuration_manager.h> #include <utils/logger.h> #include <utils/randomizer.h> -#include <sa/states/state.h> #include <transforms/prfs/prf.h> #include <transforms/crypters/crypter.h> #include <transforms/signers/signer.h> @@ -388,6 +389,14 @@ struct protected_ike_sa_t { prf_t *(*get_prf_auth_r) (protected_ike_sa_t *this); /** + * @brief Associates a child SA to this IKE SA + * + * @param this calling object + * @param child_sa child_sa to add + */ + void (*add_child_sa) (protected_ike_sa_t *this, child_sa_t *child_sa); + + /** * @brief Get the last responded message. * * @param this calling object diff --git a/Source/charon/sa/states/ike_auth_requested.c b/Source/charon/sa/states/ike_auth_requested.c index e6559319c..328971579 100644 --- a/Source/charon/sa/states/ike_auth_requested.c +++ b/Source/charon/sa/states/ike_auth_requested.c @@ -71,6 +71,11 @@ struct private_ike_auth_requested_t { * IKE_SA_INIT-Request in binary form. */ chunk_t ike_sa_init_reply_data; + + /** + * Child sa created in ike_sa_init_requested + */ + child_sa_t *child_sa; /** * Assigned Logger. @@ -136,6 +141,16 @@ struct private_ike_auth_requested_t { * - DELETE_ME */ status_t (*process_notify_payload) (private_ike_auth_requested_t *this, notify_payload_t *notify_payload); + + /** + * Destroy function called internally of this class after state change to + * state IKE_SA_ESTABLISHED succeeded. + * + * This destroy function does not destroy objects which were passed to the new state. + * + * @param this calling object + */ + void (*destroy_after_state_change) (private_ike_auth_requested_t *this); }; @@ -288,7 +303,7 @@ static status_t process_message(private_ike_auth_requested_t *this, message_t *i this->ike_sa->create_delete_established_ike_sa_job(this->ike_sa,this->sa_config->get_ike_sa_lifetime(this->sa_config)); this->ike_sa->set_new_state(this->ike_sa, (state_t*)ike_sa_established_create(this->ike_sa)); - this->public.state_interface.destroy(&(this->public.state_interface)); + this->destroy_after_state_change(this); return SUCCESS; } @@ -328,7 +343,6 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa { proposal_t *proposal, *proposal_tmp; linked_list_t *proposal_list; - child_sa_t *child_sa; chunk_t seed; prf_plus_t *prf_plus; @@ -377,10 +391,19 @@ static status_t process_sa_payload(private_ike_auth_requested_t *this, sa_payloa prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); allocator_free_chunk(&seed); - child_sa = child_sa_create(proposal, prf_plus); - prf_plus->destroy(prf_plus); - child_sa->destroy(child_sa); + if (this->child_sa) + { + if (this->child_sa->update(this->child_sa, proposal, prf_plus) != SUCCESS) + { + this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); + prf_plus->destroy(prf_plus); + proposal->destroy(proposal); + return DELETE_ME; + } + this->ike_sa->add_child_sa(this->ike_sa, this->child_sa); + } + prf_plus->destroy(prf_plus); proposal->destroy(proposal); return SUCCESS; @@ -524,6 +547,20 @@ static void destroy(private_ike_auth_requested_t *this) { allocator_free_chunk(&(this->received_nonce)); allocator_free_chunk(&(this->sent_nonce)); + allocator_free_chunk(&(this->ike_sa_init_reply_data)); + if (this->child_sa) + { + this->child_sa->destroy(this->child_sa); + } + allocator_free(this); +} +/** + * Implements protected_ike_sa_t.destroy_after_state_change + */ +static void destroy_after_state_change(private_ike_auth_requested_t *this) +{ + allocator_free_chunk(&(this->received_nonce)); + allocator_free_chunk(&(this->sent_nonce)); allocator_free_chunk(&(this->ike_sa_init_reply_data)); allocator_free(this); } @@ -531,7 +568,7 @@ static void destroy(private_ike_auth_requested_t *this) /* * Described in header. */ -ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk_t sent_nonce,chunk_t received_nonce,chunk_t ike_sa_init_reply_data) +ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk_t sent_nonce,chunk_t received_nonce,chunk_t ike_sa_init_reply_data, child_sa_t *child_sa) { private_ike_auth_requested_t *this = allocator_alloc_thing(private_ike_auth_requested_t); @@ -541,12 +578,12 @@ ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk this->public.state_interface.destroy = (void (*) (state_t *)) destroy; /* private functions */ - this->process_idr_payload = process_idr_payload; this->process_sa_payload = process_sa_payload; this->process_auth_payload = process_auth_payload; this->process_ts_payload = process_ts_payload; this->process_notify_payload = process_notify_payload; + this->destroy_after_state_change = destroy_after_state_change; /* private data */ this->ike_sa = ike_sa; @@ -554,6 +591,7 @@ ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa,chunk this->sent_nonce = sent_nonce; this->ike_sa_init_reply_data = ike_sa_init_reply_data; this->logger = this->ike_sa->get_logger(this->ike_sa); + this->child_sa = child_sa; return &(this->public); } diff --git a/Source/charon/sa/states/ike_auth_requested.h b/Source/charon/sa/states/ike_auth_requested.h index 34b948856..a8eef014c 100644 --- a/Source/charon/sa/states/ike_auth_requested.h +++ b/Source/charon/sa/states/ike_auth_requested.h @@ -41,8 +41,6 @@ typedef struct ike_auth_requested_t ike_auth_requested_t; * * @todo handle certificate payloads * - * @todo setup child SAs, if requested - * * @ingroup states */ struct ike_auth_requested_t { @@ -60,6 +58,7 @@ struct ike_auth_requested_t { * @param sent_nonce Sent nonce value in IKE_SA_INIT request * @param received_nonce Received nonce value in IKE_SA_INIT response * @param ike_sa_init_reply_data binary representation of IKE_SA_INIT reply + * @param child_sa opened but not completed child_sa * @return created ike_auth_requested_t object * * @ingroup states @@ -67,6 +66,7 @@ struct ike_auth_requested_t { ike_auth_requested_t *ike_auth_requested_create(protected_ike_sa_t *ike_sa, chunk_t sent_nonce, chunk_t received_nonce, - chunk_t ike_sa_init_reply_data); + chunk_t ike_sa_init_reply_data, + child_sa_t *child_sa); #endif /*IKE_AUTH_REQUESTED_H_*/ diff --git a/Source/charon/sa/states/ike_sa_init_requested.c b/Source/charon/sa/states/ike_sa_init_requested.c index 327eb2d7c..55f38883f 100644 --- a/Source/charon/sa/states/ike_sa_init_requested.c +++ b/Source/charon/sa/states/ike_sa_init_requested.c @@ -80,6 +80,11 @@ struct private_ike_sa_init_requested_t { chunk_t ike_sa_init_request_data; /** + * Created child sa, if any + */ + child_sa_t *child_sa; + + /** * Assigned logger * * Is logger of ike_sa! @@ -187,8 +192,6 @@ struct private_ike_sa_init_requested_t { * Destroy function called internally of this class after state change to * state IKE_AUTH_REQUESTED succeeded. * - * In case of state change to INITIATOR_INIT the default destroy function gets called. - * * This destroy function does not destroy objects which were passed to the new state. * * @param this calling object @@ -383,7 +386,8 @@ static status_t process_message(private_ike_sa_init_requested_t *this, message_t ike_sa_init_reply_data = ike_sa_init_reply->get_packet_data(ike_sa_init_reply); /* state can now be changed */ - next_state = ike_auth_requested_create(this->ike_sa,this->sent_nonce,this->received_nonce,ike_sa_init_reply_data); + next_state = ike_auth_requested_create(this->ike_sa, this->sent_nonce, this->received_nonce, + ike_sa_init_reply_data, this->child_sa); this->ike_sa->set_new_state(this->ike_sa,(state_t *) next_state); this->destroy_after_state_change(this); @@ -512,10 +516,22 @@ static status_t build_sa_payload (private_ike_sa_init_requested_t *this, message /* get proposals form config, add to payload */ sa_config = this->ike_sa->get_sa_config(this->ike_sa); proposal_list = sa_config->get_proposals(sa_config); + /* build child sa */ + this->child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); + if (this->child_sa->alloc(this->child_sa, proposal_list) != SUCCESS) + { + this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); + return DELETE_ME; + } + + /* TODO: + * Huston, we've got a problem here. Since SPIs are stored in + * the proposal, and these proposals are shared across configs, + * there may be some threading issues... fix it! + */ sa_payload = sa_payload_create_from_proposal_list(proposal_list); - /* TODO child sa stuff */ - this->logger->log(this->logger, CONTROL|LEVEL2, "Add SA payload to message"); request->add_payload(request,(payload_t *) sa_payload); @@ -705,6 +721,10 @@ static void destroy(private_ike_sa_init_requested_t *this) allocator_free(this->sent_nonce.ptr); allocator_free(this->received_nonce.ptr); allocator_free_chunk(&(this->ike_sa_init_request_data)); + if (this->child_sa) + { + this->child_sa->destroy(this->child_sa); + } if (this->proposal) { this->proposal->destroy(this->proposal); @@ -743,6 +763,7 @@ ike_sa_init_requested_t *ike_sa_init_requested_create(protected_ike_sa_t *ike_sa this->diffie_hellman = diffie_hellman; this->proposal = NULL; this->sent_nonce = sent_nonce; + this->child_sa = NULL; this->ike_sa_init_request_data = ike_sa_init_request_data; return &(this->public); diff --git a/Source/charon/sa/states/ike_sa_init_responded.c b/Source/charon/sa/states/ike_sa_init_responded.c index 536041d0d..70baa5143 100644 --- a/Source/charon/sa/states/ike_sa_init_responded.c +++ b/Source/charon/sa/states/ike_sa_init_responded.c @@ -425,10 +425,6 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo return DELETE_ME; } - /* create payload with selected propsal */ - sa_response = sa_payload_create_from_proposal(proposal); - response->add_payload(response, (payload_t*)sa_response); - /* install child SAs for AH and esp */ seed = allocator_alloc_as_chunk(this->received_nonce.len + this->sent_nonce.len); memcpy(seed.ptr, this->received_nonce.ptr, this->received_nonce.len); @@ -436,10 +432,22 @@ static status_t build_sa_payload(private_ike_sa_init_responded_t *this, sa_paylo prf_plus = prf_plus_create(this->ike_sa->get_child_prf(this->ike_sa), seed); allocator_free_chunk(&seed); - child_sa = child_sa_create(proposal, prf_plus); - prf_plus->destroy(prf_plus); - child_sa->destroy(child_sa); + child_sa = child_sa_create(this->ike_sa->get_my_host(this->ike_sa), + this->ike_sa->get_other_host(this->ike_sa)); + if (child_sa->add(child_sa, proposal, prf_plus) != SUCCESS) + { + this->logger->log(this->logger, AUDIT, "Could not install CHILD_SA! Deleting IKE_SA"); + prf_plus->destroy(prf_plus); + proposal->destroy(proposal); + return DELETE_ME; + } + this->ike_sa->add_child_sa(this->ike_sa, child_sa); + + /* create payload with selected propsal */ + sa_response = sa_payload_create_from_proposal(proposal); + response->add_payload(response, (payload_t*)sa_response); + prf_plus->destroy(prf_plus); proposal->destroy(proposal); return SUCCESS; } diff --git a/Source/charon/testcases/Makefile.testcases b/Source/charon/testcases/Makefile.testcases index a459e3221..e21b5c258 100644 --- a/Source/charon/testcases/Makefile.testcases +++ b/Source/charon/testcases/Makefile.testcases @@ -127,4 +127,8 @@ $(BUILD_DIR)rsa_test.o : $(TESTCASES_DIR)rsa_test.c $(TESTCASES_DIR)rsa_test.h TEST_OBJS+= $(BUILD_DIR)kernel_interface_test.o $(BUILD_DIR)kernel_interface_test.o : $(TESTCASES_DIR)kernel_interface_test.c $(TESTCASES_DIR)kernel_interface_test.h $(CC) $(CFLAGS) -c -o $@ $< + +TEST_OBJS+= $(BUILD_DIR)child_sa_test.o +$(BUILD_DIR)child_sa_test.o : $(TESTCASES_DIR)child_sa_test.c $(TESTCASES_DIR)child_sa_test.h + $(CC) $(CFLAGS) -c -o $@ $<
\ No newline at end of file diff --git a/Source/charon/testcases/child_sa_test.c b/Source/charon/testcases/child_sa_test.c new file mode 100644 index 000000000..09b49b78a --- /dev/null +++ b/Source/charon/testcases/child_sa_test.c @@ -0,0 +1,102 @@ +/** + * @file child_sa_test.c + * + * @brief Tests for the child_sa_t class. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "child_sa_test.h" + +#include <daemon.h> +#include <sa/child_sa.h> +#include <utils/allocator.h> +#include <utils/logger.h> + + +/** + * Described in header. + */ +void test_child_sa(protected_tester_t *tester) +{ + proposal_t *proposal1, *proposal2; + linked_list_t *list; + host_t *local_me, *remote_me; + host_t *local_other, *remote_other; + child_sa_t *local_sa, *remote_sa; + prf_plus_t *local_prf_plus, *remote_prf_plus; + prf_t *local_prf, *remote_prf; + u_int8_t key_buffer[] = {0x01,0x02,0x03,0x04}; + chunk_t key = {key_buffer, sizeof(key_buffer)}; + status_t status; + + /* setup test data */ + local_me = host_create(AF_INET, "192.168.0.1", 0); + local_other = host_create(AF_INET, "192.168.0.2", 0); + remote_me = host_create(AF_INET, "192.168.0.3", 0); + remote_other = host_create(AF_INET, "192.168.0.4", 0); + + local_sa = child_sa_create(local_me, local_other); + remote_sa = child_sa_create(remote_me, remote_other); + + proposal1 = proposal_create(1); + proposal1->add_algorithm(proposal1, ESP, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 16); + + proposal2 = proposal_create(2); + proposal2->add_algorithm(proposal2, AH, INTEGRITY_ALGORITHM, AUTH_HMAC_SHA1_96, 0); + + list = linked_list_create(); + list->insert_last(list, proposal1); + list->insert_last(list, proposal2); + + local_prf = prf_create(PRF_HMAC_SHA1); + remote_prf = prf_create(PRF_HMAC_SHA1); + local_prf->set_key(local_prf, key); + remote_prf->set_key(remote_prf, key); + local_prf_plus = prf_plus_create(local_prf, key); + remote_prf_plus = prf_plus_create(remote_prf, key); + + /* + * local plays initiator + *********************** + */ + status = local_sa->alloc(local_sa, list); + tester->assert_true(tester, status == SUCCESS, "spi allocation"); + + status = remote_sa->add(remote_sa, proposal1, remote_prf_plus); + tester->assert_true(tester, status == SUCCESS, "sa add"); + + status = local_sa->update(local_sa, proposal1, local_prf_plus); + tester->assert_true(tester, status == SUCCESS, "sa update"); + + /* cleanup */ + proposal1->destroy(proposal1); + proposal2->destroy(proposal2); + list->destroy(list); + local_prf->destroy(local_prf); + local_prf_plus->destroy(local_prf_plus); + remote_prf->destroy(remote_prf); + remote_prf_plus->destroy(remote_prf_plus); + local_sa->destroy(local_sa); + remote_sa->destroy(remote_sa); + local_me->destroy(local_me); + local_other->destroy(local_other); + remote_me->destroy(remote_me); + remote_other->destroy(remote_other); + + +} diff --git a/Source/charon/testcases/child_sa_test.h b/Source/charon/testcases/child_sa_test.h new file mode 100644 index 000000000..00e4db163 --- /dev/null +++ b/Source/charon/testcases/child_sa_test.h @@ -0,0 +1,42 @@ +/** + * @file child_sa_test.h + * + * @brief Tests for the child_sa_t class. + * + */ + +/* + * Copyright (C) 2005 Jan Hutter, Martin Willi + * Hochschule fuer Technik Rapperswil + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + + +#ifndef CHILD_SA_TEST_H_ +#define CHILD_SA_TEST_H_ + +#include <utils/tester.h> + +/** + * @brief Test function used to test the child_sa_t functionality. + * + * @param tester associated protected_tester_t object + * + * @ingroup testcases + */ +void test_child_sa(protected_tester_t *tester); + +#endif //CHILD_SA_TEST_H_ + + + + diff --git a/Source/charon/testcases/init_config_test.c b/Source/charon/testcases/init_config_test.c index 5e4506ab5..d75b00e66 100644 --- a/Source/charon/testcases/init_config_test.c +++ b/Source/charon/testcases/init_config_test.c @@ -32,9 +32,9 @@ void test_init_config(protected_tester_t *tester) { init_config_t *init_config = init_config_create("192.168.0.1","192.168.0.2",500,500); - proposal_t *prop1, *prop2, *prop3, *prop4, *selected_one; + proposal_t *prop1, *prop2, *prop3, *prop4;//, *selected_one; linked_list_t *list; - status_t status; + //status_t status; prop1 = proposal_create(1); prop1->add_algorithm(prop1, IKE, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 20); diff --git a/Source/charon/testcases/kernel_interface_test.c b/Source/charon/testcases/kernel_interface_test.c index 2f26c807a..8eb2d5f52 100644 --- a/Source/charon/testcases/kernel_interface_test.c +++ b/Source/charon/testcases/kernel_interface_test.c @@ -65,10 +65,10 @@ void test_kernel_interface(protected_tester_t *tester) - //status = kernel_interface->get_spi(kernel_interface, me, other, 50, TRUE, &spi); - //tester->assert_true(tester, status == SUCCESS, "spi get"); + status = kernel_interface->get_spi(kernel_interface, me, other, 50, FALSE, &spi); + tester->assert_true(tester, status == SUCCESS, "spi get"); - status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, TRUE, ENCR_AES_CBC, enc_key,AUTH_HMAC_MD5_96,inc_key,TRUE); + status = kernel_interface->add_sa(kernel_interface, me, other, spi, 50, FALSE, ENCR_AES_CBC, enc_key,AUTH_UNDEFINED,inc_key,TRUE); tester->assert_true(tester, status == SUCCESS, "build sa"); diff --git a/Source/charon/testcases/testcases.c b/Source/charon/testcases/testcases.c index af539cb4f..8c391ca33 100644 --- a/Source/charon/testcases/testcases.c +++ b/Source/charon/testcases/testcases.c @@ -61,6 +61,7 @@ #include <testcases/proposal_test.h> #include <testcases/rsa_test.h> #include <testcases/kernel_interface_test.h> +#include <testcases/child_sa_test.h> /* output for test messages */ extern FILE * stderr; @@ -126,6 +127,7 @@ test_t sa_config_test = {test_sa_config, "sa_config_t test"}; test_t proposal_test = {test_proposal, "proposal_t test"}; test_t rsa_test = {test_rsa, "RSA private/public key test"}; test_t kernel_interface_test = {test_kernel_interface, "Kernel Interface"}; +test_t child_sa_test = {test_child_sa, "Child SA"}; daemon_t* charon; @@ -138,6 +140,7 @@ static void daemon_kill(daemon_t *this, char* none) this->job_queue->destroy(this->job_queue); this->event_queue->destroy(this->event_queue); this->send_queue->destroy(this->send_queue); + this->kernel_interface->destroy(this->kernel_interface); //this->configuration_manager->destroy(this->configuration_manager); allocator_free(charon); } @@ -160,6 +163,7 @@ daemon_t *daemon_create() charon->job_queue = job_queue_create(); charon->event_queue = event_queue_create(); charon->send_queue = send_queue_create(); + charon->kernel_interface = kernel_interface_create(); //charon->configuration_manager = configuration_manager_create(RETRANSMIT_TIMEOUT,MAX_RETRANSMIT_COUNT,HALF_OPEN_IKE_SA_TIMEOUT); charon->sender = NULL; charon->receiver = NULL; @@ -237,6 +241,8 @@ int main() &rsa_test, NULL }; + /* get rid of compiler warning ;-) */ + *all_tests = *all_tests; /* allocator needs initialization */ allocator_init(); @@ -244,13 +250,14 @@ int main() daemon_create(); charon->logger_manager->disable_logger_level(charon->logger_manager,TESTER,FULL); + charon->logger_manager->enable_logger_level(charon->logger_manager,CHILD_SA,FULL); /* charon->logger_manager->enable_logger_level(charon->logger_manager,TESTER,RAW); */ tester_t *tester = tester_create(test_output, FALSE); - tester->perform_tests(tester,all_tests); - //tester->perform_test(tester,&kernel_interface_test); + //tester->perform_tests(tester,all_tests); + tester->perform_test(tester,&child_sa_test); tester->destroy(tester); diff --git a/Source/charon/threads/kernel_interface.c b/Source/charon/threads/kernel_interface.c index 4fba85cbd..f5273e100 100644 --- a/Source/charon/threads/kernel_interface.c +++ b/Source/charon/threads/kernel_interface.c @@ -40,6 +40,10 @@ #include <utils/linked_list.h> +#define KERNEL_ESP 50 +#define KERNEL_AH 51 + + typedef struct netlink_message_t netlink_message_t; /** @@ -83,48 +87,48 @@ struct private_kernel_interface_t { /** * Public part of the kernel_interface_t object. */ - kernel_interface_t public; - - /** - * Netlink communication socket. - */ - int socket; - + kernel_interface_t public; + + /** + * Netlink communication socket. + */ + int socket; + pid_t pid; - /** - * Sequence number for messages. - */ - u_int32_t seq; - - /** - * List of responded messages. - */ - linked_list_t *responses; - - /** - * Thread which receives messages. - */ - pthread_t thread; - - /** - * Mutex locks access to replies list. - */ - pthread_mutex_t mutex; - - /** - * Condvar allows signaling of threads waiting for a reply. - */ - pthread_cond_t condvar; - - /** - * Function for the thread, receives messages. - */ - void (*receive_messages) (private_kernel_interface_t *this); - - /** - * Sends a netlink_message_t down to the kernel and wait for reply. - */ - status_t (*send_message) (private_kernel_interface_t *this, netlink_message_t *request, netlink_message_t **response); + /** + * Sequence number for messages. + */ + u_int32_t seq; + + /** + * List of responded messages. + */ + linked_list_t *responses; + + /** + * Thread which receives messages. + */ + pthread_t thread; + + /** + * Mutex locks access to replies list. + */ + pthread_mutex_t mutex; + + /** + * Condvar allows signaling of threads waiting for a reply. + */ + pthread_cond_t condvar; + + /** + * Function for the thread, receives messages. + */ + void (*receive_messages) (private_kernel_interface_t *this); + + /** + * Sends a netlink_message_t down to the kernel and wait for reply. + */ + status_t (*send_message) (private_kernel_interface_t *this, netlink_message_t *request, netlink_message_t **response); }; mapping_t kernel_encryption_algs_m[] = { @@ -157,41 +161,42 @@ static status_t get_spi(private_kernel_interface_t *this, host_t *src, host_t *d { netlink_message_t request, *response; - memset(&request, 0, sizeof(request)); - request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.spi))); - request.hdr.nlmsg_flags = NLM_F_REQUEST; - request.hdr.nlmsg_type = XFRM_MSG_ALLOCSPI; + memset(&request, 0, sizeof(request)); + request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.spi))); + request.hdr.nlmsg_flags = NLM_F_REQUEST; + request.hdr.nlmsg_type = XFRM_MSG_ALLOCSPI; request.spi.info.saddr = src->get_xfrm_addr(src); request.spi.info.id.daddr = dest->get_xfrm_addr(dest); - request.spi.info.mode = tunnel_mode; - request.spi.info.id.proto = protocol; - request.spi.info.family = PF_INET; - request.spi.min = 100; - request.spi.max = 200; - - if (this->send_message(this, &request, &response) != SUCCESS) - { - return FAILED; - } - - if (response->hdr.nlmsg_type == NLMSG_ERROR) - { - return FAILED; - } - - if (response->hdr.nlmsg_type != XFRM_MSG_NEWSA) - { - return FAILED; - } - else if (response->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(response->sa))) - { + request.spi.info.mode = tunnel_mode; + /* TODO: this should be done with getprotobyname() */ + request.spi.info.id.proto = (protocol == ESP) ? KERNEL_ESP : KERNEL_AH; + request.spi.info.family = PF_INET; + request.spi.min = 100; + request.spi.max = 200; + + if (this->send_message(this, &request, &response) != SUCCESS) + { return FAILED; - } + } + + if (response->hdr.nlmsg_type == NLMSG_ERROR) + { + return FAILED; + } + + if (response->hdr.nlmsg_type != XFRM_MSG_NEWSA) + { + return FAILED; + } + else if (response->hdr.nlmsg_len < NLMSG_LENGTH(sizeof(response->sa))) + { + return FAILED; + } *spi = response->sa.id.spi; allocator_free(response); - - return SUCCESS; + + return SUCCESS; } static status_t add_sa( private_kernel_interface_t *this, @@ -206,45 +211,46 @@ static status_t add_sa( private_kernel_interface_t *this, chunk_t integrity_key, bool replace) { - netlink_message_t request, *response; - POS; - memset(&request, 0, sizeof(request)); - - request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; - request.hdr.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; - - request.sa.saddr = me->get_xfrm_addr(me); - request.sa.id.daddr = other->get_xfrm_addr(other); - - request.sa.id.spi = spi; - request.sa.id.proto = protocol; - request.sa.family = me->get_family(me); - request.sa.mode = tunnel_mode; - request.sa.replay_window = 0; //sa->replay_window; ??? - request.sa.reqid = 0; //sa->reqid; ??? - request.sa.lft.soft_byte_limit = XFRM_INF; - request.sa.lft.soft_packet_limit = XFRM_INF; - request.sa.lft.hard_byte_limit = XFRM_INF; - request.sa.lft.hard_packet_limit = XFRM_INF; - - request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.sa))); - - if (enc_alg != ENCR_UNDEFINED) - { + netlink_message_t request, *response; + memset(&request, 0, sizeof(request)); + + + request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + request.hdr.nlmsg_type = replace ? XFRM_MSG_UPDSA : XFRM_MSG_NEWSA; + + request.sa.saddr = me->get_xfrm_addr(me); + request.sa.id.daddr = other->get_xfrm_addr(other); + + request.sa.id.spi = spi; + /* TODO: this should be done with getprotobyname() */ + request.sa.id.proto = (protocol == ESP) ? KERNEL_ESP : KERNEL_AH; + request.sa.family = me->get_family(me); + request.sa.mode = tunnel_mode; + request.sa.replay_window = 0; //sa->replay_window; ??? + request.sa.reqid = 0; //sa->reqid; ??? + request.sa.lft.soft_byte_limit = XFRM_INF; + request.sa.lft.soft_packet_limit = XFRM_INF; + request.sa.lft.hard_byte_limit = XFRM_INF; + request.sa.lft.hard_packet_limit = XFRM_INF; + + request.hdr.nlmsg_len = NLMSG_ALIGN(NLMSG_LENGTH(sizeof(request.sa))); + + if (enc_alg != ENCR_UNDEFINED) + { netlink_algo_t *nla = (netlink_algo_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len); - - nla->type = XFRMA_ALG_CRYPT; + + nla->type = XFRMA_ALG_CRYPT; nla->length = sizeof(netlink_algo_t) + encryption_key.len; nla->algo.alg_key_len = encryption_key.len * 8; strcpy(nla->algo.alg_name, mapping_find(kernel_encryption_algs_m, enc_alg)); memcpy(nla->algo.alg_key, encryption_key.ptr, encryption_key.len); - + request.hdr.nlmsg_len += nla->length; - } - - if (int_alg != AUTH_UNDEFINED) - { + } + + if (int_alg != AUTH_UNDEFINED) + { netlink_algo_t *nla = (netlink_algo_t*)(((u_int8_t*)&request) + request.hdr.nlmsg_len); nla->type = XFRMA_ALG_AUTH; @@ -252,20 +258,20 @@ static status_t add_sa( private_kernel_interface_t *this, nla->algo.alg_key_len = integrity_key.len * 8; strcpy(nla->algo.alg_name, mapping_find(kernel_integrity_algs_m, int_alg)); memcpy(nla->algo.alg_key, integrity_key.ptr, integrity_key.len); - + request.hdr.nlmsg_len += nla->length; - } - - /* add IPComp */ - - if (this->send_message(this, &request, &response) != SUCCESS) - { - allocator_free(response); - return FAILED; - } - - allocator_free(response); - return SUCCESS; + } + + /* add IPComp here*/ + + if (this->send_message(this, &request, &response) != SUCCESS) + { + allocator_free(response); + return FAILED; + } + + allocator_free(response); + return SUCCESS; } @@ -276,7 +282,7 @@ static status_t send_message(private_kernel_interface_t *this, netlink_message_t request->hdr.nlmsg_seq = ++this->seq; request->hdr.nlmsg_pid = this->pid; - + memset(&addr, 0, sizeof(struct sockaddr_nl)); addr.nl_family = AF_NETLINK; addr.nl_pid = 0; @@ -308,17 +314,17 @@ static status_t send_message(private_kernel_interface_t *this, netlink_message_t if (listed_response->hdr.nlmsg_seq == request->hdr.nlmsg_seq) { /* matches our request, this is the reply */ - *response = listed_response; - found = TRUE; - break; - } - } - iterator->destroy(iterator); - - if (found) - { - break; - } + *response = listed_response; + found = TRUE; + break; + } + } + iterator->destroy(iterator); + + if (found) + { + break; + } /* we should time out, if something goes wrong */ pthread_cond_wait(&(this->condvar), &(this->mutex)); } @@ -330,16 +336,16 @@ static status_t send_message(private_kernel_interface_t *this, netlink_message_t static void receive_messages(private_kernel_interface_t *this) -{ +{ while(TRUE) { netlink_message_t response, *listed_response; while (TRUE) { - struct sockaddr_nl addr; + struct sockaddr_nl addr; socklen_t addr_length; size_t length; - + addr_length = sizeof(addr); response.hdr.nlmsg_type = XFRM_MSG_NEWSA; @@ -347,11 +353,11 @@ static void receive_messages(private_kernel_interface_t *this) if (length < 0) { if (errno == EINTR) - { - /* interrupted, try again */ + { + /* interrupted, try again */ continue; - } - charon->kill(charon, "receiving from netlink socket failed"); + } + charon->kill(charon, "receiving from netlink socket failed"); } if (!NLMSG_OK(&response.hdr, length)) { @@ -361,7 +367,7 @@ static void receive_messages(private_kernel_interface_t *this) if (addr.nl_pid != 0) { /* not from kernel. not interested, try another one */ - continue; + continue; } break; } diff --git a/Source/charon/threads/kernel_interface.h b/Source/charon/threads/kernel_interface.h index eeebbcdf8..7f57a04d6 100644 --- a/Source/charon/threads/kernel_interface.h +++ b/Source/charon/threads/kernel_interface.h @@ -54,8 +54,8 @@ struct kernel_interface_t { * @todo Cleanup method params */ status_t (*add_sa)(kernel_interface_t *this, - host_t *me, - host_t *other, + host_t *src, + host_t *dst, u_int32_t spi, int protocol, bool tunnel_mode, diff --git a/Source/charon/utils/logger_manager.c b/Source/charon/utils/logger_manager.c index 036024180..fb832efdf 100644 --- a/Source/charon/utils/logger_manager.c +++ b/Source/charon/utils/logger_manager.c @@ -175,11 +175,10 @@ static logger_t *create_logger(private_logger_manager_t *this, logger_context_t log_thread_ids = TRUE; break; case IKE_SA: - logger_level |= LEVEL1; log_thread_ids = TRUE; break; case CHILD_SA: - logger_level |= LEVEL1|PRIVATE; + logger_level |= LEVEL1; log_thread_ids = TRUE; break; case CONFIGURATION_MANAGER: |