[17545] in Kerberos_V5_Development
RE: clock skew and preauth
daemon@ATHENA.MIT.EDU (Stef Walter)
Thu Apr 5 12:32:21 2012
Message-ID: <4F7DC8EC.9090807@gnome.org>
Date: Thu, 05 Apr 2012 18:31:40 +0200
From: Stef Walter <stefw@gnome.org>
MIME-Version: 1.0
To: checker@d6.com, tlyu@mit.edu, Greg Hudson <ghudson@mit.edu>
Content-Type: multipart/mixed; boundary="------------000000010805040604090508"
Cc: Nico Williams <nico@cryptonector.com>, krbdev@mit.edu
Errors-To: krbdev-bounces@mit.edu
This is a multi-part message in MIME format.
--------------000000010805040604090508
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
[Sorry this isn't a follow up to the previous thread on this topic. I
just joined the mailing list yesterday.]
I ran into the same problem as recently discussed on the mailing list,
with preauth encrypted-timestamp failing due to out of sync clocks.
That's despite kdc_timesync = 1.
Greg pointed out this patch:
http://mailman.mit.edu/pipermail/kerberos/2012-March/018014.html
In my opinion, the problem with that patch is we're using an
unauthenticated source (krb5_error->stime) to set the global time offset
for the entire library (and storing it in the cache file). This could
be abused.
Attached is a patch which:
* Stores a timestamp offset in krb5_clpreauth_rock when preauth is
requested, and uses it during preauth encrypted timestamp.
* Exposes a new callback for client preauth plugins. Suggested
by Greg.
* Refactors krb5_us_timeofday() so we don't copy paste around
the offset calculation code.
* Uses an offset because of the prompting delay problem [1]
* Only enables preauth offsets if kdc_timesync != 0.
Does this look like a good approach? I'll file a PR for it if so.
Cheers,
Stef
[1] http://krbdev.mit.edu/rt/Ticket/Display.html?id=7063
--------------000000010805040604090508
Content-Type: text/x-patch;
name="0001-Support-using-kdc-time-during-encrypted-timestamp-pr.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename*0="0001-Support-using-kdc-time-during-encrypted-timestamp-pr.pa";
filename*1="tch"
>From 78c700cbcc5408a2a792bc94fd93eb242fbd5c88 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw@gnome.org>
Date: Thu, 5 Apr 2012 10:02:57 +0200
Subject: [PATCH] Support using kdc time during encrypted timestamp preauth
* This allows us to preauthenticate using encrypted
timestamp without having a system time synced with
the KDC.
* Complements the kdc_timesync functionality, and is
controlled by the same config option.
* Worth noting that this changes the semantics of the
encrypted timestamp to that of a challenge response.
The goals of preauthentication are met, however.
* Adds a new callback to krb5_clpreauth_callbacks
which allows retrieval of the last preauth request
server time.
* Track the server time using an offset, so that
if prompting takes a while we can still guess
it appropriately.
---
src/include/k5-int.h | 13 ++++++++++
src/include/krb5/preauth_plugin.h | 20 ++++++++++++++
src/lib/krb5/krb/get_in_tkt.c | 3 +++
src/lib/krb5/krb/preauth2.c | 46 ++++++++++++++++++++++++++++++--
src/lib/krb5/krb/preauth_encts.c | 13 ++++++++--
src/lib/krb5/os/ustime.c | 52 ++++++++++++++++++++++++-------------
6 files changed, 125 insertions(+), 22 deletions(-)
diff --git a/src/include/k5-int.h b/src/include/k5-int.h
index 7ef421d..0ad0226 100644
--- a/src/include/k5-int.h
+++ b/src/include/k5-int.h
@@ -665,6 +665,11 @@ typedef struct _krb5_os_context {
char * default_ccname;
} *krb5_os_context;
+krb5_error_code krb5int_us_timeofday_with_offset(krb5_timestamp offset_secs,
+ krb5_int32 offset_usecs,
+ krb5_timestamp *seconds,
+ krb5_int32 *microseconds);
+
/*
* Flags for the os_flags field
*
@@ -753,6 +758,10 @@ struct krb5_clpreauth_rock_st {
krb5_principal client;
krb5_prompter_fct prompter;
void *prompter_data;
+
+ /* Discovered offset of server time during preauth */
+ krb5_timestamp pa_offset_secs;
+ krb5_int32 pa_offset_usecs;
};
typedef struct _krb5_pa_enc_ts {
@@ -1036,6 +1045,10 @@ void KRB5_CALLCONV krb5_preauth_prepare_request(krb5_context,
krb5_kdc_req *);
void KRB5_CALLCONV krb5_preauth_request_context_init(krb5_context);
void KRB5_CALLCONV krb5_preauth_request_context_fini(krb5_context);
+void KRB5_CALLCONV krb5_preauth_note_req_timestamp (krb5_context kcontext,
+ krb5_clpreauth_rock rock,
+ krb5_timestamp stime_secs,
+ krb5_int32 stime_usecs);
void KRB5_CALLCONV
krb5_free_sam_challenge_2(krb5_context, krb5_sam_challenge_2 *);
diff --git a/src/include/krb5/preauth_plugin.h b/src/include/krb5/preauth_plugin.h
index f732b94..9fb9b11 100644
--- a/src/include/krb5/preauth_plugin.h
+++ b/src/include/krb5/preauth_plugin.h
@@ -176,6 +176,26 @@ typedef struct krb5_clpreauth_callbacks_st {
const krb5_keyblock *keyblock);
/* End of version 1 clpreauth callbacks. */
+
+ /* Beginning of version 2 clpreauth callbacks. */
+
+ /*
+ * Get the timestamp to use in a preauth response. If
+ * @allow_unauthenticated is set to 1, and the library has been
+ * configured to allow it, then this function will offset the current
+ * time using unauthenticated timestamp information received from the
+ * server.
+ *
+ * Using @allow_unauthenticated = 1 should only be done in contexts
+ * where it would not introduce a security issue.
+ */
+ krb5_error_code (*get_preauth_timeofday)(krb5_context context,
+ krb5_clpreauth_rock rock,
+ int allow_unauthenticated,
+ krb5_timestamp *seconds,
+ krb5_int32 *microseconds);
+
+ /* End of version 2 clpreauth callbacks. */
} *krb5_clpreauth_callbacks;
/*
diff --git a/src/lib/krb5/krb/get_in_tkt.c b/src/lib/krb5/krb/get_in_tkt.c
index fc8df83..b16dd06 100644
--- a/src/lib/krb5/krb/get_in_tkt.c
+++ b/src/lib/krb5/krb/get_in_tkt.c
@@ -1328,6 +1328,9 @@ 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;
+ krb5_preauth_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 0c8ead5..07c2991 100644
--- a/src/lib/krb5/krb/preauth2.c
+++ b/src/lib/krb5/krb/preauth2.c
@@ -412,14 +412,56 @@ 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_timeofday(krb5_context context,
+ krb5_clpreauth_rock rock,
+ int allow_unauthenticated,
+ krb5_timestamp *seconds,
+ krb5_int32 *microseconds)
+{
+ if (allow_unauthenticated &&
+ (context->library_options & KRB5_LIBOPT_SYNC_KDCTIME)) {
+ return krb5int_us_timeofday_with_offset(rock->pa_offset_secs,
+ rock->pa_offset_usecs,
+ seconds, microseconds);
+
+ } else {
+ return krb5_us_timeofday (context, seconds, microseconds);
+ }
+}
+
static struct krb5_clpreauth_callbacks_st callbacks = {
- 1,
+ 2,
get_etype,
fast_armor,
get_as_key,
- set_as_key
+ set_as_key,
+ get_preauth_timeofday,
};
+void KRB5_CALLCONV
+krb5_preauth_note_req_timestamp(krb5_context kcontext,
+ krb5_clpreauth_rock rock,
+ krb5_timestamp stime_secs,
+ krb5_int32 stime_usecs)
+{
+ krb5_timestamp local_secs;
+ krb5_int32 local_usecs;
+ int ret;
+
+ /*
+ * We don't calculate against krb5_us_timeofday() because
+ * that is already offset and can change between calls.
+ */
+ ret = krb5_crypto_us_timeofday(&local_secs, &local_usecs);
+ if (ret != 0)
+ return;
+
+ /* This is stored as an offset, since prompting can take a long time. */
+ rock->pa_offset_secs = stime_secs - local_secs;
+ rock->pa_offset_usecs = stime_usecs - local_usecs;
+}
+
/* Tweak the request body, for now adding any enctypes which the module claims
* to add support for to the list, but in the future perhaps doing more
* involved things. */
diff --git a/src/lib/krb5/krb/preauth_encts.c b/src/lib/krb5/krb/preauth_encts.c
index 63e4259..a6b75f6 100644
--- a/src/lib/krb5/krb/preauth_encts.c
+++ b/src/lib/krb5/krb/preauth_encts.c
@@ -58,8 +58,17 @@ 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. This timestamp
+ * is unauthenticated. By using it here, we change the semantics of the
+ * encrypted timestamp preauth to that of a challenge response.
+ *
+ * If kdc_timesync is not configured, then this will just use local time.
+ */
+ if (cb->vers >= 2)
+ ret = (cb->get_preauth_timeofday) (context, rock, 1, &pa_enc.patimestamp, &pa_enc.pausec);
+ else
+ ret = krb5_us_timeofday(context, &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 be94a82..899b7e6 100644
--- a/src/lib/krb5/os/ustime.c
+++ b/src/lib/krb5/os/ustime.c
@@ -36,33 +36,49 @@
#include "k5-int.h"
krb5_error_code KRB5_CALLCONV
-krb5_us_timeofday(krb5_context context, krb5_timestamp *seconds, krb5_int32 *microseconds)
+krb5int_us_timeofday_with_offset(krb5_timestamp offset_secs,
+ krb5_int32 offset_usecs,
+ krb5_timestamp *seconds,
+ krb5_int32 *microseconds)
{
- 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_usecs;
+ if (usec > 1000000) {
+ usec -= 1000000;
+ sec++;
+ }
+ if (usec < 0) {
+ usec += 1000000;
+ sec--;
}
+ sec += offset_secs;
+
*seconds = sec;
*microseconds = 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 krb5int_us_timeofday_with_offset (os_ctx->time_offset,
+ os_ctx->usec_offset,
+ seconds, microseconds);
+
+ } else {
+ return krb5_crypto_us_timeofday(seconds, microseconds);
+ }
+}
--
1.7.9.3
--------------000000010805040604090508
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
_______________________________________________
krbdev mailing list krbdev@mit.edu
https://mailman.mit.edu/mailman/listinfo/krbdev
--------------000000010805040604090508--