(for example, when converting ``rcmd.hostname`` to
``host/hostname.domain``).
+**disable_encrypted_timestamp**
+ If this flag is true, the client will not perform encrypted
+ timestamp preauthentication if requested by the KDC. Setting this
+ flag can help to prevent dictionary attacks by active attackers,
+ if the realm's KDCs support SPAKE preauthentication or if initial
+ authentication always uses another mechanism or always uses FAST.
+ This flag persists across client referrals during initial
+ authentication. This flag does not prevent the KDC from offering
+ encrypted timestamp. New in release 1.17.
+
**http_anchors**
When KDCs and kpasswd servers are accessed through HTTPS proxies, this tag
can be used to specify the location of the CA certificate which should be
Clients which do not implement SPAKE preauthentication will fall back
to encrypted timestamp.
+An active attacker can force a fallback to encrypted timestamp by
+modifying the initial KDC response, defeating the protection against
+dictionary attacks. To prevent this fallback on clients which do
+implement SPAKE preauthentication, set the
+**disable_encrypted_timestamp** variable to ``true`` in the
+:ref:`realms` subsection for realms whose KDCs offer SPAKE
+preauthentication.
+
By default, SPAKE preauthentication requires an extra network round
trip to the KDC during initial authentication. If most of the clients
in a realm support SPAKE, this extra round trip can be eliminated
#define KRB5_CONF_DES_CRC_SESSION_SUPPORTED "des_crc_session_supported"
#define KRB5_CONF_DICT_FILE "dict_file"
#define KRB5_CONF_DISABLE "disable"
+#define KRB5_CONF_DISABLE_ENCRYPTED_TIMESTAMP "disable_encrypted_timestamp"
#define KRB5_CONF_DISABLE_LAST_SUCCESS "disable_last_success"
#define KRB5_CONF_DISABLE_LOCKOUT "disable_lockout"
#define KRB5_CONF_DNS_CANONICALIZE_HOSTNAME "dns_canonicalize_hostname"
#define TRACE_PREAUTH_ENC_TS(c, sec, usec, plain, enc) \
TRACE(c, "Encrypted timestamp (for {long}.{int}): plain {hexdata}, " \
"encrypted {hexdata}", (long) sec, (int) usec, plain, enc)
+#define TRACE_PREAUTH_ENC_TS_DISABLED(c) \
+ TRACE(c, "Ignoring encrypted timestamp because it is disabled")
#define TRACE_PREAUTH_ETYPE_INFO(c, etype, salt, s2kparams) \
TRACE(c, "Selected etype info: etype {etype}, salt \"{data}\", " \
"params \"{data}\"", etype, salt, s2kparams)
free(tmp);
}
+/* Return true if encrypted timestamp is disabled for realm. */
+static krb5_boolean
+encts_disabled(profile_t profile, const krb5_data *realm)
+{
+ krb5_error_code ret;
+ char *realmstr;
+ int bval;
+
+ realmstr = k5memdup0(realm->data, realm->length, &ret);
+ if (realmstr == NULL)
+ return FALSE;
+ ret = profile_get_boolean(profile, KRB5_CONF_REALMS, realmstr,
+ KRB5_CONF_DISABLE_ENCRYPTED_TIMESTAMP, FALSE,
+ &bval);
+ free(realmstr);
+ return (ret == 0) ? bval : FALSE;
+}
+
/**
* Throw away any pre-authentication realm state and begin with a
* unauthenticated or optimistically authenticated request. If fast_upgrade is
goto cleanup;
}
+ /* Never set encts_disabled back to false, so it can't be circumvented with
+ * client realm referrals. */
+ if (encts_disabled(context->profile, &ctx->request->client->realm))
+ ctx->encts_disabled = TRUE;
+
krb5_free_principal(context, ctx->request->server);
ctx->request->server = NULL;
krb5_boolean info_pa_permitted;
krb5_boolean restarted;
krb5_boolean fallback_disabled;
+ krb5_boolean encts_disabled;
struct krb5_responder_context_st rctx;
krb5_preauthtype selected_preauth_type;
krb5_preauthtype allowed_preauth_type;
#include <k5-int.h>
#include <krb5/clpreauth_plugin.h>
#include "int-proto.h"
+#include "init_creds_ctx.h"
static krb5_error_code
encts_prep_questions(krb5_context context, krb5_clpreauth_moddata moddata,
krb5_data *encoded_previous_request,
krb5_pa_data *pa_data)
{
- cb->need_as_key(context, rock);
+ krb5_init_creds_context ctx = (krb5_init_creds_context)rock;
+
+ if (!ctx->encts_disabled)
+ cb->need_as_key(context, rock);
return 0;
}
krb5_prompter_fct prompter, void *prompter_data,
krb5_pa_data ***out_padata)
{
+ krb5_init_creds_context ctx = (krb5_init_creds_context)rock;
krb5_error_code ret;
krb5_pa_enc_ts pa_enc;
krb5_data *ts = NULL, *enc_ts = NULL;
enc_data.ciphertext = empty_data();
+ if (ctx->encts_disabled) {
+ TRACE_PREAUTH_ENC_TS_DISABLED(context);
+ k5_setmsg(context, KRB5_PREAUTH_FAILED,
+ _("Encrypted timestamp is disabled"));
+ return KRB5_PREAUTH_FAILED;
+ }
+
ret = cb->get_as_key(context, rock, &as_key);
if (ret)
goto cleanup;
r1.kinit('abc@XYZ', 'pw', ['-E'])
r1.klist('abc\@XYZ@KRBTEST2.COM', 'krbtgt/KRBTEST2.COM')
+# Test that disable_encrypted_timestamp persists across client
+# referrals. (This test relies on SPAKE not being enabled by default
+# on the KDC.)
+r2.run([kadminl, 'modprinc', '+preauth', 'user'])
+msgs = ('Encrypted timestamp (for ')
+r1.kinit('user', password('user'), ['-C'], expected_trace=msgs)
+dconf = {'realms': {'$realm': {'disable_encrypted_timestamp': 'true'}}}
+denv = r1.special_env('disable_encts', False, krb5_conf=dconf)
+msgs = ('Ignoring encrypted timestamp because it is disabled',
+ '/Encrypted timestamp is disabled')
+r1.kinit('user', None, ['-C'], env=denv, expected_code=1, expected_trace=msgs,
+ expected_msg='Encrypted timestamp is disabled')
+
success('KDC host referral tests')