svn rev #23479: trunk/src/ lib/gssapi/ lib/gssapi/generic/ lib/gssapi/krb5/ lib/gssapi/mechglue/ ...

ghudson@MIT.EDU ghudson at MIT.EDU
Wed Dec 16 23:49:27 EST 2009


http://src.mit.edu/fisheye/changelog/krb5/?cs=23479
Commit By: ghudson
Log Message:
ticket: 6597
subject: Add GSS extensions to store credentials, generate random bits

Merge /users/lhoward/gssextras-no-cqa to trunk.  Adds
gss_pseudo_random and gss_store_cred.



Changed Files:
U   trunk/src/lib/gssapi/generic/gssapi.hin
U   trunk/src/lib/gssapi/krb5/Makefile.in
U   trunk/src/lib/gssapi/krb5/gssapiP_krb5.h
U   trunk/src/lib/gssapi/krb5/gssapi_err_krb5.et
U   trunk/src/lib/gssapi/krb5/gssapi_krb5.c
A   trunk/src/lib/gssapi/krb5/prf.c
A   trunk/src/lib/gssapi/krb5/store_cred.c
U   trunk/src/lib/gssapi/libgssapi_krb5.exports
U   trunk/src/lib/gssapi/mechglue/Makefile.in
U   trunk/src/lib/gssapi/mechglue/g_initialize.c
A   trunk/src/lib/gssapi/mechglue/g_prf.c
U   trunk/src/lib/gssapi/mechglue/g_store_cred.c
U   trunk/src/lib/gssapi/mechglue/mglueP.h
U   trunk/src/lib/gssapi/spnego/gssapiP_spnego.h
U   trunk/src/lib/gssapi/spnego/spnego_mech.c
U   trunk/src/tests/gssapi/Makefile.in
A   trunk/src/tests/gssapi/t_gssexts.c
Modified: trunk/src/lib/gssapi/generic/gssapi.hin
===================================================================
--- trunk/src/lib/gssapi/generic/gssapi.hin	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/generic/gssapi.hin	2009-12-17 04:49:27 UTC (rev 23479)
@@ -780,6 +780,31 @@
     const gss_OID,      /* mech_type */
     gss_name_t *);      /* output_name */
 
+/* RFC 4401 */
+
+#define GSS_C_PRF_KEY_FULL      0
+#define GSS_C_PRF_KEY_PARTIAL   1
+
+OM_uint32 KRB5_CALLCONV
+gss_pseudo_random(
+    OM_uint32 *,        /* minor_status */
+    gss_ctx_id_t,       /* context */
+    int,                /* prf_key */
+    const gss_buffer_t, /* prf_in */
+    ssize_t,            /* desired_output_len */
+    gss_buffer_t);      /* prf_out */
+
+OM_uint32 KRB5_CALLCONV
+gss_store_cred(
+    OM_uint32 *,        /* minor_status */
+    const gss_cred_id_t,/* input_cred_handle */
+    gss_cred_usage_t,   /* input_usage */
+    const gss_OID,      /* desired_mech */
+    OM_uint32,          /* overwrite_cred */
+    OM_uint32,          /* default_cred */
+    gss_OID_set *,      /* elements_stored */
+    gss_cred_usage_t *);/* cred_usage_stored */
+
 #if TARGET_OS_MAC
 #    pragma pack(pop)
 #endif

Modified: trunk/src/lib/gssapi/krb5/Makefile.in
===================================================================
--- trunk/src/lib/gssapi/krb5/Makefile.in	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/krb5/Makefile.in	2009-12-17 04:49:27 UTC (rev 23479)
@@ -68,6 +68,7 @@
 	$(srcdir)/krb5_gss_glue.c \
 	$(srcdir)/lucid_context.c \
 	$(srcdir)/naming_exts.c \
+	$(srcdir)/prf.c \
 	$(srcdir)/process_context_token.c \
 	$(srcdir)/rel_cred.c \
 	$(srcdir)/rel_oid.c \
@@ -78,6 +79,7 @@
 	$(srcdir)/ser_sctx.c \
 	$(srcdir)/set_ccache.c \
 	$(srcdir)/sign.c \
+	$(srcdir)/store_cred.c \
 	$(srcdir)/unseal.c \
 	$(srcdir)/util_cksum.c \
 	$(srcdir)/util_crypt.c \
@@ -120,6 +122,7 @@
 	$(OUTPRE)krb5_gss_glue.$(OBJEXT) \
 	$(OUTPRE)lucid_context.$(OBJEXT) \
 	$(OUTPRE)naming_exts.$(OBJEXT) \
+	$(OUTPRE)prf.$(OBJEXT) \
 	$(OUTPRE)process_context_token.$(OBJEXT) \
 	$(OUTPRE)rel_cred.$(OBJEXT) \
 	$(OUTPRE)rel_oid.$(OBJEXT) \
@@ -130,6 +133,7 @@
 	$(OUTPRE)ser_sctx.$(OBJEXT) \
 	$(OUTPRE)set_ccache.$(OBJEXT) \
 	$(OUTPRE)sign.$(OBJEXT) \
+	$(OUTPRE)store_cred.$(OBJEXT) \
 	$(OUTPRE)unseal.$(OBJEXT) \
 	$(OUTPRE)util_cksum.$(OBJEXT) \
 	$(OUTPRE)util_crypt.$(OBJEXT) \
