krb5 commit [krb5-1.18]: Add tests for S4U request-authdata handling

Greg Hudson ghudson at mit.edu
Mon Jan 27 11:05:24 EST 2020


https://github.com/krb5/krb5/commit/8642b06696fd7fca68aae475bd4113be5a1658cb
commit 8642b06696fd7fca68aae475bd4113be5a1658cb
Author: Isaac Boukris <iboukris at gmail.com>
Date:   Thu Dec 12 03:20:44 2019 +0100

    Add tests for S4U request-authdata handling
    
    In adata.c, look up the server in the keytab by ticket->server (which
    has the canonicalized realm), to allow testing of cross-realm RBCD
    (although unused for now).
    
    In s4u2proxy.c, set KRB5_GC_CANONICALIZE to support RBCD, and add an
    authdata request option.  Add an s4u2self test harness with authdata
    request option.
    
    [ghudson at mit.edu: minor code simplifications; edited commit message]
    
    (cherry picked from commit 2d039a2b4c3ba6d71da8fcf76658dc63bc659f0c)
    
    ticket: 8866
    version_fixed: 1.18

 .gitignore              |    1 +
 src/tests/Makefile.in   |   11 +++--
 src/tests/adata.c       |    4 +-
 src/tests/s4u2proxy.c   |   37 +++++++++++++-
 src/tests/s4u2self.c    |  128 +++++++++++++++++++++++++++++++++++++++++++++++
 src/tests/t_authdata.py |   22 ++++++++-
 6 files changed, 195 insertions(+), 8 deletions(-)

diff --git a/.gitignore b/.gitignore
index adf6615..ae1c262 100644
--- a/.gitignore
+++ b/.gitignore
@@ -444,6 +444,7 @@ local.properties
 /src/tests/responder
 /src/tests/s2p
 /src/tests/s4u2proxy
+/src/tests/s4u2self
 /src/tests/unlockiter
 
 /src/tests/asn.1/expected_encode.out
diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in
index 81ca4cb..3f88f17 100644
--- a/src/tests/Makefile.in
+++ b/src/tests/Makefile.in
@@ -8,10 +8,10 @@ RUN_DB_TEST = $(RUN_SETUP) KRB5_KDC_PROFILE=kdc.conf KRB5_CONFIG=krb5.conf \
 
 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 \
-	replay.o responder.o s2p.o s4u2proxy.o unlockiter.o
+	replay.o responder.o s2p.o s4u2self.o s4u2proxy.o unlockiter.o
 EXTRADEPSRCS= adata.c etinfo.c forward.c gcred.c hist.c hooks.c hrealm.c \
 	icinterleave.c icred.c kdbtest.c localauth.c plugorder.c rdreq.c \
-	replay.c responder.c s2p.c s4u2proxy.c unlockiter.c
+	replay.c responder.c s2p.c s4u2self.c s4u2proxy.c unlockiter.c
 
 TEST_DB = ./testdb
 TEST_REALM = FOO.TEST.REALM
@@ -72,6 +72,9 @@ responder: responder.o $(KRB5_BASE_DEPLIBS)
 s2p: s2p.o $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o $@ s2p.o $(KRB5_BASE_LIBS)
 
+s4u2self: s4u2self.o $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o $@ s4u2self.o $(KRB5_BASE_LIBS)
+
 s4u2proxy: s4u2proxy.o $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o $@ s4u2proxy.o $(KRB5_BASE_LIBS)
 
@@ -117,7 +120,7 @@ kdb_check: kdc.conf krb5.conf
 
 check-pytests: adata etinfo forward gcred hist hooks hrealm icinterleave icred
 check-pytests: kdbtest localauth plugorder rdreq replay responder s2p s4u2proxy
-check-pytests: unlockiter
+check-pytests: unlockiter s4u2self
 	$(RUNPYTEST) $(srcdir)/t_general.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_hooks.py $(PYTESTFLAGS)
 	$(RUNPYTEST) $(srcdir)/t_dump.py $(PYTESTFLAGS)
@@ -180,7 +183,7 @@ check-pytests: unlockiter
 clean:
 	$(RM) adata etinfo forward gcred hist hooks hrealm icinterleave icred
 	$(RM) kdbtest localauth plugorder rdreq replay responder s2p s4u2proxy
-	$(RM) unlockiter
+	$(RM) unlockiter s4u2self
 	$(RM) krb5.conf kdc.conf
 	$(RM) -rf kdc_realm/sandbox ldap
 	$(RM) au.log
diff --git a/src/tests/adata.c b/src/tests/adata.c
index df77c80..d3bd08e 100644
--- a/src/tests/adata.c
+++ b/src/tests/adata.c
@@ -303,9 +303,11 @@ main(int argc, char **argv)
     check(krb5_get_credentials(ctx, KRB5_GC_NO_STORE, ccache, &in_creds,
                                &creds));
 
+    assert(in_creds.authdata == NULL || creds->authdata != NULL);
+
     check(krb5_decode_ticket(&creds->ticket, &ticket));
     check(krb5_kt_default(ctx, &keytab));
