--- /dev/null
- SOURCES_BOTH += src/eap_common/chap.c
+AUTOMAKE_OPTIONS = foreign
+
+AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils
+ +noinst_HEADERS = \
+ + src/common/defs.h \
+ + src/common/eapol_common.h \
+ + src/common/ieee802_11_common.h \
+ + src/common/ieee802_11_defs.h \
+ + src/common/privsep_commands.h \
+ + src/common/version.h \
+ + src/common/wpa_common.h \
+ + src/common/wpa_ctrl.h
+ +
+ +EXTRA_DIST = src/tls/libtommath.c
+
+SOURCES_BOTH = src/eap_common/eap_peap_common.c
+SOURCES_BOTH += src/eap_common/eap_psk_common.c
+SOURCES_BOTH += src/eap_common/eap_pax_common.c
+SOURCES_BOTH += src/eap_common/eap_sake_common.c
+SOURCES_BOTH += src/eap_common/eap_gpsk_common.c
- SOURCES_peer += src/eap_peer/eap_tls_common.c
+ +SOURCES_BOTH += src/eap_common/chap.c \
+ +src/eap_common/chap.h \
+ + src/eap_common/eap_common.h \
+ + src/eap_common/eap_defs.h \
+ + src/eap_common/eap_fast_common.h \
+ + src/eap_common/eap_gpsk_common.h \
+ + src/eap_common/eap_ikev2_common.h \
+ + src/eap_common/eap_pax_common.h \
+ + src/eap_common/eap_peap_common.h \
+ + src/eap_common/eap_psk_common.h \
+ + src/eap_common/eap_pwd_common.h \
+ + src/eap_common/eap_sake_common.h \
+ + src/eap_common/eap_sim_common.h \
+ + src/eap_common/eap_tlv_common.h \
+ + src/eap_common/eap_ttls.h \
+ + src/eap_common/eap_wsc_common.h \
+ + src/eap_common/ikev2_common.h
+ +
+
+SOURCES_peer = src/eap_peer/eap_tls.c
+SOURCES_peer += src/eap_peer/eap_peap.c
+SOURCES_peer += src/eap_peer/eap_ttls.c
+SOURCES_peer += src/eap_peer/eap_md5.c
+SOURCES_peer += src/eap_peer/eap_mschapv2.c
+SOURCES_peer += src/eap_peer/mschapv2.c
+SOURCES_peer += src/eap_peer/eap_otp.c
+SOURCES_peer += src/eap_peer/eap_gtc.c
+SOURCES_peer += src/eap_peer/eap_leap.c
+SOURCES_peer += src/eap_peer/eap_psk.c
+SOURCES_peer += src/eap_peer/eap_pax.c
+SOURCES_peer += src/eap_peer/eap_sake.c
+SOURCES_peer += src/eap_peer/eap_gpsk.c
+SOURCES_peer += src/eap_peer/eap.c
+SOURCES_peer += src/eap_common/eap_common.c
+SOURCES_peer += src/eap_peer/eap_methods.c
- src/utils/os_unix.c
+ +SOURCES_peer += src/eap_peer/eap_tls_common.c \
+ + src/eap_peer/eap_config.h \
+ + src/eap_peer/eap_fast_pac.h \
+ + src/eap_peer/eap.h \
+ + src/eap_peer/eap_i.h \
+ + src/eap_peer/eap_methods.h \
+ + src/eap_peer/eap_tls_common.h \
+ + src/eap_peer/ikev2.h \
+ + src/eap_peer/mschapv2.h \
+ + src/eap_peer/tncc.h
+ +
+CFLAGS += -DEAP_TLS
+CFLAGS += -DEAP_PEAP
+CFLAGS += -DEAP_TTLS
+CFLAGS += -DEAP_MD5
+CFLAGS += -DEAP_MSCHAPv2
+CFLAGS += -DEAP_GTC
+CFLAGS += -DEAP_OTP
+CFLAGS += -DEAP_LEAP
+CFLAGS += -DEAP_PSK
+CFLAGS += -DEAP_PAX
+CFLAGS += -DEAP_SAKE
+CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256
+
+CFLAGS += -DEAP_SERVER_IDENTITY
+CFLAGS += -DEAP_SERVER_TLS
+CFLAGS += -DEAP_SERVER_PEAP
+CFLAGS += -DEAP_SERVER_TTLS
+CFLAGS += -DEAP_SERVER_MD5
+CFLAGS += -DEAP_SERVER_MSCHAPV2
+CFLAGS += -DEAP_SERVER_GTC
+CFLAGS += -DEAP_SERVER_PSK
+CFLAGS += -DEAP_SERVER_PAX
+CFLAGS += -DEAP_SERVER_SAKE
+CFLAGS += -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256
+
+CFLAGS += -DIEEE8021X_EAPOL
+CFLAGS += -DCONFIG_IPV6
+
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
++CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+
+UTILS_SRCS = src/utils/base64.c \
+ src/utils/common.c \
+ src/utils/ip_addr.c \
+ src/utils/radiotap.c \
+ src/utils/trace.c \
+ src/utils/uuid.c \
+ src/utils/wpa_debug.c \
+ src/utils/wpabuf.c \
- src/crypto/fips_prf_internal.c
+ + src/utils/os_unix.c \
+ + src/utils/base64.h \
+ + src/utils/build_config.h \
+ + src/utils/common.h \
+ + src/utils/eloop.h \
+ + src/utils/includes.h \
+ + src/utils/ip_addr.h \
+ + src/utils/list.h \
+ + src/utils/os.h \
+ + src/utils/pcsc_funcs.h \
+ + src/utils/radiotap.h \
+ + src/utils/radiotap_iter.h \
+ + src/utils/state_machine.h \
+ + src/utils/trace.h \
+ + src/utils/uuid.h \
+ + src/utils/wpabuf.h \
+ + src/utils/wpa_debug.h
+ +
+
+CRYPTO_SRCS = \
+ src/crypto/aes-cbc.c \
+ src/crypto/aes-ctr.c \
+ src/crypto/aes-eax.c \
+ src/crypto/aes-encblock.c \
+ src/crypto/aes-internal.c \
+ src/crypto/aes-internal-dec.c \
+ src/crypto/aes-internal-enc.c \
+ src/crypto/aes-omac1.c \
+ src/crypto/aes-unwrap.c \
+ src/crypto/aes-wrap.c \
+ src/crypto/des-internal.c \
+ src/crypto/dh_group5.c \
+ src/crypto/dh_groups.c \
+ src/crypto/md4-internal.c \
+ src/crypto/md5.c \
+ src/crypto/md5-internal.c \
+ src/crypto/md5-non-fips.c \
+ src/crypto/milenage.c \
+ src/crypto/ms_funcs.c \
+ src/crypto/rc4.c \
+ src/crypto/sha1.c \
+ src/crypto/sha1-internal.c \
+ src/crypto/sha1-pbkdf2.c \
+ src/crypto/sha1-tlsprf.c \
+ src/crypto/sha1-tprf.c \
+ src/crypto/sha256.c \
+ src/crypto/sha256-internal.c \
+ src/crypto/crypto_internal.c \
+ src/crypto/crypto_internal-cipher.c \
+ src/crypto/crypto_internal-modexp.c \
+ src/crypto/crypto_internal-rsa.c \
+ src/crypto/tls_internal.c \
- src/tls/x509v3.c
+ + src/crypto/fips_prf_internal.c \
+ + src/crypto/aes.h \
+ + src/crypto/aes_i.h \
+ + src/crypto/aes_wrap.h \
+ + src/crypto/crypto.h \
+ + src/crypto/des_i.h \
+ + src/crypto/dh_group5.h \
+ + src/crypto/dh_groups.h \
+ + src/crypto/md5.h \
+ + src/crypto/md5_i.h \
+ + src/crypto/milenage.h \
+ + src/crypto/ms_funcs.h \
+ + src/crypto/sha1.h \
+ + src/crypto/sha1_i.h \
+ + src/crypto/sha256.h \
+ + src/crypto/tls.h
+ +
+
+TLS_SRCS = \
+ src/tls/asn1.c \
+ src/tls/bignum.c \
+ src/tls/pkcs1.c \
+ src/tls/pkcs5.c \
+ src/tls/pkcs8.c \
+ src/tls/rsa.c \
+ src/tls/tlsv1_client.c \
+ src/tls/tlsv1_client_read.c \
+ src/tls/tlsv1_client_write.c \
+ src/tls/tlsv1_common.c \
+ src/tls/tlsv1_cred.c \
+ src/tls/tlsv1_record.c \
+ src/tls/tlsv1_server.c \
+ src/tls/tlsv1_server_read.c \
+ src/tls/tlsv1_server_write.c \
+ + src/tls/x509v3.c \
+ + src/tls/asn1.h \
+ + src/tls/bignum.h \
+ + src/tls/pkcs1.h \
+ + src/tls/pkcs5.h \
+ + src/tls/pkcs8.h \
+ + src/tls/rsa.h \
+ + src/tls/tlsv1_client.h \
+ + src/tls/tlsv1_client_i.h \
+ + src/tls/tlsv1_common.h \
+ + src/tls/tlsv1_cred.h \
+ + src/tls/tlsv1_record.h \
+ + src/tls/tlsv1_server.h \
+ + src/tls/tlsv1_server_i.h \
+ + src/tls/x509v3.h
+
+libeap_la_SOURCES = $(SOURCES_BOTH) $(SOURCES_peer) $(UTILS_SRCS) $(CRYPTO_SRCS) $(TLS_SRCS)
+
+noinst_LTLIBRARIES = libeap.la
--- /dev/null
- static GSSEAP_THREAD_ONCE gssEapStatusInfoKeyOnce = GSSEAP_ONCE_INITIALIZER;
- static GSSEAP_THREAD_KEY gssEapStatusInfoKey;
-
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Function for converting mechanism error codes to strings.
+ */
+
+#include "gssapiP_eap.h"
+
- static void
- destroyStatusInfo(void *arg)
+struct gss_eap_status_info {
+ OM_uint32 code;
+ char *message;
+ struct gss_eap_status_info *next;
+};
+
- struct gss_eap_status_info *p = arg, *next;
+ +void
+ +gssEapDestroyStatusInfo(struct gss_eap_status_info *p)
+{
- for (p = arg; p != NULL; p = next) {
+ + struct gss_eap_status_info *next;
+
- static void
- createStatusInfoKey(void)
- {
- GSSEAP_KEY_CREATE(&gssEapStatusInfoKey, destroyStatusInfo);
- }
-
+ + for (; p != NULL; p = next) {
+ next = p->next;
+ GSSEAP_FREE(p->message);
+ GSSEAP_FREE(p);
+ }
+}
+
- struct gss_eap_status_info **next = NULL, *p;
-
- GSSEAP_ONCE(&gssEapStatusInfoKeyOnce, createStatusInfoKey);
-
- p = GSSEAP_GETSPECIFIC(gssEapStatusInfoKey);
- for (; p != NULL; p = p->next) {
- if (p->code == minor) {
- /* Set message in-place */
- if (p->message != NULL)
- GSSEAP_FREE(p->message);
- p->message = message;
- return;
+/*
+ * Associate a message with a mechanism (minor) status code. This function
+ * takes ownership of the message regardless of success. The message must
+ * be explicitly cleared, if required, so it is suggested that a specific
+ * minor code is either always or never associated with a message, to avoid
+ * dangling (and potentially confusing) error messages.
+ */
+static void
+saveStatusInfoNoCopy(OM_uint32 minor, char *message)
+{
- next = &p->next;
+ + struct gss_eap_status_info **next = NULL, *p = NULL;
+ + struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
+ +
+ + if (tld != NULL) {
+ + for (p = tld->statusInfo; p != NULL; p = p->next) {
+ + if (p->code == minor) {
+ + /* Set message in-place */
+ + if (p->message != NULL)
+ + GSSEAP_FREE(p->message);
+ + p->message = message;
+ + return;
+ + }
+ + next = &p->next;
+ }
- p = GSSEAP_CALLOC(1, sizeof(*p));
+ + p = GSSEAP_CALLOC(1, sizeof(*p));
+ }
+
- GSSEAP_SETSPECIFIC(gssEapStatusInfoKey, p);
+ if (p == NULL) {
+ if (message != NULL)
+ GSSEAP_FREE(message);
+ return;
+ }
+
+ p->code = minor;
+ p->message = message;
+
+ if (next != NULL)
+ *next = p;
+ else
- GSSEAP_ONCE(&gssEapStatusInfoKeyOnce, createStatusInfoKey);
-
- for (p = GSSEAP_GETSPECIFIC(gssEapStatusInfoKey);
- p != NULL;
- p = p->next) {
- if (p->code == minor)
- return p->message;
+ + tld->statusInfo = p;
+}
+
+static const char *
+getStatusInfo(OM_uint32 minor)
+{
+ struct gss_eap_status_info *p;
+ + struct gss_eap_thread_local_data *tld = gssEapGetThreadLocalData();
+
-
+ + if (tld != NULL) {
+ + for (p = tld->statusInfo; p != NULL; p = p->next) {
+ + if (p->code == minor)
+ + return p->message;
+ + }
+ }
- gss_display_status(OM_uint32 *minor,
- OM_uint32 status_value,
- int status_type,
- gss_OID mech_type,
- OM_uint32 *message_context,
- gss_buffer_t status_string)
+ return NULL;
+}
+
+void
+gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...)
+{
+ +#ifdef WIN32
+ + OM_uint32 tmpMajor, tmpMinor;
+ + char buf[BUFSIZ];
+ + gss_buffer_desc s = GSS_C_EMPTY_BUFFER;
+ + va_list ap;
+ +
+ + if (format != NULL) {
+ + va_start(ap, format);
+ + snprintf(buf, sizeof(buf), format, ap);
+ + va_end(ap);
+ + }
+ +
+ + tmpMajor = makeStringBuffer(&tmpMinor, buf, &s);
+ + if (!GSS_ERROR(tmpMajor))
+ + saveStatusInfoNoCopy(minor, (char *)s.value);
+ +#else
+ char *s = NULL;
+ int n;
+ va_list ap;
+
+ if (format != NULL) {
+ va_start(ap, format);
+ n = vasprintf(&s, format, ap);
+ + if (n == -1)
+ + s = NULL;
+ va_end(ap);
++ if (n == -1)
++ s = NULL;
+ }
+
+ saveStatusInfoNoCopy(minor, s);
+ +#endif /* WIN32 */
+}
+
+OM_uint32
- if (!gssEapIsMechanismOid(mech_type)) {
- *minor = GSSEAP_WRONG_MECH;
- return GSS_S_BAD_MECH;
- }
-
- if (status_type != GSS_C_MECH_CODE ||
- *message_context != 0) {
- /* we rely on the mechglue for GSS_C_GSS_CODE */
- *minor = 0;
- return GSS_S_BAD_STATUS;
- }
-
+ +gssEapDisplayStatus(OM_uint32 *minor,
+ + OM_uint32 status_value,
+ + gss_buffer_t status_string)
+{
+ OM_uint32 major;
+ krb5_context krbContext = NULL;
+ const char *errMsg;
+
+ status_string->length = 0;
+ status_string->value = NULL;
+
+ errMsg = getStatusInfo(status_value);
+ if (errMsg == NULL) {
+ GSSEAP_KRB_INIT(&krbContext);
+
+ /* Try the com_err message */
+ errMsg = krb5_get_error_message(krbContext, status_value);
+ }
+
+ if (errMsg != NULL) {
+ major = makeStringBuffer(minor, errMsg, status_string);
+ } else {
+ major = GSS_S_COMPLETE;
+ *minor = 0;
+ }
+
+ if (krbContext != NULL)
+ krb5_free_error_message(krbContext, errMsg);
+
+ return major;
+}
+ +
+ +OM_uint32 GSSAPI_CALLCONV
+ +gss_display_status(OM_uint32 *minor,
+ + OM_uint32 status_value,
+ + int status_type,
+ + gss_OID mech_type,
+ + OM_uint32 *message_context,
+ + gss_buffer_t status_string)
+ +{
+ + if (!gssEapIsMechanismOid(mech_type)) {
+ + *minor = GSSEAP_WRONG_MECH;
+ + return GSS_S_BAD_MECH;
+ + }
+ +
+ + if (status_type != GSS_C_MECH_CODE ||
+ + *message_context != 0) {
+ + /* we rely on the mechglue for GSS_C_GSS_CODE */
+ + *minor = 0;
+ + return GSS_S_BAD_STATUS;
+ + }
+ +
+ + return gssEapDisplayStatus(minor, status_value, status_string);
+ +}
--- /dev/null
- assert(CTX_IS_INITIATOR(ctx));
+/*
+ * Copyright (c) 2011, JANET(UK)
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of JANET(UK) nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Establish a security context on the initiator (client). These functions
+ * wrap around libeap.
+ */
+
+#include "gssapiP_eap.h"
+
+static OM_uint32
+policyVariableToFlag(enum eapol_bool_var variable)
+{
+ OM_uint32 flag = 0;
+
+ switch (variable) {
+ case EAPOL_eapSuccess:
+ flag = CTX_FLAG_EAP_SUCCESS;
+ break;
+ case EAPOL_eapRestart:
+ flag = CTX_FLAG_EAP_RESTART;
+ break;
+ case EAPOL_eapFail:
+ flag = CTX_FLAG_EAP_FAIL;
+ break;
+ case EAPOL_eapResp:
+ flag = CTX_FLAG_EAP_RESP;
+ break;
+ case EAPOL_eapNoResp:
+ flag = CTX_FLAG_EAP_NO_RESP;
+ break;
+ case EAPOL_eapReq:
+ flag = CTX_FLAG_EAP_REQ;
+ break;
+ case EAPOL_portEnabled:
+ flag = CTX_FLAG_EAP_PORT_ENABLED;
+ break;
+ case EAPOL_altAccept:
+ flag = CTX_FLAG_EAP_ALT_ACCEPT;
+ break;
+ case EAPOL_altReject:
+ flag = CTX_FLAG_EAP_ALT_REJECT;
+ break;
+ }
+
+ return flag;
+}
+
+static struct eap_peer_config *
+peerGetConfig(void *ctx)
+{
+ gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
+
+ return &gssCtx->initiatorCtx.eapPeerConfig;
+}
+
+static Boolean
+peerGetBool(void *data, enum eapol_bool_var variable)
+{
+ gss_ctx_id_t ctx = data;
+ OM_uint32 flag;
+
+ if (ctx == GSS_C_NO_CONTEXT)
+ return FALSE;
+
+ flag = policyVariableToFlag(variable);
+
+ return ((ctx->flags & flag) != 0);
+}
+
+static void
+peerSetBool(void *data, enum eapol_bool_var variable,
+ Boolean value)
+{
+ gss_ctx_id_t ctx = data;
+ OM_uint32 flag;
+
+ if (ctx == GSS_C_NO_CONTEXT)
+ return;
+
+ flag = policyVariableToFlag(variable);
+
+ if (value)
+ ctx->flags |= flag;
+ else
+ ctx->flags &= ~(flag);
+}
+
+static unsigned int
+peerGetInt(void *data, enum eapol_int_var variable)
+{
+ gss_ctx_id_t ctx = data;
+
+ if (ctx == GSS_C_NO_CONTEXT)
+ return FALSE;
+
- assert(CTX_IS_INITIATOR(ctx));
+ + GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
+
+ switch (variable) {
+ case EAPOL_idleWhile:
+ return ctx->initiatorCtx.idleWhile;
+ break;
+ }
+
+ return 0;
+}
+
+static void
+peerSetInt(void *data, enum eapol_int_var variable,
+ unsigned int value)
+{
+ gss_ctx_id_t ctx = data;
+
+ if (ctx == GSS_C_NO_CONTEXT)
+ return;
+
- peerConfigInit(OM_uint32 *minor,
- gss_cred_id_t cred,
- gss_ctx_id_t ctx)
+ + GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx));
+
+ switch (variable) {
+ case EAPOL_idleWhile:
+ ctx->initiatorCtx.idleWhile = value;
+ break;
+ }
+}
+
+static struct wpabuf *
+peerGetEapReqData(void *ctx)
+{
+ gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
+
+ return &gssCtx->initiatorCtx.reqData;
+}
+
+static void
+peerSetConfigBlob(void *ctx GSSEAP_UNUSED,
+ struct wpa_config_blob *blob GSSEAP_UNUSED)
+{
+}
+
+static const struct wpa_config_blob *
+peerGetConfigBlob(void *ctx GSSEAP_UNUSED,
+ const char *name GSSEAP_UNUSED)
+{
+ return NULL;
+}
+
+static void
+peerNotifyPending(void *ctx GSSEAP_UNUSED)
+{
+}
+
+static struct eapol_callbacks gssEapPolicyCallbacks = {
+ peerGetConfig,
+ peerGetBool,
+ peerSetBool,
+ peerGetInt,
+ peerSetInt,
+ peerGetEapReqData,
+ peerSetConfigBlob,
+ peerGetConfigBlob,
+ peerNotifyPending,
+};
+
+#ifdef GSSEAP_DEBUG
+extern int wpa_debug_level;
+#endif
+
+static OM_uint32
- assert(cred != GSS_C_NO_CREDENTIAL);
+ +peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
+{
+ OM_uint32 major;
+ krb5_context krbContext;
+ struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
+ gss_buffer_desc identity = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc realm = GSS_C_EMPTY_BUFFER;
+ + gss_cred_id_t cred = ctx->cred;
+
+ eapPeerConfig->identity = NULL;
+ eapPeerConfig->identity_len = 0;
+ eapPeerConfig->anonymous_identity = NULL;
+ eapPeerConfig->anonymous_identity_len = 0;
+ eapPeerConfig->password = NULL;
+ eapPeerConfig->password_len = 0;
+
- assert(cred->name != GSS_C_NO_NAME);
+ + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
+
+ GSSEAP_KRB_INIT(&krbContext);
+
+ eapPeerConfig->fragment_size = 1024;
+#ifdef GSSEAP_DEBUG
+ wpa_debug_level = 0;
+#endif
+
- gss_cred_id_t cred,
+ + GSSEAP_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;
+ }
+
+ /* identity */
+ major = gssEapDisplayName(minor, cred->name, &identity, NULL);
+ if (GSS_ERROR(major))
+ return major;
+
+ eapPeerConfig->identity = (unsigned char *)identity.value;
+ eapPeerConfig->identity_len = identity.length;
+
+ krbPrincRealmToGssBuffer(cred->name->krbPrincipal, &realm);
+
+ /* anonymous_identity */
+ eapPeerConfig->anonymous_identity = GSSEAP_MALLOC(realm.length + 2);
+ if (eapPeerConfig->anonymous_identity == NULL) {
+ *minor = ENOMEM;
+ return GSS_S_FAILURE;
+ }
+
+ eapPeerConfig->anonymous_identity[0] = '@';
+ memcpy(eapPeerConfig->anonymous_identity + 1, realm.value, realm.length);
+ eapPeerConfig->anonymous_identity[1 + realm.length] = '\0';
+ eapPeerConfig->anonymous_identity_len = 1 + realm.length;
+
+ /* password */
+ eapPeerConfig->password = (unsigned char *)cred->password.value;
+ eapPeerConfig->password_len = cred->password.length;
+
+ + /* certs */
+ + eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value;
+ + eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value;
+ + eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value;
+ +
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+peerConfigFree(OM_uint32 *minor,
+ gss_ctx_id_t ctx)
+{
+ struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
+
+ if (eapPeerConfig->identity != NULL) {
+ GSSEAP_FREE(eapPeerConfig->identity);
+ eapPeerConfig->identity = NULL;
+ eapPeerConfig->identity_len = 0;
+ }
+
+ if (eapPeerConfig->anonymous_identity != NULL) {
+ GSSEAP_FREE(eapPeerConfig->anonymous_identity);
+ eapPeerConfig->anonymous_identity = NULL;
+ eapPeerConfig->anonymous_identity_len = 0;
+ }
+
+ *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)
+{
+ OM_uint32 major;
+ const unsigned char *key;
+ size_t keyLength;
+
+#if 1
+ /* XXX actually check for mutual auth */
+ if (reqFlags & GSS_C_MUTUAL_FLAG)
+ ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
+#endif
+
+ /* Cache encryption type derived from selected mechanism OID */
+ major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (!eap_key_available(ctx->initiatorCtx.eap)) {
+ *minor = GSSEAP_KEY_UNAVAILABLE;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ key = eap_get_eapKeyData(ctx->initiatorCtx.eap, &keyLength);
+
+ if (keyLength < EAP_EMSK_LEN) {
+ *minor = GSSEAP_KEY_TOO_SHORT;
+ return GSS_S_UNAVAILABLE;
+ }
+
+ major = gssEapDeriveRfc3961Key(minor,
+ &key[EAP_EMSK_LEN / 2],
+ EAP_EMSK_LEN / 2,
+ ctx->encryptionType,
+ &ctx->rfc3961Key);
+ if (GSS_ERROR(major))
+ return major;
+
+ major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key,
+ &ctx->checksumType);
+ if (GSS_ERROR(major))
+ return major;
+
+ 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;
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+initBegin(OM_uint32 *minor,
- assert(cred != GSS_C_NO_CREDENTIAL);
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED)
+{
+ OM_uint32 major;
+ + gss_cred_id_t cred = ctx->cred;
+
- assert(GSS_ERROR(major));
+ + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
+
+ if (cred->expiryTime)
+ ctx->expiryTime = cred->expiryTime;
+ else if (timeReq == 0 || timeReq == GSS_C_INDEFINITE)
+ ctx->expiryTime = 0;
+ else
+ ctx->expiryTime = time(NULL) + timeReq;
+
+ /*
+ * The credential mutex protects its name, however we need to
+ * explicitly lock the acceptor name (unlikely as it may be
+ * that it has attributes set on it).
+ */
+ major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName);
+ if (GSS_ERROR(major))
+ return major;
+
+ if (target != GSS_C_NO_NAME) {
+ GSSEAP_MUTEX_LOCK(&target->mutex);
+
+ major = gssEapDuplicateName(minor, target, &ctx->acceptorName);
+ if (GSS_ERROR(major)) {
+ GSSEAP_MUTEX_UNLOCK(&target->mutex);
+ return major;
+ }
+
+ GSSEAP_MUTEX_UNLOCK(&target->mutex);
+ }
+
+ major = gssEapCanonicalizeOid(minor,
+ mech,
+ OID_FLAG_NULL_VALID | OID_FLAG_MAP_NULL_TO_DEFAULT_MECH,
+ &ctx->mechanismUsed);
+ if (GSS_ERROR(major))
+ return major;
+
+ /* If credentials were provided, check they're usable with this mech */
+ if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) {
+ *minor = GSSEAP_CRED_MECH_MISMATCH;
+ return GSS_S_BAD_MECH;
+ }
+
+ *minor = 0;
+ return GSS_S_COMPLETE;
+}
+
+static OM_uint32
+eapGssSmInitError(OM_uint32 *minor,
+ gss_cred_id_t cred GSSEAP_UNUSED,
+ gss_ctx_id_t ctx GSSEAP_UNUSED,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken GSSEAP_UNUSED,
+ OM_uint32 *smFlags GSSEAP_UNUSED)
+{
+ 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;
+ }
+
- assert(cred != GSS_C_NO_CREDENTIAL);
-
+ + GSSEAP_ASSERT(GSS_ERROR(major));
+
+ return major;
+}
+
+#ifdef GSSEAP_ENABLE_REAUTH
+static OM_uint32
+eapGssSmInitGssReauth(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags,
+ OM_uint32 timeReq,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken,
+ OM_uint32 *smFlags GSSEAP_UNUSED)
+{
+ OM_uint32 major, tmpMinor;
+ gss_name_t mechTarget = GSS_C_NO_NAME;
+ gss_OID actualMech = GSS_C_NO_OID;
+ OM_uint32 gssFlags, timeRec;
+
- assert(GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE);
+ + /*
+ + * Here we use the passed in credential handle because the resolved
+ + * context credential does not currently have the reauth creds.
+ + */
+ if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL) {
+ if (!gssEapCanReauthP(cred, target, timeReq))
+ return GSS_S_CONTINUE_NEEDED;
+
+ ctx->flags |= CTX_FLAG_KRB_REAUTH;
+ } else if ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ *minor = GSSEAP_WRONG_ITOK;
+ goto cleanup;
+ }
+
+ + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
+ +
+ major = gssEapMechToGlueName(minor, target, &mechTarget);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ major = gssInitSecContext(minor,
+ cred->reauthCred,
+ &ctx->reauthCtx,
+ mechTarget,
+ (gss_OID)gss_mech_krb5,
+ reqFlags | GSS_C_MUTUAL_FLAG,
+ timeReq,
+ chanBindings,
+ inputToken,
+ &actualMech,
+ outputToken,
+ &gssFlags,
+ &timeRec);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ctx->gssFlags = gssFlags;
+
+ if (major == GSS_S_COMPLETE) {
- assert((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
- assert(inputToken == GSS_C_NO_BUFFER);
+ + GSSEAP_ASSERT(GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE);
+
+ major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
+ } else {
+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE);
+ }
+
+cleanup:
+ gssReleaseName(&tmpMinor, &mechTarget);
+
+ return major;
+}
+#endif /* GSSEAP_ENABLE_REAUTH */
+
+#ifdef GSSEAP_DEBUG
+static OM_uint32
+eapGssSmInitVendorInfo(OM_uint32 *minor,
+ gss_cred_id_t cred GSSEAP_UNUSED,
+ gss_ctx_id_t ctx GSSEAP_UNUSED,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_buffer_t inputToken GSSEAP_UNUSED,
+ gss_buffer_t outputToken,
+ OM_uint32 *smFlags GSSEAP_UNUSED)
+{
+ OM_uint32 major;
+
+ major = makeStringBuffer(minor, "JANET(UK)", outputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ return GSS_S_CONTINUE_NEEDED;
+}
+#endif
+
+static OM_uint32
+eapGssSmInitAcceptorName(OM_uint32 *minor,
+ gss_cred_id_t cred GSSEAP_UNUSED,
+ gss_ctx_id_t ctx,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_buffer_t inputToken GSSEAP_UNUSED,
+ gss_buffer_t outputToken,
+ OM_uint32 *smFlags GSSEAP_UNUSED)
+{
+ OM_uint32 major;
+
+ if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL &&
+ ctx->acceptorName != GSS_C_NO_NAME) {
+
+ /* Send desired target name to acceptor */
+ major = gssEapDisplayName(minor, ctx->acceptorName,
+ outputToken, NULL);
+ if (GSS_ERROR(major))
+ return major;
+ } else if (inputToken != GSS_C_NO_BUFFER &&
+ ctx->acceptorName == GSS_C_NO_NAME) {
+ /* Accept target name hint from acceptor */
+ major = gssEapImportName(minor, inputToken,
+ GSS_C_NT_USER_NAME,
+ ctx->mechanismUsed,
+ &ctx->acceptorName);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ /*
+ * Currently, other parts of the code assume that the acceptor name
+ * is available, hence this check.
+ */
+ if (ctx->acceptorName == GSS_C_NO_NAME) {
+ *minor = GSSEAP_NO_ACCEPTOR_NAME;
+ return GSS_S_FAILURE;
+ }
+
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+eapGssSmInitIdentity(OM_uint32 *minor,
+ gss_cred_id_t cred GSSEAP_UNUSED,
+ gss_ctx_id_t ctx,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_buffer_t inputToken GSSEAP_UNUSED,
+ gss_buffer_t outputToken GSSEAP_UNUSED,
+ OM_uint32 *smFlags)
+{
+ struct eap_config eapConfig;
+
+#ifdef GSSEAP_ENABLE_REAUTH
+ if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE) {
+ OM_uint32 tmpMinor;
+
+ /* server didn't support reauthentication, sent EAP request */
+ gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER);
+ ctx->flags &= ~(CTX_FLAG_KRB_REAUTH);
+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL);
+ } else
+#endif
+ *smFlags |= SM_FLAG_FORCE_SEND_TOKEN;
+
- gss_cred_id_t cred,
+ + GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0);
+ + GSSEAP_ASSERT(inputToken == GSS_C_NO_BUFFER);
+
+ 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;
+ }
+
+ GSSEAP_SM_TRANSITION_NEXT(ctx);
+
+ *minor = 0;
+
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+eapGssSmInitAuthenticate(OM_uint32 *minor,
- assert(inputToken != GSS_C_NO_BUFFER);
+ + gss_cred_id_t cred GSSEAP_UNUSED,
+ gss_ctx_id_t ctx,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_buffer_t inputToken GSSEAP_UNUSED,
+ gss_buffer_t outputToken,
+ OM_uint32 *smFlags)
+{
+ OM_uint32 major;
+ OM_uint32 tmpMinor;
+ struct wpabuf *resp = NULL;
+
+ *minor = 0;
+
- major = peerConfigInit(minor, cred, ctx);
+ + GSSEAP_ASSERT(inputToken != GSS_C_NO_BUFFER);
+
- assert(ctx->initiatorCtx.eap != NULL);
- assert(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED);
+ + major = peerConfigInit(minor, ctx);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
- eap_peer_sm_step(ctx->initiatorCtx.eap);
+ + GSSEAP_ASSERT(ctx->initiatorCtx.eap != NULL);
+ + GSSEAP_ASSERT(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED);
+
+ ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */
+
+ wpabuf_set(&ctx->initiatorCtx.reqData,
+ inputToken->value, inputToken->length);
+
+ major = GSS_S_CONTINUE_NEEDED;
+
- assert(major == GSS_S_CONTINUE_NEEDED);
++ (void) eap_peer_sm_step(ctx->initiatorCtx.eap);
+ if (ctx->flags & CTX_FLAG_EAP_RESP) {
+ ctx->flags &= ~(CTX_FLAG_EAP_RESP);
+
+ resp = eap_get_eapRespData(ctx->initiatorCtx.eap);
+ } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) {
+ major = initReady(minor, ctx, reqFlags);
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS);
+ major = GSS_S_CONTINUE_NEEDED;
+ GSSEAP_SM_TRANSITION_NEXT(ctx);
+ } else if (ctx->flags & CTX_FLAG_EAP_FAIL) {
+ major = GSS_S_DEFECTIVE_CREDENTIAL;
+ *minor = GSSEAP_PEER_AUTH_FAILURE;
+ } else {
+ major = GSS_S_DEFECTIVE_TOKEN;
+ *minor = GSSEAP_PEER_BAD_MESSAGE;
+ }
+
+cleanup:
+ if (resp != NULL) {
+ OM_uint32 tmpMajor;
+ gss_buffer_desc respBuf;
+
- assert(outputToken->value != NULL);
+ + GSSEAP_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;
+ *minor = tmpMinor;
+ }
+
+ *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
+ }
+
+ wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0);
+ peerConfigFree(&tmpMinor, ctx);
+
+ return major;
+}
+
+static OM_uint32
+eapGssSmInitGssFlags(OM_uint32 *minor,
+ gss_cred_id_t cred GSSEAP_UNUSED,
+ gss_ctx_id_t ctx,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_buffer_t inputToken GSSEAP_UNUSED,
+ gss_buffer_t outputToken,
+ OM_uint32 *smFlags GSSEAP_UNUSED)
+{
+ unsigned char wireFlags[4];
+ gss_buffer_desc flagsBuf;
+
+ store_uint32_be(ctx->gssFlags & GSSEAP_WIRE_FLAGS_MASK, wireFlags);
+
+ flagsBuf.length = sizeof(wireFlags);
+ flagsBuf.value = wireFlags;
+
+ return duplicateBuffer(minor, &flagsBuf, outputToken);
+}
+
+static OM_uint32
+eapGssSmInitGssChannelBindings(OM_uint32 *minor,
+ gss_cred_id_t cred GSSEAP_UNUSED,
+ gss_ctx_id_t ctx,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings,
+ gss_buffer_t inputToken GSSEAP_UNUSED,
+ gss_buffer_t outputToken,
+ OM_uint32 *smFlags)
+{
+ OM_uint32 major;
+ gss_buffer_desc buffer = GSS_C_EMPTY_BUFFER;
+
+ if (chanBindings != GSS_C_NO_CHANNEL_BINDINGS)
+ buffer = chanBindings->application_data;
+
+ major = gssEapWrap(minor, ctx, TRUE, GSS_C_QOP_DEFAULT,
+ &buffer, NULL, outputToken);
+ if (GSS_ERROR(major))
+ return major;
+
- gss_init_sec_context(OM_uint32 *minor,
+ + GSSEAP_ASSERT(outputToken->value != NULL);
+
+ *minor = 0;
+ *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
+
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+static OM_uint32
+eapGssSmInitInitiatorMIC(OM_uint32 *minor,
+ gss_cred_id_t cred GSSEAP_UNUSED,
+ gss_ctx_id_t ctx,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_buffer_t inputToken GSSEAP_UNUSED,
+ gss_buffer_t outputToken,
+ OM_uint32 *smFlags)
+{
+ OM_uint32 major;
+
+ major = gssEapMakeTokenMIC(minor, ctx, outputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ GSSEAP_SM_TRANSITION_NEXT(ctx);
+
+ *minor = 0;
+ *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
+
+ return GSS_S_CONTINUE_NEEDED;
+}
+
+#ifdef GSSEAP_ENABLE_REAUTH
+static OM_uint32
+eapGssSmInitReauthCreds(OM_uint32 *minor,
+ gss_cred_id_t cred,
+ gss_ctx_id_t ctx,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken GSSEAP_UNUSED,
+ OM_uint32 *smFlags GSSEAP_UNUSED)
+{
+ OM_uint32 major;
+
+ if (ctx->gssFlags & GSS_C_MUTUAL_FLAG) {
+ major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken);
+ if (GSS_ERROR(major))
+ return major;
+ }
+
+ *minor = 0;
+ return GSS_S_CONTINUE_NEEDED;
+}
+#endif /* GSSEAP_ENABLE_REAUTH */
+
+static OM_uint32
+eapGssSmInitAcceptorMIC(OM_uint32 *minor,
+ gss_cred_id_t cred GSSEAP_UNUSED,
+ gss_ctx_id_t ctx,
+ gss_name_t target GSSEAP_UNUSED,
+ gss_OID mech GSSEAP_UNUSED,
+ OM_uint32 reqFlags GSSEAP_UNUSED,
+ OM_uint32 timeReq GSSEAP_UNUSED,
+ gss_channel_bindings_t chanBindings GSSEAP_UNUSED,
+ gss_buffer_t inputToken,
+ gss_buffer_t outputToken GSSEAP_UNUSED,
+ OM_uint32 *smFlags GSSEAP_UNUSED)
+{
+ OM_uint32 major;
+
+ major = gssEapVerifyTokenMIC(minor, ctx, inputToken);
+ if (GSS_ERROR(major))
+ return major;
+
+ GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED);
+
+ *minor = 0;
+
+ return GSS_S_COMPLETE;
+}
+
+static struct gss_eap_sm eapGssInitiatorSm[] = {
+ {
+ ITOK_TYPE_CONTEXT_ERR,
+ ITOK_TYPE_NONE,
+ GSSEAP_STATE_ALL & ~(GSSEAP_STATE_INITIAL),
+ 0,
+ eapGssSmInitError
+ },
+ {
+ ITOK_TYPE_ACCEPTOR_NAME_RESP,
+ ITOK_TYPE_ACCEPTOR_NAME_REQ,
+ GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE,
+ 0,
+ eapGssSmInitAcceptorName
+ },
+#ifdef GSSEAP_DEBUG
+ {
+ ITOK_TYPE_NONE,
+ ITOK_TYPE_VENDOR_INFO,
+ GSSEAP_STATE_INITIAL,
+ 0,
+ eapGssSmInitVendorInfo
+ },
+#endif
+#ifdef GSSEAP_ENABLE_REAUTH
+ {
+ ITOK_TYPE_REAUTH_RESP,
+ ITOK_TYPE_REAUTH_REQ,
+ GSSEAP_STATE_INITIAL | GSSEAP_STATE_REAUTHENTICATE,
+ 0,
+ eapGssSmInitGssReauth
+ },
+#endif
+ {
+ ITOK_TYPE_NONE,
+ ITOK_TYPE_NONE,
+#ifdef GSSEAP_ENABLE_REAUTH
+ GSSEAP_STATE_REAUTHENTICATE |
+#endif
+ GSSEAP_STATE_INITIAL,
+ SM_ITOK_FLAG_REQUIRED,
+ eapGssSmInitIdentity
+ },
+ {
+ ITOK_TYPE_EAP_REQ,
+ ITOK_TYPE_EAP_RESP,
+ GSSEAP_STATE_AUTHENTICATE,
+ SM_ITOK_FLAG_REQUIRED,
+ eapGssSmInitAuthenticate
+ },
+ {
+ ITOK_TYPE_NONE,
+ ITOK_TYPE_GSS_FLAGS,
+ GSSEAP_STATE_INITIATOR_EXTS,
+ 0,
+ eapGssSmInitGssFlags
+ },
+ {
+ ITOK_TYPE_NONE,
+ ITOK_TYPE_GSS_CHANNEL_BINDINGS,
+ GSSEAP_STATE_INITIATOR_EXTS,
+ SM_ITOK_FLAG_REQUIRED,
+ eapGssSmInitGssChannelBindings
+ },
+ {
+ ITOK_TYPE_NONE,
+ ITOK_TYPE_INITIATOR_MIC,
+ GSSEAP_STATE_INITIATOR_EXTS,
+ SM_ITOK_FLAG_REQUIRED,
+ eapGssSmInitInitiatorMIC
+ },
+#ifdef GSSEAP_ENABLE_REAUTH
+ {
+ ITOK_TYPE_REAUTH_CREDS,
+ ITOK_TYPE_NONE,
+ GSSEAP_STATE_ACCEPTOR_EXTS,
+ 0,
+ eapGssSmInitReauthCreds
+ },
+#endif
+ /* other extensions go here */
+ {
+ ITOK_TYPE_ACCEPTOR_MIC,
+ ITOK_TYPE_NONE,
+ GSSEAP_STATE_ACCEPTOR_EXTS,
+ SM_ITOK_FLAG_REQUIRED,
+ eapGssSmInitAcceptorMIC
+ }
+};
+
+OM_uint32
- gss_ctx_id_t *context_handle,
+ +gssEapInitSecContext(OM_uint32 *minor,
+ gss_cred_id_t cred,
- gss_ctx_id_t ctx = *context_handle;
- int initialContextToken = 0;
+ + gss_ctx_id_t ctx,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ OM_uint32 req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID *actual_mech_type,
+ gss_buffer_t output_token,
+ OM_uint32 *ret_flags,
+ OM_uint32 *time_rec)
+{
+ OM_uint32 major, tmpMinor;
- *minor = 0;
-
- output_token->length = 0;
- output_token->value = NULL;
-
- if (ctx == GSS_C_NO_CONTEXT) {
- if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
- *minor = GSSEAP_WRONG_SIZE;
- return GSS_S_DEFECTIVE_TOKEN;
- }
+ + int initialContextToken = (ctx->mechanismUsed == GSS_C_NO_OID);
+
- major = gssEapAllocContext(minor, &ctx);
+ + /*
+ + * XXX is acquiring the credential lock here necessary? The password is
+ + * mutable but the contract could specify that this is not updated whilst
+ + * a context is being initialized.
+ + */
+ + if (cred != GSS_C_NO_CREDENTIAL)
+ + GSSEAP_MUTEX_LOCK(&cred->mutex);
+
- return major;
-
- ctx->flags |= CTX_FLAG_INITIATOR;
- initialContextToken = 1;
-
- *context_handle = ctx;
- }
-
- GSSEAP_MUTEX_LOCK(&ctx->mutex);
-
- if (cred == 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,
- &ctx->defaultCred,
- NULL,
- NULL);
- if (GSS_ERROR(major))
- goto cleanup;
- }
+ + if (ctx->cred == GSS_C_NO_CREDENTIAL) {
+ + major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred);
+ if (GSS_ERROR(major))
- cred = ctx->defaultCred;
+ + goto cleanup;
+
- GSSEAP_MUTEX_LOCK(&cred->mutex);
+ + GSSEAP_ASSERT(ctx->cred != GSS_C_NO_CREDENTIAL);
+ }
+
- if ((cred->flags & CRED_FLAG_INITIATE) == 0) {
- major = GSS_S_NO_CRED;
- *minor = GSSEAP_CRED_USAGE_MISMATCH;
- goto cleanup;
- }
+ + GSSEAP_MUTEX_LOCK(&ctx->cred->mutex);
+
- major = initBegin(minor, cred, ctx, target_name, mech_type,
+ + GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_RESOLVED);
+ + GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_INITIATE);
+
+ if (initialContextToken) {
- assert(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
+ + major = initBegin(minor, ctx, target_name, mech_type,
+ req_flags, time_req, input_chan_bindings);
+ if (GSS_ERROR(major))
+ goto cleanup;
+ }
+
+ major = gssEapSmStep(minor,
+ cred,
+ ctx,
+ target_name,
+ mech_type,
+ req_flags,
+ time_req,
+ input_chan_bindings,
+ input_token,
+ output_token,
+ eapGssInitiatorSm,
+ sizeof(eapGssInitiatorSm) / sizeof(eapGssInitiatorSm[0]));
+ if (GSS_ERROR(major))
+ goto cleanup;
+
+ if (actual_mech_type != NULL) {
+ OM_uint32 tmpMajor;
+
+ tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, actual_mech_type);
+ if (GSS_ERROR(tmpMajor)) {
+ major = tmpMajor;
+ *minor = tmpMinor;
+ goto cleanup;
+ }
+ }
+ if (ret_flags != NULL)
+ *ret_flags = ctx->gssFlags;
+ if (time_rec != NULL)
+ gssEapContextTime(&tmpMinor, ctx, time_rec);
+
+ + GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED);
+
+cleanup:
+ if (cred != GSS_C_NO_CREDENTIAL)
+ GSSEAP_MUTEX_UNLOCK(&cred->mutex);
+ + if (ctx->cred != GSS_C_NO_CREDENTIAL)
+ + GSSEAP_MUTEX_UNLOCK(&ctx->cred->mutex);
+ +
+ + return major;
+ +}
+ +
+ +OM_uint32 GSSAPI_CALLCONV
+ +gss_init_sec_context(OM_uint32 *minor,
+ + gss_cred_id_t cred,
+ + gss_ctx_id_t *context_handle,
+ + gss_name_t target_name,
+ + gss_OID mech_type,
+ + OM_uint32 req_flags,
+ + OM_uint32 time_req,
+ + gss_channel_bindings_t input_chan_bindings,
+ + gss_buffer_t input_token,
+ + gss_OID *actual_mech_type,
+ + gss_buffer_t output_token,
+ + OM_uint32 *ret_flags,
+ + OM_uint32 *time_rec)
+ +{
+ + OM_uint32 major, tmpMinor;
+ + gss_ctx_id_t ctx = *context_handle;
+ +
+ + *minor = 0;
+ +
+ + output_token->length = 0;
+ + output_token->value = NULL;
+ +
+ + if (ctx == GSS_C_NO_CONTEXT) {
+ + if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
+ + *minor = GSSEAP_WRONG_SIZE;
+ + return GSS_S_DEFECTIVE_TOKEN;
+ + }
+ +
+ + major = gssEapAllocContext(minor, &ctx);
+ + if (GSS_ERROR(major))
+ + return major;
+ +
+ + ctx->flags |= CTX_FLAG_INITIATOR;
+ +
+ + *context_handle = ctx;
+ + }
+ +
+ + GSSEAP_MUTEX_LOCK(&ctx->mutex);
+ +
+ + major = gssEapInitSecContext(minor,
+ + cred,
+ + ctx,
+ + target_name,
+ + mech_type,
+ + req_flags,
+ + time_req,
+ + input_chan_bindings,
+ + input_token,
+ + actual_mech_type,
+ + output_token,
+ + ret_flags,
+ + time_rec);
+ +
+ GSSEAP_MUTEX_UNLOCK(&ctx->mutex);
+
+ if (GSS_ERROR(major))
+ gssEapReleaseContext(&tmpMinor, context_handle);
+
+ return major;
+}