From krb5-bugs-incoming-bounces@PCH.mit.edu Tue Apr 10 17:56:40 2012
Return-Path: <krb5-bugs-incoming-bounces@PCH.mit.edu>
Received: from pch.mit.edu (PCH.MIT.EDU [18.7.21.90])
by krbdev.mit.edu (Postfix) with ESMTP id 767EC3DF5D;
Tue, 10 Apr 2012 17:56:40 -0400 (EDT)
Received: from pch.mit.edu (pch.mit.edu [127.0.0.1])
by pch.mit.edu (8.13.6/8.12.8) with ESMTP id q3ALue42003781;
Tue, 10 Apr 2012 17:56:40 -0400
Received: from mailhub-dmz-1.mit.edu (MAILHUB-DMZ-1.MIT.EDU [18.9.21.41])
by pch.mit.edu (8.13.6/8.12.8) with ESMTP id q3AJXDs7015231
for <krb5-bugs-incoming@PCH.mit.edu>; Tue, 10 Apr 2012 15:33:13 -0400
Received: from dmz-mailsec-scanner-8.mit.edu (DMZ-MAILSEC-SCANNER-8.MIT.EDU
[18.7.68.37])
by mailhub-dmz-1.mit.edu (8.13.8/8.9.2) with ESMTP id q3AJWnet005286
for <krb5-bugs@mit.edu>; Tue, 10 Apr 2012 15:33:13 -0400
X-AuditID: 12074425-b7f4a6d0000008e0-43-4f848af73c4e
Authentication-Results: symauth.service.identifier; spf=pass; senderid=pass
Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28])
by dmz-mailsec-scanner-8.mit.edu (Symantec Messaging Gateway) with SMTP
id 40.51.02272.8FA848F4; Tue, 10 Apr 2012 15:33:13 -0400 (EDT)
Received: from int-mx10.intmail.prod.int.phx2.redhat.com
(int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q3AJXBqV020837
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK)
for <krb5-bugs@mit.edu>; Tue, 10 Apr 2012 15:33:11 -0400
Received: from stef-desktop.thewalter.lan (ovpn-116-53.ams2.redhat.com
[10.36.116.53])
by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP
id q3AJX83d017838
for <krb5-bugs@mit.edu>; Tue, 10 Apr 2012 15:33:09 -0400
Message-ID: <4F848AF4.1040902@redhat.com>
Date: Tue, 10 Apr 2012 21:33:08 +0200
From: Stef Walter <stefw@redhat.com>
User-Agent: Mozilla/5.0 (X11; Linux x86_64;
rv:11.0) Gecko/20120329 Thunderbird/11.0.1
MIME-Version: 1.0
To: krb5-bugs@mit.edu
Subject: KRB5_TRACE is broken in trunk
Content-Type: multipart/mixed; boundary="------------090900040107070508090107"
X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrNKsWRWlGSWpSXmKPExsVysWW7jO7PrhZ/g44NHBYND4+zOzB6NJ05
yhzAGMVlk5Kak1mWWqRvl8CV8a3zO3vBpKyKfROOszUwHvXtYuTkkBAwkdjYvIkNxGYU8JZ4
c/U4O0RcTOLCvfVAcS4OIYETjBKrJr1jhHA2MUns7+hkhXDeMkpM6e8Dcjg4eAU0JRp67UFM
FgFViZ7rXiCD2ARUJOa9m8MMEhYVCJP4fcwBJMwrIChxcuYTFhBbREBU4uXfY2C2sICaxNeG
52A3MAsESEyc1MsMcY+2RMOsySwTGPlnIWmfhaQMwtaReNf3AMqWl9j+dg6UnSJx6/InRlRx
LiC7gVFi3fZtbAsY2VcxyqbkVunmJmbmFKcm6xYnJ+blpRbpWujlZpbopaaUbmIEhrYQu4vq
DsYJh5QOMQpwMCrx8C7yb/EXYk0sK67MPcQoycGkJMo7vR0oxJeUn1KZkVicEV9UmpNafIhR
BWjZow2rLzBKseTl56UqifCeygOq401JrKxKLcqHKZPmYFES59XUeucnJJCeWJKanZpakFoE
k2XiYD/EKMPBoSTBaw6MciHBotT01Iq0zJwSZDWcIILrEKMEBw/QGg6QQt7igsTc4sx0iKJT
jIpS4rwSIAkBkERGaR7cAFCaqv////8lRlkpYV5GBgYGIR6gC4CBgJAHpblXjOLAABDmlQOZ
wpOZVwI3/RXQYiagxQb3m0EWlyQipKQaGCf8eBLLU57SuPEC9ztVuwzzlM3/Dgm+6zmbkCyy
L1tfYZ6AqWb6UsX2DZEn58et+bh9aRCHw4Hn96ItM4S4NIPvrPgnZH6xd4qngFPXY46VaZ8f
83p5vGZ7zPlD75nynA953O8fMC53y1h1MFjc/EPq5O2rvV4KMsjONvHcvfc289Z9W5bUT1Vi
Kc5INNRiLipOBACHO+w1TgMAAA==
X-Mailman-Approved-At: Tue, 10 Apr 2012 17:56:39 -0400
X-BeenThere: krb5-bugs-incoming@mailman.mit.edu
X-Mailman-Version: 2.1.6
Precedence: list
Sender: krb5-bugs-incoming-bounces@PCH.mit.edu
Errors-To: krb5-bugs-incoming-bounces@PCH.mit.edu
This is a multi-part message in MIME format.
--------------090900040107070508090107
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Apr 4 18:13:49 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
Architecture: x86_64
Much work has gone into making krb5 work with a clock skew between the
client and the KDC when requesting tickets. I believe this work was
based on:
http://static.usenix.org/publications/compsystems/1996/win_davis.pdf
Sadly the oft-used encrypted timestamp authentication fails on clock
skew. The encrypted timestamp authentication uses the current clock time
as a sort of nonce to prevent reply attacks on the preauthentication. As
(what was originally) a nice feature, it also helped report clock skew
errors.
However now that clock skew is no longer an issue for requesting tickets
from the KDC, we can use the server time in the preauth encrypted
timestamp as the nonce.
The server time received in the preauth error is not integrity protected
or authenticated. However this is a minor issue. Theoretical attacks
that might be seemingly enabled by this change are already possible.
This changes the semantics of the encrypted timestamp preauth to a
challenge response, with an nonce. Where the server sends some data, and
the client sends it back after processing it with its key.
In addition, almost all NTP deployments for syncing client time with
server time use NTP in an insecure manner. In so many cases client
software does a hard 'ntpdate' time reset immediately before requesting
kerberos tickets. This behavior is dangerous and should be discouraged.
The way to do that is complete work to make krb5 time offset agnostic.
This patch fixes many of these use cases.
Lastly syncing the client clock does not work with multiple realm use of
kerberos, unless of course, all the realms KDC's have their clocks
synced to a common time source. This is not always true in the wild, as
Davis, Geer and Ts'o point out in their paper.
Discussed on the mailing list at:
http://mailman.mit.edu/pipermail/krbdev/2012-April/010724.html
Patch is attached.
--------------090900040107070508090107
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"
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
--------------090900040107070508090107--
Return-Path: <krb5-bugs-incoming-bounces@PCH.mit.edu>
Received: from pch.mit.edu (PCH.MIT.EDU [18.7.21.90])
by krbdev.mit.edu (Postfix) with ESMTP id 767EC3DF5D;
Tue, 10 Apr 2012 17:56:40 -0400 (EDT)
Received: from pch.mit.edu (pch.mit.edu [127.0.0.1])
by pch.mit.edu (8.13.6/8.12.8) with ESMTP id q3ALue42003781;
Tue, 10 Apr 2012 17:56:40 -0400
Received: from mailhub-dmz-1.mit.edu (MAILHUB-DMZ-1.MIT.EDU [18.9.21.41])
by pch.mit.edu (8.13.6/8.12.8) with ESMTP id q3AJXDs7015231
for <krb5-bugs-incoming@PCH.mit.edu>; Tue, 10 Apr 2012 15:33:13 -0400
Received: from dmz-mailsec-scanner-8.mit.edu (DMZ-MAILSEC-SCANNER-8.MIT.EDU
[18.7.68.37])
by mailhub-dmz-1.mit.edu (8.13.8/8.9.2) with ESMTP id q3AJWnet005286
for <krb5-bugs@mit.edu>; Tue, 10 Apr 2012 15:33:13 -0400
X-AuditID: 12074425-b7f4a6d0000008e0-43-4f848af73c4e
Authentication-Results: symauth.service.identifier; spf=pass; senderid=pass
Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28])
by dmz-mailsec-scanner-8.mit.edu (Symantec Messaging Gateway) with SMTP
id 40.51.02272.8FA848F4; Tue, 10 Apr 2012 15:33:13 -0400 (EDT)
Received: from int-mx10.intmail.prod.int.phx2.redhat.com
(int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.23])
by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id q3AJXBqV020837
(version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK)
for <krb5-bugs@mit.edu>; Tue, 10 Apr 2012 15:33:11 -0400
Received: from stef-desktop.thewalter.lan (ovpn-116-53.ams2.redhat.com
[10.36.116.53])
by int-mx10.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP
id q3AJX83d017838
for <krb5-bugs@mit.edu>; Tue, 10 Apr 2012 15:33:09 -0400
Message-ID: <4F848AF4.1040902@redhat.com>
Date: Tue, 10 Apr 2012 21:33:08 +0200
From: Stef Walter <stefw@redhat.com>
User-Agent: Mozilla/5.0 (X11; Linux x86_64;
rv:11.0) Gecko/20120329 Thunderbird/11.0.1
MIME-Version: 1.0
To: krb5-bugs@mit.edu
Subject: KRB5_TRACE is broken in trunk
Content-Type: multipart/mixed; boundary="------------090900040107070508090107"
X-Scanned-By: MIMEDefang 2.68 on 10.5.11.23
X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrNKsWRWlGSWpSXmKPExsVysWW7jO7PrhZ/g44NHBYND4+zOzB6NJ05
yhzAGMVlk5Kak1mWWqRvl8CV8a3zO3vBpKyKfROOszUwHvXtYuTkkBAwkdjYvIkNxGYU8JZ4
c/U4O0RcTOLCvfVAcS4OIYETjBKrJr1jhHA2MUns7+hkhXDeMkpM6e8Dcjg4eAU0JRp67UFM
FgFViZ7rXiCD2ARUJOa9m8MMEhYVCJP4fcwBJMwrIChxcuYTFhBbREBU4uXfY2C2sICaxNeG
52A3MAsESEyc1MsMcY+2RMOsySwTGPlnIWmfhaQMwtaReNf3AMqWl9j+dg6UnSJx6/InRlRx
LiC7gVFi3fZtbAsY2VcxyqbkVunmJmbmFKcm6xYnJ+blpRbpWujlZpbopaaUbmIEhrYQu4vq
DsYJh5QOMQpwMCrx8C7yb/EXYk0sK67MPcQoycGkJMo7vR0oxJeUn1KZkVicEV9UmpNafIhR
BWjZow2rLzBKseTl56UqifCeygOq401JrKxKLcqHKZPmYFES59XUeucnJJCeWJKanZpakFoE
k2XiYD/EKMPBoSTBaw6MciHBotT01Iq0zJwSZDWcIILrEKMEBw/QGg6QQt7igsTc4sx0iKJT
jIpS4rwSIAkBkERGaR7cAFCaqv////8lRlkpYV5GBgYGIR6gC4CBgJAHpblXjOLAABDmlQOZ
wpOZVwI3/RXQYiagxQb3m0EWlyQipKQaGCf8eBLLU57SuPEC9ztVuwzzlM3/Dgm+6zmbkCyy
L1tfYZ6AqWb6UsX2DZEn58et+bh9aRCHw4Hn96ItM4S4NIPvrPgnZH6xd4qngFPXY46VaZ8f
83p5vGZ7zPlD75nynA953O8fMC53y1h1MFjc/EPq5O2rvV4KMsjONvHcvfc289Z9W5bUT1Vi
Kc5INNRiLipOBACHO+w1TgMAAA==
X-Mailman-Approved-At: Tue, 10 Apr 2012 17:56:39 -0400
X-BeenThere: krb5-bugs-incoming@mailman.mit.edu
X-Mailman-Version: 2.1.6
Precedence: list
Sender: krb5-bugs-incoming-bounces@PCH.mit.edu
Errors-To: krb5-bugs-incoming-bounces@PCH.mit.edu
This is a multi-part message in MIME format.
--------------090900040107070508090107
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
Show quoted text
>Submitter-Id: net
>Originator: Stef Walter
>Organization: Red Hat
>Confidential: no
>Synopsis: Support using kdc time during encrypted timestamp preauth
>Severity: non-critical
>Priority: medium
>Category: krb5-libs
>Class: change-request
>Release: 1.10-prerelease
>Environment: Fedora 17
System: Linux stef-desktop.thewalter.lan 3.3.1-3.fc17.x86_64 #1 SMP Wed>Originator: Stef Walter
>Organization: Red Hat
>Confidential: no
>Synopsis: Support using kdc time during encrypted timestamp preauth
>Severity: non-critical
>Priority: medium
>Category: krb5-libs
>Class: change-request
>Release: 1.10-prerelease
>Environment: Fedora 17
Apr 4 18:13:49 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
Architecture: x86_64
Show quoted text
>Description:
Much work has gone into making krb5 work with a clock skew between the
client and the KDC when requesting tickets. I believe this work was
based on:
http://static.usenix.org/publications/compsystems/1996/win_davis.pdf
Sadly the oft-used encrypted timestamp authentication fails on clock
skew. The encrypted timestamp authentication uses the current clock time
as a sort of nonce to prevent reply attacks on the preauthentication. As
(what was originally) a nice feature, it also helped report clock skew
errors.
However now that clock skew is no longer an issue for requesting tickets
from the KDC, we can use the server time in the preauth encrypted
timestamp as the nonce.
The server time received in the preauth error is not integrity protected
or authenticated. However this is a minor issue. Theoretical attacks
that might be seemingly enabled by this change are already possible.
This changes the semantics of the encrypted timestamp preauth to a
challenge response, with an nonce. Where the server sends some data, and
the client sends it back after processing it with its key.
In addition, almost all NTP deployments for syncing client time with
server time use NTP in an insecure manner. In so many cases client
software does a hard 'ntpdate' time reset immediately before requesting
kerberos tickets. This behavior is dangerous and should be discouraged.
The way to do that is complete work to make krb5 time offset agnostic.
This patch fixes many of these use cases.
Lastly syncing the client clock does not work with multiple realm use of
kerberos, unless of course, all the realms KDC's have their clocks
synced to a common time source. This is not always true in the wild, as
Davis, Geer and Ts'o point out in their paper.
Discussed on the mailing list at:
http://mailman.mit.edu/pipermail/krbdev/2012-April/010724.html
Show quoted text
>Fix:
Patch is attached.
--------------090900040107070508090107
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"
Show quoted text
>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
--------------090900040107070508090107--