get GSS-EAP working again with TLV
authorLuke Howard <lukeh@padl.com>
Tue, 8 Mar 2011 06:24:09 +0000 (17:24 +1100)
committerLuke Howard <lukeh@padl.com>
Tue, 8 Mar 2011 13:38:47 +0000 (00:38 +1100)
accept_sec_context.c
gssapiP_eap.h
gsseap_err.et
init_sec_context.c
util.h
util_sm.c
util_token.c

index d9e232e..8b6acf0 100644 (file)
@@ -49,7 +49,7 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor,
                         gss_channel_bindings_t chanBindings,
                         gss_buffer_t inputToken,
                         gss_buffer_t outputToken,
-                        int *transitionState);
+                        OM_uint32 *smFlags);
 #endif
 
 /*
@@ -139,7 +139,7 @@ eapGssSmAcceptIdentity(OM_uint32 *minor,
                        gss_channel_bindings_t chanBindings __attribute__((__unused__)),
                        gss_buffer_t inputToken,
                        gss_buffer_t outputToken,
-                       int *transitionState)
+                       OM_uint32 *smFlags)
 {
     OM_uint32 major;
     struct wpabuf *reqData;
@@ -180,7 +180,7 @@ eapGssSmAcceptIdentity(OM_uint32 *minor,
     wpabuf_free(reqData);
 
     *minor = 0;
-    *transitionState = 1;
+    *smFlags |= SM_FLAG_TRANSITION;
 
     return GSS_S_CONTINUE_NEEDED;
 }
@@ -430,7 +430,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
                            gss_channel_bindings_t chanBindings,
                            gss_buffer_t inputToken,
                            gss_buffer_t outputToken,
-                           int *transitionState)
+                           OM_uint32 *smFlags)
 {
     OM_uint32 major, tmpMinor;
     struct rs_connection *rconn;
@@ -538,7 +538,7 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
         if (GSS_ERROR(major))
             goto cleanup;
 
-        *transitionState = 1;
+        *smFlags |= SM_FLAG_TRANSITION;
     }
 
     major = GSS_S_CONTINUE_NEEDED;
@@ -564,7 +564,7 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
                                  gss_channel_bindings_t chanBindings,
                                  gss_buffer_t inputToken,
                                  gss_buffer_t outputToken,
-                                 int *transitionState)
+                                 OM_uint32 *smFlags)
 {
     OM_uint32 major, tmpMinor;
     gss_iov_buffer_desc iov[2];
@@ -585,6 +585,9 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
         !bufferEqual(&iov[0].buffer, &chanBindings->application_data)) {
         major = GSS_S_BAD_BINDINGS;
         *minor = GSSEAP_BINDINGS_MISMATCH;
+    } else {
+        major = GSS_S_CONTINUE_NEEDED;
+        *minor = 0;
     }
 
     gss_release_buffer(&tmpMinor, &iov[0].buffer);
@@ -592,6 +595,24 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
     return major;
 }
 
+static OM_uint32
+eapGssSmAcceptCompleteInitiatorExts(OM_uint32 *minor,
+                                    gss_cred_id_t cred,
+                                    gss_ctx_id_t ctx,
+                                    gss_name_t target __attribute__((__unused__)),
+                                    gss_OID mech __attribute__((__unused__)),
+                                    OM_uint32 reqFlags __attribute__((__unused__)),
+                                    OM_uint32 timeReq __attribute__((__unused__)),
+                                    gss_channel_bindings_t chanBindings __attribute__((__unused__)),
+                                    gss_buffer_t inputToken,
+                                    gss_buffer_t outputToken,
+                                    OM_uint32 *smFlags)
+{
+    *minor = 0;
+    *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL;
+    return GSS_S_CONTINUE_NEEDED;
+}
+
 #ifdef GSSEAP_ENABLE_REAUTH
 static OM_uint32
 eapGssSmAcceptReauthCreds(OM_uint32 *minor,
@@ -604,7 +625,7 @@ eapGssSmAcceptReauthCreds(OM_uint32 *minor,
                           gss_channel_bindings_t chanBindings __attribute__((__unused__)),
                           gss_buffer_t inputToken,
                           gss_buffer_t outputToken,
-                          int *transitionState)
+                          OM_uint32 *smFlags)
 {
     OM_uint32 major;
 
@@ -621,20 +642,20 @@ eapGssSmAcceptReauthCreds(OM_uint32 *minor,
 #endif
 
 static OM_uint32
-eapGssSmAcceptNegoExtFinished(OM_uint32 *minor,
-                              gss_cred_id_t cred,
-                              gss_ctx_id_t ctx,
-                              gss_name_t target __attribute__((__unused__)),
-                              gss_OID mech __attribute__((__unused__)),
-                              OM_uint32 reqFlags __attribute__((__unused__)),
-                              OM_uint32 timeReq __attribute__((__unused__)),
-                              gss_channel_bindings_t chanBindings __attribute__((__unused__)),
-                              gss_buffer_t inputToken,
-                              gss_buffer_t outputToken,
-                              int *transitionState)
+eapGssSmAcceptCompleteAcceptorExts(OM_uint32 *minor,
+                                   gss_cred_id_t cred,
+                                   gss_ctx_id_t ctx,
+                                   gss_name_t target __attribute__((__unused__)),
+                                   gss_OID mech __attribute__((__unused__)),
+                                   OM_uint32 reqFlags __attribute__((__unused__)),
+                                   OM_uint32 timeReq __attribute__((__unused__)),
+                                   gss_channel_bindings_t chanBindings __attribute__((__unused__)),
+                                   gss_buffer_t inputToken,
+                                   gss_buffer_t outputToken,
+                                   OM_uint32 *smFlags)
 {
     *minor = 0;
-    *transitionState = 1;
+    *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL;
     return GSS_S_COMPLETE;
 }
 
@@ -668,16 +689,24 @@ static struct gss_eap_sm eapGssAcceptorSm[] = {
     {
         ITOK_TYPE_GSS_CHANNEL_BINDINGS,
         ITOK_TYPE_NONE,
-        GSSEAP_STATE_NEGO_EXT,
+        GSSEAP_STATE_INITIATOR_EXTS,
         1, /* critical */
         1, /* required */
         eapGssSmAcceptGssChannelBindings,
     },
