summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGreg Hudson <ghudson@mit.edu>2009-12-17 04:49:27 +0000
committerGreg Hudson <ghudson@mit.edu>2009-12-17 04:49:27 +0000
commit00784193904880a9e7f73ff477d287cd22d4e158 (patch)
treef04c444af920a28dcbbe4f1730db6021301211b7
parent09b6eb4836a4ec82fc2145db185737a9e7d4b9e1 (diff)
downloadkrb5-00784193904880a9e7f73ff477d287cd22d4e158.tar.gz
krb5-00784193904880a9e7f73ff477d287cd22d4e158.tar.xz
krb5-00784193904880a9e7f73ff477d287cd22d4e158.zip
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. ticket: 6597 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@23479 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r--src/lib/gssapi/generic/gssapi.hin25
-rw-r--r--src/lib/gssapi/krb5/Makefile.in6
-rw-r--r--src/lib/gssapi/krb5/gssapiP_krb5.h18
-rw-r--r--src/lib/gssapi/krb5/gssapi_err_krb5.et1
-rw-r--r--src/lib/gssapi/krb5/gssapi_krb5.c3
-rw-r--r--src/lib/gssapi/krb5/prf.c139
-rw-r--r--src/lib/gssapi/krb5/store_cred.c188
-rw-r--r--src/lib/gssapi/libgssapi_krb5.exports2
-rw-r--r--src/lib/gssapi/mechglue/Makefile.in3
-rw-r--r--src/lib/gssapi/mechglue/g_initialize.c2
-rw-r--r--src/lib/gssapi/mechglue/g_prf.c84
-rw-r--r--src/lib/gssapi/mechglue/g_store_cred.c2
-rw-r--r--src/lib/gssapi/mechglue/mglueP.h10
-rw-r--r--src/lib/gssapi/spnego/gssapiP_spnego.h11
-rw-r--r--src/lib/gssapi/spnego/spnego_mech.c19
-rw-r--r--src/tests/gssapi/Makefile.in14
-rw-r--r--src/tests/gssapi/t_gssexts.c420
17 files changed, 939 insertions, 8 deletions
diff --git a/src/lib/gssapi/generic/gssapi.hin b/src/lib/gssapi/generic/gssapi.hin
index 422b4dbef..e60d04d87 100644
--- a/src/lib/gssapi/generic/gssapi.hin
+++ b/src/lib/gssapi/generic/gssapi.hin
@@ -780,6 +780,31 @@ gss_canonicalize_name(
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
diff --git a/src/lib/gssapi/krb5/Makefile.in b/src/lib/gssapi/krb5/Makefile.in
index 6dee42367..01591b2c0 100644
--- a/src/lib/gssapi/krb5/Makefile.in
+++ b/src/lib/gssapi/krb5/Makefile.in
@@ -68,6 +68,7 @@ SRCS = \
$(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 @@ SRCS = \
$(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 @@ OBJS = \
$(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 @@ OBJS = \
$(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 @@ STLIBOBJS = \
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 @@ STLIBOBJS = \
ser_sctx.o \
set_ccache.o \
sign.o \
+ store_cred.o \
unseal.o \
util_cksum.o \
util_crypt.o \
diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h
index 0127e8ccb..2ac4b3ae2 100644
--- a/src/lib/gssapi/krb5/gssapiP_krb5.h
+++ b/src/lib/gssapi/krb5/gssapiP_krb5.h
@@ -909,6 +909,24 @@ krb5_gss_release_any_name_mapping(OM_uint32 *minor_status,
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,
diff --git a/src/lib/gssapi/krb5/gssapi_err_krb5.et b/src/lib/gssapi/krb5/gssapi_err_krb5.et
index c2a705c84..4cfd68a00 100644
--- a/src/lib/gssapi/krb5/gssapi_err_krb5.et
+++ b/src/lib/gssapi/krb5/gssapi_err_krb5.et
@@ -37,4 +37,5 @@ error_code KG_BAD_SEQ, "Sequence number in token is corrupt"
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
diff --git a/src/lib/gssapi/krb5/gssapi_krb5.c b/src/lib/gssapi/krb5/gssapi_krb5.c
index 2892e7885..b68bc9a73 100644
--- a/src/lib/gssapi/krb5/gssapi_krb5.c
+++ b/src/lib/gssapi/krb5/gssapi_krb5.c
@@ -671,7 +671,7 @@ static struct gss_config krb5_mechanism = {
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 @@ static struct gss_config krb5_mechanism = {
krb5_gss_export_name_composite,
krb5_gss_map_name_to_any,
krb5_gss_release_any_name_mapping,
+ krb5_gss_pseudo_random,
};
diff --git a/src/lib/gssapi/krb5/prf.c b/src/lib/gssapi/krb5/prf.c
new file mode 100644
index 000000000..f87c6b0c1
--- /dev/null
+++ b/src/lib/gssapi/krb5/prf.c
@@ -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;
+}
+
diff --git a/src/lib/gssapi/krb5/store_cred.c b/src/lib/gssapi/krb5/store_cred.c
new file mode 100644
index 000000000..a8ed6ffbb
--- /dev/null
+++ b/src/lib/gssapi/krb5/store_cred.c
@@ -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;
+}
+
diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports
index 60754df7a..e7f7b3609 100644
--- a/src/lib/gssapi/libgssapi_krb5.exports
+++ b/src/lib/gssapi/libgssapi_krb5.exports
@@ -68,6 +68,7 @@ gss_nt_service_name_v2
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_seal
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
diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in
index adb5c8adf..0858a4a98 100644
--- a/src/lib/gssapi/mechglue/Makefile.in
+++ b/src/lib/gssapi/mechglue/Makefile.in
@@ -43,6 +43,7 @@ SRCS = \
$(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 @@ OBJS = \
$(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 @@ STLIBOBJS = \
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 \
diff --git a/src/lib/gssapi/mechglue/g_initialize.c b/src/lib/gssapi/mechglue/g_initialize.c
index 3929f761b..e01d17474 100644
--- a/src/lib/gssapi/mechglue/g_initialize.c
+++ b/src/lib/gssapi/mechglue/g_initialize.c
@@ -773,6 +773,8 @@ build_dynamicMech(void *dl, const gss_OID mech_type)
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);
diff --git a/src/lib/gssapi/mechglue/g_prf.c b/src/lib/gssapi/mechglue/g_prf.c
new file mode 100644
index 000000000..74a3a21b6
--- /dev/null
+++ b/src/lib/gssapi/mechglue/g_prf.c
@@ -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;
+}
diff --git a/src/lib/gssapi/mechglue/g_store_cred.c b/src/lib/gssapi/mechglue/g_store_cred.c
index 1d438c4b9..3b286ecd4 100644
--- a/src/lib/gssapi/mechglue/g_store_cred.c
+++ b/src/lib/gssapi/mechglue/g_store_cred.c
@@ -63,7 +63,7 @@ OM_uint32 gss_store_cred(minor_status,
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;
diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h
index f35ac1447..517ca481b 100644
--- a/src/lib/gssapi/mechglue/mglueP.h
+++ b/src/lib/gssapi/mechglue/mglueP.h
@@ -573,6 +573,16 @@ typedef struct gss_config {
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 */
diff --git a/src/lib/gssapi/spnego/gssapiP_spnego.h b/src/lib/gssapi/spnego/gssapiP_spnego.h
index 43b004931..80c23e283 100644
--- a/src/lib/gssapi/spnego/gssapiP_spnego.h
+++ b/src/lib/gssapi/spnego/gssapiP_spnego.h
@@ -519,6 +519,17 @@ spnego_gss_release_any_name_mapping
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
diff --git a/src/lib/gssapi/spnego/spnego_mech.c b/src/lib/gssapi/spnego/spnego_mech.c
index 2aa8ad5dd..e0f53d579 100644
--- a/src/lib/gssapi/spnego/spnego_mech.c
+++ b/src/lib/gssapi/spnego/spnego_mech.c
@@ -268,6 +268,7 @@ static struct gss_config spnego_mechanism =
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 @@ spnego_gss_release_any_name_mapping(OM_uint32 *minor_status,
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
diff --git a/src/tests/gssapi/Makefile.in b/src/tests/gssapi/Makefile.in
index b48e5d97b..98020d449 100644
--- a/src/tests/gssapi/Makefile.in
+++ b/src/tests/gssapi/Makefile.in
@@ -4,19 +4,21 @@ DEFINES = -DUSE_AUTOCONF_H
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_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_namingexts: t_namingexts.o $(GSS_DEPLIBS) $(KRB5_BASE_DEPLIBS)
+ $(CC_LINK) -o t_namingexts t_namingexts.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
diff --git a/src/tests/gssapi/t_gssexts.c b/src/tests/gssapi/t_gssexts.c
new file mode 100644
index 000000000..959378af5
--- /dev/null
+++ b/src/tests/gssapi/t_gssexts.c
@@ -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@WIN.MIT.EDU'
+ * ./t_s4u delegtest@WIN.MIT.EDU HOST/WIN-EQ7E4AA2WR8.win.mit.edu@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;
+}