Merged the hostap_2.6 updates, and the Leap of Faith work, from the hostap_update...
authorDan Breslau <dbreslau@painless-security.com>
Tue, 25 Oct 2016 20:30:32 +0000 (16:30 -0400)
committerDan Breslau <dbreslau@painless-security.com>
Tue, 25 Oct 2016 20:30:32 +0000 (16:30 -0400)
1  2 
libeap/src/eap_peer/eap_ttls.c
mech_eap/gssapiP_eap.h
mech_eap/init_sec_context.c
mech_eap/util.h

@@@ -1,15 -1,9 +1,9 @@@
  /*
   * EAP peer method: EAP-TTLS (RFC 5281)
-  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+  * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
   *
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the GNU General Public License version 2 as
-  * published by the Free Software Foundation.
-  *
-  * Alternatively, this software may be distributed under the terms of BSD
-  * license.
-  *
-  * See README and COPYING for more details.
+  * This software may be distributed under the terms of the BSD license.
+  * See README for more details.
   */
  
  #include "includes.h"
  #include "eap_config.h"
  
  
- /* Maximum supported TTLS version
-  * 0 = RFC 5281
-  * 1 = draft-funk-eap-ttls-v1-00.txt
-  */
- #ifndef EAP_TTLS_VERSION
- #define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
- #endif /* EAP_TTLS_VERSION */
- #define MSCHAPV2_KEY_LEN 16
- #define MSCHAPV2_NT_RESPONSE_LEN 24
+ #define EAP_TTLS_VERSION 0
  
  
  static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
  
  struct eap_ttls_data {
        struct eap_ssl_data ssl;
-       int ssl_initialized;
  
-       int ttls_version, force_ttls_version;
+       int ttls_version;
  
        const struct eap_method *phase2_method;
        void *phase2_priv;
        int phase2_success;
        int phase2_start;
+       EapDecision decision_succ;
  
        enum phase2_types {
                EAP_TTLS_PHASE2_EAP,
        int resuming; /* starting a resumed session */
        int reauth; /* reauthentication */
        u8 *key_data;
+       u8 *session_id;
+       size_t id_len;
  
        struct wpabuf *pending_phase2_req;
+       struct wpabuf *pending_resp;
        int chbind_req_sent; /* channel binding request was sent */
        int done_butfor_cb; /*we turned METHOD_DONE into METHOD_MAY_CONT to receive cb*/
-   EapDecision cbDecision;
+       EapDecision cbDecision;
  #ifdef EAP_TNC
        int ready_for_tnc;
        int tnc_started;
@@@ -105,46 -92,75 +92,75 @@@ static void * eap_ttls_init(struct eap_
  {
        struct eap_ttls_data *data;
        struct eap_peer_config *config = eap_get_config(sm);
+       int selected_non_eap;
        char *selected;
  
        data = os_zalloc(sizeof(*data));
        if (data == NULL)
                return NULL;
        data->ttls_version = EAP_TTLS_VERSION;
-       data->force_ttls_version = -1;
        selected = "EAP";
+       selected_non_eap = 0;
        data->phase2_type = EAP_TTLS_PHASE2_EAP;
  
- #if EAP_TTLS_VERSION > 0
-       if (config && config->phase1) {
-               const char *pos = os_strstr(config->phase1, "ttlsver=");
-               if (pos) {
-                       data->force_ttls_version = atoi(pos + 8);
-                       data->ttls_version = data->force_ttls_version;
-                       wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version "
-                                  "%d", data->force_ttls_version);
+       /*
+        * Either one auth= type or one or more autheap= methods can be
+        * specified.
+        */
+       if (config && config->phase2) {
+               const char *token, *last = NULL;
+               while ((token = cstr_token(config->phase2, " \t", &last))) {
+                       if (os_strncmp(token, "auth=", 5) != 0)
+                               continue;
+                       token += 5;
+                       if (last - token == 8 &&
+                           os_strncmp(token, "MSCHAPV2", 8) == 0) {
+                               selected = "MSCHAPV2";
+                               data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
+                       } else if (last - token == 6 &&
+                                  os_strncmp(token, "MSCHAP", 6) == 0) {
+                               selected = "MSCHAP";
+                               data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
+                       } else if (last - token == 3 &&
+                                  os_strncmp(token, "PAP", 3) == 0) {
+                               selected = "PAP";
+                               data->phase2_type = EAP_TTLS_PHASE2_PAP;
+                       } else if (last - token == 4 &&
+                                  os_strncmp(token, "CHAP", 4) == 0) {
+                               selected = "CHAP";
+                               data->phase2_type = EAP_TTLS_PHASE2_CHAP;
+                       } else {
+                               wpa_printf(MSG_ERROR,
+                                          "EAP-TTLS: Unsupported Phase2 type '%s'",
+                                          token);
+                               eap_ttls_deinit(sm, data);
+                               return NULL;
+                       }
+                       if (selected_non_eap) {
+                               wpa_printf(MSG_ERROR,
+                                          "EAP-TTLS: Only one Phase2 type can be specified");
+                               eap_ttls_deinit(sm, data);
+                               return NULL;
+                       }
+                       selected_non_eap = 1;
                }
-       }
- #endif /* EAP_TTLS_VERSION */
  
-       if (config && config->phase2) {
                if (os_strstr(config->phase2, "autheap=")) {
+                       if (selected_non_eap) {
+                               wpa_printf(MSG_ERROR,
+                                          "EAP-TTLS: Both auth= and autheap= params cannot be specified");
+                               eap_ttls_deinit(sm, data);
+                               return NULL;
+                       }
                        selected = "EAP";
                        data->phase2_type = EAP_TTLS_PHASE2_EAP;
-               } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) {
-                       selected = "MSCHAPV2";
-                       data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
-               } else if (os_strstr(config->phase2, "auth=MSCHAP")) {
-                       selected = "MSCHAP";
-                       data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
-               } else if (os_strstr(config->phase2, "auth=PAP")) {
-                       selected = "PAP";
-                       data->phase2_type = EAP_TTLS_PHASE2_PAP;
-               } else if (os_strstr(config->phase2, "auth=CHAP")) {
-                       selected = "CHAP";
-                       data->phase2_type = EAP_TTLS_PHASE2_CHAP;
                }
        }
        wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
  
        if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
                data->phase2_eap_type.method = EAP_TYPE_NONE;
        }
  
- #if EAP_TTLS_VERSION > 0
-       if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
-           data->ttls_version > 0) {
-               if (data->force_ttls_version > 0) {
-                       wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
-                                  "TLS library does not support TLS/IA.",
-                                  data->force_ttls_version);
-                       eap_ttls_deinit(sm, data);
-                       return NULL;
-               }
-               data->ttls_version = 0;
+       if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) {
+               wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
+               eap_ttls_deinit(sm, data);
+               return NULL;
        }
- #endif /* EAP_TTLS_VERSION */
  
        return data;
  }
@@@ -189,6 -197,15 +197,15 @@@ static void eap_ttls_phase2_eap_deinit(
  }
  
  
+ static void eap_ttls_free_key(struct eap_ttls_data *data)
+ {
+       if (data->key_data) {
+               bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+               data->key_data = NULL;
+       }
+ }
  static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
  {
        struct eap_ttls_data *data = priv;
                return;
        eap_ttls_phase2_eap_deinit(sm, data);
        os_free(data->phase2_eap_types);
-       if (data->ssl_initialized)
-               eap_peer_tls_ssl_deinit(sm, &data->ssl);
-       os_free(data->key_data);
+       eap_peer_tls_ssl_deinit(sm, &data->ssl);
+       eap_ttls_free_key(data);
+       os_free(data->session_id);
        wpabuf_free(data->pending_phase2_req);
+       wpabuf_free(data->pending_resp);
        os_free(data);
  }
  
@@@ -222,7 -240,8 +240,8 @@@ static u8 * eap_ttls_avp_hdr(u8 *avphdr
        }
  
        avp->avp_code = host_to_be32(avp_code);
-       avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
+       avp->avp_length = host_to_be32(((u32) flags << 24) |
+                                      (u32) (hdrlen + len));
  
        return avphdr + hdrlen;
  }
