factor out EAP into Identity and Authenticate states
authorLuke Howard <lukeh@padl.com>
Mon, 20 Sep 2010 21:30:50 +0000 (23:30 +0200)
committerLuke Howard <lukeh@padl.com>
Mon, 20 Sep 2010 21:30:50 +0000 (23:30 +0200)
mech_eap/accept_sec_context.c
mech_eap/gssapiP_eap.h
mech_eap/gssapi_eap.h
mech_eap/import_sec_context.c
mech_eap/init_sec_context.c
mech_eap/mech_eap.exports
mech_eap/set_cred_option.c
mech_eap/util_context.c
mech_eap/util_cred.c

index d54fb2a..af35d56 100644 (file)
@@ -98,6 +98,67 @@ acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx)
 }
 
 static OM_uint32
+eapGssSmAcceptIdentity(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;
+    rc_handle *rh;
+    union {
+        struct eap_hdr eap;
+        unsigned char data[5];
+    } pdu;
+    gss_buffer_desc pduBuffer;
+    char *config = RC_CONFIG_FILE;
+
+    if (inputToken != GSS_C_NO_BUFFER && inputToken->length != 0)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    assert(ctx->acceptorCtx.radHandle == NULL);
+
+    if (cred != GSS_C_NO_CREDENTIAL && cred->radiusConfigFile != NULL)
+        config = cred->radiusConfigFile;
+
+    rh = ctx->acceptorCtx.radHandle = rc_read_config(config);
+    if (rh == NULL) {
+        *minor = errno;
+        return GSS_S_FAILURE;
+    }
+
+    if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
+        *minor = errno;
+        return GSS_S_FAILURE;
+    }
+
+    if (ctx->acceptorName == GSS_C_NO_NAME &&
+        cred != GSS_C_NO_CREDENTIAL &&
+        cred->name != GSS_C_NO_NAME) {
+        major = gss_duplicate_name(minor, cred->name, &ctx->acceptorName);
+        if (GSS_ERROR(major))
+            return major;
+    }
+
+    pdu.eap.code = EAP_CODE_REQUEST;
+    pdu.eap.identifier = 0;
+    pdu.eap.length = htons(sizeof(pdu.data));
+    pdu.data[4] = EAP_TYPE_IDENTITY;
+
+    pduBuffer.length = sizeof(pdu.data);
+    pduBuffer.value = pdu.data;
+
+    major = duplicateBuffer(minor, &pduBuffer, outputToken);
+    if (GSS_ERROR(major))
+        return major;
+
+    ctx->state = EAP_STATE_AUTHENTICATE;
+
+    return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
 eapGssSmAcceptAuthenticate(OM_uint32 *minor,
                            gss_ctx_id_t ctx,
                            gss_cred_id_t cred,
@@ -113,29 +174,6 @@ eapGssSmAcceptAuthenticate(OM_uint32 *minor,
     rc_handle *rh = ctx->acceptorCtx.radHandle;
     char msgBuffer[4096];
 
-    if (rh == NULL) {
-        rh = ctx->acceptorCtx.radHandle = rc_read_config(RC_CONFIG_FILE);
-        if (rh == NULL) {
-            *minor = errno;
-            major = GSS_S_FAILURE;
-            goto cleanup;
-        }
-
-        if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
-            *minor = errno;
-            major = GSS_S_FAILURE;
-            goto cleanup;
-        }
-    }
-
-    if (ctx->acceptorName == GSS_C_NO_NAME &&
-        cred != GSS_C_NO_CREDENTIAL &&
-        cred->name != GSS_C_NO_NAME) {
-        major = gss_duplicate_name(minor, cred->name, &ctx->acceptorName);
-        if (GSS_ERROR(major))
-            goto cleanup;
-    }
-
     if (rc_avpair_add(rh, &send, PW_EAP_MESSAGE,
                       inputToken->value, inputToken->length, 0) == NULL) {
         *minor = ENOMEM;
@@ -203,7 +241,7 @@ eapGssSmAcceptGssChannelBindings(OM_uint32 *minor,
                                  gss_channel_bindings_t chanBindings,
                                  gss_buffer_t outputToken)
 {
-    OM_uint32 major, tmpMinor;
+    OM_uint32 major;
     gss_iov_buffer_desc iov[2];
 
     outputToken->length = 0;
@@ -271,11 +309,8 @@ static struct gss_eap_acceptor_sm {
                               gss_channel_bindings_t,
                               gss_buffer_t);
 } eapGssAcceptorSm[] = {
+    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  eapGssSmAcceptIdentity           },
     { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  eapGssSmAcceptAuthenticate       },
-#if 0
-    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  NULL                             },
-    { TOK_TYPE_EAP_RESP,    TOK_TYPE_EAP_REQ,  NULL                             },
-#endif
     { TOK_TYPE_GSS_CB,      TOK_TYPE_NONE,     eapGssSmAcceptGssChannelBindings },
     { TOK_TYPE_NONE,        TOK_TYPE_NONE,     eapGssSmAcceptEstablished        },
 };
