Merge remote-tracking branch 'origin/master' into debian
authorSam Hartman <hartmans@painless-security.com>
Mon, 5 Dec 2011 19:09:28 +0000 (14:09 -0500)
committerSam Hartman <hartmans@painless-security.com>
Mon, 5 Dec 2011 19:09:28 +0000 (14:09 -0500)
Conflicts:
.gitmodules
cyrus-sasl
libradsec
mod_auth_kerb
moonshot/.gitignore
moonshot/libeap
moonshot/mech_eap/init_sec_context.c
moonshot/mech_eap/unwrap_iov.c
shibboleth/opensaml2
shibboleth/resolver
shibboleth/sp

1  2  3 
.gitignore
libeap/Makefile.am
mech_eap/display_status.c
mech_eap/init_sec_context.c

diff --cc .gitignore
@@@@ -1,2 -1,14 -1,17 +1,3 @@@@
 - Makefile.in
 - aclocal.m4
  -*.o
  -*.d
  -*~
  -wpa_supplicant/eapol_test
  -wpa_supplicant/preauth_test
  -wpa_supplicant/wpa_cli
  -wpa_supplicant/wpa_passphrase
  -wpa_supplicant/wpa_supplicant
  -wpa_supplicant/wpa_priv
  -wpa_supplicant/wpa_gui/Makefile
  -wpa_supplicant/wpa_gui/wpa_gui
  -wpa_supplicant/wpa_gui-qt4/Makefile
  -wpa_supplicant/wpa_gui-qt4/wpa_gui
  -hostapd/hostapd
  -hostapd/hostapd_cli
  -hostapd/hlr_auc_gw
  -hostapd/nt_password_hash
  +autom4te.cache
-  
 - configure
 - config.*
 - ltmain.sh
 - libtool
 - depcomp
 - m4
 - !m4/minuso.m4
 - build-aux
 - !build-aux/compile
+ +mech_eap.spec
+ +mech_eap*tar*
index b3e8865,163e4ff,0000000..1f4ccd5
mode 100644,100644,000000..100644
--- /dev/null
@@@@ -1,127 -1,211 -1,0 +1,212 @@@@
-  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
index 4b80d17,fc0d1ab,0000000..ef28e76
mode 100644,100644,000000..100644
--- /dev/null
@@@@ -1,189 -1,203 -1,0 +1,205 @@@@
-  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);
+ +}
index af76a4b,e99b479,0000000..f781f3d
mode 100644,100644,000000..100644
--- /dev/null
@@@@ -1,1058 -1,1097 -1,0 +1,1097 @@@@
-      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;
  +}