summaryrefslogtreecommitdiffstats
path: root/src/tests
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2012-04-24 01:05:41 +0000
committerGreg Hudson <ghudson@mit.edu>2012-04-24 01:05:41 +0000
commit2782e80a12bccd920fa71e23166ac97c4470a637 (patch)
tree2c2e4c0f03fdbb9144043494b65b4f404d99fdfd /src/tests
parent8230c4b7b7323cdef2a6c877deb710a15380f40f (diff)
downloadkrb5-2782e80a12bccd920fa71e23166ac97c4470a637.tar.gz
krb5-2782e80a12bccd920fa71e23166ac97c4470a637.tar.xz
krb5-2782e80a12bccd920fa71e23166ac97c4470a637.zip
Try all history keys to decrypt password history
A database created prior to 1.3 will have multiple password history keys, and kadmin prior to 1.8 won't necessarily choose the first one. So if there are multiple keys, we have to try them all. If none of the keys can decrypt a password history entry, don't fail the password change operation; it's not worth it without positive evidence of password reuse. ticket: 7099 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25819 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/Makefile.in6
-rw-r--r--src/tests/hist.c99
-rw-r--r--src/tests/t_pwhist.py20
3 files changed, 124 insertions, 1 deletions
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 9c5d269a13..5ee619a1eb 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -18,6 +18,9 @@ TEST_PREFIX = "foo bar"
KADMIN_OPTS= -d $(TEST_DB) -r $(TEST_REALM) -P $(TEST_MKEY)
KTEST_OPTS= $(KADMIN_OPTS) -p $(TEST_PREFIX) -n $(TEST_NUM) -D $(TEST_DEPTH)
+hist: hist.o $(KDB5_DEPLIBS) $(KADMSRV_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o $@ hist.o $(KDB5_LIBS) $(KADMSRV_LIBS) $(KRB5_BASE_LIBS)
+
check-unix:: kdb_check
kdc.conf: Makefile
@@ -60,7 +63,7 @@ kdb_check: kdc.conf krb5.conf
$(RUN_SETUP) $(VALGRIND) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) destroy -f
$(RM) $(TEST_DB)* stash_file
-check-pytests::
+check-pytests:: hist
$(RUNPYTEST) $(srcdir)/t_general.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_anonpkinit.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_lockout.py $(PYTESTFLAGS)
@@ -73,6 +76,7 @@ check-pytests::
$(RUNPYTEST) $(srcdir)/t_crossrealm.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_skew.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_keytab.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_pwhist.py $(PYTESTFLAGS)
# $(RUNPYTEST) $(srcdir)/kdc_realm/kdcref.py $(PYTESTFLAGS)
clean::
diff --git a/src/tests/hist.c b/src/tests/hist.c
new file mode 100644
index 0000000000..c0b2b978c2
--- /dev/null
+++ b/src/tests/hist.c
@@ -0,0 +1,99 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* tests/hist.c - Perform unusual operations on history keys */
+/*
+ * Copyright (C) 2012 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.
+ */
+
+/*
+ * This program is invoked from t_pwhist.py to simulate some conditions
+ * normally only seen in databases created before krb5 1.3. With the "make"
+ * argument, the history key is rolled over to a kvno containing two keys
+ * (since krb5 1.3 we ordinarily ensure that there's only one). With the
+ * "swap" argument, the two history keys are swapped in order; we use this
+ * operation to simulate the case where krb5 1.7 or earlier chose something
+ * other than the first history key to create pasword history entries.
+ */
+
+#include <k5-int.h>
+#include <kadm5/admin.h>
+
+static void
+check(krb5_error_code ret)
+{
+ if (ret) {
+ fprintf(stderr, "Unexpected failure, aborting\n");
+ abort();
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ krb5_context ctx;
+ krb5_db_entry *ent;
+ krb5_principal hprinc;
+ kadm5_principal_ent_rec kent;
+ krb5_key_salt_tuple ks[2];
+ krb5_key_data kd;
+ kadm5_config_params params = { 0 };
+ void *handle;
+ char *realm;
+ long mask = KADM5_PRINCIPAL | KADM5_MAX_LIFE | KADM5_ATTRIBUTES;
+
+ check(kadm5_init_krb5_context(&ctx));
+ check(krb5_parse_name(ctx, "kadmin/history", &hprinc));
+ check(krb5_get_default_realm(ctx, &realm));
+ params.mask |= KADM5_CONFIG_REALM;
+ params.realm = realm;
+ check(kadm5_init(ctx, "user", "", "", &params, KADM5_STRUCT_VERSION,
+ KADM5_API_VERSION_3, NULL, &handle));
+ if (strcmp(argv[1], "make") == 0) {
+ memset(&kent, 0, sizeof(kent));
+ kent.principal = hprinc;
+ kent.max_life = KRB5_KDB_DISALLOW_ALL_TIX;
+ kent.attributes = 0;
+ ks[0].ks_enctype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
+ ks[0].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL;
+ ks[1].ks_enctype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
+ ks[1].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL;
+ check(kadm5_create_principal_3(handle, &kent, mask, 2, ks, NULL));
+ } else if (strcmp(argv[1], "swap") == 0) {
+ check(krb5_db_get_principal(ctx, hprinc, 0, &ent));
+ kd = ent->key_data[0];
+ ent->key_data[0] = ent->key_data[1];
+ ent->key_data[1] = kd;
+ check(krb5_db_put_principal(ctx, ent));
+ krb5_db_free_principal(ctx, ent);
+ }
+ krb5_free_default_realm(ctx, realm);
+ kadm5_destroy(handle);
+ krb5_free_principal(ctx, hprinc);
+ krb5_free_context(ctx);
+ return 0;
+}
diff --git a/src/tests/t_pwhist.py b/src/tests/t_pwhist.py
new file mode 100644
index 0000000000..4ae546668d
--- /dev/null
+++ b/src/tests/t_pwhist.py
@@ -0,0 +1,20 @@
+#!/usr/bin/python
+from k5test import *
+
+# Regression test for issue #7099: databases created prior to krb5 1.3 have
+# multiple history keys, and kadmin prior to 1.7 didn't necessarily use the
+# first one to create history entries.
+realm = K5Realm(start_kadmind=False, start_kdc=False)
+# Create a history principal with two keys.
+realm.run_as_master(['./hist', 'make'])
+realm.run_kadminl('addpol -history 2 pol')
+realm.run_kadminl('modprinc -policy pol user')
+realm.run_kadminl('cpw -pw pw2 user')
+# Swap the keys, simulating older kadmin having chosen the second entry.
+realm.run_as_master(['./hist', 'swap'])
+# Make sure we can read the history entry.
+output = realm.run_kadminl('cpw -pw %s user' % password('user'))
+if 'Cannot reuse password' not in output:
+ fail('Expected error not seen in output')
+
+success('Password history tests')