index eef4206..0b2e64e 100644 (file)
@@ -96,6 +96,7 @@ struct gss_cred_id_struct {
     gss_buffer_desc password;
     gss_OID_set mechanisms;
     time_t expiryTime;
+    char *radiusConfigFile;
 };
 
 #define CTX_FLAG_INITIATOR                  0x00000001
@@ -103,11 +104,8 @@ struct gss_cred_id_struct {
 #define CTX_IS_INITIATOR(ctx)               (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
 
 enum gss_eap_state {
-    EAP_STATE_AUTHENTICATE = 0,
-#if 0
-    EAP_STATE_KEY_TRANSPORT,
-    EAP_STATE_SECURE_ASSOCIATION,
-#endif
+    EAP_STATE_IDENTITY = 0,
+    EAP_STATE_AUTHENTICATE,
     EAP_STATE_GSS_CHANNEL_BINDINGS,
     EAP_STATE_ESTABLISHED
 };
index 2c8cee0..5e121f5 100644 (file)
@@ -46,6 +46,9 @@ extern gss_OID GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM;
 /* name type */
 extern gss_OID GSS_EAP_NT_PRINCIPAL_NAME;
 
+/* set credential option for acceptor configuration file */
+extern gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE;
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
index 28962fb..751ed54 100644 (file)
@@ -206,7 +206,7 @@ gssEapImportContext(OM_uint32 *minor,
     remain -= 16;
 
     /* Validate state */
-    if (ctx->state < EAP_STATE_AUTHENTICATE ||
+    if (ctx->state < EAP_STATE_IDENTITY ||
         ctx->state > EAP_STATE_ESTABLISHED)
         return GSS_S_DEFECTIVE_TOKEN;
 
index 9ec5e66..dd90745 100644 (file)
@@ -188,8 +188,7 @@ extern int wpa_debug_level;
 static OM_uint32
 peerConfigInit(OM_uint32 *minor,
                gss_cred_id_t cred,
-               gss_ctx_id_t ctx,
-               int loadConfig)
+               gss_ctx_id_t ctx)
 {
     krb5_context krbContext;
     struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
@@ -198,10 +197,8 @@ peerConfigInit(OM_uint32 *minor,
 
     GSSEAP_KRB_INIT(&krbContext);
 
-    if (loadConfig) {
-        eapPeerConfig->fragment_size = 1024;
-        wpa_debug_level = 0;
-    }
+    eapPeerConfig->fragment_size = 1024;
+    wpa_debug_level = 0;
 
     code = krb5_unparse_name(krbContext, cred->name->krbPrincipal, &identity);
     if (code != 0) {
@@ -277,6 +274,67 @@ initReady(OM_uint32 *minor, gss_ctx_id_t ctx)
     return GSS_S_COMPLETE;
 }
 
+static gss_buffer_desc emptyBuffer = GSS_C_EMPTY_BUFFER;
+
+static OM_uint32
+eapGssSmInitIdentity(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 initialContextToken;
+    time_t now;
+    OM_uint32 major;
+
+    initialContextToken = (inputToken == GSS_C_NO_BUFFER ||
+                           inputToken->length == 0);
+    if (!initialContextToken)
+        return GSS_S_DEFECTIVE_TOKEN;
+
+    time(&now);
+    if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
+        ctx->expiryTime = 0;
+    else
+        ctx->expiryTime = now + timeReq;
+
+    major = gss_duplicate_name(minor, cred->name, &ctx->initiatorName);
+    if (GSS_ERROR(major))
+        return major;
+
+    major = gss_duplicate_name(minor, target, &ctx->acceptorName);
+    if (GSS_ERROR(major))
+        return major;
+
+    if (mech == GSS_C_NULL_OID || oidEqual(mech, GSS_EAP_MECHANISM)) {
+        major = gssEapDefaultMech(minor, &ctx->mechanismUsed);
+    } else if (gssEapIsConcreteMechanismOid(mech)) {
+        if (!gssEapInternalizeOid(mech, &ctx->mechanismUsed))
+            major = duplicateOid(minor, mech, &ctx->mechanismUsed);
+    } else {
+        major = GSS_S_BAD_MECH;
+    }
+    if (GSS_ERROR(major))
+        return major;
+
+    /* If credentials were provided, check they're usable with this mech */
+    if (!gssEapCredAvailable(cred, ctx->mechanismUsed))
+        return GSS_S_BAD_MECH;
+
+    major = duplicateBuffer(minor, &emptyBuffer, outputToken);
+    if (GSS_ERROR(major))
+        return major;
+
+    ctx->state = EAP_STATE_AUTHENTICATE;
+
+    return GSS_S_CONTINUE_NEEDED;
+}
+
 static OM_uint32
 eapGssSmInitAuthenticate(OM_uint32 *minor,
                          gss_cred_id_t cred,
@@ -290,19 +348,15 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
                          gss_buffer_t outputToken)
 {
     OM_uint32 major;
-    OM_uint32 tmpMajor, tmpMinor;
-    time_t now;
-    int initialContextToken = 0, code;
-    gss_buffer_desc respBuf = GSS_C_EMPTY_BUFFER;
-
-    initialContextToken = (inputToken == GSS_C_NO_BUFFER ||
-                           inputToken->length == 0);
+    OM_uint32 tmpMinor;
+    int code;
+    struct wpabuf *resp = NULL;
 
-    major = peerConfigInit(minor, cred, ctx, initialContextToken);
+    major = peerConfigInit(minor, cred, ctx);
     if (GSS_ERROR(major))
         goto cleanup;
 
-    if (initialContextToken) {
+    if (ctx->initiatorCtx.eap == NULL) {
         struct eap_config eapConfig;
 
         memset(&eapConfig, 0, sizeof(eapConfig));
@@ -312,45 +366,14 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
                                                  &gssEapPolicyCallbacks,
                                                  ctx,
                                                  &eapConfig);
-
-        time(&now);
-        if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
-            ctx->expiryTime = 0;
-        else
-            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, &ctx->acceptorName);
-        if (GSS_ERROR(major))
+        if (ctx->initiatorCtx.eap == NULL) {
+            major = GSS_S_FAILURE;
             goto cleanup;
-
-        if (mech == GSS_C_NULL_OID || oidEqual(mech, GSS_EAP_MECHANISM)) {
-            major = gssEapDefaultMech(minor, &ctx->mechanismUsed);
-        } else if (gssEapIsConcreteMechanismOid(mech)) {
-            if (!gssEapInternalizeOid(mech, &ctx->mechanismUsed))
-                major = duplicateOid(minor, mech, &ctx->mechanismUsed);
-        } else {
-            major = GSS_S_BAD_MECH;
         }
-        if (GSS_ERROR(major))
-            goto cleanup;
-
-        /* If credentials were provided, check they're usable with this mech */
-        if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
-            major = GSS_S_BAD_MECH;
-            goto cleanup;
-        }
-
-        respBuf.value = ""; /* emit empty inner token */
-        major = GSS_S_CONTINUE_NEEDED;
-        goto cleanup;
-    } else {
-        ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
     }
 
+    ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
+
     wpabuf_set(&ctx->initiatorCtx.reqData,
                inputToken->value, inputToken->length);
 
@@ -358,14 +381,11 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
 
     code = eap_peer_sm_step(ctx->initiatorCtx.eap);
     if (ctx->flags & CTX_FLAG_EAP_RESP) {
-        struct wpabuf *resp;
 
         ctx->flags &= ~(CTX_FLAG_EAP_RESP);
 
         resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
         if (resp != NULL) {
-            respBuf.length = wpabuf_len(resp);
-            respBuf.value = (void *)wpabuf_head(resp);
         }
     } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
         major = initReady(minor, ctx);
@@ -382,11 +402,15 @@ eapGssSmInitAuthenticate(OM_uint32 *minor,
     }
 
 cleanup:
-    if (respBuf.value != NULL) {
+    if (resp != NULL) {
         OM_uint32 tmpMajor;
+        gss_buffer_desc respBuf;
 
         assert(major == GSS_S_CONTINUE_NEEDED);
 
+        respBuf.length = wpabuf_len(resp);
+        respBuf.value = (void *)wpabuf_head(resp);
+
         tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken);
         if (GSS_ERROR(tmpMajor)) {
             major = tmpMajor;
@@ -400,38 +424,6 @@ cleanup:
     return major;
 }
 
-#if 0
-static OM_uint32
-eapGssSmInitKeyTransport(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)
-{
-    GSSEAP_NOT_IMPLEMENTED;
-}
-
-static OM_uint32
-eapGssSmInitSecureAssoc(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)
-{
-    GSSEAP_NOT_IMPLEMENTED;
-}
-#endif
-
 static OM_uint32
 eapGssSmInitGssChannelBindings(OM_uint32 *minor,
                                gss_cred_id_t cred,
@@ -444,7 +436,7 @@ eapGssSmInitGssChannelBindings(OM_uint32 *minor,
                                gss_buffer_t inputToken,
                                gss_buffer_t outputToken)
 {
-    OM_uint32 major, tmpMinor;
+    OM_uint32 major;
     gss_iov_buffer_desc iov[2];
     gss_buffer_desc buf;
 
@@ -515,11 +507,8 @@ 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        },
-#if 0
-    { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP,  eapGssSmInitKeyTransport        },
-    { TOK_TYPE_EAP_REQ, TOK_TYPE_EAP_RESP,  eapGssSmInitSecureAssoc         },
-#endif
     { TOK_TYPE_NONE,    TOK_TYPE_GSS_CB,    eapGssSmInitGssChannelBindings  },
     { TOK_TYPE_NONE,    TOK_TYPE_NONE,      eapGssSmInitEstablished         },
 };
index ad4dc24..ddd2826 100644 (file)
@@ -47,4 +47,5 @@ GSS_EAP_MECHANISM
 GSS_EAP_AES128_CTS_HMAC_SHA1_96_MECHANISM
 GSS_EAP_AES256_CTS_HMAC_SHA1_96_MECHANISM
 GSS_EAP_NT_PRINCIPAL_NAME
+GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE
 gssspi_acquire_cred_with_password
index d5c5709..0affb32 100644 (file)
 
 #include "gssapiP_eap.h"
 
+static OM_uint32
+setCredRadiusConfigFile(OM_uint32 *minor,
+                        gss_cred_id_t cred,
+                        const gss_OID oid,
+                        const gss_buffer_t buffer)
+{
+    OM_uint32 major;
+    gss_buffer_desc configFileBuffer = GSS_C_EMPTY_BUFFER;
+
+    if (buffer != GSS_C_NO_BUFFER && buffer->length != 0) {
+        major = duplicateBuffer(minor, buffer, &configFileBuffer);
+        if (GSS_ERROR(major))
+            return major;
+    }
+
+    if (cred->radiusConfigFile != NULL)
+        free(cred->radiusConfigFile);
+
+    cred->radiusConfigFile = (char *)configFileBuffer.value;
+
+    *minor = 0;
+    return GSS_S_COMPLETE;
+}
+
 static struct {
     gss_OID_desc oid;
-    OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t *pCred,
+    OM_uint32 (*setOption)(OM_uint32 *, gss_cred_id_t cred,
                            const gss_OID, const gss_buffer_t);
 } setCredOps[] = {
+    /* 1.3.6.1.4.1.5322.21.3.3.1 */
+    {
+        { 11, "\x2B\x06\x01\x04\x01\xA9\x4A\x15\x03\x03\x01" },
+        setCredRadiusConfigFile,
+    },
 };
 
+gss_OID GSS_EAP_CRED_SET_RADIUS_CONFIG_FILE = &setCredOps[0].oid;
+
 OM_uint32
 gssspi_set_cred_option(OM_uint32 *minor,
                        gss_cred_id_t cred,
@@ -50,7 +81,7 @@ gssspi_set_cred_option(OM_uint32 *minor,
 
     for (i = 0; i < sizeof(setCredOps) / sizeof(setCredOps[0]); i++) {
         if (oidEqual(&setCredOps[i].oid, desired_object)) {
-            major = (*setCredOps[i].setOption)(minor, &cred,
+            major = (*setCredOps[i].setOption)(minor, cred,
                                               desired_object, value);
             break;
         }
index 99c9405..5d2a55d 100644 (file)
@@ -53,7 +53,7 @@ gssEapAllocContext(OM_uint32 *minor,
         return GSS_S_FAILURE;
     }
 
-    ctx->state = EAP_STATE_AUTHENTICATE;
+    ctx->state = EAP_STATE_IDENTITY;
 
     /*
      * Integrity, confidentiality, sequencing and replay detection are
index d1f31ee..bec6120 100644 (file)
@@ -75,6 +75,9 @@ gssEapReleaseCred(OM_uint32 *minor, gss_cred_id_t *pCred)
         GSSEAP_FREE(cred->password.value);
     }
 
+    if (cred->radiusConfigFile != NULL)
+        free(cred->radiusConfigFile);
+
     GSSEAP_MUTEX_DESTROY(&cred->mutex);
     memset(cred, 0, sizeof(*cred));
     GSSEAP_FREE(cred);
@@ -98,6 +101,7 @@ gssEapAcquireCred(OM_uint32 *minor,
     OM_uint32 major, tmpMinor;
     gss_cred_id_t cred;
 
+    /* XXX TODO validate with changed set_cred_option API */
     *pCred = GSS_C_NO_CREDENTIAL;
 
     major = gssEapAllocCred(minor, &cred);