-    check(krb5_kt_get_entry(ctx, keytab, server, ticket->enc_part.kvno,
+    check(krb5_kt_get_entry(ctx, keytab, ticket->server, ticket->enc_part.kvno,
                             ticket->enc_part.enctype, &ktent));
     check(krb5_decrypt_tkt_part(ctx, &ktent.key, ticket));
 
diff --git a/src/tests/s4u2proxy.c b/src/tests/s4u2proxy.c
index 28bff61..4adf6ac 100644
--- a/src/tests/s4u2proxy.c
+++ b/src/tests/s4u2proxy.c
@@ -31,7 +31,7 @@
  */
 
 /*
- * Usage: s4u2proxy evccname targetname
+ * Usage: s4u2proxy evccname targetname [ad-type ad-contents]
  *
  * evccname contains an evidence ticket.  The default ccache contains a TGT for
  * the intermediate service.  The default keytab contains a key for the
@@ -57,6 +57,28 @@ check(krb5_error_code code)
     }
 }
 
+static krb5_authdata **
+make_request_authdata(int type, const char *contents)
+{
+    krb5_authdata *ad;
+    krb5_authdata **req_authdata;
+
+    ad = malloc(sizeof(*ad));
+    assert(ad != NULL);
+    ad->magic = KV5M_AUTHDATA;
+    ad->ad_type = type;
+    ad->length = strlen(contents);
+    ad->contents = (unsigned char *)strdup(contents);
+    assert(ad->contents != NULL);
+
+    req_authdata = malloc(2 * sizeof(*req_authdata));
+    assert(req_authdata != NULL);
+    req_authdata[0] = ad;
+    req_authdata[1] = NULL;
+
+    return req_authdata;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -66,6 +88,12 @@ main(int argc, char **argv)
     krb5_keytab defkt;
     krb5_creds mcred, ev_cred, *new_cred;
     krb5_ticket *ev_ticket;
+    krb5_authdata **req_authdata = NULL;
+
+    if (argc == 5) {
+        req_authdata = make_request_authdata(atoi(argv[3]), argv[4]);
+        argc -= 2;
+    }
 
     assert(argc == 3);
     check(krb5_init_context(&context));
@@ -91,12 +119,16 @@ main(int argc, char **argv)
     /* Make an S4U2Proxy request for the target service. */
     mcred.client = client_name;
     mcred.server = target_name;
-    check(krb5_get_credentials_for_proxy(context, KRB5_GC_NO_STORE, defcc,
+    mcred.authdata = req_authdata;
+    check(krb5_get_credentials_for_proxy(context, KRB5_GC_NO_STORE |
+                                         KRB5_GC_CANONICALIZE, defcc,
                                          &mcred, ev_ticket, &new_cred));
 
     /* Store the new cred in the default ccache. */
     check(krb5_cc_store_cred(context, defcc, new_cred));
 
+    assert(req_authdata == NULL || new_cred->authdata != NULL);
+
     krb5_cc_close(context, defcc);
     krb5_cc_close(context, evcc);
     krb5_kt_close(context, defkt);
@@ -106,6 +138,7 @@ main(int argc, char **argv)
     krb5_free_cred_contents(context, &ev_cred);
     krb5_free_ticket(context, ev_ticket);
     krb5_free_creds(context, new_cred);
+    krb5_free_authdata(context, req_authdata);
     krb5_free_context(context);
     return 0;
 }
diff --git a/src/tests/s4u2self.c b/src/tests/s4u2self.c
new file mode 100644
index 0000000..c8e4822
--- /dev/null
+++ b/src/tests/s4u2self.c
@@ -0,0 +1,128 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright (C) 2019 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.
+ */
+
+/*
+ * Usage: s4u2self user self out_cache [ad-type ad-contents]
+ *
+ * The default ccache contains a TGT for the intermediate service self.  An
+ * S4U2Self request is made to self.  The resulting cred is stored in
+ * out_cache.
+ */
+
+#include <k5-int.h>
+
+static krb5_context ctx;
+
+static void
+check(krb5_error_code code)
+{
+    const char *errmsg;
+
+    if (code) {
+        errmsg = krb5_get_error_message(ctx, code);
+        fprintf(stderr, "%s\n", errmsg);
+        krb5_free_error_message(ctx, errmsg);
+        exit(1);
+    }
+}
+
+static krb5_authdata **
+make_request_authdata(int type, const char *contents)
+{
+    krb5_authdata *ad;
+    krb5_authdata **req_authdata;
+
+    ad = malloc(sizeof(*ad));
+    assert(ad != NULL);
+    ad->magic = KV5M_AUTHDATA;
+    ad->ad_type = type;
+    ad->length = strlen(contents);
+    ad->contents = (unsigned char *)strdup(contents);
+    assert(ad->contents != NULL);
+
+    req_authdata = malloc(2 * sizeof(*req_authdata));
+    assert(req_authdata != NULL);
+    req_authdata[0] = ad;
+    req_authdata[1] = NULL;
+
+    return req_authdata;
+}
+
+int
+main(int argc, char **argv)
+{
+    krb5_context context;
+    krb5_ccache defcc, ocache;
+    krb5_principal client, self;
+    krb5_creds mcred, *new_cred;
+    krb5_authdata **req_authdata = NULL;
+
+    if (argc == 6) {
+        req_authdata = make_request_authdata(atoi(argv[4]), argv[5]);
+        argc -= 2;
+    }
+
+    assert(argc == 4);
+    check(krb5_init_context(&context));
+
+    /* Open the default ccache. */
+    check(krb5_cc_default(context, &defcc));
+
+    check(krb5_parse_name(context, argv[1], &client));
+    check(krb5_parse_name(context, argv[2], &self));
+
+    memset(&mcred, 0, sizeof(mcred));
+    mcred.client = client;
+    mcred.server = self;
+    mcred.authdata = req_authdata;
+    check(krb5_get_credentials_for_user(context, KRB5_GC_NO_STORE |
+                                        KRB5_GC_CANONICALIZE, defcc,
+                                        &mcred, NULL, &new_cred));
+
+    if (strcmp(argv[3], "-") == 0) {
+        check(krb5_cc_store_cred(context, defcc, new_cred));
+    } else {
+        check(krb5_cc_resolve(context, argv[3], &ocache));
+        check(krb5_cc_initialize(context, ocache, new_cred->client));
+        check(krb5_cc_store_cred(context, ocache, new_cred));
+        krb5_cc_close(context, ocache);
+    }
+
+    assert(req_authdata == NULL || new_cred->authdata != NULL);
+
+    krb5_cc_close(context, defcc);
+    krb5_free_principal(context, client);
+    krb5_free_principal(context, self);
+    krb5_free_creds(context, new_cred);
+    krb5_free_authdata(context, req_authdata);
+    krb5_free_context(context);
+    return 0;
+}
diff --git a/src/tests/t_authdata.py b/src/tests/t_authdata.py
index 9b41bc0..44965dd 100644
--- a/src/tests/t_authdata.py
+++ b/src/tests/t_authdata.py
@@ -193,7 +193,9 @@ realm2.stop()
 testprincs = {'krbtgt/KRBTEST.COM': {'keys': 'aes128-cts'},
               'krbtgt/FOREIGN': {'keys': 'aes128-cts'},
               'user': {'keys': 'aes128-cts', 'flags': '+preauth'},
-              'service/1': {'keys': 'aes128-cts', 'flags': '+preauth'},
+              'user2': {'keys': 'aes128-cts', 'flags': '+preauth'},
+              'service/1': {'keys': 'aes128-cts',
+                            'flags': '+ok_to_auth_as_delegate'},
               'service/2': {'keys': 'aes128-cts'},
               'noauthdata': {'keys': 'aes128-cts',
                              'flags': '+no_auth_data_required'}}
@@ -219,6 +221,11 @@ out = realm.run(['./adata', '-p', realm.user_princ, 'service/1'])
 if '97:' in out:
     fail('auth-indicator present in S4U2Self response')
 
+# Get another S4U2Self ticket with requested authdata.
+realm.run(['./s4u2self', 'user', 'service/1', '-', '-2', 'self_ad'])
+realm.run(['./adata', '-p', realm.user_princ, 'service/1', '-2', 'self_ad'],
+          expected_msg=' -2: self_ad')
+
 # S4U2Proxy (indicators should come from evidence ticket, not TGT)
 mark('S4U2Proxy (auth indicators from evidence ticket expected)')
 realm.kinit(realm.user_princ, None, ['-k', '-f', '-X', 'indicators=indcl',
@@ -228,6 +235,19 @@ out = realm.run(['./adata', '-p', realm.user_princ, 'service/2'])
 if '+97: [indcl]' not in out or '[inds1]' in out:
     fail('correct auth-indicator not seen for S4U2Proxy req')
 
+# Get another S4U2Proxy ticket including request-authdata.
+realm.run(['./s4u2proxy', usercache, 'service/2', '-2', 'proxy_ad'])
+realm.run(['./adata', '-p', realm.user_princ, 'service/2', '-2', 'proxy_ad'],
+          expected_msg=' -2: proxy_ad')
+
+# Get an S4U2Proxy ticket using an evidence ticket obtained by S4U2Self,
+# with request authdata in both steps.
+realm.run(['./s4u2self', 'user2', 'service/1', usercache, '-2', 'self_ad'])
+realm.run(['./s4u2proxy', usercache, 'service/2', '-2', 'proxy_ad'])
+out = realm.run(['./adata', '-p', 'user2', 'service/2', '-2', 'proxy_ad'])
+if ' -2: self_ad' not in out or ' -2: proxy_ad' not in out:
+    fail('expected authdata not seen in S4U2Proxy ticket')
+
 # Test alteration of auth indicators by KDB module (AS and TGS).
 realm.kinit(realm.user_princ, None, ['-k', '-X', 'indicators=dummy dbincr1'])
 realm.run(['./adata', realm.krbtgt_princ], expected_msg='+97: [dbincr2]')


More information about the cvs-krb5 mailing list