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