accept_sec_context: only destroy request if it is populated
[mech_eap.orig] / init_sec_context.c
index f7eda20..b2cdffe 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, JANET(UK)
+ * Copyright (c) 2011, JANET(UK)
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * SUCH DAMAGE.
  */
 
+/*
+ * Establish a security context on the initiator (client). These functions
+ * wrap around libeap.
+ */
+
 #include "gssapiP_eap.h"
 
 #ifdef GSSEAP_ENABLE_REAUTH
@@ -197,7 +202,9 @@ static struct eapol_callbacks gssEapPolicyCallbacks = {
     peerNotifyPending,
 };
 
+#ifdef GSSEAP_DEBUG
 extern int wpa_debug_level;
+#endif
 
 static OM_uint32
 peerConfigInit(OM_uint32 *minor,
@@ -219,7 +226,16 @@ peerConfigInit(OM_uint32 *minor,
     GSSEAP_KRB_INIT(&krbContext);
 
     eapPeerConfig->fragment_size = 1024;
+#ifdef GSSEAP_DEBUG
     wpa_debug_level = 0;
+#endif
+
+    assert(cred->name != GSS_C_NO_NAME);
+
+    if ((cred->name->flags & (NAME_FLAG_NAI | NAME_FLAG_SERVICE)) == 0) {
+        *minor = GSSEAP_BAD_INITIATOR_NAME;
+        return GSS_S_BAD_NAME;
+    }
 
     code = krb5_unparse_name(krbContext, cred->name->krbPrincipal, &identity);
     if (code != 0) {
@@ -232,6 +248,7 @@ peerConfigInit(OM_uint32 *minor,
     eapPeerConfig->password = (unsigned char *)cred->password.value;
     eapPeerConfig->password_len = cred->password.length;
 
+    *minor = 0;
     return GSS_S_COMPLETE;
 }
 
@@ -246,9 +263,13 @@ peerConfigFree(OM_uint32 *minor,
 
     krb5_free_unparsed_name(krbContext, (char *)eapPeerConfig->identity);
 
+    *minor = 0;
     return GSS_S_COMPLETE;
 }
 
+/*
+ * Mark an initiator context as ready for cryptographic operations
+ */
 static OM_uint32
 initReady(OM_uint32 *minor, gss_ctx_id_t ctx, OM_uint32 reqFlags)
 {
@@ -353,16 +374,19 @@ initBegin(OM_uint32 *minor,
         if (!gssEapInternalizeOid(mech, &ctx->mechanismUsed))
             major = duplicateOid(minor, mech, &ctx->mechanismUsed);
     } else {
-        *minor = GSSEAP_WRONG_MECH;
         major = GSS_S_BAD_MECH;
+        *minor = GSSEAP_WRONG_MECH;
     }
     if (GSS_ERROR(major))
         return major;
 
     /* If credentials were provided, check they're usable with this mech */
-    if (!gssEapCredAvailable(cred, ctx->mechanismUsed))
+    if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
+        *minor = GSSEAP_CRED_MECH_MISMATCH;
         return GSS_S_BAD_MECH;
+    }
 
+    *minor = 0;
     return GSS_S_COMPLETE;
 }
 
@@ -393,8 +417,9 @@ eapGssSmInitIdentity(OM_uint32 *minor,
     if (GSS_ERROR(major))
         return major;
 
-    ctx->state = EAP_STATE_AUTHENTICATE;
+    ctx->state = GSSEAP_STATE_AUTHENTICATE;
 
+    *minor = 0;
     return GSS_S_CONTINUE_NEEDED;
 }
 
@@ -418,6 +443,8 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
     struct wpabuf *resp = NULL;
     int initialContextToken;
 
+    *minor = 0;
+
     initialContextToken = (inputToken == GSS_C_NO_BUFFER ||
                            inputToken->length == 0);
 
@@ -435,8 +462,8 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
                                                  ctx,
                                                  &eapConfig);
         if (ctx->initiatorCtx.eap == NULL) {
-            *minor = GSSEAP_PEER_INIT_FAILURE;
             major = GSS_S_FAILURE;
+            *minor = GSSEAP_PEER_SM_INIT_FAILURE;
             goto cleanup;
         }
 
@@ -462,16 +489,16 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
 
         ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
         major = GSS_S_CONTINUE_NEEDED;
-        ctx->state = EAP_STATE_EXTENSIONS_REQ;
+        ctx->state = GSSEAP_STATE_EXTENSIONS_REQ;
     } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
