#include "gssapiP_eap.h"
+#define EAP_MAX_METHODS 8
+
+#define EAP_TTLS_AUTH_PAP 1
+#define EAP_TTLS_AUTH_CHAP 2
+#define EAP_TTLS_AUTH_MSCHAP 4
+#define EAP_TTLS_AUTH_MSCHAPV2 8
+
+#if 1
+struct eap_user {
+ struct {
+ int vendor;
+ u32 method;
+ } methods[EAP_MAX_METHODS];
+ u8 *password;
+ size_t password_len;
+ int password_hash; /* whether password is hashed with
+ * nt_password_hash() */
+ int phase2;
+ int force_version;
+ int ttls_auth; /* bitfield of
+ * EAP_TTLS_AUTH_{PAP,CHAP,MSCHAP,MSCHAPV2} */
+};
+
+struct eap_eapol_interface {
+ /* Lower layer to full authenticator variables */
+ Boolean eapResp; /* shared with EAPOL Backend Authentication */
+ struct wpabuf *eapRespData;
+ Boolean portEnabled;
+ int retransWhile;
+ Boolean eapRestart; /* shared with EAPOL Authenticator PAE */
+ int eapSRTT;
+ int eapRTTVAR;
+
+ /* Full authenticator to lower layer variables */
+ Boolean eapReq; /* shared with EAPOL Backend Authentication */
+ Boolean eapNoReq; /* shared with EAPOL Backend Authentication */
+ Boolean eapSuccess;
+ Boolean eapFail;
+ Boolean eapTimeout;
+ struct wpabuf *eapReqData;
+ u8 *eapKeyData;
+ size_t eapKeyDataLen;
+ Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
+
+ /* AAA interface to full authenticator variables */
+ Boolean aaaEapReq;
+ Boolean aaaEapNoReq;
+ Boolean aaaSuccess;
+ Boolean aaaFail;
+ struct wpabuf *aaaEapReqData;
+ u8 *aaaEapKeyData;
+ size_t aaaEapKeyDataLen;
+ Boolean aaaEapKeyAvailable;
+ int aaaMethodTimeout;
+
+ /* Full authenticator to AAA interface variables */
+ Boolean aaaEapResp;
+ struct wpabuf *aaaEapRespData;
+ /* aaaIdentity -> eap_get_identity() */
+ Boolean aaaTimeout;
+};
+
+#define eapol_callbacks SERVER_eapol_callbacks
+
+struct eapol_callbacks {
+ int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
+ int phase2, struct eap_user *user);
+ const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
+};
+
+#define eap_config SERVER_eap_config
+
+struct eap_config {
+ void *ssl_ctx;
+ void *msg_ctx;
+ void *eap_sim_db_priv;
+ Boolean backend_auth;
+ int eap_server;
+ u8 *pac_opaque_encr_key;
+ u8 *eap_fast_a_id;
+ size_t eap_fast_a_id_len;
+ char *eap_fast_a_id_info;
+ int eap_fast_prov;
+ int pac_key_lifetime;
+ int pac_key_refresh_time;
+ int eap_sim_aka_result_ind;
+ int tnc;
+ struct wps_context *wps;
+ const struct wpabuf *assoc_wps_ie;
+ const u8 *peer_addr;
+ int fragment_size;
+};
+
+struct eap_sm * eap_server_sm_init(void *eapol_ctx,
+ struct eapol_callbacks *eapol_cb,
+ struct eap_config *eap_conf);
+void eap_server_sm_deinit(struct eap_sm *sm);
+int eap_server_sm_step(struct eap_sm *sm);
+void eap_sm_notify_cached(struct eap_sm *sm);
+void eap_sm_pending_cb(struct eap_sm *sm);
+int eap_sm_method_pending(struct eap_sm *sm);
+const u8 * eap_get_identity(struct eap_sm *sm, size_t *len);
+struct eap_eapol_interface * eap_get_interface(struct eap_sm *sm);
+
+static OM_uint32
+initTls(OM_uint32 *minor,
+ gss_ctx_id_t ctx)
+{
+ struct tls_config tconf;
+ struct tls_connection_params tparams;
+
+ memset(&tconf, 0, sizeof(tconf));
+ ctx->acceptorCtx.tlsContext = tls_init(&tconf);
+ if (ctx->acceptorCtx.tlsContext == NULL)
+ return GSS_S_FAILURE;
+
+ memset(&tparams, 0, sizeof(tparams));
+ tparams.ca_cert = "ca.pem";
+ tparams.client_cert = "server.pem";
+ tparams.private_key = "server-key.pem";
+
+ if (tls_global_set_params(ctx->acceptorCtx.tlsContext, &tparams)) {
+ return GSS_S_FAILURE;
+ }
+
+ if (tls_global_set_verify(ctx->acceptorCtx.tlsContext, 0)) {
+ return GSS_S_FAILURE;
+ }
+
+ return GSS_S_COMPLETE;
+}
+
+static int
+serverGetEapUser(void *ctx,
+ const unsigned char *identity,
+ size_t identityLength,
+ int phase2,
+ struct eap_user *user)
+{
+ gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
+ OM_uint32 major, minor;
+ gss_buffer_desc buf;
+
+ memset(user, 0, sizeof(*user));
+
+ buf.length = identityLength;
+ buf.value = (void *)identity;
+
+ if (phase2 == 0) {
+ user->methods[0].vendor = EAP_VENDOR_IETF;
+ user->methods[0].method = EAP_TYPE_PEAP;
+ return 0;
+ }
+
+ major = gssEapImportName(&minor, &buf, GSS_C_NT_USER_NAME,
+ &gssCtx->initiatorName);
+ if (GSS_ERROR(major))
+ return -1;
+
+ /*
+ * OK, obviously there is no real security here, this is simply
+ * for testing the token exchange; this code will be completely
+ * replaced with libradsec once that library is available.
+ */
+ user->methods[0].vendor = EAP_VENDOR_IETF;
+ user->methods[0].method = EAP_TYPE_MSCHAPV2;
+ user->password = (unsigned char *)strdup("");
+ user->password_len = 0;
+
+ return 0;
+}
+
+static const char *
+serverGetEapReqIdText(void *ctx,
+ size_t *len)
+{
+ *len = 0;
+ return NULL;
+}
+#endif
+
+static OM_uint32
+serverDeriveKey(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);
+ }
+
+ return GSS_S_COMPLETE;
+}
+
static OM_uint32
eapGssSmAcceptAuthenticate(OM_uint32 *minor,
gss_ctx_id_t ctx,
gss_channel_bindings_t chanBindings,
gss_buffer_t outputToken)
{
- OM_uint32 major, tmpMinor;
+ OM_uint32 major, tmpMinor, tmpMajor;
+ int code;
+ struct wpabuf respData;
+ struct eap_config *config = (struct eap_config *)&ctx->acceptorCtx.eapConfig;
+ static struct eapol_callbacks cb = { serverGetEapUser, serverGetEapReqIdText };
+
+ wpabuf_set(&respData, inputToken->value, inputToken->length);
+ ctx->acceptorCtx.eapPolInterface->eapRespData = &respData;
+ ctx->acceptorCtx.eapPolInterface->eapResp = TRUE;
+
+ if (ctx->acceptorCtx.eap == NULL) {
+ /* initial context token */
+ config->eap_server = 1;
+ config->ssl_ctx = ctx->acceptorCtx.tlsContext;
+
+ major = initTls(minor, ctx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ctx->acceptorCtx.eap = eap_server_sm_init(ctx, &cb, config);
+ if (ctx->acceptorCtx.eap == NULL) {
+ major = GSS_S_FAILURE;
+ goto cleanup;
+ }
+ }
+
+ if (ctx->acceptorName == GSS_C_NO_NAME && cred->name != GSS_C_NO_NAME) {
+ major = gss_duplicate_name(minor, cred->name, &ctx->acceptorName);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ code = eap_server_sm_step(ctx->acceptorCtx.eap);
+
+ if (ctx->acceptorCtx.eapPolInterface->eapReq) {
+ ctx->acceptorCtx.eapPolInterface->eapReq = 0;
+ major = GSS_S_CONTINUE_NEEDED;
+ }
+
+ if (ctx->acceptorCtx.eapPolInterface->eapSuccess) {
+ major = serverDeriveKey(minor, ctx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ctx->acceptorCtx.eapPolInterface->eapSuccess = 0;
+ ctx->state = EAP_STATE_ESTABLISHED;
+ major = GSS_S_COMPLETE;
+ } else if (ctx->acceptorCtx.eapPolInterface->eapFail) {
+ ctx->acceptorCtx.eapPolInterface->eapFail = 0;
+ major = GSS_S_FAILURE;
+ } else if (code == 0) {
+ major = GSS_S_FAILURE;
+ }
+
+ if (ctx->acceptorCtx.eapPolInterface->eapReqData != NULL) {
+ gss_buffer_desc buf;
+
+ buf.length = wpabuf_len(ctx->acceptorCtx.eapPolInterface->eapReqData);
+ buf.value = (void *)wpabuf_head(ctx->acceptorCtx.eapPolInterface->eapReqData);
+
+ tmpMajor = duplicateBuffer(&tmpMinor, &buf, outputToken);
+ if (GSS_ERROR(tmpMajor)) {
+ major = tmpMajor;
+ goto cleanup;
+ }
+ }
cleanup:
return major;
}
+static OM_uint32
+eapGssSmAcceptEstablished(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)
+{
+ /* Called with already established context */
+ *minor = EINVAL;
+ return GSS_S_BAD_STATUS;
+}
static struct eap_gss_acceptor_sm {
enum gss_eap_token_type inputTokenType;
gss_channel_bindings_t,
gss_buffer_t);
} eapGssAcceptorSm[] = {
- { TOK_TYPE_EAP_RESP, TOK_TYPE_EAP_REQ, NULL },
+ { 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 },
};
OM_uint32
gss_ctx_id_t ctx = *context_handle;
struct eap_gss_acceptor_sm *sm = NULL;
gss_buffer_desc innerInputToken, innerOutputToken;
-
+
*minor = 0;
innerOutputToken.length = 0;
} while (major == GSS_S_CONTINUE_NEEDED && innerOutputToken.length == 0);
if (src_name != NULL && ctx->initiatorName != GSS_C_NO_NAME) {
- major = gss_duplicate_name(&minor, ctx->initiatorName, src_name);
+ major = gss_duplicate_name(minor, ctx->initiatorName, src_name);
if (GSS_ERROR(major))
goto cleanup;
}
}
static int
+eapServerRegisterMethods(void)
+{
+ int ret = 0;
+
+#ifdef EAP_SERVER_IDENTITY
+ if (ret == 0)
+ ret = eap_server_identity_register();
+#endif /* EAP_SERVER_IDENTITY */
+
+#ifdef EAP_SERVER_MD5
+ if (ret == 0)
+ ret = eap_server_md5_register();
+#endif /* EAP_SERVER_MD5 */
+
+#ifdef EAP_SERVER_TLS
+ if (ret == 0)
+ ret = eap_server_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_MSCHAPV2
+ if (ret == 0)
+ ret = eap_server_mschapv2_register();
+#endif /* EAP_SERVER_MSCHAPV2 */
+
+#ifdef EAP_SERVER_PEAP
+ if (ret == 0)
+ ret = eap_server_peap_register();
+#endif /* EAP_SERVER_PEAP */
+
+#ifdef EAP_SERVER_TLV
+ if (ret == 0)
+ ret = eap_server_tlv_register();
+#endif /* EAP_SERVER_TLV */
+#ifdef EAP_SERVER_GTC
+ if (ret == 0)
+ ret = eap_server_gtc_register();
+#endif /* EAP_SERVER_GTC */
+
+#ifdef EAP_SERVER_TTLS
+ if (ret == 0)
+ ret = eap_server_ttls_register();
+#endif /* EAP_SERVER_TTLS */
+
+#ifdef EAP_SERVER_SIM
+ if (ret == 0)
+ ret = eap_server_sim_register();
+#endif /* EAP_SERVER_SIM */
+
+#ifdef EAP_SERVER_AKA
+ if (ret == 0)
+ ret = eap_server_aka_register();
+#endif /* EAP_SERVER_AKA */
+
+#ifdef EAP_SERVER_AKA_PRIME
+ if (ret == 0)
+ ret = eap_server_aka_prime_register();
+#endif /* EAP_SERVER_AKA_PRIME */
+
+#ifdef EAP_SERVER_PAX
+ if (ret == 0)
+ ret = eap_server_pax_register();
+#endif /* EAP_SERVER_PAX */
+
+#ifdef EAP_SERVER_PSK
+ if (ret == 0)
+ ret = eap_server_psk_register();
+#endif /* EAP_SERVER_PSK */
+
+#ifdef EAP_SERVER_SAKE
+ if (ret == 0)
+ ret = eap_server_sake_register();
+#endif /* EAP_SERVER_SAKE */
+
+#ifdef EAP_SERVER_GPSK
+ if (ret == 0)
+ ret = eap_server_gpsk_register();
+#endif /* EAP_SERVER_GPSK */
+
+#ifdef EAP_SERVER_VENDOR_TEST
+ if (ret == 0)
+ ret = eap_server_vendor_test_register();
+#endif /* EAP_SERVER_VENDOR_TEST */
+
+#ifdef EAP_SERVER_FAST
+ if (ret == 0)
+ ret = eap_server_fast_register();
+#endif /* EAP_SERVER_FAST */
+
+#ifdef EAP_SERVER_WSC
+ if (ret == 0)
+ ret = eap_server_wsc_register();
+#endif /* EAP_SERVER_WSC */
+
+#ifdef EAP_SERVER_IKEV2
+ if (ret == 0)
+ ret = eap_server_ikev2_register();
+#endif /* EAP_SERVER_IKEV2 */
+
+#ifdef EAP_SERVER_TNC
+ if (ret == 0)
+ ret = eap_server_tnc_register();
+#endif /* EAP_SERVER_TNC */
+}
+
+static int
gssEapInitLibEap(void)
{
return eapPeerRegisterMethods();
ret = gssEapInitLibEap();
if (ret == 0)
- gssEapInitLibRadSec();
+#if 0
+ ret = gssEapInitLibRadSec();
+#else
+ ret = eapServerRegisterMethods();
+#endif
}
static void
gssEapFinalize(void)
{
eap_peer_unregister_methods();
+#if 1
+ eap_server_unregister_methods();
+#endif
}