krb5 commit: Use cached S4U2Proxy tickets in GSSAPI

Greg Hudson ghudson at mit.edu
Mon Feb 29 16:13:23 EST 2016


https://github.com/krb5/krb5/commit/f149b9cc1e0f8c6e7cca2ee0a5fd8feff7deaf58
commit f149b9cc1e0f8c6e7cca2ee0a5fd8feff7deaf58
Author: Isaac Boukris <iboukris at gmail.com>
Date:   Mon Feb 1 18:08:24 2016 +0200

    Use cached S4U2Proxy tickets in GSSAPI
    
    Ticket #7047 allowed credentials obtain using S4U2Proxy through GSSAPI
    to be cached, but doesn't actually use the cached credentials.  Modify
    get_credentials() to check the cache for the desired client name
    first, then to make an S4U2Proxy request if we don't find it.
    
    Test this change by adding code to t_s4u.c to repeat the constrained
    delegation request and verify that only three tickets are present in
    the cache.
    
    [ghudson at mit.edu: squash commits; commit message rewrite; minor style
    edits; changed test code to use gss_store_cred_into() to avoid the
    need to pick a principal to initialize the ccache with]
    
    ticket: 8372 (new)

 src/lib/gssapi/krb5/init_sec_context.c |   71 ++++++++++++++++---------------
 src/tests/gssapi/t_s4u.c               |   66 +++++++++++++++++++++++++++++
 2 files changed, 103 insertions(+), 34 deletions(-)

diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c
index 4d05d78..70f7955 100644
--- a/src/lib/gssapi/krb5/init_sec_context.c
+++ b/src/lib/gssapi/krb5/init_sec_context.c
@@ -127,7 +127,7 @@ static krb5_error_code get_credentials(context, cred, server, now,
     krb5_creds **out_creds;
 {
     krb5_error_code     code;
-    krb5_creds          in_creds, evidence_creds, *result_creds = NULL;
+    krb5_creds          in_creds, evidence_creds, mcreds, *result_creds = NULL;
     krb5_flags          flags = 0;
 
     *out_creds = NULL;
@@ -139,37 +139,7 @@ static krb5_error_code get_credentials(context, cred, server, now,
 
     assert(cred->name != NULL);
 
-    /*
-     * Do constrained delegation if we have proxy credentials and
-     * we're not trying to get a ticket to ourselves (in which case
-     * we can just use the S4U2Self or evidence ticket directly).
-     */
-    if (cred->impersonator &&
-        !krb5_principal_compare(context, cred->impersonator, server->princ)) {
-        krb5_creds mcreds;
-
-        flags |= KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
-
-        memset(&mcreds, 0, sizeof(mcreds));
-
-        mcreds.magic = KV5M_CREDS;
-        mcreds.server = cred->impersonator;
-        mcreds.client = cred->name->princ;
-
-        code = krb5_cc_retrieve_cred(context, cred->ccache,
-                                     KRB5_TC_MATCH_AUTHDATA, &mcreds,
-                                     &evidence_creds);
-        if (code)
-            goto cleanup;
-
-        assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
-
-        in_creds.client = cred->impersonator;
-        in_creds.second_ticket = evidence_creds.ticket;
-    } else {
-        in_creds.client = cred->name->princ;
-    }
-
+    in_creds.client = cred->name->princ;
     in_creds.server = server->princ;
     in_creds.times.endtime = endtime;
     in_creds.authdata = NULL;
@@ -188,12 +158,45 @@ static krb5_error_code get_credentials(context, cred, server, now,
             goto cleanup;
     }
 
-    /* Don't go out over the network if we used IAKERB */
-    if (cred->iakerb_mech)
+    /*
+     * For IAKERB or constrained delegation, only check the cache in this step.
+     * For IAKERB we will ask the server to make any necessary TGS requests;
+     * for constrained delegation we will adjust in_creds and make an S4U2Proxy
+     * request below if the cache lookup fails.
+     */
+    if (cred->impersonator != NULL || cred->iakerb_mech)
         flags |= KRB5_GC_CACHED;
 
     code = krb5_get_credentials(context, flags, cred->ccache,
                                 &in_creds, &result_creds);
+
+    /*
+     * Try constrained delegation if we have proxy credentials, unless
+     * we are trying to get a ticket to ourselves (in which case we could
+     * just use the evidence ticket directly from cache).
+     */
+    if (code == KRB5_CC_NOTFOUND && cred->impersonator != NULL &&
+        !cred->iakerb_mech &&
+        !krb5_principal_compare(context, cred->impersonator, server->princ)) {
+
+        memset(&mcreds, 0, sizeof(mcreds));
+        mcreds.magic = KV5M_CREDS;
+        mcreds.server = cred->impersonator;
+        mcreds.client = cred->name->princ;
+        code = krb5_cc_retrieve_cred(context, cred->ccache,
+                                     KRB5_TC_MATCH_AUTHDATA, &mcreds,
+                                     &evidence_creds);
+        if (code)
+            goto cleanup;
+
+        assert(evidence_creds.ticket_flags & TKT_FLG_FORWARDABLE);
+        in_creds.client = cred->impersonator;
+        in_creds.second_ticket = evidence_creds.ticket;
+        flags = KRB5_GC_CANONICALIZE | KRB5_GC_CONSTRAINED_DELEGATION;
+        code = krb5_get_credentials(context, flags, cred->ccache,
+                                    &in_creds, &result_creds);
+    }
+
     if (code)
         goto cleanup;
 
diff --git a/src/tests/gssapi/t_s4u.c b/src/tests/gssapi/t_s4u.c
index c33560f..5bc1e44 100644
--- a/src/tests/gssapi/t_s4u.c
+++ b/src/tests/gssapi/t_s4u.c
@@ -123,6 +123,55 @@ init_accept_sec_context(gss_cred_id_t claimant_cred_handle,
 }
 
 static void
+check_ticket_count(gss_cred_id_t cred, int expected)
+{
+    krb5_error_code ret;
+    krb5_context context = NULL;
+    krb5_creds kcred;
+    krb5_cc_cursor cur;
+    krb5_ccache ccache;
+    int count = 0;
+    gss_key_value_set_desc store;
+    gss_key_value_element_desc elem;
+    OM_uint32 major, minor;
+    const char *ccname = "MEMORY:count";
+
+    store.count = 1;
+    store.elements = &elem;
+    elem.key = "ccache";
+    elem.value = ccname;
+    major = gss_store_cred_into(&minor, cred, GSS_C_INITIATE, &mech_krb5, 1, 0,
+                                &store, NULL, NULL);
+    check_gsserr("gss_store_cred_into", major, minor);
+
+    ret = krb5_init_context(&context);
+    check_k5err(context, "krb5_init_context", ret);
+
+    ret = krb5_cc_resolve(context, ccname, &ccache);
+    check_k5err(context, "krb5_cc_resolve", ret);
+
+    ret = krb5_cc_start_seq_get(context, ccache, &cur);
+    check_k5err(context, "krb5_cc_start_seq_get", ret);
+
+    while (!krb5_cc_next_cred(context, ccache, &cur, &kcred)) {
+        if (!krb5_is_config_principal(context, kcred.server))
+            count++;
+        krb5_free_cred_contents(context, &kcred);
+    }
+
+    ret = krb5_cc_end_seq_get(context, ccache, &cur);
+    check_k5err(context, "krb5_cc_end_seq_get", ret);
+
+    if (expected != count) {
+        printf("Expected %d tickets but got %d\n", expected, count);
+        exit(1);
+    }
+
+    krb5_cc_destroy(context, ccache);
+    krb5_free_context(context);
+}
+
+static void
 constrained_delegate(gss_OID_set desired_mechs, gss_name_t target,
                      gss_cred_id_t delegated_cred_handle,
                      gss_cred_id_t verifier_cred_handle)
@@ -164,7 +213,24 @@ constrained_delegate(gss_OID_set desired_mechs, gss_name_t target,
 
     (void)gss_release_buffer(&minor, &token);
     (void)gss_delete_sec_context(&minor, &initiator_context, NULL);
+
+    /* Ensure a second call does not acquire new ticket. */
+    major = gss_init_sec_context(&minor, delegated_cred_handle,
+                                 &initiator_context, target,
+                                 mechs ? &mechs->elements[0] : &mech_krb5,
+                                 GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG,
+                                 GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS,
+                                 GSS_C_NO_BUFFER, NULL, &token, NULL,
+                                 &time_rec);
+    check_gsserr("gss_init_sec_context", major, minor);
+
+    (void)gss_release_buffer(&minor, &token);
+    (void)gss_delete_sec_context(&minor, &initiator_context, NULL);
     (void)gss_release_oid_set(&minor, &mechs);
+
+    /* We expect three tickets: our TGT, the evidence ticket, and the ticket to
+     * the target service. */
+    check_ticket_count(delegated_cred_handle, 3);
 }
 
 int


More information about the cvs-krb5 mailing list