@@ -175,6 +179,7 @@
 	krb5_gss_glue.o \
 	lucid_context.o \
 	naming_exts.o \
+	prf.o \
 	process_context_token.o \
 	rel_cred.o \
 	rel_oid.o \
@@ -185,6 +190,7 @@
 	ser_sctx.o \
 	set_ccache.o \
 	sign.o \
+	store_cred.o \
 	unseal.o \
 	util_cksum.o \
 	util_crypt.o \

Modified: trunk/src/lib/gssapi/krb5/gssapiP_krb5.h
===================================================================
--- trunk/src/lib/gssapi/krb5/gssapiP_krb5.h	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/krb5/gssapiP_krb5.h	2009-12-17 04:49:27 UTC (rev 23479)
@@ -909,6 +909,24 @@
                                   gss_buffer_t type_id,
                                   gss_any_t *input);
 
+OM_uint32
+krb5_gss_pseudo_random(OM_uint32 *minor_status,
+                       gss_ctx_id_t context,
+                       int prf_key,
+                       const gss_buffer_t prf_in,
+                       ssize_t desired_output_len,
+                       gss_buffer_t prf_out);
+
+OM_uint32
+krb5_gss_store_cred(OM_uint32 *minor_status,
+                    gss_cred_id_t input_cred_handle,
+                    gss_cred_usage_t cred_usage,
+                    const gss_OID desired_mech,
+                    OM_uint32 overwrite_cred,
+                    OM_uint32 default_cred,
+                    gss_OID_set *elements_stored,
+                    gss_cred_usage_t *cred_usage_stored);
+
 /* s4u_gss_glue.c */
 OM_uint32
 kg_compose_deleg_cred(OM_uint32 *minor_status,

Modified: trunk/src/lib/gssapi/krb5/gssapi_err_krb5.et
===================================================================
--- trunk/src/lib/gssapi/krb5/gssapi_err_krb5.et	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/krb5/gssapi_err_krb5.et	2009-12-17 04:49:27 UTC (rev 23479)
@@ -37,4 +37,5 @@
 error_code KG_EMPTY_CCACHE, "Credential cache is empty"
 error_code KG_NO_CTYPES, "Acceptor and Initiator share no checksum types"
 error_code KG_LUCID_VERSION, "Requested lucid context version not supported"
+error_code KG_INPUT_TOO_LONG, "PRF input too long"
 end

Modified: trunk/src/lib/gssapi/krb5/gssapi_krb5.c
===================================================================
--- trunk/src/lib/gssapi/krb5/gssapi_krb5.c	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/krb5/gssapi_krb5.c	2009-12-17 04:49:27 UTC (rev 23479)
@@ -671,7 +671,7 @@
     krb5_gss_internal_release_oid,
     krb5_gss_wrap_size_limit,
     krb5_gss_export_name,
-    NULL,                        /* store_cred */
+    krb5_gss_store_cred,
     krb5_gss_inquire_sec_context_by_oid,
     krb5_gss_inquire_cred_by_oid,
     krb5_gss_set_sec_context_option,
@@ -693,6 +693,7 @@
     krb5_gss_export_name_composite,
     krb5_gss_map_name_to_any,
     krb5_gss_release_any_name_mapping,
+    krb5_gss_pseudo_random,
 };
 
 

Copied: trunk/src/lib/gssapi/krb5/prf.c (from rev 23476, users/lhoward/gssextras-no-cqa/src/lib/gssapi/krb5/prf.c)
===================================================================
--- trunk/src/lib/gssapi/krb5/prf.c	                        (rev 0)
+++ trunk/src/lib/gssapi/krb5/prf.c	2009-12-17 04:49:27 UTC (rev 23479)
@@ -0,0 +1,139 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * lib/gssapi/krb5/prf.c
+ *
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ */
+
+#include <assert.h>
+#include "k5-int.h"          /* for zap() */
+#include "gssapiP_krb5.h"
+#include <stdarg.h>
+
+OM_uint32
+krb5_gss_pseudo_random(OM_uint32 *minor_status,
+                       gss_ctx_id_t context,
+                       int prf_key,
+                       const gss_buffer_t prf_in,
+                       ssize_t desired_output_len,
+                       gss_buffer_t prf_out)
+{
+    krb5_error_code code;
+    krb5_key key = NULL;
+    krb5_gss_ctx_id_t ctx;
+    int i;
+    OM_uint32 minor;
+    size_t prflen;
+    krb5_data t, ns;
+    unsigned char *p;
+
+    prf_out->length = 0;
+    prf_out->value = NULL;
+
+    if (!kg_validate_ctx_id(context)) {
+        *minor_status = G_VALIDATE_FAILED;
+        return GSS_S_NO_CONTEXT;
+    }
+
+    t.length = 0;
+    t.data = NULL;
+
+    ns.length = 0;
+    ns.data = NULL;
+
+    ctx = (krb5_gss_ctx_id_t)context;
+
+    switch (prf_key) {
+    case GSS_C_PRF_KEY_FULL:
+        if (ctx->have_acceptor_subkey) {
+            key = ctx->acceptor_subkey;
+            break;
+        }
+        /* fallthrough */
+    case GSS_C_PRF_KEY_PARTIAL:
+        key = ctx->subkey;
+        break;
+    default:
+        code = EINVAL;
+        goto cleanup;
+    }
+
+    if (key == NULL) {
+        code = EINVAL;
+        goto cleanup;
+    }
+
+    prf_out->value = k5alloc(desired_output_len, &code);
+    if (prf_out->value == NULL) {
+        code = KG_INPUT_TOO_LONG;
+        goto cleanup;
+    }
+    prf_out->length = desired_output_len;
+
+    code = krb5_c_prf_length(ctx->k5_context,
+                             krb5_k_key_enctype(ctx->k5_context, key),
+                             &prflen);
+    if (code != 0)
+        goto cleanup;
+
+    ns.length = 4 + prf_in->length;
+    ns.data = k5alloc(ns.length, &code);
+    if (ns.data == NULL) {
+        code = KG_INPUT_TOO_LONG;
+        goto cleanup;
+    }
+
+    t.length = prflen;
+    t.data = k5alloc(t.length, &code);
+    if (t.data == NULL)
+        goto cleanup;
+
+    memcpy(ns.data + 4, prf_in->value, prf_in->length);
+    i = 0;
+    p = (unsigned char *)prf_out->value;
+    while (desired_output_len > 0) {
+        store_32_be(i, ns.data);
+
+        code = krb5_k_prf(ctx->k5_context, key, &ns, &t);
+        if (code != 0)
+            goto cleanup;
+
+        memcpy(p, t.data, MIN(t.length, desired_output_len));
+
+        p += t.length;
+        desired_output_len -= t.length;
+        i++;
+    }
+
+cleanup:
+    if (code != 0)
+        gss_release_buffer(&minor, prf_out);
+    krb5_free_data_contents(ctx->k5_context, &ns);
+    krb5_free_data_contents(ctx->k5_context, &t);
+
+    *minor_status = (OM_uint32)code;
+    return (code == 0) ? GSS_S_COMPLETE : GSS_S_FAILURE;
+}
+