@@@ -308,46 -327,14 +327,14 @@@ static int eap_ttls_avp_radius_vsa_enca
        return 0;
  }
  
- #if EAP_TTLS_VERSION > 0
- static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
-                                           struct eap_ttls_data *data,
-                                           const u8 *key, size_t key_len)
- {
-       u8 *buf;
-       size_t buf_len;
-       int ret;
-       if (key) {
-               buf_len = 2 + key_len;
-               buf = os_malloc(buf_len);
-               if (buf == NULL)
-                       return -1;
-               WPA_PUT_BE16(buf, key_len);
-               os_memcpy(buf + 2, key, key_len);
-       } else {
-               buf = NULL;
-               buf_len = 0;
-       }
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
-                       "secret permutation", buf, buf_len);
-       ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
-                                                    data->ssl.conn,
-                                                    buf, buf_len);
-       os_free(buf);
-       return ret;
- }
- #endif /* EAP_TTLS_VERSION */
  static int eap_ttls_v0_derive_key(struct eap_sm *sm,
                                  struct eap_ttls_data *data)
  {
-       os_free(data->key_data);
+       eap_ttls_free_key(data);
        data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
                                                 "ttls keying material",
-                                                EAP_TLS_KEY_LEN);
+                                                EAP_TLS_KEY_LEN +
+                                                EAP_EMSK_LEN);
        if (!data->key_data) {
                wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key");
                return -1;
  
        wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
                        data->key_data, EAP_TLS_KEY_LEN);
-       return 0;
- }
- #if EAP_TTLS_VERSION > 0
- static int eap_ttls_v1_derive_key(struct eap_sm *sm,
-                                 struct eap_ttls_data *data)
- {
-       struct tls_keys keys;
-       u8 *rnd;
-       os_free(data->key_data);
-       data->key_data = NULL;
-       os_memset(&keys, 0, sizeof(keys));
-       if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-           keys.client_random == NULL || keys.server_random == NULL ||
-           keys.inner_secret == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-                          "client random, or server random to derive keying "
-                          "material");
-               return -1;
-       }
-       rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-       data->key_data = os_malloc(EAP_TLS_KEY_LEN);
-       if (rnd == NULL || data->key_data == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
-               os_free(rnd);
-               os_free(data->key_data);
-               data->key_data = NULL;
-               return -1;
-       }
-       os_memcpy(rnd, keys.client_random, keys.client_random_len);
-       os_memcpy(rnd + keys.client_random_len, keys.server_random,
-                 keys.server_random_len);
-       if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-                   "ttls v1 keying material", rnd, keys.client_random_len +
-                   keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) {
-               wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-               os_free(rnd);
-               os_free(data->key_data);
-               data->key_data = NULL;
-               return -1;
+       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
+                       data->key_data + EAP_TLS_KEY_LEN,
+                       EAP_EMSK_LEN);
+       os_free(data->session_id);
+       data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
+                                                         EAP_TYPE_TTLS,
+                                                         &data->id_len);
+       if (data->session_id) {
+               wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id",
+                           data->session_id, data->id_len);
+       } else {
+               wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id");
        }
  
-       wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
-                   rnd, keys.client_random_len + keys.server_random_len);
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
-                       keys.inner_secret, keys.inner_secret_len);
-       os_free(rnd);
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
-                       data->key_data, EAP_TLS_KEY_LEN);
        return 0;
  }
- #endif /* EAP_TTLS_VERSION */
  
  
+ #ifndef CONFIG_FIPS
  static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
                                        struct eap_ttls_data *data, size_t len)
  {
- #if EAP_TTLS_VERSION > 0
-       struct tls_keys keys;
-       u8 *challenge, *rnd;
- #endif /* EAP_TTLS_VERSION */
-       if (data->ttls_version == 0) {
-               return eap_peer_tls_derive_key(sm, &data->ssl,
-                                              "ttls challenge", len);
-       }
- #if EAP_TTLS_VERSION > 0
-       os_memset(&keys, 0, sizeof(keys));
-       if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-           keys.client_random == NULL || keys.server_random == NULL ||
-           keys.inner_secret == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-                          "client random, or server random to derive "
-                          "implicit challenge");
-               return NULL;
-       }
-       rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-       challenge = os_malloc(len);
-       if (rnd == NULL || challenge == NULL) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
-                          "challenge derivation");
-               os_free(rnd);
-               os_free(challenge);
-               return NULL;
-       }
-       os_memcpy(rnd, keys.server_random, keys.server_random_len);
-       os_memcpy(rnd + keys.server_random_len, keys.client_random,
-                 keys.client_random_len);
-       if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-                   "inner application challenge", rnd,
-                   keys.client_random_len + keys.server_random_len,
-                   challenge, len)) {
-               wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
-                          "challenge");
-               os_free(rnd);
-               os_free(challenge);
-               return NULL;
-       }
-       os_free(rnd);
-       wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
-                       challenge, len);
-       return challenge;
- #else /* EAP_TTLS_VERSION */
-       return NULL;
- #endif /* EAP_TTLS_VERSION */
- }
- static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm,
-                                        struct eap_ttls_data *data,
-                                        struct eap_method_ret *ret)
- {
- #if EAP_TTLS_VERSION > 0
-       if (data->ttls_version > 0) {
-               const struct eap_method *m = data->phase2_method;
-               void *priv = data->phase2_priv;
-               /* TTLSv1 requires TLS/IA FinalPhaseFinished */
-               if (ret->decision == DECISION_UNCOND_SUCC)
-                       ret->decision = DECISION_COND_SUCC;
-               ret->methodState = METHOD_CONT;
-               if (ret->decision == DECISION_COND_SUCC &&
-                   m->isKeyAvailable && m->getKey &&
-                   m->isKeyAvailable(sm, priv)) {
-                       u8 *key;
-                       size_t key_len;
-                       key = m->getKey(sm, priv, &key_len);
-                       if (key) {
-                               eap_ttls_ia_permute_inner_secret(
-                                       sm, data, key, key_len);
-                               os_free(key);
-                       }
-               }
-       }
- #endif /* EAP_TTLS_VERSION */
+       return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
  }
+ #endif /* CONFIG_FIPS */
  
  
  static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
@@@ -556,7 -413,6 +413,6 @@@ static int eap_ttls_phase2_eap_process(
                ret->methodState = iret.methodState;
                ret->decision = iret.decision;
        }
-       eap_ttlsv1_phase2_eap_finish(sm, data, ret);
  
        return 0;
  }
@@@ -677,31 -533,16 +533,16 @@@ static int eap_ttls_phase2_request_eap(
  }
  
  
- static void eap_ttlsv1_permute_inner(struct eap_sm *sm,
-                                    struct eap_ttls_data *data)
- {
- #if EAP_TTLS_VERSION > 0
-       u8 session_key[2 * MSCHAPV2_KEY_LEN];
-       if (data->ttls_version == 0)
-               return;
-       get_asymetric_start_key(data->master_key, session_key,
-                               MSCHAPV2_KEY_LEN, 0, 0);
-       get_asymetric_start_key(data->master_key,
-                               session_key + MSCHAPV2_KEY_LEN,
-                               MSCHAPV2_KEY_LEN, 1, 0);
-       eap_ttls_ia_permute_inner_secret(sm, data, session_key,
-                                        sizeof(session_key));
- #endif /* EAP_TTLS_VERSION */
- }
  static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
                                            struct eap_ttls_data *data,
                                            struct eap_method_ret *ret,
                                            struct wpabuf **resp)
  {
+ #ifdef CONFIG_FIPS
+       wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build");
+       return -1;
+ #else /* CONFIG_FIPS */
+ #ifdef EAP_MSCHAPv2
        struct wpabuf *msg;
        u8 *buf, *pos, *challenge, *peer_challenge;
        const u8 *identity, *password;
                           "implicit challenge");
                return -1;
        }
-       peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
  
        pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
                               RADIUS_VENDOR_ID_MICROSOFT, 1,
        data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
        *pos++ = data->ident;
        *pos++ = 0; /* Flags */
