implemented RFC4478 (repeated authentication)
authorMartin Willi <martin@strongswan.org>
Tue, 20 Nov 2007 12:06:40 +0000 (12:06 -0000)
committerMartin Willi <martin@strongswan.org>
Tue, 20 Nov 2007 12:06:40 +0000 (12:06 -0000)
changed %V printf handler to take a time delta, %#V now takes two arguments

17 files changed:
src/charon/config/backends/sqlite_backend.c
src/charon/config/peer_cfg.c
src/charon/config/peer_cfg.h
src/charon/control/interfaces/stroke_interface.c
src/charon/encoding/payloads/notify_payload.c
src/charon/encoding/payloads/notify_payload.h
src/charon/sa/ike_sa.c
src/charon/sa/ike_sa.h
src/charon/sa/task_manager.c
src/charon/sa/tasks/ike_auth.c
src/libstrongswan/crypto/ac.c
src/libstrongswan/crypto/ca.c
src/libstrongswan/crypto/crl.c
src/libstrongswan/crypto/x509.c
src/libstrongswan/library.c
src/libstrongswan/printf_hook.c
src/libstrongswan/printf_hook.h

index 33093a7..806ccaf 100644 (file)
@@ -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 "
index d61ed95..fa842c5 100644 (file)
@@ -132,30 +132,29 @@ struct private_peer_cfg_t {
        u_int32_t keyingtries;
        
        /**
-        * user reauthentication instead of rekeying
+        * enable support for MOBIKE
         */
-       bool use_reauth;
+       bool use_mobike;
        
        /**
-        * enable support for MOBIKE
+        * Time before starting rekeying
         */
-       bool use_mobike;
+       u_int32_t rekey_time;
        
        /**
-        * Time before an SA gets invalid
+        * Time before starting reauthentication
         */
-       u_int32_t lifetime;
+       u_int32_t reauth_time;
        
        /**
-        * Time before an SA gets rekeyed
+        * Time, which specifies the range of a random value substracted from above.
         */
-       u_int32_t rekeytime;
+       u_int32_t jitter_time;
        
        /**
-        * Time, which specifies the range of a random value
-        * substracted from lifetime.
+        * Delay before deleting a rekeying/reauthenticating SA
         */
-       u_int32_t jitter;
+       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;
index 3d238e6..12c1f5c 100644 (file)
@@ -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
+        */
+       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
         */
-       bool (*use_reauth) (peer_cfg_t *this);
+       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,
index 134044b..26c55be 100755 (executable)
@@ -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, ", reauthentication in %V", &reauth);
+               }
+               if (!rekey && !reauth)
                {
-                       fprintf(out, "rekeying disabled\n");
+                       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
                        {
index 74a6c31..d32257a 100644 (file)
@@ -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;
index 4a9ad99..03f61d4 100644 (file)
@@ -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 */
 };
 
 /**
index 4cd0498..798b0e7 100644 (file)
@@ -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.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)
                                {
-                                       this->time.delete = now + hard;
+                                       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,14 +1934,59 @@ 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.
  */
 static status_t roam(private_ike_sa_t *this, bool address)
@@ -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;
index 99f09e9..975447d 100644 (file)
@@ -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 <library.h>
@@ -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,
 };
 
 /**
@@ -234,13 +251,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.
         *
         * @param this                  calling object
@@ -257,6 +267,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.
         * 
         * @param this                  calling object
@@ -846,6 +865,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.
         *
         * The virtual IP is assigned per IKE_SA, not per CHILD_SA. It has the same
index f448477..ef00014 100644 (file)
@@ -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;
                                        }
index a3cd6a2..0a9aef2 100644 (file)
@@ -298,6 +298,23 @@ static status_t collect_other_init_data(private_ike_auth_t *this, message_t *mes
 }
 
 /**
+ * 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
  */
 static status_t build_auth_eap(private_ike_auth_t *this, message_t *message)
@@ -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)
index 9aca701..3028212 100644 (file)
@@ -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");
        }
index a785909..1577c15 100644 (file)
@@ -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));
index 14f9df6..024d962 100755 (executable)
@@ -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
        {
index 4317810..375a79b 100755 (executable)
@@ -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");
        }
index 9f96d11..f66818b 100644 (file)
@@ -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);
 }
index 0407e8c..baf3396 100644 (file)
@@ -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;
+}
+
index 03bcf44..77b228d 100644 (file)
@@ -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_ */