From ee61471113c2eac23324c5e8a4b5843ca0679e09 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Tue, 20 Nov 2007 12:06:40 +0000 Subject: [PATCH] implemented RFC4478 (repeated authentication) changed %V printf handler to take a time delta, %#V now takes two arguments --- src/charon/config/backends/sqlite_backend.c | 17 +- src/charon/config/peer_cfg.c | 94 ++++++---- src/charon/config/peer_cfg.h | 44 ++--- .../control/interfaces/stroke_interface.c | 42 +++-- src/charon/encoding/payloads/notify_payload.c | 26 +-- src/charon/encoding/payloads/notify_payload.h | 5 +- src/charon/sa/ike_sa.c | 172 ++++++++++++++---- src/charon/sa/ike_sa.h | 45 ++++- src/charon/sa/task_manager.c | 7 + src/charon/sa/tasks/ike_auth.c | 27 +++ src/libstrongswan/crypto/ac.c | 6 +- src/libstrongswan/crypto/ca.c | 4 +- src/libstrongswan/crypto/crl.c | 4 +- src/libstrongswan/crypto/x509.c | 6 +- src/libstrongswan/library.c | 19 +- src/libstrongswan/printf_hook.c | 23 +++ src/libstrongswan/printf_hook.h | 3 +- 17 files changed, 382 insertions(+), 162 deletions(-) diff --git a/src/charon/config/backends/sqlite_backend.c b/src/charon/config/backends/sqlite_backend.c index 33093a735..806ccafc4 100644 --- a/src/charon/config/backends/sqlite_backend.c +++ b/src/charon/config/backends/sqlite_backend.c @@ -188,13 +188,13 @@ static peer_cfg_t *process_peer_cfg_row(private_sqlite_backend_t *this, sqlite3_column_int(stmt, 5), /* auth_method */ sqlite3_column_int(stmt, 6), /* eap_type */ sqlite3_column_int(stmt, 7), /* keyingtries */ - sqlite3_column_int(stmt, 8), /* lifetime */ - sqlite3_column_int(stmt, 9), /* rekeytime */ - sqlite3_column_int(stmt, 10), /* jitter */ - sqlite3_column_int(stmt, 13), /* reauth */ + sqlite3_column_int(stmt, 8), /* rekey_time */ + sqlite3_column_int(stmt, 9), /* reauth_time */ + sqlite3_column_int(stmt, 10), /* jitter_time */ + sqlite3_column_int(stmt, 11), /* over_time */ sqlite3_column_int(stmt, 14), /* mobike */ - sqlite3_column_int(stmt, 11), /* dpd_delay */ - sqlite3_column_int(stmt, 12), /* dpd_action */ + sqlite3_column_int(stmt, 12), /* dpd_delay */ + sqlite3_column_int(stmt, 13), /* dpd_action */ local_vip, remote_vip, FALSE, NULL, NULL); add_children(this, peer_cfg, sqlite3_column_int(stmt, 0)); return peer_cfg; @@ -225,8 +225,9 @@ static peer_cfg_t *get_peer_cfg(private_sqlite_backend_t *this, if (sqlite3_prepare_v2(this->db, "SELECT peer_configs.oid, name, local_id, remote_id, cert_policy, " - "auth_method, eap_type, keyingtries, lifetime, rekeytime, jitter, " - "dpd_delay, dpd_action, reauth, mobike, local_vip, remote_vip, " + "auth_method, eap_type, keyingtries, " + "rekey_time, reauth_time, jitter_time, over_time, " + "dpd_delay, dpd_action, mobike, local_vip, remote_vip, " "local, remote, certreq " "FROM peer_configs, ike_configs " "ON peer_configs.ike_cfg = ike_configs.oid " diff --git a/src/charon/config/peer_cfg.c b/src/charon/config/peer_cfg.c index d61ed9512..fa842c514 100644 --- a/src/charon/config/peer_cfg.c +++ b/src/charon/config/peer_cfg.c @@ -131,31 +131,30 @@ struct private_peer_cfg_t { */ u_int32_t keyingtries; - /** - * user reauthentication instead of rekeying - */ - bool use_reauth; - /** * enable support for MOBIKE */ bool use_mobike; /** - * Time before an SA gets invalid + * Time before starting rekeying */ - u_int32_t lifetime; + u_int32_t rekey_time; /** - * Time before an SA gets rekeyed + * Time before starting reauthentication */ - u_int32_t rekeytime; + u_int32_t reauth_time; /** - * Time, which specifies the range of a random value - * substracted from lifetime. + * Time, which specifies the range of a random value substracted from above. */ - u_int32_t jitter; + u_int32_t jitter_time; + + /** + * Delay before deleting a rekeying/reauthenticating SA + */ + u_int32_t over_time; /** * What to do with an SA when other peer seams to be dead? @@ -353,29 +352,45 @@ static u_int32_t get_keyingtries(private_peer_cfg_t *this) } /** - * Implementation of peer_cfg_t.get_soft_lifetime + * Implementation of peer_cfg_t.get_rekey_time. */ -static u_int32_t get_lifetime(private_peer_cfg_t *this, bool rekey) +static u_int32_t get_rekey_time(private_peer_cfg_t *this) { - if (rekey) + if (this->rekey_time == 0) { - if (this->jitter == 0) - { - return this->rekeytime; - } - return this->rekeytime - (random() % this->jitter); + return 0; } - return this->lifetime; + if (this->jitter_time == 0) + { + return this->rekey_time; + } + return this->rekey_time - (random() % this->jitter_time); } - + /** - * Implementation of peer_cfg_t.use_reauth. + * Implementation of peer_cfg_t.get_reauth_time. */ -static bool use_reauth(private_peer_cfg_t *this) +static u_int32_t get_reauth_time(private_peer_cfg_t *this) { - return this->use_reauth; + if (this->reauth_time == 0) + { + return 0; + } + if (this->jitter_time == 0) + { + return this->reauth_time; + } + return this->reauth_time - (random() % this->jitter_time); } - + +/** + * Implementation of peer_cfg_t.get_over_time. + */ +static u_int32_t get_over_time(private_peer_cfg_t *this) +{ + return this->over_time; +} + /** * Implementation of peer_cfg_t.use_mobike. */ @@ -503,9 +518,9 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, identification_t *my_ca, identification_t *other_ca, linked_list_t *groups, cert_policy_t cert_policy, auth_method_t auth_method, eap_type_t eap_type, - u_int32_t keyingtries, u_int32_t lifetime, - u_int32_t rekeytime, u_int32_t jitter, - bool reauth, bool mobike, + u_int32_t keyingtries, u_int32_t rekey_time, + u_int32_t reauth_time, u_int32_t jitter_time, + u_int32_t over_time, bool mobike, u_int32_t dpd_delay, dpd_action_t dpd_action, host_t *my_virtual_ip, host_t *other_virtual_ip, bool p2p_mediation, peer_cfg_t *p2p_mediated_by, @@ -529,8 +544,9 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->public.get_auth_method = (auth_method_t (*) (peer_cfg_t *))get_auth_method; this->public.get_eap_type = (eap_type_t (*) (peer_cfg_t *))get_eap_type; this->public.get_keyingtries = (u_int32_t (*) (peer_cfg_t *))get_keyingtries; - this->public.get_lifetime = (u_int32_t (*) (peer_cfg_t *, bool rekey))get_lifetime; - this->public.use_reauth = (bool (*) (peer_cfg_t *))use_reauth; + this->public.get_rekey_time = (u_int32_t(*)(peer_cfg_t*))get_rekey_time; + this->public.get_reauth_time = (u_int32_t(*)(peer_cfg_t*))get_reauth_time; + this->public.get_over_time = (u_int32_t(*)(peer_cfg_t*))get_over_time; this->public.use_mobike = (bool (*) (peer_cfg_t *))use_mobike; this->public.get_dpd_delay = (u_int32_t (*) (peer_cfg_t *))get_dpd_delay; this->public.get_dpd_action = (dpd_action_t (*) (peer_cfg_t *))get_dpd_action; @@ -559,10 +575,18 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ike_version, ike_cfg_t *ike_cfg, this->auth_method = auth_method; this->eap_type = eap_type; this->keyingtries = keyingtries; - this->lifetime = lifetime; - this->rekeytime = rekeytime; - this->jitter = jitter; - this->use_reauth = reauth; + this->rekey_time = rekey_time; + this->reauth_time = reauth_time; + if (rekey_time && jitter_time > rekey_time) + { + jitter_time = rekey_time; + } + if (reauth_time && jitter_time > reauth_time) + { + jitter_time = reauth_time; + } + this->jitter_time = jitter_time; + this->over_time = over_time; this->use_mobike = mobike; this->dpd_delay = dpd_delay; this->dpd_action = dpd_action; diff --git a/src/charon/config/peer_cfg.h b/src/charon/config/peer_cfg.h index 3d238e6aa..12c1f5c45 100644 --- a/src/charon/config/peer_cfg.h +++ b/src/charon/config/peer_cfg.h @@ -244,27 +244,28 @@ struct peer_cfg_t { u_int32_t (*get_keyingtries) (peer_cfg_t *this); /** - * @brief Get the lifetime of a IKE_SA. + * @brief Get a time to start rekeying (is randomized with jitter). * - * If "rekey" is set to TRUE, a lifetime is returned before the first - * rekeying should be started. If it is FALSE, the actual lifetime is - * returned when the IKE_SA must be deleted. - * The rekey time automatically contains a jitter to avoid simlutaneous - * rekeying. - * - * @param this child_config - * @param rekey TRUE to get rekey time - * @return lifetime in seconds + * @param this calling object + * @return time in s when to start rekeying, 0 disables rekeying */ - u_int32_t (*get_lifetime) (peer_cfg_t *this, bool rekey); + u_int32_t (*get_rekey_time)(peer_cfg_t *this); /** - * @brief Should a full reauthentication be done instead of rekeying? - * + * @brief Get a time to start reauthentication (is randomized with jitter). + * * @param this calling object - * @return TRUE to use full reauthentication + * @return time in s when to start reauthentication, 0 disables it */ - bool (*use_reauth) (peer_cfg_t *this); + u_int32_t (*get_reauth_time)(peer_cfg_t *this); + + /** + * @brief Get the timeout of a rekeying/reauthenticating SA. + * + * @param thsi calling object + * @return timeout in s + */ + u_int32_t (*get_over_time)(peer_cfg_t *this); /** * @brief Use MOBIKE (RFC4555) if peer supports it? @@ -393,9 +394,10 @@ struct peer_cfg_t { * @param auth_method auth method to use to authenticate us * @param eap_type EAP type to use for peer authentication * @param keyingtries how many keying tries should be done before giving up - * @param lifetime lifetime before deleting an SA - * @param rekeytime lifetime before rekeying an SA - * @param jitter range of random to substract from rekeytime + * @param rekey_time timeout before starting rekeying + * @param reauth_time timeout before starting reauthentication + * @param jitter_time timerange to randomly substract from rekey/reauth time + * @param over_time maximum overtime before closing a rekeying/reauth SA * @param reauth sould be done reauthentication instead of rekeying? * @param mobike use MOBIKE (RFC4555) if peer supports it * @param dpd_delay after how many seconds of inactivity to check DPD @@ -414,9 +416,9 @@ peer_cfg_t *peer_cfg_create(char *name, u_int ikev_version, ike_cfg_t *ike_cfg, identification_t *my_ca, identification_t *other_ca, linked_list_t *groups, cert_policy_t cert_policy, auth_method_t auth_method, eap_type_t eap_type, - u_int32_t keyingtries, u_int32_t lifetime, - u_int32_t rekeytime, u_int32_t jitter, - bool reauth, bool mobike, + u_int32_t keyingtries, u_int32_t rekey_time, + u_int32_t reauth_time, u_int32_t jitter_time, + u_int32_t over_time, bool mobike, u_int32_t dpd_delay, dpd_action_t dpd_action, host_t *my_virtual_ip, host_t *other_virtual_ip, bool p2p_mediation, peer_cfg_t *p2p_mediated_by, diff --git a/src/charon/control/interfaces/stroke_interface.c b/src/charon/control/interfaces/stroke_interface.c index 134044b96..26c55be2d 100755 --- a/src/charon/control/interfaces/stroke_interface.c +++ b/src/charon/control/interfaces/stroke_interface.c @@ -611,15 +611,25 @@ static void stroke_add_conn(stroke_msg_t *msg, FILE *out) ike_cfg->add_proposal(ike_cfg, proposal); } + u_int32_t rekey = 0, reauth = 0, over, jitter; + + jitter = msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100; + over = msg->add_conn.rekey.margin; + if (msg->add_conn.rekey.reauth) + { + reauth = msg->add_conn.rekey.ike_lifetime - over; + } + else + { + rekey = msg->add_conn.rekey.ike_lifetime - over; + } peer_cfg = peer_cfg_create(msg->add_conn.name, msg->add_conn.ikev2 ? 2 : 1, ike_cfg, my_id, other_id, my_ca, other_ca, other_groups, msg->add_conn.me.sendcert, msg->add_conn.auth_method, msg->add_conn.eap_type, - msg->add_conn.rekey.tries, msg->add_conn.rekey.ike_lifetime, - msg->add_conn.rekey.ike_lifetime - msg->add_conn.rekey.margin, - msg->add_conn.rekey.margin * msg->add_conn.rekey.fuzz / 100, - msg->add_conn.rekey.reauth, msg->add_conn.mobike, + msg->add_conn.rekey.tries, rekey, reauth, jitter, over, + msg->add_conn.mobike, msg->add_conn.dpd.delay, msg->add_conn.dpd.action, my_vip, other_vip, msg->add_conn.p2p.mediation, mediated_by_cfg, peer_id); } @@ -1102,9 +1112,8 @@ static void stroke_del_ca(stroke_msg_t *msg, FILE *out) */ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) { - peer_cfg_t *cfg = ike_sa->get_peer_cfg(ike_sa); ike_sa_id_t *id = ike_sa->get_id(ike_sa); - u_int32_t next, now = time(NULL); + u_int32_t rekey, reauth; fprintf(out, "%12s[%d]: %N, %H[%D]...%H[%D]\n", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), @@ -1114,21 +1123,26 @@ static void log_ike_sa(FILE *out, ike_sa_t *ike_sa, bool all) if (all) { - fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s, ", + fprintf(out, "%12s[%d]: IKE SPIs: %.16llx_i%s %.16llx_r%s", ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa), id->get_initiator_spi(id), id->is_initiator(id) ? "*" : "", id->get_responder_spi(id), id->is_initiator(id) ? "" : "*"); - ike_sa->get_stats(ike_sa, &next); - if (next) + rekey = ike_sa->get_statistic(ike_sa, STAT_REKEY_TIME); + reauth = ike_sa->get_statistic(ike_sa, STAT_REAUTH_TIME); + if (rekey) { - fprintf(out, "%s in %V\n", cfg->use_reauth(cfg) ? - "reauthentication" : "rekeying", &now, &next); + fprintf(out, ", rekeying in %V", &rekey); } - else + if (reauth) { - fprintf(out, "rekeying disabled\n"); + fprintf(out, ", reauthentication in %V", &reauth); } + if (!rekey && !reauth) + { + fprintf(out, ", rekeying disabled"); + } + fprintf(out, "\n"); } } @@ -1186,7 +1200,7 @@ static void log_child_sa(FILE *out, child_sa_t *child_sa, bool all) if (rekey) { - fprintf(out, "in %V", &now, &rekey); + fprintf(out, "in %#V", &now, &rekey); } else { diff --git a/src/charon/encoding/payloads/notify_payload.c b/src/charon/encoding/payloads/notify_payload.c index 74a6c3197..d32257af6 100644 --- a/src/charon/encoding/payloads/notify_payload.c +++ b/src/charon/encoding/payloads/notify_payload.c @@ -57,13 +57,9 @@ ENUM_NEXT(notify_type_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED, AUTH "INVALID_SELECTORS", "UNACCEPTABLE_ADDRESSES", "UNEXPECTED_NAT_DETECTED"); -#ifdef P2P ENUM_NEXT(notify_type_names, P2P_CONNECT_FAILED, P2P_CONNECT_FAILED, UNEXPECTED_NAT_DETECTED, "P2P_CONNECT_FAILED"); ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, P2P_CONNECT_FAILED, -#else -ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED, -#endif /* P2P */ "INITIAL_CONTACT", "SET_WINDOW_SIZE", "ADDITIONAL_TS_POSSIBLE", @@ -86,7 +82,6 @@ ENUM_NEXT(notify_type_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETE "AUTH_LIFETIME"); ENUM_NEXT(notify_type_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME, "EAP_ONLY_AUTHENTICATION"); -#ifdef P2P ENUM_NEXT(notify_type_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION, "USE_BEET_MODE"); ENUM_NEXT(notify_type_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE, @@ -97,9 +92,6 @@ ENUM_NEXT(notify_type_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE, "P2P_SESSIONKEY", "P2P_RESPONSE"); ENUM_END(notify_type_names, P2P_RESPONSE); -#else -ENUM_END(notify_type_names, EAP_ONLY_AUTHENTICATION); -#endif /* P2P */ ENUM_BEGIN(notify_type_short_names, UNSUPPORTED_CRITICAL_PAYLOAD, UNSUPPORTED_CRITICAL_PAYLOAD, @@ -128,13 +120,9 @@ ENUM_NEXT(notify_type_short_names, SINGLE_PAIR_REQUIRED, UNEXPECTED_NAT_DETECTED "INVAL_SEL", "UNACCEPT_ADDR", "UNEXPECT_NAT"); -#ifdef P2P ENUM_NEXT(notify_type_short_names, P2P_CONNECT_FAILED, P2P_CONNECT_FAILED, UNEXPECTED_NAT_DETECTED, "P2P_CONN_FAIL"); ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, P2P_CONNECT_FAILED, -#else -ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NAT_DETECTED, -#endif /* P2P */ "INIT_CONTACT", "SET_WINSIZE", "ADD_TS_POSS", @@ -157,7 +145,6 @@ ENUM_NEXT(notify_type_short_names, INITIAL_CONTACT, AUTH_LIFETIME, UNEXPECTED_NA "AUTH_LFT"); ENUM_NEXT(notify_type_short_names, EAP_ONLY_AUTHENTICATION, EAP_ONLY_AUTHENTICATION, AUTH_LIFETIME, "EAP_ONLY"); -#ifdef P2P ENUM_NEXT(notify_type_short_names, USE_BEET_MODE, USE_BEET_MODE, EAP_ONLY_AUTHENTICATION, "BEET_MODE"); ENUM_NEXT(notify_type_short_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE, @@ -168,9 +155,6 @@ ENUM_NEXT(notify_type_short_names, P2P_MEDIATION, P2P_RESPONSE, USE_BEET_MODE, "P2P_SKEY", "P2P_R"); ENUM_END(notify_type_short_names, P2P_RESPONSE); -#else -ENUM_END(notify_type_short_names, EAP_ONLY_AUTHENTICATION); -#endif /* P2P */ typedef struct private_notify_payload_t private_notify_payload_t; @@ -342,7 +326,15 @@ static status_t verify(private_notify_payload_t *this) } break; } - // FIXME: check size of P2P-NAT-T payloads + case AUTH_LIFETIME: + { + if (this->notification_data.len != 4) + { + bad_length = TRUE; + } + break; + } + /* FIXME: check size of P2P-NAT-T payloads */ default: /* TODO: verify */ break; diff --git a/src/charon/encoding/payloads/notify_payload.h b/src/charon/encoding/payloads/notify_payload.h index 4a9ad992b..03f61d473 100644 --- a/src/charon/encoding/payloads/notify_payload.h +++ b/src/charon/encoding/payloads/notify_payload.h @@ -68,10 +68,9 @@ enum notify_type_t { INVALID_SELECTORS = 39, UNACCEPTABLE_ADDRESSES = 40, UNEXPECTED_NAT_DETECTED = 41, -#ifdef P2P /* P2P-NAT-T, private use */ P2P_CONNECT_FAILED = 8192, -#endif /* P2P */ + /* notify status messages */ INITIAL_CONTACT = 16384, SET_WINDOW_SIZE = 16385, @@ -99,7 +98,6 @@ enum notify_type_t { EAP_ONLY_AUTHENTICATION = 40960, /* BEET mode, not even a draft yet. private use */ USE_BEET_MODE = 40961, -#ifdef P2P /* P2P-NAT-T, private use */ P2P_MEDIATION = 40962, P2P_ENDPOINT = 40963, @@ -107,7 +105,6 @@ enum notify_type_t { P2P_SESSIONID = 40965, P2P_SESSIONKEY = 40966, P2P_RESPONSE = 40967 -#endif /* P2P */ }; /** diff --git a/src/charon/sa/ike_sa.c b/src/charon/sa/ike_sa.c index 4cd049880..798b0e7dd 100644 --- a/src/charon/sa/ike_sa.c +++ b/src/charon/sa/ike_sa.c @@ -248,6 +248,8 @@ struct private_ike_sa_t { u_int32_t established; /** when IKE_SA gets rekeyed */ u_int32_t rekey; + /** when IKE_SA gets reauthenticated */ + u_int32_t reauth; /** when IKE_SA gets deleted */ u_int32_t delete; } time; @@ -307,16 +309,31 @@ static char *get_name(private_ike_sa_t *this) return "(unnamed)"; } - /** - * Implementation of ike_sa_t.get_stats. + * Implementation of ike_sa_t.get_statistic. */ -static void get_stats(private_ike_sa_t *this, u_int32_t *next_rekeying) +static u_int32_t get_statistic(private_ike_sa_t *this, statistic_t kind) { - if (next_rekeying) + time_t now = time(NULL); + + switch (kind) { - *next_rekeying = this->time.rekey; + case STAT_REKEY_TIME: + if (this->time.rekey > now) + { + return this->time.rekey - now; + } + break; + case STAT_REAUTH_TIME: + if (this->time.reauth > now) + { + return this->time.reauth - now; + } + break; + default: + break; } + return 0; } /** @@ -493,10 +510,6 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition, this->conditions |= condition; switch (condition) { - case COND_STALE: - DBG1(DBG_IKE, "no route to %H, setting IKE_SA to stale", - this->other_host); - break; case COND_NAT_HERE: DBG1(DBG_IKE, "local host is behind NAT, sending keep alives"); this->conditions |= COND_NAT_ANY; @@ -519,9 +532,6 @@ static void set_condition(private_ike_sa_t *this, ike_condition_t condition, this->conditions &= ~condition; switch (condition) { - case COND_STALE: - DBG1(DBG_IKE, "new route to %H found", this->other_host); - break; case COND_NAT_HERE: case COND_NAT_FAKE: case COND_NAT_THERE: @@ -610,36 +620,58 @@ static void set_state(private_ike_sa_t *this, ike_sa_state_t state) if (this->state == IKE_CONNECTING) { job_t *job; - u_int32_t now = time(NULL); - u_int32_t soft, hard; - bool reauth; + u_int32_t t; - this->time.established = now; - /* start DPD checks */ - send_dpd(this); + /* calculate rekey, reauth and lifetime */ + this->time.established = time(NULL); - /* schedule rekeying/reauthentication */ - soft = this->peer_cfg->get_lifetime(this->peer_cfg, TRUE); - hard = this->peer_cfg->get_lifetime(this->peer_cfg, FALSE); - reauth = this->peer_cfg->use_reauth(this->peer_cfg); - DBG1(DBG_IKE, "scheduling %s in %ds, maximum lifetime %ds", - reauth ? "reauthentication": "rekeying", soft, hard); - - if (soft) + /* schedule rekeying if we have a time which is smaller than + * an already scheduled rekeying */ + t = this->peer_cfg->get_rekey_time(this->peer_cfg); + if (t && (this->time.rekey == 0 || + (this->time.rekey > t + this->time.established))) { - this->time.rekey = now + soft; - job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, reauth); - charon->scheduler->schedule_job(charon->scheduler, job, - soft * 1000); + this->time.rekey = t + this->time.established; + job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, FALSE); + charon->scheduler->schedule_job(charon->scheduler, + job, t * 1000); + DBG1(DBG_IKE, "scheduling rekeying in %ds", t); } - - if (hard) + t = this->peer_cfg->get_reauth_time(this->peer_cfg); + if (t && (this->time.reauth == 0 || + (this->time.reauth > t + this->time.established))) { - this->time.delete = now + hard; + this->time.reauth = t + this->time.established; + job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE); + charon->scheduler->schedule_job(charon->scheduler, + job, t * 1000); + DBG1(DBG_IKE, "scheduling reauthentication in %ds", t); + } + t = this->peer_cfg->get_over_time(this->peer_cfg); + if (this->time.rekey || this->time.reauth) + { + if (this->time.reauth == 0) + { + this->time.delete = this->time.rekey; + } + else if (this->time.rekey == 0) + { + this->time.delete = this->time.reauth; + } + else + { + this->time.delete = min(this->time.rekey, this->time.reauth); + } + this->time.delete += t; + t = this->time.delete - this->time.established; job = (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE); charon->scheduler->schedule_job(charon->scheduler, job, - hard * 1000); + t * 1000); + DBG1(DBG_IKE, "maximum IKE_SA lifetime %ds", t); } + + /* start DPD checks */ + send_dpd(this); } break; } @@ -1902,13 +1934,58 @@ static status_t rekey(private_ike_sa_t *this) static status_t reestablish(private_ike_sa_t *this) { task_t *task; - + + /* we can't reauthenticate as responder when we use EAP or virtual IPs. + * If the peer does not support RFC4478, there is no way to keep the + * IKE_SA up. */ + if (!this->ike_sa_id->is_initiator(this->ike_sa_id)) + { + DBG1(DBG_IKE, "initiator did not reauthenticate as requested"); + if (this->other_virtual_ip != NULL || + has_condition(this, COND_EAP_AUTHENTICATED)) + { + time_t now = time(NULL); + + DBG1(DBG_IKE, "IKE_SA will timeout in %#V", &now, &this->time.delete); + return FAILED; + } + else + { + DBG1(DBG_IKE, "reauthenticating actively"); + } + } task = (task_t*)ike_reauth_create(&this->public); this->task_manager->queue_task(this->task_manager, task); - + return this->task_manager->initiate(this->task_manager); } +/** + * Implementation of ike_sa_t.set_auth_lifetime. + */ +static void set_auth_lifetime(private_ike_sa_t *this, u_int32_t lifetime) +{ + job_t *job; + u_int32_t reduction = this->peer_cfg->get_over_time(this->peer_cfg); + + this->time.reauth = time(NULL) + lifetime - reduction; + job = (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE); + + if (lifetime < reduction) + { + DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, starting reauthentication", + lifetime); + charon->processor->queue_job(charon->processor, job); + } + else + { + DBG1(DBG_IKE, "received AUTH_LIFETIME of %ds, scheduling reauthentication" + " in %ds", lifetime, lifetime - reduction); + charon->scheduler->schedule_job(charon->scheduler, job, + (lifetime - reduction) * 1000); + } +} + /** * Implementation of ike_sa_t.roam. */ @@ -1935,7 +2012,6 @@ static status_t roam(private_ike_sa_t *this, bool address) me = charon->kernel_interface->get_source_addr(charon->kernel_interface, other); - set_condition(this, COND_STALE, FALSE); if (me) { if (me->ip_equals(me, this->my_host) && @@ -2009,6 +2085,24 @@ static status_t inherit(private_ike_sa_t *this, private_ike_sa_t *other) /* move pending tasks to the new IKE_SA */ this->task_manager->adopt_tasks(this->task_manager, other->task_manager); + /* reauthentication timeout survives a rekeying */ + if (other->time.reauth) + { + time_t reauth, delete, now = time(NULL); + + this->time.reauth = other->time.reauth; + reauth = this->time.reauth - now; + delete = reauth + this->peer_cfg->get_over_time(this->peer_cfg); + this->time.delete = this->time.reauth + delete; + DBG1(DBG_IKE, "rescheduling reauthentication in %ds after rekeying, " + "lifetime reduced to %ds", reauth, delete); + charon->scheduler->schedule_job(charon->scheduler, + (job_t*)rekey_ike_sa_job_create(this->ike_sa_id, TRUE), + reauth * 1000); + charon->scheduler->schedule_job(charon->scheduler, + (job_t*)delete_ike_sa_job_create(this->ike_sa_id, TRUE), + delete * 1000); + } /* we have to initate here, there may be new tasks to handle */ return this->task_manager->initiate(this->task_manager); } @@ -2209,8 +2303,8 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) /* Public functions */ this->public.get_state = (ike_sa_state_t (*)(ike_sa_t*)) get_state; this->public.set_state = (void (*)(ike_sa_t*,ike_sa_state_t)) set_state; - this->public.get_stats = (void (*)(ike_sa_t*,u_int32_t*))get_stats; this->public.get_name = (char* (*)(ike_sa_t*))get_name; + this->public.get_statistic = (u_int32_t(*)(ike_sa_t*, statistic_t kind))get_statistic; this->public.process_message = (status_t (*)(ike_sa_t*, message_t*)) process_message; this->public.initiate = (status_t (*)(ike_sa_t*,child_cfg_t*)) initiate; this->public.route = (status_t (*)(ike_sa_t*,child_cfg_t*)) route; @@ -2258,6 +2352,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->public.destroy_child_sa = (status_t (*)(ike_sa_t*,protocol_id_t,u_int32_t))destroy_child_sa; this->public.rekey = (status_t (*)(ike_sa_t*))rekey; this->public.reestablish = (status_t (*)(ike_sa_t*))reestablish; + this->public.set_auth_lifetime = (void(*)(ike_sa_t*, u_int32_t lifetime))set_auth_lifetime; this->public.roam = (status_t(*)(ike_sa_t*,bool))roam; this->public.inherit = (status_t (*)(ike_sa_t*,ike_sa_t*))inherit; this->public.generate_message = (status_t (*)(ike_sa_t*,message_t*,packet_t**))generate_message; @@ -2298,6 +2393,7 @@ ike_sa_t * ike_sa_create(ike_sa_id_t *ike_sa_id) this->time.inbound = this->time.outbound = time(NULL); this->time.established = 0; this->time.rekey = 0; + this->time.reauth = 0; this->time.delete = 0; this->ike_cfg = NULL; this->peer_cfg = NULL; diff --git a/src/charon/sa/ike_sa.h b/src/charon/sa/ike_sa.h index 99f09e98a..975447d9c 100644 --- a/src/charon/sa/ike_sa.h +++ b/src/charon/sa/ike_sa.h @@ -29,6 +29,7 @@ typedef enum ike_extension_t ike_extension_t; typedef enum ike_condition_t ike_condition_t; typedef enum ike_sa_state_t ike_sa_state_t; +typedef enum statistic_t statistic_t; typedef struct ike_sa_t ike_sa_t; #include @@ -115,9 +116,25 @@ enum ike_condition_t { COND_NAT_FAKE = (1<<3), /** - * peer is currently not reachable (due missing route, ...) + * peer has ben authenticated using EAP */ - COND_STALE = (1<<4), + COND_EAP_AUTHENTICATED = (1<<4), +}; + +/** + * Information and statistics to query from an SA + */ +enum statistic_t { + + /** + * Relative time for scheduled rekeying + */ + STAT_REKEY_TIME, + + /** + * Relative time for scheduled reauthentication + */ + STAT_REAUTH_TIME, }; /** @@ -233,13 +250,6 @@ struct ike_sa_t { */ ike_sa_state_t (*get_state) (ike_sa_t *this); - /** - * @brief Get some statistics about this IKE_SA. - * - * @param next_rekeying when the next rekeying is scheduled - */ - void (*get_stats)(ike_sa_t *this, u_int32_t *next_rekeying); - /** * @brief Set the state of the IKE_SA. * @@ -256,6 +266,15 @@ struct ike_sa_t { */ char* (*get_name) (ike_sa_t *this); + /** + * @brief Get statistic values from the IKE_SA. + * + * @param this calling object + * @param kind kind of requested value + * @return value as integer + */ + u_int32_t (*get_statistic)(ike_sa_t *this, statistic_t kind); + /** * @brief Get the own host address. * @@ -845,6 +864,14 @@ struct ike_sa_t { */ status_t (*reestablish) (ike_sa_t *this); + /** + * @brief Set the lifetime limit received from a AUTH_LIFETIME notify. + * + * @param this calling object + * @param lifetime lifetime in seconds + */ + void (*set_auth_lifetime)(ike_sa_t *this, u_int32_t lifetime); + /** * @brief Set the virtual IP to use for this IKE_SA and its children. * diff --git a/src/charon/sa/task_manager.c b/src/charon/sa/task_manager.c index f4484774e..ef0001483 100644 --- a/src/charon/sa/task_manager.c +++ b/src/charon/sa/task_manager.c @@ -777,6 +777,13 @@ static status_t process_request(private_task_manager_t *this, break; default: break; + case AUTH_LIFETIME: + { /* hackish: a separate task would be overkill here */ + chunk_t data = notify->get_notification_data(notify); + u_int32_t lifetime = ntohl(*(u_int32_t*)data.ptr); + this->ike_sa->set_auth_lifetime(this->ike_sa, lifetime); + break; + } } break; } diff --git a/src/charon/sa/tasks/ike_auth.c b/src/charon/sa/tasks/ike_auth.c index a3cd6a2bc..0a9aef217 100644 --- a/src/charon/sa/tasks/ike_auth.c +++ b/src/charon/sa/tasks/ike_auth.c @@ -297,6 +297,23 @@ static status_t collect_other_init_data(private_ike_auth_t *this, message_t *mes return NEED_MORE; } +/** + * add the AUTH_LIFETIME notify to the message + */ +static void add_auth_lifetime(private_ike_auth_t *this, message_t *message) +{ + chunk_t chunk; + u_int32_t lifetime; + + lifetime = this->ike_sa->get_statistic(this->ike_sa, STAT_REAUTH_TIME); + if (lifetime) + { + chunk = chunk_from_thing(lifetime); + *(u_int32_t*)chunk.ptr = htonl(lifetime); + message->add_notify(message, FALSE, AUTH_LIFETIME, chunk); + } +} + /** * Implementation of task_t.build to create AUTH payload from EAP data */ @@ -326,6 +343,7 @@ static status_t build_auth_eap(private_ike_auth_t *this, message_t *message) this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); + add_auth_lifetime(this, message); return SUCCESS; } return NEED_MORE; @@ -520,6 +538,7 @@ static status_t process_r(private_ike_auth_t *this, message_t *message) break; case NOT_FOUND: /* use EAP if no AUTH payload found */ + this->ike_sa->set_condition(this->ike_sa, COND_EAP_AUTHENTICATED, TRUE); this->eap_auth = eap_authenticator_create(this->ike_sa); break; default: @@ -581,6 +600,7 @@ static status_t build_r(private_ike_auth_t *this, message_t *message) this->ike_sa->get_my_host(this->ike_sa), this->ike_sa->get_other_host(this->ike_sa), this->ike_sa->get_other_id(this->ike_sa)); + add_auth_lifetime(this, message); return SUCCESS; } @@ -645,6 +665,13 @@ static status_t process_i(private_ike_auth_t *this, message_t *message) case ADDITIONAL_IP6_ADDRESS: /* handled in ike_mobike task */ break; + case AUTH_LIFETIME: + { + chunk_t data = notify->get_notification_data(notify); + u_int32_t lifetime = ntohl(*(u_int32_t*)data.ptr); + this->ike_sa->set_auth_lifetime(this->ike_sa, lifetime); + break; + } default: { if (type < 16383) diff --git a/src/libstrongswan/crypto/ac.c b/src/libstrongswan/crypto/ac.c index 9aca701f5..30282124c 100644 --- a/src/libstrongswan/crypto/ac.c +++ b/src/libstrongswan/crypto/ac.c @@ -544,7 +544,7 @@ static void list(const private_x509ac_t *this, FILE *out, bool utc) fprintf(out, " validity: not before %#T, ", &this->notBefore, utc); if (now < this->notBefore) { - fprintf(out, "not valid yet (valid in %V)\n", &now, &this->notBefore); + fprintf(out, "not valid yet (valid in %#V)\n", &now, &this->notBefore); } else { @@ -554,14 +554,14 @@ static void list(const private_x509ac_t *this, FILE *out, bool utc) fprintf(out, " not after %#T, ", &this->notAfter, utc); if (now > this->notAfter) { - fprintf(out, "expired (%V ago)\n", &now, &this->notAfter); + fprintf(out, "expired (%#V ago)\n", &now, &this->notAfter); } else { fprintf(out, "ok"); if (now > this->notAfter - ACERT_WARNING_INTERVAL * 60 * 60 * 24) { - fprintf(out, " (expires in %V)", &now, &this->notAfter); + fprintf(out, " (expires in %#V)", &now, &this->notAfter); } fprintf(out, " \n"); } diff --git a/src/libstrongswan/crypto/ca.c b/src/libstrongswan/crypto/ca.c index a78590954..1577c155d 100644 --- a/src/libstrongswan/crypto/ca.c +++ b/src/libstrongswan/crypto/ca.c @@ -279,11 +279,11 @@ static void list_certinfos(private_ca_info_t *this, FILE *out, bool utc) fprintf(out, "%#T, until %#T, ", &thisUpdate, utc, &nextUpdate, utc); if (now > nextUpdate) { - fprintf(out, "expired (%V ago)\n", &now, &nextUpdate); + fprintf(out, "expired (%#V ago)\n", &now, &nextUpdate); } else { - fprintf(out, "ok (expires in %V)\n", &now, &nextUpdate); + fprintf(out, "ok (expires in %#V)\n", &now, &nextUpdate); } fprintf(out, " serial: %#B, %N\n", &serial, cert_status_names, certinfo->get_status(certinfo)); diff --git a/src/libstrongswan/crypto/crl.c b/src/libstrongswan/crypto/crl.c index 14f9df6c9..024d96239 100755 --- a/src/libstrongswan/crypto/crl.c +++ b/src/libstrongswan/crypto/crl.c @@ -463,11 +463,11 @@ static void list(private_crl_t *this, FILE* out, bool utc) } else if (now > this->nextUpdate) { - fprintf(out, "expired (%V ago)\n", &now, &this->nextUpdate); + fprintf(out, "expired (%#V ago)\n", &now, &this->nextUpdate); } else if (now > this->nextUpdate - CRL_WARNING_INTERVAL * 60 * 60 * 24) { - fprintf(out, "ok (expires in %V)\n", &now, &this->nextUpdate); + fprintf(out, "ok (expires in %#V)\n", &now, &this->nextUpdate); } else { diff --git a/src/libstrongswan/crypto/x509.c b/src/libstrongswan/crypto/x509.c index 4317810e2..375a79b31 100755 --- a/src/libstrongswan/crypto/x509.c +++ b/src/libstrongswan/crypto/x509.c @@ -1182,7 +1182,7 @@ static void list(private_x509_t *this, FILE *out, bool utc) fprintf(out, " validity: not before %#T, ", &this->notBefore, utc); if (now < this->notBefore) { - fprintf(out, "not valid yet (valid in %V)\n", &now, &this->notBefore); + fprintf(out, "not valid yet (valid in %#V)\n", &now, &this->notBefore); } else { @@ -1192,14 +1192,14 @@ static void list(private_x509_t *this, FILE *out, bool utc) fprintf(out, " not after %#T, ", &this->notAfter, utc); if (now > this->notAfter) { - fprintf(out, "expired (%V ago)\n", &now, &this->notAfter); + fprintf(out, "expired (%#V ago)\n", &now, &this->notAfter); } else { fprintf(out, "ok"); if (now > this->notAfter - CERT_WARNING_INTERVAL * 60 * 60 * 24) { - fprintf(out, " (expires in %V)", &now, &this->notAfter); + fprintf(out, " (expires in %#V)", &now, &this->notAfter); } fprintf(out, " \n"); } diff --git a/src/libstrongswan/library.c b/src/libstrongswan/library.c index 9f96d119c..f66818bc2 100644 --- a/src/libstrongswan/library.c +++ b/src/libstrongswan/library.c @@ -150,11 +150,20 @@ static int print_time(FILE *stream, const struct printf_info *info, static int print_time_delta(FILE *stream, const struct printf_info *info, const void *const *args) { - time_t *start = *((time_t**)(args[0])); - time_t *end = *((time_t**)(args[1])); - u_int delta = abs(*end - *start); - char* unit = "second"; + time_t *arg1, *arg2; + time_t delta; + + arg1 = *((time_t**)(args[0])); + if (info->alt) + { + arg2 = *((time_t**)(args[1])); + delta = abs(*arg1 - *arg2); + } + else + { + delta = *arg1; + } if (delta > 2 * 60 * 60 * 24) { @@ -180,5 +189,5 @@ static int print_time_delta(FILE *stream, const struct printf_info *info, static void __attribute__ ((constructor))print_register() { register_printf_function(PRINTF_TIME, print_time, arginfo_ptr_alt_ptr_int); - register_printf_function(PRINTF_TIME_DELTA, print_time_delta, arginfo_ptr_ptr); + register_printf_function(PRINTF_TIME_DELTA, print_time_delta, arginfo_ptr_alt_ptr_ptr); } diff --git a/src/libstrongswan/printf_hook.c b/src/libstrongswan/printf_hook.c index 0407e8c82..baf339640 100644 --- a/src/libstrongswan/printf_hook.c +++ b/src/libstrongswan/printf_hook.c @@ -116,3 +116,26 @@ int arginfo_ptr_alt_ptr_int(const struct printf_info *info, size_t n, int *argty } return 1; } + +/** + * special arginfo handler respecting alt flag + */ +int arginfo_ptr_alt_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes) +{ + if (info->alt) + { + if (n > 1) + { + argtypes[0] = PA_POINTER; + argtypes[1] = PA_POINTER; + } + return 2; + } + + if (n > 0) + { + argtypes[0] = PA_POINTER; + } + return 1; +} + diff --git a/src/libstrongswan/printf_hook.h b/src/libstrongswan/printf_hook.h index 03bcf447d..77b228da0 100644 --- a/src/libstrongswan/printf_hook.h +++ b/src/libstrongswan/printf_hook.h @@ -44,7 +44,7 @@ #define PRINTF_TRAFFIC_SELECTOR 'R' /** 1 argument: time_t *time; with #-modifier 2 arguments: time_t *time, bool utc */ #define PRINTF_TIME 'T' -/** 2 arguments: time_t *begin, time_t *end */ +/** 1 argument: time_t *delta; with #-modifier 2 arguments: time_t *begin, time_t *end */ #define PRINTF_TIME_DELTA 'V' /** @@ -55,6 +55,7 @@ int arginfo_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes); int arginfo_ptr_int(const struct printf_info *info, size_t n, int *argtypes); int arginfo_int_int(const struct printf_info *info, size_t n, int *argtypes); int arginfo_ptr_alt_ptr_int(const struct printf_info *info, size_t n, int *argtypes); +int arginfo_ptr_alt_ptr_ptr(const struct printf_info *info, size_t n, int *argtypes); int arginfo_int_alt_int_int(const struct printf_info *info, size_t n, int *argtypes); #endif /* PRINTF_HOOK_H_ */