+    {
+        ITOK_TYPE_NONE,
+        ITOK_TYPE_NONE,
+        GSSEAP_STATE_INITIATOR_EXTS,
+        1, /* critical */
+        1, /* required */
+        eapGssSmAcceptCompleteInitiatorExts,
+    },
 #ifdef GSSEAP_ENABLE_REAUTH
     {
         ITOK_TYPE_NONE,
         ITOK_TYPE_REAUTH_CREDS,
-        GSSEAP_STATE_NEGO_EXT,
+        GSSEAP_STATE_ACCEPTOR_EXTS,
         0, /* critical */
         0, /* required */
         eapGssSmAcceptReauthCreds,
@@ -686,10 +715,10 @@ static struct gss_eap_sm eapGssAcceptorSm[] = {
     {
         ITOK_TYPE_NONE,
         ITOK_TYPE_NONE,
-        GSSEAP_STATE_NEGO_EXT,
+        GSSEAP_STATE_ACCEPTOR_EXTS,
         1, /* critical */
         1, /* required */
-        eapGssSmAcceptNegoExtFinished
+        eapGssSmAcceptCompleteAcceptorExts
     },
 };
 
@@ -827,10 +856,8 @@ acceptReadyKrb(OM_uint32 *minor,
     if (GSS_ERROR(major))
         return major;
 
-    ctx->state = GSSEAP_STATE_NEGO_EXT; /* skip */
-
     *minor = 0;
-    return GSS_S_COMPLETE; /* advance state */
+    return GSS_S_COMPLETE;
 }
 
 static OM_uint32
@@ -844,7 +871,7 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor,
                         gss_channel_bindings_t chanBindings,
                         gss_buffer_t inputToken,
                         gss_buffer_t outputToken,
-                        int *transitionState)
+                        OM_uint32 *smFlags)
 {
     OM_uint32 major, tmpMinor;
     gss_name_t krbInitiator = GSS_C_NO_NAME;
@@ -873,7 +900,10 @@ eapGssSmAcceptGssReauth(OM_uint32 *minor,
     if (major == GSS_S_COMPLETE) {
         major = acceptReadyKrb(minor, ctx, cred,
                                krbInitiator, mech, timeRec);
-        *transitionState = 1;
+        if (major == GSS_S_COMPLETE) {
+            ctx->state = GSSEAP_STATE_ACCEPTOR_EXTS;
+            *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL;
+        }
     }
 
     ctx->gssFlags = gssFlags;
index 884ed86..290da74 100644 (file)
@@ -143,9 +143,10 @@ struct gss_cred_id_struct
 enum gss_eap_state {
     GSSEAP_STATE_INITIAL        = 0x01,     /* initial state */
     GSSEAP_STATE_AUTHENTICATE   = 0x02,     /* exchange EAP messages */
-    GSSEAP_STATE_NEGO_EXT       = 0x04,     /* negotiate extensions */
-    GSSEAP_STATE_ESTABLISHED    = 0x08,     /* context established */
-    GSSEAP_STATE_ALL            = 0x0F
+    GSSEAP_STATE_INITIATOR_EXTS = 0x04,     /* initiator extensions */
+    GSSEAP_STATE_ACCEPTOR_EXTS  = 0x08,     /* acceptor extensions */
+    GSSEAP_STATE_ESTABLISHED    = 0x10,     /* context established */
+    GSSEAP_STATE_ALL            = 0x1F
 };
 
 #define GSSEAP_STATE_NEXT(s)    ((s) << 1)
@@ -167,9 +168,13 @@ struct gss_eap_sm {
                               gss_channel_bindings_t,
                               gss_buffer_t,
                               gss_buffer_t,
-                              int *);
+                              OM_uint32 *);
 };
 
