svn rev #25808: trunk/src/ include/ include/krb5/ lib/krb5/krb/ lib/krb5/os/ ...

ghudson@MIT.EDU ghudson at MIT.EDU
Tue Apr 17 00:07:34 EDT 2012


http://src.mit.edu/fisheye/changelog/krb5/?cs=25808
Commit By: ghudson
Log Message:
Allow preauth mechs to work with clock skew

Add a clpreauth callback which gets the time of day using an offset
determined by the preauth-required error, and use it in encrypted
timestamp and encrypted challenge.  This timestamp is not necessarily
authenticated, but the security consequences for those preauth mechs
are minor (and can be mitigated by turning off kdc_timesync on
clients).

Based on a patch from Stef Walter.

ticket: 7114


Changed Files:
U   trunk/src/include/k5-int.h
U   trunk/src/include/krb5/preauth_plugin.h
U   trunk/src/lib/krb5/krb/get_in_tkt.c
U   trunk/src/lib/krb5/krb/preauth2.c
U   trunk/src/lib/krb5/krb/preauth_ec.c
U   trunk/src/lib/krb5/krb/preauth_encts.c
U   trunk/src/lib/krb5/os/ustime.c
U   trunk/src/tests/t_skew.py
Modified: trunk/src/include/k5-int.h
===================================================================
--- trunk/src/include/k5-int.h	2012-04-17 03:19:12 UTC (rev 25807)
+++ trunk/src/include/k5-int.h	2012-04-17 04:07:34 UTC (rev 25808)
@@ -665,6 +665,12 @@
     char *                  default_ccname;
 } *krb5_os_context;
 
+/* Get the current time of day plus a specified offset. */
+krb5_error_code k5_time_with_offset(krb5_timestamp offset,
+                                    krb5_int32 offset_usec,
+                                    krb5_timestamp *time_out,
+                                    krb5_int32 *usec_out);
+
 /*
  * Flags for the os_flags field
  *
@@ -753,6 +759,11 @@
     krb5_principal client;
     krb5_prompter_fct prompter;
     void *prompter_data;
+
+    /* Discovered offset of server time during preauth */
+    krb5_timestamp pa_offset;
+    krb5_int32 pa_offset_usec;
+    enum { NO_OFFSET = 0, UNAUTH_OFFSET, AUTH_OFFSET } pa_offset_state;
 };
 
 typedef struct _krb5_pa_enc_ts {

Modified: trunk/src/include/krb5/preauth_plugin.h
===================================================================
--- trunk/src/include/krb5/preauth_plugin.h	2012-04-17 03:19:12 UTC (rev 25807)
+++ trunk/src/include/krb5/preauth_plugin.h	2012-04-17 04:07:34 UTC (rev 25808)
@@ -176,6 +176,24 @@
                                   const krb5_keyblock *keyblock);
 
     /* End of version 1 clpreauth callbacks. */
+
+    /*
+     * Get the current time for use in a preauth response.  If
+     * allow_unauth_time is true and the library has been configured to allow
+     * it, the current time will be offset using unauthenticated timestamp
+     * information received from the KDC in the preauth-required error, if one
+     * has been received.  Otherwise, the timestamp in a preauth-required error
+     * will only be used if it is protected by a FAST channel.  Only set
+     * allow_unauth_time if using an unauthenticated time offset would not
+     * create a security issue.
+     */
+    krb5_error_code (*get_preauth_time)(krb5_context context,
+                                        krb5_clpreauth_rock rock,
+                                        krb5_boolean allow_unauth_time,
+                                        krb5_timestamp *time_out,
+                                        krb5_int32 *usec_out);
+
+    /* End of version 2 clpreauth callbacks (added in 1.11). */
 } *krb5_clpreauth_callbacks;
 
 /*

Modified: trunk/src/lib/krb5/krb/get_in_tkt.c
===================================================================
--- trunk/src/lib/krb5/krb/get_in_tkt.c	2012-04-17 03:19:12 UTC (rev 25807)
+++ trunk/src/lib/krb5/krb/get_in_tkt.c	2012-04-17 04:07:34 UTC (rev 25808)
@@ -1281,6 +1281,23 @@
     return KRB5_CONFIG_ETYPE_NOSUPP;
 }
 
+/* Note the difference between the KDC's time, as reported to us in a
+ * preauth-required error, and the current time. */
+static void
+note_req_timestamp(krb5_context kcontext, krb5_clpreauth_rock rock,
+                   krb5_timestamp kdc_time, krb5_int32 kdc_usec)
+{
+    krb5_timestamp now;
+    krb5_int32 usec;
+
+    if (k5_time_with_offset(0, 0, &now, &usec) != 0)
+        return;
+    rock->pa_offset = kdc_time - now;
+    rock->pa_offset_usec = kdc_usec - usec;
+    rock->pa_offset_state = (rock->fast_state->armor_key != NULL) ?
+        AUTH_OFFSET : UNAUTH_OFFSET;
+}
+
 static krb5_error_code
 init_creds_step_reply(krb5_context context,
                       krb5_init_creds_context ctx,
@@ -1328,6 +1345,8 @@
             krb5_free_pa_data(context, ctx->preauth_to_use);
             ctx->preauth_to_use = ctx->err_padata;
             ctx->err_padata = NULL;
+            note_req_timestamp(context, &ctx->preauth_rock,
+                               ctx->err_reply->stime, ctx->err_reply->susec);
             /* this will trigger a new call to krb5_do_preauth() */
             krb5_free_error(context, ctx->err_reply);
             ctx->err_reply = NULL;

Modified: trunk/src/lib/krb5/krb/preauth2.c
===================================================================
--- trunk/src/lib/krb5/krb/preauth2.c	2012-04-17 03:19:12 UTC (rev 25807)
+++ trunk/src/lib/krb5/krb/preauth2.c	2012-04-17 04:07:34 UTC (rev 25808)
@@ -412,12 +412,31 @@
     return krb5_copy_keyblock_contents(context, keyblock, rock->as_key);
 }
 
