Added proper GSS encapsulation of token sent
authorkouril <kouril>
Fri, 5 Sep 2003 14:38:15 +0000 (14:38 +0000)
committerkouril <kouril>
Fri, 5 Sep 2003 14:38:15 +0000 (14:38 +0000)
spnegokrb5/accept_sec_context.c
spnegokrb5/decapsulate.c [new file with mode: 0644]
spnegokrb5/encapsulate.c [new file with mode: 0644]
spnegokrb5/external.c [new file with mode: 0644]
spnegokrb5/init_sec_context.c
spnegokrb5/spnegokrb5_locl.h [new file with mode: 0644]

index 3735fae..c603b7b 100644 (file)
@@ -2,20 +2,17 @@
  * SPNEGO wrapper for Kerberos5 GSS-API 
  * kouril@ics.muni.cz, 2003
  */
-#include <stdlib.h>
-#include <errno.h>
 
-#include <gssapi.h>
-#include <spnego_asn1.h>
+#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 (file)
index 0000000..949280c
--- /dev/null
@@ -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 (file)
index 0000000..2fc95f4
--- /dev/null
@@ -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 (file)
index 0000000..ab44688
--- /dev/null
@@ -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;
index a76a491..9f79dee 100644 (file)
@@ -2,24 +2,27 @@
  *  SPNEGO wrapper for Kerberos5 GSS-API
  *  kouril@ics.muni.cz, 2003
  */
-#include <stdlib.h>
-#include <errno.h>
 
-#include <gssapi.h>
-#include <spnego_asn1.h>
+#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 (file)
index 0000000..6dba1ca
--- /dev/null
@@ -0,0 +1,10 @@
+#include <stdlib.h>
+#include <errno.h>
+
+#include <gssapi.h>
+#include <spnego_asn1.h>
+#include <der.h>
+#include <asn1_err.h>
+
+extern gss_OID GSS_KRB5_MECH;
+extern gss_OID GSS_SPNEGO_MECH;