+#define SM_FLAG_TRANSITION                  0x00000001
+#define SM_FLAG_FORCE_SEND_TOKEN            0x00000002
+#define SM_FLAG_STOP_EVAL                   0x00000004
+
 #define CTX_IS_ESTABLISHED(ctx)             ((ctx)->state == GSSEAP_STATE_ESTABLISHED)
 
 /* Initiator context flags */
index 0a34d12..369d2b8 100644 (file)
@@ -95,6 +95,7 @@ error_code GSSEAP_BAD_PRF_KEY,                  "PRF key usage type is unknown"
 #
 error_code GSSEAP_LIBEAP_INIT_FAILURE,          "Failed to initialize EAP library"
 error_code GSSEAP_PEER_SM_INIT_FAILURE,         "Failed to create EAP state machine"
+error_code GSSEAP_PEER_SM_STEP_FAILURE,         "Failed to step EAP state machine"
 error_code GSSEAP_PEER_AUTH_FAILURE,            "EAP peer authentication failure"
 error_code GSSEAP_PEER_BAD_MESSAGE,             "Received bad EAP message"
 
index 56bbd6c..5d3ebb7 100644 (file)
@@ -392,7 +392,7 @@ eapGssSmInitError(OM_uint32 *minor,
                   gss_channel_bindings_t chanBindings,
                   gss_buffer_t inputToken,
                   gss_buffer_t outputToken,
-                  int *transitionState)
+                  OM_uint32 *smFlags)
 {
     OM_uint32 major;
     unsigned char *p;
@@ -429,7 +429,7 @@ eapGssSmInitGssReauth(OM_uint32 *minor,
                       gss_channel_bindings_t chanBindings,
                       gss_buffer_t inputToken,
                       gss_buffer_t outputToken,
-                      int *transitionState)
+                      OM_uint32 *smFlags)
 {
     OM_uint32 major, tmpMinor;
     gss_name_t mechTarget = GSS_C_NO_NAME;
@@ -481,10 +481,10 @@ eapGssSmInitGssReauth(OM_uint32 *minor,
         major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
         if (GSS_ERROR(major))
             goto cleanup;
-        ctx->state = GSSEAP_STATE_NEGO_EXT; /* skip */
+        ctx->state = GSSEAP_STATE_ACCEPTOR_EXTS;
     }
 
-    *transitionState = 1;
+    *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL;
 
 cleanup:
     gssReleaseName(&tmpMinor, &mechTarget);
@@ -493,6 +493,30 @@ cleanup:
 }
 #endif /* GSSEAP_ENABLE_REAUTH */
 