+static krb5_error_code
+get_preauth_time(krb5_context context, krb5_clpreauth_rock rock,
+                 krb5_boolean allow_unauth_time, krb5_timestamp *time_out,
+                 krb5_int32 *usec_out)
+{
+    if (rock->pa_offset_state != NO_OFFSET &&
+        (allow_unauth_time || rock->pa_offset_state == AUTH_OFFSET) &&
+        (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME)) {
+        /* Use the offset we got from the preauth-required error. */
+        return k5_time_with_offset(rock->pa_offset, rock->pa_offset_usec,
+                                   time_out, usec_out);
+
+    } else {
+        /* Use the time offset from the context, or no offset. */
+        return krb5_us_timeofday(context, time_out, usec_out);
+    }
+}
+
 static struct krb5_clpreauth_callbacks_st callbacks = {
-    1,
+    2,
     get_etype,
     fast_armor,
     get_as_key,
-    set_as_key
+    set_as_key,
+    get_preauth_time
 };
 
 /* Tweak the request body, for now adding any enctypes which the module claims

Modified: trunk/src/lib/krb5/krb/preauth_ec.c
===================================================================
--- trunk/src/lib/krb5/krb/preauth_ec.c	2012-04-17 03:19:12 UTC (rev 25807)
+++ trunk/src/lib/krb5/krb/preauth_ec.c	2012-04-17 04:07:34 UTC (rev 25808)
@@ -92,7 +92,10 @@
         krb5_data *encoded_ts = NULL;
         krb5_pa_enc_ts ts;
         enc.ciphertext.data = NULL;
-        retval = krb5_us_timeofday(context, &ts.patimestamp, &ts.pausec);
+        /* Use the timestamp from the preauth-required error if possible.
+         * This time should always be secured by the FAST channel. */
+        retval = cb->get_preauth_time(context, rock, FALSE, &ts.patimestamp,
+                                      &ts.pausec);
         if (retval == 0)
             retval = encode_krb5_pa_enc_ts(&ts, &encoded_ts);
         if (retval == 0)

Modified: trunk/src/lib/krb5/krb/preauth_encts.c
===================================================================
--- trunk/src/lib/krb5/krb/preauth_encts.c	2012-04-17 03:19:12 UTC (rev 25807)
+++ trunk/src/lib/krb5/krb/preauth_encts.c	2012-04-17 04:07:34 UTC (rev 25808)
@@ -58,8 +58,15 @@
         goto cleanup;
     TRACE_PREAUTH_ENC_TS_KEY_GAK(context, as_key);
 
-    /* now get the time of day, and encrypt it accordingly */
-    ret = krb5_us_timeofday(context, &pa_enc.patimestamp, &pa_enc.pausec);
+    /*
+     * Try and use the timestamp of the preauth request, even if it's
+     * unauthenticated.  We could be fooled into making a preauth response for
+     * a future time, but that has no security consequences other than the
+     * KDC's audit logs.  If kdc_timesync is not configured, then this will
+     * just use local time.
+     */
+    ret = cb->get_preauth_time(context, rock, TRUE, &pa_enc.patimestamp,
+                               &pa_enc.pausec);
     if (ret)
         goto cleanup;
 

