krb5 commit: Add tests for KDC etype-info behavior
Greg Hudson
ghudson at mit.edu
Wed Jul 8 18:24:55 EDT 2015
https://github.com/krb5/krb5/commit/5cf4a7e220141f10f51995ceae9b9e74232a31b7
commit 5cf4a7e220141f10f51995ceae9b9e74232a31b7
Author: Greg Hudson <ghudson at mit.edu>
Date: Fri Jun 5 21:19:15 2015 -0400
Add tests for KDC etype-info behavior
Create a new test harness etinfo.c which can display etype-info2
information in KDC responses. Use it to test the etype-info results
in preauth_required error e-data and AS-REP padata.
ticket: 8199
.gitignore | 1 +
src/tests/Makefile.in | 19 +++--
src/tests/etinfo.c | 166 +++++++++++++++++++++++++++++++++++++++++++++
src/tests/t_etype_info.py | 76 +++++++++++++++++++++
4 files changed, 255 insertions(+), 7 deletions(-)
diff --git a/.gitignore b/.gitignore
index d9ceb21..090dc90 100644
--- a/.gitignore
+++ b/.gitignore
@@ -250,6 +250,7 @@ testlog
/src/slave/kproplog
/src/tests/adata
+/src/tests/etinfo
/src/tests/gcred
/src/tests/hist
/src/tests/hrealm
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 121c1e1..602d74a 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -5,9 +5,9 @@ SUBDIRS = resolve asn.1 create hammer verify gssapi dejagnu shlib \
RUN_SETUP = @KRB5_RUN_ENV@ KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf
-OBJS= adata.o gcred.o hist.o hrealm.o kdbtest.o plugorder.o t_init_creds.o \
- t_localauth.o rdreq.o responder.o s2p.o
-EXTRADEPSRCS= adata.c gcred.c hist.c hrealm.c kdbtest.c plugorder.c \
+OBJS= adata.o etinfo.o gcred.o hist.o hrealm.o kdbtest.o plugorder.o \
+ t_init_creds.o t_localauth.o rdreq.o responder.o s2p.o
+EXTRADEPSRCS= adata.c etinfo.c gcred.c hist.c hrealm.c kdbtest.c plugorder.c \
t_init_creds.c t_localauth.c rdreq.o responder.c s2p.c
TEST_DB = ./testdb
@@ -23,6 +23,9 @@ KTEST_OPTS= $(KADMIN_OPTS) -p $(TEST_PREFIX) -n $(TEST_NUM) -D $(TEST_DEPTH)
adata: adata.o $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o $@ adata.o $(KRB5_BASE_LIBS)
+etinfo: etinfo.o $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o $@ etinfo.o $(KRB5_BASE_LIBS)
+
gcred: gcred.o $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o $@ gcred.o $(KRB5_BASE_LIBS)
@@ -100,8 +103,8 @@ kdb_check: kdc.conf krb5.conf
$(RUN_SETUP) $(VALGRIND) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) destroy -f
$(RM) $(TEST_DB)* stash_file
-check-pytests:: adata gcred hist hrealm kdbtest plugorder rdreq responder
-check-pytests:: s2p t_init_creds t_localauth unlockiter
+check-pytests:: adata etinfo gcred hist hrealm kdbtest plugorder rdreq
+check-pytests:: responder s2p t_init_creds t_localauth unlockiter
$(RUNPYTEST) $(srcdir)/t_general.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_dump.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_iprop.py $(PYTESTFLAGS)
@@ -140,6 +143,7 @@ check-pytests:: s2p t_init_creds t_localauth unlockiter
$(RUNPYTEST) $(srcdir)/jsonwalker.py -d $(srcdir)/au_dict.json \
-i au.log
$(RUNPYTEST) $(srcdir)/t_salt.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_etype_info.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_bogus_kdc_req.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_kdc_log.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_proxy.py $(PYTESTFLAGS)
@@ -148,7 +152,8 @@ check-pytests:: s2p t_init_creds t_localauth unlockiter
$(RUNPYTEST) $(srcdir)/t_authdata.py $(PYTESTFLAGS)
clean::
- $(RM) adata gcred hist hrealm kdbtest plugorder rdreq responder s2p
- $(RM) t_init_creds t_localauth krb5.conf kdc.conf
+ $(RM) gcred hist hrealm kdbtest plugorder rdreq responder s2p
+ $(RM) adata etinfo gcred hist hrealm kdbtest plugorder rdreq responder
+ $(RM) s2p t_init_creds t_localauth krb5.conf kdc.conf
$(RM) -rf kdc_realm/sandbox ldap
$(RM) au.log
diff --git a/src/tests/etinfo.c b/src/tests/etinfo.c
new file mode 100644
index 0000000..dc45638
--- /dev/null
+++ b/src/tests/etinfo.c
@@ -0,0 +1,166 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* tests/etinfo.c - Test harness for KDC etype-info behavior */
+/*
+ * Copyright (C) 2015 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Send an AS-REQ to the KDC for a specified principal, with an optionally
+ * specified request enctype list. Decode the output as either an AS-REP or a
+ * KRB-ERROR and display the PA-ETYPE-INFO2, PA-ETYPE-INFO, and PA-PW-SALT
+ * padata in the following format:
+ *
+ * error/asrep etype-info2/etype-info/pw-salt enctype salt [s2kparams]
+ *
+ * enctype is omitted for PA-PW-SALT entries. salt is displayed directly;
+ * s2kparams is displayed in uppercase hex.
+ */
+
+#include "k5-int.h"
+
+static krb5_context ctx;
+
+static void
+check(krb5_error_code code)
+{
+ const char *errmsg;
+
+ if (code) {
+ errmsg = krb5_get_error_message(ctx, code);
+ fprintf(stderr, "%s\n", errmsg);
+ krb5_free_error_message(ctx, errmsg);
+ exit(1);
+ }
+}
+
+static void
+display_etinfo(krb5_etype_info_entry **list, const char *l1, const char *l2)
+{
+ krb5_etype_info_entry *info;
+ char etname[256];
+ unsigned int i;
+
+ for (; *list != NULL; list++) {
+ info = *list;
+ check(krb5_enctype_to_name(info->etype, TRUE, etname, sizeof(etname)));
+ printf("%s %s %s ", l1, l2, etname);
+ if (info->length != KRB5_ETYPE_NO_SALT)
+ printf("%.*s", info->length, info->salt);
+ else
+ printf("(default)");
+ if (info->s2kparams.length > 0) {
+ printf(" ");
+ for (i = 0; i < info->s2kparams.length; i++)
+ printf("%02X", (unsigned char)info->s2kparams.data[i]);
+ }
+ printf("\n");
+ }
+}
+
+static void
+display_padata(krb5_pa_data **pa_list, const char *label)
+{
+ krb5_pa_data *pa;
+ krb5_data d;
+ krb5_etype_info_entry **etinfo_list;
+
+ for (; pa_list != NULL && *pa_list != NULL; pa_list++) {
+ pa = *pa_list;
+ d = make_data(pa->contents, pa->length);
+ if (pa->pa_type == KRB5_PADATA_ETYPE_INFO2) {
+ check(decode_krb5_etype_info2(&d, &etinfo_list));
+ display_etinfo(etinfo_list, label, "etype_info2");
+ krb5_free_etype_info(ctx, etinfo_list);
+ } else if (pa->pa_type == KRB5_PADATA_ETYPE_INFO) {
+ check(decode_krb5_etype_info(&d, &etinfo_list));
+ display_etinfo(etinfo_list, label, "etype_info");
+ krb5_free_etype_info(ctx, etinfo_list);
+ } else if (pa->pa_type == KRB5_PADATA_PW_SALT) {
+ printf("%s pw_salt %.*s\n", label, (int)d.length, d.data);
+ } else if (pa->pa_type == KRB5_PADATA_AFS3_SALT) {
+ printf("%s afs3_salt %.*s\n", label, (int)d.length, d.data);
+ }
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ krb5_principal client;
+ krb5_init_creds_context icc;
+ krb5_data reply, request, realm;
+ krb5_error *error;
+ krb5_kdc_rep *asrep;
+ krb5_pa_data **padata;
+ krb5_enctype *enctypes, def[] = { ENCTYPE_NULL };
+ unsigned int flags;
+ int master = 0;
+
+ if (argc < 2 && argc > 3) {
+ fprintf(stderr, "Usage: %s princname [enctypes]\n", argv[0]);
+ exit(1);
+ }
+ check(krb5_init_context(&ctx));
+ check(krb5_parse_name(ctx, argv[1], &client));
+ if (argc >= 3) {
+ check(krb5int_parse_enctype_list(ctx, "", argv[2], def, &enctypes));
+ krb5_set_default_in_tkt_ktypes(ctx, enctypes);
+ free(enctypes);
+ }
+
+ check(krb5_init_creds_init(ctx, client, NULL, NULL, 0, NULL, &icc));
+ reply = empty_data();
+ check(krb5_init_creds_step(ctx, icc, &reply, &request, &realm, &flags));
+ assert(flags == KRB5_INIT_CREDS_STEP_FLAG_CONTINUE);
+ check(krb5_sendto_kdc(ctx, &request, &realm, &reply, &master, 0));
+
+ if (decode_krb5_error(&reply, &error) == 0) {
+ decode_krb5_padata_sequence(&error->e_data, &padata);
+ if (error->error != KDC_ERR_PREAUTH_REQUIRED) {
+ fprintf(stderr, "Unexpected error %d\n", (int)error->error);
+ return 1;
+ }
+ display_padata(padata, "error");
+ krb5_free_pa_data(ctx, padata);
+ krb5_free_error(ctx, error);
+ } else if (decode_krb5_as_rep(&reply, &asrep) == 0) {
+ display_padata(asrep->padata, "asrep");
+ krb5_free_kdc_rep(ctx, asrep);
+ } else {
+ abort();
+ }
+
+ krb5_free_data_contents(ctx, &request);
+ krb5_free_data_contents(ctx, &reply);
+ krb5_free_data_contents(ctx, &realm);
+ krb5_init_creds_free(ctx, icc);
+ krb5_free_principal(ctx, client);
+ krb5_free_context(ctx);
+ return 0;
+}
diff --git a/src/tests/t_etype_info.py b/src/tests/t_etype_info.py
new file mode 100644
index 0000000..8ff6ad6
--- /dev/null
+++ b/src/tests/t_etype_info.py
@@ -0,0 +1,76 @@
+#!/usr/bin/python
+from k5test import *
+
+supported_enctypes = 'aes128-cts des3-cbc-sha1 rc4-hmac des-cbc-crc:afs3'
+conf = {'libdefaults': {'allow_weak_crypto': 'true'},
+ 'realms': {'$realm': {'supported_enctypes': supported_enctypes}}}
+realm = K5Realm(create_host=False, get_creds=False, krb5_conf=conf)
+
+realm.run([kadminl, 'addprinc', '-pw', 'pw', '+requires_preauth',
+ 'preauthuser'])
+realm.run([kadminl, 'addprinc', '-pw', 'pw', '-e', 'rc4-hmac',
+ '+requires_preauth', 'rc4user'])
+realm.run([kadminl, 'addprinc', '-nokey', '+requires_preauth', 'nokeyuser'])
+
+
+# Run the test harness for the given principal and request enctype
+# list. Compare the output to the expected lines, ignoring order.
+def test_etinfo(princ, enctypes, expected_lines):
+ lines = realm.run(['./etinfo', princ, enctypes]).splitlines()
+ if sorted(lines) != sorted(expected_lines):
+ fail('Unexpected output for princ %s, etypes %s' % (princ, enctypes))
+
+
+# With no newer enctypes in the request, PA-ETYPE-INFO2,
+# PA-ETYPE-INFO, and PA-PW-SALT appear in the AS-REP, each listing one
+# key for the most preferred matching enctype.
+test_etinfo('user', 'rc4-hmac-exp des3 rc4 des-cbc-crc',
+ ['asrep etype_info2 des3-cbc-sha1 KRBTEST.COMuser',
+ 'asrep etype_info des3-cbc-sha1 KRBTEST.COMuser',
+ 'asrep pw_salt KRBTEST.COMuser'])
+
+# With a newer enctype in the request (even if it is not the most
+# preferred enctype and doesn't match any keys), only PA-ETYPE-INFO2
+# appears.
+test_etinfo('user', 'rc4 aes256-cts',
+ ['asrep etype_info2 rc4-hmac KRBTEST.COMuser'])
+
+# In preauth-required errors, PA-PW-SALT does not appear, but the same
+# etype-info2 values are expected.
+test_etinfo('preauthuser', 'rc4-hmac-exp des3 rc4 des-cbc-crc',
+ ['error etype_info2 des3-cbc-sha1 KRBTEST.COMpreauthuser',
+ 'error etype_info des3-cbc-sha1 KRBTEST.COMpreauthuser'])
+test_etinfo('preauthuser', 'rc4 aes256-cts',
+ ['error etype_info2 rc4-hmac KRBTEST.COMpreauthuser'])
+
+# AFS3 salt for DES enctypes is conveyed using s2kparams in
+# PA-ETYPE-INFO2, not at all in PA-ETYPE-INFO, and with a special padata
+# type instead of PA-PW-SALT.
+test_etinfo('user', 'des-cbc-crc rc4',
+ ['asrep etype_info2 des-cbc-crc KRBTEST.COM 01',
+ 'asrep etype_info des-cbc-crc KRBTEST.COM',
+ 'asrep afs3_salt KRBTEST.COM'])
+test_etinfo('preauthuser', 'des-cbc-crc rc4',
+ ['error etype_info2 des-cbc-crc KRBTEST.COM 01',
+ 'error etype_info des-cbc-crc KRBTEST.COM'])
+
+# DES keys can be used with other DES enctypes. The requested enctype
+# shows up in the etype-info, not the database key enctype.
+test_etinfo('user', 'des-cbc-md4 rc4',
+ ['asrep etype_info2 des-cbc-md4 KRBTEST.COM 01',
+ 'asrep etype_info des-cbc-md4 KRBTEST.COM',
+ 'asrep afs3_salt KRBTEST.COM'])
+test_etinfo('user', 'des-cbc-md5 rc4',
+ ['asrep etype_info2 des KRBTEST.COM 01',
+ 'asrep etype_info des KRBTEST.COM',
+ 'asrep afs3_salt KRBTEST.COM'])
+
+# If no keys are found matching the request enctypes, a
+# preauth-required error can be generated with no etype-info at all
+# (to allow for preauth mechs which don't depend on long-term keys).
+# An AS-REP cannot be generated without preauth as there is no reply
+# key.
+test_etinfo('rc4user', 'des3', [])
+test_etinfo('nokeyuser', 'des3', [])
+
+success('KDC etype-info tests')
More information about the cvs-krb5
mailing list