summaryrefslogtreecommitdiffstats
path: root/src/lib
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2012-04-17 04:07:34 +0000
committerGreg Hudson <ghudson@mit.edu>2012-04-17 04:07:34 +0000
commit5f39a4438eafd693a3eb8366bbc3901efe62e538 (patch)
treefc738c1ef2b58474b2622c5e1937a22bd1eaeffa /src/lib
parent8d689cea3561d5912db218a4fdf9bdf3c1c6d3b0 (diff)
downloadkrb5-5f39a4438eafd693a3eb8366bbc3901efe62e538.tar.gz
krb5-5f39a4438eafd693a3eb8366bbc3901efe62e538.tar.xz
krb5-5f39a4438eafd693a3eb8366bbc3901efe62e538.zip
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 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25808 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/krb5/krb/get_in_tkt.c19
-rw-r--r--src/lib/krb5/krb/preauth2.c23
-rw-r--r--src/lib/krb5/krb/preauth_ec.c5
-rw-r--r--src/lib/krb5/krb/preauth_encts.c11
-rw-r--r--src/lib/krb5/os/ustime.c54
5 files changed, 86 insertions, 26 deletions
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index fc8df83df..aaabc4e21 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -1281,6 +1281,23 @@ check_reply_enctype(krb5_init_creds_context ctx)
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 @@ init_creds_step_reply(krb5_context context,
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;
diff --git a/src/lib/krb5/krb/preauth2.c b/src/lib/krb5/krb/preauth2.c
index 0c8ead5fe..06a135a36 100644
--- a/src/lib/krb5/krb/preauth2.c
+++ b/src/lib/krb5/krb/preauth2.c
@@ -412,12 +412,31 @@ set_as_key(krb5_context context, krb5_clpreauth_rock rock,
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
diff --git a/src/lib/krb5/krb/preauth_ec.c b/src/lib/krb5/krb/preauth_ec.c
index 7e7565b6f..48a4a17bf 100644
--- a/src/lib/krb5/krb/preauth_ec.c
+++ b/src/lib/krb5/krb/preauth_ec.c
@@ -92,7 +92,10 @@ ec_process(krb5_context context, krb5_clpreauth_moddata moddata,
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)
diff --git a/src/lib/krb5/krb/preauth_encts.c b/src/lib/krb5/krb/preauth_encts.c
index 63e4259eb..559c6700f 100644
--- a/src/lib/krb5/krb/preauth_encts.c
+++ b/src/lib/krb5/krb/preauth_encts.c
@@ -58,8 +58,15 @@ encts_process(krb5_context context, krb5_clpreauth_moddata moddata,
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;
diff --git a/src/lib/krb5/os/ustime.c b/src/lib/krb5/os/ustime.c
index be94a8218..90fa4a6e2 100644
--- a/src/lib/krb5/os/ustime.c
+++ b/src/lib/krb5/os/ustime.c
@@ -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++;
+ }
+ if (usec < 0) {
+ usec += 1000000;
+ sec--;
}
- *seconds = sec;
- *microseconds = usec;
+ 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);
+ }
+}