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

Greg Hudson <[email protected]>
Newsgroups gmane.comp.encryption.kerberos.cvs
Message-ID <[email protected]>
https://github.com/krb5/krb5/commit/8642b06696fd7fca68aae475bd4113be5a1658cb
commit 8642b06696fd7fca68aae475bd4113be5a1658cb
Author: Isaac Boukris <[email protected]>
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.
    
    [[email protected]: 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]')
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.