diff --git a/src/charon/config/connections/connection.c b/src/charon/config/connections/connection.c index 9893c8a4c..9a90f765a 100644 --- a/src/charon/config/connections/connection.c +++ b/src/charon/config/connections/connection.c @@ -213,7 +213,7 @@ static diffie_hellman_group_t get_dh_group(private_connection_t *this) } } iterator->destroy(iterator); - return MODP_UNDEFINED; + return MODP_NONE; } /** diff --git a/src/charon/config/policies/policy.c b/src/charon/config/policies/policy.c index 5f6706bc1..22c63c559 100644 --- a/src/charon/config/policies/policy.c +++ b/src/charon/config/policies/policy.c @@ -22,6 +22,7 @@ #include #include +#include #include "policy.h" @@ -80,7 +81,23 @@ struct private_policy_t { * list for traffic selectors for others site */ linked_list_t *other_ts; - + + /** + * Time before an SA gets invalid + */ + u_int32_t soft_lifetime; + + /** + * Time before an SA gets rekeyed + */ + u_int32_t hard_lifetime; + + /** + * Time, which specifies the range of a random value + * substracted from soft_lifetime. + */ + u_int32_t jitter; + /** * select_traffic_selectors for both */ @@ -313,18 +330,18 @@ static void add_proposal(private_policy_t *this, proposal_t *proposal) /** * Implementation of policy_t.get_soft_lifetime */ -static u_int32_t get_soft_lifetime(policy_t *this) +static u_int32_t get_soft_lifetime(private_policy_t *this) { srandom(time(NULL)+getpid()); - return 5 + (random() % 10); + return this->soft_lifetime - (random() % this->jitter); } /** * Implementation of policy_t.get_hard_lifetime */ -static u_int32_t get_hard_lifetime(policy_t *this) +static u_int32_t get_hard_lifetime(private_policy_t *this) { - return 20; + return this->hard_lifetime; } /** @@ -334,7 +351,9 @@ static policy_t *clone(private_policy_t *this) { private_policy_t *clone = (private_policy_t*)policy_create(this->name, this->my_id->clone(this->my_id), - this->other_id->clone(this->other_id)); + this->other_id->clone(this->other_id), + this->hard_lifetime, this->soft_lifetime, + this->jitter); iterator_t *iterator; proposal_t *proposal; traffic_selector_t *ts; @@ -434,7 +453,9 @@ static status_t destroy(private_policy_t *this) /* * Described in header-file */ -policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id) +policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id, + u_int32_t hard_lifetime, u_int32_t soft_lifetime, + u_int32_t jitter) { private_policy_t *this = malloc_thing(private_policy_t); @@ -465,6 +486,9 @@ policy_t *policy_create(char *name, identification_t *my_id, identification_t *o this->name = strdup(name); this->my_id = my_id; this->other_id = other_id; + this->hard_lifetime = hard_lifetime; + this->soft_lifetime = soft_lifetime; + this->jitter = jitter; /* initialize private members*/ this->my_ca = NULL; diff --git a/src/charon/config/policies/policy.h b/src/charon/config/policies/policy.h index 44ed1922c..089d75112 100644 --- a/src/charon/config/policies/policy.h +++ b/src/charon/config/policies/policy.h @@ -277,14 +277,23 @@ struct policy_t { * @brief Create a configuration object for IKE_AUTH and later. * * name-string gets cloned, ID's not. + * Lifetimes are in seconds. To prevent to peers to start rekeying at the + * same time, a jitter may be specified. Rekeying of an SA starts at + * (soft_lifetime - random(0, jitter)). After a successful rekeying, + * the hard_lifetime limit counter is reset. You should specify + * hard_lifetime > soft_lifetime > jitter. * * @param name name of the policy * @param my_id identification_t for ourselves * @param other_id identification_t for the remote guy + * @param hard_lifetime lifetime before deleting an SA + * @param soft_lifetime lifetime before rekeying an SA + * @param jitter range of randomization time * @return policy_t object * * @ingroup config */ -policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id); +policy_t *policy_create(char *name, identification_t *my_id, identification_t *other_id, + u_int32_t hard_lifetime, u_int32_t soft_lifetime, u_int32_t jitter); #endif /* POLICY_H_ */ diff --git a/src/charon/sa/child_sa.c b/src/charon/sa/child_sa.c index e1dff27da..2b2b6a732 100644 --- a/src/charon/sa/child_sa.c +++ b/src/charon/sa/child_sa.c @@ -82,6 +82,11 @@ struct private_child_sa_t { */ u_int32_t reqid; + /** + * time, on which SA was installed + */ + time_t install_time; + /** * Lifetime before rekeying */ @@ -239,6 +244,8 @@ static status_t install(private_child_sa_t *this, proposal_t *proposal, prf_plus mine ? 0 : this->soft_lifetime, this->hard_lifetime, enc_algo, int_algo, prf_plus, mine); + + this->install_time = time(NULL); return status; } @@ -406,11 +413,12 @@ static void log_status(private_child_sa_t *this, logger_t *logger, char* name) { logger = this->logger; } - logger->log(logger, CONTROL|LEVEL1, " \"%s\": protected with %s (0x%x/0x%x), reqid %d:", + logger->log(logger, CONTROL|LEVEL1, " \"%s\": protected with %s (0x%x/0x%x), reqid %d, rekeying in %ds:", name, this->protocol == PROTO_ESP ? "ESP" : "AH", htonl(this->me.spi), htonl(this->other.spi), - this->reqid); + this->reqid, + this->soft_lifetime - (time(NULL) - this->install_time)); iterator = this->policies->create_iterator(this->policies, TRUE); while (iterator->has_next(iterator)) { diff --git a/src/charon/sa/states/create_child_sa_requested.c b/src/charon/sa/states/create_child_sa_requested.c index b9bf2800d..ebd9469cc 100644 --- a/src/charon/sa/states/create_child_sa_requested.c +++ b/src/charon/sa/states/create_child_sa_requested.c @@ -223,7 +223,15 @@ static status_t process_message(private_create_child_sa_requested_t *this, messa if (response->get_request(response)) { this->logger->log(this->logger, ERROR | LEVEL1, "CREATE_CHILD_SA requests not allowed state create_child_sa_requested"); - return FAILED; + /* TODO: our state implementation currently can not handle incoming requests cleanly here. + * If a request comes in before an outstanding reply, we can not handle it the correct way. + * Currently, we create a ESTABLISHED state and let it process the message... But we + * need changes in the whole state mechanism. + */ + state_t *state = (state_t*)ike_sa_established_create(this->ike_sa); + state->process_message(state, response); + state->destroy(state); + return SUCCESS; } /* get signer for verification and crypter for decryption */ diff --git a/src/charon/sa/states/delete_child_sa_requested.c b/src/charon/sa/states/delete_child_sa_requested.c index 4d4ea5f11..8cad93d8d 100644 --- a/src/charon/sa/states/delete_child_sa_requested.c +++ b/src/charon/sa/states/delete_child_sa_requested.c @@ -80,7 +80,15 @@ static status_t process_message(private_delete_child_sa_requested_t *this, messa if (response->get_request(response)) { this->logger->log(this->logger, ERROR | LEVEL1, "INFORMATIONAL requests not allowed state delete_child_sa_requested"); - return FAILED; + /* TODO: our state implementation currently can not handle incoming requests cleanly here. + * If a request comes in before an outstanding reply, we can not handle it cleanly. + * Currently, we create a ESTABLISHED state and let it process the message... But we + * need changes in the whole state mechanism. + */ + state_t *state = (state_t*)ike_sa_established_create(this->ike_sa); + state->process_message(state, response); + state->destroy(state); + return SUCCESS; } /* get signer for verification and crypter for decryption */ diff --git a/src/charon/sa/states/ike_sa_established.c b/src/charon/sa/states/ike_sa_established.c index 5841f74f4..66f0c103b 100644 --- a/src/charon/sa/states/ike_sa_established.c +++ b/src/charon/sa/states/ike_sa_established.c @@ -274,6 +274,17 @@ static status_t process_create_child_sa(private_ike_sa_established_t *this, mess nonce_request = (nonce_payload_t*)payload; break; } + case KEY_EXCHANGE: + { + /* we currently do not support a diffie hellman exchange + * for CHILD_SAs. */ + u_int16_t no_group[1]; + no_group[0] = htons(MODP_NONE); + chunk_t no_group_chunk = chunk_from_buf(no_group); + this->ike_sa->send_notify(this->ike_sa, CREATE_CHILD_SA, INVALID_KE_PAYLOAD, no_group_chunk); + payloads->destroy(payloads); + return FAILED; + } case NOTIFY: { notify = (notify_payload_t*)payload; diff --git a/src/charon/sa/states/responder_init.c b/src/charon/sa/states/responder_init.c index 2923bbb27..07fcaabd2 100644 --- a/src/charon/sa/states/responder_init.c +++ b/src/charon/sa/states/responder_init.c @@ -369,7 +369,7 @@ static status_t build_ke_payload(private_responder_init_t *this,ke_payload_t *ke this->logger->log(this->logger, CONTROL | LEVEL2, "Process received KE payload"); group = ke_request->get_dh_group_number(ke_request); - if (group == MODP_UNDEFINED) + if (group == MODP_NONE) { this->logger->log(this->logger, AUDIT, "No diffie hellman group to select. Deleting IKE_SA"); return DESTROY_ME; @@ -560,7 +560,7 @@ responder_init_t *responder_init_create(protected_ike_sa_t *ike_sa) this->logger = logger_manager->get_logger(logger_manager, IKE_SA); this->sent_nonce = CHUNK_INITIALIZER; this->received_nonce = CHUNK_INITIALIZER; - this->dh_group_number = MODP_UNDEFINED; + this->dh_group_number = MODP_NONE; this->diffie_hellman = NULL; this->proposal = NULL; diff --git a/src/charon/threads/stroke_interface.c b/src/charon/threads/stroke_interface.c index b2d49c946..2ca9a0a4a 100755 --- a/src/charon/threads/stroke_interface.c +++ b/src/charon/threads/stroke_interface.c @@ -332,7 +332,10 @@ static void stroke_add_conn(private_stroke_t *this, stroke_msg_t *msg) other_host->get_address(other_host), other_id->get_string(other_id)); - policy = policy_create(msg->add_conn.name, my_id, other_id); + policy = policy_create(msg->add_conn.name, my_id, other_id, + msg->add_conn.rekey.ipsec_lifetime, + msg->add_conn.rekey.ipsec_lifetime - msg->add_conn.rekey.margin, + msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100); proposal = proposal_create(PROTO_ESP); proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 128); proposal->add_algorithm(proposal, ENCRYPTION_ALGORITHM, ENCR_AES_CBC, 256); diff --git a/src/libstrongswan/crypto/diffie_hellman.c b/src/libstrongswan/crypto/diffie_hellman.c index 1e3dcc79c..0a3eef352 100644 --- a/src/libstrongswan/crypto/diffie_hellman.c +++ b/src/libstrongswan/crypto/diffie_hellman.c @@ -34,7 +34,7 @@ * String mappings for diffie_hellman_group_t. */ mapping_t diffie_hellman_group_m[] = { - {MODP_UNDEFINED, "MODP_UNDEFINED"}, + {MODP_NONE, "MODP_NONE"}, {MODP_768_BIT, "MODP_768_BIT"}, {MODP_1024_BIT, "MODP_1024_BIT"}, {MODP_1536_BIT, "MODP_1536_BIT"}, diff --git a/src/libstrongswan/crypto/diffie_hellman.h b/src/libstrongswan/crypto/diffie_hellman.h index 48a165557..4f9ba49f7 100644 --- a/src/libstrongswan/crypto/diffie_hellman.h +++ b/src/libstrongswan/crypto/diffie_hellman.h @@ -38,7 +38,7 @@ typedef enum diffie_hellman_group_t diffie_hellman_group_t; * @ingroup transforms */ enum diffie_hellman_group_t { - MODP_UNDEFINED = 1024, + MODP_NONE = 0, MODP_768_BIT = 1, MODP_1024_BIT = 2, MODP_1536_BIT = 5, diff --git a/src/starter/starterstroke.c b/src/starter/starterstroke.c index 16d911f93..b4f85b360 100644 --- a/src/starter/starterstroke.c +++ b/src/starter/starterstroke.c @@ -125,6 +125,11 @@ int starter_stroke_add_conn(starter_conn_t *conn) msg.length = offsetof(stroke_msg_t, buffer); msg.add_conn.ikev2 = conn->keyexchange == KEY_EXCHANGE_IKEV2; msg.add_conn.name = push_string(&msg, connection_name(conn)); + msg.add_conn.rekey.ipsec_lifetime = conn->sa_ipsec_life_seconds; + msg.add_conn.rekey.ike_lifetime = conn->sa_ike_life_seconds; + msg.add_conn.rekey.margin = conn->sa_rekey_margin; + msg.add_conn.rekey.tries = conn->sa_keying_tries; + msg.add_conn.rekey.fuzz = conn->sa_rekey_fuzz; starter_stroke_add_end(&msg, &msg.add_conn.me, &conn->right); starter_stroke_add_end(&msg, &msg.add_conn.other, &conn->left); diff --git a/src/stroke/stroke.c b/src/stroke/stroke.c index 3e2c473eb..d5357222f 100644 --- a/src/stroke/stroke.c +++ b/src/stroke/stroke.c @@ -28,8 +28,6 @@ #include "stroke.h" -#define streq(a, b) (strcmp((a), (b)) == 0) /* clearer shorthand */ - static char* push_string(stroke_msg_t *msg, char *string) { u_int string_start = msg->length; @@ -103,6 +101,12 @@ static int add_connection(char *name, msg.add_conn.name = push_string(&msg, name); msg.add_conn.ikev2 = 1; + msg.add_conn.rekey.ipsec_lifetime = 0; + msg.add_conn.rekey.ike_lifetime = 0; + msg.add_conn.rekey.margin = 0; + msg.add_conn.rekey.tries = 0; + msg.add_conn.rekey.fuzz = 0; + msg.add_conn.me.id = push_string(&msg, my_id); msg.add_conn.me.address = push_string(&msg, my_addr); msg.add_conn.me.subnet = push_string(&msg, my_net); diff --git a/src/stroke/stroke.h b/src/stroke/stroke.h index fd7870f6c..e9bdedd0e 100644 --- a/src/stroke/stroke.h +++ b/src/stroke/stroke.h @@ -86,6 +86,13 @@ struct stroke_msg_t { struct { char *name; bool ikev2; + struct { + time_t ipsec_lifetime; + time_t ike_lifetime; + time_t margin; + unsigned long tries; + unsigned long fuzz; + } rekey; stroke_end_t me, other; } add_conn;