Refactor
authorLuke Howard <lukeh@padl.com>
Thu, 9 Sep 2010 10:59:06 +0000 (12:59 +0200)
committerLuke Howard <lukeh@padl.com>
Thu, 9 Sep 2010 10:59:06 +0000 (12:59 +0200)
Makefile.am
accept_sec_context.c
gssapiP_eap.h
init_sec_context.c
util.h
util_buffer.c [new file with mode: 0644]
util_context.c
util_mech.c
util_token.c

index 4637ad6..7cbe203 100644 (file)
@@ -54,6 +54,7 @@ libmech_eap_la_SOURCES =                      \
        store_cred.c                            \
        unwrap.c                                \
        unwrap_iov.c                            \
+       util_buffer.c                           \
        util_context.c                          \
        util_cksum.c                            \
        util_cred.c                             \
index fe2c8dd..25f35ce 100644 (file)
 
 #include "gssapiP_eap.h"
 
+static OM_uint32
+eapGssSmAcceptAuthenticate(OM_uint32 *minor,
+                           gss_ctx_id_t ctx,
+                           gss_cred_id_t cred,
+                           gss_buffer_t inputToken,
+                           gss_channel_bindings_t chanBindings,
+                           gss_buffer_t outputToken)
+{
+    OM_uint32 major, tmpMinor;
+
+cleanup:
+    return major;
+}
+
+
+static struct eap_gss_acceptor_sm {
+    enum gss_eap_token_type inputTokenType;
+    enum gss_eap_token_type outputTokenType;
+    OM_uint32 (*processToken)(OM_uint32 *,
+                              gss_ctx_id_t,
+                              gss_cred_id_t,
+                              gss_buffer_t,
+                              gss_channel_bindings_t,
+                              gss_buffer_t);
+} eapGssAcceptorSm[] = {
+    { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, NULL },
+};
+
 OM_uint32
 gss_accept_sec_context(OM_uint32 *minor,
                        gss_ctx_id_t *context_handle,
-                       gss_cred_id_t acceptor_cred_handle,
-                       gss_buffer_t input_token_buffer,
+                       gss_cred_id_t cred,
+                       gss_buffer_t input_token,
                        gss_channel_bindings_t input_chan_bindings,
                        gss_name_t *src_name,
                        gss_OID *mech_type,
@@ -45,5 +73,84 @@ gss_accept_sec_context(OM_uint32 *minor,
                        OM_uint32 *time_rec,
                        gss_cred_id_t *delegated_cred_handle)
 {
-    GSSEAP_NOT_IMPLEMENTED;
+    OM_uint32 major, tmpMinor;
+    gss_ctx_id_t ctx = *context_handle;
+    struct eap_gss_acceptor_sm *sm = NULL;
+    gss_buffer_desc innerInputToken, innerOutputToken;
+    
+    *minor = 0;
+
+    innerOutputToken.length = 0;
+    innerOutputToken.value = NULL;
+
+    output_token->length = 0;
+    output_token->value = NULL;
+
+    if (cred != GSS_C_NO_CREDENTIAL && !(cred->flags & CRED_FLAG_ACCEPT)) {
+        return GSS_S_NO_CRED;
+    }
+
+    if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
+        return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    if (ctx == GSS_C_NO_CONTEXT) {
+        major = gssEapAllocContext(minor, &ctx);
+        if (GSS_ERROR(major))
+            return major;
+
+        *context_handle = ctx;
+    }
+
+    GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
+    sm = &eapGssAcceptorSm[ctx->state];
+
+    major = gssEapVerifyToken(minor, ctx, input_token,
+                              sm->inputTokenType, &innerInputToken);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    major = (sm->processToken)(minor,
+                               ctx,
+                               cred,
+                               &innerInputToken,
+                               input_chan_bindings,
+                               &innerOutputToken);
+    if (GSS_ERROR(major))
+        goto cleanup;
+
+    if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
+        major = gss_duplicate_name(&minor, ctx->initiatorName, src_name);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+    if (mech_type != NULL) {
+        if (!gssEapInternalizeOid(ctx->mechanismUsed, mech_type))
+            duplicateOid(&tmpMinor, ctx->mechanismUsed, mech_type);
+    }
+    if (innerOutputToken.length != 0) {
+        major = gssEapMakeToken(minor, ctx, &innerOutputToken,
+                                sm->outputTokenType, output_token);
+        if (GSS_ERROR(major))
+            goto cleanup;
+    }
+    if (ret_flags != NULL)
+        *ret_flags = ctx->gssFlags;
+    if (time_rec != NULL)
+        gss_context_time(&tmpMinor, ctx, time_rec);
+    if (delegated_cred_handle != NULL)
+        *delegated_cred_handle = GSS_C_NO_CREDENTIAL;
+
+    assert(ctx->state == EAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED);
+
+cleanup:
+    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+    if (GSS_ERROR(major))
+        gssEapReleaseContext(&tmpMinor, context_handle);
+
+    gss_release_buffer(&tmpMinor, &innerOutputToken);
+
+    return major;
 }
index 1427272..2483924 100644 (file)
@@ -124,13 +124,6 @@ struct eap_gss_initiator_ctx {
 struct eap_gss_acceptor_ctx {
 };
 
-typedef OM_uint32 (*eap_gss_acceptor_sm)(OM_uint32 *,
-                                         gss_ctx_id_t,
-                                         gss_cred_id_t,
-                                         gss_buffer_t,
-                                         gss_channel_bindings_t,
-                                         gss_buffer_t);
-
 struct gss_ctx_id_struct {
     GSSEAP_MUTEX mutex;
     enum eap_gss_state state;
index 5075ed8..b9ff0be 100644 (file)
@@ -140,46 +140,45 @@ peerSetInt(void *data, enum eapol_int_var variable,
 }
 
 static OM_uint32
-eapGssSmAuthenticate(OM_uint32 *minor,
-                     gss_cred_id_t cred,
-                     gss_ctx_id_t ctx,
-                     gss_name_t target_name,
-                     gss_OID mech_type,
-                     OM_uint32 req_flags,
-                     OM_uint32 time_req,
-                     gss_channel_bindings_t input_chan_bindings,
-                     gss_buffer_t input_token,
-                     gss_buffer_t output_token)
+eapGssSmInitAuthenticate(OM_uint32 *minor,
+                         gss_cred_id_t cred,
+                         gss_ctx_id_t ctx,
+                         gss_name_t target,
+                         gss_OID mech,
+                         OM_uint32 reqFlags,
+                         OM_uint32 timeReq,
+                         gss_channel_bindings_t chanBindings,
+                         gss_buffer_t inputToken,
+                         gss_buffer_t outputToken)
 {
     OM_uint32 major, tmpMinor;
     time_t now;
 
-    if (input_token == GSS_C_NO_BUFFER || input_token->length == 0) {
+    if (inputToken == GSS_C_NO_BUFFER || inputToken->length == 0) {
         /* first time */
-        req_flags &= GSS_C_TRANS_FLAG | GSS_C_REPLAY_FLAG | GSS_C_DCE_STYLE;
-        ctx->gssFlags |= req_flags;
+        reqFlags &= GSS_C_TRANS_FLAG | GSS_C_REPLAY_FLAG | GSS_C_DCE_STYLE;
+        ctx->gssFlags |= reqFlags;
 
         time(&now);
 
-        if (time_req == 0 || time_req == GSS_C_INDEFINITE)
+        if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
             ctx->expiryTime = 0;
         else
-            ctx->expiryTime = now + time_req;
+            ctx->expiryTime = now + timeReq;
 
         major = gss_duplicate_name(minor, cred->name, &ctx->initiatorName);
         if (GSS_ERROR(major))
             goto cleanup;
 
-        major = gss_duplicate_name(minor, target_name, &ctx->acceptorName);
+        major = gss_duplicate_name(minor, target, &ctx->acceptorName);
         if (GSS_ERROR(major))
             goto cleanup;
 
-        if (mech_type == GSS_C_NULL_OID ||
-            oidEqual(mech_type, GSS_EAP_MECHANISM)) {
+        if (mech == GSS_C_NULL_OID || oidEqual(mech, GSS_EAP_MECHANISM)) {
             major = gssEapDefaultMech(minor, &ctx->mechanismUsed);
-        } else if (gssEapIsMechanismOid(mech_type)) {
-            if (!gssEapInternalizeOid(mech_type, &ctx->mechanismUsed))
-                major = duplicateOid(minor, mech_type, &ctx->mechanismUsed);
+        } else if (gssEapIsConcreteMechanismOid(mech)) {
+            if (!gssEapInternalizeOid(mech, &ctx->mechanismUsed))
+                major = duplicateOid(minor, mech, &ctx->mechanismUsed);
         } else {
             major = GSS_S_BAD_MECH;
         }
@@ -205,13 +204,13 @@ static struct eap_gss_initiator_sm {
                               gss_buffer_t,
                               gss_buffer_t);
 } eapGssInitiatorSm[] = {
-    { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP, eapGssSmAuthenticate },
+    { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP, eapGssSmInitAuthenticate },
 };
 
 OM_uint32
 gss_init_sec_context(OM_uint32 *minor,
                      gss_cred_id_t cred,
-                     gss_ctx_id_t *pCtx,
+                     gss_ctx_id_t *context_handle,
                      gss_name_t target_name,
                      gss_OID mech_type,
                      OM_uint32 req_flags,
@@ -224,7 +223,7 @@ gss_init_sec_context(OM_uint32 *minor,
                      OM_uint32 *time_rec)
 {
     OM_uint32 major, tmpMinor;
-    gss_ctx_id_t ctx = *pCtx;
+    gss_ctx_id_t ctx = *context_handle;
     struct eap_gss_initiator_sm *sm = NULL;
     gss_buffer_desc innerInputToken, innerOutputToken;
 
@@ -237,23 +236,25 @@ gss_init_sec_context(OM_uint32 *minor,
     output_token->value = NULL;
 
     if (cred != GSS_C_NO_CREDENTIAL && !(cred->flags & CRED_FLAG_INITIATE)) {
-        major = GSS_S_NO_CRED;
-        goto cleanup;
+        return GSS_S_NO_CRED;
     }
 
     if (ctx == GSS_C_NO_CONTEXT) {
         if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
-            major = GSS_S_DEFECTIVE_TOKEN;
-            goto cleanup;
+            return GSS_S_DEFECTIVE_TOKEN;
         }
 
         major = gssEapAllocContext(minor, &ctx);
         if (GSS_ERROR(major))
-            goto cleanup;
+            return major;
+
+        ctx->flags |= CTX_FLAG_INITIATOR;
 
-        *pCtx = ctx;
+        *context_handle = ctx;
     }
 
+    GSSEAP_MUTEX_LOCK(&ctx->mutex);
+
     sm = &eapGssInitiatorSm[ctx->state];
 
     if (input_token != GSS_C_NO_BUFFER) {
@@ -274,32 +275,33 @@ gss_init_sec_context(OM_uint32 *minor,
                                req_flags,
                                time_req,
                                input_chan_bindings,
-                               input_token,
-                               output_token);
+                               &innerInputToken,
+                               &innerOutputToken);
     if (GSS_ERROR(major))
         goto cleanup;
 
-    if (output_token->length != 0) {
+    if (actual_mech_type != NULL) {
+        if (!gssEapInternalizeOid(ctx->mechanismUsed, actual_mech_type))
+            duplicateOid(&tmpMinor, ctx->mechanismUsed, actual_mech_type);
+    }
+    if (innerOutputToken.length != 0) {
         major = gssEapMakeToken(minor, ctx, &innerOutputToken,
                                 sm->outputTokenType, output_token);
         if (GSS_ERROR(major))
             goto cleanup;
     }
-
-    if (actual_mech_type != NULL) {
-        if (!gssEapInternalizeOid(ctx->mechanismUsed, actual_mech_type))
-            duplicateOid(&tmpMinor, ctx->mechanismUsed, actual_mech_type);
-    }
     if (ret_flags != NULL)
         *ret_flags = ctx->gssFlags;
     if (time_rec != NULL)
         gss_context_time(&tmpMinor, ctx, time_rec);
 
-    assert(ctx->state == EAP_STATE_ESTABLISHED || output_token->length != 0);
+    assert(ctx->state == EAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED);
 
 cleanup:
+    GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
     if (GSS_ERROR(major))
-        gssEapReleaseContext(&tmpMinor, pCtx);
+        gssEapReleaseContext(&tmpMinor, context_handle);
 
     gss_release_buffer(&tmpMinor, &innerOutputToken);
 
diff --git a/util.h b/util.h
index 5be9538..0fceafe 100644 (file)
--- a/util.h
+++ b/util.h
@@ -76,6 +76,23 @@ enum gss_eap_token_type {
     TOK_TYPE_GSS_CHANNEL_BINDINGS    = 0x0603,  /* draft-howlett-eap-gss */
 };
 
+/* util_buffer.c */
+OM_uint32
+makeStringBuffer(OM_uint32 *minor,
+                 const char *string,
+                 gss_buffer_t buffer);
+
+OM_uint32
+bufferToString(OM_uint32 *minor,
+               const gss_buffer_t buffer,
+               char **pString);
+
+OM_uint32
+duplicateBuffer(OM_uint32 *minor,
+                const gss_buffer_t src,
+                gss_buffer_t dst);
+
+/* util_cksum.c */
 int
 gssEapSign(krb5_context context,
            krb5_cksumtype type,
@@ -206,6 +223,9 @@ gssEapOidToEnctype(OM_uint32 *minor,
 int
 gssEapIsMechanismOid(const gss_OID oid);
 
+int
+gssEapIsConcreteMechanismOid(const gss_OID oid);
+
 OM_uint32
 gssEapValidateMechs(OM_uint32 *minor,
                    const gss_OID_set mechs);
@@ -312,7 +332,7 @@ makeTokenHeader(const gss_OID_desc *mech,
                 enum gss_eap_token_type tok_type);
 
 int
-verifyTokenHeader(const gss_OID_desc * mech,
+verifyTokenHeader(gss_OID mech,
                   size_t *body_size,
                   unsigned char **buf_in,
                   size_t toksize_in,
@@ -411,70 +431,4 @@ load_uint64_be(const void *cvp)
     return ((uint64_t)load_uint32_be(p) << 32) | load_uint32_be(p + 4);
 }
 
-static OM_uint32
-makeStringBuffer(OM_uint32 *minor,
-                 const char *string,
-                 gss_buffer_t buffer)
-{
-    size_t len = strlen(string);
-
-    buffer->value = GSSEAP_MALLOC(len + 1);
-    if (buffer->value == NULL) {
-        *minor = ENOMEM;
-        return GSS_S_FAILURE;
-    }
-    memcpy(buffer->value, string, len + 1);
-    buffer->length = len;
-
-    *minor = 0;
-    return GSS_S_COMPLETE;
-}
-
-static OM_uint32
-bufferToString(OM_uint32 *minor,
-               const gss_buffer_t buffer,
-               char **pString)
-{
-    char *s;
-
-    s = GSSEAP_MALLOC(buffer->length + 1);
-    if (s == NULL) {
-        *minor = ENOMEM;
-        return GSS_S_FAILURE;
-    }
-    memcpy(s, buffer->value, buffer->length);
-    s[buffer->length] = '\0';
-
-    *pString = s;
-
-    *minor = 0;
-    return GSS_S_COMPLETE;
-}
-
-static OM_uint32
-duplicateBuffer(OM_uint32 *minor,
-                const gss_buffer_t src,
-                gss_buffer_t dst)
-{
-    dst->length = 0;
-    dst->value = NULL;
-
-    if (src == GSS_C_NO_BUFFER)
-        return GSS_S_COMPLETE;
-
-    dst->value = GSSEAP_MALLOC(src->length + 1);
-    if (dst->value == NULL) {
-        *minor = ENOMEM;
-        return GSS_S_FAILURE;
-    }
-
-    dst->length = src->length;
-    memcpy(dst->value, src->value, dst->length);
-
-    ((unsigned char *)dst->value)[dst->length] = '\0';
-
-    *minor = 0;
-    return GSS_S_COMPLETE;
-}
-
 #endif /* _UTIL_H_ */
diff --git a/util_buffer.c b/util_buffer.c
new file mode 100644 (file)
index 0000000..df1c0ac
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2010, JANET(UK)
+ * 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 JANET(UK) 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 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 "gssapiP_eap.h"
+
+OM_uint32
+makeStringBuffer(OM_uint32 *minor,
+                 const char *string,
+                 gss_buffer_t buffer)
+{
+    size_t len = strlen(string);
+
+    buffer->value = GSSEAP_MALLOC(len + 1);
+    if (buffer->value == NULL) {
+        *minor = ENOMEM;
+        return GSS_S_FAILURE;
+    }
+    memcpy(buffer->value, string, len + 1);
+    buffer->length = len;
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+bufferToString(OM_uint32 *minor,
+               const gss_buffer_t buffer,
+               char **pString)
+{
+    char *s;
+
+    s = GSSEAP_MALLOC(buffer->length + 1);
+    if (s == NULL) {
+        *minor = ENOMEM;
+        return GSS_S_FAILURE;
+    }
+    memcpy(s, buffer->value, buffer->length);
+    s[buffer->length] = '\0';
+
+    *pString = s;
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
+
+OM_uint32
+duplicateBuffer(OM_uint32 *minor,
+                const gss_buffer_t src,
+                gss_buffer_t dst)
+{
+    dst->length = 0;
+    dst->value = NULL;
+
+    if (src == GSS_C_NO_BUFFER)
+        return GSS_S_COMPLETE;
+
+    dst->value = GSSEAP_MALLOC(src->length + 1);
+    if (dst->value == NULL) {
+        *minor = ENOMEM;
+        return GSS_S_FAILURE;
+    }
+
+    dst->length = src->length;
+    memcpy(dst->value, src->value, dst->length);
+
+    ((unsigned char *)dst->value)[dst->length] = '\0';
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
index d777b17..6e2715a 100644 (file)
@@ -88,7 +88,7 @@ OM_uint32
 gssEapReleaseContext(OM_uint32 *minor,
                      gss_ctx_id_t *pCtx)
 {
-    OM_uint32 major, tmpMinor;
+    OM_uint32 tmpMinor;
     gss_ctx_id_t ctx = *pCtx;
     krb5_context krbContext = NULL;
 
@@ -127,7 +127,6 @@ gssEapMakeToken(OM_uint32 *minor,
                 enum gss_eap_token_type tokenType,
                 gss_buffer_t outputToken)
 {
-    OM_uint32 major;
     unsigned char *p;
 
     outputToken->length = tokenSize(ctx->mechanismUsed, innerToken->length);
@@ -155,12 +154,32 @@ gssEapVerifyToken(OM_uint32 *minor,
     OM_uint32 major;
     size_t bodySize;
     unsigned char *p = (unsigned char *)inputToken->value;
+    gss_OID_desc oidBuf;
+    gss_OID oid;
+
+    if (ctx->mechanismUsed != GSS_C_NO_OID) {
+        oid = ctx->mechanismUsed;
+    } else {
+        oidBuf.elements = NULL;
+        oidBuf.length = 0;
+        oid = &oidBuf;
+    }
 
-    major = verifyTokenHeader(ctx->mechanismUsed, &bodySize, &p,
-                              inputToken->length, tokenType);
+    major = verifyTokenHeader(oid, &bodySize, &p, inputToken->length, tokenType);
     if (GSS_ERROR(major))
         return major;
 
+    if (ctx->mechanismUsed != GSS_C_NO_OID) {
+        if (!gssEapIsConcreteMechanismOid(oid))
+            return GSS_S_BAD_MECH;
+
+        if (!gssEapInternalizeOid(oid, &ctx->mechanismUsed)) {
+            major = duplicateOid(minor, oid, &ctx->mechanismUsed);
+            if (GSS_ERROR(major))
+                return major;
+        }
+    }
+
     innerInputToken->length = bodySize;
     innerInputToken->value = p;
 
index 4aece80..2919b34 100644 (file)
@@ -66,19 +66,19 @@ gss_OID GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM    = &gssEapConcreteMechs[1];
 gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM    = &gssEapConcreteMechs[2];
 
 int
-gssEapIsMechanismOid(const gss_OID oid)
+gssEapIsConcreteMechanismOid(const gss_OID oid)
 {
-    if (oid == GSS_C_NO_OID) {
-        return TRUE;
-    } else if (oidEqual(oid, GSS_EAP_MECHANISM)) {
-        return TRUE;
-    } else if (oid->length > gssEapMechPrefix.length &&
-               memcmp(oid->elements, gssEapMechPrefix.elements,
-                      gssEapMechPrefix.length) == 0) {
-        return TRUE;
-    }
+    return oid->length > gssEapMechPrefix.length &&
+           memcmp(oid->elements, gssEapMechPrefix.elements,
+                  gssEapMechPrefix.length) == 0;
+}
 
-    return FALSE;
+int
+gssEapIsMechanismOid(const gss_OID oid)
+{
+    return oid == GSS_C_NO_OID ||
+           oidEqual(oid, GSS_EAP_MECHANISM) ||
+           gssEapIsConcreteMechanismOid(oid);
 }
 
 OM_uint32
index bb7ef7a..e089690 100644 (file)
@@ -197,12 +197,11 @@ makeTokenHeader(
  */
 
 int
-verifyTokenHeader(
-    const gss_OID_desc * mech,
-    size_t *body_size,
-    unsigned char **buf_in,
-    size_t toksize_in,
-    enum gss_eap_token_type tok_type)
+verifyTokenHeader(gss_OID mech,
+                  size_t *body_size,
+                  unsigned char **buf_in,
+                  size_t toksize_in,
+                  enum gss_eap_token_type tok_type)
 {
     unsigned char *buf = *buf_in;
     ssize_t seqsize;
@@ -239,8 +238,13 @@ verifyTokenHeader(
     toid.elements = buf;
     buf += toid.length;
 
-    if (!oidEqual(&toid, mech))
+    if (mech->elements == NULL) {
+        *mech = toid;
+        if (toid.length == 0)
+            return EINVAL;
+    } else if (!oidEqual(&toid, mech)) {
         return EINVAL;
+    }
 
     if (tok_type != TOK_TYPE_NONE) {
         if (toksize -= 2 < 0)