Copied: trunk/src/lib/gssapi/krb5/store_cred.c (from rev 23476, users/lhoward/gssextras-no-cqa/src/lib/gssapi/krb5/store_cred.c)
===================================================================
--- trunk/src/lib/gssapi/krb5/store_cred.c	                        (rev 0)
+++ trunk/src/lib/gssapi/krb5/store_cred.c	2009-12-17 04:49:27 UTC (rev 23479)
@@ -0,0 +1,188 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * lib/gssapi/krb5/store_cred.c
+ *
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ *
+ */
+
+#include <assert.h>
+#include "k5-int.h"          /* for zap() */
+#include "gssapiP_krb5.h"
+#include <stdarg.h>
+
+static int
+has_unexpired_creds(krb5_gss_cred_id_t kcred,
+                    const gss_OID desired_mech,
+                    int default_cred)
+{
+    OM_uint32 major_status, minor;
+    gss_name_t cred_name;
+    gss_OID_set_desc desired_mechs;
+    gss_cred_id_t tmp_cred = GSS_C_NO_CREDENTIAL;
+    OM_uint32 time_rec;
+
+    desired_mechs.count = 1;
+    desired_mechs.elements = (gss_OID)desired_mech;
+
+    if (default_cred)
+        cred_name = GSS_C_NO_NAME;
+    else
+        cred_name = (gss_name_t)kcred->name;
+
+    major_status = krb5_gss_acquire_cred(&minor, cred_name, 0,
+                                         &desired_mechs, GSS_C_INITIATE,
+                                         &tmp_cred, NULL, &time_rec);
+
+    krb5_gss_release_cred(&minor, &tmp_cred);
+
+    return (GSS_ERROR(major_status) || time_rec);
+}
+
+static OM_uint32
+copy_initiator_creds(OM_uint32 *minor_status,
+                     gss_cred_id_t input_cred_handle,
+                     const gss_OID desired_mech,
+                     OM_uint32 overwrite_cred,
+                     OM_uint32 default_cred)
+{
+    OM_uint32 major_status;
+    krb5_error_code code;
+    krb5_gss_cred_id_t kcred = NULL;
+    krb5_context context = NULL;
+    krb5_ccache ccache = NULL;
+
+    if (!default_cred) {
+        *minor_status = G_STORE_NON_DEFAULT_CRED_NOSUPP;
+        major_status = GSS_S_FAILURE;
+        goto cleanup;
+    }
+
+    code = krb5_gss_init_context(&context);
+    if (code != 0) {
+        *minor_status = code;
+        major_status = GSS_S_FAILURE;
+        goto cleanup;
+    }
+
+    major_status = krb5_gss_validate_cred_1(minor_status,
+                                            input_cred_handle,
+                                            context);
+    if (GSS_ERROR(major_status))
+        goto cleanup;
+
+    kcred = (krb5_gss_cred_id_t)input_cred_handle;
+
+    if (kcred->ccache == NULL || kcred->proxy_cred) {
+        *minor_status = KG_CCACHE_NOMATCH;
+        major_status = GSS_S_DEFECTIVE_CREDENTIAL;
+        goto cleanup;
+    }
+
+    if (!overwrite_cred &&
+        has_unexpired_creds(kcred, desired_mech, default_cred)) {
+        major_status = GSS_S_DUPLICATE_ELEMENT;
+        goto cleanup;
+    }
+
+    code = krb5int_cc_default(context, &ccache);
+    if (code != 0) {
+        *minor_status = code;
+        major_status = GSS_S_FAILURE;
+        goto cleanup;
+    }
+
+    code = krb5_cc_copy_creds(context, kcred->ccache, ccache);
+    if (code != 0) {
+        *minor_status = code;
+        major_status = GSS_S_FAILURE;
+        goto cleanup;
+    }
+
+    *minor_status = 0;
+    major_status = GSS_S_COMPLETE;
+
+cleanup:
+    if (kcred != NULL)
+        k5_mutex_unlock(&kcred->lock);
+
+    krb5_cc_close(context, ccache);
+    krb5_free_context(context);
+
+    return major_status;
+}
+
+OM_uint32
+krb5_gss_store_cred(OM_uint32 *minor_status,
+                    gss_cred_id_t input_cred_handle,
+                    gss_cred_usage_t cred_usage,
+                    const gss_OID desired_mech,
+                    OM_uint32 overwrite_cred,
+                    OM_uint32 default_cred,
+                    gss_OID_set *elements_stored,
+                    gss_cred_usage_t *cred_usage_stored)
+{
+    OM_uint32 major_status;
+    gss_cred_usage_t actual_usage;
+    OM_uint32 lifetime;
+
+    if (input_cred_handle == GSS_C_NO_CREDENTIAL)
+        return GSS_S_NO_CRED;
+
+    major_status = GSS_S_FAILURE;
+
+    if (cred_usage == GSS_C_ACCEPT) {
+        *minor_status = G_STORE_ACCEPTOR_CRED_NOSUPP;
+        return GSS_S_FAILURE;
+    } else if (cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
+        *minor_status = G_BAD_USAGE;
+        return GSS_S_FAILURE;
+    }
+
+    major_status = krb5_gss_inquire_cred(minor_status, input_cred_handle,
+                                         NULL, &lifetime,
+                                         &actual_usage, elements_stored);
+    if (GSS_ERROR(major_status))
+        return major_status;
+
+    if (lifetime == 0)
+        return GSS_S_CREDENTIALS_EXPIRED;
+
+    if (actual_usage != GSS_C_INITIATE && actual_usage != GSS_C_BOTH) {
+        *minor_status = G_BAD_USAGE;
+        return GSS_S_FAILURE;
+    }
+
+    major_status = copy_initiator_creds(minor_status, input_cred_handle,
+                                        desired_mech, overwrite_cred,
+                                        default_cred);
+    if (GSS_ERROR(major_status))
+        return major_status;
+
+    if (cred_usage_stored != NULL)
+        *cred_usage_stored = GSS_C_INITIATE;
+
+    return GSS_S_COMPLETE;
+}
+

