From: Greg Hudson Date: Sun, 19 Aug 2012 03:40:29 +0000 (-0400) Subject: Introduce gss_export_cred and gss_import_cred X-Git-Tag: krb5-1.11-alpha1~190 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=abc6b8ce993c4c8393228ab5a01f26e7c5b251b2;p=thirdparty%2Fkrb5.git Introduce gss_export_cred and gss_import_cred Add gss_export_cred and gss_import_cred mechglue functions to serialize and unserialize GSSAPI credential handles. Mechanism implementations and tests will follow. ticket: 7354 (new) --- diff --git a/doc/rst_source/krb_appldev/gssapi.rst b/doc/rst_source/krb_appldev/gssapi.rst index 214e3a091c..29c06b565c 100644 --- a/doc/rst_source/krb_appldev/gssapi.rst +++ b/doc/rst_source/krb_appldev/gssapi.rst @@ -164,6 +164,54 @@ If the *desired_name* is a krb5 principal name or a local system name type which is mapped to a krb5 principal name, clients will only be allowed to authenticate to that principal in the default keytab. + +Importing and exporting credentials +----------------------------------- + +The following GSSAPI extensions can be used to import and export +credentials (declared in ````):: + + OM_uint32 gss_export_cred(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + gss_buffer_t token); + + OM_uint32 gss_import_cred(OM_uint32 *minor_status, + gss_buffer_t token, + gss_cred_id_t *cred_handle); + +The first function serializes a GSSAPI credential handle into a +buffer; the second unseralizes a buffer into a GSSAPI credential +handle. Serializing a credential does not destroy it. If any of the +mechanisms used in *cred_handle* do not support serialization, +gss_export_cred will return **GSS_S_UNAVAILABLE**. As with other +GSSAPI serialization functions, these extensions are only intended to +work with a matching implementation on the other side; they do not +serialize credentials in a standardized format. + +A serialized credential may contain secret information such as ticket +session keys. The serialization format does not protect this +information from eavesdropping or tampering. The calling application +must take care to protect the serialized credential when communicating +it over an insecure channel or to an untrusted party. + +A krb5 GSSAPI credential may contain references to a credential cache, +a client keytab, an acceptor keytab, and a replay cache. These +resources are normally serialized as references to their external +locations (such as the filename of the credential cache). Because of +this, a serialized krb5 credential can only be imported by a process +with similar privileges to the exporter. A serialized credential +should not be trusted if it originates from a source with lower +privileges than the importer, as it may contain references to external +credential cache, keytab, or replay cache resources not accessible to +the originator. + +An exception to the above rule applies when a krb5 GSSAPI credential +refers to a memory credential cache, as is normally the case for +delegated credentials received by gss_accept_sec_context_. In this +case, the contents of the credential cache are serialized, so that the +resulting token may be imported even if the original memory credential +cache no longer exists. + .. _gss_accept_sec_context: http://tools.ietf.org/html/rfc2744.html#section-5.1 .. _gss_acquire_cred: http://tools.ietf.org/html/rfc2744.html#section-5.2 .. _gss_export_name: http://tools.ietf.org/html/rfc2744.html#section-5.13 diff --git a/src/lib/gssapi/generic/gssapi_ext.h b/src/lib/gssapi/generic/gssapi_ext.h index dd12ffecbf..d8c8b6ab85 100644 --- a/src/lib/gssapi/generic/gssapi_ext.h +++ b/src/lib/gssapi/generic/gssapi_ext.h @@ -518,6 +518,18 @@ gss_store_cred_into( gss_OID_set *, /* elements_stored */ gss_cred_usage_t *); /* cred_usage_stored */ +OM_uint32 KRB5_CALLCONV +gss_export_cred( + OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* cred_handle */ + gss_buffer_t); /* token */ + +OM_uint32 KRB5_CALLCONV +gss_import_cred( + OM_uint32 *, /* minor_status */ + gss_buffer_t, /* token */ + gss_cred_id_t *); /* cred_handle */ + #ifdef __cplusplus } #endif diff --git a/src/lib/gssapi/libgssapi_krb5.exports b/src/lib/gssapi/libgssapi_krb5.exports index 3da3a237c4..242a3c0dc8 100644 --- a/src/lib/gssapi/libgssapi_krb5.exports +++ b/src/lib/gssapi/libgssapi_krb5.exports @@ -60,11 +60,13 @@ gss_display_name_ext gss_display_status gss_duplicate_name gss_encapsulate_token +gss_export_cred gss_export_name gss_export_name_composite gss_export_sec_context gss_get_mic gss_get_name_attribute +gss_import_cred gss_import_name gss_import_sec_context gss_indicate_mechs diff --git a/src/lib/gssapi/mechglue/Makefile.in b/src/lib/gssapi/mechglue/Makefile.in index 63302f0ee0..9987d156bf 100644 --- a/src/lib/gssapi/mechglue/Makefile.in +++ b/src/lib/gssapi/mechglue/Makefile.in @@ -29,10 +29,12 @@ SRCS = \ $(srcdir)/g_dup_name.c \ $(srcdir)/g_encapsulate_token.c \ $(srcdir)/g_exp_sec_context.c \ + $(srcdir)/g_export_cred.c \ $(srcdir)/g_export_name.c \ $(srcdir)/g_export_name_comp.c \ $(srcdir)/g_get_name_attr.c \ $(srcdir)/g_glue.c \ + $(srcdir)/g_imp_cred.c \ $(srcdir)/g_imp_name.c \ $(srcdir)/g_imp_sec_context.c \ $(srcdir)/g_init_sec_context.c \ @@ -91,10 +93,12 @@ OBJS = \ $(OUTPRE)g_dup_name.$(OBJEXT) \ $(OUTPRE)g_encapsulate_token.$(OBJEXT) \ $(OUTPRE)g_exp_sec_context.$(OBJEXT) \ + $(OUTPRE)g_export_cred.$(OBJEXT) \ $(OUTPRE)g_export_name.$(OBJEXT) \ $(OUTPRE)g_export_name_comp.$(OBJEXT) \ $(OUTPRE)g_get_name_attr.$(OBJEXT) \ $(OUTPRE)g_glue.$(OBJEXT) \ + $(OUTPRE)g_imp_cred.$(OBJEXT) \ $(OUTPRE)g_imp_name.$(OBJEXT) \ $(OUTPRE)g_imp_sec_context.$(OBJEXT) \ $(OUTPRE)g_init_sec_context.$(OBJEXT) \ @@ -153,10 +157,12 @@ STLIBOBJS = \ g_dup_name.o \ g_encapsulate_token.o \ g_exp_sec_context.o \ + g_export_cred.o \ g_export_name.o \ g_export_name_comp.o \ g_get_name_attr.o \ g_glue.o \ + g_imp_cred.o \ g_imp_name.o \ g_imp_sec_context.o \ g_init_sec_context.o \ diff --git a/src/lib/gssapi/mechglue/g_export_cred.c b/src/lib/gssapi/mechglue/g_export_cred.c new file mode 100644 index 0000000000..4994c9b5b7 --- /dev/null +++ b/src/lib/gssapi/mechglue/g_export_cred.c @@ -0,0 +1,116 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/gssapi/mechglue/g_export_cred.c - gss_export_cred definition */ +/* + * Copyright (C) 2012 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. + */ + +#include "mglueP.h" + +static OM_uint32 +val_exp_cred_args(OM_uint32 *minor_status, gss_cred_id_t cred_handle, + gss_buffer_t token) +{ + + /* Initialize outputs. */ + if (minor_status != NULL) + *minor_status = 0; + if (token != GSS_C_NO_BUFFER) { + token->length = 0; + token->value = NULL; + } + + /* Validate arguments. */ + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + if (cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_NO_CRED; + if (token == GSS_C_NO_BUFFER) + return GSS_S_CALL_INACCESSIBLE_WRITE; + return GSS_S_COMPLETE; +} + +OM_uint32 KRB5_CALLCONV +gss_export_cred(OM_uint32 * minor_status, gss_cred_id_t cred_handle, + gss_buffer_t token) +{ + OM_uint32 status, tmpmin; + gss_union_cred_t cred; + gss_OID mech_oid; + gss_mechanism mech; + gss_buffer_desc mech_token; + struct k5buf buf; + char lenbuf[4]; + int i; + + status = val_exp_cred_args(minor_status, cred_handle, token); + if (status != GSS_S_COMPLETE) + return status; + + krb5int_buf_init_dynamic(&buf); + + cred = (gss_union_cred_t) cred_handle; + for (i = 0; i < cred->count; i++) { + /* Get an export token for this mechanism. */ + mech_oid = &cred->mechs_array[i]; + mech = gssint_get_mechanism(mech_oid); + if (mech == NULL) { + status = GSS_S_DEFECTIVE_CREDENTIAL; + goto error; + } + if (mech->gss_export_cred == NULL) { + status = GSS_S_UNAVAILABLE; + goto error; + } + status = mech->gss_export_cred(minor_status, cred->cred_array[i], + &mech_token); + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); + goto error; + } + + /* Append the mech OID and token to buf. */ + store_32_be(mech_oid->length, lenbuf); + krb5int_buf_add_len(&buf, lenbuf, 4); + krb5int_buf_add_len(&buf, mech_oid->elements, mech_oid->length); + store_32_be(mech_token.length, lenbuf); + krb5int_buf_add_len(&buf, lenbuf, 4); + krb5int_buf_add_len(&buf, mech_token.value, mech_token.length); + gss_release_buffer(&tmpmin, &mech_token); + } + + if (krb5int_buf_data(&buf) == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + return k5buf_to_gss(minor_status, &buf, token); + +error: + krb5int_free_buf(&buf); + return status; +} diff --git a/src/lib/gssapi/mechglue/g_imp_cred.c b/src/lib/gssapi/mechglue/g_imp_cred.c new file mode 100644 index 0000000000..20083cbcac --- /dev/null +++ b/src/lib/gssapi/mechglue/g_imp_cred.c @@ -0,0 +1,164 @@ +/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ +/* lib/gssapi/mechglue/g_imp_cred.c - gss_import_cred definition */ +/* + * Copyright (C) 2012 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. + */ + +#include "mglueP.h" + +static OM_uint32 +val_imp_cred_args(OM_uint32 *minor_status, gss_buffer_t token, + gss_cred_id_t *cred_handle) +{ + /* Initialize outputs. */ + if (minor_status != NULL) + *minor_status = 0; + if (cred_handle != NULL) + *cred_handle = GSS_C_NO_CREDENTIAL; + + /* Validate arguments. */ + if (minor_status == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + if (cred_handle == NULL) + return GSS_S_CALL_INACCESSIBLE_WRITE; + if (token == GSS_C_NO_BUFFER) + return GSS_S_CALL_INACCESSIBLE_READ | GSS_S_DEFECTIVE_TOKEN; + if (GSS_EMPTY_BUFFER(token)) + return GSS_S_DEFECTIVE_TOKEN; + return GSS_S_COMPLETE; +} + +/* Populate mech_oid and mech_token with the next entry in token, using aliased + * memory from token. Advance token by the amount consumed. */ +static OM_uint32 +get_entry(OM_uint32 *minor_status, gss_buffer_t token, gss_OID mech_oid, + gss_buffer_t mech_token) +{ + OM_uint32 len; + + /* Get the mechanism OID. */ + if (token->length < 4) + return GSS_S_DEFECTIVE_TOKEN; + len = load_32_be(token->value); + if (token->length - 4 < len) + return GSS_S_DEFECTIVE_TOKEN; + mech_oid->length = len; + mech_oid->elements = (char *)token->value + 4; + token->value = (char *)token->value + 4 + len; + token->length -= 4 + len; + + /* Get the mechanism token. */ + if (token->length < 4) + return GSS_S_DEFECTIVE_TOKEN; + len = load_32_be(token->value); + if (token->length - 4 < len) + return GSS_S_DEFECTIVE_TOKEN; + mech_token->length = len; + mech_token->value = (char *)token->value + 4; + token->value = (char *)token->value + 4 + len; + token->length -= 4 + len; + + return GSS_S_COMPLETE; +} + +OM_uint32 KRB5_CALLCONV +gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token, + gss_cred_id_t *cred_handle) +{ + OM_uint32 status, tmpmin, count; + gss_union_cred_t cred = NULL; + gss_mechanism mech; + gss_buffer_desc tok, mech_token; + gss_OID_desc mech_oid; + gss_cred_id_t mech_cred; + void *elemcopy; + + status = val_imp_cred_args(minor_status, token, cred_handle); + if (status != GSS_S_COMPLETE) + return status; + + /* Count the entries in token. */ + for (tok = *token, count = 0; tok.length > 0; count++) { + status = get_entry(minor_status, &tok, &mech_oid, &mech_token); + if (status != GSS_S_COMPLETE) + return status; + } + + /* Allocate a union credential. */ + cred = calloc(1, sizeof(*cred)); + if (cred == NULL) + goto oom; + cred->loopback = cred; + cred->count = 0; + cred->mechs_array = calloc(count, sizeof(*cred->mechs_array)); + if (cred->mechs_array == NULL) + goto oom; + cred->cred_array = calloc(count, sizeof(*cred->cred_array)); + if (cred->cred_array == NULL) + goto oom; + + tok = *token; + while (tok.length > 0) { + (void)get_entry(minor_status, &tok, &mech_oid, &mech_token); + + /* Import this entry's mechanism token. */ + mech = gssint_get_mechanism(&mech_oid); + if (mech == NULL || mech->gss_import_cred == NULL) { + status = GSS_S_DEFECTIVE_TOKEN; + goto error; + } + status = mech->gss_import_cred(minor_status, &mech_token, &mech_cred); + if (status != GSS_S_COMPLETE) { + map_error(minor_status, mech); + goto error; + } + + /* Add the resulting mechanism cred to the union cred. */ + elemcopy = malloc(mech_oid.length); + if (elemcopy == NULL) { + if (mech->gss_release_cred != NULL) + mech->gss_release_cred(&tmpmin, &mech_cred); + goto oom; + } + memcpy(elemcopy, mech_oid.elements, mech_oid.length); + cred->mechs_array[cred->count].length = mech_oid.length; + cred->mechs_array[cred->count].elements = elemcopy; + cred->cred_array[cred->count++] = mech_cred; + } + + *cred_handle = cred; + return GSS_S_COMPLETE; + +oom: + status = GSS_S_FAILURE; + *minor_status = ENOMEM; +error: + (void)gss_release_cred(&tmpmin, &cred); + return status; +} diff --git a/src/lib/gssapi/mechglue/mglueP.h b/src/lib/gssapi/mechglue/mglueP.h index 17a9fbbda8..02a7d79530 100644 --- a/src/lib/gssapi/mechglue/mglueP.h +++ b/src/lib/gssapi/mechglue/mglueP.h @@ -634,6 +634,20 @@ typedef struct gss_config { OM_uint32 * /* time_rec */ /* */); + OM_uint32 (KRB5_CALLCONV *gss_export_cred) + ( + OM_uint32 *, /* minor_status */ + gss_cred_id_t, /* cred_handle */ + gss_buffer_t /* token */ + /* */); + + OM_uint32 (KRB5_CALLCONV *gss_import_cred) + ( + OM_uint32 *, /* minor_status */ + gss_buffer_t, /* token */ + gss_cred_id_t * /* cred_handle */ + /* */); + } *gss_mechanism; /* diff --git a/src/lib/gssapi32.def b/src/lib/gssapi32.def index 296506da16..00c707474b 100644 --- a/src/lib/gssapi32.def +++ b/src/lib/gssapi32.def @@ -174,3 +174,5 @@ EXPORTS gss_acquire_cred_from @139 gss_add_cred_from @140 gss_store_cred_into @141 + gss_export_cred @142 + gss_import_cred @143