#include "gssapiP_eap.h"
+#ifdef BUILTIN_EAP
+#define EAP_KEY_AVAILABLE(ctx) ((ctx)->acceptorCtx.eapPolInterface->eapKeyAvailable)
+#define EAP_KEY_DATA(ctx) ((ctx)->acceptorCtx.eapPolInterface->eapKeyData)
+#define EAP_KEY_LENGTH(ctx) ((ctx)->acceptorCtx.eapPolInterface->eapKeyDataLen)
+#else
+#define EAP_KEY_AVAILABLE(ctx) 0
+#define EAP_KEY_DATA(ctx) NULL
+#define EAP_KEY_LENGTH(ctx) 0
+#endif /* BUILTIN_EAP */
+
+static OM_uint32
+acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx);
+
+#ifdef BUILTIN_EAP
#define EAP_MAX_METHODS 8
#define EAP_TTLS_AUTH_PAP 1
#define EAP_TTLS_AUTH_MSCHAP 4
#define EAP_TTLS_AUTH_MSCHAPV2 8
-#if 1
struct eap_user {
struct {
int vendor;
const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
+#include <eap_server/eap_i.h>
+
static OM_uint32
initTls(OM_uint32 *minor,
gss_ctx_id_t ctx)
*len = 0;
return NULL;
}
-#endif
-
-static OM_uint32
-completeAccept(OM_uint32 *minor, gss_ctx_id_t ctx)
-{
- OM_uint32 major;
- krb5_context krbContext;
-
- GSSEAP_KRB_INIT(&krbContext);
-
- /* Cache encryption type derived from selected mechanism OID */
- major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
- if (GSS_ERROR(major))
- return major;
-
- if (ctx->encryptionType != ENCTYPE_NULL &&
- ctx->acceptorCtx.eapPolInterface->eapKeyAvailable) {
- major = gssEapDeriveRFC3961Key(minor,
- ctx->acceptorCtx.eapPolInterface->eapKeyData,
- ctx->acceptorCtx.eapPolInterface->eapKeyDataLen,
- ctx->encryptionType,
- &ctx->rfc3961Key);
- if (GSS_ERROR(major))
- return major;
- } else {
- /*
- * draft-howlett-eap-gss says that integrity/confidentialty should
- * always be advertised as available, but if we have no keying
- * material it seems confusing to the caller to advertise this.
- */
- ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
- }
-
- sequenceInit(&ctx->seqState, ctx->recvSeq,
- ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
- ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
- TRUE);
-
- return GSS_S_COMPLETE;
-}
static OM_uint32
eapGssSmAcceptAuthenticate(OM_uint32 *minor,
int code;
struct wpabuf respData;
static struct eapol_callbacks cb = { serverGetEapUser, serverGetEapReqIdText };
-
if (ctx->acceptorCtx.eap == NULL) {
struct eap_config eapConfig;
if (ctx->acceptorCtx.eapPolInterface->eapSuccess) {
ctx->acceptorCtx.eapPolInterface->eapSuccess = 0;
- ctx->state = EAP_STATE_ESTABLISHED;
- major = completeAccept(minor, ctx);
+ major = acceptReady(minor, ctx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ctx->state = EAP_STATE_GSS_CHANNEL_BINDINGS;
+ major = GSS_S_CONTINUE_NEEDED;
} else if (ctx->acceptorCtx.eapPolInterface->eapFail) {
ctx->acceptorCtx.eapPolInterface->eapFail = 0;
major = GSS_S_FAILURE;
return major;
}
+#else
+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;
+}
+#endif /* BUILTIN_EAP */
+
+static OM_uint32
+eapGssSmAcceptGssChannelBindings(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;
+ gss_iov_buffer_desc iov[2];
+
+ outputToken->length = 0;
+ outputToken->value = NULL;
+
+ if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS) {
+ ctx->state = EAP_STATE_ESTABLISHED;
+ return GSS_S_COMPLETE;
+ }
+
+ if (inputToken->length < 14) {
+ return GSS_S_DEFECTIVE_TOKEN;
+ }
+
+ iov[0].type = GSS_IOV_BUFFER_TYPE_DATA;
+ iov[0].buffer.length = 0;
+ iov[0].buffer.value = NULL;
+
+ if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
+ iov[0].buffer = chanBindings->application_data;
+
+ iov[1].type = GSS_IOV_BUFFER_TYPE_HEADER;
+ iov[1].buffer.length = 16;
+ iov[1].buffer.value = (unsigned char *)inputToken->value - 2;
+
+ assert(load_uint16_be(iov[1].buffer.value) == TOK_TYPE_GSS_CB);
+
+ iov[2].type = GSS_IOV_BUFFER_TYPE_TRAILER;
+ iov[2].buffer.length = inputToken->length - 14;
+ iov[2].buffer.value = (unsigned char *)inputToken->value + 14;
+
+ major = gssEapUnwrapOrVerifyMIC(minor, ctx, NULL, NULL,
+ iov, 3, TOK_TYPE_GSS_CB);
+ if (major == GSS_S_COMPLETE) {
+ ctx->state = EAP_STATE_ESTABLISHED;
+ }
+
+#if 0
+ gss_release_buffer(&tmpMinor, &iov[0].buffer);
+#endif
+
+ return major;
+}
static OM_uint32
eapGssSmAcceptEstablished(OM_uint32 *minor,
return GSS_S_BAD_STATUS;
}
-static struct eap_gss_acceptor_sm {
+static struct gss_eap_acceptor_sm {
enum gss_eap_token_type inputTokenType;
enum gss_eap_token_type outputTokenType;
OM_uint32 (*processToken)(OM_uint32 *,
gss_channel_bindings_t,
gss_buffer_t);
} eapGssAcceptorSm[] = {
- { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, eapGssSmAcceptAuthenticate },
- { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, NULL },
- { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, NULL },
- { TOK_TYPE_GSS_CB, TOK_TYPE_NONE, NULL },
- { TOK_TYPE_NONE, TOK_TYPE_NONE, eapGssSmAcceptEstablished },
+ { 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 },
};
OM_uint32
OM_uint32 major;
OM_uint32 tmpMajor, tmpMinor;
gss_ctx_id_t ctx = *context_handle;
- struct eap_gss_acceptor_sm *sm = NULL;
- gss_buffer_desc innerInputToken, innerOutputToken;
+ struct gss_eap_acceptor_sm *sm = NULL;
+ gss_buffer_desc innerInputToken = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc innerOutputToken = GSS_C_EMPTY_BUFFER;
*minor = 0;
- innerOutputToken.length = 0;
- innerOutputToken.value = NULL;
-
output_token->length = 0;
output_token->value = NULL;
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;
+ }
+
do {
+ sm = &eapGssAcceptorSm[ctx->state];
+
major = (sm->processToken)(minor,
ctx,
cred,
return major;
}
+
+/*
+ * Mark a context as ready for cryptographic operations
+ */
+static OM_uint32
+acceptReady(OM_uint32 *minor, gss_ctx_id_t ctx)
+{
+ OM_uint32 major;
+
+ /* Cache encryption type derived from selected mechanism OID */
+ major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (ctx->encryptionType != ENCTYPE_NULL &&
+ EAP_KEY_AVAILABLE(ctx)) {
+ major = gssEapDeriveRfc3961Key(minor,
+ EAP_KEY_DATA(ctx),
+ EAP_KEY_LENGTH(ctx),
+ ctx->encryptionType,
+ &ctx->rfc3961Key);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
+ &ctx->checksumType);
+ if (GSS_ERROR(major))
+ return major;
+ } else {
+ /*
+ * draft-howlett-eap-gss says that integrity/confidentialty should
+ * always be advertised as available, but if we have no keying
+ * material it seems confusing to the caller to advertise this.
+ */
+ ctx->gssFlags &= ~(GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG);
+ }
+
+ major = sequenceInit(minor,
+ &ctx->seqState, ctx->recvSeq,
+ ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0),
+ ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0),
+ TRUE);
+ if (GSS_ERROR(major))
+ return major;
+
+ return GSS_S_COMPLETE;
+}