From d1645cde73a6a91ca183e628cd0cffb0e2e36313 Mon Sep 17 00:00:00 2001 From: kouril Date: Fri, 5 Sep 2003 14:38:15 +0000 Subject: [PATCH] Added proper GSS encapsulation of token sent --- spnegokrb5/accept_sec_context.c | 23 +++------ spnegokrb5/decapsulate.c | 105 +++++++++++++++++++++++++++++++++++++++ spnegokrb5/encapsulate.c | 107 ++++++++++++++++++++++++++++++++++++++++ spnegokrb5/external.c | 11 +++++ spnegokrb5/init_sec_context.c | 79 ++++++++++++++++++++--------- spnegokrb5/spnegokrb5_locl.h | 10 ++++ 6 files changed, 296 insertions(+), 39 deletions(-) create mode 100644 spnegokrb5/decapsulate.c create mode 100644 spnegokrb5/encapsulate.c create mode 100644 spnegokrb5/external.c create mode 100644 spnegokrb5/spnegokrb5_locl.h diff --git a/spnegokrb5/accept_sec_context.c b/spnegokrb5/accept_sec_context.c index 3735fae..c603b7b 100644 --- a/spnegokrb5/accept_sec_context.c +++ b/spnegokrb5/accept_sec_context.c @@ -2,20 +2,17 @@ * SPNEGO wrapper for Kerberos5 GSS-API * kouril@ics.muni.cz, 2003 */ -#include -#include -#include -#include +#include "spnegokrb5_locl.h" #define ALLOC(X) (X) = calloc(1, sizeof(*(X))) #define OID_cmp(o1, o2) \ - (((o1).length == (o2).length) && \ - (memcmp((o1).components, (o2).components,(int) (o1).length) == 0)) + (((o1)->length == (o2)->length) && \ + (memcmp((o1)->components, (o2)->components,(int) (o1)->length) == 0)) static int -create_reply(OM_uint32 major_status, oid *mech, gss_buffer_t mech_token, +create_reply(OM_uint32 major_status, gss_OID mech, gss_buffer_t mech_token, gss_buffer_t output_token) { NegTokenTarg targ_token; @@ -37,7 +34,7 @@ create_reply(OM_uint32 major_status, oid *mech, gss_buffer_t mech_token, ret = ENOMEM; goto end; } - copy_MechType(mech, targ_token.supportedMech); + copy_MechType((oid*)mech, targ_token.supportedMech); if (mech_token->length > 0) { ALLOC(targ_token.responseToken); @@ -86,12 +83,6 @@ OM_uint32 gss_accept_sec_context_spnego gss_buffer_desc krb5_input_token = GSS_C_EMPTY_BUFFER; size_t len; int ret; - unsigned krb5_oid_array[] = - {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02}; - oid krb5_oid; - - krb5_oid.length = sizeof(krb5_oid_array); - krb5_oid.components = krb5_oid_array; memset(&init_token, 0, sizeof(init_token)); @@ -104,7 +95,7 @@ OM_uint32 gss_accept_sec_context_spnego } if (init_token.mechTypes == NULL || init_token.mechTypes->len == 0 || - OID_cmp(init_token.mechTypes->val[0], krb5_oid)) { + OID_cmp(&init_token.mechTypes->val[0], (oid *)GSS_KRB5_MECH)) { *minor_status = EINVAL; ret = GSS_S_BAD_MECH; goto end; @@ -131,7 +122,7 @@ OM_uint32 gss_accept_sec_context_spnego goto end; } - ret = create_reply(major_status, &krb5_oid, &krb5_output_token, output_token); + ret = create_reply(major_status, GSS_KRB5_MECH, &krb5_output_token, output_token); if (ret) { *minor_status = ret; ret = GSS_S_FAILURE; diff --git a/spnegokrb5/decapsulate.c b/spnegokrb5/decapsulate.c new file mode 100644 index 0000000..949280c --- /dev/null +++ b/spnegokrb5/decapsulate.c @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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 "gssapi_locl.h" + +RCSID("$Id$"); + +OM_uint32 +gssapi_krb5_verify_header(u_char **str, + size_t total_len, + char *type) +{ + size_t len, len_len, mech_len, foo; + int e; + u_char *p = *str; + + if (total_len < 1) + return GSS_S_DEFECTIVE_TOKEN; + if (*p++ != 0x60) + return GSS_S_DEFECTIVE_TOKEN; + e = der_get_length (p, total_len - 1, &len, &len_len); + if (e || 1 + len_len + len != total_len) + return GSS_S_DEFECTIVE_TOKEN; + p += len_len; + if (*p++ != 0x06) + return GSS_S_DEFECTIVE_TOKEN; + e = der_get_length (p, total_len - 1 - len_len - 1, + &mech_len, &foo); + if (e) + return GSS_S_DEFECTIVE_TOKEN; + p += foo; + if (mech_len != GSS_KRB5_MECHANISM->length) + return GSS_S_BAD_MECH; + if (memcmp(p, + GSS_KRB5_MECHANISM->elements, + GSS_KRB5_MECHANISM->length) != 0) + return GSS_S_BAD_MECH; + p += mech_len; + if (memcmp (p, type, 2) != 0) + return GSS_S_DEFECTIVE_TOKEN; + p += 2; + *str = p; + return GSS_S_COMPLETE; +} + +/* + * Remove the GSS-API wrapping from `in_token' giving `out_data. + * Does not copy data, so just free `in_token'. + */ + +OM_uint32 +gssapi_krb5_decapsulate( + OM_uint32 *minor_status, + gss_buffer_t input_token_buffer, + krb5_data *out_data, + char *type +) +{ + u_char *p; + OM_uint32 ret; + + p = input_token_buffer->value; + ret = gssapi_krb5_verify_header(&p, + input_token_buffer->length, + type); + if (ret) { + *minor_status = 0; + return ret; + } + + out_data->length = input_token_buffer->length - + (p - (u_char *)input_token_buffer->value); + out_data->data = p; + return GSS_S_COMPLETE; +} diff --git a/spnegokrb5/encapsulate.c b/spnegokrb5/encapsulate.c new file mode 100644 index 0000000..2fc95f4 --- /dev/null +++ b/spnegokrb5/encapsulate.c @@ -0,0 +1,107 @@ +/* + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. 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. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE 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 INSTITUTE 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 "spnegokrb5_locl.h" + +void +gssapi_spnego_encap_length (size_t data_len, + size_t *len, + size_t *total_len) +{ + size_t len_len; + +#if 0 + *len = 1 + 1 + GSS_SPNEGO_MECH->length + 2 + data_len; +#else + *len = 1 + 1 + GSS_SPNEGO_MECH->length + data_len; +#endif + + len_len = length_len(*len); + + *total_len = 1 + len_len + *len; +} + +u_char * +gssapi_spnego_make_header (u_char *p, + size_t len, + u_char *type) +{ + int e; + size_t len_len, foo; + + *p++ = 0x60; + len_len = length_len(len); + e = der_put_length (p + len_len - 1, len_len, len, &foo); + if(e || foo != len_len) + abort (); + p += len_len; + *p++ = 0x06; + *p++ = GSS_SPNEGO_MECH->length; + memcpy (p, GSS_SPNEGO_MECH->elements, GSS_SPNEGO_MECH->length); + p += GSS_SPNEGO_MECH->length; +#if 0 + memcpy (p, type, 2); + p += 2; +#endif + return p; +} + +/* + * Give it a krb5_data and it will encapsulate with extra GSS-API wrappings. + */ + +OM_uint32 +gssapi_spnego_encapsulate( + OM_uint32 *minor_status, + unsigned char *buf, + size_t buf_size, + gss_buffer_t output_token, + u_char *type +) +{ + size_t len, outer_len; + u_char *p; + + gssapi_spnego_encap_length (buf_size, &len, &outer_len); + + output_token->length = outer_len; + output_token->value = malloc (outer_len); + if (output_token->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + + p = gssapi_spnego_make_header (output_token->value, len, type); + memcpy (p, buf, buf_size); + return GSS_S_COMPLETE; +} diff --git a/spnegokrb5/external.c b/spnegokrb5/external.c new file mode 100644 index 0000000..ab44688 --- /dev/null +++ b/spnegokrb5/external.c @@ -0,0 +1,11 @@ +#include "spnegokrb5_locl.h" + +static gss_OID_desc gss_krb5_mech_oid_desc = + {9, (void *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"}; + +gss_OID GSS_KRB5_MECH = &gss_krb5_mech_oid_desc; + +static gss_OID_desc gss_spnego_mech_oid_desc = + {6, (void *)"\x2b\x06\x01\x05\x05\x02"}; + +gss_OID GSS_SPNEGO_MECH = &gss_spnego_mech_oid_desc; diff --git a/spnegokrb5/init_sec_context.c b/spnegokrb5/init_sec_context.c index a76a491..9f79dee 100644 --- a/spnegokrb5/init_sec_context.c +++ b/spnegokrb5/init_sec_context.c @@ -2,24 +2,27 @@ * SPNEGO wrapper for Kerberos5 GSS-API * kouril@ics.muni.cz, 2003 */ -#include -#include -#include -#include +#include "spnegokrb5_locl.h" #define ALLOC(X) (X) = calloc(1, sizeof(*(X))) static int -add_mech(MechTypeList *mech_list, oid *mech) +add_mech(MechTypeList *mech_list, gss_OID mech) { MechType *tmp; + int ret; tmp = realloc(mech_list->val, (mech_list->len + 1) * sizeof(*tmp)); if (tmp == NULL) return ENOMEM; mech_list->val = tmp; - copy_MechType(mech, mech_list->val + mech_list->len); + + ret = der_get_oid(mech->elements, mech->length, + &mech_list->val[mech_list->len], NULL); + if (ret) + return ret; + mech_list->len++; return 0; } @@ -66,28 +69,23 @@ OM_uint32 gss_init_sec_context_spnego( size_t buf_size; size_t len; int ret; - unsigned krb5_oid_array[] = - {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02}; - oid krb5_oid; memset(&token_init, 0, sizeof(token_init)); - krb5_oid.length = sizeof(krb5_oid_array); - krb5_oid.components = krb5_oid_array; - ALLOC(token_init.mechTypes); if (token_init.mechTypes == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } - ret = add_mech(token_init.mechTypes, &krb5_oid); + ret = add_mech(token_init.mechTypes, GSS_KRB5_MECH); if (ret) { *minor_status = ret; ret = GSS_S_FAILURE; goto end; } +#if 0 ALLOC(token_init.reqFlags); if (token_init.reqFlags == NULL) { *minor_status = ENOMEM; @@ -95,12 +93,13 @@ OM_uint32 gss_init_sec_context_spnego( goto end; } set_context_flags(req_flags, token_init.reqFlags); +#endif major_status = gss_init_sec_context(minor_status, initiator_cred_handle, context_handle, target_name, - (gss_OID) &krb5_oid, + GSS_KRB5_MECH, req_flags, time_req, input_chan_bindings, @@ -129,16 +128,50 @@ OM_uint32 gss_init_sec_context_spnego( /* The MS implementation of SPNEGO seems to not like the mechListMIC field, * so we omit it (it's optional anyway) */ - ASN1_MALLOC_ENCODE(NegTokenInit, buf, buf_size, &token_init, &len, ret); - if (ret || buf_size != len) { - *minor_status = EINVAL; /* XXX */ - ret = GSS_S_FAILURE; - goto end; - } + buf_size = 1024; + buf = malloc(buf_size); + + do { + ret = encode_NegTokenInit(buf + buf_size -1, + buf_size, + &token_init, &len); + if (ret == 0) { + size_t tmp; + + ret = der_put_length_and_tag(buf + buf_size - len - 1, + buf_size - len, + len, + CONTEXT, + CONS, + 0, + &tmp); + if (ret == 0) + len += tmp; + } + if (ret) { + if (ret == ASN1_OVERFLOW) { + u_char *tmp; + + buf_size *= 2; + tmp = realloc (buf, buf_size); + if (tmp == NULL) { + *minor_status = ENOMEM; + ret = GSS_S_FAILURE; + goto end; + } + buf = tmp; + } else { + *minor_status = ret; + ret = GSS_S_FAILURE; + goto end; + } + } + } while (ret == ASN1_OVERFLOW); + + ret = gssapi_spnego_encapsulate(minor_status, + buf + buf_size - len, len, + output_token, "\x01\x00"); - output_token->value = buf; - output_token->length = buf_size; - buf = NULL; ret = major_status; end: diff --git a/spnegokrb5/spnegokrb5_locl.h b/spnegokrb5/spnegokrb5_locl.h new file mode 100644 index 0000000..6dba1ca --- /dev/null +++ b/spnegokrb5/spnegokrb5_locl.h @@ -0,0 +1,10 @@ +#include +#include + +#include +#include +#include +#include + +extern gss_OID GSS_KRB5_MECH; +extern gss_OID GSS_SPNEGO_MECH; -- 2.1.4