-       os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+       if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
+               os_free(challenge);
+               wpabuf_free(msg);
+               wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
+                          "random data for peer challenge");
+               return -1;
+       }
+       peer_challenge = pos;
        pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
        os_memset(pos, 0, 8); /* Reserved, must be zero */
        pos += 8;
                                     password_len, pwhash, challenge,
                                     peer_challenge, pos, data->auth_response,
                                     data->master_key)) {
+               os_free(challenge);
                wpabuf_free(msg);
                wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
                           "response");
        }
        data->auth_response_valid = 1;
  
-       eap_ttlsv1_permute_inner(sm, data);
        pos += 24;
        os_free(challenge);
        AVP_PAD(buf, pos);
        wpabuf_put(msg, pos - buf);
        *resp = msg;
  
-       if (sm->workaround && data->ttls_version == 0) {
-               /* At least FreeRADIUS seems to be terminating
-                * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
-                * packet. */
-               wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - "
-                          "allow success without tunneled response");
-               ret->methodState = METHOD_MAY_CONT;
-               ret->decision = DECISION_COND_SUCC;
-       }
        return 0;
+ #else /* EAP_MSCHAPv2 */
+       wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+       return -1;
+ #endif /* EAP_MSCHAPv2 */
+ #endif /* CONFIG_FIPS */
  }
  
  
@@@ -792,6 -633,10 +633,10 @@@ static int eap_ttls_phase2_request_msch
                                          struct eap_method_ret *ret,
                                          struct wpabuf **resp)
  {
+ #ifdef CONFIG_FIPS
+       wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build");
+       return -1;
+ #else /* CONFIG_FIPS */
        struct wpabuf *msg;
        u8 *buf, *pos, *challenge;
        const u8 *identity, *password;
        wpabuf_put(msg, pos - buf);
        *resp = msg;
  
-       if (data->ttls_version > 0) {
-               /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-                * so do not allow connection to be terminated yet. */
-               ret->methodState = METHOD_CONT;
-               ret->decision = DECISION_COND_SUCC;
-       } else {
-               /* EAP-TTLS/MSCHAP does not provide tunneled success
-                * notification, so assume that Phase2 succeeds. */
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_COND_SUCC;
-       }
+       /* EAP-TTLS/MSCHAP does not provide tunneled success
+        * notification, so assume that Phase2 succeeds. */
+       ret->methodState = METHOD_DONE;
+       ret->decision = DECISION_COND_SUCC;
  
        return 0;
+ #endif /* CONFIG_FIPS */
  }
  
  
@@@ -921,17 -760,10 +760,10 @@@ static int eap_ttls_phase2_request_pap(
        wpabuf_put(msg, pos - buf);
        *resp = msg;
  
-       if (data->ttls_version > 0) {
-               /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-                * so do not allow connection to be terminated yet. */
-               ret->methodState = METHOD_CONT;
-               ret->decision = DECISION_COND_SUCC;
-       } else {
-               /* EAP-TTLS/PAP does not provide tunneled success notification,
-                * so assume that Phase2 succeeds. */
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_COND_SUCC;
-       }
+       /* EAP-TTLS/PAP does not provide tunneled success notification,
+        * so assume that Phase2 succeeds. */
+       ret->methodState = METHOD_DONE;
+       ret->decision = DECISION_COND_SUCC;
  
        return 0;
  }
@@@ -942,6 -774,10 +774,10 @@@ static int eap_ttls_phase2_request_chap
                                        struct eap_method_ret *ret,
                                        struct wpabuf **resp)
  {
+ #ifdef CONFIG_FIPS
+       wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build");
+       return -1;
+ #else /* CONFIG_FIPS */
        struct wpabuf *msg;
        u8 *buf, *pos, *challenge;
        const u8 *identity, *password;
        wpabuf_put(msg, pos - buf);
        *resp = msg;
  
-       if (data->ttls_version > 0) {
-               /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-                * so do not allow connection to be terminated yet. */
-               ret->methodState = METHOD_CONT;
-               ret->decision = DECISION_COND_SUCC;
-       } else {
-               /* EAP-TTLS/CHAP does not provide tunneled success
-                * notification, so assume that Phase2 succeeds. */
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_COND_SUCC;
-       }
+       /* EAP-TTLS/CHAP does not provide tunneled success
+        * notification, so assume that Phase2 succeeds. */
+       ret->methodState = METHOD_DONE;
+       ret->decision = DECISION_COND_SUCC;
  
        return 0;
+ #endif /* CONFIG_FIPS */
  }
  
  
@@@ -1089,36 -919,6 +919,6 @@@ static int eap_ttls_phase2_request(stru
  }
  
  
- #if EAP_TTLS_VERSION > 0
- static struct wpabuf * eap_ttls_build_phase_finished(
-       struct eap_sm *sm, struct eap_ttls_data *data, int id, int final)
- {
-       struct wpabuf *req, *buf;
-       buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
-                                                   data->ssl.conn,
-                                                   final);
-       if (buf == NULL)
-               return NULL;
-       req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS,
-                           1 + wpabuf_len(buf),
-                           EAP_CODE_RESPONSE, id);
-       if (req == NULL) {
-               wpabuf_free(buf);
-               return NULL;
-       }
-       wpabuf_put_u8(req, data->ttls_version);
-       wpabuf_put_buf(req, buf);
-       wpabuf_free(buf);
-       eap_update_len(req);
-       return req;
- }
- #endif /* EAP_TTLS_VERSION */
  struct ttls_parse_avp {
        u8 *mschapv2;
        u8 *eapdata;
@@@ -1359,6 -1159,7 +1159,7 @@@ static int eap_ttls_encrypt_response(st
                                 resp, out_data)) {
                wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
                           "frame");
+               wpabuf_free(resp);
                return -1;
        }
        wpabuf_free(resp);
@@@ -1370,7 -1171,7 +1171,7 @@@ static int eap_ttls_add_chbind_request(
                                       struct eap_ttls_data *data,
                                       struct wpabuf **resp)
  {
 -      struct wpabuf *chbind_req, *res;
 +      struct wpabuf *chbind_req;
        int length = 1, i;
        struct eap_peer_config *config = eap_get_config(sm);
  
@@@ -1533,6 -1334,7 +1334,7 @@@ static int eap_ttls_process_phase2_msch
                                            struct eap_method_ret *ret,
                                            struct ttls_parse_avp *parse)
  {
+ #ifdef EAP_MSCHAPv2
        if (parse->mschapv2_error) {
                wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received "
                           "MS-CHAP-Error - failed");
  
        wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
                   "authentication succeeded");
-       if (data->ttls_version > 0) {
-               /*
-                * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report
-                * success, so do not allow connection to be terminated
-                * yet.
-                */
-               ret->methodState = METHOD_CONT;
-               ret->decision = DECISION_COND_SUCC;
-       } else {
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_UNCOND_SUCC;
-               data->phase2_success = 1;
-       }
+       ret->methodState = METHOD_DONE;
+       ret->decision = DECISION_UNCOND_SUCC;
+       data->phase2_success = 1;
  
        /*
         * Reply with empty data; authentication server will reply
         * with EAP-Success after this.
         */
        return 1;
+ #else /* EAP_MSCHAPv2 */
+       wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+       return -1;
+ #endif /* EAP_MSCHAPv2 */
  }
  
  
@@@ -1728,24 -1524,6 +1524,6 @@@ static int eap_ttls_process_decrypted(s
  }
  
  
- #if EAP_TTLS_VERSION > 0
- static void eap_ttls_final_phase_finished(struct eap_sm *sm,
-                                         struct eap_ttls_data *data,
-                                         struct eap_method_ret *ret,
-                                         u8 identifier,
-                                         struct wpabuf **out_data)
- {
-       wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received");
-       wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded");
-       ret->methodState = METHOD_DONE;
-       ret->decision = DECISION_UNCOND_SUCC;
-       data->phase2_success = 1;
-       *out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1);
-       eap_ttls_v1_derive_key(sm, data);
- }
- #endif /* EAP_TTLS_VERSION */
  static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
                                              struct eap_ttls_data *data,
                                              struct eap_method_ret *ret,
                           "processing failed");
                retval = -1;
        } else {
+               struct eap_peer_config *config = eap_get_config(sm);
+               if (resp == NULL &&
+                   (config->pending_req_identity ||
+                    config->pending_req_password ||
+                    config->pending_req_otp ||
+                    config->pending_req_new_password)) {
+                       /*
+                        * Use empty buffer to force implicit request
+                        * processing when EAP request is re-processed after
+                        * user input.
+                        */
+                       wpabuf_free(data->pending_phase2_req);
+                       data->pending_phase2_req = wpabuf_alloc(0);
+               }
                retval = eap_ttls_encrypt_response(sm, data, resp, identifier,
                                                   out_data);
        }