Modified: trunk/src/lib/gssapi/libgssapi_krb5.exports
===================================================================
--- trunk/src/lib/gssapi/libgssapi_krb5.exports	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/libgssapi_krb5.exports	2009-12-17 04:49:27 UTC (rev 23479)
@@ -68,6 +68,7 @@
 gss_nt_string_uid_name
 gss_nt_user_name
 gss_oid_to_str
+gss_pseudo_random
 gss_process_context_token
 gss_release_any_name_mapping
 gss_release_buffer_set
@@ -81,6 +82,7 @@
 gss_set_name_attribute
 gss_set_sec_context_option
 gss_sign
+gss_store_cred
 gss_str_to_oid
 gss_test_oid_set_member
 gss_unseal

Modified: trunk/src/lib/gssapi/mechglue/Makefile.in
===================================================================
--- trunk/src/lib/gssapi/mechglue/Makefile.in	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/mechglue/Makefile.in	2009-12-17 04:49:27 UTC (rev 23479)
@@ -43,6 +43,7 @@
 	$(srcdir)/g_mech_invoke.c \
 	$(srcdir)/g_mechname.c \
 	$(srcdir)/g_oid_ops.c \
+	$(srcdir)/g_prf.c \
 	$(srcdir)/g_process_context.c \
 	$(srcdir)/g_rel_buffer.c \
 	$(srcdir)/g_rel_cred.c \
@@ -96,6 +97,7 @@
 	$(OUTPRE)g_mech_invoke.$(OBJEXT) \
 	$(OUTPRE)g_mechname.$(OBJEXT) \
 	$(OUTPRE)g_oid_ops.$(OBJEXT) \
+	$(OUTPRE)g_prf.$(OBJEXT) \
 	$(OUTPRE)g_process_context.$(OBJEXT) \
 	$(OUTPRE)g_rel_buffer.$(OBJEXT) \
 	$(OUTPRE)g_rel_cred.$(OBJEXT) \
@@ -149,6 +151,7 @@
 	g_mech_invoke.o \
 	g_mechname.o \
 	g_oid_ops.o \
+	g_prf.o \
 	g_process_context.o \
 	g_rel_buffer.o \
 	g_rel_cred.o \

Modified: trunk/src/lib/gssapi/mechglue/g_initialize.c
===================================================================
--- trunk/src/lib/gssapi/mechglue/g_initialize.c	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/mechglue/g_initialize.c	2009-12-17 04:49:27 UTC (rev 23479)
@@ -773,6 +773,8 @@
 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_export_name_composite);
 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_map_name_to_any);
 	GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_release_any_name_mapping);
