[krbdev.mit.edu #7114] Support using kdc time during encrypted timestamp preauth

The RT System itself via RT rt-comment at krbdev.mit.edu
Tue Apr 10 17:56:41 EDT 2012


>From krb5-bugs-incoming-bounces at PCH.mit.edu  Tue Apr 10 17:56:40 2012
Return-Path: <krb5-bugs-incoming-bounces at 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 at 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 at 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 at 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 at mit.edu>; Tue, 10 Apr 2012 15:33:09 -0400
Message-ID: <4F848AF4.1040902 at redhat.com>
Date: Tue, 10 Apr 2012 21:33:08 +0200
From: Stef Walter <stefw at 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 at 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 at mailman.mit.edu
X-Mailman-Version: 2.1.6
Precedence: list
Sender: krb5-bugs-incoming-bounces at PCH.mit.edu
Errors-To: krb5-bugs-incoming-bounces at 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

>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
Apr 4 18:13:49 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
Architecture: x86_64

>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

>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"

>From 78c700cbcc5408a2a792bc94fd93eb242fbd5c88 Mon Sep 17 00:00:00 2001
From: Stef Walter <stefw at 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--



More information about the krb5-bugs mailing list