@@@ -1862,17 -1655,6 +1655,6 @@@ static int eap_ttls_decrypt(struct eap_
        if (retval)
                goto done;
  
- #if EAP_TTLS_VERSION > 0
-       if (data->ttls_version > 0 &&
-           (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) &&
-           tls_connection_ia_final_phase_finished(sm->ssl_ctx,
-                                                  data->ssl.conn)) {
-               eap_ttls_final_phase_finished(sm, data, ret, identifier,
-                                             out_data);
-               goto done;
-       }
- #endif /* EAP_TTLS_VERSION */
  continue_req:
        data->phase2_start = 0;
  
@@@ -1897,58 -1679,59 +1679,59 @@@ done
  }
  
  
- static int eap_ttls_process_start(struct eap_sm *sm,
-                                 struct eap_ttls_data *data, u8 flags,
-                                 struct eap_method_ret *ret)
- {
-       struct eap_peer_config *config = eap_get_config(sm);
-       wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)",
-                  flags & EAP_TLS_VERSION_MASK, data->ttls_version);
- #if EAP_TTLS_VERSION > 0
-       if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version)
-               data->ttls_version = flags & EAP_TLS_VERSION_MASK;
-       if (data->force_ttls_version >= 0 &&
-           data->force_ttls_version != data->ttls_version) {
-               wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select "
-                          "forced TTLS version %d",
-                          data->force_ttls_version);
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_FAIL;
-               ret->allowNotifications = FALSE;
-               return -1;
-       }
-       wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d",
-                  data->ttls_version);
-       if (data->ttls_version > 0)
-               data->ssl.tls_ia = 1;
- #endif /* EAP_TTLS_VERSION */
-       if (!data->ssl_initialized &&
-           eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
-               wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
-               return -1;
-       }
-       data->ssl_initialized = 1;
-       wpa_printf(MSG_DEBUG, "EAP-TTLS: Start");
-       return 0;
- }
  static int eap_ttls_process_handshake(struct eap_sm *sm,
                                      struct eap_ttls_data *data,
                                      struct eap_method_ret *ret,
                                      u8 identifier,
-                                     const u8 *in_data, size_t in_len,
+                                     const struct wpabuf *in_data,
                                      struct wpabuf **out_data)
  {
        int res;
  
+       if (sm->waiting_ext_cert_check && data->pending_resp) {
+               struct eap_peer_config *config = eap_get_config(sm);
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TTLS: External certificate check succeeded - continue handshake");
+                       *out_data = data->pending_resp;
+                       data->pending_resp = NULL;
+                       sm->waiting_ext_cert_check = 0;
+                       return 0;
+               }
+               if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
+                       wpa_printf(MSG_DEBUG,
+                                  "EAP-TTLS: External certificate check failed - force authentication failure");
+                       ret->methodState = METHOD_DONE;
+                       ret->decision = DECISION_FAIL;
+                       sm->waiting_ext_cert_check = 0;
+                       return 0;
+               }
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TTLS: Continuing to wait external server certificate validation");
+               return 0;
+       }
        res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
                                          data->ttls_version, identifier,
-                                         in_data, in_len, out_data);
+                                         in_data, out_data);
+       if (res < 0) {
+               wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed");
+               ret->methodState = METHOD_DONE;
+               ret->decision = DECISION_FAIL;
+               return -1;
+       }
+       if (sm->waiting_ext_cert_check) {
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TTLS: Waiting external server certificate validation");
+               wpabuf_free(data->pending_resp);
+               data->pending_resp = *out_data;
+               *out_data = NULL;
+               return 0;
+       }
  
        if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
                wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
                        ret->methodState = METHOD_MAY_CONT;
                }
                data->phase2_start = 1;
-               if (data->ttls_version == 0)
-                       eap_ttls_v0_derive_key(sm, data);
+               eap_ttls_v0_derive_key(sm, data);
  
                if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
                        if (eap_ttls_decrypt(sm, data, ret, identifier,
        }
  
        if (res == 2) {
-               struct wpabuf msg;
                /*
                 * Application data included in the handshake message.
                 */
                wpabuf_free(data->pending_phase2_req);
                data->pending_phase2_req = *out_data;
                *out_data = NULL;
-               wpabuf_set(&msg, in_data, in_len);
-               res = eap_ttls_decrypt(sm, data, ret, identifier, &msg,
+               res = eap_ttls_decrypt(sm, data, ret, identifier, in_data,
                                       out_data);
        }
  
@@@ -1996,13 -1776,14 +1776,14 @@@ static void eap_ttls_check_auth_status(
                                       struct eap_ttls_data *data,
                                       struct eap_method_ret *ret)
  {
-       if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) {
+       if (ret->methodState == METHOD_DONE) {
                ret->allowNotifications = FALSE;
                if (ret->decision == DECISION_UNCOND_SUCC ||
                    ret->decision == DECISION_COND_SUCC) {
                        wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
                                   "completed successfully");
                        data->phase2_success = 1;
+                       data->decision_succ = ret->decision;
  #ifdef EAP_TNC
                        if (!data->ready_for_tnc && !data->tnc_started) {
                                /*
                        }
  #endif /* EAP_TNC */
                }
-       } else if (data->ttls_version == 0 &&
-                  ret->methodState == METHOD_MAY_CONT &&
+       } else if (ret->methodState == METHOD_MAY_CONT &&
                   (ret->decision == DECISION_UNCOND_SUCC ||
                    ret->decision == DECISION_COND_SUCC)) {
                        wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
                                   "completed successfully (MAY_CONT)");
                        data->phase2_success = 1;
+                       data->decision_succ = ret->decision;
+       } else if (data->decision_succ != DECISION_FAIL &&
+                  data->phase2_success &&
+                  !data->ssl.tls_out) {
+               /*
+                * This is needed to cover the case where the final Phase 2
+                * message gets fragmented since fragmentation clears
+                * decision back to FAIL.
+                */
+               wpa_printf(MSG_DEBUG,
+                          "EAP-TTLS: Restore success decision after fragmented frame sent completely");
+               ret->decision = data->decision_succ;
        }
  }
  
@@@ -2035,6 -1827,7 +1827,7 @@@ static struct wpabuf * eap_ttls_process
        struct wpabuf *resp;
        const u8 *pos;
        struct eap_ttls_data *data = priv;
+       struct wpabuf msg;
  
        pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret,
                                        reqData, &left, &flags);
        id = eap_get_id(reqData);
  
        if (flags & EAP_TLS_FLAGS_START) {
-               if (eap_ttls_process_start(sm, data, flags, ret) < 0)
-                       return NULL;
+               wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
+                          "ver=%d)", flags & EAP_TLS_VERSION_MASK,
+                          data->ttls_version);
  
                /* RFC 5281, Ch. 9.2:
                 * "This packet MAY contain additional information in the form
                 * For now, ignore any potential extra data.
                 */
                left = 0;
-       } else if (!data->ssl_initialized) {
-               wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not "
-                          "include Start flag");
-               ret->methodState = METHOD_DONE;
-               ret->decision = DECISION_FAIL;
-               ret->allowNotifications = FALSE;
-               return NULL;
        }
  
+       wpabuf_set(&msg, pos, left);
        resp = NULL;
        if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
            !data->resuming) {
-               struct wpabuf msg;
-               wpabuf_set(&msg, pos, left);
                res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp);
        } else {
                res = eap_ttls_process_handshake(sm, data, ret, id,
-                                                pos, left, &resp);
+                                                &msg, &resp);
        }
  
        eap_ttls_check_auth_status(sm, data, ret);