+        /* RFC 4401 (introduced in 1.8) */
+	GSS_ADD_DYNAMIC_METHOD(dl, mech, gss_pseudo_random);
 
 	assert(mech_type != GSS_C_NO_OID);
 

Copied: trunk/src/lib/gssapi/mechglue/g_prf.c (from rev 23476, users/lhoward/gssextras-no-cqa/src/lib/gssapi/mechglue/g_prf.c)
===================================================================
--- trunk/src/lib/gssapi/mechglue/g_prf.c	                        (rev 0)
+++ trunk/src/lib/gssapi/mechglue/g_prf.c	2009-12-17 04:49:27 UTC (rev 23479)
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2009 by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+/*
+ *  glue routine for gss_pseudo_random
+ */
+
+#include "mglueP.h"
+
+OM_uint32 KRB5_CALLCONV
+gss_pseudo_random (OM_uint32 *minor_status,
+	           gss_ctx_id_t context_handle,
+	           int prf_key,
+	           const gss_buffer_t prf_in,
+	           ssize_t desired_output_len,
+	           gss_buffer_t prf_out)
+{
+    OM_uint32		status;
+    gss_union_ctx_id_t	ctx;
+    gss_mechanism	mech;
+
+    if (minor_status == NULL)
+	return GSS_S_CALL_INACCESSIBLE_WRITE;
+
+    if (context_handle == GSS_C_NO_CONTEXT)
+	return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
+
+    if (prf_in == GSS_C_NO_BUFFER)
+	return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CONTEXT;
+
+    if (prf_out == GSS_C_NO_BUFFER)
+	return GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CONTEXT;
+
+    prf_out->length = 0;
+    prf_out->value = NULL;
+
+    /*
+     * select the approprate underlying mechanism routine and
+     * call it.
+     */
+
+    ctx = (gss_union_ctx_id_t) context_handle;
+    mech = gssint_get_mechanism (ctx->mech_type);
+
+    if (mech != NULL) {
+	if (mech->gss_pseudo_random != NULL) {
+	    status = mech->gss_pseudo_random(minor_status,
+					     ctx->internal_ctx_id,
+					     prf_key,
+					     prf_in,
+					     desired_output_len,
+					     prf_out);
+	    if (status != GSS_S_COMPLETE)
+		map_error(minor_status, mech);
+	} else
+	    status = GSS_S_UNAVAILABLE;
+
+	return status;
+    }
+
+    return GSS_S_BAD_MECH;
+}

Modified: trunk/src/lib/gssapi/mechglue/g_store_cred.c
===================================================================
--- trunk/src/lib/gssapi/mechglue/g_store_cred.c	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/mechglue/g_store_cred.c	2009-12-17 04:49:27 UTC (rev 23479)
@@ -63,7 +63,7 @@
 			cred_usage_stored)
 
 OM_uint32		*minor_status;
-const gss_cred_id_t	 input_cred_handle;
+gss_cred_id_t	         input_cred_handle;
 gss_cred_usage_t	 cred_usage;
 const gss_OID		 desired_mech;
 OM_uint32		 overwrite_cred;

Modified: trunk/src/lib/gssapi/mechglue/mglueP.h
===================================================================
--- trunk/src/lib/gssapi/mechglue/mglueP.h	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/mechglue/mglueP.h	2009-12-17 04:49:27 UTC (rev 23479)
@@ -573,6 +573,16 @@
 	    gss_any_t *			/* input */
 	/* */);
 
+        OM_uint32       (*gss_pseudo_random)
+        (
+            OM_uint32 *,                /* minor_status */
+            gss_ctx_id_t,               /* context */
+            int,                        /* prf_key */
+            const gss_buffer_t,         /* prf_in */
+            ssize_t,                    /* desired_output_len */
+            gss_buffer_t                /* prf_out */
+        /* */);
+
 } *gss_mechanism;
 
 /* This structure MUST NOT be used by any code outside libgss */

Modified: trunk/src/lib/gssapi/spnego/gssapiP_spnego.h
===================================================================
--- trunk/src/lib/gssapi/spnego/gssapiP_spnego.h	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/spnego/gssapiP_spnego.h	2009-12-17 04:49:27 UTC (rev 23479)
@@ -519,6 +519,17 @@
 	gss_any_t *input
 );
 
+OM_uint32
+spnego_gss_pseudo_random
+(
+	OM_uint32 *minor_status,
+	gss_ctx_id_t context,
+	int prf_key,
+	const gss_buffer_t prf_in,
+	ssize_t desired_output_len,
+	gss_buffer_t prf_out
+);
+
 #ifdef	__cplusplus
 }
 #endif

Modified: trunk/src/lib/gssapi/spnego/spnego_mech.c
===================================================================
--- trunk/src/lib/gssapi/spnego/spnego_mech.c	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/lib/gssapi/spnego/spnego_mech.c	2009-12-17 04:49:27 UTC (rev 23479)
@@ -268,6 +268,7 @@
 	spnego_gss_export_name_composite,
 	spnego_gss_map_name_to_any,
 	spnego_gss_release_any_name_mapping,
+	spnego_gss_pseudo_random,
 };
 
 #ifdef _GSS_STATIC_LINK
@@ -2485,6 +2486,24 @@
 	return (ret);
 }
 