-        *minor = GSSEAP_PEER_AUTH_FAILURE;
         major = GSS_S_DEFECTIVE_CREDENTIAL;
+        *minor = GSSEAP_PEER_AUTH_FAILURE;
     } else if (code == 0 && initialContextToken) {
         resp = &emptyWpaBuffer;
         major = GSS_S_CONTINUE_NEEDED;
     } else {
-        *minor = GSSEAP_PEER_BAD_MESSAGE;
         major = GSS_S_DEFECTIVE_TOKEN;
+        *minor = GSSEAP_PEER_BAD_MESSAGE;
     }
 
 cleanup:
@@ -517,8 +544,9 @@ eapGssSmInitExtensionsReq(OM_uint32 *minor,
 
     assert(outputToken->value != NULL);
 
-    ctx->state = EAP_STATE_EXTENSIONS_RESP;
+    ctx->state = GSSEAP_STATE_EXTENSIONS_RESP;
 
+    *minor = 0;
     return GSS_S_CONTINUE_NEEDED;
 }
 
@@ -540,8 +568,9 @@ eapGssSmInitExtensionsResp(OM_uint32 *minor,
     if (GSS_ERROR(major))
         return major;
 
-    ctx->state = EAP_STATE_ESTABLISHED;
+    ctx->state = GSSEAP_STATE_ESTABLISHED;
 
+    *minor = 0;
     return GSS_S_COMPLETE;
 }
 
@@ -562,6 +591,39 @@ eapGssSmInitEstablished(OM_uint32 *minor,
     return GSS_S_BAD_STATUS;
 }
 
+static OM_uint32
+eapGssSmInitError(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;
+    unsigned char *p;
+
+    if (inputToken->length < 8) {
+        *minor = GSSEAP_TOK_TRUNC;
+        return GSS_S_DEFECTIVE_TOKEN;
+    }
+
+    p = (unsigned char *)inputToken->value;
+
+    major = load_uint32_be(&p[0]);
+    *minor = ERROR_TABLE_BASE_eapg + load_uint32_be(&p[4]);
+
+    if (!GSS_ERROR(major) || !IS_WIRE_ERROR(*minor)) {
+        major = GSS_S_FAILURE;
+        *minor = GSSEAP_BAD_ERROR_TOKEN;
+    }
+
+    return major;
+}
+
 static struct gss_eap_initiator_sm {
     enum gss_eap_token_type inputTokenType;
     enum gss_eap_token_type outputTokenType;
@@ -576,13 +638,14 @@ static struct gss_eap_initiator_sm {
                               gss_buffer_t,
                               gss_buffer_t);
 } eapGssInitiatorSm[] = {
-    { TOK_TYPE_NONE,    TOK_TYPE_EAP_RESP,      eapGssSmInitIdentity            },
-    { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP,      eapGssSmInitAuthenticate        },
-    { TOK_TYPE_NONE,    TOK_TYPE_EXT_REQ,       eapGssSmInitExtensionsReq       },
-    { TOK_TYPE_EXT_RESP,TOK_TYPE_NONE,          eapGssSmInitExtensionsResp      },
-    { TOK_TYPE_NONE,    TOK_TYPE_NONE,          eapGssSmInitEstablished         },
+    { TOK_TYPE_NONE,        TOK_TYPE_EAP_RESP,      eapGssSmInitIdentity            },
+    { TOK_TYPE_EAP_REQ,     TOK_TYPE_EAP_RESP,      eapGssSmInitAuthenticate        },
+    { TOK_TYPE_NONE,        TOK_TYPE_EXT_REQ,       eapGssSmInitExtensionsReq       },
+    { TOK_TYPE_EXT_RESP,    TOK_TYPE_NONE,          eapGssSmInitExtensionsResp      },
+    { TOK_TYPE_NONE,        TOK_TYPE_NONE,          eapGssSmInitEstablished         },
+    { TOK_TYPE_CONTEXT_ERR, TOK_TYPE_NONE,          eapGssSmInitError               },
 #ifdef GSSEAP_ENABLE_REAUTH
-    { TOK_TYPE_GSS_REAUTH, TOK_TYPE_GSS_REAUTH, eapGssSmInitGssReauth           },
+    { TOK_TYPE_GSS_REAUTH,  TOK_TYPE_GSS_REAUTH,    eapGssSmInitGssReauth           },
 #endif
 };
 