@@@ -2098,6 -1885,9 +1885,9 @@@ static void eap_ttls_deinit_for_reauth(
        struct eap_ttls_data *data = priv;
        wpabuf_free(data->pending_phase2_req);
        data->pending_phase2_req = NULL;
+       wpabuf_free(data->pending_resp);
+       data->pending_resp = NULL;
+       data->decision_succ = DECISION_FAIL;
  #ifdef EAP_TNC
        data->ready_for_tnc = 0;
        data->tnc_started = 0;
  static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
  {
        struct eap_ttls_data *data = priv;
-       os_free(data->key_data);
-       data->key_data = NULL;
+       eap_ttls_free_key(data);
+       os_free(data->session_id);
+       data->session_id = NULL;
        if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
                os_free(data);
                return NULL;
@@@ -2135,7 -1926,7 +1926,7 @@@ static int eap_ttls_get_status(struct e
        ret = os_snprintf(buf + len, buflen - len,
                          "EAP-TTLSv%d Phase2 method=",
                          data->ttls_version);
-       if (ret < 0 || (size_t) ret >= buflen - len)
+       if (os_snprintf_error(buflen - len, ret))
                return len;
        len += ret;
        switch (data->phase2_type) {
                ret = 0;
                break;
        }
-       if (ret < 0 || (size_t) ret >= buflen - len)
+       if (os_snprintf_error(buflen - len, ret))
                return len;
        len += ret;
  
@@@ -2194,10 -1985,47 +1985,47 @@@ static u8 * eap_ttls_getKey(struct eap_
  }
  
  
+ static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+ {
+       struct eap_ttls_data *data = priv;
+       u8 *id;
+       if (data->session_id == NULL || !data->phase2_success)
+               return NULL;
+       id = os_malloc(data->id_len);
+       if (id == NULL)
+               return NULL;
+       *len = data->id_len;
+       os_memcpy(id, data->session_id, data->id_len);
+       return id;
+ }
+ static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+ {
+       struct eap_ttls_data *data = priv;
+       u8 *key;
+       if (data->key_data == NULL)
+               return NULL;
+       key = os_malloc(EAP_EMSK_LEN);
+       if (key == NULL)
+               return NULL;
+       *len = EAP_EMSK_LEN;
+       os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+       return key;
+ }
  int eap_peer_ttls_register(void)
  {
        struct eap_method *eap;
-       int ret;
  
        eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
                                    EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
        eap->process = eap_ttls_process;
        eap->isKeyAvailable = eap_ttls_isKeyAvailable;
        eap->getKey = eap_ttls_getKey;
+       eap->getSessionId = eap_ttls_get_session_id;
        eap->get_status = eap_ttls_get_status;
        eap->has_reauth_data = eap_ttls_has_reauth_data;
        eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
        eap->init_for_reauth = eap_ttls_init_for_reauth;
+       eap->get_emsk = eap_ttls_get_emsk;
  
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return ret;
+       return eap_peer_method_register(eap);
  }
diff --combined mech_eap/gssapiP_eap.h
@@@ -77,13 -77,8 +77,13 @@@ typedef struct gss_any *gss_any_t
  typedef const gss_OID_desc *gss_const_OID;
  #endif
  
 +#ifndef GSS_IOV_BUFFER_TYPE_MIC_TOKEN
 +#define GSS_IOV_BUFFER_TYPE_MIC_TOKEN      12  /* MIC token destination */
 +#endif
 +
  /* Kerberos headers */
  #include <krb5.h>
 +#include <com_err.h>
  
  /* EAP headers */
  #include <includes.h>
@@@ -188,6 -183,7 +188,7 @@@ struct gss_cred_id_struc
  #define CTX_FLAG_EAP_ALT_ACCEPT             0x00800000
  #define CTX_FLAG_EAP_ALT_REJECT             0x01000000
  #define CTX_FLAG_EAP_CHBIND_ACCEPT          0x02000000
+ #define CTX_FLAG_EAP_TRIGGER_START          0x04000000
  #define CTX_FLAG_EAP_MASK                   0xFFFF0000
  
  #define CONFIG_BLOB_CLIENT_CERT             0
@@@ -283,7 -279,7 +284,7 @@@ OM_uint3
  gssEapInitSecContext(OM_uint32 *minor,
                       gss_cred_id_t cred,
                       gss_ctx_id_t ctx,
 -                     gss_name_t target_name,
 +                     gss_const_name_t target_name,
                       gss_OID mech_type,
                       OM_uint32 req_flags,
                       OM_uint32 time_req,
@@@ -315,14 -311,12 +316,14 @@@ gssEapUnwrapOrVerifyMIC(OM_uint32 *mino
  
  OM_uint32
  gssEapWrapIovLength(OM_uint32 *minor,
 -                    gss_ctx_id_t ctx,
 +                    gss_const_ctx_id_t ctx,
                      int conf_req_flag,
                      gss_qop_t qop_req,
                      int *conf_state,
                      gss_iov_buffer_desc *iov,
 -                    int iov_count);
 +                    int iov_count,
 +                    enum gss_eap_token_type tokType);
 +
  OM_uint32
  gssEapWrap(OM_uint32 *minor,
             gss_ctx_id_t ctx,
             gss_buffer_t output_message_buffer);
  
  unsigned char
 -rfc4121Flags(gss_ctx_id_t ctx, int receiving);
 +rfc4121Flags(gss_const_ctx_id_t ctx, int receiving);
  
  /* display_status.c */
  void
@@@ -386,7 -380,7 +387,7 @@@ gssEapImportContext(OM_uint32 *minor
  /* pseudo_random.c */
  OM_uint32
  gssEapPseudoRandom(OM_uint32 *minor,
 -                   gss_ctx_id_t ctx,
 +                   gss_const_ctx_id_t ctx,
                     int prf_key,
                     const gss_buffer_t prf_in,
                     gss_buffer_t prf_out);
@@@ -414,42 -408,14 +415,42 @@@ gssEapInitiatorInit(OM_uint32 *minor)
  void
  gssEapFinalize(void);
  
 -  /* Debugging and tracing*/
 -  #define gssEapTrace(_fmt, ...) wpa_printf(MSG_INFO, _fmt, __VA_ARGS__);
 -
 -void
 -gssEapTraceStatus(const char *function, OM_uint32 major, OM_uint32 minor);
 +/* Debugging and tracing */
  
 +static inline void
 +gssEapTraceStatus(const char *function,
 +                  OM_uint32 major,
 +                  OM_uint32 minor)
 +{
 +    gss_buffer_desc gssErrorCodeBuf = GSS_C_EMPTY_BUFFER;
 +    gss_buffer_desc gssMechBuf = GSS_C_EMPTY_BUFFER;
 +    OM_uint32 tmpMajor, tmpMinor;
 +    OM_uint32 messageCtx = 0;
 +
 +    tmpMajor = gss_display_status(&tmpMinor, major,
 +                                  GSS_C_GSS_CODE, GSS_C_NO_OID,
 +                                  &messageCtx, &gssErrorCodeBuf);
 +    if (!GSS_ERROR(tmpMajor)) {
 +        if (minor == 0)
 +            tmpMajor = makeStringBuffer(&tmpMinor, "no minor", &gssMechBuf);
 +        else
 +            tmpMajor = gssEapDisplayStatus(&tmpMinor, minor, &gssMechBuf);
 +    }
 +
 +    if (!GSS_ERROR(tmpMajor))
 +      wpa_printf(MSG_INFO, "%s: %.*s/%.*s",
 +                 function,
 +                   (int)gssErrorCodeBuf.length, (char *)gssErrorCodeBuf.value,
 +                 (int)gssMechBuf.length, (char *)gssMechBuf.value);
 +    else
 +        wpa_printf(MSG_INFO, "%s: %u/%u",
 +                  function, major, minor);
 +
 +    gss_release_buffer(&tmpMinor, &gssErrorCodeBuf);
 +    gss_release_buffer(&tmpMinor, &gssMechBuf);
 +}
  
 -  /*If built as a library on Linux, don't respect environment when set*uid*/
 +/* If built as a library on Linux, don't respect environment when set*uid */
  #ifdef HAVE_SECURE_GETENV
  #define getenv secure_getenv
  #endif
@@@ -39,6 -39,8 +39,8 @@@
  #include "radius/radius.h"
  #include "util_radius.h"
  #include "utils/radius_utils.h"
+ #include "openssl/err.h"
+ #include "libmoonshot.h"
  
  /* methods allowed for phase1 authentication*/
  static const struct eap_method_type allowed_eap_method_types[] = {
@@@ -78,6 -80,9 +80,9 @@@ policyVariableToFlag(enum eapol_bool_va
      case EAPOL_altReject:
          flag = CTX_FLAG_EAP_ALT_REJECT;
          break;
+     case EAPOL_eapTriggerStart:
+         flag = CTX_FLAG_EAP_TRIGGER_START;
+         break;
      }
  
      return flag;
@@@ -198,6 -203,7 +203,7 @@@ peerNotifyPending(void *ctx GSSEAP_UNUS
  {
  }
  
  static struct eapol_callbacks gssEapPolicyCallbacks = {
      peerGetConfig,
      peerGetBool,
      peerSetConfigBlob,
      peerGetConfigBlob,
      peerNotifyPending,
+     NULL,  /* eap_param_needed */
+     NULL   /* eap_notify_cert */
  };
  
  
@@@ -353,6 -361,91 +361,91 @@@ peerProcessChbindResponse(void *context
      } /* else log failures? */
  }
  
+ static int cert_to_byte_array(X509 *cert, unsigned char **bytes)
+ {
+       unsigned char *buf;
+     unsigned char *p;
+       int len = i2d_X509(cert, NULL);
+       if (len <= 0) {
+               return -1;
+     }
+       p = buf = GSSEAP_MALLOC(len);
+       if (buf == NULL) {
+               return -1;
+     }
+       i2d_X509(cert, &buf);
+     *bytes = p;
+     return len;
+ }
+ static int sha256(unsigned char *bytes, int len, unsigned char *hash)
+ {
+       EVP_MD_CTX ctx;
+       unsigned int hash_len;
+       EVP_MD_CTX_init(&ctx);
+       if (!EVP_DigestInit_ex(&ctx, EVP_sha256(), NULL)) {
+               printf("sha256(init_sec_context.c): EVP_DigestInit_ex failed: %s",
+                          ERR_error_string(ERR_get_error(), NULL));
+               return -1;
+       }
+     if (!EVP_DigestUpdate(&ctx, bytes, len)) {
+               printf("sha256(init_sec_context.c): EVP_DigestUpdate failed: %s",
+                                  ERR_error_string(ERR_get_error(), NULL));
+         return -1;
+       }
+       if (!EVP_DigestFinal(&ctx, hash, &hash_len)) {
+               printf("sha256(init_sec_context.c): EVP_DigestFinal failed: %s",
+                                  ERR_error_string(ERR_get_error(), NULL));
+               return -1;
+       }
+       return hash_len;
+ }
+ static int peerValidateServerCert(int ok_so_far, X509* cert, void *ca_ctx)
+ {
+     char                 *realm = NULL;
+     unsigned char        *cert_bytes = NULL;
+     int                   cert_len;
+     unsigned char         hash[32];
+     int                   hash_len;
+     MoonshotError        *error = NULL;
+     struct eap_peer_config *eap_config = (struct eap_peer_config *) ca_ctx;
+     char *identity = strdup((const char *) eap_config->identity);
+     // Truncate the identity to just the username; make a separate string for the realm.
+     char* at = strchr(identity, '@');
+     if (at != NULL) {
+         realm = strdup(at + 1);
+         *at = '\0';
+     }
+     
+     cert_len = cert_to_byte_array(cert, &cert_bytes);
+     hash_len = sha256(cert_bytes, cert_len, hash);
+     GSSEAP_FREE(cert_bytes);
+     
+     if (hash_len != 32) {
+         fprintf(stderr, "peerValidateServerCert: Error: hash_len=%d, not 32!\n", hash_len);
+         return FALSE;
+     }
+     ok_so_far = moonshot_confirm_ca_certificate(identity, realm, hash, 32, &error);
+     free(identity);
+     if (realm != NULL) {
+         free(realm);
+     }
+     
+     wpa_printf(MSG_INFO, "peerValidateServerCert: Returning %d\n", ok_so_far);
+     return ok_so_far;
+ }
  static OM_uint32
  peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
  {
              eapPeerConfig->client_cert = (unsigned char *)cred->clientCertificate.value;
              eapPeerConfig->private_key = (unsigned char *)cred->privateKey.value;
          }
-         eapPeerConfig->private_key_passwd = (unsigned char *)cred->password.value;
+         eapPeerConfig->private_key_passwd = (char *)cred->password.value;
      }
  
+     eapPeerConfig->server_cert_cb = peerValidateServerCert;
+     eapPeerConfig->server_cert_ctx = eapPeerConfig;
      *minor = 0;
      return GSS_S_COMPLETE;
  }
@@@ -543,7 -639,7 +639,7 @@@ initReady(OM_uint32 *minor, gss_ctx_id_
  static OM_uint32
  initBegin(OM_uint32 *minor,
            gss_ctx_id_t ctx,
 -          gss_name_t target,
 +          gss_const_name_t target,
            gss_OID mech,
            OM_uint32 reqFlags GSSEAP_UNUSED,
            OM_uint32 timeReq,
          return major;
  
      if (target != GSS_C_NO_NAME) {
 -        GSSEAP_MUTEX_LOCK(&target->mutex);
 +        GSSEAP_MUTEX_LOCK(&((gss_name_t)target)->mutex);
  
          major = gssEapDuplicateName(minor, target, &ctx->acceptorName);
          if (GSS_ERROR(major)) {
 -            GSSEAP_MUTEX_UNLOCK(&target->mutex);
 +            GSSEAP_MUTEX_LOCK(&((gss_name_t)target)->mutex);
              return major;
          }
  
 -        GSSEAP_MUTEX_UNLOCK(&target->mutex);
 +        GSSEAP_MUTEX_UNLOCK(&((gss_name_t)target)->mutex);
      }
  
      major = gssEapCanonicalizeOid(minor,
@@@ -603,7 -699,7 +699,7 @@@ static OM_uint3
  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_const_name_t target GSSEAP_UNUSED,
                    gss_OID mech GSSEAP_UNUSED,
                    OM_uint32 reqFlags GSSEAP_UNUSED,
                    OM_uint32 timeReq GSSEAP_UNUSED,
@@@ -643,7 -739,7 +739,7 @@@ static OM_uint3
  eapGssSmInitGssReauth(OM_uint32 *minor,
                        gss_cred_id_t cred,
                        gss_ctx_id_t ctx,
 -                      gss_name_t target,
 +                      gss_const_name_t target,
                        gss_OID mech GSSEAP_UNUSED,
                        OM_uint32 reqFlags,
                        OM_uint32 timeReq,
@@@ -719,7 -815,7 +815,7 @@@ static OM_uint3
  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_const_name_t target GSSEAP_UNUSED,
                         gss_OID mech GSSEAP_UNUSED,
                         OM_uint32 reqFlags GSSEAP_UNUSED,
                         OM_uint32 timeReq GSSEAP_UNUSED,
@@@ -742,7 -838,7 +838,7 @@@ static OM_uint3
  eapGssSmInitAcceptorName(OM_uint32 *minor,
                           gss_cred_id_t cred GSSEAP_UNUSED,
                           gss_ctx_id_t ctx,
 -                         gss_name_t target GSSEAP_UNUSED,
 +                         gss_const_name_t target GSSEAP_UNUSED,
                           gss_OID mech GSSEAP_UNUSED,
                           OM_uint32 reqFlags GSSEAP_UNUSED,
                           OM_uint32 timeReq GSSEAP_UNUSED,
@@@ -825,7 -921,7 +921,7 @@@ static OM_uint3
  eapGssSmInitIdentity(OM_uint32 *minor,
                       gss_cred_id_t cred GSSEAP_UNUSED,
                       gss_ctx_id_t ctx,
 -                     gss_name_t target GSSEAP_UNUSED,
 +                     gss_const_name_t target GSSEAP_UNUSED,
                       gss_OID mech GSSEAP_UNUSED,
                       OM_uint32 reqFlags GSSEAP_UNUSED,
                       OM_uint32 timeReq GSSEAP_UNUSED,
                       OM_uint32 *smFlags)
  {
      struct eap_config eapConfig;
+     memset(&eapConfig, 0, sizeof(eapConfig));
+     eapConfig.cert_in_cb = 1;
  
  #ifdef GSSEAP_ENABLE_REAUTH
      if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE) {
      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,
+                                              NULL, /* ctx?? */
                                               &eapConfig);
      if (ctx->initiatorCtx.eap == NULL) {
          *minor = GSSEAP_PEER_SM_INIT_FAILURE;
@@@ -881,7 -977,7 +977,7 @@@ static OM_uint3
  eapGssSmInitAuthenticate(OM_uint32 *minor,
                           gss_cred_id_t cred GSSEAP_UNUSED,
                           gss_ctx_id_t ctx,
 -                         gss_name_t target GSSEAP_UNUSED,
 +                         gss_const_name_t target GSSEAP_UNUSED,
                           gss_OID mech GSSEAP_UNUSED,
                           OM_uint32 reqFlags GSSEAP_UNUSED,
                           OM_uint32 timeReq GSSEAP_UNUSED,
@@@ -962,7 -1058,7 +1058,7 @@@ static OM_uint3
  eapGssSmInitGssFlags(OM_uint32 *minor,
                       gss_cred_id_t cred GSSEAP_UNUSED,
                       gss_ctx_id_t ctx,
 -                     gss_name_t target GSSEAP_UNUSED,
 +                     gss_const_name_t target GSSEAP_UNUSED,
                       gss_OID mech GSSEAP_UNUSED,
                       OM_uint32 reqFlags GSSEAP_UNUSED,
                       OM_uint32 timeReq GSSEAP_UNUSED,
@@@ -991,7 -1087,7 +1087,7 @@@ static OM_uint3
  eapGssSmInitGssChannelBindings(OM_uint32 *minor,
                                 gss_cred_id_t cred GSSEAP_UNUSED,
                                 gss_ctx_id_t ctx,
 -                               gss_name_t target GSSEAP_UNUSED,
 +                               gss_const_name_t target GSSEAP_UNUSED,
                                 gss_OID mech GSSEAP_UNUSED,
                                 OM_uint32 reqFlags GSSEAP_UNUSED,
                                 OM_uint32 timeReq GSSEAP_UNUSED,
@@@ -1047,7 -1143,7 +1143,7 @@@ static OM_uint3
  eapGssSmInitInitiatorMIC(OM_uint32 *minor,
                           gss_cred_id_t cred GSSEAP_UNUSED,
                           gss_ctx_id_t ctx,
 -                         gss_name_t target GSSEAP_UNUSED,
 +                         gss_const_name_t target GSSEAP_UNUSED,
                           gss_OID mech GSSEAP_UNUSED,
                           OM_uint32 reqFlags GSSEAP_UNUSED,
                           OM_uint32 timeReq GSSEAP_UNUSED,
@@@ -1075,7 -1171,7 +1171,7 @@@ static OM_uint3
  eapGssSmInitReauthCreds(OM_uint32 *minor,
                          gss_cred_id_t cred,
                          gss_ctx_id_t ctx,
 -                        gss_name_t target GSSEAP_UNUSED,
 +                        gss_const_name_t target GSSEAP_UNUSED,
                          gss_OID mech GSSEAP_UNUSED,
                          OM_uint32 reqFlags GSSEAP_UNUSED,
                          OM_uint32 timeReq GSSEAP_UNUSED,
@@@ -1101,7 -1197,7 +1197,7 @@@ static OM_uint3
  eapGssSmInitAcceptorMIC(OM_uint32 *minor,
                          gss_cred_id_t cred GSSEAP_UNUSED,
                          gss_ctx_id_t ctx,
 -                        gss_name_t target GSSEAP_UNUSED,
 +                        gss_const_name_t target GSSEAP_UNUSED,
                          gss_OID mech GSSEAP_UNUSED,
                          OM_uint32 reqFlags GSSEAP_UNUSED,
                          OM_uint32 timeReq GSSEAP_UNUSED,
@@@ -1218,7 -1314,7 +1314,7 @@@ OM_uint3
  gssEapInitSecContext(OM_uint32 *minor,
                       gss_cred_id_t cred,
                       gss_ctx_id_t ctx,
 -                     gss_name_t target_name,
 +                     gss_const_name_t target_name,
                       gss_OID mech_type,
                       OM_uint32 req_flags,
                       OM_uint32 time_req,
@@@ -1305,17 -1401,9 +1401,17 @@@ cleanup
  
  OM_uint32 GSSAPI_CALLCONV
  gss_init_sec_context(OM_uint32 *minor,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                     gss_const_cred_id_t cred,
 +#else
                       gss_cred_id_t cred,
 +#endif
                       gss_ctx_id_t *context_handle,
 +#ifdef HAVE_HEIMDAL_VERSION
 +                     gss_const_name_t target_name,
 +#else
                       gss_name_t target_name,
 +#endif
                       gss_OID mech_type,
                       OM_uint32 req_flags,
                       OM_uint32 time_req,
      GSSEAP_MUTEX_LOCK(&ctx->mutex);
  
      major = gssEapInitSecContext(minor,
 -                                 cred,
 +                                 (gss_cred_id_t)cred,
                                   ctx,
                                   target_name,
                                   mech_type,
      if (GSS_ERROR(major))
          gssEapReleaseContext(&tmpMinor, context_handle);
  
 -    gssEapTraceStatus( "gss_init_sec_context", major, *minor);
 +    gssEapTraceStatus("gss_init_sec_context", major, *minor);
 +
      return major;
  }
diff --combined mech_eap/util.h
@@@ -142,17 -142,6 +142,17 @@@ bufferEqualString(const gss_buffer_t b1
  }
  
  /* util_cksum.c */
 +enum gss_eap_token_type {
 +    TOK_TYPE_NONE                    = 0x0000,  /* no token */
 +    TOK_TYPE_MIC                     = 0x0404,  /* RFC 4121 MIC token */
 +    TOK_TYPE_WRAP                    = 0x0504,  /* RFC 4121 wrap token */
 +    TOK_TYPE_EXPORT_NAME             = 0x0401,  /* RFC 2743 exported name */
 +    TOK_TYPE_EXPORT_NAME_COMPOSITE   = 0x0402,  /* exported composite name */
 +    TOK_TYPE_DELETE_CONTEXT          = 0x0405,  /* RFC 2743 delete context */
 +    TOK_TYPE_INITIATOR_CONTEXT       = 0x0601,  /* initiator-sent context token */
 +    TOK_TYPE_ACCEPTOR_CONTEXT        = 0x0602,  /* acceptor-sent context token */
 +};
 +
  int
  gssEapSign(krb5_context context,
             krb5_cksumtype type,
  #endif
             krb5_keyusage sign_usage,
             gss_iov_buffer_desc *iov,
 -           int iov_count);
 +           int iov_count,
 +           enum gss_eap_token_type toktype);
  
  int
  gssEapVerify(krb5_context context,
               krb5_keyusage sign_usage,
               gss_iov_buffer_desc *iov,
               int iov_count,
 +             enum gss_eap_token_type toktype,
               int *valid);
  
  #if 0
@@@ -192,6 -179,17 +192,6 @@@ gssEapEncodeGssChannelBindings(OM_uint3
  /* util_context.c */
  #define EAP_EXPORT_CONTEXT_V1           1
  
 -enum gss_eap_token_type {
 -    TOK_TYPE_NONE                    = 0x0000,  /* no token */
 -    TOK_TYPE_MIC                     = 0x0404,  /* RFC 4121 MIC token */
 -    TOK_TYPE_WRAP                    = 0x0504,  /* RFC 4121 wrap token */
 -    TOK_TYPE_EXPORT_NAME             = 0x0401,  /* RFC 2743 exported name */
 -    TOK_TYPE_EXPORT_NAME_COMPOSITE   = 0x0402,  /* exported composite name */
 -    TOK_TYPE_DELETE_CONTEXT          = 0x0405,  /* RFC 2743 delete context */
 -    TOK_TYPE_INITIATOR_CONTEXT       = 0x0601,  /* initiator-sent context token */
 -    TOK_TYPE_ACCEPTOR_CONTEXT        = 0x0602,  /* acceptor-sent context token */
 -};
 -
  /* inner token types and flags */
  #define ITOK_TYPE_NONE                  0x00000000
  #define ITOK_TYPE_CONTEXT_ERR           0x00000001 /* critical */
@@@ -238,7 -236,7 +238,7 @@@ gssEapVerifyToken(OM_uint32 *minor
  
  OM_uint32
  gssEapContextTime(OM_uint32 *minor,
 -                  gss_ctx_id_t context_handle,
 +                  gss_const_ctx_id_t context_handle,
                    OM_uint32 *time_rec);
  
  OM_uint32
@@@ -260,7 -258,7 +260,7 @@@ gssEapPrimaryMechForCred(gss_cred_id_t 
  
  OM_uint32
  gssEapAcquireCred(OM_uint32 *minor,
 -                  const gss_name_t desiredName,
 +                  gss_const_name_t desiredName,
                    OM_uint32 timeReq,
                    const gss_OID_set desiredMechs,
                    int cred_usage,
@@@ -282,15 -280,15 +282,15 @@@ gssEapSetCredClientCertificate(OM_uint3
  OM_uint32
  gssEapSetCredService(OM_uint32 *minor,
                       gss_cred_id_t cred,
 -                     const gss_name_t target);
 +                     gss_const_name_t target);
  
  OM_uint32
  gssEapResolveInitiatorCred(OM_uint32 *minor,
                             const gss_cred_id_t cred,
 -                           const gss_name_t target,
 +                           gss_const_name_t target,
                             gss_cred_id_t *resolvedCred);
  
 -int gssEapCredAvailable(gss_cred_id_t cred, gss_OID mech);
 +int gssEapCredAvailable(gss_const_cred_id_t cred, gss_OID mech);
  
  OM_uint32
  gssEapInquireCred(OM_uint32 *minor,
@@@ -331,11 -329,6 +331,11 @@@ gssEapLocateIov(gss_iov_buffer_desc *io
                  int iov_count,
                  OM_uint32 type);
  
 +gss_iov_buffer_t
 +gssEapLocateHeaderIov(gss_iov_buffer_desc *iov,
 +                      int iov_count,
 +                      enum gss_eap_token_type toktype);
 +
  void
  gssEapIovMessageLength(gss_iov_buffer_desc *iov,
                         int iov_count,
@@@ -470,7 -463,7 +470,7 @@@ krbCryptoLength(krb5_context krbContext
  #ifdef HAVE_HEIMDAL_VERSION
                  krb5_crypto krbCrypto,
  #else
 -                krb5_keyblock *key,
 +                const krb5_keyblock *key,
  #endif
                  int type,
                  size_t *length);
@@@ -480,7 -473,7 +480,7 @@@ krbPaddingLength(krb5_context krbContex
  #ifdef HAVE_HEIMDAL_VERSION
                   krb5_crypto krbCrypto,
  #else
 -                 krb5_keyblock *key,
 +                 const krb5_keyblock *key,
  #endif
                   size_t dataLength,
                   size_t *padLength);
@@@ -490,7 -483,7 +490,7 @@@ krbBlockSize(krb5_context krbContext
  #ifdef HAVE_HEIMDAL_VERSION
                   krb5_crypto krbCrypto,
  #else
 -                 krb5_keyblock *key,
 +                 const krb5_keyblock *key,
  #endif
                   size_t *blockSize);
  
@@@ -522,7 -515,7 +522,7 @@@ krbMakeCred(krb5_context context
  /* util_lucid.c */
  OM_uint32
  gssEapExportLucidSecContext(OM_uint32 *minor,
 -                            gss_ctx_id_t ctx,
 +                            gss_const_ctx_id_t ctx,
                              const gss_OID desiredObject,
                              gss_buffer_set_t *data_set);
  
@@@ -586,7 -579,7 +586,7 @@@ libMoonshotResolveDefaultIdentity(OM_ui
  OM_uint32
  libMoonshotResolveInitiatorCred(OM_uint32 *minor,
                                  gss_cred_id_t cred,
 -                                const gss_name_t targetName);
 +                                gss_const_name_t targetName);
  
  /* util_name.c */
  #define EXPORT_NAME_FLAG_OID                    0x1
  OM_uint32 gssEapAllocName(OM_uint32 *minor, gss_name_t *pName);
  OM_uint32 gssEapReleaseName(OM_uint32 *minor, gss_name_t *pName);
  OM_uint32 gssEapExportName(OM_uint32 *minor,
 -                           const gss_name_t name,
 +                           gss_const_name_t name,
                             gss_buffer_t exportedName);
  OM_uint32 gssEapExportNameInternal(OM_uint32 *minor,
 -                                   const gss_name_t name,
 +                                   gss_const_name_t name,
                                     gss_buffer_t exportedName,
                                     OM_uint32 flags);
  OM_uint32 gssEapImportName(OM_uint32 *minor,
@@@ -613,18 -606,18 +613,18 @@@ OM_uint32 gssEapImportNameInternal(OM_u
                                     OM_uint32 flags);
  OM_uint32
  gssEapDuplicateName(OM_uint32 *minor,
 -                    const gss_name_t input_name,
 +                    gss_const_name_t input_name,
                      gss_name_t *dest_name);
  
  OM_uint32
  gssEapCanonicalizeName(OM_uint32 *minor,
 -                       const gss_name_t input_name,
 +                       gss_const_name_t input_name,
                         const gss_OID mech_type,
                         gss_name_t *dest_name);
  
  OM_uint32
  gssEapDisplayName(OM_uint32 *minor,
 -                  gss_name_t name,
 +                  gss_const_name_t name,
                    gss_buffer_t output_name_buffer,
                    gss_OID *output_name_type);
  
  
  OM_uint32
  gssEapCompareName(OM_uint32 *minor,
 -                  gss_name_t name1,
 -                  gss_name_t name2,
 +                  gss_const_name_t name1,
 +                  gss_const_name_t name2,
                    OM_uint32 flags,
                    int *name_equal);
  
@@@ -662,17 -655,8 +662,8 @@@ duplicateOidSet(OM_uint32 *minor
                  const gss_OID_set src,
                  gss_OID_set *dst);
  
- static inline int
- oidEqual(const gss_OID_desc *o1, const gss_OID_desc *o2)
- {
-     if (o1 == GSS_C_NO_OID)
-         return (o2 == GSS_C_NO_OID);
-     else if (o2 == GSS_C_NO_OID)
-         return (o1 == GSS_C_NO_OID);
-     else
-         return (o1->length == o2->length &&
-                 memcmp(o1->elements, o2->elements, o1->length) == 0);
- }
+ extern int
+ oidEqual(const gss_OID_desc *o1, const gss_OID_desc *o2);
  
  /* util_ordering.c */
  OM_uint32
@@@ -735,7 -719,7 +726,7 @@@ struct gss_eap_sm 
      OM_uint32 (*processToken)(OM_uint32 *,
                                gss_cred_id_t,
                                gss_ctx_id_t,
 -                              gss_name_t,
 +                              gss_const_name_t,
                                gss_OID,
                                OM_uint32,
                                OM_uint32,
@@@ -758,7 -742,7 +749,7 @@@ OM_uint3
  gssEapSmStep(OM_uint32 *minor,
               gss_cred_id_t cred,
               gss_ctx_id_t ctx,
 -             gss_name_t target,
 +             gss_const_name_t target,
               gss_OID mech,
               OM_uint32 reqFlags,
               OM_uint32 timeReq,
@@@ -1062,7 -1046,7 +1053,7 @@@ krbPrincUnparseServiceSpecifics(krb5_co
  }
  
  static inline void
 -krbFreeUnparsedName(krb5_context krbContext, gss_buffer_t nameBuf)
 +krbFreeUnparsedName(krb5_context krbContext GSSEAP_UNUSED, gss_buffer_t nameBuf)
  {
  #ifdef HAVE_HEIMDAL_VERSION
      krb5_xfree((char *) nameBuf->value);