+OM_uint32
+spnego_gss_pseudo_random(OM_uint32 *minor_status,
+			 gss_ctx_id_t context,
+			 int prf_key,
+			 const gss_buffer_t prf_in,
+			 ssize_t desired_output_len,
+			 gss_buffer_t prf_out)
+{
+	OM_uint32 ret;
+	ret = gss_pseudo_random(minor_status,
+				context,
+				prf_key,
+				prf_in,
+				desired_output_len,
+				prf_out);
+        return (ret);
+}
+
 /*
  * We will release everything but the ctx_handle so that it
  * can be passed back to init/accept context. This routine should

Modified: trunk/src/tests/gssapi/Makefile.in
===================================================================
--- trunk/src/tests/gssapi/Makefile.in	2009-12-16 23:33:29 UTC (rev 23478)
+++ trunk/src/tests/gssapi/Makefile.in	2009-12-17 04:49:27 UTC (rev 23479)
@@ -4,19 +4,21 @@
 PROG_LIBPATH=-L$(TOPLIBD)
 PROG_RPATH=$(KRB5_LIBDIR)
 
-SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c $(srcdir)/t_namingexts.c
+SRCS= $(srcdir)/t_imp_name.c $(srcdir)/t_s4u.c $(srcdir)/t_namingexts.c $(srcdir)/t_gssexts.c
 
-OBJS= t_imp_name.o t_s4u.o t_namingexts.o
+OBJS= t_imp_name.o t_s4u.o t_namingexts.o t_gssexts.o
 
-all:: t_imp_name t_s4u t_namingexts
+all:: t_imp_name t_s4u t_namingexts t_gssexts
 
 t_imp_name: t_imp_name.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o t_imp_name t_imp_name.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+t_s4u: t_s4u.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_s4u t_s4u.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
 t_namingexts: t_namingexts.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
 	$(CC_LINK) -o t_namingexts t_namingexts.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
-t_s4u: t_s4u.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
-	$(CC_LINK) -o t_s4u t_s4u.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
+t_gssexts: t_gssexts.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+	$(CC_LINK) -o t_gssexts t_gssexts.o $(GSS_LIBS) $(KRB5_BASE_LIBS)
 
 clean::
-	$(RM) t_imp_name t_s4u t_namingexts
+	$(RM) t_imp_name t_s4u t_namingexts t_gssexts
 

Copied: trunk/src/tests/gssapi/t_gssexts.c (from rev 23476, users/lhoward/gssextras-no-cqa/src/tests/gssapi/t_gssexts.c)
===================================================================
--- trunk/src/tests/gssapi/t_gssexts.c	                        (rev 0)
+++ trunk/src/tests/gssapi/t_gssexts.c	2009-12-17 04:49:27 UTC (rev 23479)
@@ -0,0 +1,420 @@
+/* -*- mode: c; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 2009  by the Massachusetts Institute of Technology.
+ * All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ *   require a specific license from the United States Government.
+ *   It is the responsibility of any person or organization contemplating
+ *   export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission.  Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is" without express
+ * or implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gssapi/gssapi_krb5.h>
+
+/*
+ * Test program for protocol transition (S4U2Self) and constrained delegation
+ * (S4U2Proxy)
+ *
+ * Note: because of name canonicalization, the following tips may help
+ * when configuring with Active Directory:
+ *
+ * - Create a computer account FOO$
+ * - Set the UPN to host/foo.domain (no suffix); this is necessary to
+ *   be able to send an AS-REQ as this principal, otherwise you would
+ *   need to use the canonical name (FOO$), which will cause principal
+ *   comparison errors in gss_accept_sec_context().
+ * - Add a SPN of host/foo.domain
+ * - Configure the computer account to support constrained delegation with
+ *   protocol transition (Trust this computer for delegation to specified
+ *   services only / Use any authentication protocol)
+ * - Add host/foo.domain to the keytab (possibly easiest to do this
+ *   with ktadd)
+ *
+ * For S4U2Proxy to work the TGT must be forwardable too.
+ *
+ * Usage eg:
+ *
+ * kinit -k -t test.keytab -f 'host/test.win.mit.edu at WIN.MIT.EDU'
+ * ./t_s4u delegtest at WIN.MIT.EDU HOST/WIN-EQ7E4AA2WR8.win.mit.edu at WIN.MIT.EDU test.keytab
+ */
+
+static gss_OID_desc spnego_mech = { 6, "\053\006\001\005\005\002" };
+
+static int use_spnego = 0;
+
+static void displayStatus_1(m, code, type)
+     char *m;
+     OM_uint32 code;
+     int type;
+{
+     OM_uint32 maj_stat, min_stat;
+     gss_buffer_desc msg;
+     OM_uint32 msg_ctx;
+
+     msg_ctx = 0;
+     while (1) {
+          maj_stat = gss_display_status(&min_stat, code,
+                                       type, GSS_C_NULL_OID,
+                                       &msg_ctx, &msg);
+          fprintf(stderr, "%s: %s\n", m, (char *)msg.value);
+          (void) gss_release_buffer(&min_stat, &msg);
+
+          if (!msg_ctx)
+               break;
+     }
+}
+
+static void displayStatus(msg, maj_stat, min_stat)
+     char *msg;
+     OM_uint32 maj_stat;
+     OM_uint32 min_stat;
+{
+     displayStatus_1(msg, maj_stat, GSS_C_GSS_CODE);
+     displayStatus_1(msg, min_stat, GSS_C_MECH_CODE);
+}
+
+static OM_uint32
+displayCanonName(OM_uint32 *minor, gss_name_t name, char *tag)
+{
+    gss_name_t canon;
+    OM_uint32 major, tmp_minor;
+    gss_buffer_desc buf;
+
+    major = gss_canonicalize_name(minor, name,
+                                  (gss_OID)gss_mech_krb5, &canon);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_canonicalize_name", major, *minor);
+        return major;
+    }
+
+    major = gss_display_name(minor, canon, &buf, NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_display_name", major, *minor);
+        gss_release_name(&tmp_minor, &canon);
+        return major;
+    }
+
+    printf("%s:\t%s\n", tag, (char *)buf.value);
+
+    gss_release_buffer(&tmp_minor, &buf);
+    gss_release_name(&tmp_minor, &canon);
+
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+displayOID(OM_uint32 *minor, gss_OID oid, char *tag)
+{
+    OM_uint32 major, tmp_minor;
+    gss_buffer_desc buf;
+
+    major = gss_oid_to_str(minor, oid, &buf);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_oid_to_str", major, *minor);
+        return major;
+    }
+
+    printf("%s:\t%s\n", tag, (char *)buf.value);
+
+    gss_release_buffer(&tmp_minor, &buf);
+
+    return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+testPrf(OM_uint32 *minor,
+        gss_ctx_id_t initiatorContext,
+        gss_ctx_id_t acceptorContext,
+        int flags)
+{
+    gss_buffer_desc constant;
+    OM_uint32 major, tmp_minor;
+    unsigned int i;
+    gss_buffer_desc initiatorPrf;
+    gss_buffer_desc acceptorPrf;
+
+    constant.value = "gss prf test";
+    constant.length = strlen((char *)constant.value);
+
+    initiatorPrf.value = NULL;
+    acceptorPrf.value = NULL;
+
+    major = gss_pseudo_random(minor, initiatorContext, flags,
+                              &constant, 19, &initiatorPrf);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_pseudo_random", major, *minor);
+        return major;
+    }
+
+    printf("%s\n", flags == GSS_C_PRF_KEY_FULL ?
+        "PRF_KEY_FULL" : "PRF_KEY_PARTIAL");
+
+    printf("Initiator PRF: ");
+    for (i = 0; i < initiatorPrf.length; i++) {
+        printf("%02x ", ((char *)initiatorPrf.value)[i] & 0xFF);
+    }
+    printf("\n");
+
+    major = gss_pseudo_random(minor, acceptorContext, flags,
+                              &constant, 19, &acceptorPrf);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_pseudo_random", major, *minor);
+        gss_release_buffer(&tmp_minor, &initiatorPrf);
+        return major;
+    }
+
+    printf("Acceptor  PRF: ");
+    for (i = 0; i < acceptorPrf.length; i++) {
+        printf("%02x ", ((char *)acceptorPrf.value)[i] & 0xFF);
+    }
+    printf("\n");
+
+    if (acceptorPrf.length != initiatorPrf.length ||
+        memcmp(acceptorPrf.value, initiatorPrf.value, initiatorPrf.length)) {
+        fprintf(stderr, "Initiator and acceptor PRF output does not match\n");
+        major = GSS_S_FAILURE;
+    }
+
+    gss_release_buffer(&tmp_minor, &initiatorPrf);
+    gss_release_buffer(&tmp_minor, &acceptorPrf);
+
+    return major;
+}
+
+static OM_uint32
+initAcceptSecContext(OM_uint32 *minor,
+                     gss_cred_id_t claimant_cred_handle,
+                     gss_cred_id_t verifier_cred_handle,
+                     gss_cred_id_t *deleg_cred_handle)
+{
+    OM_uint32 major, tmp_minor;
+    gss_buffer_desc token, tmp;
+    gss_ctx_id_t initiator_context = GSS_C_NO_CONTEXT;
+    gss_ctx_id_t acceptor_context = GSS_C_NO_CONTEXT;
+    gss_name_t source_name = GSS_C_NO_NAME;
+    gss_name_t target_name = GSS_C_NO_NAME;
+    OM_uint32 time_rec;
+    gss_OID mech = GSS_C_NO_OID;
+
+    token.value = NULL;
+    token.length = 0;
+
+    tmp.value = NULL;
+    tmp.length = 0;
+
+    *deleg_cred_handle = GSS_C_NO_CREDENTIAL;
+
+    major = gss_inquire_cred(minor, verifier_cred_handle,
+                             &target_name, NULL, NULL, NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_inquire_cred", major, *minor);
+        return major;
+    }
+
+    displayCanonName(minor, target_name, "Target name");
+
+    mech = use_spnego ? (gss_OID)&spnego_mech : (gss_OID)gss_mech_krb5;
+    displayOID(minor, mech, "Target mech");
+
+    major = gss_init_sec_context(minor,
+                                 claimant_cred_handle,
+                                 &initiator_context,
+                                 target_name,
+                                 mech,
+                                 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);
+
+    if (target_name != GSS_C_NO_NAME)
+        (void) gss_release_name(&tmp_minor, &target_name);
+
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_init_sec_context", major, *minor);
+        return major;
+    }
+
+    mech = GSS_C_NO_OID;
+
+    major = gss_accept_sec_context(minor,
+                                   &acceptor_context,
+                                   verifier_cred_handle,
+                                   &token,
+                                   GSS_C_NO_CHANNEL_BINDINGS,
+                                   &source_name,
+                                   &mech,
+                                   &tmp,
+                                   NULL,
+                                   &time_rec,
+                                   deleg_cred_handle);
+
+    if (GSS_ERROR(major))
+        displayStatus("gss_accept_sec_context", major, *minor);
+    else {
+        testPrf(minor, initiator_context, acceptor_context, GSS_C_PRF_KEY_FULL);
+        testPrf(minor, initiator_context, acceptor_context, GSS_C_PRF_KEY_PARTIAL);
+    }
+
+    (void) gss_release_name(&tmp_minor, &source_name);
+    (void) gss_delete_sec_context(&tmp_minor, &acceptor_context, NULL);
+    (void) gss_delete_sec_context(minor, &initiator_context, NULL);
+    (void) gss_release_buffer(&tmp_minor, &token);
+    (void) gss_release_buffer(&tmp_minor, &tmp);
+    (void) gss_release_oid(&tmp_minor, &mech);
+
+    return major;
+}
+
+int main(int argc, char *argv[])
+{
+    OM_uint32 minor, major;
+    gss_cred_id_t impersonator_cred_handle = GSS_C_NO_CREDENTIAL;
+    gss_cred_id_t user_cred_handle = GSS_C_NO_CREDENTIAL;
+    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_desc mechs;
+    gss_OID_set actual_mechs = GSS_C_NO_OID_SET;
+    gss_buffer_desc buf;
+
+    if (argc < 2 || argc > 5) {
+        fprintf(stderr, "Usage: %s [--spnego] [user] "
+                        "[proxy-target] [keytab]\n", argv[0]);
+        fprintf(stderr, "       proxy-target and keytab are optional\n");
+        exit(1);
+    }
+
+    if (strcmp(argv[1], "--spnego") == 0) {
+        use_spnego++;
+        argc--;
+        argv++;
+    }
+
+    buf.value = argv[1];
+    buf.length = strlen((char *)buf.value);
+
+    major = gss_import_name(&minor, &buf,
+                            (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
+                            &user);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_import_name(user)", major, minor);
+        goto out;
+    }
+
+    if (argc > 2 && strcmp(argv[2], "-")) {
+        buf.value = argv[2];
+        buf.length = strlen((char *)buf.value);
+
+        major = gss_import_name(&minor, &buf,
+                                (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME,
+                                &target);
+        if (GSS_ERROR(major)) {
+            displayStatus("gss_import_name(target)", major, minor);
+            goto out;
+        }
+    } else {
+        target = GSS_C_NO_NAME;
+    }
+
+    if (argc > 3) {
+        major = krb5_gss_register_acceptor_identity(argv[3]);
+        if (GSS_ERROR(major)) {
+            displayStatus("krb5_gss_register_acceptor_identity",
+                          major, minor);
+            goto out;
+        }
+    }
+
+    mechs.elements = use_spnego ? (gss_OID)&spnego_mech :
+                                  (gss_OID)gss_mech_krb5;
+    mechs.count = 1;
+
+    /* get default cred */
+    major = gss_acquire_cred(&minor,
+                             GSS_C_NO_NAME,
+                             GSS_C_INDEFINITE,
+                             &mechs,
+                             GSS_C_BOTH,
+                             &impersonator_cred_handle,
+                             &actual_mechs,
+                             NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_acquire_cred", major, minor);
+        goto out;
+    }
+
+    (void) gss_release_oid_set(&minor, &actual_mechs);
+
+    printf("Protocol transition tests follow\n");
+    printf("-----------------------------------\n\n");
+
+    /* get S4U2Self cred */
+    major = gss_acquire_cred_impersonate_name(&minor,
+                                              impersonator_cred_handle,
+                                              user,
+                                              GSS_C_INDEFINITE,
+                                              &mechs,
+                                              GSS_C_INITIATE,
+                                              &user_cred_handle,
+                                              &actual_mechs,
+                                              NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_acquire_cred_impersonate_name", major, minor);
+        goto out;
+    }
+
+    /* Try to store it in default ccache */
+    major = gss_store_cred(&minor,
+                           user_cred_handle,
+                           GSS_C_INITIATE,
+                           &mechs.elements[0],
+                           1,
+                           1,
+                           NULL,
+                           NULL);
+    if (GSS_ERROR(major)) {
+        displayStatus("gss_store_cred", major, minor);
+        goto out;
+    }
+
+    major = initAcceptSecContext(&minor,
+                                 user_cred_handle,
+                                 impersonator_cred_handle,
+                                 &delegated_cred_handle);
+    if (GSS_ERROR(major))
+        goto out;
+
+    printf("\n");
+
+out:
+    (void) gss_release_name(&minor, &user);
+    (void) gss_release_name(&minor, &target);
+    (void) gss_release_cred(&minor, &delegated_cred_handle);
+    (void) gss_release_cred(&minor, &impersonator_cred_handle);
+    (void) gss_release_cred(&minor, &user_cred_handle);
+    (void) gss_release_oid_set(&minor, &actual_mechs);
+
+    return GSS_ERROR(major) ? 1 : 0;
+}




More information about the cvs-krb5 mailing list