+#ifdef GSSEAP_DEBUG
+static OM_uint32
+eapGssSmInitVendorInfo(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 *smFlags)
+{
+    OM_uint32 major;
+
+    major = makeStringBuffer(minor, "JANET(UK)", outputToken);
+    if (GSS_ERROR(major))
+        return major;
+
+    return GSS_S_CONTINUE_NEEDED;
+}
+#endif
+
 static OM_uint32
 eapGssSmInitIdentity(OM_uint32 *minor,
                      gss_cred_id_t cred,
@@ -504,18 +528,13 @@ eapGssSmInitIdentity(OM_uint32 *minor,
                      gss_channel_bindings_t chanBindings,
                      gss_buffer_t inputToken,
                      gss_buffer_t outputToken,
-                     int *transitionState)
+                     OM_uint32 *smFlags)
 {
     OM_uint32 major;
-    int initialContextToken;
+    struct eap_config eapConfig;
 
     assert((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
-
-    initialContextToken = (inputToken->length == 0);
-    if (!initialContextToken) {
-        *minor = GSSEAP_WRONG_SIZE;
-        return GSS_S_DEFECTIVE_TOKEN;
-    }
+    assert(inputToken == GSS_C_NO_BUFFER);
 
     major = initBegin(minor, cred, ctx, target, mech,
                       reqFlags, timeReq, chanBindings,
@@ -523,17 +542,32 @@ eapGssSmInitIdentity(OM_uint32 *minor,
     if (GSS_ERROR(major))
         return major;
 
-    outputToken->length = 0;
-    outputToken->value = NULL;
+    memset(&eapConfig, 0, sizeof(eapConfig));
+
+    ctx->initiatorCtx.eap = eap_peer_sm_init(ctx,
+                                             &gssEapPolicyCallbacks,
+                                             ctx,
+                                             &eapConfig);
+    if (ctx->initiatorCtx.eap == NULL) {
+        *minor = GSSEAP_PEER_SM_INIT_FAILURE;
+        return GSS_S_FAILURE;
+    }
+
+    ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED;
+
+    /* poke EAP state machine */
+    if (eap_peer_sm_step(ctx->initiatorCtx.eap) != 0) {
+        *minor = GSSEAP_PEER_SM_STEP_FAILURE;
+        return GSS_S_FAILURE;
+    }
 
+    /* force sending of empty token */
     *minor = 0;
-    *transitionState = 1;
+    *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_FORCE_SEND_TOKEN;
 
-    return GSS_S_COMPLETE;
+    return GSS_S_CONTINUE_NEEDED;
 }
 
-static struct wpabuf emptyWpaBuffer;
-
 static OM_uint32
 eapGssSmInitAuthenticate(OM_uint32 *minor,
                          gss_cred_id_t cred,
@@ -545,48 +579,31 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
                          gss_channel_bindings_t chanBindings,
                          gss_buffer_t inputToken,
                          gss_buffer_t outputToken,
-                         int *transitionState)
+                         OM_uint32 *smFlags)
 {
     OM_uint32 major;
     OM_uint32 tmpMinor;
     int code;
     struct wpabuf *resp = NULL;
-    int initialContextToken;
 
     *minor = 0;
 
-    initialContextToken = (inputToken == GSS_C_NO_BUFFER ||
-                           inputToken->length == 0);
+    assert(inputToken != GSS_C_NO_BUFFER);
 
     major = peerConfigInit(minor, cred, ctx);
     if (GSS_ERROR(major))
         goto cleanup;
 
-    if (ctx->initiatorCtx.eap == NULL) {
-        struct eap_config eapConfig;
-
-        memset(&eapConfig, 0, sizeof(eapConfig));
-
-        ctx->initiatorCtx.eap = eap_peer_sm_init(ctx,
-                                                 &gssEapPolicyCallbacks,
-                                                 ctx,
-                                                 &eapConfig);
-        if (ctx->initiatorCtx.eap == NULL) {
-            major = GSS_S_FAILURE;
-            *minor = GSSEAP_PEER_SM_INIT_FAILURE;
-            goto cleanup;
-        }
-
-        ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED;
-    }
+    assert(ctx->initiatorCtx.eap != NULL);
+    assert(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED);
 
     ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
 
-    major = GSS_S_CONTINUE_NEEDED;
-
     wpabuf_set(&ctx->initiatorCtx.reqData,
                inputToken->value, inputToken->length);
 
+    major = GSS_S_CONTINUE_NEEDED;
+
     code = eap_peer_sm_step(ctx->initiatorCtx.eap);
     if (ctx->flags & CTX_FLAG_EAP_RESP) {
         ctx->flags &= ~(CTX_FLAG_EAP_RESP);
@@ -598,12 +615,11 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
             goto cleanup;
 
         ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
-        *transitionState = 1;
+        major = GSS_S_CONTINUE_NEEDED;
+        *smFlags |= SM_FLAG_TRANSITION;
     } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
         major = GSS_S_DEFECTIVE_CREDENTIAL;
         *minor = GSSEAP_PEER_AUTH_FAILURE;
-    } else if (code == 0 && initialContextToken) {
-        /* */
     } else {
         major = GSS_S_DEFECTIVE_TOKEN;
         *minor = GSSEAP_PEER_BAD_MESSAGE;
@@ -614,7 +630,7 @@ cleanup:
         OM_uint32 tmpMajor;
         gss_buffer_desc respBuf;
 
-        assert(!GSS_ERROR(major));
+        assert(major == GSS_S_CONTINUE_NEEDED);
 
         respBuf.length = wpabuf_len(resp);
         respBuf.value = (void *)wpabuf_head(resp);
@@ -643,7 +659,7 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor,
                                gss_channel_bindings_t chanBindings,
                                gss_buffer_t inputToken,
                                gss_buffer_t outputToken,
-                               int *transitionState)
+                               OM_uint32 *smFlags)
 {
     OM_uint32 major;
     gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
@@ -674,7 +690,7 @@ eapGssSmInitReauthCreds(OM_uint32 *minor,
                         gss_channel_bindings_t chanBindings,
                         gss_buffer_t inputToken,
                         gss_buffer_t outputToken,
-                        int *transitionState)
+                        OM_uint32 *smFlags)
 {
     OM_uint32 major;
 
@@ -688,28 +704,45 @@ eapGssSmInitReauthCreds(OM_uint32 *minor,
 #endif /* GSSEAP_ENABLE_REAUTH */
 
 static OM_uint32
-eapGssSmInitNegoExtFinished(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,
-                            int *transitionState)
+eapGssSmInitCompleteAcceptorExts(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 *smFlags)
 {
     *minor = 0;
-    *transitionState = 1;
+    *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL;
     return GSS_S_COMPLETE;
 }
 
+static OM_uint32
+eapGssSmInitCompleteInitiatorExts(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 *smFlags)
+{
+    *minor = 0;
+    *smFlags |= SM_FLAG_TRANSITION | SM_FLAG_STOP_EVAL;
+    return GSS_S_CONTINUE_NEEDED;
+}
 static struct gss_eap_sm eapGssInitiatorSm[] = {
     {
         ITOK_TYPE_CONTEXT_ERR,
         ITOK_TYPE_NONE,
-        GSSEAP_STATE_ALL,
+        GSSEAP_STATE_ALL & ~(GSSEAP_STATE_INITIAL),
         1, /* critical */
         0, /* required */
         eapGssSmInitError,
@@ -724,6 +757,16 @@ static struct gss_eap_sm eapGssInitiatorSm[] = {
         eapGssSmInitGssReauth,
     },
 #endif
+#if 0
+    {
+        ITOK_TYPE_NONE,
+        ITOK_TYPE_VENDOR_INFO,
+        GSSEAP_STATE_INITIAL,
+        0, /* critical */
+        0, /* required */
+        eapGssSmInitVendorInfo,
+    },
+#endif
     {
         ITOK_TYPE_NONE,
         ITOK_TYPE_NONE,
@@ -743,16 +786,24 @@ static struct gss_eap_sm eapGssInitiatorSm[] = {
     {
         ITOK_TYPE_NONE,
         ITOK_TYPE_GSS_CHANNEL_BINDINGS,
-        GSSEAP_STATE_NEGO_EXT,
+        GSSEAP_STATE_INITIATOR_EXTS,
         1, /* critical */
         1, /* required */
         eapGssSmInitGssChannelBindings,
     },
+    {
+        ITOK_TYPE_NONE,
+        ITOK_TYPE_NONE,
+        GSSEAP_STATE_INITIATOR_EXTS,
+        1, /* critical */
+        1, /* required */
+        eapGssSmInitCompleteInitiatorExts
+    },
 #ifdef GSSEAP_ENABLE_REAUTH
     {
         ITOK_TYPE_REAUTH_CREDS,
         ITOK_TYPE_NONE,
-        GSSEAP_STATE_NEGO_EXT,
+        GSSEAP_STATE_ACCEPTOR_EXTS,
         0, /* critical */
         0, /* required */
         eapGssSmInitReauthCreds,
@@ -762,10 +813,10 @@ static struct gss_eap_sm eapGssInitiatorSm[] = {
     {
         ITOK_TYPE_NONE,
         ITOK_TYPE_NONE,
-        GSSEAP_STATE_NEGO_EXT,
+        GSSEAP_STATE_ACCEPTOR_EXTS,
         1, /* critical */
         1, /* required */
-        eapGssSmInitNegoExtFinished
+        eapGssSmInitCompleteAcceptorExts
     }
 };
 
@@ -786,7 +837,6 @@ gss_init_sec_context(OM_uint32 *minor,
 {
     OM_uint32 major, tmpMinor;
     gss_ctx_id_t ctx = *context_handle;
-    int initialContextToken = 0;
 
     *minor = 0;
 
@@ -805,7 +855,6 @@ gss_init_sec_context(OM_uint32 *minor,
 
         ctx->flags |= CTX_FLAG_INITIATOR;
 
-        initialContextToken = 1;
         *context_handle = ctx;
     }
 
diff --git a/util.h b/util.h
index 7f433e9..b081cce 100644 (file)
--- a/util.h
+++ b/util.h
@@ -168,11 +168,13 @@ enum gss_eap_token_type {
 #define ITOK_TYPE_REAUTH_CREDS          0x00000007
 #define ITOK_TYPE_REAUTH_REQ            0x00000008
 #define ITOK_TYPE_REAUTH_RESP           0x00000009
+#define ITOK_TYPE_VERSION_INFO          0x0000000A
+#define ITOK_TYPE_VENDOR_INFO           0x0000000B
 
 #define ITOK_FLAG_CRITICAL              0x80000000  /* critical, wire flag */
 #define ITOK_FLAG_VERIFIED              0x40000000  /* verified, API flag */
 
-#define ITOK_TYPE_MASK                  (~(EXT_FLAG_CRITICAL | EXT_FLAG_VERIFIED))
+#define ITOK_TYPE_MASK                  (~(ITOK_FLAG_CRITICAL | ITOK_FLAG_VERIFIED))
 
 OM_uint32 gssEapAllocContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
 OM_uint32 gssEapReleaseContext(OM_uint32 *minor, gss_ctx_id_t *pCtx);
index 71783e2..17af663 100644 (file)
--- a/util_sm.c
+++ b/util_sm.c
 
 #include "gssapiP_eap.h"
 
+static const char *
+gssEapStateToString(enum gss_eap_state state)
+{
+    const char *s;
+
+    switch (state) {
+    case GSSEAP_STATE_INITIAL:
+        s = "INITIAL";
+        break;
+    case GSSEAP_STATE_AUTHENTICATE:
+        s = "AUTHENTICATE";
+        break;
+    case GSSEAP_STATE_INITIATOR_EXTS:
+        s = "INITIATOR_EXTS";
+        break;
+    case GSSEAP_STATE_ACCEPTOR_EXTS:
+        s = "ACCEPTOR_EXTS";
+        break;
+    case GSSEAP_STATE_ESTABLISHED:
+        s = "ESTABLISHED";
+        break;
+    default:
+        s = "INVALID";
+        break;
+    }
+
+    return s;
+}
+
 static OM_uint32
 makeErrorToken(OM_uint32 *minor,
                OM_uint32 majorStatus,
@@ -90,8 +119,9 @@ gssEapSmStep(OM_uint32 *minor,
     gss_buffer_set_t innerInputTokens = GSS_C_NO_BUFFER_SET;
     gss_buffer_set_t innerOutputTokens = GSS_C_NO_BUFFER_SET;
     OM_uint32 *inputTokenTypes = NULL, *outputTokenTypes = NULL;
+    unsigned int smFlags = 0;
     size_t i, j;
-    enum gss_eap_state inputState = ctx->state;
+    int initialContextToken = 0;
 
     assert(smCount > 0);
 
@@ -117,6 +147,8 @@ gssEapSmStep(OM_uint32 *minor,
         major = GSS_S_DEFECTIVE_TOKEN;
         *minor = GSSEAP_WRONG_SIZE;
         goto cleanup;
+    } else {
+        initialContextToken = 1;
     }
 
     if (ctx->state == GSSEAP_STATE_ESTABLISHED) {
@@ -132,6 +164,8 @@ gssEapSmStep(OM_uint32 *minor,
     if (GSS_ERROR(major))
         goto cleanup;
 
+    assert(innerInputTokens != GSS_C_NO_BUFFER_SET);
+
     major = gss_create_empty_buffer_set(minor, &innerOutputTokens);
     if (GSS_ERROR(major))
         goto cleanup;
@@ -161,8 +195,6 @@ gssEapSmStep(OM_uint32 *minor,
      * is reached.
      */
     do {
-        int transitionState = 0;
-
         major = GSS_S_COMPLETE;
 
         for (i = 0; i < smCount; i++) {
@@ -175,17 +207,17 @@ gssEapSmStep(OM_uint32 *minor,
             if ((smp->validStates & ctx->state) == 0)
                 continue;
 
-            if (innerInputTokens == GSS_C_NO_BUFFER_SET) {
-                processToken = ((smp->validStates & GSSEAP_STATE_INITIAL) != 0);
-            } else if (inputState != ctx->state) {
-                processToken = (smp->inputTokenType == ITOK_TYPE_NONE);
-            } else {
+            if (smp->inputTokenType == ITOK_TYPE_NONE || initialContextToken) {
+                processToken = 1;
+            } else if ((smFlags & SM_FLAG_TRANSITION) == 0) {
                 for (j = 0; j < innerInputTokens->count; j++) {
-                    processToken = (smp->inputTokenType == inputTokenTypes[j]);
-                    if (innerInputToken != GSS_C_NO_BUFFER && processToken) {
-                        major = GSS_S_DEFECTIVE_TOKEN;
-                        *minor = GSSEAP_DUPLICATE_ITOK;
-                        break;
+                    if ((inputTokenTypes[j] & ITOK_TYPE_MASK) == smp->inputTokenType) {
+                        processToken = 1;
+                        if (innerInputToken != GSS_C_NO_BUFFER) {
+                            major = GSS_S_DEFECTIVE_TOKEN;
+                            *minor = GSSEAP_DUPLICATE_ITOK;
+                            break;
+                        }
                     }
                     innerInputToken = &innerInputTokens->elements[j];
                     inputTokenType = &inputTokenTypes[j];
@@ -200,9 +232,11 @@ gssEapSmStep(OM_uint32 *minor,
 #endif
 
             if (processToken) {
+                smFlags = 0;
+
                 major = smp->processToken(minor, cred, ctx, target, mech, reqFlags,
                                          timeReq, chanBindings, innerInputToken,
-                                         &innerOutputToken, &transitionState);
+                                         &innerOutputToken, &smFlags);
                 if (GSS_ERROR(major))
                     break;
 
@@ -217,7 +251,7 @@ gssEapSmStep(OM_uint32 *minor,
                         outputTokenTypes[innerOutputTokens->count] |= ITOK_FLAG_CRITICAL;
                     innerOutputTokens->count++;
                 }
-                if (transitionState)
+                if (smFlags & SM_FLAG_STOP_EVAL)
                     break;
             } else if (smp->required && smp->inputTokenType != ITOK_TYPE_NONE) {
                 major = GSS_S_DEFECTIVE_TOKEN;
@@ -226,15 +260,21 @@ gssEapSmStep(OM_uint32 *minor,
             }
         }
 
-        if (GSS_ERROR(major) || !transitionState)
+        if (GSS_ERROR(major) || (smFlags & SM_FLAG_TRANSITION) == 0)
             break;
 
         assert(ctx->state < GSSEAP_STATE_ESTABLISHED);
 
+#ifdef GSSEAP_DEBUG
+        fprintf(stderr, "GSS-EAP: state transition %s->%s\n",
+                gssEapStateToString(ctx->state),
+                gssEapStateToString(GSSEAP_STATE_NEXT(ctx->state)));
+#endif
+
         ctx->state = GSSEAP_STATE_NEXT(ctx->state);
 
-        if (innerOutputTokens->count != 0) {
-            assert(major == GSS_S_CONTINUE_NEEDED);
+        if (innerOutputTokens->count != 0 || (smFlags & SM_FLAG_FORCE_SEND_TOKEN)) {
+            assert(major == GSS_S_CONTINUE_NEEDED || ctx->state == GSSEAP_STATE_ESTABLISHED);
             break; /* send any tokens if we have them */
         }
     } while (ctx->state != GSSEAP_STATE_ESTABLISHED);
@@ -242,7 +282,7 @@ gssEapSmStep(OM_uint32 *minor,
     assert(innerOutputTokens->count <= smCount);
 
     /* Check we understood all critical tokens */
-    if (!GSS_ERROR(major) && innerInputTokens != GSS_C_NO_BUFFER_SET) {
+    if (!GSS_ERROR(major)) {
         for (j = 0; j < innerInputTokens->count; j++) {
             if ((inputTokenTypes[j] & ITOK_FLAG_CRITICAL) &&
                 (inputTokenTypes[j] & ITOK_FLAG_VERIFIED) == 0) {
@@ -273,7 +313,7 @@ gssEapSmStep(OM_uint32 *minor,
 
 #ifdef GSSEAP_DEBUG
     for (i = 0; i < innerOutputTokens->count; i++) {
-        fprintf(stderr, "GSS-EAP: type %d length %zd value %p\n",
+        fprintf(stderr, "GSS-EAP: type %08x length %zd value %p\n",
                 outputTokenTypes[i],
                 innerOutputTokens->elements[i].length,
                 innerOutputTokens->elements[i].value);
@@ -298,7 +338,7 @@ gssEapSmStep(OM_uint32 *minor,
     }
 
     assert(GSS_ERROR(major) ||
-           (major == GSS_S_CONTINUE_NEEDED && ctx->state < GSSEAP_STATE_ESTABLISHED) ||
+           (major == GSS_S_CONTINUE_NEEDED && (ctx->state > GSSEAP_STATE_INITIAL && ctx->state < GSSEAP_STATE_ESTABLISHED)) ||
            (major == GSS_S_COMPLETE && ctx->state == GSSEAP_STATE_ESTABLISHED));
 
 cleanup:
index dab1251..a929198 100644 (file)
@@ -307,6 +307,8 @@ der_read_length(unsigned char **buf, ssize_t *bufsize)
 size_t
 tokenSize(const gss_OID_desc *mech, size_t body_size)
 {
+    assert(mech != GSS_C_NO_OID);
+
     /* set body_size to sequence contents size */
     body_size += 4 + (size_t) mech->length;         /* NEED overflow check */
     return 1 + der_length_size(body_size) + body_size;