From krb5-bugs-incoming-bounces@PCH.mit.edu Tue Apr 10 17:56:40 2012 Return-Path: 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 ; 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 ; 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 ; 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 ; 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 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 >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 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--