@@ -608,7 +671,6 @@ gss_init_sec_context(OM_uint32 *minor,
     gss_buffer_desc innerInputToken;
     gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
     enum gss_eap_token_type tokType;
-    gss_cred_id_t defaultCred = GSS_C_NO_CREDENTIAL;
     int initialContextToken = 0;
 
     *minor = 0;
@@ -635,47 +697,49 @@ gss_init_sec_context(OM_uint32 *minor,
     GSSEAP_MUTEX_LOCK(&ctx->mutex);
 
     if (cred == GSS_C_NO_CREDENTIAL) {
-        if (ctx->initiatorCtx.defaultCred == GSS_C_NO_CREDENTIAL) {
+        if (ctx->defaultCred == GSS_C_NO_CREDENTIAL) {
             major = gssEapAcquireCred(minor,
                                       GSS_C_NO_NAME,
                                       GSS_C_NO_BUFFER,
                                       time_req,
                                       GSS_C_NO_OID_SET,
                                       GSS_C_INITIATE,
-                                      &defaultCred,
+                                      &ctx->defaultCred,
                                       NULL,
                                       NULL);
             if (GSS_ERROR(major))
                 goto cleanup;
         }
 
-        cred = ctx->initiatorCtx.defaultCred;
+        cred = ctx->defaultCred;
     }
 
     GSSEAP_MUTEX_LOCK(&cred->mutex);
 
 #ifdef GSSEAP_ENABLE_REAUTH
     if (initialContextToken && gssEapCanReauthP(cred, target_name, time_req))
-        ctx->state = EAP_STATE_KRB_REAUTH_GSS;
+        ctx->state = GSSEAP_STATE_KRB_REAUTH;
 #endif
 
     if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
-        *minor = GSSEAP_CRED_USAGE_MISMATCH;
         major = GSS_S_NO_CRED;
+        *minor = GSSEAP_CRED_USAGE_MISMATCH;
         goto cleanup;
     }
 
     sm = &eapGssInitiatorSm[ctx->state];
 
-    if (input_token != GSS_C_NO_BUFFER) {
+    if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
         major = gssEapVerifyToken(minor, ctx, input_token,
                                   &tokType, &innerInputToken);
         if (GSS_ERROR(major))
             goto cleanup;
 
-        if (tokType != sm->inputTokenType) {
-            *minor = GSSEAP_WRONG_TOK_ID;
+        if (tokType == TOK_TYPE_CONTEXT_ERR) {
+            ctx->state = GSSEAP_STATE_ERROR;
+        } else if (tokType != sm->inputTokenType) {
             major = GSS_S_DEFECTIVE_TOKEN;
+            *minor = GSSEAP_WRONG_TOK_ID;
             goto cleanup;
         }
     } else {
@@ -722,7 +786,7 @@ gss_init_sec_context(OM_uint32 *minor,
     if (time_rec != NULL)
         gssEapContextTime(&tmpMinor, ctx, time_rec);
 
-    assert(ctx->state == EAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED);
+    assert(ctx->state == GSSEAP_STATE_ESTABLISHED || major == GSS_S_CONTINUE_NEEDED);
 
 cleanup:
     if (cred != GSS_C_NO_CREDENTIAL)
@@ -757,7 +821,7 @@ eapGssSmInitGssReauth(OM_uint32 *minor,
 
     assert(cred != GSS_C_NO_CREDENTIAL);
 
-    ctx->flags |= CTX_FLAG_KRB_REAUTH_GSS;
+    ctx->flags |= CTX_FLAG_KRB_REAUTH;
 
     if (inputToken->length == 0) {
         major = initBegin(minor, cred, ctx, target, mech,
@@ -793,7 +857,7 @@ eapGssSmInitGssReauth(OM_uint32 *minor,
         major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
         if (GSS_ERROR(major))
             goto cleanup;
-        ctx->state = EAP_STATE_ESTABLISHED;
+        ctx->state = GSSEAP_STATE_ESTABLISHED;
     }
 
 cleanup: