summaryrefslogtreecommitdiff
path: root/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/Makefile.in27
-rw-r--r--src/tests/create/kdb5_mkdums.c2
-rw-r--r--src/tests/dejagnu/pkinit-certs/ca.pem54
-rw-r--r--src/tests/dejagnu/pkinit-certs/generic.p12bin0 -> 2477 bytes
-rw-r--r--src/tests/dejagnu/pkinit-certs/generic.pem21
-rw-r--r--src/tests/dejagnu/pkinit-certs/kdc.pem50
-rwxr-xr-xsrc/tests/dejagnu/pkinit-certs/make-certs.sh69
-rw-r--r--src/tests/dejagnu/pkinit-certs/privkey-enc.pem52
-rw-r--r--src/tests/dejagnu/pkinit-certs/privkey.pem50
-rw-r--r--src/tests/dejagnu/pkinit-certs/user-enc.p12bin3029 -> 2837 bytes
-rw-r--r--src/tests/dejagnu/pkinit-certs/user-upn.p12bin0 -> 2829 bytes
-rw-r--r--src/tests/dejagnu/pkinit-certs/user-upn.pem28
-rw-r--r--src/tests/dejagnu/pkinit-certs/user-upn2.p12bin0 -> 2813 bytes
-rw-r--r--src/tests/dejagnu/pkinit-certs/user-upn2.pem28
-rw-r--r--src/tests/dejagnu/pkinit-certs/user-upn3.p12bin0 -> 2829 bytes
-rw-r--r--src/tests/dejagnu/pkinit-certs/user-upn3.pem28
-rw-r--r--src/tests/dejagnu/pkinit-certs/user.p12bin3104 -> 2837 bytes
-rw-r--r--src/tests/dejagnu/pkinit-certs/user.pem56
-rw-r--r--src/tests/deps16
-rw-r--r--src/tests/gssapi/Makefile.in27
-rw-r--r--src/tests/gssapi/deps7
-rw-r--r--src/tests/gssapi/t_authind.py20
-rwxr-xr-xsrc/tests/gssapi/t_ccselect.py69
-rwxr-xr-xsrc/tests/gssapi/t_client_keytab.py60
-rw-r--r--src/tests/gssapi/t_enctypes.c14
-rwxr-xr-xsrc/tests/gssapi/t_enctypes.py4
-rwxr-xr-xsrc/tests/gssapi/t_export_cred.py4
-rwxr-xr-xsrc/tests/gssapi/t_gssapi.py130
-rw-r--r--src/tests/gssapi/t_invalid.c57
-rw-r--r--src/tests/gssapi/t_lifetime.c140
-rw-r--r--src/tests/gssapi/t_s4u.c20
-rwxr-xr-xsrc/tests/gssapi/t_s4u.py21
-rw-r--r--src/tests/hammer/kdc5_hammer.c47
-rw-r--r--src/tests/icinterleave.c128
-rw-r--r--src/tests/icred.c67
-rw-r--r--src/tests/kdbtest.c5
-rw-r--r--src/tests/responder.c2
-rwxr-xr-xsrc/tests/t_audit.py11
-rw-r--r--src/tests/t_authdata.py66
-rwxr-xr-xsrc/tests/t_ccache.py60
-rw-r--r--src/tests/t_certauth.py47
-rwxr-xr-xsrc/tests/t_crossrealm.py49
-rwxr-xr-xsrc/tests/t_dump.py31
-rwxr-xr-xsrc/tests/t_general.py37
-rwxr-xr-xsrc/tests/t_hostrealm.py5
-rwxr-xr-xsrc/tests/t_iprop.py103
-rw-r--r--src/tests/t_kadm5_auth.py81
-rwxr-xr-xsrc/tests/t_kadm5_hook.py10
-rwxr-xr-xsrc/tests/t_kadmin_acl.py269
-rw-r--r--src/tests/t_kadmin_parsing.py30
-rwxr-xr-xsrc/tests/t_kdb.py219
-rwxr-xr-xsrc/tests/t_kdb_locking.py5
-rw-r--r--src/tests/t_kdcpolicy.py62
-rwxr-xr-xsrc/tests/t_keydata.py16
-rwxr-xr-xsrc/tests/t_keyrollover.py16
-rwxr-xr-xsrc/tests/t_keytab.py50
-rwxr-xr-xsrc/tests/t_kprop.py13
-rwxr-xr-xsrc/tests/t_localauth.py5
-rwxr-xr-xsrc/tests/t_mkey.py45
-rwxr-xr-xsrc/tests/t_otp.py10
-rwxr-xr-xsrc/tests/t_pkinit.py154
-rwxr-xr-xsrc/tests/t_policy.py101
-rw-r--r--src/tests/t_preauth.py183
-rwxr-xr-xsrc/tests/t_pwqual.py25
-rwxr-xr-xsrc/tests/t_referral.py18
-rwxr-xr-xsrc/tests/t_renew.py78
-rwxr-xr-xsrc/tests/t_salt.py12
-rwxr-xr-xsrc/tests/t_skew.py22
-rwxr-xr-xsrc/tests/t_stringattr.py4
-rw-r--r--src/tests/t_y2038.py75
70 files changed, 2105 insertions, 1110 deletions
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index b55469146626..67d3e8200e3f 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -6,12 +6,12 @@ SUBDIRS = resolve asn.1 create hammer verify gssapi dejagnu shlib \
RUN_DB_TEST = $(RUN_SETUP) KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf \
LC_ALL=C $(VALGRIND)
-OBJS= adata.o etinfo.o forward.o gcred.o hist.o hooks.o hrealm.o icred.o \
- kdbtest.o localauth.o plugorder.o rdreq.o responder.o s2p.o \
- s4u2proxy.o unlockiter.o
+OBJS= adata.o etinfo.o forward.o gcred.o hist.o hooks.o hrealm.o \
+ icinterleave.o icred.o kdbtest.o localauth.o plugorder.o rdreq.o \
+ responder.o s2p.o s4u2proxy.o unlockiter.o
EXTRADEPSRCS= adata.c etinfo.c forward.c gcred.c hist.c hooks.c hrealm.c \
- icred.c kdbtest.c localauth.c plugorder.c rdreq.o responder.c s2p.c \
- s4u2proxy.c unlockiter.c
+ icinterleave.c icred.c kdbtest.c localauth.c plugorder.c rdreq.o \
+ responder.c s2p.c s4u2proxy.c unlockiter.c
TEST_DB = ./testdb
TEST_REALM = FOO.TEST.REALM
@@ -44,6 +44,9 @@ hooks: hooks.o $(KRB5_BASE_DEPLIBS)
hrealm: hrealm.o $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o $@ hrealm.o $(KRB5_BASE_LIBS)
+icinterleave: icinterleave.o $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o $@ icinterleave.o $(KRB5_BASE_LIBS)
+
icred: icred.o $(KRB5_BASE_DEPLIBS)
$(CC_LINK) -o $@ icred.o $(KRB5_BASE_LIBS)
@@ -115,8 +118,9 @@ kdb_check: kdc.conf krb5.conf
$(RUN_DB_TEST) ../kadmin/dbutil/kdb5_util $(KADMIN_OPTS) destroy -f
$(RM) $(TEST_DB)* stash_file
-check-pytests: adata etinfo forward gcred hist hooks hrealm icred kdbtest
-check-pytests: localauth plugorder rdreq responder s2p s4u2proxy unlockiter
+check-pytests: adata etinfo forward gcred hist hooks hrealm icinterleave icred
+check-pytests: kdbtest localauth plugorder rdreq responder s2p s4u2proxy
+check-pytests: unlockiter
$(RUNPYTEST) $(srcdir)/t_general.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_hooks.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_dump.py $(PYTESTFLAGS)
@@ -128,6 +132,7 @@ check-pytests: localauth plugorder rdreq responder s2p s4u2proxy unlockiter
$(RUNPYTEST) $(srcdir)/t_otp.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_localauth.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_kadm5_hook.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_kadm5_auth.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_pwqual.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_hostrealm.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_kdb_locking.py $(PYTESTFLAGS)
@@ -167,10 +172,14 @@ check-pytests: localauth plugorder rdreq responder s2p s4u2proxy unlockiter
$(RUNPYTEST) $(srcdir)/t_preauth.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_princflags.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_tabdump.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_certauth.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_y2038.py $(PYTESTFLAGS)
+ $(RUNPYTEST) $(srcdir)/t_kdcpolicy.py $(PYTESTFLAGS)
clean:
- $(RM) adata etinfo forward gcred hist hooks hrealm icred kdbtest
- $(RM) localauth plugorder rdreq responder s2p s4u2proxy unlockiter
+ $(RM) adata etinfo forward gcred hist hooks hrealm icinterleave icred
+ $(RM) kdbtest localauth plugorder rdreq responder s2p s4u2proxy
+ $(RM) unlockiter
$(RM) krb5.conf kdc.conf
$(RM) -rf kdc_realm/sandbox ldap
$(RM) au.log
diff --git a/src/tests/create/kdb5_mkdums.c b/src/tests/create/kdb5_mkdums.c
index 622f549f9f2e..7c0666601c48 100644
--- a/src/tests/create/kdb5_mkdums.c
+++ b/src/tests/create/kdb5_mkdums.c
@@ -247,7 +247,7 @@ add_princ(context, str_newprinc)
{
/* Add mod princ to db entry */
- krb5_int32 now;
+ krb5_timestamp now;
retval = krb5_timeofday(context, &now);
if (retval) {
diff --git a/src/tests/dejagnu/pkinit-certs/ca.pem b/src/tests/dejagnu/pkinit-certs/ca.pem
index 55fe02c92773..f7421ba02491 100644
--- a/src/tests/dejagnu/pkinit-certs/ca.pem
+++ b/src/tests/dejagnu/pkinit-certs/ca.pem
@@ -1,29 +1,29 @@
-----BEGIN CERTIFICATE-----
-MIIE5TCCA82gAwIBAgIJANsFDWp1HgAaMA0GCSqGSIb3DQEBBQUAMIGnMQswCQYD
-VQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czESMBAGA1UEBxMJQ2FtYnJp
-ZGdlMQwwCgYDVQQKEwNNSVQxKTAnBgNVBAsTIEluc2VjdXJlIFBraW5pdCBLZXJi
-ZXJvcyB0ZXN0IENBMTMwMQYDVQQDFCpwa2luaXQgdGVzdCBzdWl0ZSBDQTsgZG8g
-bm90IHVzZSBvdGhlcndpc2UwHhcNMTAwMTA2MTQ1MTI3WhcNMjMwOTE1MTQ1MTI3
-WjCBpzELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNV
-BAcTCUNhbWJyaWRnZTEMMAoGA1UEChMDTUlUMSkwJwYDVQQLEyBJbnNlY3VyZSBQ
-a2luaXQgS2VyYmVyb3MgdGVzdCBDQTEzMDEGA1UEAxQqcGtpbml0IHRlc3Qgc3Vp
-dGUgQ0E7IGRvIG5vdCB1c2Ugb3RoZXJ3aXNlMIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAnYLMe58ny00MgskJP7tZ3PIQRpQkXGLJZKI0HfntCRbIuvmn
-ZejPSKdNMyejzRIyjdw1FDJUAnpXYcic3TD5817G5H63UrllAGuy+lhQWNzE6c6K
-ueerevR3pMaqHXonaflVasUu5e2AAWVnFbz4x04uLlQejqPwm5sR1xTeLUnVfSY7
-5NbXGIE488iDV0wW8nqGoVWn/TsRd+7KuQUIkJpt8+V6Jk6hPIcPqe6h7mXNGsgc
-5dBSqBwVcjU9DbeT4xxxEmgQdLt7qdNwV1ZPLQnTQpogNrT5uf3oSbOTsyM02GOW
-riIRmsqq81sfMrpviTRRDwoqTUEhoCSor0UmcwIDAQABo4IBEDCCAQwwHQYDVR0O
-BBYEFFn82RUKgTvkFn0cgwyCQpNeWCxYMIHcBgNVHSMEgdQwgdGAFFn82RUKgTvk
-Fn0cgwyCQpNeWCxYoYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNTWFz
-c2FjaHVzZXR0czESMBAGA1UEBxMJQ2FtYnJpZGdlMQwwCgYDVQQKEwNNSVQxKTAn
-BgNVBAsTIEluc2VjdXJlIFBraW5pdCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQD
-FCpwa2luaXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCCQDb
-BQ1qdR4AGjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBVL2Q6Xubs
-gm881cAy6esku17/BSTZur7hCLHTGof1ZKNcCXALjmwNYNC3tl6owqpX8CSdBdsD
-Bw/Vs9p3mqnaVEoZc8uW8zS6LoAQbcqiYdQHdEXMh3ec8uvAfmdlQsIsm5Ux8q8L
-NM6bKnUOqOFOHme+RC4FGOLb8JqnnuQdwyIZaUyQP6hXbw4zyDphfgo1ZlZn20xh
-I555kPfAZKEi/d3WY0oN4k+sfCs9tWRNjmqZfKkH1OqRpjCFGG0b0vY77MFRMuPz
-YtN2iD3plgla7KkUMljp9th/Z8Ok79uA1TNLYKzoBjlAX0vToxfa8rrSNo1dHFKT
-e5Tj7+29DE4I
+MIIE5TCCA82gAwIBAgIBATANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
+A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
+dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
+b3RoZXJ3aXNlMB4XDTE3MDgyNTE4MzIxMFoXDTI4MDgwNzE4MzIxMFowgacxCzAJ
+BgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlDYW1i
+cmlkZ2UxDDAKBgNVBAoMA01JVDEpMCcGA1UECwwgSW5zZWN1cmUgUEtJTklUIEtl
+cmJlcm9zIHRlc3QgQ0ExMzAxBgNVBAMMKnBraW5pdCB0ZXN0IHN1aXRlIENBOyBk
+byBub3QgdXNlIG90aGVyd2lzZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAL8HFT/+Uia/TcSFIJJd7Z7ZFvMOYLhEkCyqRhW1ggDp0xrIAoh/fyxq4qId
+S8f7Aurf39kzyS9NtDD2snKwfoLaZpunIXNLCujrlrqdhKsZdtl8aYLmjIhTLu4r
+rN5WZIRQULbkLiuqc6ZFOjOZxkR0NkC/CyfQTJO5a2TaMrweLswmY0k5KlAoevps
+h+LPXsLC66sqgYuWDD8c1Z9GlI8dW2abRPt+WUKskEgHqYJrCkjvPIZgS7UDAzpU
+OCXopDDr/qQ9dnAYzt98r/pCx621/2R4JttZbdsXQDbQaHhV69iJqACqZB0lLyKO
+Ka4Y2U5zy3++t6pd3oGlWCr96D0CAwEAAaOCARgwggEUMB0GA1UdDgQWBBSvEuBX
+VNKtIomCkLcxpsKp9Ag9qzCB1AYDVR0jBIHMMIHJgBSvEuBXVNKtIomCkLcxpsKp
+9Ag9q6GBraSBqjCBpzELMAkGA1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0
+dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoGA1UECgwDTUlUMSkwJwYDVQQLDCBJ
+bnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVzdCBDQTEzMDEGA1UEAwwqcGtpbml0
+IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ugb3RoZXJ3aXNlggEBMAsGA1UdDwQE
+AwIB/jAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQArUoCjqxsY
+/m3nx/5BQSkBAL4T5RgWIX+L4y4GXloYYlafpw+SxRq0QffFm5fpCJBnMd21MbPl
+k/YA+oq0/76cKyQmJ6h/Wl4KHCKKMmvGuhCEXzmrevk/EJ8lJXNdPfbBueAuLeyU
+7X9tO8i9fJ59AZ9YWD9d//puOF+8xeHPxJIxHcR2jHpUOJPtm4yVu1LreHiJJTu4
+Xotp9yMpJu/uJM3aBKVS5N/5JreraLj9N6N8nZ/7nEw9Dj1zzGHcHCcqtcxz1oOH
+Zbg5Jo8HhVhIHxKdKLvwEk60P+lkGFIE+IUmhWfcbbprTGs7VhxREwxaWyCapCOk
+qlhbJdEcjHr2
-----END CERTIFICATE-----
diff --git a/src/tests/dejagnu/pkinit-certs/generic.p12 b/src/tests/dejagnu/pkinit-certs/generic.p12
new file mode 100644
index 000000000000..238baa56bc7b
--- /dev/null
+++ b/src/tests/dejagnu/pkinit-certs/generic.p12
Binary files differ
diff --git a/src/tests/dejagnu/pkinit-certs/generic.pem b/src/tests/dejagnu/pkinit-certs/generic.pem
new file mode 100644
index 000000000000..706c2f341c87
--- /dev/null
+++ b/src/tests/dejagnu/pkinit-certs/generic.pem
@@ -0,0 +1,21 @@
+-----BEGIN CERTIFICATE-----
+MIIDZjCCAk4CAQcwDQYJKoZIhvcNAQELBQAwgacxCzAJBgNVBAYTAlVTMRYwFAYD
+VQQIDA1NYXNzYWNodXNldHRzMRIwEAYDVQQHDAlDYW1icmlkZ2UxDDAKBgNVBAoM
+A01JVDEpMCcGA1UECwwgSW5zZWN1cmUgUEtJTklUIEtlcmJlcm9zIHRlc3QgQ0Ex
+MzAxBgNVBAMMKnBraW5pdCB0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVy
+d2lzZTAeFw0xNzA4MjUxODMyMTFaFw0yODA4MDcxODMyMTFaMEoxCzAJBgNVBAYT
+AlVTMRYwFAYDVQQIDA1NYXNzYWNodXNldHRzMRQwEgYDVQQKDAtLUkJURVNULkNP
+TTENMAsGA1UEAwwEdXNlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AL8HFT/+Uia/TcSFIJJd7Z7ZFvMOYLhEkCyqRhW1ggDp0xrIAoh/fyxq4qIdS8f7
+Aurf39kzyS9NtDD2snKwfoLaZpunIXNLCujrlrqdhKsZdtl8aYLmjIhTLu4rrN5W
+ZIRQULbkLiuqc6ZFOjOZxkR0NkC/CyfQTJO5a2TaMrweLswmY0k5KlAoevpsh+LP
+XsLC66sqgYuWDD8c1Z9GlI8dW2abRPt+WUKskEgHqYJrCkjvPIZgS7UDAzpUOCXo
+pDDr/qQ9dnAYzt98r/pCx621/2R4JttZbdsXQDbQaHhV69iJqACqZB0lLyKOKa4Y
+2U5zy3++t6pd3oGlWCr96D0CAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAAniIG+xJ
+6rXbrH2kt40GE58fFzrIlzhG4VzncNnpFitvPEMzN0kMa5LBX5/zSYiMawQBQ7C0
+FpCjz+n82VVW8iabCNoqUUNwOP7ZYmsoraHT9klSak/mLfAXOyOG3DUV9jntivnl
+HUIiDO7Pf6GnVVROio9psQEVOX1+W1uq9Vs79+F5GI/s0QR9dG0qXvdJ0h5UdVee
+8LVXQOi3cQKyBOwECwt0HA0pJwwcD6w9e8Y2NYTeOTamWGQVEV3NlcvtdSVuDJ8y
+lTke2YbEKyHdcsQ1vrDHtdyfEmJcgO5c9EL5ptYJB7Yv1QiwWJOhLdT13IBYvOtO
+ebOF6zAD73Bpkw==
+-----END CERTIFICATE-----
diff --git a/src/tests/dejagnu/pkinit-certs/kdc.pem b/src/tests/dejagnu/pkinit-certs/kdc.pem
index 5575ab579a33..4eb811debabf 100644
--- a/src/tests/dejagnu/pkinit-certs/kdc.pem
+++ b/src/tests/dejagnu/pkinit-certs/kdc.pem
@@ -1,25 +1,29 @@
-----BEGIN CERTIFICATE-----
-MIIEMjCCAxqgAwIBAgIBAjANBgkqhkiG9w0BAQUFADCBpzELMAkGA1UEBhMCVVMx
-FjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcTCUNhbWJyaWRnZTEMMAoG
-A1UEChMDTUlUMSkwJwYDVQQLEyBJbnNlY3VyZSBQa2luaXQgS2VyYmVyb3MgdGVz
-dCBDQTEzMDEGA1UEAxQqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
-b3RoZXJ3aXNlMB4XDTEwMDEwNjE0NTgwOFoXDTIzMDkxNTE0NTgwOFowSjELMAkG
-A1UEBhMCVVMxFjAUBgNVBAgTDU1hc3NhY2h1c2V0dHMxFTATBgNVBAoTDEtSQlRF
-U1QuQ09NIDEMMAoGA1UECxMDS0RDMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
-CgKCAQEAnYLMe58ny00MgskJP7tZ3PIQRpQkXGLJZKI0HfntCRbIuvmnZejPSKdN
-MyejzRIyjdw1FDJUAnpXYcic3TD5817G5H63UrllAGuy+lhQWNzE6c6KueerevR3
-pMaqHXonaflVasUu5e2AAWVnFbz4x04uLlQejqPwm5sR1xTeLUnVfSY75NbXGIE4
-88iDV0wW8nqGoVWn/TsRd+7KuQUIkJpt8+V6Jk6hPIcPqe6h7mXNGsgc5dBSqBwV
-cjU9DbeT4xxxEmgQdLt7qdNwV1ZPLQnTQpogNrT5uf3oSbOTsyM02GOWriIRmsqq
-81sfMrpviTRRDwoqTUEhoCSor0UmcwIDAQABo4HEMIHBMAkGA1UdEwQCMAAwCwYD
-VR0PBAQDAgPoMBIGA1UdJQQLMAkGBysGAQUCAwUwHQYDVR0OBBYEFFn82RUKgTvk
-Fn0cgwyCQpNeWCxYMB8GA1UdIwQYMBaAFFn82RUKgTvkFn0cgwyCQpNeWCxYMAkG
-A1UdEgQCMAAwSAYDVR0RBEEwP6A9BgYrBgEFAgKgMzAxoA0bC0tSQlRFU1QuQ09N
-oSAwHqADAgEBoRcwFRsGa3JidGd0GwtLUkJURVNULkNPTTANBgkqhkiG9w0BAQUF
-AAOCAQEAP0byILHLWPyGlv/1HN34DfIpLdVkgGar2yceMtZ2v/7UjeA5PlZc8DFM
-20bTq/vIN0eWDTPLI57e+MzQTMxs2UHsic4su0m5DG0cvQTsBXRK51CW/qUF+4n0
-qSEORULiDF6LNoo8akoLukNBhzBh+aqYt4aB46hhsmDmNZTDP1CXsNGHQI9/L52l
-oqpUGx8tBpKIFos95PSajXrQn2u66rSMMi4aawitM2igurHPDMbC+XvEYMtXpOS5
-3PEzXEYiSV3TWLTzIE9ytswHeZyHCbp7XHx0LVZFxzqtIe4qmwJJOGhlbH21Izr4
-feF5h5e2ZrOVREY4cKkJmJhEwsqBVA==
+MIIE4TCCA8mgAwIBAgIBAjANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
+A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
+dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
+b3RoZXJ3aXNlMB4XDTE3MDgyNTE4MzIxMFoXDTI4MDgwNzE4MzIxMFowSTELMAkG
+A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
+U1QuQ09NMQwwCgYDVQQDDANLREMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC/BxU//lImv03EhSCSXe2e2RbzDmC4RJAsqkYVtYIA6dMayAKIf38sauKi
+HUvH+wLq39/ZM8kvTbQw9rJysH6C2mabpyFzSwro65a6nYSrGXbZfGmC5oyIUy7u
+K6zeVmSEUFC25C4rqnOmRTozmcZEdDZAvwsn0EyTuWtk2jK8Hi7MJmNJOSpQKHr6
+bIfiz17CwuurKoGLlgw/HNWfRpSPHVtmm0T7fllCrJBIB6mCawpI7zyGYEu1AwM6
+VDgl6KQw6/6kPXZwGM7ffK/6Qsettf9keCbbWW3bF0A20Gh4VevYiagAqmQdJS8i
+jimuGNlOc8t/vreqXd6BpVgq/eg9AgMBAAGjggFzMIIBbzAdBgNVHQ4EFgQUrxLg
+V1TSrSKJgpC3MabCqfQIPaswgdQGA1UdIwSBzDCByYAUrxLgV1TSrSKJgpC3MabC
+qfQIPauhga2kgaowgacxCzAJBgNVBAYTAlVTMRYwFAYDVQQIDA1NYXNzYWNodXNl
+dHRzMRIwEAYDVQQHDAlDYW1icmlkZ2UxDDAKBgNVBAoMA01JVDEpMCcGA1UECwwg
+SW5zZWN1cmUgUEtJTklUIEtlcmJlcm9zIHRlc3QgQ0ExMzAxBgNVBAMMKnBraW5p
+dCB0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZYIBATALBgNVHQ8E
+BAMCA+gwDAYDVR0TAQH/BAIwADBIBgNVHREEQTA/oD0GBisGAQUCAqAzMDGgDRsL
+S1JCVEVTVC5DT02hIDAeoAMCAQGhFzAVGwZrcmJ0Z3QbC0tSQlRFU1QuQ09NMBIG
+A1UdJQQLMAkGBysGAQUCAwUwDQYJKoZIhvcNAQELBQADggEBAFMX7ZTpNPdzFwkE
+hrab7fSDeoG+mN0yorY8e5Evx6sE7pXOtHgHIjQY2Ys0lk2mhbsIKptL/R6jTxWR
+rbmU6jFNFeJgn5ba3NWdhlUiZ8WKe2knp6uc9ZDIK007XaKA4rRoHlJ3vHXoF+ga
+JFOYwRzCtAlmsOCQ0UetoC3Ju6Y6NhCXIE8f81dsh6RMADoQT0n/fcLY/JtbbLXK
+ANTIWHm0oSX9wvOU/yZkYGuwcPd91cc6Mea8f3J8D/OiatMZXc3719extmeR6Cv6
+aba31kv9wtbxVuxkR7HhjlJhzhqfzfIp3tNREaIxPb/qKGWBOjwxGRqSUkdEqMvD
+GjaSlyc=
-----END CERTIFICATE-----
diff --git a/src/tests/dejagnu/pkinit-certs/make-certs.sh b/src/tests/dejagnu/pkinit-certs/make-certs.sh
index b82ef6f83f6e..63f0c6f75b8b 100755
--- a/src/tests/dejagnu/pkinit-certs/make-certs.sh
+++ b/src/tests/dejagnu/pkinit-certs/make-certs.sh
@@ -4,7 +4,9 @@ NAMETYPE=1
KEYSIZE=2048
DAYS=4000
REALM=KRBTEST.COM
+LOWREALM=krbtest.com
KRB5_PRINCIPAL_SAN=1.3.6.1.5.2.2
+KRB5_UPN_SAN=1.3.6.1.4.1.311.20.2.3
PKINIT_KDC_EKU=1.3.6.1.5.2.3.5
PKINIT_CLIENT_EKU=1.3.6.1.5.2.3.4
TLS_SERVER_EKU=1.3.6.1.5.5.7.3.1
@@ -85,6 +87,30 @@ keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
basicConstraints = critical,CA:FALSE
subjectAltName = otherName:$KRB5_PRINCIPAL_SAN;SEQUENCE:krb5princ_client
extendedKeyUsage = $CLIENT_EKU_LIST
+
+[exts_upn_client]
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer:always
+keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
+basicConstraints = critical,CA:FALSE
+subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user@$LOWREALM
+extendedKeyUsage = $CLIENT_EKU_LIST
+
+[exts_upn2_client]
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer:always
+keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
+basicConstraints = critical,CA:FALSE
+subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user
+extendedKeyUsage = $CLIENT_EKU_LIST
+
+[exts_upn3_client]
+subjectKeyIdentifier = hash
+authorityKeyIdentifier = keyid:always,issuer:always
+keyUsage = nonRepudiation,digitalSignature,keyEncipherment,keyAgreement
+basicConstraints = critical,CA:FALSE
+subjectAltName = otherName:$KRB5_UPN_SAN;UTF8:user@$REALM
+extendedKeyUsage = $CLIENT_EKU_LIST
EOF
# Generate a private key.
@@ -96,15 +122,14 @@ SUBJECT=ca openssl req -config openssl.cnf -new -x509 -extensions exts_ca \
-set_serial 1 -days $DAYS -key privkey.pem -out ca.pem
# Generate a KDC certificate.
-SUBJECT=kdc openssl req -config openssl.cnf -new -subj /CN=kdc \
- -key privkey.pem -out kdc.csr
+SUBJECT=kdc openssl req -config openssl.cnf -new -key privkey.pem -out kdc.csr
SUBJECT=kdc openssl x509 -extfile openssl.cnf -extensions exts_kdc \
-set_serial 2 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
-out kdc.pem -in kdc.csr
# Generate a client certificate and PKCS#12 bundles.
-SUBJECT=user openssl req -config openssl.cnf -new -subj /CN=user \
- -key privkey.pem -out user.csr
+SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \
+ -out user.csr
SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_client \
-set_serial 3 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
-out user.pem -in user.csr
@@ -113,5 +138,39 @@ openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user.p12 \
openssl pkcs12 -export -in user.pem -inkey privkey.pem -out user-enc.p12 \
-passout pass:encrypted
+# Generate a client certificate and PKCS#12 bundles with a UPN SAN.
+SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \
+ -out user-upn.csr
+SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn_client \
+ -set_serial 4 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
+ -out user-upn.pem -in user-upn.csr
+openssl pkcs12 -export -in user-upn.pem -inkey privkey.pem -out user-upn.p12 \
+ -passout pass:
+
+SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \
+ -out user-upn2.csr
+SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn2_client \
+ -set_serial 5 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
+ -out user-upn2.pem -in user-upn2.csr
+openssl pkcs12 -export -in user-upn2.pem -inkey privkey.pem \
+ -out user-upn2.p12 -passout pass:
+
+SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \
+ -out user-upn3.csr
+SUBJECT=user openssl x509 -extfile openssl.cnf -extensions exts_upn3_client \
+ -set_serial 6 -days $DAYS -req -CA ca.pem -CAkey privkey.pem \
+ -out user-upn3.pem -in user-upn3.csr
+openssl pkcs12 -export -in user-upn3.pem -inkey privkey.pem \
+ -out user-upn3.p12 -passout pass:
+
+# Generate a client certificate and PKCS#12 bundle with no PKINIT extensions.
+SUBJECT=user openssl req -config openssl.cnf -new -key privkey.pem \
+ -out generic.csr
+SUBJECT=user openssl x509 -set_serial 7 -days $DAYS -req -CA ca.pem \
+ -CAkey privkey.pem -out generic.pem -in generic.csr
+openssl pkcs12 -export -in generic.pem -inkey privkey.pem -out generic.p12 \
+ -passout pass:
+
# Clean up.
-rm -f openssl.cnf kdc.csr user.csr
+rm -f openssl.cnf kdc.csr user.csr user-upn.csr user-upn2.csr user-upn3.csr
+rm -f generic.csr
diff --git a/src/tests/dejagnu/pkinit-certs/privkey-enc.pem b/src/tests/dejagnu/pkinit-certs/privkey-enc.pem
index 9f7816f17951..ee35e5cdcf66 100644
--- a/src/tests/dejagnu/pkinit-certs/privkey-enc.pem
+++ b/src/tests/dejagnu/pkinit-certs/privkey-enc.pem
@@ -1,30 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
-DEK-Info: DES-EDE3-CBC,91CA660D6286E453
+DEK-Info: DES-EDE3-CBC,7DF54DB740F92845
-DpJ5bo/AN37NcxTNv0Z4d5YomWqyryqYhuA43FlzWWKubld4Gp+owAv5BUd4VLx7
-Efq23ODfuiuh5zna/ZXnY+9m8RHS5AxDd2Kr1s/fVsn+m2Lw9qS69DLjxTjEuDLU
-AwmVADqQUbvocZEt0Byn9oY4ku2lGOY/ax7tZ1WegLInnoCqT2xGC6TLw7Gwr3mX
-z6xFB2Yv4PbvVU8y4V+ka0p5manxptYkrbAkC+vrC4LPUACdbonmpeXUxAfVV9hL
-EMzY74IqY2QS1xFMhbLh2HunfjjC3HZ1wXMf1/LtLl1nnodiOk5o+MTLEHO+npaO
-rJn2z3V/eQsr93M8/K5ONQcPAKZGOCmNpNQUj1UHnUHEubhpI+nqRYe3vqem5GaH
-8gn+uc1/N6c/Bs037iSLWvkgk8mvHgH/26JobZ8qg9yYgVUl3AIVkkGwLGhE5+Kn
-593/p4E5Mb6ttv3ZJ4f3Mz/1b84guhTENY67zxnQEGnpEjfRKoEN1vmHi6mIuWld
-rrUCJ/x1Yvy2tN9eyuTNsGCcfvPeY22RrKgl7Wi0EIvBlLPKBQxqXOA7Mi9Acapd
-+n5pW2Ka2FABSifZ36owa7SJEJ0GLMtdHmZPirolgIjOZVOMbSj2UuR/kXVZjZUM
-LcRcVI1z8NgKF3RKs653HqkphcyRQMMQrL/A38t+v0zFA2P3HPoNWcD+BfKg0H37
-bHPjXdlvAD5yiFXKb1XN99utW5G/qCq5CdzAirm7drxR0bs4ZIV4SwTulvWLW644
-RYes8x7WKg3WUxtair++c1eTwTPhMLz/SxERYXxSUqpxJiRgYTQhwwbE22P6FCWT
-H9pso5IMi6AJp35CGaYHi78NPLWVmrxgkkv2uBoDFd/iIQTac60aG/F86aozQD7V
-DmHINEcsN3lVUmHinoNTcIfc5EZVEbLQIBhy3XI0UDxWuLnchVlU3ad1OKqknbbi
-Ik3lmeLz07JFbpCcMk+xDlQsZYbxcRzyRh0NsWvHXuG77Hbcrnk3ndxT8wADsfOn
-foXf1/R/gf7PDmte3nFlpEcJCHyeY1haIqgk4WsnUUKP56O75cGF1ylkaBrDPlLw
-WaN2Li537ALo6TyB0jspdCzPqIRt8Gr4muoX0tqFjSfKaWmRb3Y7i6jbVrh8d6KV
-xqLse0Vkaip4Lgf/VUWOTvlfHz9nLD0xR6OUPeQ3jxGdhLxmcYec1oRj1aVMlp6f
-PyC6TN+NlPEtv6KWWB9OMc420DGOWllvS5+zsm7Ff7/5TkXlWmlhfhrkyQVy8NOe
-/3ygPbpSfCFjJMwdbEX+ic/Qjk04f3CluP3FYiIG/Pd6ny6rclrhPHg08X6+sciU
-Rj7QtoFpVsDvde2QO0depdoysAG1j1a+sas2lYNPG8hdzbPe20xIJCmF0fWfdxOy
-BxxtKzpq46S8xKLfxAMvKrZNuZy5xhs3JMUjpxTIam7ZiQXd752LdzGx2s4CII6d
-mkeQ/d32TDACAxyEK8es4Mcm3IoCAq/NjIU/ICwGDeOmfDUpsV2TMrg+aKMKcwUE
-UK4bMXercw7Cs0C3o6mdCTFrTtsihHNTrbb7yyN83XK76niSc+LREbuJ8T0vp1Yh
+3I3F5dJkYmjX49YRQub+AzWPOJock699vQZV3oxcAabcZWtLVbQ75QBXXBPEtm3j
+LAqb3gRxfETHNHsSIEwGtN3rYre1UdKs3Bu9ROQNTvlbCwRdss3JA1kGhJu2o5bu
+hf5sjpfR+ivf2prJ4whfhb4+efCHE0Ll669V33D2kbPKX0VCokkRmxsIoVtHd2qu
+d1HM/EkjxrOy/GHZ+93mkSeWC4hz56VL5ApGOV4wHuphdvKy121mU0mjtQRKF2El
+N7DtM9/AIAkLPx5wxrTJXuELd+BBDPbRMwmvgqCX1m8sJLJT2fBzVKRKWexowp7T
+d3j9hT+kMiWCTgd4vJ+i/KPkK460Cy9PzFrzCtWut4jh6rZ+F9Tdp1g4Np0ygWAg
+q9tV4RC7ylW0DeseRTXTLuohngfu0h7mXuhutr1Xmq+SoRuhBllZyexV4jJMc1kZ
+2nv9RJ+h7mCAQbLSVvWCZpngfK2IcZhi4hfNiiQ/wqc6rE3eaBIR9E60kaCeBpWB
+rxZm4VHOrwJw0GsaCRLQez1F65Ulk4TA+7TYJWnW/MGrvBptuBamwxk28Ts6eOee
+RVwb/AdY4QBVJKKT+/e3Lfy409evmdTAA2N+tbYzALC1cH4ex4sO0BifaLmKo3t1
+fC2FLna4P9F17bbjcS1lSWVJKodofUEt4H03X7LaMhwe+sLRuKBIoTH2nLPHLIYg
+B8NO1yFiJPFL0a8fi9kG8JJlCPkASQC5vcYg6BE40b7h7T4qw0HmkuH3i6TX6bsG
+nQlryJ2BfQM+IT3MTEh/T1iHPZcTwFLPF9HMnZ/ydL/nM2kElF6YfMClFvuDGULQ
+zmsvG4D/ndSisapJQeoevAwtCHybh8/3cy8CoAjBE9C1JlHOvP2+64rzvFVUAKfa
+z5aZQQJKcdXcKcM8u8PgEyCN5x5tBqWQjSHR904k25KRkePAh8SoiSDuNQPwtzbB
+RHesvkaSXuUaN7q1+oJzeQvzO8i79ud0Diu5y2KePrlB4HBSWCuWmvz9U+WvGBiw
+KpEUAp/YpkqB1as4IUBDNjV1Y77cyUZ+/8EkPgAvB9wltCCAyQ5xi1h70cDJdabj
+swabRD5JV1JLalFMDrOeOPZh1heaTNHXV8f7m8rMVeYVzVTM1JoQLlvKxcc3LVfN
+9RLn/vTN7Ox//+385UiozC/PAo/Cep6Z1Wz+cwsd62HH0LVimVt2mrmHRKY983cw
+U6cZyhvcTB5UOdJdhwbHfnxQipWRu//XRYY/yVdB6W2J4Gzh//adJfKOmHd8+cB+
+y8Q1yZP3diTGkhyY9pkXS7Gv2Q9mcXlMJtoyb7rqBIL/osVTKdsZn7Cj6ZYB6ftF
++hKQKNs/bKXYs3PF09UOInfUf57pENSr1AQBQceAisAsr8znRYsFlpqZ5L8G6um7
+XBneZ1RBj41wheB8g3kL6hj2UrXrE2rxDAw175a3BaxP/Wc2JgGcBWyJTVcZ35Ab
+f24UNlrfcJdgEFETEiy12WY2VaqJCSY3J6YSimHDbffX+ku8QgU1shZf9z8K1l1A
+OJQzbjlxPZT/k4cfw/Xi0rHdgWGcmL7tKLkTcrG/AixdEoI9KCSlQGSksI8CfFmj
-----END RSA PRIVATE KEY-----
diff --git a/src/tests/dejagnu/pkinit-certs/privkey.pem b/src/tests/dejagnu/pkinit-certs/privkey.pem
index 1825dec4e34d..548e5a8d524a 100644
--- a/src/tests/dejagnu/pkinit-certs/privkey.pem
+++ b/src/tests/dejagnu/pkinit-certs/privkey.pem
@@ -1,27 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
-MIIEpQIBAAKCAQEAnYLMe58ny00MgskJP7tZ3PIQRpQkXGLJZKI0HfntCRbIuvmn
-ZejPSKdNMyejzRIyjdw1FDJUAnpXYcic3TD5817G5H63UrllAGuy+lhQWNzE6c6K
-ueerevR3pMaqHXonaflVasUu5e2AAWVnFbz4x04uLlQejqPwm5sR1xTeLUnVfSY7
-5NbXGIE488iDV0wW8nqGoVWn/TsRd+7KuQUIkJpt8+V6Jk6hPIcPqe6h7mXNGsgc
-5dBSqBwVcjU9DbeT4xxxEmgQdLt7qdNwV1ZPLQnTQpogNrT5uf3oSbOTsyM02GOW
-riIRmsqq81sfMrpviTRRDwoqTUEhoCSor0UmcwIDAQABAoIBAQCSMh5Tu9S2yUwM
-dEZmZiGxhuf+anAZZAOjqT4QeLI/Fmu3yBNM7rq+p7JrAabyp6pOq46EsXXyWtWS
-SB742wWUk2quGMNVQAj0TAJyhNgGstr+XJu8k8BBPnlycobhF0lP/oH+uQifl0KR
-iSoWLjEG5JTOoXs/UAD6nQMBDDhv9TweEwSyIY9jq1J5Q3wVXm/Nr/FJ/8O53guJ
-/TQeo6dtdx6x2+oxKkeWinfxmy2nSoEZd0eb3WUNPZswijO7QgSJolOo83VNqFcn
-lj8hYT41zUM4chple8kGnuSV4ql4a1w/52dSTLKJbgukIqvxeDtKNost344eQqkS
-Lwcc+NO5AoGBAM0bR8TmFlbP4RJAEOOilXTYgP6Ttd1r1mRXGi3DRPyv4EWGT7WW
-MmBHsqU6Mqz+fcoD/AIy1BBdenhaYrrwyCSvitJpoHPjqzOJDX33wUcrnYeincQ3
-PVzpF41O45vTmm692DSJ8t/uR8DhGpCzf/kxuA9ixvdKgMPgBHYeb5zlAoGBAMSY
-KZvgwbtlRR25CGaUgOCHtW76puaPcyxEeCbJEKkJO1vZDAf8vi1zXOM4e/gorKHm
-349ZrBQfFCrvtZG//KvI12MpjBs0Z/ijSCwS4EkYJaSH+Hm+1ygLdArwWEFkNncL
-qQ+Wme1OUoDiAAxRiBKUxUF/pAQqn7X+0MGa2th3AoGBAJ8kRaFu7XJaRUZF01Ts
-d4571kqxDXFKFMUyGCvd0Q9G33rSZdJ9QYUW3HP7HgrAQ5WVVdnW2lgAT+BGMUjf
-PkvIsKvmLQr+YX3RH1jX/W1dWBM/h64RNll6uj14Mn5bxv2Z68GIL5y0Y5QylMwl
-mmwdubSmbb6+Xf6dOJj1sKBJAoGBAJwP0tAMHp6daL2Mmk+cSaZz9KJx1bYnYB1f
-CSZ47IHTc0yZQ0S/7VR1ROKXf0njOA+aEBRi8ghTF5ZyDefyySixWdI9NByQgIzP
-Sca7AVLlGVTAH4694VzHosngO59FZzsfhYh7XBwW1cW8Ip+kxWlCskgphFFOaNR3
-wM5AGMRHAoGAJELs9VYPRJd7h4dPUa2RqfVPlYkcMwvoLYykY0wE5mjoNaJkQbUr
-W5aKhidh4h48fImt2rpB6OYSofYC4yu3VDEr/Kl2nSb8UPE5qEd1pvmdkHSxMNkh
-M2diIqot6s2v20lE/6UCqLXonlquRK1MAlyfPw9yZHP9meCvlBsYZXc=
+MIIEpAIBAAKCAQEAvwcVP/5SJr9NxIUgkl3tntkW8w5guESQLKpGFbWCAOnTGsgC
+iH9/LGrioh1Lx/sC6t/f2TPJL020MPaycrB+gtpmm6chc0sK6OuWup2Eqxl22Xxp
+guaMiFMu7ius3lZkhFBQtuQuK6pzpkU6M5nGRHQ2QL8LJ9BMk7lrZNoyvB4uzCZj
+STkqUCh6+myH4s9ewsLrqyqBi5YMPxzVn0aUjx1bZptE+35ZQqyQSAepgmsKSO88
+hmBLtQMDOlQ4JeikMOv+pD12cBjO33yv+kLHrbX/ZHgm21lt2xdANtBoeFXr2Imo
+AKpkHSUvIo4prhjZTnPLf763ql3egaVYKv3oPQIDAQABAoIBAEe7ACa8d9qm4SvX
+FYkAjjakq/JuxrDKxhyPf6utMXjoVGXtDs50matzI1DekVMxlUHe+O5VfMkvc2cj
+a5SXY5n9KqRuGKhzWFBoDnxao7Of5zn5dqE5szGJksjKS6pdZHcutXBHtHKfGbgo
+rJctuf6AaNLdKfI0TFz4NjRznrN2NyFQGhXzPpq34Qm3Rg91hVlU3A8FYjE7ez6b
+vlJBsbKqnvzxEQMWTk0z0bWC79zE1ElH3Hpwfwb2cG7H4EXf0j6N5k2zODg7C45I
+xWtlES+OpZqdDH6mKFBQojU375j6rb2plZGkTA+qxX9GvG7GsF5aOM6Wkge7SUeT
+NUY2lB0CgYEA83u0TtxCMye1p+ykZwQdcEKR+l4aSjNsM2V2s8Zy4eZseR7f5fgZ
+71ggIpzK9pjT55OiYJOwsEkZAPB0gBgiEcqJgow52w3Hg8sUU5LBEahUpx3Qm64W
+64WNIOL9oVXYQu1S/yJ3iWPMQcH1xIlDtPPC1LH+yHyEOnGe4szIeccCgYEAyNkN
+K2JEbbfK7Wsh3/MOtx5KCkzJzFClTSQZ55IxRUf+myauljKt+kI99jYV6eoicAJv
+SMHQeYurLtSkhuyptAHUqo5xgH0HZ7cE7LV1nfam2p588Yg21nIId9XLDPK4AvCx
+Phz1oznaiGMu4jB7esozuW4FKxB1kRmUikM8bdsCgYEA23jMRLFhsr6+jclPP9SD
+vKck8mtUg0Hq7EEvSEk/UMTlTiA4bhC/P/FNtiVjBfkoOXvoR+mYwK6DLUeRm80l
+GKhaXySLGhtHllK91b9Y7NOwypqjaVD5M/9EATraqEy7DUjjITsuSNd+TF/LawbX
+0wpOum5fXNRwVEYKlCFHLA0CgYApr3LeSDzvkK/batrTAj1RoEW5sYpIj4xfYFjI
+CT2UpYagaPzfS5F0WX9GtJ8Dt4aCPN8f+KnuMCDNTXEAV+o45BBhfcLs6gY5bnDl
+OBw7NtAWm8JO1viatXwwcvz7qPysD4yZ2aTZxc4ndH5sj6dxKrpliAIml/nuraJ4
+t8+49QKBgQCxJ7ZDlM9J0quVivSui5aoZ7iLEiu6GSZ5yF1HSNXY69OnqQK3UxMl
+aERCn/cKqtquJQK3v1IE6k6uAaoM7PXDVKqKSH0Z1Jpqciqjg+J/i7Vym6oCdjer
+6zt6P7Q13f9X9uUlZBnNrT9jk5WjR9pSpxAc0vU78VKa0lZMZ3bROg==
-----END RSA PRIVATE KEY-----
diff --git a/src/tests/dejagnu/pkinit-certs/user-enc.p12 b/src/tests/dejagnu/pkinit-certs/user-enc.p12
index 107480c6d256..b2648ceaa04b 100644
--- a/src/tests/dejagnu/pkinit-certs/user-enc.p12
+++ b/src/tests/dejagnu/pkinit-certs/user-enc.p12
Binary files differ
diff --git a/src/tests/dejagnu/pkinit-certs/user-upn.p12 b/src/tests/dejagnu/pkinit-certs/user-upn.p12
new file mode 100644
index 000000000000..6daa5b378b83
--- /dev/null
+++ b/src/tests/dejagnu/pkinit-certs/user-upn.p12
Binary files differ
diff --git a/src/tests/dejagnu/pkinit-certs/user-upn.pem b/src/tests/dejagnu/pkinit-certs/user-upn.pem
new file mode 100644
index 000000000000..21960ea6e2f1
--- /dev/null
+++ b/src/tests/dejagnu/pkinit-certs/user-upn.pem
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIExTCCA62gAwIBAgIBBDANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
+A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
+dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
+b3RoZXJ3aXNlMB4XDTE3MDgyNTE4MzIxMVoXDTI4MDgwNzE4MzIxMVowSjELMAkG
+A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
+U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvwcVP/5SJr9NxIUgkl3tntkW8w5guESQLKpGFbWCAOnTGsgCiH9/LGri
+oh1Lx/sC6t/f2TPJL020MPaycrB+gtpmm6chc0sK6OuWup2Eqxl22XxpguaMiFMu
+7ius3lZkhFBQtuQuK6pzpkU6M5nGRHQ2QL8LJ9BMk7lrZNoyvB4uzCZjSTkqUCh6
++myH4s9ewsLrqyqBi5YMPxzVn0aUjx1bZptE+35ZQqyQSAepgmsKSO88hmBLtQMD
+OlQ4JeikMOv+pD12cBjO33yv+kLHrbX/ZHgm21lt2xdANtBoeFXr2ImoAKpkHSUv
+Io4prhjZTnPLf763ql3egaVYKv3oPQIDAQABo4IBVjCCAVIwHQYDVR0OBBYEFK8S
+4FdU0q0iiYKQtzGmwqn0CD2rMIHUBgNVHSMEgcwwgcmAFK8S4FdU0q0iiYKQtzGm
+wqn0CD2roYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
+ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM
+IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu
+aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P
+BAQDAgPoMAwGA1UdEwEB/wQCMAAwKwYDVR0RBCQwIqAgBgorBgEEAYI3FAIDoBIM
+EHVzZXJAa3JidGVzdC5jb20wEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG9w0B
+AQsFAAOCAQEAceeR7lFXkEEjcMGK/mvNOT5zXcq27ipYuV5HBgGGNLqiawc7NTxF
+ocyZf9HujNOMvBNblTml2GJQ9wmyQesVTGgJFTGORS2sFizICq19jISxrv44cdeF
+X/KQxNmnviClkL9jfA/6oKU0uSpvUAUet3MmDuo8O7ebVXVEmQdvLrhP9ycHGq8u
+qG+5qjN4dpf/ejtCCMGGZdUdPxPosoXJzf17hpyt8/YQohKG2igLSy1O68tuHTXb
+L4yiB52JQdnJfOU1a+vUSk425zMI00MU1aLcDxcjI64kxYBpWflDqn9Ky0N6vA1i
+OoBZgRFeQSELxUp7SUsK4xO2gPM2w0zzvQ==
+-----END CERTIFICATE-----
diff --git a/src/tests/dejagnu/pkinit-certs/user-upn2.p12 b/src/tests/dejagnu/pkinit-certs/user-upn2.p12
new file mode 100644
index 000000000000..8f4c6b2d05d1
--- /dev/null
+++ b/src/tests/dejagnu/pkinit-certs/user-upn2.p12
Binary files differ
diff --git a/src/tests/dejagnu/pkinit-certs/user-upn2.pem b/src/tests/dejagnu/pkinit-certs/user-upn2.pem
new file mode 100644
index 000000000000..37e123adec83
--- /dev/null
+++ b/src/tests/dejagnu/pkinit-certs/user-upn2.pem
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIEuTCCA6GgAwIBAgIBBTANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
+A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
+dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
+b3RoZXJ3aXNlMB4XDTE3MDgyNTE4MzIxMVoXDTI4MDgwNzE4MzIxMVowSjELMAkG
+A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
+U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvwcVP/5SJr9NxIUgkl3tntkW8w5guESQLKpGFbWCAOnTGsgCiH9/LGri
+oh1Lx/sC6t/f2TPJL020MPaycrB+gtpmm6chc0sK6OuWup2Eqxl22XxpguaMiFMu
+7ius3lZkhFBQtuQuK6pzpkU6M5nGRHQ2QL8LJ9BMk7lrZNoyvB4uzCZjSTkqUCh6
++myH4s9ewsLrqyqBi5YMPxzVn0aUjx1bZptE+35ZQqyQSAepgmsKSO88hmBLtQMD
+OlQ4JeikMOv+pD12cBjO33yv+kLHrbX/ZHgm21lt2xdANtBoeFXr2ImoAKpkHSUv
+Io4prhjZTnPLf763ql3egaVYKv3oPQIDAQABo4IBSjCCAUYwHQYDVR0OBBYEFK8S
+4FdU0q0iiYKQtzGmwqn0CD2rMIHUBgNVHSMEgcwwgcmAFK8S4FdU0q0iiYKQtzGm
+wqn0CD2roYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
+ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM
+IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu
+aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P
+BAQDAgPoMAwGA1UdEwEB/wQCMAAwHwYDVR0RBBgwFqAUBgorBgEEAYI3FAIDoAYM
+BHVzZXIwEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG9w0BAQsFAAOCAQEAkYoU
+bTCe61BRrB1yw8mIpnXlRrVLV91M8YEr07Jzk4qGfRLXbWf9BnMpxzbU4YVzEifh
+w6+gYSWGjgq4kDmp6tcY3IDGvzXkglKMAZv2mpFnBa6ZooEQ96tgg9O9G5Lg8Sv0
+kSkoySJq03xapucEZbhPrtGNHKwB/EDo3T0Iaby+Go9bqkObNfuIFXRXC6HqPBS4
+khss6cJ+daEE3Yg21QZ1BUlncwYbkCzt+xp3YaHlY41gdaMdF0tn6iRJjANAM2Kg
+6J45M4GKKT3yo5hJAWIS4lSCZX92g/uiT7BcBhE+vDzi3JuEc1QKajgnza1BMZMG
+EEIPWkC+Lfg8scWS5g==
+-----END CERTIFICATE-----
diff --git a/src/tests/dejagnu/pkinit-certs/user-upn3.p12 b/src/tests/dejagnu/pkinit-certs/user-upn3.p12
new file mode 100644
index 000000000000..da888f519d91
--- /dev/null
+++ b/src/tests/dejagnu/pkinit-certs/user-upn3.p12
Binary files differ
diff --git a/src/tests/dejagnu/pkinit-certs/user-upn3.pem b/src/tests/dejagnu/pkinit-certs/user-upn3.pem
new file mode 100644
index 000000000000..754114f5da3e
--- /dev/null
+++ b/src/tests/dejagnu/pkinit-certs/user-upn3.pem
@@ -0,0 +1,28 @@
+-----BEGIN CERTIFICATE-----
+MIIExTCCA62gAwIBAgIBBjANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
+A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
+dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
+b3RoZXJ3aXNlMB4XDTE3MDgyNTE4MzIxMVoXDTI4MDgwNzE4MzIxMVowSjELMAkG
+A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
+U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvwcVP/5SJr9NxIUgkl3tntkW8w5guESQLKpGFbWCAOnTGsgCiH9/LGri
+oh1Lx/sC6t/f2TPJL020MPaycrB+gtpmm6chc0sK6OuWup2Eqxl22XxpguaMiFMu
+7ius3lZkhFBQtuQuK6pzpkU6M5nGRHQ2QL8LJ9BMk7lrZNoyvB4uzCZjSTkqUCh6
++myH4s9ewsLrqyqBi5YMPxzVn0aUjx1bZptE+35ZQqyQSAepgmsKSO88hmBLtQMD
+OlQ4JeikMOv+pD12cBjO33yv+kLHrbX/ZHgm21lt2xdANtBoeFXr2ImoAKpkHSUv
+Io4prhjZTnPLf763ql3egaVYKv3oPQIDAQABo4IBVjCCAVIwHQYDVR0OBBYEFK8S
+4FdU0q0iiYKQtzGmwqn0CD2rMIHUBgNVHSMEgcwwgcmAFK8S4FdU0q0iiYKQtzGm
+wqn0CD2roYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
+ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM
+IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu
+aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P
+BAQDAgPoMAwGA1UdEwEB/wQCMAAwKwYDVR0RBCQwIqAgBgorBgEEAYI3FAIDoBIM
+EHVzZXJAS1JCVEVTVC5DT00wEgYDVR0lBAswCQYHKwYBBQIDBDANBgkqhkiG9w0B
+AQsFAAOCAQEAurL26+vQNYFbJNAFJ3yHOt1nwAVO4/OlCtgqzOAq0nBs35HY10Qe
+y8eRcxrLmm4O/Wy+Rwre2v3pIP0AclvIytDzEm6K3Pgj4yJfUUM3VhnSOlXQP6UG
+D9Z9pVxNiDeykj5/SzxwOQAmJbPcMx9aRwP9wOLMwUxi5sKHQlL9YUTC1hffhuYY
+Yccc2dHWd5IyaKaLp9yBVXQryNdVTBYrGA2ZqcwETmcXqU/wCo/Rmf10Ra1sj88X
+VfTb4Sr0j9RaSKeXRZgbEu6kz9i2WK70dcDke08xRv4xVfrlbXrfIS+Va9WYKxrf
+Xb0XCkKp32Q0EHqapeJrCcuQtnDMGvncTQ==
+-----END CERTIFICATE-----
diff --git a/src/tests/dejagnu/pkinit-certs/user.p12 b/src/tests/dejagnu/pkinit-certs/user.p12
index a7c2baddf67f..e9c044c5b1d0 100644
--- a/src/tests/dejagnu/pkinit-certs/user.p12
+++ b/src/tests/dejagnu/pkinit-certs/user.p12
Binary files differ
diff --git a/src/tests/dejagnu/pkinit-certs/user.pem b/src/tests/dejagnu/pkinit-certs/user.pem
index e6beefcde771..5b2853bc83d1 100644
--- a/src/tests/dejagnu/pkinit-certs/user.pem
+++ b/src/tests/dejagnu/pkinit-certs/user.pem
@@ -1,32 +1,28 @@
-----BEGIN CERTIFICATE-----
-MIIFkjCCBHqgAwIBAgIIYo5oQQ6iySowDQYJKoZIhvcNAQEFBQAwgacxCzAJBgNV
-BAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNldHRzMRIwEAYDVQQHEwlDYW1icmlk
-Z2UxDDAKBgNVBAoTA01JVDEpMCcGA1UECxMgSW5zZWN1cmUgUGtpbml0IEtlcmJl
-cm9zIHRlc3QgQ0ExMzAxBgNVBAMUKnBraW5pdCB0ZXN0IHN1aXRlIENBOyBkbyBu
-b3QgdXNlIG90aGVyd2lzZTAeFw0xMzAxMTcxODU5MDVaFw0yMzEyMzExODU5MDVa
-MIGhMQswCQYDVQQGEwJVUzEWMBQGA1UECBMNTWFzc2FjaHVzZXR0czESMBAGA1UE
-BxMJQ2FtYnJpZGdlMQwwCgYDVQQKEwNNSVQxKTAnBgNVBAsTIEluc2VjdXJlIFBr
-aW5pdCBLZXJiZXJvcyB0ZXN0IENBMS0wKwYDVQQDFCRwa2luaXQgdGVzdCBzdWl0
-ZSBjbGllbnQ7IGRvIG5vdCB1c2UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQCdgsx7nyfLTQyCyQk/u1nc8hBGlCRcYslkojQd+e0JFsi6+adl6M9Ip00z
-J6PNEjKN3DUUMlQCeldhyJzdMPnzXsbkfrdSuWUAa7L6WFBY3MTpzoq556t69Hek
-xqodeidp+VVqxS7l7YABZWcVvPjHTi4uVB6Oo/CbmxHXFN4tSdV9Jjvk1tcYgTjz
-yINXTBbyeoahVaf9OxF37sq5BQiQmm3z5XomTqE8hw+p7qHuZc0ayBzl0FKoHBVy
-NT0Nt5PjHHESaBB0u3up03BXVk8tCdNCmiA2tPm5/ehJs5OzIzTYY5auIhGayqrz
-Wx8yum+JNFEPCipNQSGgJKivRSZzAgMBAAGjggHEMIIBwDAdBgNVHQ4EFgQUWfzZ
-FQqBO+QWfRyDDIJCk15YLFgwgdwGA1UdIwSB1DCB0YAUWfzZFQqBO+QWfRyDDIJC
-k15YLFihga2kgaowgacxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl
-dHRzMRIwEAYDVQQHEwlDYW1icmlkZ2UxDDAKBgNVBAoTA01JVDEpMCcGA1UECxMg
-SW5zZWN1cmUgUGtpbml0IEtlcmJlcm9zIHRlc3QgQ0ExMzAxBgNVBAMUKnBraW5p
-dCB0ZXN0IHN1aXRlIENBOyBkbyBub3QgdXNlIG90aGVyd2lzZYIJANsFDWp1HgAa
-MA4GA1UdDwEB/wQEAwIE8DB9BgNVHREEdjB0oC4GBisGAQUCAqAkMCKgDRsLS1JC
-VEVTVC5DT02hETAPoAMCAQGhCDAGGwR1c2VyoCAGCisGAQQBgjcUAgOgEgwQdXNl
-ckBrcmJ0ZXN0LmNvbaAgBgorBgEEAYI3FAIDoBIMEHVzZXJAS1JCVEVTVC5DT00w
-JgYDVR0lBB8wHQYHKwYBBQIDBAYIKwYBBQUHAwQGCCsGAQUFBwMCMAkGA1UdEwQC
-MAAwDQYJKoZIhvcNAQEFBQADggEBAJZ+5CMbEj9anyH/b/jxUT8yGgYB3KGj7qL+
-RdU2zjgsQUMSdnlqQzpuEcY3z1wK94dYQVsPaYBv+zHl0rXFMfKlm97nVdCJi0ep
-vplNAaUlhkma3D8rkPN5LmIdHslpJD6pwbV+o69aCEsrwm38flmEnBX0OUynULod
-icDvxOxhmYG2kXmUmF7wZXI+XWX8b/TloDNLAnYfjKytMa3SQdp6wtj76BCk+ZZQ
-GAF3D0BS36lkNQ/8buHFhVv/tC/rFvql8DRbFzk6W02Ymq2OhcP0uz67rFZ2KjZ5
-Z0WP1REC8Cv7yoqOKPk8S+1FK+8RdKHjT1n/n+Mws72F72bxQWQ=
+MIIE0zCCA7ugAwIBAgIBAzANBgkqhkiG9w0BAQsFADCBpzELMAkGA1UEBhMCVVMx
+FjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxEjAQBgNVBAcMCUNhbWJyaWRnZTEMMAoG
+A1UECgwDTUlUMSkwJwYDVQQLDCBJbnNlY3VyZSBQS0lOSVQgS2VyYmVyb3MgdGVz
+dCBDQTEzMDEGA1UEAwwqcGtpbml0IHRlc3Qgc3VpdGUgQ0E7IGRvIG5vdCB1c2Ug
+b3RoZXJ3aXNlMB4XDTE3MDgyNTE4MzIxMVoXDTI4MDgwNzE4MzIxMVowSjELMAkG
+A1UEBhMCVVMxFjAUBgNVBAgMDU1hc3NhY2h1c2V0dHMxFDASBgNVBAoMC0tSQlRF
+U1QuQ09NMQ0wCwYDVQQDDAR1c2VyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAvwcVP/5SJr9NxIUgkl3tntkW8w5guESQLKpGFbWCAOnTGsgCiH9/LGri
+oh1Lx/sC6t/f2TPJL020MPaycrB+gtpmm6chc0sK6OuWup2Eqxl22XxpguaMiFMu
+7ius3lZkhFBQtuQuK6pzpkU6M5nGRHQ2QL8LJ9BMk7lrZNoyvB4uzCZjSTkqUCh6
++myH4s9ewsLrqyqBi5YMPxzVn0aUjx1bZptE+35ZQqyQSAepgmsKSO88hmBLtQMD
+OlQ4JeikMOv+pD12cBjO33yv+kLHrbX/ZHgm21lt2xdANtBoeFXr2ImoAKpkHSUv
+Io4prhjZTnPLf763ql3egaVYKv3oPQIDAQABo4IBZDCCAWAwHQYDVR0OBBYEFK8S
+4FdU0q0iiYKQtzGmwqn0CD2rMIHUBgNVHSMEgcwwgcmAFK8S4FdU0q0iiYKQtzGm
+wqn0CD2roYGtpIGqMIGnMQswCQYDVQQGEwJVUzEWMBQGA1UECAwNTWFzc2FjaHVz
+ZXR0czESMBAGA1UEBwwJQ2FtYnJpZGdlMQwwCgYDVQQKDANNSVQxKTAnBgNVBAsM
+IEluc2VjdXJlIFBLSU5JVCBLZXJiZXJvcyB0ZXN0IENBMTMwMQYDVQQDDCpwa2lu
+aXQgdGVzdCBzdWl0ZSBDQTsgZG8gbm90IHVzZSBvdGhlcndpc2WCAQEwCwYDVR0P
+BAQDAgPoMAwGA1UdEwEB/wQCMAAwOQYDVR0RBDIwMKAuBgYrBgEFAgKgJDAioA0b
+C0tSQlRFU1QuQ09NoREwD6ADAgEBoQgwBhsEdXNlcjASBgNVHSUECzAJBgcrBgEF
+AgMEMA0GCSqGSIb3DQEBCwUAA4IBAQClwfj6ACfmDie1YoKzr3zSWZJKZimv7wG1
+iZMNPE6bw22ZmE+P+Vq6WrY5M5e4u7ZdvFmkVq3rUA0HoU6bk3YLGapgsEAG6W1R
+LVzxwoYDf4poOMqjCL34eLFdlVeRDADiulROE8bJGrPLJIiqeii0c7Kzxxuh5nxl
+QHDgNV0fHQQJlejgJssOqgGErsCXCq7k6kkqB8MnKVMErRjsYuY3YI2tpjxBq9nA
+A9dXgIU1zEUVzfpxzBjL9+2pMctbL1y4/ePpTP1+PlfI81TwrQNvMGYjxKNZM1ab
+lZt37n8GQUZQyZ2TacR4JyY+w20ivE/JPN0L3Ncmem6bO1CULpwO
-----END CERTIFICATE-----
diff --git a/src/tests/deps b/src/tests/deps
index 751805061c14..a7f1515bd795 100644
--- a/src/tests/deps
+++ b/src/tests/deps
@@ -80,8 +80,20 @@ $(OUTPRE)hrealm.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
$(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
$(top_srcdir)/include/socket-utils.h hrealm.c
-$(OUTPRE)icred.$(OBJEXT): $(BUILDTOP)/include/krb5/krb5.h \
- $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h icred.c
+$(OUTPRE)icinterleave.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h icinterleave.c
+$(OUTPRE)icred.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/krb5.h \
+ icred.c
$(OUTPRE)kdbtest.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
$(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \
$(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \
diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in
index 6c146429793d..604f926dec45 100644
--- a/src/tests/gssapi/Makefile.in
+++ b/src/tests/gssapi/Makefile.in
@@ -15,15 +15,16 @@ SRCS= $(srcdir)/ccinit.c $(srcdir)/ccrefresh.c $(srcdir)/common.c \
$(srcdir)/t_gssexts.c $(srcdir)/t_imp_cred.c $(srcdir)/t_imp_name.c \
$(srcdir)/t_invalid.c $(srcdir)/t_inq_cred.c $(srcdir)/t_inq_ctx.c \
$(srcdir)/t_inq_mechs_name.c $(srcdir)/t_iov.c \
- $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c $(srcdir)/t_pcontok.c \
- $(srcdir)/t_prf.c $(srcdir)/t_s4u.c $(srcdir)/t_s4u2proxy_krb5.c \
- $(srcdir)/t_saslname.c $(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c
+ $(srcdir)/t_lifetime.c $(srcdir)/t_namingexts.c $(srcdir)/t_oid.c \
+ $(srcdir)/t_pcontok.c $(srcdir)/t_prf.c $(srcdir)/t_s4u.c \
+ $(srcdir)/t_s4u2proxy_krb5.c $(srcdir)/t_saslname.c \
+ $(srcdir)/t_spnego.c $(srcdir)/t_srcattrs.c
OBJS= ccinit.o ccrefresh.o common.o t_accname.o t_ccselect.o t_ciflags.o \
t_credstore.o t_enctypes.o t_err.o t_export_cred.o t_export_name.o \
t_gssexts.o t_imp_cred.o t_imp_name.o t_invalid.o t_inq_cred.o \
- t_inq_ctx.o t_inq_mechs_name.o t_iov.o t_namingexts.o t_oid.o \
- t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \
+ t_inq_ctx.o t_inq_mechs_name.o t_iov.o t_lifetime.o t_namingexts.o \
+ t_oid.o t_pcontok.o t_prf.o t_s4u.o t_s4u2proxy_krb5.o t_saslname.o \
t_spnego.o t_srcattrs.o
COMMON_DEPS= common.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
@@ -31,9 +32,9 @@ COMMON_LIBS= common.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
all: ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore t_enctypes \
t_err t_export_cred t_export_name t_gssexts t_imp_cred t_imp_name \
- t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_namingexts \
- t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname t_spnego \
- t_srcattrs
+ t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov t_lifetime \
+ t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5 t_saslname \
+ t_spnego t_srcattrs
check-unix: t_oid
$(RUN_TEST) ./t_invalid
@@ -42,8 +43,8 @@ check-unix: t_oid
check-pytests: ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore \
t_enctypes t_err t_export_cred t_export_name t_imp_cred t_inq_cred \
- t_inq_ctx t_inq_mechs_name t_iov t_pcontok t_s4u t_s4u2proxy_krb5 \
- t_spnego t_srcattrs
+ t_inq_ctx t_inq_mechs_name t_iov t_lifetime t_pcontok t_s4u \
+ t_s4u2proxy_krb5 t_spnego t_srcattrs
$(RUNPYTEST) $(srcdir)/t_gssapi.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_ccselect.py $(PYTESTFLAGS)
$(RUNPYTEST) $(srcdir)/t_client_keytab.py $(PYTESTFLAGS)
@@ -88,6 +89,8 @@ t_inq_mechs_name: t_inq_mechs_name.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_inq_mechs_name.o $(COMMON_LIBS)
t_iov: t_iov.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_iov.o $(COMMON_LIBS)
+t_lifetime: t_lifetime.o $(COMMON_DEPS)
+ $(CC_LINK) -o $@ t_lifetime.o $(COMMON_LIBS)
t_namingexts: t_namingexts.o $(COMMON_DEPS)
$(CC_LINK) -o $@ t_namingexts.o $(COMMON_LIBS)
t_pcontok: t_pcontok.o $(COMMON_DEPS)
@@ -111,5 +114,5 @@ clean:
$(RM) ccinit ccrefresh t_accname t_ccselect t_ciflags t_credstore
$(RM) t_enctypes t_err t_export_cred t_export_name t_gssexts t_imp_cred
$(RM) t_imp_name t_invalid t_inq_cred t_inq_ctx t_inq_mechs_name t_iov
- $(RM) t_namingexts t_oid t_pcontok t_prf t_s4u t_s4u2proxy_krb5
- $(RM) t_saslname t_spnego t_srcattrs
+ $(RM) t_lifetime t_namingexts t_oid t_pcontok t_prf t_s4u
+ $(RM) t_s4u2proxy_krb5 t_saslname t_spnego t_srcattrs
diff --git a/src/tests/gssapi/deps b/src/tests/gssapi/deps
index be3cefbb456b..b784deb638d0 100644
--- a/src/tests/gssapi/deps
+++ b/src/tests/gssapi/deps
@@ -45,7 +45,8 @@ $(OUTPRE)t_enctypes.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
$(BUILDTOP)/include/gssapi/gssapi_krb5.h $(BUILDTOP)/include/krb5/krb5.h \
$(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
- $(COM_ERR_DEPS) $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
+ $(COM_ERR_DEPS) $(srcdir)/../../lib/gssapi/generic/gssapi_ext.h \
+ $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
$(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
$(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
$(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
@@ -113,6 +114,10 @@ $(OUTPRE)t_iov.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
$(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
$(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
common.h t_iov.c
+$(OUTPRE)t_lifetime.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
+ $(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
+ common.h t_lifetime.c
$(OUTPRE)t_namingexts.$(OBJEXT): $(BUILDTOP)/include/gssapi/gssapi.h \
$(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssapi/gssapi_krb5.h \
$(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(top_srcdir)/include/krb5.h \
diff --git a/src/tests/gssapi/t_authind.py b/src/tests/gssapi/t_authind.py
index 316bc4093801..84793beb623f 100644
--- a/src/tests/gssapi/t_authind.py
+++ b/src/tests/gssapi/t_authind.py
@@ -24,9 +24,8 @@ if ('Attribute auth-indicators Authenticated Complete') not in out:
if '73757065727374726f6e67' not in out:
fail('Expected auth indicator not seen in name attributes')
-out = realm.run(['./t_srcattrs', 'p:service/2'], expected_code=1)
-if 'gss_init_sec_context: KDC policy rejects request' not in out:
- fail('Expected error message not seen for indicator mismatch')
+msg = 'gss_init_sec_context: KDC policy rejects request'
+realm.run(['./t_srcattrs', 'p:service/2'], expected_code=1, expected_msg=msg)
realm.kinit(realm.user_princ, password('user'), ['-X', 'indicators=one two'])
out = realm.run(['./t_srcattrs', 'p:service/2'])
@@ -35,4 +34,19 @@ if '6f6e65' not in out or '74776f' not in out:
fail('Expected auth indicator not seen in name attributes')
realm.stop()
+
+# Test the FAST encrypted challenge auth indicator.
+kdcconf = {'realms': {'$realm': {'encrypted_challenge_indicator': 'fast'}}}
+realm = K5Realm(kdc_conf=kdcconf)
+realm.run([kadminl, 'modprinc', '+requires_preauth', realm.user_princ])
+realm.run([kadminl, 'xst', realm.host_princ])
+realm.kinit(realm.user_princ, password('user'))
+realm.kinit(realm.user_princ, password('user'), ['-T', realm.ccache])
+out = realm.run(['./t_srcattrs', 'p:' + realm.host_princ])
+if ('Attribute auth-indicators Authenticated Complete') not in out:
+ fail('Expected attribute type not seen')
+if '66617374' not in out:
+ fail('Expected auth indicator not seen in name attributes')
+
+realm.stop()
success('GSSAPI auth indicator tests')
diff --git a/src/tests/gssapi/t_ccselect.py b/src/tests/gssapi/t_ccselect.py
index 6be6b4ec06c1..3503f92699b1 100755
--- a/src/tests/gssapi/t_ccselect.py
+++ b/src/tests/gssapi/t_ccselect.py
@@ -31,12 +31,20 @@ r2 = K5Realm(create_user=False, realm='KRBTEST2.COM', portbase=62000,
host1 = 'p:' + r1.host_princ
host2 = 'p:' + r2.host_princ
-
-# gsserver specifies the target as a GSS name. The resulting
-# principal will have the host-based type, but the realm won't be
-# known before the client cache is selected (since k5test realms have
-# no domain-realm mapping by default).
-gssserver = 'h:host@' + hostname
+foo = 'foo.krbtest.com'
+foo2 = 'foo.krbtest2.com'
+foobar = "foo.bar.krbtest.com"
+
+# These strings specify the target as a GSS name. The resulting
+# principal will have the host-based type, with the referral realm
+# (since k5test realms have no domain-realm mapping by default).
+# krb5_cc_select() will use the fallback realm, which is either the
+# uppercased parent domain, or the default realm if the hostname is a
+# single component.
+gssserver = 'h:host@' + foo
+gssserver2 = 'h:host@' + foo2
+gssserver_bar = 'h:host@' + foobar
+gsslocal = 'h:host@localhost'
# refserver specifies the target as a principal in the referral realm.
# The principal won't be treated as a host principal by the
@@ -45,9 +53,8 @@ refserver = 'p:host/' + hostname + '@'
# Verify that we can't get initiator creds with no credentials in the
# collection.
-output = r1.run(['./t_ccselect', host1, '-'], expected_code=1)
-if 'No Kerberos credentials available' not in output:
- fail('Expected error not seen in output when no credentials available')
+r1.run(['./t_ccselect', host1, '-'], expected_code=1,
+ expected_msg='No Kerberos credentials available')
# Make a directory collection and use it for client commands in both realms.
ccdir = os.path.join(r1.testdir, 'cc')
@@ -67,6 +74,18 @@ r1.addprinc(alice, password('alice'))
r1.addprinc(bob, password('bob'))
r2.addprinc(zaphod, password('zaphod'))
+# Create host principals and keytabs for fallback realm tests.
+r1.addprinc('host/localhost')
+r2.addprinc('host/localhost')
+r1.addprinc('host/' + foo)
+r2.addprinc('host/' + foo2)
+r1.addprinc('host/' + foobar)
+r1.extract_keytab('host/localhost', r1.keytab)
+r2.extract_keytab('host/localhost', r2.keytab)
+r1.extract_keytab('host/' + foo, r1.keytab)
+r2.extract_keytab('host/' + foo2, r2.keytab)
+r1.extract_keytab('host/' + foobar, r1.keytab)
+
# Get tickets for one user in each realm (zaphod will be primary).
r1.kinit(alice, password('alice'))
r2.kinit(zaphod, password('zaphod'))
@@ -94,10 +113,29 @@ if output != (zaphod + '\n'):
fail('zaphod not chosen as default initiator name for server in r1')
# Check that primary cache is used if server realm is unknown.
-output = r2.run(['./t_ccselect', gssserver])
+output = r2.run(['./t_ccselect', refserver])
if output != (zaphod + '\n'):
fail('zaphod not chosen via primary cache for unknown server realm')
-r1.run(['./t_ccselect', gssserver], expected_code=1)
+r1.run(['./t_ccselect', gssserver2], expected_code=1)
+# Check ccache selection using a fallback realm.
+output = r1.run(['./t_ccselect', gssserver])
+if output != (alice + '\n'):
+ fail('alice not chosen via parent domain fallback')
+output = r2.run(['./t_ccselect', gssserver2])
+if output != (zaphod + '\n'):
+ fail('zaphod not chosen via parent domain fallback')
+# Check ccache selection using a fallback realm (default realm).
+output = r1.run(['./t_ccselect', gsslocal])
+if output != (alice + '\n'):
+ fail('alice not chosen via default realm fallback')
+output = r2.run(['./t_ccselect', gsslocal])
+if output != (zaphod + '\n'):
+ fail('zaphod not chosen via default realm fallback')
+
+# Check that realm ccselect fallback works correctly
+r1.run(['./t_ccselect', gssserver_bar], expected_msg=alice)
+r2.kinit(zaphod, password('zaphod'))
+r1.run(['./t_ccselect', gssserver_bar], expected_msg=alice)
# Get a second cred in r1 (bob will be primary).
r1.kinit(bob, password('bob'))
@@ -105,20 +143,19 @@ r1.kinit(bob, password('bob'))
# Try some cache selections using .k5identity.
k5id = open(os.path.join(r1.testdir, '.k5identity'), 'w')
k5id.write('%s realm=%s\n' % (alice, r1.realm))
-k5id.write('%s service=ho*t host=%s\n' % (zaphod, hostname))
+k5id.write('%s service=ho*t host=localhost\n' % zaphod)
k5id.write('noprinc service=bogus')
k5id.close()
output = r1.run(['./t_ccselect', host1])
if output != (alice + '\n'):
fail('alice not chosen via .k5identity realm line.')
-output = r2.run(['./t_ccselect', gssserver])
+output = r2.run(['./t_ccselect', gsslocal])
if output != (zaphod + '\n'):
fail('zaphod not chosen via .k5identity service/host line.')
output = r1.run(['./t_ccselect', refserver])
if output != (bob + '\n'):
fail('bob not chosen via primary cache when no .k5identity line matches.')
-output = r1.run(['./t_ccselect', 'h:bogus@' + hostname], expected_code=1)
-if 'Can\'t find client principal noprinc' not in output:
- fail('Expected error not seen when k5identity selects bad principal.')
+r1.run(['./t_ccselect', 'h:bogus@' + foo2], expected_code=1,
+ expected_msg="Can't find client principal noprinc")
success('GSSAPI credential selection tests')
diff --git a/src/tests/gssapi/t_client_keytab.py b/src/tests/gssapi/t_client_keytab.py
index 4c8747a506c1..2da87f45b5b2 100755
--- a/src/tests/gssapi/t_client_keytab.py
+++ b/src/tests/gssapi/t_client_keytab.py
@@ -15,9 +15,7 @@ realm.extract_keytab(realm.user_princ, realm.client_keytab)
realm.extract_keytab(bob, realm.client_keytab)
# Test 1: no name/cache specified, pick first principal from client keytab
-out = realm.run(['./t_ccselect', phost])
-if realm.user_princ not in out:
- fail('Authenticated as wrong principal')
+realm.run(['./t_ccselect', phost], expected_msg=realm.user_princ)
realm.run([kdestroy])
# Test 2: no name/cache specified, pick principal from k5identity
@@ -25,36 +23,27 @@ k5idname = os.path.join(realm.testdir, '.k5identity')
k5id = open(k5idname, 'w')
k5id.write('%s service=host host=%s\n' % (bob, hostname))
k5id.close()
-out = realm.run(['./t_ccselect', gssserver])
-if bob not in out:
- fail('Authenticated as wrong principal')
+realm.run(['./t_ccselect', gssserver], expected_msg=bob)
os.remove(k5idname)
realm.run([kdestroy])
# Test 3: no name/cache specified, default ccache has name but no creds
realm.run(['./ccinit', realm.ccache, bob])
-out = realm.run(['./t_ccselect', phost])
-if bob not in out:
- fail('Authenticated as wrong principal')
+realm.run(['./t_ccselect', phost], expected_msg=bob)
# Leave tickets for next test.
# Test 4: name specified, non-collectable default cache doesn't match
-out = realm.run(['./t_ccselect', phost, puser], expected_code=1)
-if 'Principal in credential cache does not match desired name' not in out:
- fail('Expected error not seen')
+msg = 'Principal in credential cache does not match desired name'
+realm.run(['./t_ccselect', phost, puser], expected_code=1, expected_msg=msg)
realm.run([kdestroy])
# Test 5: name specified, nonexistent default cache
-out = realm.run(['./t_ccselect', phost, pbob])
-if bob not in out:
- fail('Authenticated as wrong principal')
+realm.run(['./t_ccselect', phost, pbob], expected_msg=bob)
# Leave tickets for next test.
# Test 6: name specified, matches default cache, time to refresh
realm.run(['./ccrefresh', realm.ccache, '1'])
-out = realm.run(['./t_ccselect', phost, pbob])
-if bob not in out:
- fail('Authenticated as wrong principal')
+realm.run(['./t_ccselect', phost, pbob], expected_msg=bob)
out = realm.run(['./ccrefresh', realm.ccache])
if int(out) < 1000:
fail('Credentials apparently not refreshed')
@@ -67,9 +56,8 @@ realm.run([kdestroy])
# Test 8: ccache specified with name but no creds; name not in client keytab
realm.run(['./ccinit', realm.ccache, realm.host_princ])
-out = realm.run(['./t_imp_cred', phost], expected_code=1)
-if 'Credential cache is empty' not in out:
- fail('Expected error not seen')
+realm.run(['./t_imp_cred', phost], expected_code=1,
+ expected_msg='Credential cache is empty')
realm.run([kdestroy])
# Test 9: ccache specified with name but no creds; name in client keytab
@@ -104,16 +92,12 @@ realm.env['KRB5CCNAME'] = ccname
# Test 12: name specified, matching cache in collection with no creds
bobcache = os.path.join(ccdir, 'tktbob')
realm.run(['./ccinit', bobcache, bob])
-out = realm.run(['./t_ccselect', phost, pbob])
-if bob not in out:
- fail('Authenticated as wrong principal')
+realm.run(['./t_ccselect', phost, pbob], expected_msg=bob)
# Leave tickets for next test.
# Test 13: name specified, matching cache in collection, time to refresh
realm.run(['./ccrefresh', bobcache, '1'])
-out = realm.run(['./t_ccselect', phost, pbob])
-if bob not in out:
- fail('Authenticated as wrong principal')
+realm.run(['./t_ccselect', phost, pbob], expected_msg=bob)
out = realm.run(['./ccrefresh', bobcache])
if int(out) < 1000:
fail('Credentials apparently not refreshed')
@@ -121,22 +105,15 @@ realm.run([kdestroy, '-A'])
# Test 14: name specified, collection has default for different principal
realm.kinit(realm.user_princ, password('user'))
-out = realm.run(['./t_ccselect', phost, pbob])
-if bob not in out:
- fail('Authenticated as wrong principal')
-out = realm.run([klist])
-if 'Default principal: %s\n' % realm.user_princ not in out:
- fail('Default cache overwritten by acquire_cred')
+realm.run(['./t_ccselect', phost, pbob], expected_msg=bob)
+msg = 'Default principal: %s\n' % realm.user_princ
+realm.run([klist], expected_msg=msg)
realm.run([kdestroy, '-A'])
# Test 15: name specified, collection has no default cache
-out = realm.run(['./t_ccselect', phost, pbob])
-if bob not in out:
- fail('Authenticated as wrong principal')
+realm.run(['./t_ccselect', phost, pbob], expected_msg=bob)
# Make sure the tickets we acquired didn't become the default
-out = realm.run([klist], expected_code=1)
-if 'No credentials cache found' not in out:
- fail('Expected error not seen')
+realm.run([klist], expected_code=1, expected_msg='No credentials cache found')
realm.run([kdestroy, '-A'])
# Test 16: default client keytab cannot be resolved, but valid
@@ -145,8 +122,7 @@ conf = {'libdefaults': {'default_client_keytab_name': '%{'}}
bad_cktname = realm.special_env('bad_cktname', False, krb5_conf=conf)
del bad_cktname['KRB5_CLIENT_KTNAME']
realm.kinit(realm.user_princ, password('user'))
-out = realm.run(['./t_ccselect', phost], env=bad_cktname)
-if realm.user_princ not in out:
- fail('Expected principal not seen for bad client keytab name')
+realm.run(['./t_ccselect', phost], env=bad_cktname,
+ expected_msg=realm.user_princ)
success('Client keytab tests')
diff --git a/src/tests/gssapi/t_enctypes.c b/src/tests/gssapi/t_enctypes.c
index a2ad18f47aba..3fd31e2f8cd5 100644
--- a/src/tests/gssapi/t_enctypes.c
+++ b/src/tests/gssapi/t_enctypes.c
@@ -32,6 +32,7 @@
#include "k5-int.h"
#include "common.h"
+#include "gssapi_ext.h"
/*
* This test program establishes contexts with the krb5 mech, the default
@@ -86,6 +87,9 @@ main(int argc, char *argv[])
gss_krb5_lucid_context_v1_t *ilucid, *alucid;
gss_krb5_rfc1964_keydata_t *i1964, *a1964;
gss_krb5_cfx_keydata_t *icfx, *acfx;
+ gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
+ gss_OID ssf_oid = GSS_C_SEC_CONTEXT_SASL_SSF;
+ unsigned int ssf;
size_t count;
void *lptr;
int c;
@@ -139,6 +143,16 @@ main(int argc, char *argv[])
establish_contexts(&mech_krb5, icred, acred, tname, flags, &ictx, &actx,
NULL, NULL, NULL);
+ /* Query the SSF value and range-check the result. */
+ major = gss_inquire_sec_context_by_oid(&minor, ictx, ssf_oid, &bufset);
+ check_gsserr("gss_inquire_sec_context_by_oid(ssf)", major, minor);
+ if (bufset->elements[0].length != 4)
+ errout("SSF buffer has unexpected length");
+ ssf = load_32_be(bufset->elements[0].value);
+ if (ssf < 56 || ssf > 256)
+ errout("SSF value not within acceptable range (56-256)");
+ (void)gss_release_buffer_set(&minor, &bufset);
+
/* Export to lucid contexts. */
major = gss_krb5_export_lucid_sec_context(&minor, &ictx, 1, &lptr);
check_gsserr("gss_export_lucid_sec_context(initiator)", major, minor);
diff --git a/src/tests/gssapi/t_enctypes.py b/src/tests/gssapi/t_enctypes.py
index 862f229895b2..f513db2b55cf 100755
--- a/src/tests/gssapi/t_enctypes.py
+++ b/src/tests/gssapi/t_enctypes.py
@@ -58,9 +58,7 @@ def test(msg, ienc, aenc, tktenc='', tktsession='', proto='', isubkey='',
# and check that it fails with the expected error message.
def test_err(msg, ienc, aenc, expected_err):
shutil.copyfile(os.path.join(realm.testdir, 'save'), realm.ccache)
- out = realm.run(cmdline(ienc, aenc), expected_code=1)
- if expected_err not in out:
- fail(msg)
+ realm.run(cmdline(ienc, aenc), expected_code=1, expected_msg=expected_err)
# By default, all of the key enctypes should be aes256.
diff --git a/src/tests/gssapi/t_export_cred.py b/src/tests/gssapi/t_export_cred.py
index 698835928901..b98962788b58 100755
--- a/src/tests/gssapi/t_export_cred.py
+++ b/src/tests/gssapi/t_export_cred.py
@@ -23,9 +23,7 @@ def ccache_restore(realm):
def check(realm, args):
ccache_restore(realm)
realm.run(['./t_export_cred'] + args)
- output = realm.run([klist, '-f'])
- if 'Flags: Ff' not in output:
- fail('Forwarded tickets not found in ccache after t_export_cred')
+ realm.run([klist, '-f'], expected_msg='Flags: Ff')
# Check a given set of arguments with no specified mech and with krb5
# and SPNEGO as the specified mech.
diff --git a/src/tests/gssapi/t_gssapi.py b/src/tests/gssapi/t_gssapi.py
index e23c936d7f44..6da5fceff3be 100755
--- a/src/tests/gssapi/t_gssapi.py
+++ b/src/tests/gssapi/t_gssapi.py
@@ -28,57 +28,40 @@ realm.run([kadminl, 'renprinc', 'service1/abraham', 'service1/andrew'])
# Test with no acceptor name, including client/keytab principal
# mismatch (non-fatal) and missing keytab entry (fatal).
-output = realm.run(['./t_accname', 'p:service1/andrew'])
-if 'service1/abraham' not in output:
- fail('Expected service1/abraham in t_accname output')
-output = realm.run(['./t_accname', 'p:service1/barack'])
-if 'service1/barack' not in output:
- fail('Expected service1/barack in t_accname output')
-output = realm.run(['./t_accname', 'p:service2/calvin'])
-if 'service2/calvin' not in output:
- fail('Expected service1/barack in t_accname output')
-output = realm.run(['./t_accname', 'p:service2/dwight'], expected_code=1)
-if ' not found in keytab' not in output:
- fail('Expected error message not seen in t_accname output')
+realm.run(['./t_accname', 'p:service1/andrew'],
+ expected_msg='service1/abraham')
+realm.run(['./t_accname', 'p:service1/barack'], expected_msg='service1/barack')
+realm.run(['./t_accname', 'p:service2/calvin'], expected_msg='service2/calvin')
+realm.run(['./t_accname', 'p:service2/dwight'], expected_code=1,
+ expected_msg=' not found in keytab')
# Test with acceptor name containing service only, including
# client/keytab hostname mismatch (non-fatal) and service name
# mismatch (fatal).
-output = realm.run(['./t_accname', 'p:service1/andrew', 'h:service1'])
-if 'service1/abraham' not in output:
- fail('Expected service1/abraham in t_accname output')
-output = realm.run(['./t_accname', 'p:service1/andrew', 'h:service2'],
- expected_code=1)
-if ' not found in keytab' not in output:
- fail('Expected error message not seen in t_accname output')
-output = realm.run(['./t_accname', 'p:service2/calvin', 'h:service2'])
-if 'service2/calvin' not in output:
- fail('Expected service2/calvin in t_accname output')
-output = realm.run(['./t_accname', 'p:service2/calvin', 'h:service1'],
- expected_code=1)
-if ' found in keytab but does not match server principal' not in output:
- fail('Expected error message not seen in t_accname output')
+realm.run(['./t_accname', 'p:service1/andrew', 'h:service1'],
+ expected_msg='service1/abraham')
+realm.run(['./t_accname', 'p:service1/andrew', 'h:service2'], expected_code=1,
+ expected_msg=' not found in keytab')
+realm.run(['./t_accname', 'p:service2/calvin', 'h:service2'],
+ expected_msg='service2/calvin')
+realm.run(['./t_accname', 'p:service2/calvin', 'h:service1'], expected_code=1,
+ expected_msg=' found in keytab but does not match server principal')
# Test with acceptor name containing service and host. Use the
# client's un-canonicalized hostname as acceptor input to mirror what
# many servers do.
-output = realm.run(['./t_accname', 'p:' + realm.host_princ,
- 'h:host@%s' % socket.gethostname()])
-if realm.host_princ not in output:
- fail('Expected %s in t_accname output' % realm.host_princ)
-output = realm.run(['./t_accname', 'p:host/-nomatch-',
- 'h:host@%s' % socket.gethostname()],
- expected_code=1)
-if ' not found in keytab' not in output:
- fail('Expected error message not seen in t_accname output')
+realm.run(['./t_accname', 'p:' + realm.host_princ,
+ 'h:host@%s' % socket.gethostname()], expected_msg=realm.host_princ)
+realm.run(['./t_accname', 'p:host/-nomatch-',
+ 'h:host@%s' % socket.gethostname()], expected_code=1,
+ expected_msg=' not found in keytab')
# Test krb5_gss_import_cred.
realm.run(['./t_imp_cred', 'p:service1/barack'])
realm.run(['./t_imp_cred', 'p:service1/barack', 'service1/barack'])
realm.run(['./t_imp_cred', 'p:service1/andrew', 'service1/abraham'])
-output = realm.run(['./t_imp_cred', 'p:service2/dwight'], expected_code=1)
-if ' not found in keytab' not in output:
- fail('Expected error message not seen in t_imp_cred output')
+realm.run(['./t_imp_cred', 'p:service2/dwight'], expected_code=1,
+ expected_msg=' not found in keytab')
# Test credential store extension.
tmpccname = 'FILE:' + os.path.join(realm.testdir, 'def_cache')
@@ -116,10 +99,8 @@ ignore_conf = {'libdefaults': {'ignore_acceptor_hostname': 'true'}}
realm = K5Realm(krb5_conf=ignore_conf)
realm.run([kadminl, 'addprinc', '-randkey', 'host/-nomatch-'])
realm.run([kadminl, 'xst', 'host/-nomatch-'])
-output = realm.run(['./t_accname', 'p:host/-nomatch-',
- 'h:host@%s' % socket.gethostname()])
-if 'host/-nomatch-' not in output:
- fail('Expected host/-nomatch- in t_accname output')
+realm.run(['./t_accname', 'p:host/-nomatch-',
+ 'h:host@%s' % socket.gethostname()], expected_msg='host/-nomatch-')
realm.stop()
@@ -141,41 +122,25 @@ r3.stop()
realm = K5Realm()
# Test deferred resolution of the default ccache for initiator creds.
-output = realm.run(['./t_inq_cred'])
-if realm.user_princ not in output:
- fail('Expected %s in t_inq_cred output' % realm.user_princ)
-output = realm.run(['./t_inq_cred', '-k'])
-if realm.user_princ not in output:
- fail('Expected %s in t_inq_cred output' % realm.user_princ)
-output = realm.run(['./t_inq_cred', '-s'])
-if realm.user_princ not in output:
- fail('Expected %s in t_inq_cred output' % realm.user_princ)
+realm.run(['./t_inq_cred'], expected_msg=realm.user_princ)
+realm.run(['./t_inq_cred', '-k'], expected_msg=realm.user_princ)
+realm.run(['./t_inq_cred', '-s'], expected_msg=realm.user_princ)
# Test picking a name from the keytab for acceptor creds.
-output = realm.run(['./t_inq_cred', '-a'])
-if realm.host_princ not in output:
- fail('Expected %s in t_inq_cred output' % realm.host_princ)
-output = realm.run(['./t_inq_cred', '-k', '-a'])
-if realm.host_princ not in output:
- fail('Expected %s in t_inq_cred output' % realm.host_princ)
-output = realm.run(['./t_inq_cred', '-s', '-a'])
-if realm.host_princ not in output:
- fail('Expected %s in t_inq_cred output' % realm.host_princ)
+realm.run(['./t_inq_cred', '-a'], expected_msg=realm.host_princ)
+realm.run(['./t_inq_cred', '-k', '-a'], expected_msg=realm.host_princ)
+realm.run(['./t_inq_cred', '-s', '-a'], expected_msg=realm.host_princ)
# Test client keytab initiation (non-deferred) with a specified name.
realm.extract_keytab(realm.user_princ, realm.client_keytab)
os.remove(realm.ccache)
-output = realm.run(['./t_inq_cred', '-k'])
-if realm.user_princ not in output:
- fail('Expected %s in t_inq_cred output' % realm.user_princ)
+realm.run(['./t_inq_cred', '-k'], expected_msg=realm.user_princ)
# Test deferred client keytab initiation and GSS_C_BOTH cred usage.
os.remove(realm.client_keytab)
os.remove(realm.ccache)
shutil.copyfile(realm.keytab, realm.client_keytab)
-output = realm.run(['./t_inq_cred', '-k', '-b'])
-if realm.host_princ not in output:
- fail('Expected %s in t_inq_cred output' % realm.host_princ)
+realm.run(['./t_inq_cred', '-k', '-b'], expected_msg=realm.host_princ)
# Test gss_export_name behavior.
out = realm.run(['./t_export_name', 'u:x'])
@@ -220,4 +185,37 @@ realm.run(['./t_ciflags', 'p:' + realm.host_princ])
# contexts.
realm.run(['./t_inq_ctx', 'user', password('user'), 'p:%s' % realm.host_princ])
+if runenv.sizeof_time_t <= 4:
+ skip_rest('y2038 GSSAPI tests', 'platform has 32-bit time_t')
+
+# Test lifetime results, using a realm with a large maximum lifetime
+# so that we can test ticket end dates after y2038.
+realm.stop()
+conf = {'realms': {'$realm': {'max_life': '9000d'}}}
+realm = K5Realm(kdc_conf=conf, get_creds=False)
+
+# Check a lifetime string result against an expected number value (or None).
+# Allow some variance due to time elapsed during the tests.
+def check_lifetime(msg, val, expected):
+ if expected is None and val != 'indefinite':
+ fail('%s: expected indefinite, got %s' % (msg, val))
+ if expected is not None and val == 'indefinite':
+ fail('%s: expected %d, got indefinite' % (msg, expected))
+ if expected is not None and abs(int(val) - expected) > 100:
+ fail('%s: expected %d, got %s' % (msg, expected, val))
+
+realm.kinit(realm.user_princ, password('user'), flags=['-l', '8500d'])
+out = realm.run(['./t_lifetime', 'p:' + realm.host_princ, str(8000 * 86400)])
+ln = out.split('\n')
+check_lifetime('icred gss_acquire_cred', ln[0], 8500 * 86400)
+check_lifetime('icred gss_inquire_cred', ln[1], 8500 * 86400)
+check_lifetime('acred gss_acquire_cred', ln[2], None)
+check_lifetime('acred gss_inquire_cred', ln[3], None)
+check_lifetime('ictx gss_init_sec_context', ln[4], 8000 * 86400)
+check_lifetime('ictx gss_inquire_context', ln[5], 8000 * 86400)
+check_lifetime('ictx gss_context_time', ln[6], 8000 * 86400)
+check_lifetime('actx gss_accept_sec_context', ln[7], 8000 * 86400 + 300)
+check_lifetime('actx gss_inquire_context', ln[8], 8000 * 86400 + 300)
+check_lifetime('actx gss_context_time', ln[9], 8000 * 86400 + 300)
+
success('GSSAPI tests')
diff --git a/src/tests/gssapi/t_invalid.c b/src/tests/gssapi/t_invalid.c
index 5c8ddac8dc84..2a332a8ae048 100644
--- a/src/tests/gssapi/t_invalid.c
+++ b/src/tests/gssapi/t_invalid.c
@@ -31,8 +31,8 @@
*/
/*
- * This file contains regression tests for some GSSAPI krb5 invalid per-message
- * token vulnerabilities.
+ * This file contains regression tests for some GSSAPI invalid token
+ * vulnerabilities.
*
* 1. A pre-CFX wrap or MIC token processed with a CFX-only context causes a
* null pointer dereference. (The token must use SEAL_ALG_NONE or it will
@@ -54,10 +54,13 @@
* causes an integer underflow when computing the original message length,
* leading to an allocation error.
*
+ * 5. In the mechglue, truncated encapsulation in the initial context token can
+ * cause input buffer overruns in gss_accept_sec_context().
+ *
* Vulnerabilities #1 and #2 also apply to IOV unwrap, although tokens with
- * fewer than 16 bytes after the ASN.1 header will be rejected. Vulnerability
- * #2 can only be robustly detected using a memory-checking environment such as
- * valgrind.
+ * fewer than 16 bytes after the ASN.1 header will be rejected.
+ * Vulnerabilities #2 and #5 can only be robustly detected using a
+ * memory-checking environment such as valgrind.
*/
#include "k5-int.h"
@@ -406,6 +409,48 @@ test_bad_pad(gss_ctx_id_t ctx, const struct test *test)
(void)gss_release_buffer(&minor, &out);
}
+static void
+try_accept(void *value, size_t len)
+{
+ OM_uint32 minor;
+ gss_buffer_desc in, out;
+ gss_ctx_id_t ctx = GSS_C_NO_CONTEXT;
+
+ /* Copy the provided value to make input overruns more obvious. */
+ in.value = malloc(len);
+ if (in.value == NULL)
+ abort();
+ memcpy(in.value, value, len);
+ in.length = len;
+ (void)gss_accept_sec_context(&minor, &ctx, GSS_C_NO_CREDENTIAL, &in,
+ GSS_C_NO_CHANNEL_BINDINGS, NULL, NULL,
+ &out, NULL, NULL, NULL);
+ gss_release_buffer(&minor, &out);
+ gss_delete_sec_context(&minor, &ctx, GSS_C_NO_BUFFER);
+ free(in.value);
+}
+
+/* Accept contexts using superficially valid but truncated encapsulations. */
+static void
+test_short_encapsulation()
+{
+ /* Include just the initial application tag, to see if we overrun reading
+ * the sequence length. */
+ try_accept("\x60", 1);
+
+ /* Indicate four additional sequence length bytes, to see if we overrun
+ * reading them (or skipping them and reading the next byte). */
+ try_accept("\x60\x84", 2);
+
+ /* Include an object identifier tag but no length, to see if we overrun
+ * reading the length. */
+ try_accept("\x60\x40\x06", 3);
+
+ /* Include an object identifier tag with a length matching the krb5 mech,
+ * but no OID bytes, to see if we overrun comparing against mechs. */
+ try_accept("\x60\x40\x06\x09", 4);
+}
+
int
main(int argc, char **argv)
{
@@ -425,5 +470,7 @@ main(int argc, char **argv)
free_fake_context(ctx);
}
+ test_short_encapsulation();
+
return 0;
}
diff --git a/src/tests/gssapi/t_lifetime.c b/src/tests/gssapi/t_lifetime.c
new file mode 100644
index 000000000000..8dcf18621bbf
--- /dev/null
+++ b/src/tests/gssapi/t_lifetime.c
@@ -0,0 +1,140 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* tests/gssapi/t_lifetime.c - display cred and context lifetimes */
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "common.h"
+
+/*
+ * Using the default credential, exercise the GSS functions which accept or
+ * produce lifetimes. Display the following results, one per line, as ASCII
+ * integers or the string "indefinite":
+ *
+ * initiator cred lifetime according to gss_acquire_cred()
+ * initiator cred lifetime according to gss_inquire_cred()
+ * acceptor cred lifetime according to gss_acquire_cred()
+ * acceptor cred lifetime according to gss_inquire_cred()
+ * initiator context lifetime according to gss_init_sec_context()
+ * initiator context lifetime according to gss_inquire_context()
+ * initiator context lifetime according to gss_context_time()
+ * acceptor context lifetime according to gss_init_sec_context()
+ * acceptor context lifetime according to gss_inquire_context()
+ * acceptor context lifetime according to gss_context_time()
+ */
+
+static void
+display_time(OM_uint32 tval)
+{
+ if (tval == GSS_C_INDEFINITE)
+ puts("indefinite");
+ else
+ printf("%u\n", (unsigned int)tval);
+}
+
+int
+main(int argc, char *argv[])
+{
+ OM_uint32 minor, major;
+ gss_cred_id_t icred, acred;
+ gss_name_t tname;
+ gss_ctx_id_t ictx = GSS_C_NO_CONTEXT, actx = GSS_C_NO_CONTEXT;
+ gss_buffer_desc itok = GSS_C_EMPTY_BUFFER, atok = GSS_C_EMPTY_BUFFER;
+ OM_uint32 time_req = GSS_C_INDEFINITE, time_rec;
+
+ if (argc < 2 || argc > 3) {
+ fprintf(stderr, "Usage: %s targetname [time_req]\n", argv[0]);
+ return 1;
+ }
+ tname = import_name(argv[1]);
+ if (argc >= 3)
+ time_req = atoll(argv[2]);
+
+ /* Get initiator cred and display its lifetime according to
+ * gss_acquire_cred and gss_inquire_cred. */
+ major = gss_acquire_cred(&minor, GSS_C_NO_NAME, time_req, &mechset_krb5,
+ GSS_C_INITIATE, &icred, NULL, &time_rec);
+ check_gsserr("gss_acquire_cred(initiate)", major, minor);
+ display_time(time_rec);
+ major = gss_inquire_cred(&minor, icred, NULL, &time_rec, NULL, NULL);
+ check_gsserr("gss_inquire_cred(initiate)", major, minor);
+ display_time(time_rec);
+
+ /* Get acceptor cred and display its lifetime according to gss_acquire_cred
+ * and gss_inquire_cred. */
+ major = gss_acquire_cred(&minor, GSS_C_NO_NAME, time_req, &mechset_krb5,
+ GSS_C_ACCEPT, &acred, NULL, &time_rec);
+ check_gsserr("gss_acquire_cred(accept)", major, minor);
+ display_time(time_rec);
+ major = gss_inquire_cred(&minor, acred, NULL, &time_rec, NULL, NULL);
+ check_gsserr("gss_inquire_cred(accept)", major, minor);
+ display_time(time_rec);
+
+ /* Make an initiator context and display its lifetime according to
+ * gss_init_sec_context, gss_inquire_context, and gss_context_time. */
+ major = gss_init_sec_context(&minor, icred, &ictx, tname, &mech_krb5, 0,
+ time_req, GSS_C_NO_CHANNEL_BINDINGS, &atok,
+ NULL, &itok, NULL, &time_rec);
+ check_gsserr("gss_init_sec_context", major, minor);
+ assert(major == GSS_S_COMPLETE);
+ display_time(time_rec);
+ major = gss_inquire_context(&minor, ictx, NULL, NULL, &time_rec, NULL,
+ NULL, NULL, NULL);
+ check_gsserr("gss_inquire_context(initiate)", major, minor);
+ display_time(time_rec);
+ major = gss_context_time(&minor, ictx, &time_rec);
+ check_gsserr("gss_context_time(initiate)", major, minor);
+ display_time(time_rec);
+
+ major = gss_accept_sec_context(&minor, &actx, acred, &itok,
+ GSS_C_NO_CHANNEL_BINDINGS, NULL,
+ NULL, &atok, NULL, &time_rec, NULL);
+ check_gsserr("gss_accept_sec_context", major, minor);
+ assert(major == GSS_S_COMPLETE);
+ display_time(time_rec);
+ major = gss_inquire_context(&minor, actx, NULL, NULL, &time_rec, NULL,
+ NULL, NULL, NULL);
+ check_gsserr("gss_inquire_context(accept)", major, minor);
+ display_time(time_rec);
+ major = gss_context_time(&minor, actx, &time_rec);
+ check_gsserr("gss_context_time(accept)", major, minor);
+ display_time(time_rec);
+
+ (void)gss_release_buffer(&minor, &itok);
+ (void)gss_release_buffer(&minor, &atok);
+ (void)gss_release_name(&minor, &tname);
+ (void)gss_release_cred(&minor, &icred);
+ (void)gss_release_cred(&minor, &acred);
+ (void)gss_delete_sec_context(&minor, &ictx, NULL);
+ (void)gss_delete_sec_context(&minor, &actx, NULL);
+ return 0;
+}
diff --git a/src/tests/gssapi/t_s4u.c b/src/tests/gssapi/t_s4u.c
index 5bc1e4470bdc..0400f8f61f41 100644
--- a/src/tests/gssapi/t_s4u.c
+++ b/src/tests/gssapi/t_s4u.c
@@ -242,6 +242,7 @@ main(int argc, char *argv[])
gss_cred_id_t delegated_cred_handle = GSS_C_NO_CREDENTIAL;
gss_name_t user = GSS_C_NO_NAME, target = GSS_C_NO_NAME;
gss_OID_set mechs;
+ gss_buffer_set_t bufset = GSS_C_NO_BUFFER_SET;
if (argc < 2 || argc > 5) {
fprintf(stderr, "Usage: %s [--spnego] [user] "
@@ -305,6 +306,25 @@ main(int argc, char *argv[])
fprintf(stderr, "\n");
}
+ if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
+ /* Inquire impersonator status. */
+ major = gss_inquire_cred_by_oid(&minor, user_cred_handle,
+ GSS_KRB5_GET_CRED_IMPERSONATOR,
+ &bufset);
+ check_gsserr("gss_inquire_cred_by_oid", major, minor);
+ if (bufset->count == 0)
+ errout("gss_inquire_cred_by_oid(user) returned NO impersonator");
+ (void)gss_release_buffer_set(&minor, &bufset);
+
+ major = gss_inquire_cred_by_oid(&minor, impersonator_cred_handle,
+ GSS_KRB5_GET_CRED_IMPERSONATOR,
+ &bufset);
+ check_gsserr("gss_inquire_cred_by_oid", major, minor);
+ if (bufset->count != 0)
+ errout("gss_inquire_cred_by_oid(svc) returned an impersonator");
+ (void)gss_release_buffer_set(&minor, &bufset);
+ }
+
(void)gss_release_name(&minor, &user);
(void)gss_release_name(&minor, &target);
(void)gss_release_cred(&minor, &delegated_cred_handle);
diff --git a/src/tests/gssapi/t_s4u.py b/src/tests/gssapi/t_s4u.py
index 7366e3915ee3..e4cd68469300 100755
--- a/src/tests/gssapi/t_s4u.py
+++ b/src/tests/gssapi/t_s4u.py
@@ -42,10 +42,8 @@ if ('auth1: ' + realm.user_princ not in output or
# result in no delegated credential being created by
# accept_sec_context.
realm.kinit(realm.user_princ, password('user'), ['-c', usercache])
-output = realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, pservice1,
- pservice1, pservice2])
-if 'no credential delegated' not in output:
- fail('krb5 -> no delegated cred')
+realm.run(['./t_s4u2proxy_krb5', usercache, storagecache, pservice1,
+ pservice1, pservice2], expected_msg='no credential delegated')
# Try S4U2Self. Ask for an S4U2Proxy step; this won't happen because
# service/1 isn't allowed to get a forwardable S4U2Self ticket.
@@ -61,17 +59,15 @@ if ('Warning: no delegated cred handle' not in output or
# Correct that problem and try again. As above, the S4U2Proxy step
# won't actually succeed since we don't support that in DB2.
realm.run([kadminl, 'modprinc', '+ok_to_auth_as_delegate', service1])
-output = realm.run(['./t_s4u', puser, pservice2], expected_code=1)
-if 'NOT_ALLOWED_TO_DELEGATE' not in output:
- fail('s4u2self')
+realm.run(['./t_s4u', puser, pservice2], expected_code=1,
+ expected_msg='NOT_ALLOWED_TO_DELEGATE')
# Again with SPNEGO. This uses SPNEGO for the initial authentication,
# but still uses krb5 for S4U2Proxy--the delegated cred is returned as
# a krb5 cred, not a SPNEGO cred, and t_s4u uses the delegated cred
# directly rather than saving and reacquiring it.
-output = realm.run(['./t_s4u', '--spnego', puser, pservice2], expected_code=1)
-if 'NOT_ALLOWED_TO_DELEGATE' not in output:
- fail('s4u2self')
+realm.run(['./t_s4u', '--spnego', puser, pservice2], expected_code=1,
+ expected_msg='NOT_ALLOWED_TO_DELEGATE')
realm.stop()
@@ -148,9 +144,8 @@ realm.stop()
# fail, but we can check that the right server principal was used.
r1, r2 = cross_realms(2, create_user=False)
r1.run([kinit, '-k', r1.host_princ])
-out = r1.run(['./t_s4u', 'p:' + r2.host_princ], expected_code=1)
-if 'Server not found in Kerberos database' not in out:
- fail('cross-realm s4u2self (t_s4u output)')
+r1.run(['./t_s4u', 'p:' + r2.host_princ], expected_code=1,
+ expected_msg='Server not found in Kerberos database')
r1.stop()
r2.stop()
with open(os.path.join(r2.testdir, 'kdc.log')) as f:
diff --git a/src/tests/hammer/kdc5_hammer.c b/src/tests/hammer/kdc5_hammer.c
index 0934f33fd340..efb4271e587c 100644
--- a/src/tests/hammer/kdc5_hammer.c
+++ b/src/tests/hammer/kdc5_hammer.c
@@ -436,12 +436,11 @@ int get_tgt (context, p_client_str, p_client, ccache)
{
char *cache_name = NULL; /* -f option */
long lifetime = KRB5_DEFAULT_LIFE; /* -l option */
- int options = KRB5_DEFAULT_OPTIONS;
krb5_error_code code;
krb5_creds my_creds;
krb5_timestamp start;
- krb5_principal tgt_server;
float dt;
+ krb5_get_init_creds_opt *options;
if (!brief)
fprintf(stderr, "\tgetting TGT for %s\n", p_client_str);
@@ -458,22 +457,6 @@ int get_tgt (context, p_client_str, p_client, ccache)
return(-1);
}
-
- if ((code = krb5_build_principal_ext(context, &tgt_server,
- krb5_princ_realm(context, *p_client)->length,
- krb5_princ_realm(context, *p_client)->data,
- tgtname.length,
- tgtname.data,
- krb5_princ_realm(context, *p_client)->length,
- krb5_princ_realm(context, *p_client)->data,
- 0))) {
- com_err(prog, code, "when setting up tgt principal");
- return(-1);
- }
-
- my_creds.client = *p_client;
- my_creds.server = tgt_server;
-
code = krb5_cc_initialize (context, ccache, *p_client);
if (code != 0) {
com_err (prog, code, "when initializing cache %s",
@@ -481,17 +464,26 @@ int get_tgt (context, p_client_str, p_client, ccache)
return(-1);
}
- my_creds.times.starttime = 0; /* start timer when request
- gets to KDC */
- my_creds.times.endtime = start + lifetime;
- my_creds.times.renew_till = 0;
-
if (do_timer)
swatch_on();
- code = krb5_get_in_tkt_with_password(context, options, 0,
- NULL, patype, p_client_str, ccache,
- &my_creds, 0);
+ code = krb5_get_init_creds_opt_alloc(context, &options);
+ if (code != 0) {
+ com_err(prog, code, "when allocating init cred options");
+ return(-1);
+ }
+
+ krb5_get_init_creds_opt_set_tkt_life(options, lifetime);
+
+ code = krb5_get_init_creds_opt_set_out_ccache(context, options, ccache);
+ if (code != 0) {
+ com_err(prog, code, "when setting init cred output ccache");
+ return(-1);
+ }
+
+ code = krb5_get_init_creds_password(context, &my_creds, *p_client,
+ p_client_str, NULL, NULL, 0, NULL,
+ options);
if (do_timer) {
dt = swatch_eltime();
in_tkt_times.ht_cumulative += dt;
@@ -501,8 +493,7 @@ int get_tgt (context, p_client_str, p_client, ccache)
if (dt < in_tkt_times.ht_min)
in_tkt_times.ht_min = dt;
}
- my_creds.server = my_creds.client = 0;
- krb5_free_principal(context, tgt_server);
+ krb5_get_init_creds_opt_free(context, options);
krb5_free_cred_contents(context, &my_creds);
if (code != 0) {
com_err (prog, code, "while getting initial credentials");
diff --git a/src/tests/icinterleave.c b/src/tests/icinterleave.c
new file mode 100644
index 000000000000..a1bdd3547f08
--- /dev/null
+++ b/src/tests/icinterleave.c
@@ -0,0 +1,128 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* tests/icinterleave.c - interleaved init_creds_step test harness */
+/*
+ * Copyright (C) 2017 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 test harness performs multiple initial creds operations using
+ * krb5_init_creds_step(), interleaving the operations to test the scoping of
+ * the preauth state. All principals must have the same password (or not
+ * require a password).
+ */
+
+#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);
+ }
+}
+
+int
+main(int argc, char **argv)
+{
+ const char *password;
+ char **princstrs;
+ krb5_principal client;
+ krb5_init_creds_context *iccs;
+ krb5_data req, *reps, realm;
+ krb5_boolean any_left;
+ int i, nclients, master;
+ unsigned int flags;
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: icinterleave password princ1 princ2 ...\n");
+ exit(1);
+ }
+ password = argv[1];
+ princstrs = argv + 2;
+ nclients = argc - 2;
+
+ check(krb5_init_context(&ctx));
+
+ /* Create an initial creds context for each client principal. */
+ iccs = calloc(nclients, sizeof(*iccs));
+ assert(iccs != NULL);
+ for (i = 0; i < nclients; i++) {
+ check(krb5_parse_name(ctx, princstrs[i], &client));
+ check(krb5_init_creds_init(ctx, client, NULL, NULL, 0, NULL,
+ &iccs[i]));
+ check(krb5_init_creds_set_password(ctx, iccs[i], password));
+ krb5_free_principal(ctx, client);
+ }
+
+ reps = calloc(nclients, sizeof(*reps));
+ assert(reps != NULL);
+
+ any_left = TRUE;
+ while (any_left) {
+ any_left = FALSE;
+ for (i = 0; i < nclients; i++) {
+ if (iccs[i] == NULL)
+ continue;
+ any_left = TRUE;
+
+ printf("step %d\n", i + 1);
+
+ req = empty_data();
+ realm = empty_data();
+ check(krb5_init_creds_step(ctx, iccs[i], &reps[i], &req, &realm,
+ &flags));
+ if (!(flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE)) {
+ printf("finish %d\n", i + 1);
+ krb5_init_creds_free(ctx, iccs[i]);
+ iccs[i] = NULL;
+ continue;
+ }
+
+ master = 0;
+ krb5_free_data_contents(ctx, &reps[i]);
+ check(krb5_sendto_kdc(ctx, &req, &realm, &reps[i], &master, 0));
+ krb5_free_data_contents(ctx, &req);
+ krb5_free_data_contents(ctx, &realm);
+ }
+ }
+
+ for (i = 0; i < nclients; i++)
+ krb5_free_data_contents(ctx, &reps[i]);
+ free(reps);
+ free(iccs);
+ krb5_free_context(ctx);
+ return 0;
+}
diff --git a/src/tests/icred.c b/src/tests/icred.c
index 071f91c80219..55f929cd7e77 100644
--- a/src/tests/icred.c
+++ b/src/tests/icred.c
@@ -35,8 +35,8 @@
* it is very simplistic, but it can be extended as needed.
*/
+#include "k5-platform.h"
#include <krb5.h>
-#include <stdio.h>
static krb5_context ctx;
@@ -59,29 +59,64 @@ main(int argc, char **argv)
const char *princstr, *password;
krb5_principal client;
krb5_init_creds_context icc;
+ krb5_get_init_creds_opt *opt;
krb5_creds creds;
+ krb5_boolean stepwise = FALSE;
+ krb5_preauthtype ptypes[64];
+ int c, nptypes = 0;
+ char *val;
- if (argc != 3) {
- fprintf(stderr, "Usage: icred princname password\n");
- exit(1);
+ check(krb5_init_context(&ctx));
+ check(krb5_get_init_creds_opt_alloc(ctx, &opt));
+
+ while ((c = getopt(argc, argv, "so:X:")) != -1) {
+ switch (c) {
+ case 's':
+ stepwise = TRUE;
+ break;
+ case 'o':
+ assert(nptypes < 64);
+ ptypes[nptypes++] = atoi(optarg);
+ break;
+ case 'X':
+ val = strchr(optarg, '=');
+ if (val != NULL)
+ *val++ = '\0';
+ else
+ val = "yes";
+ check(krb5_get_init_creds_opt_set_pa(ctx, opt, optarg, val));
+ break;
+ default:
+ abort();
+ }
}
- princstr = argv[1];
- password = argv[2];
- check(krb5_init_context(&ctx));
+ argc -= optind;
+ argv += optind;
+ if (argc != 2)
+ abort();
+ princstr = argv[0];
+ password = argv[1];
+
check(krb5_parse_name(ctx, princstr, &client));
- /* Try once with the traditional interface. */
- check(krb5_get_init_creds_password(ctx, &creds, client, password, NULL,
- NULL, 0, NULL, NULL));
- krb5_free_cred_contents(ctx, &creds);
+ if (nptypes > 0)
+ krb5_get_init_creds_opt_set_preauth_list(opt, ptypes, nptypes);
- /* Try again with the step interface. */
- check(krb5_init_creds_init(ctx, client, NULL, NULL, 0, NULL, &icc));
- check(krb5_init_creds_set_password(ctx, icc, password));
- check(krb5_init_creds_get(ctx, icc));
- krb5_init_creds_free(ctx, icc);
+ if (stepwise) {
+ /* Use the stepwise interface. */
+ check(krb5_init_creds_init(ctx, client, NULL, NULL, 0, NULL, &icc));
+ check(krb5_init_creds_set_password(ctx, icc, password));
+ check(krb5_init_creds_get(ctx, icc));
+ krb5_init_creds_free(ctx, icc);
+ } else {
+ /* Use the traditional one-shot interface. */
+ check(krb5_get_init_creds_password(ctx, &creds, client, password, NULL,
+ NULL, 0, NULL, opt));
+ krb5_free_cred_contents(ctx, &creds);
+ }
+ krb5_get_init_creds_opt_free(ctx, opt);
krb5_free_principal(ctx, client);
krb5_free_context(ctx);
return 0;
diff --git a/src/tests/kdbtest.c b/src/tests/kdbtest.c
index 3f63cfb5d102..3f61f3e83bbd 100644
--- a/src/tests/kdbtest.c
+++ b/src/tests/kdbtest.c
@@ -243,8 +243,9 @@ check_entry(krb5_db_entry *ent)
static void
sim_preauth(krb5_timestamp authtime, krb5_boolean ok, krb5_db_entry **entp)
{
- /* Both back ends ignore the request parameter for now. */
- krb5_db_audit_as_req(ctx, NULL, *entp, *entp, authtime,
+ /* Both back ends ignore the request, local_addr, and remote_addr
+ * parameters for now. */
+ krb5_db_audit_as_req(ctx, NULL, NULL, NULL, *entp, *entp, authtime,
ok ? 0 : KRB5KDC_ERR_PREAUTH_FAILED);
krb5_db_free_principal(ctx, *entp);
CHECK(krb5_db_get_principal(ctx, &sample_princ, 0, entp));
diff --git a/src/tests/responder.c b/src/tests/responder.c
index 21aae65c65af..82f870ea5d4b 100644
--- a/src/tests/responder.c
+++ b/src/tests/responder.c
@@ -226,7 +226,7 @@ responder(krb5_context ctx, void *rawdata, krb5_responder_context rctx)
if (chl != NULL &&
chl->identities != NULL &&
chl->identities[0] != NULL) {
- if (strncmp(chl->identities[0]->identity, "PKCS12:", 5) == 0)
+ if (strncmp(chl->identities[0]->identity, "PKCS12:", 7) == 0)
krb5_responder_pkinit_set_answer(ctx, rctx, "foo", "bar");
}
krb5_responder_pkinit_challenge_free(ctx, rctx, chl);
diff --git a/src/tests/t_audit.py b/src/tests/t_audit.py
index 69c9251e0428..00e96bfea69d 100755
--- a/src/tests/t_audit.py
+++ b/src/tests/t_audit.py
@@ -14,18 +14,15 @@ realm.run([kvno, 'target'])
# Make S4U2Self and S4U2Proxy requests so they will be audited. The
# S4U2Proxy request is expected to fail.
-out = realm.run([kvno, '-k', realm.keytab, '-U', 'user', '-P', 'target'],
- expected_code=1)
-if 'NOT_ALLOWED_TO_DELEGATE' not in out:
- fail('Unexpected error for S4U2Proxy')
+realm.run([kvno, '-k', realm.keytab, '-U', 'user', '-P', 'target'],
+ expected_code=1, expected_msg='NOT_ALLOWED_TO_DELEGATE')
# Make a U2U request so it will be audited.
uuserver = os.path.join(buildtop, 'appl', 'user_user', 'uuserver')
uuclient = os.path.join(buildtop, 'appl', 'user_user', 'uuclient')
port_arg = str(realm.server_port())
realm.start_server([uuserver, port_arg], 'Server started')
-output = realm.run([uuclient, hostname, 'testing message', port_arg])
-if 'Hello' not in output:
- fail('U2U request failed unexpectedly')
+realm.run([uuclient, hostname, 'testing message', port_arg],
+ expected_msg='Hello')
success('Audit tests')
diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py
index 33525022ba84..8a577b4b18ee 100644
--- a/src/tests/t_authdata.py
+++ b/src/tests/t_authdata.py
@@ -24,10 +24,8 @@ if ' -5: test1' not in out or '?-6: test2' not in out:
if 'fake' in out:
fail('KDC-only authdata not filtered for request with authdata')
-out = realm.run(['./adata', realm.host_princ, '!-1', 'mandatoryforkdc'],
- expected_code=1)
-if 'KDC policy rejects request' not in out:
- fail('Wrong error seen for mandatory-for-kdc failure')
+realm.run(['./adata', realm.host_princ, '!-1', 'mandatoryforkdc'],
+ expected_code=1, expected_msg='KDC policy rejects request')
# The no_auth_data_required server flag should suppress SIGNTICKET,
# but not module or request authdata.
@@ -88,6 +86,7 @@ realm, realm2 = cross_realms(2, args=({'realm': 'LOCAL'},
realm.run([kadminl, 'modprinc', '+requires_preauth', '-maxrenewlife', '2 days',
realm.user_princ])
realm.run([kadminl, 'modprinc', '-maxrenewlife', '2 days', realm.host_princ])
+realm.run([kadminl, 'modprinc', '-maxrenewlife', '2 days', realm.krbtgt_princ])
realm.extract_keytab(realm.krbtgt_princ, realm.keytab)
realm.extract_keytab(realm.host_princ, realm.keytab)
realm.extract_keytab('krbtgt/FOREIGN', realm.keytab)
@@ -98,45 +97,32 @@ realm2.extract_keytab('krbtgt/LOCAL', realm.keytab)
# AS request to local-realm service
realm.kinit(realm.user_princ, password('user'),
['-X', 'indicators=indcl', '-r', '2d', '-S', realm.host_princ])
-out = realm.run(['./adata', realm.host_princ])
-if '+97: [indcl]' not in out:
- fail('auth-indicator not seen for AS req to service')
+realm.run(['./adata', realm.host_princ], expected_msg='+97: [indcl]')
# Ticket modification request
realm.kinit(realm.user_princ, None, ['-R', '-S', realm.host_princ])
-out = realm.run(['./adata', realm.host_princ])
-if '+97: [indcl]' not in out:
- fail('auth-indicator not seen for ticket modification request')
+realm.run(['./adata', realm.host_princ], expected_msg='+97: [indcl]')
# AS request to cross TGT
realm.kinit(realm.user_princ, password('user'),
['-X', 'indicators=indcl', '-S', 'krbtgt/FOREIGN'])
-out = realm.run(['./adata', 'krbtgt/FOREIGN'])
-if '+97: [indcl]' not in out:
- fail('auth-indicator not seen for AS req to cross-realm TGT')
+realm.run(['./adata', 'krbtgt/FOREIGN'], expected_msg='+97: [indcl]')
# Multiple indicators
realm.kinit(realm.user_princ, password('user'),
['-X', 'indicators=indcl indcl2 indcl3'])
-out = realm.run(['./adata', realm.krbtgt_princ])
-if '+97: [indcl, indcl2, indcl3]' not in out:
- fail('multiple auth-indicators not seen for normal AS req')
+realm.run(['./adata', realm.krbtgt_princ],
+ expected_msg='+97: [indcl, indcl2, indcl3]')
# AS request to local TGT (resulting creds are used for TGS tests)
realm.kinit(realm.user_princ, password('user'), ['-X', 'indicators=indcl'])
-out = realm.run(['./adata', realm.krbtgt_princ])
-if '+97: [indcl]' not in out:
- fail('auth-indicator not seen for normal AS req')
+realm.run(['./adata', realm.krbtgt_princ], expected_msg='+97: [indcl]')
# Local TGS request for local realm service
-out = realm.run(['./adata', realm.host_princ])
-if '+97: [indcl]' not in out:
- fail('auth-indicator not seen for local TGS req')
+realm.run(['./adata', realm.host_princ], expected_msg='+97: [indcl]')
# Local TGS request for cross TGT service
-out = realm.run(['./adata', 'krbtgt/FOREIGN'])
-if '+97: [indcl]' not in out:
- fail('auth-indicator not seen for TGS req to cross-realm TGT')
+realm.run(['./adata', 'krbtgt/FOREIGN'], expected_msg='+97: [indcl]')
# We don't yet have support for passing auth indicators across realms,
# so just verify that indicators don't survive cross-realm requests.
@@ -152,16 +138,13 @@ if '97:' in out:
# Test that the CAMMAC signature still works during a krbtgt rollover.
realm.run([kadminl, 'cpw', '-randkey', '-keepold', realm.krbtgt_princ])
-out = realm.run(['./adata', realm.host_princ])
-if '+97: [indcl]' not in out:
- fail('auth-indicator not seen for local TGS req after krbtgt rotation')
+realm.run(['./adata', realm.host_princ], expected_msg='+97: [indcl]')
# Test indicator enforcement.
realm.addprinc('restricted')
realm.run([kadminl, 'setstr', 'restricted', 'require_auth', 'superstrong'])
-out = realm.run([kvno, 'restricted'], expected_code=1)
-if 'KDC policy rejects request' not in out:
- fail('expected error not seen for auth indicator enforcement')
+realm.run([kvno, 'restricted'], expected_code=1,
+ expected_msg='KDC policy rejects request')
realm.run([kadminl, 'setstr', 'restricted', 'require_auth', 'indcl'])
realm.run([kvno, 'restricted'])
realm.kinit(realm.user_princ, password('user'), ['-X', 'indicators=ind1 ind2'])
@@ -178,6 +161,13 @@ realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'des3-cbc-sha1',
realm.run(['./forward'])
realm.run([kvno, realm.host_princ])
+# Repeat the above test using a renewed TGT.
+realm.kinit(realm.user_princ, password('user'), ['-r', '2d'])
+realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e', 'aes128-cts',
+ realm.krbtgt_princ])
+realm.kinit(realm.user_princ, None, ['-R'])
+realm.run([kvno, realm.host_princ])
+
realm.stop()
realm2.stop()
@@ -222,13 +212,11 @@ if '+97: [indcl]' not in out or '[inds1]' in out:
# Test that KDB module authdata is included in an AS request, by
# default or with an explicit PAC request.
realm.kinit(realm.user_princ, None, ['-k'])
-out = realm.run(['./adata', realm.krbtgt_princ])
-if '-456: db-authdata-test' not in out:
- fail('DB authdata not seen in default AS request')
+realm.run(['./adata', realm.krbtgt_princ],
+ expected_msg='-456: db-authdata-test')
realm.kinit(realm.user_princ, None, ['-k', '--request-pac'])
-out = realm.run(['./adata', realm.krbtgt_princ])
-if '-456: db-authdata-test' not in out:
- fail('DB authdata not seen with --request-pac')
+realm.run(['./adata', realm.krbtgt_princ],
+ expected_msg='-456: db-authdata-test')
# Test that KDB module authdata is suppressed in an AS request by a
# negative PAC request.
@@ -238,9 +226,7 @@ if '-456: db-authdata-test' in out:
fail('DB authdata not suppressed by --no-request-pac')
# Test that KDB authdata is included in a TGS request by default.
-out = realm.run(['./adata', 'service/1'])
-if '-456: db-authdata-test' not in out:
- fail('DB authdata not seen in TGS request')
+realm.run(['./adata', 'service/1'], expected_msg='-456: db-authdata-test')
# Test that KDB authdata is suppressed in a TGS request by the
# +no_auth_data_required flag.
diff --git a/src/tests/t_ccache.py b/src/tests/t_ccache.py
index 47d96313085e..61d549b7b6a8 100755
--- a/src/tests/t_ccache.py
+++ b/src/tests/t_ccache.py
@@ -35,15 +35,11 @@ if not test_keyring:
# Test kdestroy and klist of a non-existent ccache.
realm.run([kdestroy])
-output = realm.run([klist], expected_code=1)
-if 'No credentials cache found' not in output:
- fail('Expected error message not seen in klist output')
+realm.run([klist], expected_code=1, expected_msg='No credentials cache found')
# Test kinit with an inaccessible ccache.
-out = realm.run([kinit, '-c', 'testdir/xx/yy', realm.user_princ],
- input=(password('user') + '\n'), expected_code=1)
-if 'Failed to store credentials' not in out:
- fail('Expected error message not seen in kinit output')
+realm.kinit(realm.user_princ, password('user'), flags=['-c', 'testdir/xx/yy'],
+ expected_code=1, expected_msg='Failed to store credentials')
# Test klist -s with a single ccache.
realm.run([klist, '-s'], expected_code=1)
@@ -61,13 +57,12 @@ realm.addprinc('bob', password('bob'))
realm.addprinc('carol', password('carol'))
def collection_test(realm, ccname):
+ oldccname = realm.env['KRB5CCNAME']
realm.env['KRB5CCNAME'] = ccname
realm.run([klist, '-A', '-s'], expected_code=1)
realm.kinit('alice', password('alice'))
- output = realm.run([klist])
- if 'Default principal: alice@' not in output:
- fail('Initial kinit failed to get credentials for alice.')
+ realm.run([klist], expected_msg='Default principal: alice@')
realm.run([klist, '-A', '-s'])
realm.run([kdestroy])
output = realm.run([klist], expected_code=1)
@@ -88,7 +83,7 @@ def collection_test(realm, ccname):
if '---\nalice@' not in output or output.count('\n') != 4:
fail('klist -l did not show expected output after re-kinit for alice.')
realm.kinit('bob', password('bob'))
- output = realm.run([klist, '-A'])
+ output = realm.run([klist, '-A', ccname])
if 'bob@' not in output.splitlines()[1] or 'alice@' not in output or \
'carol' not in output or output.count('Default principal:') != 3:
fail('klist -A did not show expected output after kinit for bob.')
@@ -96,17 +91,22 @@ def collection_test(realm, ccname):
output = realm.run([klist, '-l'])
if '---\ncarol@' not in output or output.count('\n') != 5:
fail('klist -l did not show expected output after kswitch to carol.')
- realm.run([kdestroy])
- output = realm.run([klist, '-l'])
+
+ # Switch to specifying the collection name on the command line
+ # (only works with klist/kdestroy for now, not kinit/kswitch).
+ realm.env['KRB5CCNAME'] = oldccname
+
+ realm.run([kdestroy, '-c', ccname])
+ output = realm.run([klist, '-l', ccname])
if 'carol@' in output or 'bob@' not in output or output.count('\n') != 4:
fail('kdestroy failed to remove only primary ccache.')
- realm.run([klist, '-s'], expected_code=1)
- realm.run([klist, '-A', '-s'])
- realm.run([kdestroy, '-A'])
- output = realm.run([klist, '-l'], expected_code=1)
+ realm.run([klist, '-s', ccname], expected_code=1)
+ realm.run([klist, '-A', '-s', ccname])
+ realm.run([kdestroy, '-A', '-c', ccname])
+ output = realm.run([klist, '-l', ccname], expected_code=1)
if not output.endswith('---\n') or output.count('\n') != 2:
fail('kdestroy -a failed to empty cache collection.')
- realm.run([klist, '-A', '-s'], expected_code=1)
+ realm.run([klist, '-A', '-s', ccname], expected_code=1)
collection_test(realm, 'DIR:' + os.path.join(realm.testdir, 'cc'))
@@ -130,25 +130,20 @@ if test_keyring:
realm.env['KRB5CCNAME'] = 'KEYRING:' + cname
realm.run([kdestroy, '-A'])
realm.kinit(realm.user_princ, password('user'))
- out = realm.run([klist, '-l'])
- if 'KEYRING:legacy:' + cname + ':' + cname not in out:
- fail('Wrong initial primary name in keyring legacy collection')
+ msg = 'KEYRING:legacy:' + cname + ':' + cname
+ realm.run([klist, '-l'], expected_msg=msg)
# Make sure this cache is linked to the session keyring.
id = realm.run([keyctl, 'search', '@s', 'keyring', cname])
- out = realm.run([keyctl, 'list', id.strip()])
- if 'user: __krb5_princ__' not in out:
- fail('Legacy cache not linked into session keyring')
+ realm.run([keyctl, 'list', id.strip()],
+ expected_msg='user: __krb5_princ__')
# Remove the collection keyring. When the collection is
# reinitialized, the legacy cache should reappear inside it
# automatically as the primary cache.
cleanup_keyring('@s', col_ringname)
- out = realm.run([klist])
- if realm.user_princ not in out:
- fail('Cannot see legacy cache after removing collection')
+ realm.run([klist], expected_msg=realm.user_princ)
coll_id = realm.run([keyctl, 'search', '@s', 'keyring', '_krb_' + cname])
- out = realm.run([keyctl, 'list', coll_id.strip()])
- if (id.strip() + ':') not in out:
- fail('Legacy cache did not reappear in collection after klist')
+ msg = id.strip() + ':'
+ realm.run([keyctl, 'list', coll_id.strip()], expected_msg=msg)
# Destroy the cache and check that it is unlinked from the session keyring.
realm.run([kdestroy])
realm.run([keyctl, 'search', '@s', 'keyring', cname], expected_code=1)
@@ -160,8 +155,7 @@ conf = {'libdefaults': {'default_ccache_name': 'testdir/%{null}abc%{uid}'}}
realm = K5Realm(krb5_conf=conf, create_kdb=False)
del realm.env['KRB5CCNAME']
uidstr = str(os.getuid())
-out = realm.run([klist], expected_code=1)
-if 'testdir/abc%s' % uidstr not in out:
- fail('Wrong ccache in klist')
+msg = 'testdir/abc%s' % uidstr
+realm.run([klist], expected_code=1, expected_msg=msg)
success('Credential cache tests')
diff --git a/src/tests/t_certauth.py b/src/tests/t_certauth.py
new file mode 100644
index 000000000000..e64a57b0d5eb
--- /dev/null
+++ b/src/tests/t_certauth.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+from k5test import *
+
+# Skip this test if pkinit wasn't built.
+if not os.path.exists(os.path.join(plugins, 'preauth', 'pkinit.so')):
+ skip_rest('certauth tests', 'PKINIT module not built')
+
+certs = os.path.join(srctop, 'tests', 'dejagnu', 'pkinit-certs')
+ca_pem = os.path.join(certs, 'ca.pem')
+kdc_pem = os.path.join(certs, 'kdc.pem')
+privkey_pem = os.path.join(certs, 'privkey.pem')
+user_pem = os.path.join(certs, 'user.pem')
+
+modpath = os.path.join(buildtop, 'plugins', 'certauth', 'test',
+ 'certauth_test.so')
+pkinit_krb5_conf = {'realms': {'$realm': {
+ 'pkinit_anchors': 'FILE:%s' % ca_pem}},
+ 'plugins': {'certauth': {'module': ['test1:' + modpath,
+ 'test2:' + modpath],
+ 'enable_only': ['test1', 'test2']}}}
+pkinit_kdc_conf = {'realms': {'$realm': {
+ 'default_principal_flags': '+preauth',
+ 'pkinit_eku_checking': 'none',
+ 'pkinit_identity': 'FILE:%s,%s' % (kdc_pem, privkey_pem),
+ 'pkinit_indicator': ['indpkinit1', 'indpkinit2']}}}
+
+file_identity = 'FILE:%s,%s' % (user_pem, privkey_pem)
+
+realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=pkinit_kdc_conf,
+ get_creds=False)
+
+# Let the test module match user to CN=user, with indicators.
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % file_identity])
+realm.klist(realm.user_princ)
+realm.run([kvno, realm.host_princ])
+realm.run(['./adata', realm.host_princ],
+ expected_msg='+97: [test1, test2, user, indpkinit1, indpkinit2]')
+
+# Let the test module mismatch with user2 to CN=user.
+realm.addprinc("user2@KRBTEST.COM")
+out = realm.kinit("user2@KRBTEST.COM",
+ flags=['-X', 'X509_user_identity=%s' % file_identity],
+ expected_code=1,
+ expected_msg='kinit: Certificate mismatch')
+
+success("certauth tests")
diff --git a/src/tests/t_crossrealm.py b/src/tests/t_crossrealm.py
index 0d967b8a50f2..e7ddb05254d8 100755
--- a/src/tests/t_crossrealm.py
+++ b/src/tests/t_crossrealm.py
@@ -25,9 +25,7 @@
from k5test import *
def test_kvno(r, princ, test, env=None):
- output = r.run([kvno, princ], env=env)
- if princ not in output:
- fail('%s: principal %s not in kvno output' % (test, princ))
+ r.run([kvno, princ], env=env, expected_msg=princ)
def stop(*realms):
@@ -35,10 +33,39 @@ def stop(*realms):
r.stop()
+# Verify that the princs appear as the service principals in the klist
+# output for the realm r, in order.
+def check_klist(r, princs):
+ out = r.run([klist])
+ count = 0
+ seen_header = False
+ for l in out.split('\n'):
+ if l.startswith('Valid starting'):
+ seen_header = True
+ continue
+ if not seen_header or l == '':
+ continue
+ if count >= len(princs):
+ fail('too many entries in klist output')
+ svcprinc = l.split()[4]
+ if svcprinc != princs[count]:
+ fail('saw service princ %s in klist output, expected %s' %
+ (svcprinc, princs[count]))
+ count += 1
+ if count != len(princs):
+ fail('not enough entries in klist output')
+
+
+def tgt(r1, r2):
+ return 'krbtgt/%s@%s' % (r1.realm, r2.realm)
+
+
# Basic two-realm test with cross TGTs in both directions.
r1, r2 = cross_realms(2)
test_kvno(r1, r2.host_princ, 'basic r1->r2')
+check_klist(r1, (tgt(r1, r1), tgt(r2, r1), r2.host_princ))
test_kvno(r2, r1.host_princ, 'basic r2->r1')
+check_klist(r2, (tgt(r2, r2), tgt(r1, r2), r1.host_princ))
stop(r1, r2)
# Test the KDC domain walk for hierarchically arranged realms. The
@@ -49,6 +76,7 @@ r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),
args=({'realm': 'A.X'}, {'realm': 'X'},
{'realm': 'B.X'}))
test_kvno(r1, r3.host_princ, 'KDC domain walk')
+check_klist(r1, (tgt(r1, r1), r3.host_princ))
stop(r1, r2, r3)
# Test client capaths. The client in A will ask for a cross TGT to D,
@@ -64,6 +92,8 @@ r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)),
{'realm': 'D', 'krb5_conf': capaths}))
r1client = r1.special_env('client', False, krb5_conf=capaths)
test_kvno(r1, r4.host_princ, 'client capaths', r1client)
+check_klist(r1, (tgt(r1, r1), tgt(r2, r1), tgt(r3, r2), tgt(r4, r3),
+ r4.host_princ))
stop(r1, r2, r3, r4)
# Test KDC capaths. The KDCs for A and B have appropriate capaths
@@ -76,6 +106,7 @@ r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)),
{'realm': 'C', 'krb5_conf': capaths},
{'realm': 'D', 'krb5_conf': capaths}))
test_kvno(r1, r4.host_princ, 'KDC capaths')
+check_klist(r1, (tgt(r1, r1), tgt(r4, r3), r4.host_princ))
stop(r1, r2, r3, r4)
# Test transited error. The KDC for C does not recognize B as an
@@ -85,9 +116,9 @@ capaths = {'capaths': {'A': {'C': 'B'}}}
r1, r2, r3 = cross_realms(3, xtgts=((0,1), (1,2)),
args=({'realm': 'A', 'krb5_conf': capaths},
{'realm': 'B'}, {'realm': 'C'}))
-output = r1.run([kvno, r3.host_princ], expected_code=1)
-if 'KDC policy rejects request' not in output:
- fail('transited 1: Expected error message not in output')
+r1.run([kvno, r3.host_princ], expected_code=1,
+ expected_msg='KDC policy rejects request')
+check_klist(r1, (tgt(r1, r1), tgt(r3, r2)))
stop(r1, r2, r3)
# Test a different kind of transited error. The KDC for D does not
@@ -99,9 +130,9 @@ r1, r2, r3, r4 = cross_realms(4, xtgts=((0,1), (1,2), (2,3)),
{'realm': 'B', 'krb5_conf': capaths},
{'realm': 'C', 'krb5_conf': capaths},
{'realm': 'D'}))
-output = r1.run([kvno, r4.host_princ], expected_code=1)
-if 'Illegal cross-realm ticket' not in output:
- fail('transited 2: Expected error message not in output')
+r1.run([kvno, r4.host_princ], expected_code=1,
+ expected_msg='Illegal cross-realm ticket')
+check_klist(r1, (tgt(r1, r1), tgt(r4, r3)))
stop(r1, r2, r3, r4)
success('Cross-realm tests')
diff --git a/src/tests/t_dump.py b/src/tests/t_dump.py
index 5d3a437625e2..8a9462bd8eaf 100755
--- a/src/tests/t_dump.py
+++ b/src/tests/t_dump.py
@@ -36,12 +36,10 @@ if 'Expiration date: [never]' not in out or 'MKey: vno 1' not in out:
out = realm.run([kadminl, 'getpols'])
if 'fred\n' not in out or 'barney\n' not in out:
fail('Missing policy after load')
-out = realm.run([kadminl, 'getpol', 'compat'])
-if 'Number of old keys kept: 5' not in out:
- fail('Policy (1.8 format) has wrong value after load')
-out = realm.run([kadminl, 'getpol', 'barney'])
-if 'Number of old keys kept: 1' not in out:
- fail('Policy has wrong value after load')
+realm.run([kadminl, 'getpol', 'compat'],
+ expected_msg='Number of old keys kept: 5')
+realm.run([kadminl, 'getpol', 'barney'],
+ expected_msg='Number of old keys kept: 1')
# Dump/load again, and make sure everything is still there.
realm.run([kdb5_util, 'dump', dumpfile])
@@ -81,15 +79,10 @@ dump_compare(realm, ['-ov'], srcdump_ov)
def load_dump_check_compare(realm, opt, srcfile):
realm.run([kdb5_util, 'destroy', '-f'])
realm.run([kdb5_util, 'load'] + opt + [srcfile])
- out = realm.run([kadminl, 'getprincs'])
- if 'user@' not in out:
- fail('Loaded dumpfile missing user principal')
- out = realm.run([kadminl, 'getprinc', 'nokeys'])
- if 'Number of keys: 0' not in out:
- fail('Loading dumpfile did not process zero-key principal')
- out = realm.run([kadminl, 'getpols'])
- if 'testpol' not in out:
- fail('Loaded dumpfile missing test policy')
+ realm.run([kadminl, 'getprincs'], expected_msg='user@')
+ realm.run([kadminl, 'getprinc', 'nokeys'],
+ expected_msg='Number of keys: 0')
+ realm.run([kadminl, 'getpols'], expected_msg='testpol')
dump_compare(realm, opt, srcfile)
# Load each format of dump, check it, re-dump it, and compare.
@@ -99,12 +92,8 @@ load_dump_check_compare(realm, ['-b7'], srcdump_b7)
# Loading the last (-b7 format) dump won't have loaded the
# per-principal kadm data. Load that incrementally with -ov.
-out = realm.run([kadminl, 'getprinc', 'user'])
-if 'Policy: [none]' not in out:
- fail('Loaded b7 dump unexpectedly contains user policy reference')
+realm.run([kadminl, 'getprinc', 'user'], expected_msg='Policy: [none]')
realm.run([kdb5_util, 'load', '-update', '-ov', srcdump_ov])
-out = realm.run([kadminl, 'getprinc', 'user'])
-if 'Policy: testpol' not in out:
- fail('Loading ov dump did not add user policy reference')
+realm.run([kadminl, 'getprinc', 'user'], expected_msg='Policy: testpol')
success('Dump/load tests')
diff --git a/src/tests/t_general.py b/src/tests/t_general.py
index 6d523fe4513d..91ad0cb8a060 100755
--- a/src/tests/t_general.py
+++ b/src/tests/t_general.py
@@ -3,10 +3,9 @@ from k5test import *
for realm in multipass_realms(create_host=False):
# Check that kinit fails appropriately with the wrong password.
- output = realm.run([kinit, realm.user_princ], input='wrong\n',
- expected_code=1)
- if 'Password incorrect while getting initial credentials' not in output:
- fail('Expected error message not seen in kinit output')
+ msg = 'Password incorrect while getting initial credentials'
+ realm.run([kinit, realm.user_princ], input='wrong\n', expected_code=1,
+ expected_msg=msg)
# Check that we can kinit as a different principal.
realm.kinit(realm.admin_princ, password('admin'))
@@ -30,6 +29,7 @@ conf={'plugins': {'pwqual': {'disable': 'empty'}}}
realm = K5Realm(create_user=False, create_host=False, krb5_conf=conf)
realm.run([kadminl, 'addprinc', '-pw', '', 'user'])
realm.run(['./icred', 'user', ''])
+realm.run(['./icred', '-s', 'user', ''])
realm.stop()
realm = K5Realm(create_host=False)
@@ -42,26 +42,17 @@ realm.run(['./responder', '-r', 'password=%s' % password('user'),
# Test that WRONG_REALM responses aren't treated as referrals unless
# they contain a crealm field pointing to a different realm.
# (Regression test for #8060.)
-out = realm.run([kinit, '-C', 'notfoundprinc'], expected_code=1)
-if 'not found in Kerberos database' not in out:
- fail('Expected error message not seen in kinit -C output')
+realm.run([kinit, '-C', 'notfoundprinc'], expected_code=1,
+ expected_msg='not found in Kerberos database')
# Spot-check KRB5_TRACE output
-tracefile = os.path.join(realm.testdir, 'trace')
-realm.run(['env', 'KRB5_TRACE=' + tracefile, kinit, realm.user_princ],
- input=(password('user') + "\n"))
-f = open(tracefile, 'r')
-trace = f.read()
-f.close()
-expected = ('Sending initial UDP request',
- 'Received answer',
- 'Selected etype info',
- 'AS key obtained',
- 'Decrypted AS reply',
- 'FAST negotiation: available',
- 'Storing user@KRBTEST.COM')
-for e in expected:
- if e not in trace:
- fail('Expected output not in kinit trace log')
+expected_trace = ('Sending initial UDP request',
+ 'Received answer',
+ 'Selected etype info',
+ 'AS key obtained',
+ 'Decrypted AS reply',
+ 'FAST negotiation: available',
+ 'Storing user@KRBTEST.COM')
+realm.kinit(realm.user_princ, password('user'), expected_trace=expected_trace)
success('FAST kinit, trace logging')
diff --git a/src/tests/t_hostrealm.py b/src/tests/t_hostrealm.py
index 76b282d2ac6e..224c067ef424 100755
--- a/src/tests/t_hostrealm.py
+++ b/src/tests/t_hostrealm.py
@@ -20,9 +20,8 @@ def test(realm, args, expected_realms, msg, env=None):
fail(msg)
def test_error(realm, args, expected_error, msg, env=None):
- out = realm.run(['./hrealm'] + args, env=env, expected_code=1)
- if expected_error not in out:
- fail(msg)
+ realm.run(['./hrealm'] + args, env=env, expected_code=1,
+ expected_msg=expected_error)
def testh(realm, host, expected_realms, msg, env=None):
test(realm, ['-h', host], expected_realms, msg, env=env)
diff --git a/src/tests/t_iprop.py b/src/tests/t_iprop.py
index e64fdd27993c..8e23cd5de9db 100755
--- a/src/tests/t_iprop.py
+++ b/src/tests/t_iprop.py
@@ -214,9 +214,8 @@ check_ulog(7, 1, 7, [None, pr1, pr3, pr2, pr2, pr2, pr2])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, False, 6, 7)
check_ulog(2, 6, 7, [None, pr2], slave1)
-out = realm.run([kadminl, 'getprinc', pr2], env=slave1)
-if 'Attributes: DISALLOW_ALL_TIX' not in out:
- fail('slave1 does not have modification from master')
+realm.run([kadminl, 'getprinc', pr2], env=slave1,
+ expected_msg='Attributes: DISALLOW_ALL_TIX')
# Start kadmind -proponly for slave1. (Use the slave1m environment
# which defines iprop_port to $port8.)
@@ -245,15 +244,13 @@ check_ulog(8, 1, 8, [None, pr1, pr3, pr2, pr2, pr2, pr2, pr1])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, False, 7, 8)
check_ulog(3, 6, 8, [None, pr2, pr1], slave1)
-out = realm.run([kadminl, 'getprinc', pr1], env=slave1)
-if 'Maximum ticket life: 0 days 00:20:00' not in out:
- fail('slave1 does not have modification from master')
+realm.run([kadminl, 'getprinc', pr1], env=slave1,
+ expected_msg='Maximum ticket life: 0 days 00:20:00')
kpropd3.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd3, False, 7, 8)
check_ulog(2, 7, 8, [None, pr1], slave3)
-out = realm.run([kadminl, '-r', realm.realm, 'getprinc', pr1], env=slave3)
-if 'Maximum ticket life: 0 days 00:20:00' not in out:
- fail('slave3 does not have modification from slave1')
+realm.run([kadminl, '-r', realm.realm, 'getprinc', pr1], env=slave3,
+ expected_msg='Maximum ticket life: 0 days 00:20:00')
stop_daemon(kpropd3)
# Test dissimilar default_realm and domain_realm map settings (no -r realm).
@@ -287,15 +284,13 @@ check_ulog(9, 1, 9, [None, pr1, pr3, pr2, pr2, pr2, pr2, pr1, pr1])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, False, 8, 9)
check_ulog(4, 6, 9, [None, pr2, pr1, pr1], slave1)
-out = realm.run([kadminl, 'getprinc', pr1], env=slave1)
-if 'Maximum renewable life: 0 days 22:00:00\n' not in out:
- fail('slave1 does not have modification from master')
+realm.run([kadminl, 'getprinc', pr1], env=slave1,
+ expected_msg='Maximum renewable life: 0 days 22:00:00\n')
kpropd2.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd2, False, 8, 9)
check_ulog(3, 7, 9, [None, pr1, pr1], slave2)
-out = realm.run([kadminl, 'getprinc', pr1], env=slave2)
-if 'Maximum renewable life: 0 days 22:00:00\n' not in out:
- fail('slave2 does not have modification from slave1')
+realm.run([kadminl, 'getprinc', pr1], env=slave2,
+ expected_msg='Maximum renewable life: 0 days 22:00:00\n')
# Reset the ulog on slave1 to force a full resync from master. The
# resync will use the old dump file and then propagate changes.
@@ -317,15 +312,11 @@ check_ulog(10, 1, 10, [None, pr1, pr3, pr2, pr2, pr2, pr2, pr1, pr1, pr2])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, False, 9, 10)
check_ulog(5, 6, 10, [None, pr2, pr1, pr1, pr2], slave1)
-out = realm.run([kadminl, 'getprinc', pr2], env=slave1)
-if 'Attributes:\n' not in out:
- fail('slave1 does not have modification from master')
+realm.run([kadminl, 'getprinc', pr2], env=slave1, expected_msg='Attributes:\n')
kpropd2.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd2, False, 9, 10)
check_ulog(4, 7, 10, [None, pr1, pr1, pr2], slave2)
-out = realm.run([kadminl, 'getprinc', pr2], env=slave2)
-if 'Attributes:\n' not in out:
- fail('slave2 does not have modification from slave1')
+realm.run([kadminl, 'getprinc', pr2], env=slave2, expected_msg='Attributes:\n')
# Create a policy and check that it propagates via full resync.
realm.run([kadminl, 'addpol', '-minclasses', '2', 'testpol'])
@@ -333,15 +324,13 @@ check_ulog(1, 1, 1, [None])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, True, 10, 1)
check_ulog(1, 1, 1, [None], slave1)
-out = realm.run([kadminl, 'getpol', 'testpol'], env=slave1)
-if 'Minimum number of password character classes: 2' not in out:
- fail('slave1 does not have policy from master')
+realm.run([kadminl, 'getpol', 'testpol'], env=slave1,
+ expected_msg='Minimum number of password character classes: 2')
kpropd2.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd2, True, 10, 1)
check_ulog(1, 1, 1, [None], slave2)
-out = realm.run([kadminl, 'getpol', 'testpol'], env=slave2)
-if 'Minimum number of password character classes: 2' not in out:
- fail('slave2 does not have policy from slave1')
+realm.run([kadminl, 'getpol', 'testpol'], env=slave2,
+ expected_msg='Minimum number of password character classes: 2')
# Modify the policy and test that it also propagates via full resync.
realm.run([kadminl, 'modpol', '-minlength', '17', 'testpol'])
@@ -349,15 +338,13 @@ check_ulog(1, 1, 1, [None])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, True, 1, 1)
check_ulog(1, 1, 1, [None], slave1)
-out = realm.run([kadminl, 'getpol', 'testpol'], env=slave1)
-if 'Minimum password length: 17' not in out:
- fail('slave1 does not have policy change from master')
+realm.run([kadminl, 'getpol', 'testpol'], env=slave1,
+ expected_msg='Minimum password length: 17')
kpropd2.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd2, True, 1, 1)
check_ulog(1, 1, 1, [None], slave2)
-out = realm.run([kadminl, 'getpol', 'testpol'], env=slave2)
-if 'Minimum password length: 17' not in out:
- fail('slave2 does not have policy change from slave1')
+realm.run([kadminl, 'getpol', 'testpol'], env=slave2,
+ expected_msg='Minimum password length: 17')
# Delete the policy and test that it propagates via full resync.
realm.run([kadminl, 'delpol', 'testpol'])
@@ -365,15 +352,13 @@ check_ulog(1, 1, 1, [None])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, True, 1, 1)
check_ulog(1, 1, 1, [None], slave1)
-out = realm.run([kadminl, 'getpol', 'testpol'], env=slave1, expected_code=1)
-if 'Policy does not exist' not in out:
- fail('slave1 did not get policy deletion from master')
+realm.run([kadminl, 'getpol', 'testpol'], env=slave1, expected_code=1,
+ expected_msg='Policy does not exist')
kpropd2.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd2, True, 1, 1)
check_ulog(1, 1, 1, [None], slave2)
-out = realm.run([kadminl, 'getpol', 'testpol'], env=slave2, expected_code=1)
-if 'Policy does not exist' not in out:
- fail('slave2 did not get policy deletion from slave1')
+realm.run([kadminl, 'getpol', 'testpol'], env=slave2, expected_code=1,
+ expected_msg='Policy does not exist')
# Modify a principal on the master and test that it propagates incrementally.
realm.run([kadminl, 'modprinc', '-maxlife', '10 minutes', pr1])
@@ -381,15 +366,13 @@ check_ulog(2, 1, 2, [None, pr1])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, False, 1, 2)
check_ulog(2, 1, 2, [None, pr1], slave1)
-out = realm.run([kadminl, 'getprinc', pr1], env=slave1)
-if 'Maximum ticket life: 0 days 00:10:00' not in out:
- fail('slave1 does not have modification from master')
+realm.run([kadminl, 'getprinc', pr1], env=slave1,
+ expected_msg='Maximum ticket life: 0 days 00:10:00')
kpropd2.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd2, False, 1, 2)
check_ulog(2, 1, 2, [None, pr1], slave2)
-out = realm.run([kadminl, 'getprinc', pr1], env=slave2)
-if 'Maximum ticket life: 0 days 00:10:00' not in out:
- fail('slave2 does not have modification from slave1')
+realm.run([kadminl, 'getprinc', pr1], env=slave2,
+ expected_msg='Maximum ticket life: 0 days 00:10:00')
# Delete a principal and test that it propagates incrementally.
realm.run([kadminl, 'delprinc', pr3])
@@ -397,15 +380,13 @@ check_ulog(3, 1, 3, [None, pr1, pr3])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, False, 2, 3)
check_ulog(3, 1, 3, [None, pr1, pr3], slave1)
-out = realm.run([kadminl, 'getprinc', pr3], env=slave1, expected_code=1)
-if 'Principal does not exist' not in out:
- fail('slave1 does not have principal deletion from master')
+realm.run([kadminl, 'getprinc', pr3], env=slave1, expected_code=1,
+ expected_msg='Principal does not exist')
kpropd2.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd2, False, 2, 3)
check_ulog(3, 1, 3, [None, pr1, pr3], slave2)
-out = realm.run([kadminl, 'getprinc', pr3], env=slave2, expected_code=1)
-if 'Principal does not exist' not in out:
- fail('slave2 does not have principal deletion from slave1')
+realm.run([kadminl, 'getprinc', pr3], env=slave2, expected_code=1,
+ expected_msg='Principal does not exist')
# Rename a principal and test that it propagates incrementally.
renpr = "quacked@" + realm.realm
@@ -414,16 +395,14 @@ check_ulog(6, 1, 6, [None, pr1, pr3, renpr, pr1, renpr])
kpropd1.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd1, False, 3, 6)
check_ulog(6, 1, 6, [None, pr1, pr3, renpr, pr1, renpr], slave1)
-out = realm.run([kadminl, 'getprinc', pr1], env=slave1, expected_code=1)
-if 'Principal does not exist' not in out:
- fail('slave1 does not have principal deletion from master')
+realm.run([kadminl, 'getprinc', pr1], env=slave1, expected_code=1,
+ expected_msg='Principal does not exist')
realm.run([kadminl, 'getprinc', renpr], env=slave1)
kpropd2.send_signal(signal.SIGUSR1)
wait_for_prop(kpropd2, False, 3, 6)
check_ulog(6, 1, 6, [None, pr1, pr3, renpr, pr1, renpr], slave2)
-out = realm.run([kadminl, 'getprinc', pr1], env=slave2, expected_code=1)
-if 'Principal does not exist' not in out:
- fail('slave2 does not have principal deletion from master')
+realm.run([kadminl, 'getprinc', pr1], env=slave2, expected_code=1,
+ expected_msg='Principal does not exist')
realm.run([kadminl, 'getprinc', renpr], env=slave2)
pr1 = renpr
@@ -455,9 +434,8 @@ out = realm.run_kpropd_once(slave1, ['-d'])
if 'Got incremental updates (sno=2 ' not in out:
fail('Expected full dump and synchronized from kpropd -t')
check_ulog(2, 1, 2, [None, pr1], slave1)
-out = realm.run([kadminl, 'getprinc', pr1], env=slave1)
-if 'Maximum ticket life: 0 days 00:05:00' not in out:
- fail('slave1 does not have modification from master after kpropd -t')
+realm.run([kadminl, 'getprinc', pr1], env=slave1,
+ expected_msg='Maximum ticket life: 0 days 00:05:00')
# Propagate a policy change via full resync.
realm.run([kadminl, 'addpol', '-minclasses', '3', 'testpol'])
@@ -467,8 +445,7 @@ if ('Full propagation transfer finished' not in out or
'KDC is synchronized' not in out):
fail('Expected full dump and synchronized from kpropd -t')
check_ulog(1, 1, 1, [None], slave1)
-out = realm.run([kadminl, 'getpol', 'testpol'], env=slave1)
-if 'Minimum number of password character classes: 3' not in out:
- fail('slave1 does not have policy from master after kpropd -t')
+realm.run([kadminl, 'getpol', 'testpol'], env=slave1,
+ expected_msg='Minimum number of password character classes: 3')
success('iprop tests')
diff --git a/src/tests/t_kadm5_auth.py b/src/tests/t_kadm5_auth.py
new file mode 100644
index 000000000000..ba4ab8ef10cf
--- /dev/null
+++ b/src/tests/t_kadm5_auth.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python
+from k5test import *
+
+# Create a realm with the welcomer and bouncer kadm5_auth test modules
+# in place of the builtin modules.
+modpath = os.path.join(buildtop, 'plugins', 'kadm5_auth', 'test',
+ 'kadm5_auth_test.so')
+conf = {'plugins': {'kadm5_auth': {'module': ['welcomer:' + modpath,
+ 'bouncer:' + modpath],
+ 'enable_only': ['welcomer', 'bouncer']}}}
+realm = K5Realm(krb5_conf=conf, create_host=False)
+realm.start_kadmind()
+realm.prep_kadmin()
+
+# addprinc: welcomer accepts with policy VIP, bouncer denies maxlife.
+realm.run_kadmin(['addprinc', '-randkey', 'princ'], expected_code=1)
+realm.run_kadmin(['addprinc', '-randkey', '-policy', 'VIP', 'princ'])
+realm.run_kadmin(['addprinc', '-randkey', '-policy', 'VIP', '-maxlife', '3',
+ 'princ'], expected_code=1)
+
+# modprinc: welcomer accepts with only maxrenewlife, bouncer denies
+# with even-component target principal.
+realm.run_kadmin(['modprinc', '-maxlife', '3', 'princ'], expected_code=1)
+realm.run_kadmin(['modprinc', '-maxrenewlife', '3', 'princ'])
+realm.run_kadmin(['modprinc', '-maxrenewlife', '3', 'user/admin'],
+ expected_code=1)
+
+# setstr: welcomer accepts with key 'note', bouncer denies with value
+# length > 10.
+realm.run_kadmin(['setstr', 'princ', 'somekey', 'someval'], expected_code=1)
+realm.run_kadmin(['setstr', 'princ', 'note', 'abc'])
+realm.run_kadmin(['setstr', 'princ', 'note', 'abcdefghijkl'], expected_code=1)
+
+# delprinc: welcomer accepts with target principal beginning with 'd',
+# bouncer denies with "nodelete" string attribute.
+realm.run_kadmin(['delprinc', 'user'], expected_code=1)
+realm.run([kadminl, 'addprinc', '-randkey', 'deltest'])
+realm.run_kadmin(['delprinc', 'deltest'])
+realm.run([kadminl, 'addprinc', '-randkey', 'deltest'])
+realm.run([kadminl, 'setstr', 'deltest', 'nodelete', 'yes'])
+realm.run_kadmin(['delprinc', 'deltest'], expected_code=1)
+
+# renprinc: welcomer accepts with same-length first components, bouncer
+# refuses with source principal beginning with 'a'.
+realm.run_kadmin(['renprinc', 'princ', 'xyz'], expected_code=1)
+realm.run_kadmin(['renprinc', 'princ', 'abcde'])
+realm.run_kadmin(['renprinc', 'abcde', 'fghij'], expected_code=1)
+
+# addpol: welcomer accepts with minlength 3, bouncer denies with name
+# length <= 3.
+realm.run_kadmin(['addpol', 'testpol'], expected_code=1)
+realm.run_kadmin(['addpol', '-minlength', '3', 'testpol'])
+realm.run_kadmin(['addpol', '-minlength', '3', 'abc'], expected_code=1)
+
+# modpol: welcomer accepts changes to minlife, bouncer denies with
+# minlife > 10.
+realm.run_kadmin(['modpol', '-minlength', '4', 'testpol'], expected_code=1)
+realm.run_kadmin(['modpol', '-minlife', '8', 'testpol'])
+realm.run_kadmin(['modpol', '-minlife', '11', 'testpol'], expected_code=1)
+
+# getpol: welcomer accepts if policy and client policy have same length,
+# bouncer denies if policy name begins with 'x'.
+realm.run([kadminl, 'addpol', 'aaaa'])
+realm.run([kadminl, 'addpol', 'bbbb'])
+realm.run([kadminl, 'addpol', 'xxxx'])
+realm.run([kadminl, 'modprinc', '-policy', 'aaaa', 'user/admin'])
+realm.run_kadmin(['getpol', 'testpol'], expected_code=1)
+realm.run_kadmin(['getpol', 'bbbb'])
+realm.run_kadmin(['getpol', 'xxxx'], expected_code=1)
+
+# end: welcomer counts operations using "ends" string attribute on
+# "opcount" principal. kadmind is dumb and invokes the end method for
+# every RPC operation including init, so we expect four calls to the
+# end operation.
+realm.run([kadminl, 'addprinc', '-nokey', 'opcount'])
+realm.run([kadminl, 'setstr', 'opcount', 'ends', '0'])
+realm.run_kadmin(['getprinc', 'user'])
+realm.run_kadmin(['getpol', 'bbbb'])
+realm.run([kadminl, 'getstrs', 'opcount'], expected_msg='ends: 4')
+
+success('kadm5_auth pluggable interface tests')
diff --git a/src/tests/t_kadm5_hook.py b/src/tests/t_kadm5_hook.py
index 708e328b000b..c1c8c9419c09 100755
--- a/src/tests/t_kadm5_hook.py
+++ b/src/tests/t_kadm5_hook.py
@@ -7,12 +7,10 @@ plugin = os.path.join(buildtop, "plugins", "kadm5_hook", "test",
hook_krb5_conf = {'plugins': {'kadm5_hook': { 'module': 'test:' + plugin}}}
realm = K5Realm(krb5_conf=hook_krb5_conf, create_user=False, create_host=False)
-output = realm.run([kadminl, 'addprinc', '-randkey', 'test'])
-if "create: stage precommit" not in output:
- fail('kadm5_hook test output not found')
+realm.run([kadminl, 'addprinc', '-randkey', 'test'],
+ expected_msg='create: stage precommit')
-output = realm.run([kadminl, 'renprinc', 'test', 'test2'])
-if "rename: stage precommit" not in output:
- fail('kadm5_hook test output not found')
+realm.run([kadminl, 'renprinc', 'test', 'test2'],
+ expected_msg='rename: stage precommit')
success('kadm5_hook')
diff --git a/src/tests/t_kadmin_acl.py b/src/tests/t_kadmin_acl.py
index 188929a76c91..42bdf423c393 100755
--- a/src/tests/t_kadmin_acl.py
+++ b/src/tests/t_kadmin_acl.py
@@ -87,27 +87,24 @@ for pw in (['-pw', 'newpw'], ['-randkey']):
args = pw + ks
kadmin_as(all_changepw, ['cpw'] + args + ['unselected'])
kadmin_as(some_changepw, ['cpw'] + args + ['selected'])
- out = kadmin_as(none, ['cpw'] + args + ['selected'], expected_code=1)
- if 'Operation requires ``change-password\'\' privilege' not in out:
- fail('cpw failure (no perms)')
- out = kadmin_as(some_changepw, ['cpw'] + args + ['unselected'],
- expected_code=1)
- if 'Operation requires ``change-password\'\' privilege' not in out:
- fail('cpw failure (target)')
- out = kadmin_as(none, ['cpw'] + args + ['none'])
+ msg = "Operation requires ``change-password'' privilege"
+ kadmin_as(none, ['cpw'] + args + ['selected'], expected_code=1,
+ expected_msg=msg)
+ kadmin_as(some_changepw, ['cpw'] + args + ['unselected'],
+ expected_code=1, expected_msg=msg)
+ kadmin_as(none, ['cpw'] + args + ['none'])
realm.run([kadminl, 'modprinc', '-policy', 'minlife', 'none'])
- out = kadmin_as(none, ['cpw'] + args + ['none'], expected_code=1)
- if 'Current password\'s minimum life has not expired' not in out:
- fail('cpw failure (minimum life)')
+ msg = "Current password's minimum life has not expired"
+ kadmin_as(none, ['cpw'] + args + ['none'], expected_code=1,
+ expected_msg=msg)
realm.run([kadminl, 'modprinc', '-clearpolicy', 'none'])
realm.run([kadminl, 'delprinc', 'selected'])
realm.run([kadminl, 'delprinc', 'unselected'])
kadmin_as(all_add, ['addpol', 'policy'])
realm.run([kadminl, 'delpol', 'policy'])
-out = kadmin_as(none, ['addpol', 'policy'], expected_code=1)
-if 'Operation requires ``add\'\' privilege' not in out:
- fail('addpol failure (no perms)')
+kadmin_as(none, ['addpol', 'policy'], expected_code=1,
+ expected_msg="Operation requires ``add'' privilege")
# addprinc can generate two different RPC calls depending on options.
for ks in ([], ['-e', 'aes256-cts']):
@@ -117,89 +114,62 @@ for ks in ([], ['-e', 'aes256-cts']):
kadmin_as(some_add, ['addprinc'] + args + ['selected'])
realm.run([kadminl, 'delprinc', 'selected'])
kadmin_as(restricted_add, ['addprinc'] + args + ['unselected'])
- out = realm.run([kadminl, 'getprinc', 'unselected'])
- if 'REQUIRES_PRE_AUTH' not in out:
- fail('addprinc success (restrictions) -- restriction check')
+ realm.run([kadminl, 'getprinc', 'unselected'],
+ expected_msg='REQUIRES_PRE_AUTH')
realm.run([kadminl, 'delprinc', 'unselected'])
- out = kadmin_as(none, ['addprinc'] + args + ['selected'], expected_code=1)
- if 'Operation requires ``add\'\' privilege' not in out:
- fail('addprinc failure (no perms)')
- out = kadmin_as(some_add, ['addprinc'] + args + ['unselected'],
- expected_code=1)
- if 'Operation requires ``add\'\' privilege' not in out:
- fail('addprinc failure (target)')
+ kadmin_as(none, ['addprinc'] + args + ['selected'], expected_code=1,
+ expected_msg="Operation requires ``add'' privilege")
+ kadmin_as(some_add, ['addprinc'] + args + ['unselected'], expected_code=1,
+ expected_msg="Operation requires ``add'' privilege")
realm.addprinc('unselected', 'pw')
kadmin_as(all_delete, ['delprinc', 'unselected'])
realm.addprinc('selected', 'pw')
kadmin_as(some_delete, ['delprinc', 'selected'])
realm.addprinc('unselected', 'pw')
-out = kadmin_as(none, ['delprinc', 'unselected'], expected_code=1)
-if 'Operation requires ``delete\'\' privilege' not in out:
- fail('delprinc failure (no perms)')
-out = kadmin_as(some_delete, ['delprinc', 'unselected'], expected_code=1)
-if 'Operation requires ``delete\'\' privilege' not in out:
- fail('delprinc failure (no target)')
+kadmin_as(none, ['delprinc', 'unselected'], expected_code=1,
+ expected_msg="Operation requires ``delete'' privilege")
+kadmin_as(some_delete, ['delprinc', 'unselected'], expected_code=1,
+ expected_msg="Operation requires ``delete'' privilege")
realm.run([kadminl, 'delprinc', 'unselected'])
-out = kadmin_as(all_inquire, ['getpol', 'minlife'])
-if 'Policy: minlife' not in out:
- fail('getpol success (acl)')
-out = kadmin_as(none, ['getpol', 'minlife'], expected_code=1)
-if 'Operation requires ``get\'\' privilege' not in out:
- fail('getpol failure (no perms)')
+kadmin_as(all_inquire, ['getpol', 'minlife'], expected_msg='Policy: minlife')
+kadmin_as(none, ['getpol', 'minlife'], expected_code=1,
+ expected_msg="Operation requires ``get'' privilege")
realm.run([kadminl, 'modprinc', '-policy', 'minlife', 'none'])
-out = kadmin_as(none, ['getpol', 'minlife'])
-if 'Policy: minlife' not in out:
- fail('getpol success (self policy exemption)')
+kadmin_as(none, ['getpol', 'minlife'], expected_msg='Policy: minlife')
realm.run([kadminl, 'modprinc', '-clearpolicy', 'none'])
realm.addprinc('selected', 'pw')
realm.addprinc('unselected', 'pw')
-out = kadmin_as(all_inquire, ['getprinc', 'unselected'])
-if 'Principal: unselected@KRBTEST.COM' not in out:
- fail('getprinc success (acl)')
-out = kadmin_as(some_inquire, ['getprinc', 'selected'])
-if 'Principal: selected@KRBTEST.COM' not in out:
- fail('getprinc success (target)')
-out = kadmin_as(none, ['getprinc', 'selected'], expected_code=1)
-if 'Operation requires ``get\'\' privilege' not in out:
- fail('getprinc failure (no perms)')
-out = kadmin_as(some_inquire, ['getprinc', 'unselected'], expected_code=1)
-if 'Operation requires ``get\'\' privilege' not in out:
- fail('getprinc failure (target)')
-out = kadmin_as(none, ['getprinc', 'none'])
-if 'Principal: none@KRBTEST.COM' not in out:
- fail('getprinc success (self exemption)')
+kadmin_as(all_inquire, ['getprinc', 'unselected'],
+ expected_msg='Principal: unselected@KRBTEST.COM')
+kadmin_as(some_inquire, ['getprinc', 'selected'],
+ expected_msg='Principal: selected@KRBTEST.COM')
+kadmin_as(none, ['getprinc', 'selected'], expected_code=1,
+ expected_msg="Operation requires ``get'' privilege")
+kadmin_as(some_inquire, ['getprinc', 'unselected'], expected_code=1,
+ expected_msg="Operation requires ``get'' privilege")
+kadmin_as(none, ['getprinc', 'none'],
+ expected_msg='Principal: none@KRBTEST.COM')
realm.run([kadminl, 'delprinc', 'selected'])
realm.run([kadminl, 'delprinc', 'unselected'])
-out = kadmin_as(all_list, ['listprincs'])
-if 'K/M@KRBTEST.COM' not in out:
- fail('listprincs success (acl)')
-out = kadmin_as(none, ['listprincs'], expected_code=1)
-if 'Operation requires ``list\'\' privilege' not in out:
- fail('listprincs failure (no perms)')
+kadmin_as(all_list, ['listprincs'], expected_msg='K/M@KRBTEST.COM')
+kadmin_as(none, ['listprincs'], expected_code=1,
+ expected_msg="Operation requires ``list'' privilege")
realm.addprinc('selected', 'pw')
realm.addprinc('unselected', 'pw')
realm.run([kadminl, 'setstr', 'selected', 'key', 'value'])
realm.run([kadminl, 'setstr', 'unselected', 'key', 'value'])
-out = kadmin_as(all_inquire, ['getstrs', 'unselected'])
-if 'key: value' not in out:
- fail('getstrs success (acl)')
-out = kadmin_as(some_inquire, ['getstrs', 'selected'])
-if 'key: value' not in out:
- fail('getstrs success (target)')
-out = kadmin_as(none, ['getstrs', 'selected'], expected_code=1)
-if 'Operation requires ``get\'\' privilege' not in out:
- fail('getstrs failure (no perms)')
-out = kadmin_as(some_inquire, ['getstrs', 'unselected'], expected_code=1)
-if 'Operation requires ``get\'\' privilege' not in out:
- fail('getstrs failure (target)')
-out = kadmin_as(none, ['getstrs', 'none'])
-if '(No string attributes.)' not in out:
- fail('getstrs success (self exemption)')
+kadmin_as(all_inquire, ['getstrs', 'unselected'], expected_msg='key: value')
+kadmin_as(some_inquire, ['getstrs', 'selected'], expected_msg='key: value')
+kadmin_as(none, ['getstrs', 'selected'], expected_code=1,
+ expected_msg="Operation requires ``get'' privilege")
+kadmin_as(some_inquire, ['getstrs', 'unselected'], expected_code=1,
+ expected_msg="Operation requires ``get'' privilege")
+kadmin_as(none, ['getstrs', 'none'], expected_msg='(No string attributes.)')
realm.run([kadminl, 'delprinc', 'selected'])
realm.run([kadminl, 'delprinc', 'unselected'])
@@ -207,27 +177,21 @@ out = kadmin_as(all_modify, ['modpol', '-maxlife', '1 hour', 'policy'],
expected_code=1)
if 'Operation requires' in out:
fail('modpol success (acl)')
-out = kadmin_as(none, ['modpol', '-maxlife', '1 hour', 'policy'],
- expected_code=1)
-if 'Operation requires ``modify\'\' privilege' not in out:
- fail('modpol failure (no perms)')
+kadmin_as(none, ['modpol', '-maxlife', '1 hour', 'policy'], expected_code=1,
+ expected_msg="Operation requires ``modify'' privilege")
realm.addprinc('selected', 'pw')
realm.addprinc('unselected', 'pw')
kadmin_as(all_modify, ['modprinc', '-maxlife', '1 hour', 'unselected'])
kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'selected'])
kadmin_as(restricted_modify, ['modprinc', '-maxlife', '1 hour', 'unselected'])
-out = realm.run([kadminl, 'getprinc', 'unselected'])
-if 'REQUIRES_PRE_AUTH' not in out:
- fail('addprinc success (restrictions) -- restriction check')
-out = kadmin_as(all_inquire, ['modprinc', '-maxlife', '1 hour', 'selected'],
- expected_code=1)
-if 'Operation requires ``modify\'\' privilege' not in out:
- fail('addprinc failure (no perms)')
-out = kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'unselected'],
- expected_code=1)
-if 'Operation requires' not in out:
- fail('modprinc failure (target)')
+realm.run([kadminl, 'getprinc', 'unselected'],
+ expected_msg='REQUIRES_PRE_AUTH')
+kadmin_as(all_inquire, ['modprinc', '-maxlife', '1 hour', 'selected'],
+ expected_code=1,
+ expected_msg="Operation requires ``modify'' privilege")
+kadmin_as(some_modify, ['modprinc', '-maxlife', '1 hour', 'unselected'],
+ expected_code=1, expected_msg='Operation requires')
realm.run([kadminl, 'delprinc', 'selected'])
realm.run([kadminl, 'delprinc', 'unselected'])
@@ -235,12 +199,10 @@ realm.addprinc('selected', 'pw')
realm.addprinc('unselected', 'pw')
kadmin_as(all_modify, ['purgekeys', 'unselected'])
kadmin_as(some_modify, ['purgekeys', 'selected'])
-out = kadmin_as(none, ['purgekeys', 'selected'], expected_code=1)
-if 'Operation requires ``modify\'\' privilege' not in out:
- fail('purgekeys failure (no perms)')
-out = kadmin_as(some_modify, ['purgekeys', 'unselected'], expected_code=1)
-if 'Operation requires ``modify\'\' privilege' not in out:
- fail('purgekeys failure (target)')
+kadmin_as(none, ['purgekeys', 'selected'], expected_code=1,
+ expected_msg="Operation requires ``modify'' privilege")
+kadmin_as(some_modify, ['purgekeys', 'unselected'], expected_code=1,
+ expected_msg="Operation requires ``modify'' privilege")
kadmin_as(none, ['purgekeys', 'none'])
realm.run([kadminl, 'delprinc', 'selected'])
realm.run([kadminl, 'delprinc', 'unselected'])
@@ -250,36 +212,27 @@ kadmin_as(all_rename, ['renprinc', 'from', 'to'])
realm.run([kadminl, 'renprinc', 'to', 'from'])
kadmin_as(some_rename, ['renprinc', 'from', 'to'])
realm.run([kadminl, 'renprinc', 'to', 'from'])
-out = kadmin_as(all_add, ['renprinc', 'from', 'to'], expected_code=1)
-if 'Operation requires ``delete\'\' privilege' not in out:
- fail('renprinc failure (no delete perms)')
-out = kadmin_as(all_delete, ['renprinc', 'from', 'to'], expected_code=1)
-if 'Operation requires ``add\'\' privilege' not in out:
- fail('renprinc failure (no add perms)')
-out = kadmin_as(some_rename, ['renprinc', 'from', 'notto'], expected_code=1)
-if 'Operation requires ``add\'\' privilege' not in out:
- fail('renprinc failure (new target)')
+kadmin_as(all_add, ['renprinc', 'from', 'to'], expected_code=1,
+ expected_msg="Insufficient authorization for operation")
+kadmin_as(all_delete, ['renprinc', 'from', 'to'], expected_code=1,
+ expected_msg="Insufficient authorization for operation")
+kadmin_as(some_rename, ['renprinc', 'from', 'notto'], expected_code=1,
+ expected_msg="Insufficient authorization for operation")
realm.run([kadminl, 'renprinc', 'from', 'notfrom'])
-out = kadmin_as(some_rename, ['renprinc', 'notfrom', 'to'], expected_code=1)
-if 'Operation requires ``delete\'\' privilege' not in out:
- fail('renprinc failure (old target)')
-out = kadmin_as(restricted_rename, ['renprinc', 'notfrom', 'to'],
- expected_code=1)
-if 'Operation requires ``add\'\' privilege' not in out:
- fail('renprinc failure (restrictions)')
+kadmin_as(some_rename, ['renprinc', 'notfrom', 'to'], expected_code=1,
+ expected_msg="Insufficient authorization for operation")
+kadmin_as(restricted_rename, ['renprinc', 'notfrom', 'to'], expected_code=1,
+ expected_msg="Insufficient authorization for operation")
realm.run([kadminl, 'delprinc', 'notfrom'])
realm.addprinc('selected', 'pw')
realm.addprinc('unselected', 'pw')
kadmin_as(all_modify, ['setstr', 'unselected', 'key', 'value'])
kadmin_as(some_modify, ['setstr', 'selected', 'key', 'value'])
-out = kadmin_as(none, ['setstr', 'selected', 'key', 'value'], expected_code=1)
-if 'Operation requires ``modify\'\' privilege' not in out:
- fail('addprinc failure (no perms)')
-out = kadmin_as(some_modify, ['setstr', 'unselected', 'key', 'value'],
- expected_code=1)
-if 'Operation requires' not in out:
- fail('modprinc failure (target)')
+kadmin_as(none, ['setstr', 'selected', 'key', 'value'], expected_code=1,
+ expected_msg="Operation requires ``modify'' privilege")
+kadmin_as(some_modify, ['setstr', 'unselected', 'key', 'value'],
+ expected_code=1, expected_msg='Operation requires')
realm.run([kadminl, 'delprinc', 'selected'])
realm.run([kadminl, 'delprinc', 'unselected'])
@@ -287,28 +240,21 @@ kadmin_as(admin, ['addprinc', '-pw', 'pw', 'anytarget'])
realm.run([kadminl, 'delprinc', 'anytarget'])
kadmin_as(wctarget, ['addprinc', '-pw', 'pw', 'wild/card'])
realm.run([kadminl, 'delprinc', 'wild/card'])
-out = kadmin_as(wctarget, ['addprinc', '-pw', 'pw', 'wild/card/extra'],
- expected_code=1)
-if 'Operation requires' not in out:
- fail('addprinc failure (target wildcard extra component)')
+kadmin_as(wctarget, ['addprinc', '-pw', 'pw', 'wild/card/extra'],
+ expected_code=1, expected_msg='Operation requires')
realm.addprinc('admin/user', 'pw')
kadmin_as(admin, ['delprinc', 'admin/user'])
-out = kadmin_as(admin, ['delprinc', 'none'], expected_code=1)
-if 'Operation requires' not in out:
- fail('delprinc failure (wildcard backreferences not matched)')
+kadmin_as(admin, ['delprinc', 'none'], expected_code=1,
+ expected_msg='Operation requires')
realm.addprinc('four/one/three', 'pw')
kadmin_as(onetwothreefour, ['delprinc', 'four/one/three'])
kadmin_as(restrictions, ['addprinc', '-pw', 'pw', 'type1'])
-out = realm.run([kadminl, 'getprinc', 'type1'])
-if 'Policy: minlife' not in out:
- fail('restriction (policy)')
+realm.run([kadminl, 'getprinc', 'type1'], expected_msg='Policy: minlife')
realm.run([kadminl, 'delprinc', 'type1'])
kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-policy', 'minlife',
'type2'])
-out = realm.run([kadminl, 'getprinc', 'type2'])
-if 'Policy: [none]' not in out:
- fail('restriction (clearpolicy)')
+realm.run([kadminl, 'getprinc', 'type2'], expected_msg='Policy: [none]')
realm.run([kadminl, 'delprinc', 'type2'])
kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-maxlife', '1 minute',
'type3'])
@@ -319,43 +265,50 @@ if ('Maximum ticket life: 0 days 00:01:00' not in out or
realm.run([kadminl, 'delprinc', 'type3'])
kadmin_as(restrictions, ['addprinc', '-pw', 'pw', '-maxrenewlife', '1 day',
'type3'])
-out = realm.run([kadminl, 'getprinc', 'type3'])
-if 'Maximum renewable life: 0 days 02:00:00' not in out:
- fail('restriction (maxrenewlife high)')
+realm.run([kadminl, 'getprinc', 'type3'],
+ expected_msg='Maximum renewable life: 0 days 02:00:00')
realm.run([kadminl, 'addprinc', '-pw', 'pw', 'extractkeys'])
-out = kadmin_as(all_wildcard, ['ktadd', '-norandkey', 'extractkeys'],
- expected_code=1)
-if 'Operation requires ``extract-keys\'\' privilege' not in out:
- fail('extractkeys failure (all_wildcard)')
+kadmin_as(all_wildcard, ['ktadd', '-norandkey', 'extractkeys'],
+ expected_code=1,
+ expected_msg="Operation requires ``extract-keys'' privilege")
kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'])
realm.kinit('extractkeys', flags=['-k'])
os.remove(realm.keytab)
kadmin_as(all_modify, ['modprinc', '+lockdown_keys', 'extractkeys'])
-out = kadmin_as(all_changepw, ['cpw', '-pw', 'newpw', 'extractkeys'],
- expected_code=1)
-if 'Operation requires ``change-password\'\' privilege' not in out:
- fail('extractkeys failure (all_changepw)')
+kadmin_as(all_changepw, ['cpw', '-pw', 'newpw', 'extractkeys'],
+ expected_code=1,
+ expected_msg="Operation requires ``change-password'' privilege")
kadmin_as(all_changepw, ['cpw', '-randkey', 'extractkeys'])
-out = kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'],
- expected_code=1)
-if 'Operation requires ``extract-keys\'\' privilege' not in out:
- fail('extractkeys failure (all_extract)')
-out = kadmin_as(all_delete, ['delprinc', 'extractkeys'], expected_code=1)
-if 'Operation requires ``delete\'\' privilege' not in out:
- fail('extractkeys failure (all_delete)')
-out = kadmin_as(all_rename, ['renprinc', 'extractkeys', 'renamedprinc'],
- expected_code=1)
-if 'Operation requires ``delete\'\' privilege' not in out:
- fail('extractkeys failure (all_rename)')
-out = kadmin_as(all_modify, ['modprinc', '-lockdown_keys', 'extractkeys'],
- expected_code=1)
-if 'Operation requires ``modify\'\' privilege' not in out:
- fail('extractkeys failure (all_modify)')
+kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'], expected_code=1,
+ expected_msg="Operation requires ``extract-keys'' privilege")
+kadmin_as(all_delete, ['delprinc', 'extractkeys'], expected_code=1,
+ expected_msg="Operation requires ``delete'' privilege")
+kadmin_as(all_rename, ['renprinc', 'extractkeys', 'renamedprinc'],
+ expected_code=1,
+ expected_msg="Operation requires ``delete'' privilege")
+kadmin_as(all_modify, ['modprinc', '-lockdown_keys', 'extractkeys'],
+ expected_code=1,
+ expected_msg="Operation requires ``modify'' privilege")
realm.run([kadminl, 'modprinc', '-lockdown_keys', 'extractkeys'])
kadmin_as(all_extract, ['ktadd', '-norandkey', 'extractkeys'])
realm.kinit('extractkeys', flags=['-k'])
os.remove(realm.keytab)
+# Verify that self-service key changes require an initial ticket.
+realm.run([kadminl, 'cpw', '-pw', password('none'), 'none'])
+realm.run([kadminl, 'modprinc', '+allow_tgs_req', 'kadmin/admin'])
+realm.kinit('none', password('none'))
+realm.run([kvno, 'kadmin/admin'])
+msg = 'Operation requires initial ticket'
+realm.run([kadmin, '-c', realm.ccache, 'cpw', '-pw', 'newpw', 'none'],
+ expected_code=1, expected_msg=msg)
+realm.run([kadmin, '-c', realm.ccache, 'cpw', '-pw', 'newpw',
+ '-e', 'aes256-cts', 'none'], expected_code=1, expected_msg=msg)
+realm.run([kadmin, '-c', realm.ccache, 'cpw', '-randkey', 'none'],
+ expected_code=1, expected_msg=msg)
+realm.run([kadmin, '-c', realm.ccache, 'cpw', '-randkey', '-e', 'aes256-cts',
+ 'none'], expected_code=1, expected_msg=msg)
+
success('kadmin ACL enforcement')
diff --git a/src/tests/t_kadmin_parsing.py b/src/tests/t_kadmin_parsing.py
index 92d72d2b08a8..8de387c647a3 100644
--- a/src/tests/t_kadmin_parsing.py
+++ b/src/tests/t_kadmin_parsing.py
@@ -57,33 +57,27 @@ realm = K5Realm(create_host=False, get_creds=False)
realm.run([kadminl, 'addpol', 'pol'])
for instr, outstr in intervals:
realm.run([kadminl, 'modprinc', '-maxlife', instr, realm.user_princ])
- out = realm.run([kadminl, 'getprinc', realm.user_princ])
- if 'Maximum ticket life: ' + outstr + '\n' not in out:
- fail('princ maxlife: ' + instr)
+ msg = 'Maximum ticket life: ' + outstr + '\n'
+ realm.run([kadminl, 'getprinc', realm.user_princ], expected_msg=msg)
realm.run([kadminl, 'modprinc', '-maxrenewlife', instr, realm.user_princ])
- out = realm.run([kadminl, 'getprinc', realm.user_princ])
- if 'Maximum renewable life: ' + outstr + '\n' not in out:
- fail('princ maxrenewlife: ' + instr)
+ msg = 'Maximum renewable life: ' + outstr + '\n'
+ realm.run([kadminl, 'getprinc', realm.user_princ], expected_msg=msg)
realm.run([kadminl, 'modpol', '-maxlife', instr, 'pol'])
- out = realm.run([kadminl, 'getpol', 'pol'])
- if 'Maximum password life: ' + outstr + '\n' not in out:
- fail('pol maxlife: ' + instr)
+ msg = 'Maximum password life: ' + outstr + '\n'
+ realm.run([kadminl, 'getpol', 'pol'], expected_msg=msg)
realm.run([kadminl, 'modpol', '-minlife', instr, 'pol'])
- out = realm.run([kadminl, 'getpol', 'pol'])
- if 'Minimum password life: ' + outstr + '\n' not in out:
- fail('pol maxlife: ' + instr)
+ msg = 'Minimum password life: ' + outstr + '\n'
+ realm.run([kadminl, 'getpol', 'pol'], expected_msg=msg)
realm.run([kadminl, 'modpol', '-failurecountinterval', instr, 'pol'])
- out = realm.run([kadminl, 'getpol', 'pol'])
- if 'Password failure count reset interval: ' + outstr + '\n' not in out:
- fail('pol maxlife: ' + instr)
+ msg = 'Password failure count reset interval: ' + outstr + '\n'
+ realm.run([kadminl, 'getpol', 'pol'], expected_msg=msg)
realm.run([kadminl, 'modpol', '-lockoutduration', instr, 'pol'])
- out = realm.run([kadminl, 'getpol', 'pol'])
- if 'Password lockout duration: ' + outstr + '\n' not in out:
- fail('pol maxlife: ' + instr)
+ msg = 'Password lockout duration: ' + outstr + '\n'
+ realm.run([kadminl, 'getpol', 'pol'], expected_msg=msg)
success('kadmin command parsing tests')
diff --git a/src/tests/t_kdb.py b/src/tests/t_kdb.py
index 185225afa5a3..217f2cdc3bdc 100755
--- a/src/tests/t_kdb.py
+++ b/src/tests/t_kdb.py
@@ -16,22 +16,27 @@ if (not os.path.exists(os.path.join(plugins, 'kdb', 'kldap.so')) and
if 'SLAPD' not in os.environ and not which('slapd'):
skip_rest('LDAP KDB tests', 'slapd not found')
+slapadd = which('slapadd')
+if not slapadd:
+ skip_rest('LDAP KDB tests', 'slapadd not found')
+
ldapdir = os.path.abspath('ldap')
dbdir = os.path.join(ldapdir, 'ldap')
-slapd_conf = os.path.join(ldapdir, 'slapd.conf')
+slapd_conf = os.path.join(ldapdir, 'slapd.d')
slapd_out = os.path.join(ldapdir, 'slapd.out')
slapd_pidfile = os.path.join(ldapdir, 'pid')
ldap_pwfile = os.path.join(ldapdir, 'pw')
ldap_sock = os.path.join(ldapdir, 'sock')
ldap_uri = 'ldapi://%s/' % ldap_sock.replace(os.path.sep, '%2F')
schema = os.path.join(srctop, 'plugins', 'kdb', 'ldap', 'libkdb_ldap',
- 'kerberos.schema')
+ 'kerberos.openldap.ldif')
top_dn = 'cn=krb5'
admin_dn = 'cn=admin,cn=krb5'
admin_pw = 'admin'
shutil.rmtree(ldapdir, True)
os.mkdir(ldapdir)
+os.mkdir(slapd_conf)
os.mkdir(dbdir)
if 'SLAPD' in os.environ:
@@ -44,32 +49,61 @@ else:
slapd = os.path.join(ldapdir, 'slapd')
shutil.copy(system_slapd, slapd)
-# Find the core schema file if we can.
+def slap_add(ldif):
+ proc = subprocess.Popen([slapadd, '-b', 'cn=config', '-F', slapd_conf],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ (out, dummy) = proc.communicate(ldif)
+ output(out)
+ return proc.wait()
+
+
+# Configure the pid file and some authorization rules we will need for
+# SASL testing.
+if slap_add('dn: cn=config\n'
+ 'objectClass: olcGlobal\n'
+ 'olcPidFile: %s\n'
+ 'olcAuthzRegexp: '
+ '".*uidNumber=%d,cn=peercred,cn=external,cn=auth" "%s"\n'
+ 'olcAuthzRegexp: "uid=digestuser,cn=digest-md5,cn=auth" "%s"\n' %
+ (slapd_pidfile, os.geteuid(), admin_dn, admin_dn)) != 0:
+ skip_rest('LDAP KDB tests', 'slapd basic configuration failed')
+
+# Find a working writable database type, trying mdb (added in OpenLDAP
+# 2.4.27) and bdb (deprecated and sometimes not built due to licensing
+# incompatibilities).
+for dbtype in ('mdb', 'bdb'):
+ # Try to load the module. This could fail if OpenLDAP is built
+ # without module support, so ignore errors.
+ slap_add('dn: cn=module,cn=config\n'
+ 'objectClass: olcModuleList\n'
+ 'olcModuleLoad: back_%s\n' % dbtype)
+
+ dbclass = 'olc%sConfig' % dbtype.capitalize()
+ if slap_add('dn: olcDatabase=%s,cn=config\n'
+ 'objectClass: olcDatabaseConfig\n'
+ 'objectClass: %s\n'
+ 'olcSuffix: %s\n'
+ 'olcRootDN: %s\n'
+ 'olcRootPW: %s\n'
+ 'olcDbDirectory: %s\n' %
+ (dbtype, dbclass, top_dn, admin_dn, admin_pw, dbdir)) == 0:
+ break
+else:
+ skip_rest('LDAP KDB tests', 'could not find working slapd db type')
+
+if slap_add('include: file://%s\n' % schema) != 0:
+ skip_rest('LDAP KDB tests', 'failed to load Kerberos schema')
+
+# Load the core schema if we can.
ldap_homes = ['/etc/ldap', '/etc/openldap', '/usr/local/etc/openldap',
'/usr/local/etc/ldap']
-local_schema_path = '/schema/core.schema'
+local_schema_path = '/schema/core.ldif'
core_schema = next((i for i in imap(lambda x:x+local_schema_path, ldap_homes)
if os.path.isfile(i)), None)
-
-# Make a slapd config file. This is deprecated in OpenLDAP 2.3 and
-# later, but it's easier than using LDIF and slapadd. Include some
-# authz-regexp entries for SASL authentication tests. Load the core
-# schema if we found it, for use in the DIGEST-MD5 test.
-file = open(slapd_conf, 'w')
-file.write('pidfile %s\n' % slapd_pidfile)
-file.write('include %s\n' % schema)
if core_schema:
- file.write('include %s\n' % core_schema)
-file.write('moduleload back_bdb\n')
-file.write('database bdb\n')
-file.write('suffix %s\n' % top_dn)
-file.write('rootdn %s\n' % admin_dn)
-file.write('rootpw %s\n' % admin_pw)
-file.write('directory %s\n' % dbdir)
-file.write('authz-regexp .*uidNumber=%d,cn=peercred,cn=external,cn=auth %s\n' %
- (os.geteuid(), admin_dn))
-file.write('authz-regexp uid=digestuser,cn=digest-md5,cn=auth %s\n' % admin_dn)
-file.close()
+ if slap_add('include: file://%s\n' % core_schema) != 0:
+ core_schema = None
slapd_pid = -1
def kill_slapd():
@@ -80,7 +114,7 @@ def kill_slapd():
atexit.register(kill_slapd)
out = open(slapd_out, 'w')
-subprocess.call([slapd, '-h', ldap_uri, '-f', slapd_conf], stdout=out,
+subprocess.call([slapd, '-h', ldap_uri, '-F', slapd_conf], stdout=out,
stderr=out)
out.close()
pidf = open(slapd_pidfile, 'r')
@@ -167,47 +201,31 @@ if out != 'KRBTEST.COM\n':
# because we're sticking a krbPrincipalAux objectclass onto a subtree
# krbContainer, but it works and it avoids having to load core.schema
# in the test LDAP server.
-out = realm.run([kadminl, 'ank', '-randkey', '-x', 'dn=cn=krb5', 'princ1'],
- expected_code=1)
-if 'DN is out of the realm subtree' not in out:
- fail('Unexpected kadmin.local output for out-of-realm dn')
+realm.run([kadminl, 'ank', '-randkey', '-x', 'dn=cn=krb5', 'princ1'],
+ expected_code=1, expected_msg='DN is out of the realm subtree')
realm.run([kadminl, 'ank', '-randkey', '-x', 'dn=cn=t2,cn=krb5', 'princ1'])
-out = realm.run([kadminl, 'getprinc', 'princ1'])
-if 'Principal: princ1' not in out:
- fail('Unexpected kadmin.local output after creating princ1')
-out = realm.run([kadminl, 'ank', '-randkey', '-x', 'dn=cn=t2,cn=krb5',
- 'again'], expected_code=1)
-if 'ldap object is already kerberized' not in out:
- fail('Unexpected kadmin.local output trying to re-kerberize DN')
+realm.run([kadminl, 'getprinc', 'princ1'], expected_msg='Principal: princ1')
+realm.run([kadminl, 'ank', '-randkey', '-x', 'dn=cn=t2,cn=krb5', 'again'],
+ expected_code=1, expected_msg='ldap object is already kerberized')
# Check that we can't set linkdn on a non-standalone object.
-out = realm.run([kadminl, 'modprinc', '-x', 'linkdn=cn=t1,cn=krb5', 'princ1'],
- expected_code=1)
-if 'link information can not be set' not in out:
- fail('Unexpected kadmin.local output trying to set linkdn on princ1')
+realm.run([kadminl, 'modprinc', '-x', 'linkdn=cn=t1,cn=krb5', 'princ1'],
+ expected_code=1, expected_msg='link information can not be set')
# Create a principal with a specified linkdn.
-out = realm.run([kadminl, 'ank', '-randkey', '-x', 'linkdn=cn=krb5', 'princ2'],
- expected_code=1)
-if 'DN is out of the realm subtree' not in out:
- fail('Unexpected kadmin.local output for out-of-realm linkdn')
+realm.run([kadminl, 'ank', '-randkey', '-x', 'linkdn=cn=krb5', 'princ2'],
+ expected_code=1, expected_msg='DN is out of the realm subtree')
realm.run([kadminl, 'ank', '-randkey', '-x', 'linkdn=cn=t1,cn=krb5', 'princ2'])
# Check that we can't reset linkdn.
-out = realm.run([kadminl, 'modprinc', '-x', 'linkdn=cn=t2,cn=krb5', 'princ2'],
- expected_code=1)
-if 'kerberos principal is already linked' not in out:
- fail('Unexpected kadmin.local output for re-specified linkdn')
+realm.run([kadminl, 'modprinc', '-x', 'linkdn=cn=t2,cn=krb5', 'princ2'],
+ expected_code=1, expected_msg='kerberos principal is already linked')
# Create a principal with a specified containerdn.
-out = realm.run([kadminl, 'ank', '-randkey', '-x', 'containerdn=cn=krb5',
- 'princ3'], expected_code=1)
-if 'DN is out of the realm subtree' not in out:
- fail('Unexpected kadmin.local output for out-of-realm containerdn')
+realm.run([kadminl, 'ank', '-randkey', '-x', 'containerdn=cn=krb5', 'princ3'],
+ expected_code=1, expected_msg='DN is out of the realm subtree')
realm.run([kadminl, 'ank', '-randkey', '-x', 'containerdn=cn=t1,cn=krb5',
'princ3'])
-out = realm.run([kadminl, 'modprinc', '-x', 'containerdn=cn=t2,cn=krb5',
- 'princ3'], expected_code=1)
-if 'containerdn option not supported' not in out:
- fail('Unexpected kadmin.local output trying to reset containerdn')
+realm.run([kadminl, 'modprinc', '-x', 'containerdn=cn=t2,cn=krb5', 'princ3'],
+ expected_code=1, expected_msg='containerdn option not supported')
# Create and modify a ticket policy.
kldaputil(['create_policy', '-maxtktlife', '3hour', '-maxrenewlife', '6hour',
@@ -255,9 +273,8 @@ if out:
kldaputil(['create_policy', 'tktpol2'])
# Try to create a password policy conflicting with a ticket policy.
-out = realm.run([kadminl, 'addpol', 'tktpol2'], expected_code=1)
-if 'Already exists while creating policy "tktpol2"' not in out:
- fail('Expected error not seen in kadmin.local output')
+realm.run([kadminl, 'addpol', 'tktpol2'], expected_code=1,
+ expected_msg='Already exists while creating policy "tktpol2"')
# Try to create a ticket policy conflicting with a password policy.
realm.run([kadminl, 'addpol', 'pwpol'])
@@ -266,16 +283,13 @@ if 'Already exists while creating policy object' not in out:
fail('Expected error not seen in kdb5_ldap_util output')
# Try to use a password policy as a ticket policy.
-out = realm.run([kadminl, 'modprinc', '-x', 'tktpolicy=pwpol', 'princ4'],
- expected_code=1)
-if 'Object class violation' not in out:
- fail('Expected error not seem in kadmin.local output')
+realm.run([kadminl, 'modprinc', '-x', 'tktpolicy=pwpol', 'princ4'],
+ expected_code=1, expected_msg='Object class violation')
# Use a ticket policy as a password policy (CVE-2014-5353). This
# works with a warning; use kadmin.local -q so the warning is shown.
-out = realm.run([kadminl, '-q', 'modprinc -policy tktpol2 princ4'])
-if 'WARNING: policy "tktpol2" does not exist' not in out:
- fail('Expected error not seen in kadmin.local output')
+realm.run([kadminl, '-q', 'modprinc -policy tktpol2 princ4'],
+ expected_msg='WARNING: policy "tktpol2" does not exist')
# Do some basic tests with a KDC against the LDAP module, exercising the
# db_args processing code.
@@ -298,9 +312,8 @@ if 'krbPrincipalAuthInd: otp' not in out:
if 'krbPrincipalAuthInd: radius' not in out:
fail('Expected krbPrincipalAuthInd value not in output')
-out = realm.run([kadminl, 'getstrs', 'authind'])
-if 'require_auth: otp radius' not in out:
- fail('Expected auth indicators value not in output')
+realm.run([kadminl, 'getstrs', 'authind'],
+ expected_msg='require_auth: otp radius')
# Test service principal aliases.
realm.addprinc('canon', password('canon'))
@@ -311,14 +324,11 @@ ldap_modify('dn: krbPrincipalName=canon@KRBTEST.COM,cn=t1,cn=krb5\n'
'-\n'
'add: krbCanonicalName\n'
'krbCanonicalName: canon@KRBTEST.COM\n')
-out = realm.run([kadminl, 'getprinc', 'alias'])
-if 'Principal: canon@KRBTEST.COM\n' not in out:
- fail('Could not fetch canon through alias')
-out = realm.run([kadminl, 'getprinc', 'canon'])
-if 'Principal: canon@KRBTEST.COM\n' not in out:
- fail('Could not fetch canon through canon')
-realm.run([kvno, 'alias'])
-realm.run([kvno, 'canon'])
+realm.run([kadminl, 'getprinc', 'alias'],
+ expected_msg='Principal: canon@KRBTEST.COM\n')
+realm.run([kadminl, 'getprinc', 'canon'],
+ expected_msg='Principal: canon@KRBTEST.COM\n')
+realm.run([kvno, 'alias', 'canon'])
out = realm.run([klist])
if 'alias@KRBTEST.COM\n' not in out or 'canon@KRBTEST.COM' not in out:
fail('After fetching alias and canon, klist is missing one or both')
@@ -334,9 +344,8 @@ ldap_modify('dn: krbPrincipalName=krbtgt/KRBTEST.COM@KRBTEST.COM,'
'-\n'
'add: krbCanonicalName\n'
'krbCanonicalName: krbtgt/KRBTEST.COM@KRBTEST.COM\n')
-out = realm.run([kadminl, 'getprinc', 'tgtalias'])
-if 'Principal: krbtgt/KRBTEST.COM@KRBTEST.COM' not in out:
- fail('Could not fetch krbtgt through tgtalias')
+realm.run([kadminl, 'getprinc', 'tgtalias'],
+ expected_msg='Principal: krbtgt/KRBTEST.COM@KRBTEST.COM')
realm.kinit(realm.user_princ, password('user'))
realm.run([kvno, 'tgtalias'])
realm.klist(realm.user_princ, 'tgtalias@KRBTEST.COM')
@@ -352,9 +361,8 @@ realm.klist(realm.user_princ, 'alias@KRBTEST.COM')
# Test client principal aliases, with and without preauth.
realm.kinit('canon', password('canon'))
-out = realm.kinit('alias', password('canon'), expected_code=1)
-if 'not found in Kerberos database' not in out:
- fail('Wrong error message for kinit to alias without -C flag')
+realm.kinit('alias', password('canon'), expected_code=1,
+ expected_msg='not found in Kerberos database')
realm.kinit('alias', password('canon'), ['-C'])
realm.run([kvno, 'alias'])
realm.klist('canon@KRBTEST.COM', 'alias@KRBTEST.COM')
@@ -413,31 +421,24 @@ realm.run([kadminl, 'addprinc', '-randkey', '-e', 'aes256-cts,aes128-cts',
'kvnoprinc'])
realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e',
'aes256-cts,aes128-cts', 'kvnoprinc'])
-out = realm.run([kadminl, 'getprinc', 'kvnoprinc'])
-if 'Number of keys: 4' not in out:
- fail('After cpw -keepold, wrong number of keys')
+realm.run([kadminl, 'getprinc', 'kvnoprinc'], expected_msg='Number of keys: 4')
realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e',
'aes256-cts,aes128-cts', 'kvnoprinc'])
-out = realm.run([kadminl, 'getprinc', 'kvnoprinc'])
-if 'Number of keys: 6' not in out:
- fail('After cpw -keepold, wrong number of keys')
+realm.run([kadminl, 'getprinc', 'kvnoprinc'], expected_msg='Number of keys: 6')
# Regression test for #8041 (NULL dereference on keyless principals).
realm.run([kadminl, 'addprinc', '-nokey', 'keylessprinc'])
-out = realm.run([kadminl, 'getprinc', 'keylessprinc'])
-if 'Number of keys: 0' not in out:
- fail('Failed to create a principal with no keys')
+realm.run([kadminl, 'getprinc', 'keylessprinc'],
+ expected_msg='Number of keys: 0')
realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes256-cts,aes128-cts',
'keylessprinc'])
realm.run([kadminl, 'cpw', '-randkey', '-keepold', '-e',
'aes256-cts,aes128-cts', 'keylessprinc'])
-out = realm.run([kadminl, 'getprinc', 'keylessprinc'])
-if 'Number of keys: 4' not in out:
- fail('Failed to add keys to keylessprinc')
+realm.run([kadminl, 'getprinc', 'keylessprinc'],
+ expected_msg='Number of keys: 4')
realm.run([kadminl, 'purgekeys', '-all', 'keylessprinc'])
-out = realm.run([kadminl, 'getprinc', 'keylessprinc'])
-if 'Number of keys: 0' not in out:
- fail('After purgekeys -all, keys remain')
+realm.run([kadminl, 'getprinc', 'keylessprinc'],
+ expected_msg='Number of keys: 0')
# Test for 8354 (old password history entries when -keepold is used)
realm.run([kadminl, 'addpol', '-history', '2', 'keepoldpasspol'])
@@ -446,14 +447,20 @@ realm.run([kadminl, 'addprinc', '-policy', 'keepoldpasspol', '-pw', 'aaaa',
for p in ('bbbb', 'cccc', 'aaaa'):
realm.run([kadminl, 'cpw', '-keepold', '-pw', p, 'keepoldpassprinc'])
+if runenv.sizeof_time_t <= 4:
+ skipped('y2038 LDAP test', 'platform has 32-bit time_t')
+else:
+ # Test storage of timestamps after y2038.
+ realm.run([kadminl, 'modprinc', '-pwexpire', '2040-02-03', 'user'])
+ realm.run([kadminl, 'getprinc', 'user'], expected_msg=' 2040\n')
+
realm.stop()
# Briefly test dump and load.
dumpfile = os.path.join(realm.testdir, 'dump')
realm.run([kdb5_util, 'dump', dumpfile])
-out = realm.run([kdb5_util, 'load', dumpfile], expected_code=1)
-if 'KDB module requires -update argument' not in out:
- fail('Unexpected error from kdb5_util load without -update')
+realm.run([kdb5_util, 'load', dumpfile], expected_code=1,
+ expected_msg='KDB module requires -update argument')
realm.run([kdb5_util, 'load', '-update', dumpfile])
# Destroy the realm.
@@ -501,14 +508,10 @@ realm.addprinc(realm.user_princ, password('user'))
realm.kinit(realm.user_princ, password('user'))
realm.stop()
# Exercise DB options, which should cause binding to fail.
-out = realm.run([kadminl, '-x', 'sasl_authcid=ab', 'getprinc', 'user'],
- expected_code=1)
-if 'Cannot bind to LDAP server' not in out:
- fail('Expected error not seen in kadmin.local output')
-out = realm.run([kadminl, '-x', 'bindpwd=wrong', 'getprinc', 'user'],
- expected_code=1)
-if 'Cannot bind to LDAP server' not in out:
- fail('Expected error not seen in kadmin.local output')
+realm.run([kadminl, '-x', 'sasl_authcid=ab', 'getprinc', 'user'],
+ expected_code=1, expected_msg='Cannot bind to LDAP server')
+realm.run([kadminl, '-x', 'bindpwd=wrong', 'getprinc', 'user'],
+ expected_code=1, expected_msg='Cannot bind to LDAP server')
realm.run([kdb5_ldap_util, 'destroy', '-f'])
# We could still use tests to exercise:
diff --git a/src/tests/t_kdb_locking.py b/src/tests/t_kdb_locking.py
index e8d86e09bfd5..aac0a220f424 100755
--- a/src/tests/t_kdb_locking.py
+++ b/src/tests/t_kdb_locking.py
@@ -21,9 +21,8 @@ if not os.path.exists(kadm5_lock):
fail('kadm5 lock file not created: ' + kadm5_lock)
os.unlink(kadm5_lock)
-output = realm.kinit(p, p, [], expected_code=1)
-if 'A service is not available' not in output:
- fail('krb5kdc should have returned service not available error')
+realm.kinit(p, p, [], expected_code=1,
+ expected_msg='A service is not available')
f = open(kadm5_lock, 'w')
f.close()
diff --git a/src/tests/t_kdcpolicy.py b/src/tests/t_kdcpolicy.py
new file mode 100644
index 000000000000..5b198bb430c5
--- /dev/null
+++ b/src/tests/t_kdcpolicy.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+from k5test import *
+from datetime import datetime
+import re
+
+testpreauth = os.path.join(buildtop, 'plugins', 'preauth', 'test', 'test.so')
+testpolicy = os.path.join(buildtop, 'plugins', 'kdcpolicy', 'test',
+ 'kdcpolicy_test.so')
+krb5_conf = {'plugins': {'kdcpreauth': {'module': 'test:' + testpreauth},
+ 'clpreauth': {'module': 'test:' + testpreauth},
+ 'kdcpolicy': {'module': 'test:' + testpolicy}}}
+kdc_conf = {'realms': {'$realm': {'default_principal_flags': '+preauth',
+ 'max_renewable_life': '1d'}}}
+realm = K5Realm(krb5_conf=krb5_conf, kdc_conf=kdc_conf)
+
+realm.run([kadminl, 'addprinc', '-pw', password('fail'), 'fail'])
+
+def verify_time(out, target_time):
+ times = re.findall(r'\d\d/\d\d/\d\d \d\d:\d\d:\d\d', out)
+ times = [datetime.strptime(t, '%m/%d/%y %H:%M:%S') for t in times]
+ divisor = 1
+ while len(times) > 0:
+ starttime = times.pop(0)
+ endtime = times.pop(0)
+ renewtime = times.pop(0)
+
+ if str((endtime - starttime) * divisor) != target_time:
+ fail('unexpected lifetime value')
+ if str((renewtime - endtime) * divisor) != target_time:
+ fail('unexpected renewable value')
+
+ # Service tickets should have half the lifetime of initial
+ # tickets.
+ divisor = 2
+
+rflags = ['-r', '1d', '-l', '12h']
+
+# Test AS+TGS success path.
+realm.kinit(realm.user_princ, password('user'),
+ rflags + ['-X', 'indicators=SEVEN_HOURS'])
+realm.run([kvno, realm.host_princ])
+realm.run(['./adata', realm.host_princ], expected_msg='+97: [SEVEN_HOURS]')
+out = realm.run([klist, '-e', realm.ccache])
+verify_time(out, '7:00:00')
+
+# Test AS+TGS success path with different values.
+realm.kinit(realm.user_princ, password('user'),
+ rflags + ['-X', 'indicators=ONE_HOUR'])
+realm.run([kvno, realm.host_princ])
+realm.run(['./adata', realm.host_princ], expected_msg='+97: [ONE_HOUR]')
+out = realm.run([klist, '-e', realm.ccache])
+verify_time(out, '1:00:00')
+
+# Test TGS failure path (using previous creds).
+realm.run([kvno, 'fail@%s' % realm.realm], expected_code=1,
+ expected_msg='KDC policy rejects request')
+
+# Test AS failure path.
+realm.kinit('fail@%s' % realm.realm, password('fail'),
+ expected_code=1, expected_msg='KDC policy rejects request')
+
+success('kdcpolicy tests')
diff --git a/src/tests/t_keydata.py b/src/tests/t_keydata.py
index 686e543bd4dd..5c04a8523f08 100755
--- a/src/tests/t_keydata.py
+++ b/src/tests/t_keydata.py
@@ -5,27 +5,19 @@ realm = K5Realm(create_user=False, create_host=False)
# Create a principal with no keys.
realm.run([kadminl, 'addprinc', '-nokey', 'user'])
-out = realm.run([kadminl, 'getprinc', 'user'])
-if 'Number of keys: 0' not in out:
- fail('getprinc (addprinc -nokey)')
+realm.run([kadminl, 'getprinc', 'user'], expected_msg='Number of keys: 0')
# Change its password and check the resulting kvno.
realm.run([kadminl, 'cpw', '-pw', 'password', 'user'])
-out = realm.run([kadminl, 'getprinc', 'user'])
-if 'vno 1' not in out:
- fail('getprinc (cpw -pw)')
+realm.run([kadminl, 'getprinc', 'user'], expected_msg='vno 1')
# Delete all of its keys.
realm.run([kadminl, 'purgekeys', '-all', 'user'])
-out = realm.run([kadminl, 'getprinc', 'user'])
-if 'Number of keys: 0' not in out:
- fail('getprinc (purgekeys)')
+realm.run([kadminl, 'getprinc', 'user'], expected_msg='Number of keys: 0')
# Randomize its keys and check the resulting kvno.
realm.run([kadminl, 'cpw', '-randkey', 'user'])
-out = realm.run([kadminl, 'getprinc', 'user'])
-if 'vno 1' not in out:
- fail('getprinc (cpw -randkey)')
+realm.run([kadminl, 'getprinc', 'user'], expected_msg='vno 1')
# Return true if patype appears to have been received in a hint list
# from a KDC error message, based on the trace file fname.
diff --git a/src/tests/t_keyrollover.py b/src/tests/t_keyrollover.py
index 35d0b61b8056..bfd38914b7a0 100755
--- a/src/tests/t_keyrollover.py
+++ b/src/tests/t_keyrollover.py
@@ -23,25 +23,17 @@ realm.run([kvno, princ1])
realm.run([kadminl, 'purgekeys', realm.krbtgt_princ])
# Make sure an old TGT fails after purging old TGS key.
realm.run([kvno, princ2], expected_code=1)
-output = realm.run([klist, '-e'])
-
-expected = 'krbtgt/%s@%s\n\tEtype (skey, tkt): des-cbc-crc, des-cbc-crc' % \
+msg = 'krbtgt/%s@%s\n\tEtype (skey, tkt): des-cbc-crc, des-cbc-crc' % \
(realm.realm, realm.realm)
-
-if expected not in output:
- fail('keyrollover: expected TGS enctype not found')
+realm.run([klist, '-e'], expected_msg=msg)
# Check that new key actually works.
realm.kinit(realm.user_princ, password('user'))
realm.run([kvno, realm.host_princ])
-output = realm.run([klist, '-e'])
-
-expected = 'krbtgt/%s@%s\n\tEtype (skey, tkt): ' \
+msg = 'krbtgt/%s@%s\n\tEtype (skey, tkt): ' \
'aes256-cts-hmac-sha1-96, aes256-cts-hmac-sha1-96' % \
(realm.realm, realm.realm)
-
-if expected not in output:
- fail('keyrollover: expected TGS enctype not found after change')
+realm.run([klist, '-e'], expected_msg=msg)
# Test that the KDC only accepts the first enctype for a kvno, for a
# local-realm TGS request. To set this up, we abuse an edge-case
diff --git a/src/tests/t_keytab.py b/src/tests/t_keytab.py
index a06e6c29653d..a48740ba532a 100755
--- a/src/tests/t_keytab.py
+++ b/src/tests/t_keytab.py
@@ -14,9 +14,8 @@ realm.run([ktutil], input=('rkt %s\ndelent 1\nwkt %s\n' %
realm.kinit(realm.host_princ, flags=['-k', '-t', pkeytab])
# Test kinit with no keys for client in keytab.
-output = realm.kinit(realm.user_princ, flags=['-k'], expected_code=1)
-if 'no suitable keys' not in output:
- fail('Expected error not seen in kinit output')
+realm.kinit(realm.user_princ, flags=['-k'], expected_code=1,
+ expected_msg='no suitable keys')
# Test kinit and klist with client keytab defaults.
realm.extract_keytab(realm.user_princ, realm.client_keytab);
@@ -31,14 +30,12 @@ if realm.client_keytab not in out or realm.user_princ not in out:
# Test implicit request for keytab (-i or -t without -k)
realm.run([kdestroy])
-output = realm.kinit(realm.host_princ, flags=['-t', realm.keytab])
-if 'keytab specified, forcing -k' not in output:
- fail('Expected output not seen from kinit -t keytab')
+realm.kinit(realm.host_princ, flags=['-t', realm.keytab],
+ expected_msg='keytab specified, forcing -k')
realm.klist(realm.host_princ)
realm.run([kdestroy])
-output = realm.kinit(realm.user_princ, flags=['-i'])
-if 'keytab specified, forcing -k' not in output:
- fail('Expected output not seen from kinit -i')
+realm.kinit(realm.user_princ, flags=['-i'],
+ expected_msg='keytab specified, forcing -k')
realm.klist(realm.user_princ)
# Test extracting keys with multiple key versions present.
@@ -70,12 +67,10 @@ def test_key_rotate(realm, princ, expected_kvno):
realm.run_kadmin(['ktadd', '-k', realm.keytab, princ])
realm.run([kadminl, 'ktrem', princ, 'old'])
realm.kinit(princ, flags=['-k'])
- out = realm.run([klist, '-k'])
- if ('%d %s' % (expected_kvno, princ)) not in out:
- fail('kvno %d not listed in keytab' % expected_kvno)
- out = realm.run_kadmin(['getprinc', princ])
- if ('Key: vno %d,' % expected_kvno) not in out:
- fail('vno %d not seen in getprinc output' % expected_kvno)
+ msg = '%d %s' % (expected_kvno, princ)
+ out = realm.run([klist, '-k'], expected_msg=msg)
+ msg = 'Key: vno %d,' % expected_kvno
+ out = realm.run_kadmin(['getprinc', princ], expected_msg=msg)
princ = 'foo/bar@%s' % realm.realm
realm.addprinc(princ)
@@ -109,9 +104,8 @@ f = open(realm.keytab, 'w')
f.write('\x05\x02\x00\x00\x00' + chr(len(record)))
f.write(record)
f.close()
-out = realm.run([klist, '-k'])
-if (' 2 %s' % realm.user_princ) not in out:
- fail('Expected entry not seen in klist -k output')
+msg = ' 2 %s' % realm.user_princ
+out = realm.run([klist, '-k'], expected_msg=msg)
# Make sure zero-fill isn't treated as a 32-bit kvno.
f = open(realm.keytab, 'w')
@@ -119,9 +113,8 @@ f.write('\x05\x02\x00\x00\x00' + chr(len(record) + 4))
f.write(record)
f.write('\x00\x00\x00\x00')
f.close()
-out = realm.run([klist, '-k'])
-if (' 2 %s' % realm.user_princ) not in out:
- fail('Expected entry not seen in klist -k output')
+msg = ' 2 %s' % realm.user_princ
+out = realm.run([klist, '-k'], expected_msg=msg)
# Make sure a hand-crafted 32-bit kvno is recognized.
f = open(realm.keytab, 'w')
@@ -129,9 +122,8 @@ f.write('\x05\x02\x00\x00\x00' + chr(len(record) + 4))
f.write(record)
f.write('\x00\x00\x00\x03')
f.close()
-out = realm.run([klist, '-k'])
-if (' 3 %s' % realm.user_princ) not in out:
- fail('Expected entry not seen in klist -k output')
+msg = ' 3 %s' % realm.user_princ
+out = realm.run([klist, '-k'], expected_msg=msg)
# Test parameter expansion in profile variables
realm.stop()
@@ -142,11 +134,9 @@ realm = K5Realm(krb5_conf=conf, create_kdb=False)
del realm.env['KRB5_KTNAME']
del realm.env['KRB5_CLIENT_KTNAME']
uidstr = str(os.getuid())
-out = realm.run([klist, '-k'], expected_code=1)
-if 'FILE:testdir/abc%s' % uidstr not in out:
- fail('Wrong keytab in klist -k output')
-out = realm.run([klist, '-ki'], expected_code=1)
-if 'FILE:testdir/xyz%s' % uidstr not in out:
- fail('Wrong keytab in klist -ki output')
+msg = 'FILE:testdir/abc%s' % uidstr
+out = realm.run([klist, '-k'], expected_code=1, expected_msg=msg)
+msg = 'FILE:testdir/xyz%s' % uidstr
+out = realm.run([klist, '-ki'], expected_code=1, expected_msg=msg)
success('Keytab-related tests')
diff --git a/src/tests/t_kprop.py b/src/tests/t_kprop.py
index 02cdfeec245f..39169675d6c4 100755
--- a/src/tests/t_kprop.py
+++ b/src/tests/t_kprop.py
@@ -43,9 +43,7 @@ for realm in multipass_realms(create_user=False):
realm.run([kprop, '-f', dumpfile, '-P', str(realm.kprop_port()), hostname])
check_output(kpropd)
- out = realm.run([kadminl, 'listprincs'], slave)
- if 'wakawaka' not in out:
- fail('Slave does not have all principals from master')
+ realm.run([kadminl, 'listprincs'], slave, expected_msg='wakawaka')
# default_realm tests follow.
# default_realm and domain_realm different than realm.realm (test -r argument).
@@ -79,9 +77,8 @@ realm.run([kdb5_util, 'dump', dumpfile])
realm.run([kprop, '-r', realm.realm, '-f', dumpfile, '-P',
str(realm.kprop_port()), hostname])
check_output(kpropd)
-out = realm.run([kadminl, '-r', realm.realm, 'listprincs'], slave2)
-if 'wakawaka' not in out:
- fail('Slave does not have all principals from master')
+realm.run([kadminl, '-r', realm.realm, 'listprincs'], slave2,
+ expected_msg='wakawaka')
stop_daemon(kpropd)
@@ -90,8 +87,6 @@ kpropd = realm.start_kpropd(slave3, ['-d'])
realm.run([kdb5_util, 'dump', dumpfile])
realm.run([kprop, '-f', dumpfile, '-P', str(realm.kprop_port()), hostname])
check_output(kpropd)
-out = realm.run([kadminl, 'listprincs'], slave3)
-if 'wakawaka' not in out:
- fail('Slave does not have all principals from master')
+realm.run([kadminl, 'listprincs'], slave3, expected_msg='wakawaka')
success('kprop tests')
diff --git a/src/tests/t_localauth.py b/src/tests/t_localauth.py
index 4590485ac55d..aa625d038f38 100755
--- a/src/tests/t_localauth.py
+++ b/src/tests/t_localauth.py
@@ -14,9 +14,8 @@ def test_an2ln(env, aname, result, msg):
fail(msg)
def test_an2ln_err(env, aname, err, msg):
- out = realm.run(['./localauth', aname], env=env, expected_code=1)
- if err not in out:
- fail(msg)
+ realm.run(['./localauth', aname], env=env, expected_code=1,
+ expected_msg=err)
def test_userok(env, aname, lname, ok, msg):
out = realm.run(['./localauth', aname, lname], env=env)
diff --git a/src/tests/t_mkey.py b/src/tests/t_mkey.py
index c53b71b45ca4..615cd91cac6e 100755
--- a/src/tests/t_mkey.py
+++ b/src/tests/t_mkey.py
@@ -92,9 +92,8 @@ def check_stash(*expected):
# Verify that the user principal has the expected mkvno.
def check_mkvno(princ, expected_mkvno):
- out = realm.run([kadminl, 'getprinc', princ])
- if ('MKey: vno %d\n' % expected_mkvno) not in out:
- fail('Unexpected mkvno in user DB entry')
+ msg = 'MKey: vno %d\n' % expected_mkvno
+ realm.run([kadminl, 'getprinc', princ], expected_msg=msg)
# Change the password using either kadmin.local or kadmin, then check
@@ -160,9 +159,8 @@ check_mkvno(realm.user_princ, 1)
collisionfile = os.path.join(realm.testdir, 'stash_tmp')
f = open(collisionfile, 'w')
f.close()
-output = realm.run([kdb5_util, 'stash'], expected_code=1)
-if 'Temporary stash file already exists' not in output:
- fail('Did not detect temp stash file collision')
+realm.run([kdb5_util, 'stash'], expected_code=1,
+ expected_msg='Temporary stash file already exists')
os.unlink(collisionfile)
# Add a new master key with no options. Verify that:
@@ -179,9 +177,8 @@ change_password_check_mkvno(True, realm.user_princ, 'abcd', 1)
change_password_check_mkvno(False, realm.user_princ, 'user', 1)
# Verify that use_mkey won't make all master keys inactive.
-out = realm.run([kdb5_util, 'use_mkey', '1', 'now+1day'], expected_code=1)
-if 'there must be one master key currently active' not in out:
- fail('Unexpected error from use_mkey making all mkeys inactive')
+realm.run([kdb5_util, 'use_mkey', '1', 'now+1day'], expected_code=1,
+ expected_msg='there must be one master key currently active')
check_mkey_list((2, defetype, False, False), (1, defetype, True, True))
# Make the new master key active. Verify that:
@@ -194,9 +191,8 @@ change_password_check_mkvno(True, realm.user_princ, 'abcd', 2)
change_password_check_mkvno(False, realm.user_princ, 'user', 2)
# Check purge_mkeys behavior with both master keys still in use.
-out = realm.run([kdb5_util, 'purge_mkeys', '-f', '-v'])
-if 'All keys in use, nothing purged.' not in out:
- fail('Unexpected output from purge_mkeys with both mkeys in use')
+realm.run([kdb5_util, 'purge_mkeys', '-f', '-v'],
+ expected_msg='All keys in use, nothing purged.')
# Do an update_princ_encryption dry run and for real. Verify that:
# 1. The target master key is 2 (the active mkvno).
@@ -226,9 +222,8 @@ update_princ_encryption(False, 2, nprincs - 1, 0)
check_mkvno(realm.user_princ, 2)
# Test the safety check for purging with an outdated stash file.
-out = realm.run([kdb5_util, 'purge_mkeys', '-f'], expected_code=1)
-if 'stash file needs updating' not in out:
- fail('Unexpected error from purge_mkeys safety check')
+realm.run([kdb5_util, 'purge_mkeys', '-f'], expected_code=1,
+ expected_msg='stash file needs updating')
# Update the master stash file and check it. Save a copy of the old
# one for a later test.
@@ -253,18 +248,15 @@ check_mkey_list((2, defetype, True, True))
check_master_dbent(2, (2, defetype))
os.rename(stash_file, stash_file + '.save')
os.rename(stash_file + '.old', stash_file)
-out = realm.run([kadminl, 'getprinc', 'user'], expected_code=1)
-if 'Unable to decrypt latest master key' not in out:
- fail('Unexpected error from kadmin.local with old stash file')
+realm.run([kadminl, 'getprinc', 'user'], expected_code=1,
+ expected_msg='Unable to decrypt latest master key')
os.rename(stash_file + '.save', stash_file)
realm.run([kdb5_util, 'stash'])
check_stash((2, defetype))
-out = realm.run([kdb5_util, 'use_mkey', '1'], expected_code=1)
-if '1 is an invalid KVNO value' not in out:
- fail('Unexpected error from use_mkey with invalid kvno')
-out = realm.run([kdb5_util, 'purge_mkeys', '-f', '-v'])
-if 'There is only one master key which can not be purged.' not in out:
- fail('Unexpected output from purge_mkeys with one mkey')
+realm.run([kdb5_util, 'use_mkey', '1'], expected_code=1,
+ expected_msg='1 is an invalid KVNO value')
+realm.run([kdb5_util, 'purge_mkeys', '-f', '-v'],
+ expected_msg='There is only one master key which can not be purged.')
# Add a third master key with a specified enctype. Verify that:
# 1. The new master key receives the correct number.
@@ -331,8 +323,7 @@ check_mkey_list((2, defetype, True, True), (1, des3, True, False))
# Regression test for #8395. Purge the master key and verify that a
# master key fetch does not segfault.
realm.run([kadminl, 'purgekeys', '-all', 'K/M'])
-out = realm.run([kadminl, 'getprinc', realm.user_princ], expected_code=1)
-if 'Cannot find master key record in database' not in out:
- fail('Unexpected output from failed master key fetch')
+realm.run([kadminl, 'getprinc', realm.user_princ], expected_code=1,
+ expected_msg='Cannot find master key record in database')
success('Master key rollover tests')
diff --git a/src/tests/t_otp.py b/src/tests/t_otp.py
index f098374f9e61..9b18ff94b9cc 100755
--- a/src/tests/t_otp.py
+++ b/src/tests/t_otp.py
@@ -199,9 +199,8 @@ realm.run([kadminl, 'setstr', realm.user_princ, 'otp', otpconfig('udp')])
realm.kinit(realm.user_princ, 'accept', flags=flags)
verify(daemon, queue, True, realm.user_princ.split('@')[0], 'accept')
realm.extract_keytab(realm.krbtgt_princ, realm.keytab)
-out = realm.run(['./adata', realm.krbtgt_princ])
-if '+97: [indotp1, indotp2]' not in out:
- fail('auth indicators not seen in OTP ticket')
+realm.run(['./adata', realm.krbtgt_princ],
+ expected_msg='+97: [indotp1, indotp2]')
# Repeat with an indicators override in the string attribute.
daemon = UDPRadiusDaemon(args=(server_addr, secret_file, 'accept', queue))
@@ -212,9 +211,8 @@ realm.run([kadminl, 'setstr', realm.user_princ, 'otp', oconf])
realm.kinit(realm.user_princ, 'accept', flags=flags)
verify(daemon, queue, True, realm.user_princ.split('@')[0], 'accept')
realm.extract_keytab(realm.krbtgt_princ, realm.keytab)
-out = realm.run(['./adata', realm.krbtgt_princ])
-if '+97: [indtok1, indtok2]' not in out:
- fail('auth indicators not seen in OTP ticket')
+realm.run(['./adata', realm.krbtgt_princ],
+ expected_msg='+97: [indtok1, indtok2]')
# Detect upstream pyrad bug
# https://github.com/wichert/pyrad/pull/18
diff --git a/src/tests/t_pkinit.py b/src/tests/t_pkinit.py
index 526473b429f8..b790a7cda071 100755
--- a/src/tests/t_pkinit.py
+++ b/src/tests/t_pkinit.py
@@ -23,6 +23,10 @@ privkey_pem = os.path.join(certs, 'privkey.pem')
privkey_enc_pem = os.path.join(certs, 'privkey-enc.pem')
user_p12 = os.path.join(certs, 'user.p12')
user_enc_p12 = os.path.join(certs, 'user-enc.p12')
+user_upn_p12 = os.path.join(certs, 'user-upn.p12')
+user_upn2_p12 = os.path.join(certs, 'user-upn2.p12')
+user_upn3_p12 = os.path.join(certs, 'user-upn3.p12')
+generic_p12 = os.path.join(certs, 'generic.p12')
path = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs')
path_enc = os.path.join(os.getcwd(), 'testdir', 'tmp-pkinit-certs-enc')
@@ -36,6 +40,20 @@ pkinit_kdc_conf = {'realms': {'$realm': {
restrictive_kdc_conf = {'realms': {'$realm': {
'restrict_anonymous_to_tgt': 'true' }}}
+testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'},
+ 'user': {'keys': 'aes128-cts', 'flags': '+preauth'},
+ 'user2': {'keys': 'aes128-cts', 'flags': '+preauth'}}
+alias_kdc_conf = {'realms': {'$realm': {
+ 'default_principal_flags': '+preauth',
+ 'pkinit_eku_checking': 'none',
+ 'pkinit_allow_upn': 'true',
+ 'pkinit_identity': 'FILE:%s,%s' % (kdc_pem, privkey_pem),
+ 'database_module': 'test'}},
+ 'dbmodules': {'test': {
+ 'db_library': 'test',
+ 'alias': {'user@krbtest.com': 'user'},
+ 'princs': testprincs}}}
+
file_identity = 'FILE:%s,%s' % (user_pem, privkey_pem)
file_enc_identity = 'FILE:%s,%s' % (user_pem, privkey_enc_pem)
dir_identity = 'DIR:%s' % path
@@ -45,11 +63,51 @@ dir_file_identity = 'FILE:%s,%s' % (os.path.join(path, 'user.crt'),
dir_file_enc_identity = 'FILE:%s,%s' % (os.path.join(path_enc, 'user.crt'),
os.path.join(path_enc, 'user.key'))
p12_identity = 'PKCS12:%s' % user_p12
+p12_upn_identity = 'PKCS12:%s' % user_upn_p12
+p12_upn2_identity = 'PKCS12:%s' % user_upn2_p12
+p12_upn3_identity = 'PKCS12:%s' % user_upn3_p12
+p12_generic_identity = 'PKCS12:%s' % generic_p12
p12_enc_identity = 'PKCS12:%s' % user_enc_p12
p11_identity = 'PKCS11:soft-pkcs11.so'
p11_token_identity = ('PKCS11:module_name=soft-pkcs11.so:'
'slotid=1:token=SoftToken (token)')
+# Start a realm with the test kdb module for the following UPN SAN tests.
+realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=alias_kdc_conf,
+ create_kdb=False)
+realm.start_kdc()
+
+# Compatibility check: cert contains UPN "user", which matches the
+# request principal user@KRBTEST.COM if parsed as a normal principal.
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p12_upn2_identity])
+
+# Compatibility check: cert contains UPN "user@KRBTEST.COM", which matches
+# the request principal user@KRBTEST.COM if parsed as a normal principal.
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p12_upn3_identity])
+
+# Cert contains UPN "user@krbtest.com" which is aliased to the request
+# principal.
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p12_upn_identity])
+
+# Test an id-pkinit-san match to a post-canonical principal.
+realm.kinit('user@krbtest.com',
+ flags=['-E', '-X', 'X509_user_identity=%s' % p12_identity])
+
+# Test a UPN match to a post-canonical principal. (This only works
+# for the cert with the UPN containing just "user", as we don't allow
+# UPN reparsing when comparing to the canonicalized client principal.)
+realm.kinit('user@krbtest.com',
+ flags=['-E', '-X', 'X509_user_identity=%s' % p12_upn2_identity])
+
+# Test a mismatch.
+msg = 'kinit: Client name mismatch while getting initial credentials'
+realm.run([kinit, '-X', 'X509_user_identity=%s' % p12_upn2_identity, 'user2'],
+ expected_code=1, expected_msg=msg)
+realm.stop()
+
realm = K5Realm(krb5_conf=pkinit_krb5_conf, kdc_conf=pkinit_kdc_conf,
get_creds=False)
@@ -61,9 +119,8 @@ realm.klist(realm.user_princ)
realm.run([kvno, realm.host_princ])
# Test anonymous PKINIT.
-out = realm.kinit('@%s' % realm.realm, flags=['-n'], expected_code=1)
-if 'not found in Kerberos database' not in out:
- fail('Wrong error for anonymous PKINIT without anonymous enabled')
+realm.kinit('@%s' % realm.realm, flags=['-n'], expected_code=1,
+ expected_msg='not found in Kerberos database')
realm.addprinc('WELLKNOWN/ANONYMOUS')
realm.kinit('@%s' % realm.realm, flags=['-n'])
realm.klist('WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS')
@@ -78,9 +135,8 @@ f.write('WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS a *')
f.close()
realm.start_kadmind()
realm.run([kadmin, '-n', 'addprinc', '-pw', 'test', 'testadd'])
-out = realm.run([kadmin, '-n', 'getprinc', 'testadd'], expected_code=1)
-if "Operation requires ``get'' privilege" not in out:
- fail('Anonymous kadmin has too much privilege')
+realm.run([kadmin, '-n', 'getprinc', 'testadd'], expected_code=1,
+ expected_msg="Operation requires ``get'' privilege")
realm.stop_kadmind()
# Test with anonymous restricted; FAST should work but kvno should fail.
@@ -89,9 +145,8 @@ realm.stop_kdc()
realm.start_kdc(env=r_env)
realm.kinit('@%s' % realm.realm, flags=['-n'])
realm.kinit('@%s' % realm.realm, flags=['-n', '-T', realm.ccache])
-out = realm.run([kvno, realm.host_princ], expected_code=1)
-if 'KDC policy rejects request' not in out:
- fail('Wrong error for restricted anonymous PKINIT')
+realm.run([kvno, realm.host_princ], expected_code=1,
+ expected_msg='KDC policy rejects request')
# Regression test for #8458: S4U2Self requests crash the KDC if
# anonymous is restricted.
@@ -117,6 +172,29 @@ realm.kinit(realm.user_princ,
'-X', 'flag_RSA_PROTOCOL=yes'])
realm.klist(realm.user_princ)
+# Test a DH parameter renegotiation by temporarily setting a 4096-bit
+# minimum on the KDC. (Preauth type 16 is PKINIT PA_PK_AS_REQ;
+# 109 is PKINIT TD_DH_PARAMETERS; 133 is FAST PA-FX-COOKIE.)
+minbits_kdc_conf = {'realms': {'$realm': {'pkinit_dh_min_bits': '4096'}}}
+minbits_env = realm.special_env('restrict', True, kdc_conf=minbits_kdc_conf)
+realm.stop_kdc()
+realm.start_kdc(env=minbits_env)
+expected_trace = ('Sending unauthenticated request',
+ '/Additional pre-authentication required',
+ 'Preauthenticating using KDC method data',
+ 'Preauth module pkinit (16) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, 16',
+ '/Key parameters not accepted',
+ 'Preauth tryagain input types (16): 109, 133',
+ 'trying again with KDC-provided parameters',
+ 'Preauth module pkinit (16) tryagain returned: 0/Success',
+ 'Followup preauth for next request: 16, 133')
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % file_identity],
+ expected_trace=expected_trace)
+realm.stop_kdc()
+realm.start_kdc()
+
# Run the basic test - PKINIT with FILE: identity, with a password on the key,
# supplied by the prompter.
# Expect failure if the responder does nothing, and we have no prompter.
@@ -128,9 +206,8 @@ realm.kinit(realm.user_princ,
password='encrypted')
realm.klist(realm.user_princ)
realm.run([kvno, realm.host_princ])
-out = realm.run(['./adata', realm.host_princ])
-if '+97: [indpkinit1, indpkinit2]' not in out:
- fail('auth indicators not seen in PKINIT ticket')
+realm.run(['./adata', realm.host_princ],
+ expected_msg='+97: [indpkinit1, indpkinit2]')
# Run the basic test - PKINIT with FILE: identity, with a password on the key,
# supplied by the responder.
@@ -217,6 +294,51 @@ realm.run(['./responder', '-X', 'X509_user_identity=%s' % p12_enc_identity,
realm.klist(realm.user_princ)
realm.run([kvno, realm.host_princ])
+# Match a single rule.
+rule = '<SAN>^user@KRBTEST.COM$'
+realm.run([kadminl, 'setstr', realm.user_princ, 'pkinit_cert_match', rule])
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p12_identity])
+realm.klist(realm.user_princ)
+
+# Match a combined rule (default prefix is &&).
+rule = '<SUBJECT>CN=user$<KU>digitalSignature,keyEncipherment'
+realm.run([kadminl, 'setstr', realm.user_princ, 'pkinit_cert_match', rule])
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p12_identity])
+realm.klist(realm.user_princ)
+
+# Fail an && rule.
+rule = '&&<SUBJECT>O=OTHER.COM<SAN>^user@KRBTEST.COM$'
+realm.run([kadminl, 'setstr', realm.user_princ, 'pkinit_cert_match', rule])
+msg = 'kinit: Certificate mismatch while getting initial credentials'
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p12_identity],
+ expected_code=1, expected_msg=msg)
+
+# Pass an || rule.
+rule = '||<SUBJECT>O=KRBTEST.COM<SAN>^otheruser@KRBTEST.COM$'
+realm.run([kadminl, 'setstr', realm.user_princ, 'pkinit_cert_match', rule])
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p12_identity])
+realm.klist(realm.user_princ)
+
+# Fail an || rule.
+rule = '||<SUBJECT>O=OTHER.COM<SAN>^otheruser@KRBTEST.COM$'
+realm.run([kadminl, 'setstr', realm.user_princ, 'pkinit_cert_match', rule])
+msg = 'kinit: Certificate mismatch while getting initial credentials'
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p12_identity],
+ expected_code=1, expected_msg=msg)
+
+# Authorize a client cert with no PKINIT extensions using subject and
+# issuer. (Relies on EKU checking being turned off.)
+rule = '&&<SUBJECT>CN=user$<ISSUER>O=MIT,'
+realm.run([kadminl, 'setstr', realm.user_princ, 'pkinit_cert_match', rule])
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p12_generic_identity])
+realm.klist(realm.user_princ)
+
if not have_soft_pkcs11:
skip_rest('PKINIT PKCS11 tests', 'soft-pkcs11.so not found')
@@ -251,6 +373,14 @@ realm.kinit(realm.user_princ,
realm.klist(realm.user_princ)
realm.run([kvno, realm.host_princ])
+# Supply the wrong PIN, and verify that we ignore the draft9 padata offer
+# in the KDC method data after RFC 4556 PKINIT fails.
+expected_trace = ('PKINIT client has no configured identity; giving up',
+ 'PKINIT client ignoring draft 9 offer from RFC 4556 KDC')
+realm.kinit(realm.user_princ,
+ flags=['-X', 'X509_user_identity=%s' % p11_identity],
+ password='wrong', expected_code=1, expected_trace=expected_trace)
+
# PKINIT with PKCS11: identity, with a PIN supplied by the responder.
# Supply the response in raw form.
realm.run(['./responder', '-x', 'pkinit={"%s": 0}' % p11_token_identity,
diff --git a/src/tests/t_policy.py b/src/tests/t_policy.py
index bfec96a93212..26c4e466e4f0 100755
--- a/src/tests/t_policy.py
+++ b/src/tests/t_policy.py
@@ -7,35 +7,27 @@ realm = K5Realm(create_host=False, start_kadmind=True)
# Test password quality enforcement.
realm.run([kadminl, 'addpol', '-minlength', '6', '-minclasses', '2', 'pwpol'])
realm.run([kadminl, 'addprinc', '-randkey', '-policy', 'pwpol', 'pwuser'])
-out = realm.run([kadminl, 'cpw', '-pw', 'sh0rt', 'pwuser'], expected_code=1)
-if 'Password is too short' not in out:
- fail('short password')
-out = realm.run([kadminl, 'cpw', '-pw', 'longenough', 'pwuser'],
- expected_code=1)
-if 'Password does not contain enough character classes' not in out:
- fail('insufficient character classes')
+realm.run([kadminl, 'cpw', '-pw', 'sh0rt', 'pwuser'], expected_code=1,
+ expected_msg='Password is too short')
+realm.run([kadminl, 'cpw', '-pw', 'longenough', 'pwuser'], expected_code=1,
+ expected_msg='Password does not contain enough character classes')
realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'])
# Test some password history enforcement. Even with no history value,
# the current password should be denied.
-out = realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'],
- expected_code=1)
-if 'Cannot reuse password' not in out:
- fail('reuse of current password')
+realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'], expected_code=1,
+ expected_msg='Cannot reuse password')
realm.run([kadminl, 'modpol', '-history', '2', 'pwpol'])
realm.run([kadminl, 'cpw', '-pw', 'an0therpw', 'pwuser'])
-out = realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'],
- expected_code=1)
-if 'Cannot reuse password' not in out:
- fail('reuse of old password')
+realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'], expected_code=1,
+ expected_msg='Cannot reuse password')
realm.run([kadminl, 'cpw', '-pw', '3rdpassword', 'pwuser'])
realm.run([kadminl, 'cpw', '-pw', 'l0ngenough', 'pwuser'])
# Test references to nonexistent policies.
realm.run([kadminl, 'addprinc', '-randkey', '-policy', 'newpol', 'newuser'])
-out = realm.run([kadminl, 'getprinc', 'newuser'])
-if 'Policy: newpol [does not exist]\n' not in out:
- fail('getprinc output for principal referencing nonexistent policy')
+realm.run([kadminl, 'getprinc', 'newuser'],
+ expected_msg='Policy: newpol [does not exist]\n')
realm.run([kadminl, 'modprinc', '-policy', 'newpol', 'pwuser'])
# pwuser should allow reuse of the current password since newpol doesn't exist.
realm.run([kadminl, 'cpw', '-pw', '3rdpassword', 'pwuser'])
@@ -45,29 +37,20 @@ realm.run([kadmin, '-p', 'pwuser', '-w', '3rdpassword', 'cpw', '-pw',
# Create newpol and verify that it is enforced.
realm.run([kadminl, 'addpol', '-minlength', '3', 'newpol'])
-out = realm.run([kadminl, 'getprinc', 'pwuser'])
-if 'Policy: newpol\n' not in out:
- fail('getprinc after creating policy (pwuser)')
-out = realm.run([kadminl, 'cpw', '-pw', 'aa', 'pwuser'], expected_code=1)
-if 'Password is too short' not in out:
- fail('short password after creating policy (pwuser)')
-out = realm.run([kadminl, 'cpw', '-pw', '3rdpassword', 'pwuser'],
- expected_code=1)
-if 'Cannot reuse password' not in out:
- fail('reuse of current password after creating policy')
+realm.run([kadminl, 'getprinc', 'pwuser'], expected_msg='Policy: newpol\n')
+realm.run([kadminl, 'cpw', '-pw', 'aa', 'pwuser'], expected_code=1,
+ expected_msg='Password is too short')
+realm.run([kadminl, 'cpw', '-pw', '3rdpassword', 'pwuser'], expected_code=1,
+ expected_msg='Cannot reuse password')
-out = realm.run([kadminl, 'getprinc', 'newuser'])
-if 'Policy: newpol\n' not in out:
- fail('getprinc after creating policy (newuser)')
-out = realm.run([kadminl, 'cpw', '-pw', 'aa', 'newuser'], expected_code=1)
-if 'Password is too short' not in out:
- fail('short password after creating policy (newuser)')
+realm.run([kadminl, 'getprinc', 'newuser'], expected_msg='Policy: newpol\n')
+realm.run([kadminl, 'cpw', '-pw', 'aa', 'newuser'], expected_code=1,
+ expected_msg='Password is too short')
# Delete the policy and verify that it is no longer enforced.
realm.run([kadminl, 'delpol', 'newpol'])
-out = realm.run([kadminl, 'getpol', 'newpol'], expected_code=1)
-if 'Policy does not exist' not in out:
- fail('deletion of referenced policy')
+realm.run([kadminl, 'getpol', 'newpol'], expected_code=1,
+ expected_msg='Policy does not exist')
realm.run([kadminl, 'cpw', '-pw', 'aa', 'pwuser'])
# Test basic password lockout support.
@@ -78,18 +61,14 @@ realm.run([kadminl, 'modprinc', '+requires_preauth', '-policy', 'lockout',
'user'])
# kinit twice with the wrong password.
-output = realm.run([kinit, realm.user_princ], input='wrong\n', expected_code=1)
-if 'Password incorrect while getting initial credentials' not in output:
- fail('Expected error message not seen in kinit output')
-output = realm.run([kinit, realm.user_princ], input='wrong\n', expected_code=1)
-if 'Password incorrect while getting initial credentials' not in output:
- fail('Expected error message not seen in kinit output')
+realm.run([kinit, realm.user_princ], input='wrong\n', expected_code=1,
+ expected_msg='Password incorrect while getting initial credentials')
+realm.run([kinit, realm.user_princ], input='wrong\n', expected_code=1,
+ expected_msg='Password incorrect while getting initial credentials')
# Now the account should be locked out.
-output = realm.run([kinit, realm.user_princ], expected_code=1)
-if 'Client\'s credentials have been revoked while getting initial credentials' \
- not in output:
- fail('Expected lockout error message not seen in kinit output')
+m = 'Client\'s credentials have been revoked while getting initial credentials'
+realm.run([kinit, realm.user_princ], expected_code=1, expected_msg=m)
# Check that modprinc -unlock allows a further attempt.
realm.run([kadminl, 'modprinc', '-unlock', 'user'])
@@ -113,10 +92,8 @@ realm.run([kadminl, 'cpw', '-pw', 'pw2', 'user'])
# Swap the keys, simulating older kadmin having chosen the second entry.
realm.run(['./hist', 'swap'])
# Make sure we can read the history entry.
-out = realm.run([kadminl, 'cpw', '-pw', password('user'), 'user'],
- expected_code=1)
-if 'Cannot reuse password' not in out:
- fail('Expected error not seen in output')
+realm.run([kadminl, 'cpw', '-pw', password('user'), 'user'], expected_code=1,
+ expected_msg='Cannot reuse password')
# Test key/salt constraints.
@@ -142,9 +119,8 @@ realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes256-cts', 'server'])
# Test modpol.
realm.run([kadminl, 'modpol', '-allowedkeysalts', 'aes256-cts,rc4-hmac', 'ak'])
-out = realm.run([kadminl, 'getpol', 'ak'])
-if not 'Allowed key/salt types: aes256-cts,rc4-hmac' in out:
- fail('getpol does not implement allowedkeysalts?')
+realm.run([kadminl, 'getpol', 'ak'],
+ expected_msg='Allowed key/salt types: aes256-cts,rc4-hmac')
# Test subsets and full set.
realm.run([kadminl, 'cpw', '-randkey', '-e', 'rc4-hmac', 'server'])
@@ -153,19 +129,14 @@ realm.run([kadminl, 'cpw', '-randkey', '-e', 'aes256-cts,rc4-hmac', 'server'])
realm.run([kadminl, 'cpw', '-randkey', '-e', 'rc4-hmac,aes256-cts', 'server'])
# Check that the order we got is the one from the policy.
-out = realm.run([kadminl, 'getprinc', '-terse', 'server'])
-if not '2\t1\t6\t18\t0\t1\t6\t23\t0' in out:
- fail('allowed_keysalts policy did not preserve order')
+realm.run([kadminl, 'getprinc', '-terse', 'server'],
+ expected_msg='2\t1\t6\t18\t0\t1\t6\t23\t0')
# Test partially intersecting sets.
-out = realm.run([kadminl, 'cpw', '-randkey', '-e', 'rc4-hmac,aes128-cts',
- 'server'], expected_code=1)
-if not 'Invalid key/salt tuples' in out:
- fail('allowed_keysalts policy not applied properly')
-out = realm.run([kadminl, 'cpw', '-randkey', '-e',
- 'rc4-hmac,aes256-cts,aes128-cts', 'server'], expected_code=1)
-if not 'Invalid key/salt tuples' in out:
- fail('allowed_keysalts policy not applied properly')
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'rc4-hmac,aes128-cts', 'server'],
+ expected_code=1, expected_msg='Invalid key/salt tuples')
+realm.run([kadminl, 'cpw', '-randkey', '-e', 'rc4-hmac,aes256-cts,aes128-cts',
+ 'server'], expected_code=1, expected_msg='Invalid key/salt tuples')
# Test reset of allowedkeysalts.
realm.run([kadminl, 'modpol', '-allowedkeysalts', '-', 'ak'])
diff --git a/src/tests/t_preauth.py b/src/tests/t_preauth.py
index 0ef8bbca4c4f..fec0bf619ed8 100644
--- a/src/tests/t_preauth.py
+++ b/src/tests/t_preauth.py
@@ -10,18 +10,177 @@ realm = K5Realm(create_host=False, get_creds=False, krb5_conf=conf)
realm.run([kadminl, 'modprinc', '+requires_preauth', realm.user_princ])
realm.run([kadminl, 'setstr', realm.user_princ, 'teststring', 'testval'])
realm.run([kadminl, 'addprinc', '-nokey', '+requires_preauth', 'nokeyuser'])
-out = realm.run([kinit, realm.user_princ], input=password('user')+'\n')
-if 'testval' not in out:
- fail('Decrypted string attribute not in kinit output')
-out = realm.run([kinit, 'nokeyuser'], input=password('user')+'\n',
- expected_code=1)
-if 'no key' not in out:
- fail('Expected "no key" message not in kinit output')
-
-# Exercise KDC_ERR_MORE_PREAUTH_DATA_REQUIRED and secure cookies.
+realm.kinit(realm.user_princ, password('user'), expected_msg='testval')
+realm.kinit('nokeyuser', password('user'), expected_code=1,
+ expected_msg='no key')
+
+# Preauth type -123 is the test preauth module type; 133 is FAST
+# PA-FX-COOKIE; 2 is encrypted timestamp.
+
+# Test normal preauth flow.
+expected_trace = ('Sending unauthenticated request',
+ '/Additional pre-authentication required',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, -123',
+ 'Decrypted AS reply')
+realm.run(['./icred', realm.user_princ, password('user')],
+ expected_msg='testval', expected_trace=expected_trace)
+
+# Test successful optimistic preauth.
+expected_trace = ('Attempting optimistic preauth',
+ 'Processing preauth types: -123',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: -123',
+ 'Decrypted AS reply')
+realm.run(['./icred', '-o', '-123', realm.user_princ, password('user')],
+ expected_trace=expected_trace)
+
+# Test optimistic preauth failing on client, followed by successful
+# preauth using the same module.
+expected_trace = ('Attempting optimistic preauth',
+ 'Processing preauth types: -123',
+ '/induced optimistic fail',
+ 'Sending unauthenticated request',
+ '/Additional pre-authentication required',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, -123',
+ 'Decrypted AS reply')
+realm.run(['./icred', '-o', '-123', '-X', 'fail_optimistic', realm.user_princ,
+ password('user')], expected_msg='testval',
+ expected_trace=expected_trace)
+
+# Test optimistic preauth failing on KDC, followed by successful preauth
+# using the same module.
+realm.run([kadminl, 'setstr', realm.user_princ, 'failopt', 'yes'])
+expected_trace = ('Attempting optimistic preauth',
+ 'Processing preauth types: -123',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: -123',
+ '/Preauthentication failed',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, -123',
+ 'Decrypted AS reply')
+realm.run(['./icred', '-o', '-123', realm.user_princ, password('user')],
+ expected_msg='testval', expected_trace=expected_trace)
+realm.run([kadminl, 'delstr', realm.user_princ, 'failopt'])
+
+# Test KDC_ERR_MORE_PREAUTH_DATA_REQUIRED and secure cookies.
realm.run([kadminl, 'setstr', realm.user_princ, '2rt', 'secondtrip'])
-out = realm.run([kinit, realm.user_princ], input=password('user')+'\n')
-if '2rt: secondtrip' not in out:
- fail('multi round-trip cookie test')
+expected_trace = ('Sending unauthenticated request',
+ '/Additional pre-authentication required',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, -123',
+ '/More preauthentication data is required',
+ 'Continuing preauth mech -123',
+ 'Processing preauth types: -123, 133',
+ 'Produced preauth for next request: 133, -123',
+ 'Decrypted AS reply')
+realm.run(['./icred', realm.user_princ, password('user')],
+ expected_msg='2rt: secondtrip', expected_trace=expected_trace)
+
+# Test client-side failure after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED,
+# falling back to encrypted timestamp.
+expected_trace = ('Sending unauthenticated request',
+ '/Additional pre-authentication required',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, -123',
+ '/More preauthentication data is required',
+ 'Continuing preauth mech -123',
+ 'Processing preauth types: -123, 133',
+ '/induced 2rt fail',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Encrypted timestamp (for ',
+ 'module encrypted_timestamp (2) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, 2',
+ 'Decrypted AS reply')
+realm.run(['./icred', '-X', 'fail_2rt', realm.user_princ, password('user')],
+ expected_msg='2rt: secondtrip', expected_trace=expected_trace)
+
+# Test KDC-side failure after KDC_ERR_MORE_PREAUTH_DATA_REQUIRED,
+# falling back to encrypted timestamp.
+realm.run([kadminl, 'setstr', realm.user_princ, 'fail2rt', 'yes'])
+expected_trace = ('Sending unauthenticated request',
+ '/Additional pre-authentication required',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, -123',
+ '/More preauthentication data is required',
+ 'Continuing preauth mech -123',
+ 'Processing preauth types: -123, 133',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, -123',
+ '/Preauthentication failed',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Encrypted timestamp (for ',
+ 'module encrypted_timestamp (2) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, 2',
+ 'Decrypted AS reply')
+realm.run(['./icred', realm.user_princ, password('user')],
+ expected_msg='2rt: secondtrip', expected_trace=expected_trace)
+realm.run([kadminl, 'delstr', realm.user_princ, 'fail2rt'])
+
+# Test tryagain flow by inducing a KDC_ERR_ENCTYPE_NOSUPP error on the KDC.
+realm.run([kadminl, 'setstr', realm.user_princ, 'err', 'testagain'])
+expected_trace = ('Sending unauthenticated request',
+ '/Additional pre-authentication required',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, -123',
+ '/KDC has no support for encryption type',
+ 'Recovering from KDC error 14 using preauth mech -123',
+ 'Preauth tryagain input types (-123): -123, 133',
+ 'Preauth module test (-123) tryagain returned: 0/Success',
+ 'Followup preauth for next request: -123, 133',
+ 'Decrypted AS reply')
+realm.run(['./icred', realm.user_princ, password('user')],
+ expected_msg='tryagain: testagain', expected_trace=expected_trace)
+
+# Test a client-side tryagain failure, falling back to encrypted
+# timestamp.
+expected_trace = ('Sending unauthenticated request',
+ '/Additional pre-authentication required',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Preauth module test (-123) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, -123',
+ '/KDC has no support for encryption type',
+ 'Recovering from KDC error 14 using preauth mech -123',
+ 'Preauth tryagain input types (-123): -123, 133',
+ '/induced tryagain fail',
+ 'Preauthenticating using KDC method data',
+ 'Processing preauth types:',
+ 'Encrypted timestamp (for ',
+ 'module encrypted_timestamp (2) (real) returned: 0/Success',
+ 'Produced preauth for next request: 133, 2',
+ 'Decrypted AS reply')
+realm.run(['./icred', '-X', 'fail_tryagain', realm.user_princ,
+ password('user')], expected_trace=expected_trace)
+
+# Test that multiple stepwise initial creds operations can be
+# performed with the same krb5_context, with proper tracking of
+# clpreauth module request handles.
+realm.run([kadminl, 'addprinc', '-pw', 'pw', 'u1'])
+realm.run([kadminl, 'addprinc', '+requires_preauth', '-pw', 'pw', 'u2'])
+realm.run([kadminl, 'addprinc', '+requires_preauth', '-pw', 'pw', 'u3'])
+realm.run([kadminl, 'setstr', 'u2', '2rt', 'extra'])
+out = realm.run(['./icinterleave', 'pw', 'u1', 'u2', 'u3'])
+if out != ('step 1\nstep 2\nstep 3\nstep 1\nfinish 1\nstep 2\nno attr\n'
+ 'step 3\nno attr\nstep 2\n2rt: extra\nstep 3\nfinish 3\nstep 2\n'
+ 'finish 2\n'):
+ fail('unexpected output from icinterleave')
success('Pre-authentication framework tests')
diff --git a/src/tests/t_pwqual.py b/src/tests/t_pwqual.py
index 0d1d387d820d..011110bd1acf 100755
--- a/src/tests/t_pwqual.py
+++ b/src/tests/t_pwqual.py
@@ -18,29 +18,24 @@ f.close()
realm.run([kadminl, 'addpol', 'pol'])
# The built-in "empty" module rejects empty passwords even without a policy.
-out = realm.run([kadminl, 'addprinc', '-pw', '', 'p1'], expected_code=1)
-if 'Empty passwords are not allowed' not in out:
- fail('Expected error not seen for empty password')
+realm.run([kadminl, 'addprinc', '-pw', '', 'p1'], expected_code=1,
+ expected_msg='Empty passwords are not allowed')
# The built-in "dict" module rejects dictionary words, but only with a policy.
realm.run([kadminl, 'addprinc', '-pw', 'birds', 'p2'])
-out = realm.run([kadminl, 'addprinc', '-pw', 'birds', '-policy', 'pol', 'p3'],
- expected_code=1)
-if 'Password is in the password dictionary' not in out:
- fail('Expected error not seen from dictionary password')
+realm.run([kadminl, 'addprinc', '-pw', 'birds', '-policy', 'pol', 'p3'],
+ expected_code=1,
+ expected_msg='Password is in the password dictionary')
# The built-in "princ" module rejects principal components, only with a policy.
realm.run([kadminl, 'addprinc', '-pw', 'p4', 'p4'])
-out = realm.run([kadminl, 'addprinc', '-pw', 'p5', '-policy', 'pol', 'p5'],
- expected_code=1)
-if 'Password may not match principal name' not in out:
- fail('Expected error not seen from principal component')
+realm.run([kadminl, 'addprinc', '-pw', 'p5', '-policy', 'pol', 'p5'],
+ expected_code=1,
+ expected_msg='Password may not match principal name')
# The dynamic "combo" module rejects pairs of dictionary words.
-out = realm.run([kadminl, 'addprinc', '-pw', 'birdsoranges', 'p6'],
- expected_code=1)
-if 'Password may not be a pair of dictionary words' not in out:
- fail('Expected error not seen from combo module')
+realm.run([kadminl, 'addprinc', '-pw', 'birdsoranges', 'p6'], expected_code=1,
+ expected_msg='Password may not be a pair of dictionary words')
# These plugin ordering tests aren't specifically related to the
# password quality interface, but are convenient to put here.
diff --git a/src/tests/t_referral.py b/src/tests/t_referral.py
index 559fbd5f7c73..98fdf2925616 100755
--- a/src/tests/t_referral.py
+++ b/src/tests/t_referral.py
@@ -17,15 +17,18 @@ os.rename(realm.ccache, savefile)
# Get credentials and check that we got a referral to REFREALM.
def testref(realm, nametype):
shutil.copyfile(savefile, realm.ccache)
- realm.run(['./gcred', nametype, 'a/x.d'])
- realm.klist(realm.user_princ, 'a/x.d@REFREALM')
+ realm.run(['./gcred', nametype, 'a/x.d@'])
+ out = realm.run([klist]).split('\n')
+ if len(out) != 8:
+ fail('unexpected number of lines in klist output')
+ if out[5].split()[4] != 'a/x.d@' or out[6].split()[4] != 'a/x.d@REFREALM':
+ fail('unexpected service principals in klist output')
# Get credentials and check that we get an error, not a referral.
def testfail(realm, nametype):
shutil.copyfile(savefile, realm.ccache)
- out = realm.run(['./gcred', nametype, 'a/x.d'], expected_code=1)
- if 'not found in Kerberos database' not in out:
- fail('unexpected error')
+ realm.run(['./gcred', nametype, 'a/x.d@'], expected_code=1,
+ expected_msg='not found in Kerberos database')
# Create a modified KDC environment and restart the KDC.
def restart_kdc(realm, kdc_conf):
@@ -116,9 +119,8 @@ r1, r2 = cross_realms(2, xtgts=(),
create_host=False)
r2.addprinc('abc\@XYZ', 'pw')
r1.start_kdc()
-out = r1.kinit('user', expected_code=1)
-if 'not found in Kerberos database' not in out:
- fail('Expected error not seen for referral without canonicalize flag')
+r1.kinit('user', expected_code=1,
+ expected_msg='not found in Kerberos database')
r1.kinit('user', password('user'), ['-C'])
r1.klist('user@KRBTEST2.COM', 'krbtgt/KRBTEST2.COM')
r1.kinit('abc@XYZ', 'pw', ['-E'])
diff --git a/src/tests/t_renew.py b/src/tests/t_renew.py
index a5f0d4bc1479..034190c80e78 100755
--- a/src/tests/t_renew.py
+++ b/src/tests/t_renew.py
@@ -1,26 +1,55 @@
#!/usr/bin/python
from k5test import *
+from datetime import datetime
+import re
conf = {'realms': {'$realm': {'max_life': '20h', 'max_renewable_life': '20h'}}}
realm = K5Realm(create_host=False, get_creds=False, kdc_conf=conf)
-def test(testname, life, rlife, expect_renewable, env=None):
+def test(testname, life, rlife, exp_life, exp_rlife, env=None):
global realm
flags = ['-l', life]
if rlife is not None:
flags += ['-r', rlife]
realm.kinit(realm.user_princ, password('user'), flags=flags, env=env)
- out = realm.run([klist])
+ out = realm.run([klist, '-f'])
+
if ('Default principal: %s\n' % realm.user_princ) not in out:
fail('%s: did not get tickets' % testname)
- renewable = 'renew until' in out
- if renewable and not expect_renewable:
- fail('%s: tickets unexpectedly renewable' % testname)
- elif not renewable and expect_renewable:
- fail('%s: tickets unexpectedly non-renewable' % testname)
+
+ # Extract flags and check the renewable flag against expectations.
+ flags = re.findall(r'Flags: ([a-zA-Z]*)', out)[0]
+ if exp_rlife is None and 'R' in flags:
+ fail('%s: ticket unexpectedly renewable' % testname)
+ if exp_rlife is not None and 'R' not in flags:
+ fail('%s: ticket unexpectedly non-renewable' % testname)
+
+ # Extract the start time, end time, and renewable end time if present.
+ times = re.findall(r'\d\d/\d\d/\d\d \d\d:\d\d:\d\d', out)
+ times = [datetime.strptime(t, '%m/%d/%y %H:%M:%S') for t in times]
+ starttime = times[0]
+ endtime = times[1]
+ rtime = times[2] if len(times) >= 3 else None
+
+ # Check the ticket lifetime against expectations. If the lifetime
+ # was determined by the request, there may be a small error
+ # because KDC requests contain an end time rather than a lifetime.
+ life = (endtime - starttime).seconds
+ if abs(life - exp_life) > 5:
+ fail('%s: expected life %d, got %d' % (testname, exp_life, life))
+
+ # Check the ticket renewable lifetime against expectations.
+ if exp_rlife is None and rtime is not None:
+ fail('%s: ticket has unexpected renew_till' % testname)
+ if exp_rlife is not None and rtime is None:
+ fail('%s: ticket is renewable but has no renew_till' % testname)
+ if rtime is not None:
+ rlife = (rtime - starttime).seconds
+ if abs(rlife - exp_rlife) > 5:
+ fail('%s: expected rlife %d, got %d' (testname, exp_rlife, rlife))
# Get renewable tickets.
-test('simple', '1h', '2h', True)
+test('simple', '1h', '2h', 3600, 7200)
# Renew twice, to test that renewed tickets are renewable.
realm.kinit(realm.user_princ, flags=['-R'])
@@ -31,49 +60,50 @@ realm.klist(realm.user_princ)
realm.run([kvno, realm.user_princ])
# Make sure we can't renew non-renewable tickets.
-test('non-renewable', '1h', '1h', False)
-out = realm.kinit(realm.user_princ, flags=['-R'], expected_code=1)
-if "KDC can't fulfill requested option" not in out:
- fail('expected error not seen renewing non-renewable ticket')
+test('non-renewable', '1h', None, 3600, None)
+realm.kinit(realm.user_princ, flags=['-R'], expected_code=1,
+ expected_msg="KDC can't fulfill requested option")
# Test that -allow_renewable on the client principal works.
realm.run([kadminl, 'modprinc', '-allow_renewable', 'user'])
-test('disallowed client', '1h', '2h', False)
+test('disallowed client', '1h', '2h', 3600, None)
realm.run([kadminl, 'modprinc', '+allow_renewable', 'user'])
# Test that -allow_renewable on the server principal works.
realm.run([kadminl, 'modprinc', '-allow_renewable', realm.krbtgt_princ])
-test('disallowed server', '1h', '2h', False)
+test('disallowed server', '1h', '2h', 3600, None)
realm.run([kadminl, 'modprinc', '+allow_renewable', realm.krbtgt_princ])
-# Test that non-renewable tickets are issued if renew_till < till.
-test('short', '2h', '1h', False)
+# Test that trivially renewable tickets are issued if renew_till <=
+# till. (Our client code bumps up the requested renewable life to the
+# requested life.)
+test('short', '2h', '1h', 7200, 7200)
# Test that renewable tickets are issued if till > max life by
# default, but not if we configure away the RENEWABLE-OK option.
no_opts_conf = {'libdefaults': {'kdc_default_options': '0'}}
no_opts = realm.special_env('no_opts', False, krb5_conf=no_opts_conf)
realm.run([kadminl, 'modprinc', '-maxlife', '10 hours', 'user'])
-test('long', '15h', None, True)
-test('long noopts', '15h', None, False, env=no_opts)
+test('long', '15h', None, 10 * 3600, 15 * 3600)
+test('long noopts', '15h', None, 10 * 3600, None, env=no_opts)
realm.run([kadminl, 'modprinc', '-maxlife', '20 hours', 'user'])
# Test maximum renewable life on the client principal.
realm.run([kadminl, 'modprinc', '-maxrenewlife', '5 hours', 'user'])
-test('maxrenewlife client yes', '4h', '5h', True)
-test('maxrenewlife client no', '6h', '10h', False)
+test('maxrenewlife client 1', '4h', '5h', 4 * 3600, 5 * 3600)
+test('maxrenewlife client 2', '6h', '10h', 6 * 3600, 5 * 3600)
# Test maximum renewable life on the server principal.
realm.run([kadminl, 'modprinc', '-maxrenewlife', '3 hours',
realm.krbtgt_princ])
-test('maxrenewlife server yes', '2h', '3h', True)
-test('maxrenewlife server no', '4h', '8h', False)
+test('maxrenewlife server 1', '2h', '3h', 2 * 3600, 3 * 3600)
+test('maxrenewlife server 2', '4h', '8h', 4 * 3600, 3 * 3600)
# Test realm maximum life.
realm.run([kadminl, 'modprinc', '-maxrenewlife', '40 hours', 'user'])
realm.run([kadminl, 'modprinc', '-maxrenewlife', '40 hours',
realm.krbtgt_princ])
-test('maxrenewlife realm yes', '10h', '20h', True)
-test('maxrenewlife realm no', '21h', '40h', False)
+test('maxrenewlife realm 1', '10h', '20h', 10 * 3600, 20 * 3600)
+test('maxrenewlife realm 2', '21h', '40h', 20 * 3600, 20 * 3600)
success('Renewing credentials')
diff --git a/src/tests/t_salt.py b/src/tests/t_salt.py
index e923c92d13eb..ddb1905ed567 100755
--- a/src/tests/t_salt.py
+++ b/src/tests/t_salt.py
@@ -62,13 +62,11 @@ for ks in dup_kstypes:
# fails.
def test_reject_afs3(realm, etype):
query = 'ank -e ' + etype + ':afs3 -pw password princ1'
- out = realm.run([kadminl, 'ank', '-e', etype + ':afs3', '-pw', 'password',
- 'princ1'], expected_code=1)
- if 'Invalid key generation parameters from KDC' not in out:
- fail('Allowed afs3 salt for ' + etype)
- out = realm.run([kadminl, 'getprinc', 'princ1'], expected_code=1)
- if 'Principal does not exist' not in out:
- fail('Created principal with afs3 salt and enctype ' + etype)
+ realm.run([kadminl, 'ank', '-e', etype + ':afs3', '-pw', 'password',
+ 'princ1'], expected_code=1,
+ expected_msg='Invalid key generation parameters from KDC')
+ realm.run([kadminl, 'getprinc', 'princ1'], expected_code=1,
+ expected_msg='Principal does not exist')
# Verify that the afs3 salt is rejected for arcfour and pbkdf2 enctypes.
# We do not currently do any verification on the key-generation parameters
diff --git a/src/tests/t_skew.py b/src/tests/t_skew.py
index b729710702ea..f2ae066951ab 100755
--- a/src/tests/t_skew.py
+++ b/src/tests/t_skew.py
@@ -37,22 +37,16 @@ realm.kinit(realm.user_princ, password('user'),
# kinit should detect too much skew in the KDC response. kinit with
# FAST should fail from the KDC since the armor AP-REQ won't be valid.
-out = realm.kinit(realm.user_princ, password('user'), expected_code=1)
-if 'Clock skew too great in KDC reply' not in out:
- fail('Expected error message not seen in kinit skew case')
-out = realm.kinit(realm.user_princ, None, flags=['-T', fast_cache],
- expected_code=1)
-if 'Clock skew too great while' not in out:
- fail('Expected error message not seen in kinit FAST skew case')
+realm.kinit(realm.user_princ, password('user'), expected_code=1,
+ expected_msg='Clock skew too great in KDC reply')
+realm.kinit(realm.user_princ, None, flags=['-T', fast_cache], expected_code=1,
+ expected_msg='Clock skew too great while')
# kinit (with preauth) should fail from the KDC, with or without FAST.
realm.run([kadminl, 'modprinc', '+requires_preauth', 'user'])
-out = realm.kinit(realm.user_princ, password('user'), expected_code=1)
-if 'Clock skew too great while' not in out:
- fail('Expected error message not seen in kinit skew case (preauth)')
-out = realm.kinit(realm.user_princ, None, flags=['-T', fast_cache],
- expected_code=1)
-if 'Clock skew too great while' not in out:
- fail('Expected error message not seen in kinit FAST skew case (preauth)')
+realm.kinit(realm.user_princ, password('user'), expected_code=1,
+ expected_msg='Clock skew too great while')
+realm.kinit(realm.user_princ, None, flags=['-T', fast_cache], expected_code=1,
+ expected_msg='Clock skew too great while')
success('Clock skew tests')
diff --git a/src/tests/t_stringattr.py b/src/tests/t_stringattr.py
index 281c8726f629..5672a0f2006b 100755
--- a/src/tests/t_stringattr.py
+++ b/src/tests/t_stringattr.py
@@ -28,9 +28,7 @@ realm = K5Realm(start_kadmind=True, create_host=False, get_creds=False)
realm.prep_kadmin()
-out = realm.run_kadmin(['getstrs', 'user'])
-if '(No string attributes.)' not in out:
- fail('Empty attribute query')
+realm.run_kadmin(['getstrs', 'user'], expected_msg='(No string attributes.)')
realm.run_kadmin(['setstr', 'user', 'attr1', 'value1'])
realm.run_kadmin(['setstr', 'user', 'attr2', 'value2'])
diff --git a/src/tests/t_y2038.py b/src/tests/t_y2038.py
new file mode 100644
index 000000000000..02e946df46bf
--- /dev/null
+++ b/src/tests/t_y2038.py
@@ -0,0 +1,75 @@
+#!/usr/bin/python
+from k5test import *
+
+# These tests will become much less important after the y2038 boundary
+# has elapsed, and may start exhibiting problems around the year 2075.
+
+if runenv.sizeof_time_t <= 4:
+ skip_rest('y2038 timestamp tests', 'platform has 32-bit time_t')
+
+# Start a KDC running roughly 21 years in the future, after the y2038
+# boundary. Set long maximum lifetimes for later tests.
+conf = {'realms': {'$realm': {'max_life': '9000d',
+ 'max_renewable_life': '9000d'}}}
+realm = K5Realm(start_kdc=False, kdc_conf=conf)
+realm.start_kdc(['-T', '662256000'])
+
+# kinit without preauth should succeed with clock skew correction, but
+# will result in an expired ticket, because we sent an absolute end
+# time and didn't get a chance to correct it..
+realm.kinit(realm.user_princ, password('user'))
+realm.run([kvno, realm.host_princ], expected_code=1,
+ expected_msg='Ticket expired')
+
+# kinit with preauth should succeed and result in a valid ticket, as
+# we get a chance to correct the end time based on the KDC time. Try
+# with encrypted timestamp and encrypted challenge.
+realm.run([kadminl, 'modprinc', '+requires_preauth', 'user'])
+realm.kinit(realm.user_princ, password('user'))
+realm.run([kvno, realm.host_princ])
+realm.kinit(realm.user_princ, password('user'), flags=['-T', realm.ccache])
+realm.run([kvno, realm.host_princ])
+
+# Test that expiration warning works after y2038, by setting a
+# password expiration time ten minutes after the KDC time.
+realm.run([kadminl, 'modprinc', '-pwexpire', '662256600 seconds', 'user'])
+out = realm.kinit(realm.user_princ, password('user'))
+if 'will expire in less than one hour' not in out:
+ fail('password expiration message')
+year = int(out.split()[-1])
+if year < 2038 or year > 9999:
+ fail('password expiration year')
+
+realm.stop_kdc()
+realm.start_kdc()
+realm.start_kadmind()
+realm.prep_kadmin()
+
+# Test getdate parsing of absolute timestamps after 2038 and
+# marshalling over the kadmin protocol. The local time zone will
+# affect the display time by a little bit, so just look for the year.
+realm.run_kadmin(['modprinc', '-pwexpire', '2040-02-03', realm.host_princ])
+realm.run_kadmin(['getprinc', realm.host_princ], expected_msg=' 2040\n')
+
+# Get a ticket whose lifetime crosses the y2038 boundary and
+# range-check the expiration year as reported by klist.
+realm.kinit(realm.user_princ, password('user'),
+ flags=['-l', '8000d', '-r', '8500d'])
+realm.run([kvno, realm.host_princ])
+out = realm.run([klist])
+if int(out.split('\n')[4].split()[2].split('/')[2]) < 39:
+ fail('unexpected tgt expiration year')
+if int(out.split('\n')[5].split()[2].split('/')[2]) < 40:
+ fail('unexpected tgt rtill year')
+if int(out.split('\n')[6].split()[2].split('/')[2]) < 39:
+ fail('unexpected service ticket expiration year')
+if int(out.split('\n')[7].split()[2].split('/')[2]) < 40:
+ fail('unexpected service ticket rtill year')
+realm.kinit(realm.user_princ, None, ['-R'])
+out = realm.run([klist])
+if int(out.split('\n')[4].split()[2].split('/')[2]) < 39:
+ fail('unexpected renewed tgt expiration year')
+if int(out.split('\n')[5].split()[2].split('/')[2]) < 40:
+ fail('unexpected renewed tgt rtill year')
+
+success('y2038 tests')