Modified: trunk/src/lib/krb5/os/ustime.c
===================================================================
--- trunk/src/lib/krb5/os/ustime.c	2012-04-17 03:19:12 UTC (rev 25807)
+++ trunk/src/lib/krb5/os/ustime.c	2012-04-17 04:07:34 UTC (rev 25808)
@@ -35,34 +35,46 @@
 
 #include "k5-int.h"
 
-krb5_error_code KRB5_CALLCONV
-krb5_us_timeofday(krb5_context context, krb5_timestamp *seconds, krb5_int32 *microseconds)
+krb5_error_code
+k5_time_with_offset(krb5_timestamp offset, krb5_int32 offset_usec,
+                    krb5_timestamp *time_out, krb5_int32 *usec_out)
 {
-    krb5_os_context os_ctx = &context->os_context;
     krb5_int32 sec, usec;
     krb5_error_code retval;
 
-    if (os_ctx->os_flags & KRB5_OS_TOFFSET_TIME) {
-        *seconds = os_ctx->time_offset;
-        *microseconds = os_ctx->usec_offset;
-        return 0;
-    }
     retval = krb5_crypto_us_timeofday(&sec, &usec);
     if (retval)
         return retval;
-    if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) {
-        usec += os_ctx->usec_offset;
-        if (usec > 1000000) {
-            usec -= 1000000;
-            sec++;
-        }
-        if (usec < 0) {
-            usec += 1000000;
-            sec--;
-        }
-        sec += os_ctx->time_offset;
+    usec += offset_usec;
+    if (usec > 1000000) {
+        usec -= 1000000;
+        sec++;
     }
-    *seconds = sec;
-    *microseconds = usec;
+    if (usec < 0) {
+        usec += 1000000;
+        sec--;
+    }
+    sec += offset;
+
+    *time_out = sec;
+    *usec_out = usec;
     return 0;
 }
+
+krb5_error_code KRB5_CALLCONV
+krb5_us_timeofday(krb5_context context, krb5_timestamp *seconds,
+                  krb5_int32 *microseconds)
+{
+    krb5_os_context os_ctx = &context->os_context;
+
+    if (os_ctx->os_flags & KRB5_OS_TOFFSET_TIME) {
+        *seconds = os_ctx->time_offset;
+        *microseconds = os_ctx->usec_offset;
+        return 0;
+    } else if (os_ctx->os_flags & KRB5_OS_TOFFSET_VALID) {
+        return k5_time_with_offset(os_ctx->time_offset, os_ctx->usec_offset,
+                                   seconds, microseconds);
+    } else {
+        return krb5_crypto_us_timeofday(seconds, microseconds);
+    }
+}

Modified: trunk/src/tests/t_skew.py
===================================================================
--- trunk/src/tests/t_skew.py	2012-04-17 03:19:12 UTC (rev 25807)
+++ trunk/src/tests/t_skew.py	2012-04-17 04:07:34 UTC (rev 25808)
@@ -13,9 +13,13 @@
 realm.run_as_client([kvno, realm.host_princ])
 realm.run_as_client([kdestroy])
 
-# kinit (with preauth) should fail.
+# kinit (with preauth) should work, with or without FAST.
 realm.run_kadminl('modprinc +requires_preauth user')
-realm.kinit(realm.user_princ, password('user'), expected_code=1)
+realm.kinit(realm.user_princ, password('user'))
+realm.run_as_client([kvno, realm.host_princ])
+realm.kinit(realm.user_princ, password('user'), flags=['-T', realm.ccache])
+realm.run_as_client([kvno, realm.host_princ])
+realm.run_as_client([kdestroy])
 
 realm.stop()
 
@@ -31,8 +35,10 @@
 realm.kinit(realm.user_princ, password('user'), flags=['-T', realm.ccache],
             expected_code=1)
 
-# kinit (with preauth) should fail.
+# kinit (with preauth) should fail, with or without FAST.
 realm.run_kadminl('modprinc +requires_preauth user')
 realm.kinit(realm.user_princ, password('user'), expected_code=1)
+realm.kinit(realm.user_princ, password('user'), flags=['-T', realm.ccache],
+            expected_code=1)
 
 success('Clock skew tests')



More information about the cvs-krb5 mailing list