Updated through tag hostap_2_5 from git://w1.fi/hostap.git
authorDan Breslau <dbreslau@painless-security.com>
Fri, 2 Sep 2016 17:02:24 +0000 (13:02 -0400)
committerDan Breslau <dbreslau@painless-security.com>
Fri, 2 Sep 2016 17:02:24 +0000 (13:02 -0400)
1084 files changed:
1  2 
.gitignore
libeap/Android.mk
libeap/COPYING
libeap/Makefile.am
libeap/README
libeap/build_release
libeap/doc/.gitignore
libeap/doc/Makefile
libeap/doc/code_structure.doxygen
libeap/doc/ctrl_iface.doxygen
libeap/doc/dbus.doxygen
libeap/doc/directories.doxygen
libeap/doc/doxygen.conf
libeap/doc/driver_wrapper.doxygen
libeap/doc/eap.doxygen
libeap/doc/eap_server.doxygen
libeap/doc/hostapd.fig
libeap/doc/hostapd_ctrl_iface.doxygen
libeap/doc/mainpage.doxygen
libeap/doc/p2p.doxygen
libeap/doc/p2p_arch.dot
libeap/doc/p2p_arch2.dot
libeap/doc/p2p_sm.dot
libeap/doc/porting.doxygen
libeap/doc/testing_tools.doxygen
libeap/doc/wpa_supplicant.fig
libeap/eap_example/README
libeap/eap_example/dh.conf
libeap/eap_example/eap_example.c
libeap/eap_example/eap_example_peer.c
libeap/eap_example/eap_example_server.c
libeap/hostapd/Android.mk
libeap/hostapd/ChangeLog
libeap/hostapd/Makefile
libeap/hostapd/README
libeap/hostapd/README-WPS
libeap/hostapd/android.config
libeap/hostapd/config_file.c
libeap/hostapd/config_file.h
libeap/hostapd/ctrl_iface.c
libeap/hostapd/ctrl_iface.h
libeap/hostapd/defconfig
libeap/hostapd/eap_register.c
libeap/hostapd/eap_register.h
libeap/hostapd/hapd_module_tests.c
libeap/hostapd/hlr_auc_gw.c
libeap/hostapd/hlr_auc_gw.milenage_db
libeap/hostapd/hlr_auc_gw.txt
libeap/hostapd/hostapd.8
libeap/hostapd/hostapd.conf
libeap/hostapd/hostapd.eap_user
libeap/hostapd/hostapd.eap_user_sqlite
libeap/hostapd/hostapd_cli.c
libeap/hostapd/main.c
libeap/hostapd/nt_password_hash.c
libeap/hostapd/wps-ap-nfc.py
libeap/hs20/client/Android.mk
libeap/hs20/client/Makefile
libeap/hs20/client/devdetail.xml
libeap/hs20/client/devinfo.xml
libeap/hs20/client/est.c
libeap/hs20/client/oma_dm_client.c
libeap/hs20/client/osu_client.c
libeap/hs20/client/osu_client.h
libeap/hs20/client/spp_client.c
libeap/hs20/server/Makefile
libeap/hs20/server/ca/clean.sh
libeap/hs20/server/ca/est-csrattrs.cnf
libeap/hs20/server/ca/est-csrattrs.sh
libeap/hs20/server/ca/hs20.oid
libeap/hs20/server/ca/ocsp-req.sh
libeap/hs20/server/ca/ocsp-responder-ica.sh
libeap/hs20/server/ca/ocsp-responder.sh
libeap/hs20/server/ca/ocsp-update-cache.sh
libeap/hs20/server/ca/openssl-root.cnf
libeap/hs20/server/ca/openssl.cnf
libeap/hs20/server/ca/setup.sh
libeap/hs20/server/ca/w1fi_logo.png
libeap/hs20/server/hs20-osu-server.txt
libeap/hs20/server/hs20_spp_server.c
libeap/hs20/server/spp_server.c
libeap/hs20/server/spp_server.h
libeap/hs20/server/sql-example.txt
libeap/hs20/server/sql.txt
libeap/hs20/server/www/add-free.php
libeap/hs20/server/www/add-mo.php
libeap/hs20/server/www/cert-enroll.php
libeap/hs20/server/www/config.php
libeap/hs20/server/www/est.php
libeap/hs20/server/www/free-remediation.php
libeap/hs20/server/www/free.php
libeap/hs20/server/www/redirect.php
libeap/hs20/server/www/remediation.php
libeap/hs20/server/www/signup.php
libeap/hs20/server/www/spp.php
libeap/hs20/server/www/users.php
libeap/mac80211_hwsim/tools/Makefile
libeap/mac80211_hwsim/tools/hwsim_test.c
libeap/patches/openssl-0.9.8za-tls-extensions.patch
libeap/patches/openssl-0.9.8zf-tls-extensions.patch
libeap/radius_example/Makefile
libeap/radius_example/README
libeap/radius_example/radius_example.c
libeap/src/Makefile
libeap/src/ap/Makefile
libeap/src/ap/accounting.c
libeap/src/ap/accounting.h
libeap/src/ap/acs.c
libeap/src/ap/acs.h
libeap/src/ap/ap_config.c
libeap/src/ap/ap_config.h
libeap/src/ap/ap_drv_ops.c
libeap/src/ap/ap_drv_ops.h
libeap/src/ap/ap_list.c
libeap/src/ap/ap_list.h
libeap/src/ap/ap_mlme.c
libeap/src/ap/ap_mlme.h
libeap/src/ap/authsrv.c
libeap/src/ap/authsrv.h
libeap/src/ap/beacon.c
libeap/src/ap/beacon.h
libeap/src/ap/bss_load.c
libeap/src/ap/bss_load.h
libeap/src/ap/ctrl_iface_ap.c
libeap/src/ap/ctrl_iface_ap.h
libeap/src/ap/dfs.c
libeap/src/ap/dfs.h
libeap/src/ap/dhcp_snoop.c
libeap/src/ap/dhcp_snoop.h
libeap/src/ap/drv_callbacks.c
libeap/src/ap/eap_user_db.c
libeap/src/ap/gas_serv.c
libeap/src/ap/gas_serv.h
libeap/src/ap/hostapd.c
libeap/src/ap/hostapd.h
libeap/src/ap/hs20.c
libeap/src/ap/hs20.h
libeap/src/ap/hw_features.c
libeap/src/ap/hw_features.h
libeap/src/ap/iapp.c
libeap/src/ap/iapp.h
libeap/src/ap/ieee802_11.c
libeap/src/ap/ieee802_11.h
libeap/src/ap/ieee802_11_auth.c
libeap/src/ap/ieee802_11_auth.h
libeap/src/ap/ieee802_11_ht.c
libeap/src/ap/ieee802_11_shared.c
libeap/src/ap/ieee802_11_vht.c
libeap/src/ap/ieee802_1x.c
libeap/src/ap/ieee802_1x.h
libeap/src/ap/ndisc_snoop.c
libeap/src/ap/ndisc_snoop.h
libeap/src/ap/p2p_hostapd.c
libeap/src/ap/p2p_hostapd.h
libeap/src/ap/peerkey_auth.c
libeap/src/ap/pmksa_cache_auth.c
libeap/src/ap/pmksa_cache_auth.h
libeap/src/ap/preauth_auth.c
libeap/src/ap/preauth_auth.h
libeap/src/ap/sta_info.c
libeap/src/ap/sta_info.h
libeap/src/ap/tkip_countermeasures.c
libeap/src/ap/tkip_countermeasures.h
libeap/src/ap/utils.c
libeap/src/ap/vlan_init.c
libeap/src/ap/vlan_init.h
libeap/src/ap/vlan_util.c
libeap/src/ap/vlan_util.h
libeap/src/ap/wmm.c
libeap/src/ap/wmm.h
libeap/src/ap/wnm_ap.c
libeap/src/ap/wnm_ap.h
libeap/src/ap/wpa_auth.c
libeap/src/ap/wpa_auth.h
libeap/src/ap/wpa_auth_ft.c
libeap/src/ap/wpa_auth_glue.c
libeap/src/ap/wpa_auth_glue.h
libeap/src/ap/wpa_auth_i.h
libeap/src/ap/wpa_auth_ie.c
libeap/src/ap/wpa_auth_ie.h
libeap/src/ap/wps_hostapd.c
libeap/src/ap/wps_hostapd.h
libeap/src/ap/x_snoop.c
libeap/src/ap/x_snoop.h
libeap/src/common/Makefile
libeap/src/common/common_module_tests.c
libeap/src/common/defs.h
libeap/src/common/eapol_common.h
libeap/src/common/gas.c
libeap/src/common/gas.h
libeap/src/common/hw_features_common.c
libeap/src/common/hw_features_common.h
libeap/src/common/ieee802_11_common.c
libeap/src/common/ieee802_11_common.h
libeap/src/common/ieee802_11_defs.h
libeap/src/common/ieee802_1x_defs.h
libeap/src/common/privsep_commands.h
libeap/src/common/qca-vendor-attr.h
libeap/src/common/qca-vendor.h
libeap/src/common/sae.c
libeap/src/common/sae.h
libeap/src/common/tnc.h
libeap/src/common/version.h
libeap/src/common/wpa_common.c
libeap/src/common/wpa_common.h
libeap/src/common/wpa_ctrl.c
libeap/src/common/wpa_ctrl.h
libeap/src/common/wpa_helpers.c
libeap/src/common/wpa_helpers.h
libeap/src/crypto/Makefile
libeap/src/crypto/aes-cbc.c
libeap/src/crypto/aes-ccm.c
libeap/src/crypto/aes-ctr.c
libeap/src/crypto/aes-eax.c
libeap/src/crypto/aes-encblock.c
libeap/src/crypto/aes-gcm.c
libeap/src/crypto/aes-internal-dec.c
libeap/src/crypto/aes-internal-enc.c
libeap/src/crypto/aes-internal.c
libeap/src/crypto/aes-omac1.c
libeap/src/crypto/aes-siv.c
libeap/src/crypto/aes-unwrap.c
libeap/src/crypto/aes-wrap.c
libeap/src/crypto/aes.h
libeap/src/crypto/aes_i.h
libeap/src/crypto/aes_siv.h
libeap/src/crypto/aes_wrap.h
libeap/src/crypto/crypto.h
libeap/src/crypto/crypto_gnutls.c
libeap/src/crypto/crypto_internal-cipher.c
libeap/src/crypto/crypto_internal-modexp.c
libeap/src/crypto/crypto_internal-rsa.c
libeap/src/crypto/crypto_internal.c
libeap/src/crypto/crypto_libtomcrypt.c
libeap/src/crypto/crypto_module_tests.c
libeap/src/crypto/crypto_none.c
libeap/src/crypto/crypto_openssl.c
libeap/src/crypto/des-internal.c
libeap/src/crypto/des_i.h
libeap/src/crypto/dh_group5.c
libeap/src/crypto/dh_group5.h
libeap/src/crypto/dh_groups.c
libeap/src/crypto/dh_groups.h
libeap/src/crypto/fips_prf_internal.c
libeap/src/crypto/fips_prf_openssl.c
libeap/src/crypto/md4-internal.c
libeap/src/crypto/md5-internal.c
libeap/src/crypto/md5.c
libeap/src/crypto/md5.h
libeap/src/crypto/md5_i.h
libeap/src/crypto/milenage.c
libeap/src/crypto/milenage.h
libeap/src/crypto/ms_funcs.c
libeap/src/crypto/ms_funcs.h
libeap/src/crypto/random.c
libeap/src/crypto/random.h
libeap/src/crypto/rc4.c
libeap/src/crypto/sha1-internal.c
libeap/src/crypto/sha1-pbkdf2.c
libeap/src/crypto/sha1-prf.c
libeap/src/crypto/sha1-tlsprf.c
libeap/src/crypto/sha1-tprf.c
libeap/src/crypto/sha1.c
libeap/src/crypto/sha1.h
libeap/src/crypto/sha1_i.h
libeap/src/crypto/sha256-internal.c
libeap/src/crypto/sha256-kdf.c
libeap/src/crypto/sha256-prf.c
libeap/src/crypto/sha256-tlsprf.c
libeap/src/crypto/sha256.c
libeap/src/crypto/sha256.h
libeap/src/crypto/sha256_i.h
libeap/src/crypto/sha384-prf.c
libeap/src/crypto/sha384.h
libeap/src/crypto/tls.h
libeap/src/crypto/tls_gnutls.c
libeap/src/crypto/tls_internal.c
libeap/src/crypto/tls_none.c
libeap/src/crypto/tls_openssl.c
libeap/src/drivers/Makefile
libeap/src/drivers/android_drv.h
libeap/src/drivers/driver.h
libeap/src/drivers/driver_atheros.c
libeap/src/drivers/driver_bsd.c
libeap/src/drivers/driver_common.c
libeap/src/drivers/driver_hostap.c
libeap/src/drivers/driver_hostap.h
libeap/src/drivers/driver_macsec_qca.c
libeap/src/drivers/driver_ndis.c
libeap/src/drivers/driver_ndis.h
libeap/src/drivers/driver_ndis_.c
libeap/src/drivers/driver_nl80211.c
libeap/src/drivers/driver_nl80211.h
libeap/src/drivers/driver_nl80211_android.c
libeap/src/drivers/driver_nl80211_capa.c
libeap/src/drivers/driver_nl80211_event.c
libeap/src/drivers/driver_nl80211_monitor.c
libeap/src/drivers/driver_nl80211_scan.c
libeap/src/drivers/driver_none.c
libeap/src/drivers/driver_openbsd.c
libeap/src/drivers/driver_privsep.c
libeap/src/drivers/driver_roboswitch.c
libeap/src/drivers/driver_wext.c
libeap/src/drivers/driver_wext.h
libeap/src/drivers/driver_wired.c
libeap/src/drivers/drivers.c
libeap/src/drivers/drivers.mak
libeap/src/drivers/drivers.mk
libeap/src/drivers/linux_defines.h
libeap/src/drivers/linux_ioctl.c
libeap/src/drivers/linux_ioctl.h
libeap/src/drivers/linux_wext.h
libeap/src/drivers/ndis_events.c
libeap/src/drivers/netlink.c
libeap/src/drivers/netlink.h
libeap/src/drivers/nl80211_copy.h
libeap/src/drivers/priv_netlink.h
libeap/src/drivers/rfkill.c
libeap/src/drivers/rfkill.h
libeap/src/eap_common/Makefile
libeap/src/eap_common/chap.c
libeap/src/eap_common/chap.h
libeap/src/eap_common/eap_common.c
libeap/src/eap_common/eap_common.h
libeap/src/eap_common/eap_defs.h
libeap/src/eap_common/eap_eke_common.c
libeap/src/eap_common/eap_eke_common.h
libeap/src/eap_common/eap_fast_common.c
libeap/src/eap_common/eap_fast_common.h
libeap/src/eap_common/eap_gpsk_common.c
libeap/src/eap_common/eap_gpsk_common.h
libeap/src/eap_common/eap_ikev2_common.c
libeap/src/eap_common/eap_ikev2_common.h
libeap/src/eap_common/eap_pax_common.c
libeap/src/eap_common/eap_pax_common.h
libeap/src/eap_common/eap_peap_common.c
libeap/src/eap_common/eap_peap_common.h
libeap/src/eap_common/eap_psk_common.c
libeap/src/eap_common/eap_psk_common.h
libeap/src/eap_common/eap_pwd_common.c
libeap/src/eap_common/eap_pwd_common.h
libeap/src/eap_common/eap_sake_common.c
libeap/src/eap_common/eap_sake_common.h
libeap/src/eap_common/eap_sim_common.c
libeap/src/eap_common/eap_sim_common.h
libeap/src/eap_common/eap_tlv_common.h
libeap/src/eap_common/eap_ttls.h
libeap/src/eap_common/eap_wsc_common.c
libeap/src/eap_common/eap_wsc_common.h
libeap/src/eap_common/ikev2_common.c
libeap/src/eap_common/ikev2_common.h
libeap/src/eap_peer/Makefile
libeap/src/eap_peer/eap.c
libeap/src/eap_peer/eap.h
libeap/src/eap_peer/eap_aka.c
libeap/src/eap_peer/eap_config.h
libeap/src/eap_peer/eap_eke.c
libeap/src/eap_peer/eap_fast.c
libeap/src/eap_peer/eap_fast_pac.c
libeap/src/eap_peer/eap_fast_pac.h
libeap/src/eap_peer/eap_gpsk.c
libeap/src/eap_peer/eap_gtc.c
libeap/src/eap_peer/eap_i.h
libeap/src/eap_peer/eap_ikev2.c
libeap/src/eap_peer/eap_leap.c
libeap/src/eap_peer/eap_md5.c
libeap/src/eap_peer/eap_methods.c
libeap/src/eap_peer/eap_methods.h
libeap/src/eap_peer/eap_mschapv2.c
libeap/src/eap_peer/eap_otp.c
libeap/src/eap_peer/eap_pax.c
libeap/src/eap_peer/eap_peap.c
libeap/src/eap_peer/eap_proxy.h
libeap/src/eap_peer/eap_proxy_dummy.c
libeap/src/eap_peer/eap_psk.c
libeap/src/eap_peer/eap_pwd.c
libeap/src/eap_peer/eap_sake.c
libeap/src/eap_peer/eap_sim.c
libeap/src/eap_peer/eap_tls.c
libeap/src/eap_peer/eap_tls_common.c
libeap/src/eap_peer/eap_tls_common.h
libeap/src/eap_peer/eap_tnc.c
libeap/src/eap_peer/eap_ttls.c
libeap/src/eap_peer/eap_vendor_test.c
libeap/src/eap_peer/eap_wsc.c
libeap/src/eap_peer/ikev2.c
libeap/src/eap_peer/ikev2.h
libeap/src/eap_peer/mschapv2.c
libeap/src/eap_peer/mschapv2.h
libeap/src/eap_peer/tncc.c
libeap/src/eap_peer/tncc.h
libeap/src/eap_server/Makefile
libeap/src/eap_server/eap.h
libeap/src/eap_server/eap_i.h
libeap/src/eap_server/eap_methods.h
libeap/src/eap_server/eap_server.c
libeap/src/eap_server/eap_server_aka.c
libeap/src/eap_server/eap_server_eke.c
libeap/src/eap_server/eap_server_fast.c
libeap/src/eap_server/eap_server_gpsk.c
libeap/src/eap_server/eap_server_gtc.c
libeap/src/eap_server/eap_server_identity.c
libeap/src/eap_server/eap_server_ikev2.c
libeap/src/eap_server/eap_server_md5.c
libeap/src/eap_server/eap_server_methods.c
libeap/src/eap_server/eap_server_mschapv2.c
libeap/src/eap_server/eap_server_pax.c
libeap/src/eap_server/eap_server_peap.c
libeap/src/eap_server/eap_server_psk.c
libeap/src/eap_server/eap_server_pwd.c
libeap/src/eap_server/eap_server_sake.c
libeap/src/eap_server/eap_server_sim.c
libeap/src/eap_server/eap_server_tls.c
libeap/src/eap_server/eap_server_tls_common.c
libeap/src/eap_server/eap_server_tnc.c
libeap/src/eap_server/eap_server_ttls.c
libeap/src/eap_server/eap_server_vendor_test.c
libeap/src/eap_server/eap_server_wsc.c
libeap/src/eap_server/eap_sim_db.c
libeap/src/eap_server/eap_sim_db.h
libeap/src/eap_server/eap_tls_common.h
libeap/src/eap_server/ikev2.c
libeap/src/eap_server/ikev2.h
libeap/src/eap_server/tncs.c
libeap/src/eap_server/tncs.h
libeap/src/eapol_auth/Makefile
libeap/src/eapol_auth/eapol_auth_dump.c
libeap/src/eapol_auth/eapol_auth_sm.c
libeap/src/eapol_auth/eapol_auth_sm.h
libeap/src/eapol_auth/eapol_auth_sm_i.h
libeap/src/eapol_supp/Makefile
libeap/src/eapol_supp/eapol_supp_sm.c
libeap/src/eapol_supp/eapol_supp_sm.h
libeap/src/fst/Makefile
libeap/src/fst/fst.c
libeap/src/fst/fst.h
libeap/src/fst/fst_ctrl_aux.c
libeap/src/fst/fst_ctrl_aux.h
libeap/src/fst/fst_ctrl_defs.h
libeap/src/fst/fst_ctrl_iface.c
libeap/src/fst/fst_ctrl_iface.h
libeap/src/fst/fst_defs.h
libeap/src/fst/fst_group.c
libeap/src/fst/fst_group.h
libeap/src/fst/fst_iface.c
libeap/src/fst/fst_iface.h
libeap/src/fst/fst_internal.h
libeap/src/fst/fst_session.c
libeap/src/fst/fst_session.h
libeap/src/l2_packet/Makefile
libeap/src/l2_packet/l2_packet.h
libeap/src/l2_packet/l2_packet_freebsd.c
libeap/src/l2_packet/l2_packet_linux.c
libeap/src/l2_packet/l2_packet_ndis.c
libeap/src/l2_packet/l2_packet_none.c
libeap/src/l2_packet/l2_packet_pcap.c
libeap/src/l2_packet/l2_packet_privsep.c
libeap/src/l2_packet/l2_packet_winpcap.c
libeap/src/lib.rules
libeap/src/p2p/Makefile
libeap/src/p2p/p2p.c
libeap/src/p2p/p2p.h
libeap/src/p2p/p2p_build.c
libeap/src/p2p/p2p_dev_disc.c
libeap/src/p2p/p2p_go_neg.c
libeap/src/p2p/p2p_group.c
libeap/src/p2p/p2p_i.h
libeap/src/p2p/p2p_invitation.c
libeap/src/p2p/p2p_parse.c
libeap/src/p2p/p2p_pd.c
libeap/src/p2p/p2p_sd.c
libeap/src/p2p/p2p_utils.c
libeap/src/pae/Makefile
libeap/src/pae/ieee802_1x_cp.c
libeap/src/pae/ieee802_1x_cp.h
libeap/src/pae/ieee802_1x_kay.c
libeap/src/pae/ieee802_1x_kay.h
libeap/src/pae/ieee802_1x_kay_i.h
libeap/src/pae/ieee802_1x_key.c
libeap/src/pae/ieee802_1x_key.h
libeap/src/pae/ieee802_1x_secy_ops.c
libeap/src/pae/ieee802_1x_secy_ops.h
libeap/src/radius/Makefile
libeap/src/radius/radius.c
libeap/src/radius/radius.h
libeap/src/radius/radius_client.c
libeap/src/radius/radius_client.h
libeap/src/radius/radius_das.c
libeap/src/radius/radius_das.h
libeap/src/radius/radius_server.c
libeap/src/radius/radius_server.h
libeap/src/rsn_supp/Makefile
libeap/src/rsn_supp/peerkey.c
libeap/src/rsn_supp/peerkey.h
libeap/src/rsn_supp/pmksa_cache.c
libeap/src/rsn_supp/pmksa_cache.h
libeap/src/rsn_supp/preauth.c
libeap/src/rsn_supp/preauth.h
libeap/src/rsn_supp/tdls.c
libeap/src/rsn_supp/wpa.c
libeap/src/rsn_supp/wpa.h
libeap/src/rsn_supp/wpa_ft.c
libeap/src/rsn_supp/wpa_i.h
libeap/src/rsn_supp/wpa_ie.c
libeap/src/rsn_supp/wpa_ie.h
libeap/src/tls/Makefile
libeap/src/tls/asn1.c
libeap/src/tls/asn1.h
libeap/src/tls/bignum.c
libeap/src/tls/bignum.h
libeap/src/tls/libtommath.c
libeap/src/tls/pkcs1.c
libeap/src/tls/pkcs1.h
libeap/src/tls/pkcs5.c
libeap/src/tls/pkcs5.h
libeap/src/tls/pkcs8.c
libeap/src/tls/pkcs8.h
libeap/src/tls/rsa.c
libeap/src/tls/rsa.h
libeap/src/tls/tlsv1_client.c
libeap/src/tls/tlsv1_client.h
libeap/src/tls/tlsv1_client_i.h
libeap/src/tls/tlsv1_client_read.c
libeap/src/tls/tlsv1_client_write.c
libeap/src/tls/tlsv1_common.c
libeap/src/tls/tlsv1_common.h
libeap/src/tls/tlsv1_cred.c
libeap/src/tls/tlsv1_cred.h
libeap/src/tls/tlsv1_record.c
libeap/src/tls/tlsv1_record.h
libeap/src/tls/tlsv1_server.c
libeap/src/tls/tlsv1_server.h
libeap/src/tls/tlsv1_server_i.h
libeap/src/tls/tlsv1_server_read.c
libeap/src/tls/tlsv1_server_write.c
libeap/src/tls/x509v3.c
libeap/src/tls/x509v3.h
libeap/src/utils/Makefile
libeap/src/utils/base64.c
libeap/src/utils/base64.h
libeap/src/utils/bitfield.c
libeap/src/utils/bitfield.h
libeap/src/utils/browser-android.c
libeap/src/utils/browser-system.c
libeap/src/utils/browser-wpadebug.c
libeap/src/utils/browser.c
libeap/src/utils/browser.h
libeap/src/utils/build_config.h
libeap/src/utils/common.c
libeap/src/utils/common.h
libeap/src/utils/edit.c
libeap/src/utils/edit.h
libeap/src/utils/edit_readline.c
libeap/src/utils/edit_simple.c
libeap/src/utils/eloop.c
libeap/src/utils/eloop.h
libeap/src/utils/eloop_win.c
libeap/src/utils/ext_password.c
libeap/src/utils/ext_password.h
libeap/src/utils/ext_password_i.h
libeap/src/utils/ext_password_test.c
libeap/src/utils/http-utils.h
libeap/src/utils/http_curl.c
libeap/src/utils/includes.h
libeap/src/utils/ip_addr.c
libeap/src/utils/ip_addr.h
libeap/src/utils/list.h
libeap/src/utils/os.h
libeap/src/utils/os_internal.c
libeap/src/utils/os_none.c
libeap/src/utils/os_unix.c
libeap/src/utils/os_win32.c
libeap/src/utils/pcsc_funcs.c
libeap/src/utils/pcsc_funcs.h
libeap/src/utils/platform.h
libeap/src/utils/radiotap.c
libeap/src/utils/radiotap.h
libeap/src/utils/radiotap_iter.h
libeap/src/utils/state_machine.h
libeap/src/utils/trace.c
libeap/src/utils/trace.h
libeap/src/utils/utils_module_tests.c
libeap/src/utils/uuid.c
libeap/src/utils/uuid.h
libeap/src/utils/wpa_debug.c
libeap/src/utils/wpa_debug.h
libeap/src/utils/wpabuf.c
libeap/src/utils/wpabuf.h
libeap/src/utils/xml-utils.c
libeap/src/utils/xml-utils.h
libeap/src/utils/xml_libxml2.c
libeap/src/wps/Makefile
libeap/src/wps/http_client.c
libeap/src/wps/http_client.h
libeap/src/wps/http_server.c
libeap/src/wps/http_server.h
libeap/src/wps/httpread.c
libeap/src/wps/httpread.h
libeap/src/wps/ndef.c
libeap/src/wps/upnp_xml.c
libeap/src/wps/upnp_xml.h
libeap/src/wps/wps.c
libeap/src/wps/wps.h
libeap/src/wps/wps_attr_build.c
libeap/src/wps/wps_attr_parse.c
libeap/src/wps/wps_attr_parse.h
libeap/src/wps/wps_attr_process.c
libeap/src/wps/wps_common.c
libeap/src/wps/wps_defs.h
libeap/src/wps/wps_dev_attr.c
libeap/src/wps/wps_dev_attr.h
libeap/src/wps/wps_enrollee.c
libeap/src/wps/wps_er.c
libeap/src/wps/wps_er.h
libeap/src/wps/wps_er_ssdp.c
libeap/src/wps/wps_i.h
libeap/src/wps/wps_module_tests.c
libeap/src/wps/wps_registrar.c
libeap/src/wps/wps_upnp.c
libeap/src/wps/wps_upnp.h
libeap/src/wps/wps_upnp_ap.c
libeap/src/wps/wps_upnp_event.c
libeap/src/wps/wps_upnp_i.h
libeap/src/wps/wps_upnp_ssdp.c
libeap/src/wps/wps_upnp_web.c
libeap/src/wps/wps_validate.c
libeap/tests/.gitignore
libeap/tests/Makefile
libeap/tests/ap-mgmt-fuzzer/Makefile
libeap/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c
libeap/tests/ap-mgmt-fuzzer/auth.dat
libeap/tests/ap-mgmt-fuzzer/probe-req.dat
libeap/tests/eapol-fuzzer/Makefile
libeap/tests/eapol-fuzzer/eap-req-identity.dat
libeap/tests/eapol-fuzzer/eap-req-sim.dat
libeap/tests/eapol-fuzzer/eapol-fuzzer.c
libeap/tests/eapol-fuzzer/eapol-key-m1.dat
libeap/tests/hwsim/README
libeap/tests/hwsim/auth_serv/as.conf
libeap/tests/hwsim/auth_serv/as2.conf
libeap/tests/hwsim/auth_serv/ca-and-crl.pem
libeap/tests/hwsim/auth_serv/ca-incorrect.pem
libeap/tests/hwsim/auth_serv/ca.der
libeap/tests/hwsim/auth_serv/ca.pem
libeap/tests/hwsim/auth_serv/dh.conf
libeap/tests/hwsim/auth_serv/dh2.conf
libeap/tests/hwsim/auth_serv/dsaparam.pem
libeap/tests/hwsim/auth_serv/eap_user.conf
libeap/tests/hwsim/auth_serv/eap_user_vlan.conf
libeap/tests/hwsim/auth_serv/ec-ca-openssl.cnf
libeap/tests/hwsim/auth_serv/ec-ca.pem
libeap/tests/hwsim/auth_serv/ec-generate.sh
libeap/tests/hwsim/auth_serv/ec-server.key
libeap/tests/hwsim/auth_serv/ec-server.pem
libeap/tests/hwsim/auth_serv/ec-user.key
libeap/tests/hwsim/auth_serv/ec-user.pem
libeap/tests/hwsim/auth_serv/ec2-ca.pem
libeap/tests/hwsim/auth_serv/ec2-generate.sh
libeap/tests/hwsim/auth_serv/ec2-server.key
libeap/tests/hwsim/auth_serv/ec2-server.pem
libeap/tests/hwsim/auth_serv/ec2-user.key
libeap/tests/hwsim/auth_serv/ec2-user.pem
libeap/tests/hwsim/auth_serv/hlr_auc_gw.gsm
libeap/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db
libeap/tests/hwsim/auth_serv/index-revoked.txt
libeap/tests/hwsim/auth_serv/index-unknown.txt
libeap/tests/hwsim/auth_serv/index.txt
libeap/tests/hwsim/auth_serv/ocsp-req.der
libeap/tests/hwsim/auth_serv/ocsp-responder.key
libeap/tests/hwsim/auth_serv/ocsp-responder.pem
libeap/tests/hwsim/auth_serv/ocsp-server-cache.der
libeap/tests/hwsim/auth_serv/ocsp-server-cache.der-invalid
libeap/tests/hwsim/auth_serv/radius_clients.conf
libeap/tests/hwsim/auth_serv/radius_clients_ipv6.conf
libeap/tests/hwsim/auth_serv/server-eku-client-server.key
libeap/tests/hwsim/auth_serv/server-eku-client-server.pem
libeap/tests/hwsim/auth_serv/server-eku-client.key
libeap/tests/hwsim/auth_serv/server-eku-client.pem
libeap/tests/hwsim/auth_serv/server-expired.key
libeap/tests/hwsim/auth_serv/server-expired.pem
libeap/tests/hwsim/auth_serv/server-long-duration.key
libeap/tests/hwsim/auth_serv/server-long-duration.pem
libeap/tests/hwsim/auth_serv/server-no-dnsname.key
libeap/tests/hwsim/auth_serv/server-no-dnsname.pem
libeap/tests/hwsim/auth_serv/server.key
libeap/tests/hwsim/auth_serv/server.pem
libeap/tests/hwsim/auth_serv/server.pkcs12
libeap/tests/hwsim/auth_serv/user.key
libeap/tests/hwsim/auth_serv/user.pem
libeap/tests/hwsim/auth_serv/user.pkcs12
libeap/tests/hwsim/auth_serv/user.rsa-key
libeap/tests/hwsim/auth_serv/user2.pkcs12
libeap/tests/hwsim/auth_serv/user3.pkcs12
libeap/tests/hwsim/bss-1.conf
libeap/tests/hwsim/bss-2.conf
libeap/tests/hwsim/bss-3.conf
libeap/tests/hwsim/bss-ht40-1.conf
libeap/tests/hwsim/bss-ht40-2.conf
libeap/tests/hwsim/build.sh
libeap/tests/hwsim/check_kernel.py
libeap/tests/hwsim/dictionary.radius
libeap/tests/hwsim/example-hostapd.config
libeap/tests/hwsim/example-setup.txt
libeap/tests/hwsim/example-wpa_supplicant.config
libeap/tests/hwsim/fst_module_aux.py
libeap/tests/hwsim/fst_test_common.py
libeap/tests/hwsim/hostapd.accept
libeap/tests/hwsim/hostapd.macaddr
libeap/tests/hwsim/hostapd.py
libeap/tests/hwsim/hostapd.vlan
libeap/tests/hwsim/hostapd.wlan3.vlan
libeap/tests/hwsim/hostapd.wlan4.vlan
libeap/tests/hwsim/hostapd.wpa_psk
libeap/tests/hwsim/hwsim.py
libeap/tests/hwsim/hwsim_utils.py
libeap/tests/hwsim/multi-bss-acs.conf
libeap/tests/hwsim/multi-bss-iface.conf
libeap/tests/hwsim/multi-bss.conf
libeap/tests/hwsim/netlink.py
libeap/tests/hwsim/nl80211.py
libeap/tests/hwsim/p2p0.conf
libeap/tests/hwsim/p2p1.conf
libeap/tests/hwsim/p2p2.conf
libeap/tests/hwsim/radius_das.py
libeap/tests/hwsim/rfkill.py
libeap/tests/hwsim/run-all.sh
libeap/tests/hwsim/run-tests.py
libeap/tests/hwsim/start.sh
libeap/tests/hwsim/stop.sh
libeap/tests/hwsim/test_ap_acs.py
libeap/tests/hwsim/test_ap_ciphers.py
libeap/tests/hwsim/test_ap_config.py
libeap/tests/hwsim/test_ap_csa.py
libeap/tests/hwsim/test_ap_dynamic.py
libeap/tests/hwsim/test_ap_eap.py
libeap/tests/hwsim/test_ap_ft.py
libeap/tests/hwsim/test_ap_hs20.py
libeap/tests/hwsim/test_ap_ht.py
libeap/tests/hwsim/test_ap_mixed.py
libeap/tests/hwsim/test_ap_open.py
libeap/tests/hwsim/test_ap_params.py
libeap/tests/hwsim/test_ap_pmf.py
libeap/tests/hwsim/test_ap_psk.py
libeap/tests/hwsim/test_ap_qosmap.py
libeap/tests/hwsim/test_ap_roam.py
libeap/tests/hwsim/test_ap_tdls.py
libeap/tests/hwsim/test_ap_track.py
libeap/tests/hwsim/test_ap_vht.py
libeap/tests/hwsim/test_ap_vlan.py
libeap/tests/hwsim/test_ap_wps.py
libeap/tests/hwsim/test_autoscan.py
libeap/tests/hwsim/test_bgscan.py
libeap/tests/hwsim/test_cfg80211.py
libeap/tests/hwsim/test_connect_cmd.py
libeap/tests/hwsim/test_dbus.py
libeap/tests/hwsim/test_dbus_old.py
libeap/tests/hwsim/test_dfs.py
libeap/tests/hwsim/test_eap_proto.py
libeap/tests/hwsim/test_erp.py
libeap/tests/hwsim/test_ext_password.py
libeap/tests/hwsim/test_fst_config.py
libeap/tests/hwsim/test_fst_module.py
libeap/tests/hwsim/test_gas.py
libeap/tests/hwsim/test_hapd_ctrl.py
libeap/tests/hwsim/test_hostapd_oom.py
libeap/tests/hwsim/test_ibss.py
libeap/tests/hwsim/test_ieee8021x.py
libeap/tests/hwsim/test_module_tests.py
libeap/tests/hwsim/test_monitor_interface.py
libeap/tests/hwsim/test_nfc_p2p.py
libeap/tests/hwsim/test_nfc_wps.py
libeap/tests/hwsim/test_offchannel_tx.py
libeap/tests/hwsim/test_p2p_autogo.py
libeap/tests/hwsim/test_p2p_channel.py
libeap/tests/hwsim/test_p2p_concurrency.py
libeap/tests/hwsim/test_p2p_device.py
libeap/tests/hwsim/test_p2p_discovery.py
libeap/tests/hwsim/test_p2p_ext.py
libeap/tests/hwsim/test_p2p_grpform.py
libeap/tests/hwsim/test_p2p_invitation.py
libeap/tests/hwsim/test_p2p_messages.py
libeap/tests/hwsim/test_p2p_persistent.py
libeap/tests/hwsim/test_p2p_service.py
libeap/tests/hwsim/test_p2p_set.py
libeap/tests/hwsim/test_p2p_wifi_display.py
libeap/tests/hwsim/test_p2ps.py
libeap/tests/hwsim/test_peerkey.py
libeap/tests/hwsim/test_pmksa_cache.py
libeap/tests/hwsim/test_radio_work.py
libeap/tests/hwsim/test_radius.py
libeap/tests/hwsim/test_rfkill.py
libeap/tests/hwsim/test_sae.py
libeap/tests/hwsim/test_scan.py
libeap/tests/hwsim/test_ssid.py
libeap/tests/hwsim/test_sta_dynamic.py
libeap/tests/hwsim/test_suite_b.py
libeap/tests/hwsim/test_tnc.py
libeap/tests/hwsim/test_wep.py
libeap/tests/hwsim/test_wext.py
libeap/tests/hwsim/test_wnm.py
libeap/tests/hwsim/test_wpas_ap.py
libeap/tests/hwsim/test_wpas_config.py
libeap/tests/hwsim/test_wpas_ctrl.py
libeap/tests/hwsim/test_wpas_mesh.py
libeap/tests/hwsim/test_wpas_wmm_ac.py
libeap/tests/hwsim/tnc/.gitignore
libeap/tests/hwsim/tnc/Makefile
libeap/tests/hwsim/tnc/hostap2_imc.c
libeap/tests/hwsim/tnc/hostap2_imv.c
libeap/tests/hwsim/tnc/hostap_imc.c
libeap/tests/hwsim/tnc/hostap_imv.c
libeap/tests/hwsim/tnc/tnc_config
libeap/tests/hwsim/tshark.py
libeap/tests/hwsim/utils.py
libeap/tests/hwsim/vm/.gitignore
libeap/tests/hwsim/vm/README
libeap/tests/hwsim/vm/build-codecov.sh
libeap/tests/hwsim/vm/combine-codecov.sh
libeap/tests/hwsim/vm/dbus.conf
libeap/tests/hwsim/vm/inside.sh
libeap/tests/hwsim/vm/kernel-config
libeap/tests/hwsim/vm/parallel-vm.py
libeap/tests/hwsim/vm/parallel-vm.sh
libeap/tests/hwsim/vm/process-codecov.sh
libeap/tests/hwsim/vm/uevent.sh
libeap/tests/hwsim/vm/vm-run.sh
libeap/tests/hwsim/w1fi_logo.png
libeap/tests/hwsim/wlantest.py
libeap/tests/hwsim/wpasupplicant.py
libeap/tests/hwsim/wps-mixed-cred
libeap/tests/hwsim/wps-wep-cred
libeap/tests/p2p-fuzzer/Makefile
libeap/tests/p2p-fuzzer/go-neg-req.dat
libeap/tests/p2p-fuzzer/invitation-req.dat
libeap/tests/p2p-fuzzer/p2p-fuzzer.c
libeap/tests/p2p-fuzzer/p2ps-pd-req.dat
libeap/tests/p2p-fuzzer/proberesp-go.dat
libeap/tests/p2p-fuzzer/proberesp.dat
libeap/tests/test-aes.c
libeap/tests/test-asn1.c
libeap/tests/test-base64.c
libeap/tests/test-https.c
libeap/tests/test-list.c
libeap/tests/test-md4.c
libeap/tests/test-milenage.c
libeap/tests/test-rc4.c
libeap/tests/test-rsa-sig-ver.c
libeap/tests/test-sha1.c
libeap/tests/test-sha256.c
libeap/tests/test-x509.c
libeap/tests/test-x509v3.c
libeap/tests/test_x509v3_nist2.sh
libeap/tests/wnm-fuzzer/Makefile
libeap/tests/wnm-fuzzer/bss-tm-req.dat
libeap/tests/wnm-fuzzer/wnm-fuzzer.c
libeap/tests/wnm-fuzzer/wnm-notif.dat
libeap/wlantest/Makefile
libeap/wlantest/bip.c
libeap/wlantest/bss.c
libeap/wlantest/ccmp.c
libeap/wlantest/crc32.c
libeap/wlantest/ctrl.c
libeap/wlantest/gcmp.c
libeap/wlantest/inject.c
libeap/wlantest/monitor.c
libeap/wlantest/process.c
libeap/wlantest/readpcap.c
libeap/wlantest/rx_data.c
libeap/wlantest/rx_eapol.c
libeap/wlantest/rx_ip.c
libeap/wlantest/rx_mgmt.c
libeap/wlantest/rx_tdls.c
libeap/wlantest/sta.c
libeap/wlantest/test_vectors.c
libeap/wlantest/tkip.c
libeap/wlantest/wep.c
libeap/wlantest/wired.c
libeap/wlantest/wlantest.c
libeap/wlantest/wlantest.h
libeap/wlantest/wlantest_cli.c
libeap/wlantest/wlantest_ctrl.h
libeap/wlantest/writepcap.c
libeap/wpa_supplicant/.gitignore
libeap/wpa_supplicant/Android.mk
libeap/wpa_supplicant/ChangeLog
libeap/wpa_supplicant/Makefile
libeap/wpa_supplicant/README
libeap/wpa_supplicant/README-HS20
libeap/wpa_supplicant/README-P2P
libeap/wpa_supplicant/README-WPS
libeap/wpa_supplicant/README-Windows.txt
libeap/wpa_supplicant/android.config
libeap/wpa_supplicant/ap.c
libeap/wpa_supplicant/ap.h
libeap/wpa_supplicant/autoscan.c
libeap/wpa_supplicant/autoscan.h
libeap/wpa_supplicant/autoscan_exponential.c
libeap/wpa_supplicant/autoscan_periodic.c
libeap/wpa_supplicant/bgscan.c
libeap/wpa_supplicant/bgscan.h
libeap/wpa_supplicant/bgscan_learn.c
libeap/wpa_supplicant/bgscan_simple.c
libeap/wpa_supplicant/blacklist.c
libeap/wpa_supplicant/blacklist.h
libeap/wpa_supplicant/bss.c
libeap/wpa_supplicant/bss.h
libeap/wpa_supplicant/config.c
libeap/wpa_supplicant/config.h
libeap/wpa_supplicant/config_file.c
libeap/wpa_supplicant/config_none.c
libeap/wpa_supplicant/config_ssid.h
libeap/wpa_supplicant/config_winreg.c
libeap/wpa_supplicant/ctrl_iface.c
libeap/wpa_supplicant/ctrl_iface.h
libeap/wpa_supplicant/ctrl_iface_named_pipe.c
libeap/wpa_supplicant/ctrl_iface_udp.c
libeap/wpa_supplicant/ctrl_iface_unix.c
libeap/wpa_supplicant/dbus/Makefile
libeap/wpa_supplicant/dbus/dbus_common.c
libeap/wpa_supplicant/dbus/dbus_common.h
libeap/wpa_supplicant/dbus/dbus_common_i.h
libeap/wpa_supplicant/dbus/dbus_dict_helpers.c
libeap/wpa_supplicant/dbus/dbus_dict_helpers.h
libeap/wpa_supplicant/dbus/dbus_new.c
libeap/wpa_supplicant/dbus/dbus_new.h
libeap/wpa_supplicant/dbus/dbus_new_handlers.c
libeap/wpa_supplicant/dbus/dbus_new_handlers.h
libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
libeap/wpa_supplicant/dbus/dbus_new_handlers_wps.c
libeap/wpa_supplicant/dbus/dbus_new_helpers.c
libeap/wpa_supplicant/dbus/dbus_new_helpers.h
libeap/wpa_supplicant/dbus/dbus_new_introspect.c
libeap/wpa_supplicant/dbus/dbus_old.c
libeap/wpa_supplicant/dbus/dbus_old.h
libeap/wpa_supplicant/dbus/dbus_old_handlers.c
libeap/wpa_supplicant/dbus/dbus_old_handlers.h
libeap/wpa_supplicant/dbus/dbus_old_handlers_wps.c
libeap/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in
libeap/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in
libeap/wpa_supplicant/defconfig
libeap/wpa_supplicant/doc/docbook/Makefile
libeap/wpa_supplicant/doc/docbook/eapol_test.sgml
libeap/wpa_supplicant/doc/docbook/wpa_background.sgml
libeap/wpa_supplicant/doc/docbook/wpa_cli.sgml
libeap/wpa_supplicant/doc/docbook/wpa_gui.sgml
libeap/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
libeap/wpa_supplicant/doc/docbook/wpa_priv.sgml
libeap/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
libeap/wpa_supplicant/driver_i.h
libeap/wpa_supplicant/eap_proxy_dummy.mak
libeap/wpa_supplicant/eap_proxy_dummy.mk
libeap/wpa_supplicant/eap_register.c
libeap/wpa_supplicant/eapol_test.c
libeap/wpa_supplicant/eapol_test.py
libeap/wpa_supplicant/events.c
libeap/wpa_supplicant/examples/dbus-listen-preq.py
libeap/wpa_supplicant/examples/p2p-action.sh
libeap/wpa_supplicant/examples/p2p-nfc.py
libeap/wpa_supplicant/examples/p2p/p2p_connect.py
libeap/wpa_supplicant/examples/p2p/p2p_disconnect.py
libeap/wpa_supplicant/examples/p2p/p2p_find.py
libeap/wpa_supplicant/examples/p2p/p2p_flush.py
libeap/wpa_supplicant/examples/p2p/p2p_group_add.py
libeap/wpa_supplicant/examples/p2p/p2p_invite.py
libeap/wpa_supplicant/examples/p2p/p2p_listen.py
libeap/wpa_supplicant/examples/p2p/p2p_stop_find.py
libeap/wpa_supplicant/examples/udhcpd-p2p.conf
libeap/wpa_supplicant/examples/wpas-dbus-new-signals.py
libeap/wpa_supplicant/examples/wps-ap-cli
libeap/wpa_supplicant/examples/wps-nfc.py
libeap/wpa_supplicant/gas_query.c
libeap/wpa_supplicant/gas_query.h
libeap/wpa_supplicant/hs20_supplicant.c
libeap/wpa_supplicant/hs20_supplicant.h
libeap/wpa_supplicant/ibss_rsn.c
libeap/wpa_supplicant/ibss_rsn.h
libeap/wpa_supplicant/interworking.c
libeap/wpa_supplicant/interworking.h
libeap/wpa_supplicant/main.c
libeap/wpa_supplicant/main_none.c
libeap/wpa_supplicant/main_winmain.c
libeap/wpa_supplicant/main_winsvc.c
libeap/wpa_supplicant/mesh.c
libeap/wpa_supplicant/mesh.h
libeap/wpa_supplicant/mesh_mpm.c
libeap/wpa_supplicant/mesh_mpm.h
libeap/wpa_supplicant/mesh_rsn.c
libeap/wpa_supplicant/mesh_rsn.h
libeap/wpa_supplicant/nfc_pw_token.c
libeap/wpa_supplicant/notify.c
libeap/wpa_supplicant/notify.h
libeap/wpa_supplicant/offchannel.c
libeap/wpa_supplicant/offchannel.h
libeap/wpa_supplicant/p2p_supplicant.c
libeap/wpa_supplicant/p2p_supplicant.h
libeap/wpa_supplicant/p2p_supplicant_sd.c
libeap/wpa_supplicant/preauth_test.c
libeap/wpa_supplicant/scan.c
libeap/wpa_supplicant/scan.h
libeap/wpa_supplicant/sme.c
libeap/wpa_supplicant/sme.h
libeap/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in
libeap/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in
libeap/wpa_supplicant/systemd/wpa_supplicant.service.arg.in
libeap/wpa_supplicant/systemd/wpa_supplicant.service.in
libeap/wpa_supplicant/tests/test_eap_sim_common.c
libeap/wpa_supplicant/tests/test_wpa.c
libeap/wpa_supplicant/todo.txt
libeap/wpa_supplicant/utils/log2pcap.py
libeap/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
libeap/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
libeap/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
libeap/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
libeap/wpa_supplicant/wifi_display.c
libeap/wpa_supplicant/wifi_display.h
libeap/wpa_supplicant/win_if_list.c
libeap/wpa_supplicant/wmm_ac.c
libeap/wpa_supplicant/wmm_ac.h
libeap/wpa_supplicant/wnm_sta.c
libeap/wpa_supplicant/wnm_sta.h
libeap/wpa_supplicant/wpa_cli.c
libeap/wpa_supplicant/wpa_gui-qt4/addinterface.cpp
libeap/wpa_supplicant/wpa_gui-qt4/addinterface.h
libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp
libeap/wpa_supplicant/wpa_gui-qt4/eventhistory.h
libeap/wpa_supplicant/wpa_gui-qt4/main.cpp
libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
libeap/wpa_supplicant/wpa_gui-qt4/networkconfig.h
libeap/wpa_supplicant/wpa_gui-qt4/peers.cpp
libeap/wpa_supplicant/wpa_gui-qt4/peers.h
libeap/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
libeap/wpa_supplicant/wpa_gui-qt4/scanresults.h
libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp
libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h
libeap/wpa_supplicant/wpa_gui-qt4/signalbar.cpp
libeap/wpa_supplicant/wpa_gui-qt4/signalbar.h
libeap/wpa_supplicant/wpa_gui-qt4/stringquery.cpp
libeap/wpa_supplicant/wpa_gui-qt4/stringquery.h
libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp
libeap/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
libeap/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
libeap/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
libeap/wpa_supplicant/wpa_gui-qt4/wpagui.h
libeap/wpa_supplicant/wpa_gui-qt4/wpamsg.h
libeap/wpa_supplicant/wpa_passphrase.c
libeap/wpa_supplicant/wpa_priv.c
libeap/wpa_supplicant/wpa_supplicant.c
libeap/wpa_supplicant/wpa_supplicant.conf
libeap/wpa_supplicant/wpa_supplicant_conf.mk
libeap/wpa_supplicant/wpa_supplicant_conf.sh
libeap/wpa_supplicant/wpa_supplicant_i.h
libeap/wpa_supplicant/wpa_supplicant_template.conf
libeap/wpa_supplicant/wpas_glue.c
libeap/wpa_supplicant/wpas_glue.h
libeap/wpa_supplicant/wpas_kay.c
libeap/wpa_supplicant/wpas_kay.h
libeap/wpa_supplicant/wpas_module_tests.c
libeap/wpa_supplicant/wps_supplicant.c
libeap/wpa_supplicant/wps_supplicant.h
libeap/wpadebug/AndroidManifest.xml
libeap/wpadebug/README
libeap/wpadebug/build.xml
libeap/wpadebug/project.properties
libeap/wpadebug/res/layout/cred_edit.xml
libeap/wpadebug/res/layout/main.xml
libeap/wpadebug/res/raw/shell_commands.txt
libeap/wpadebug/res/raw/wpa_commands.txt
libeap/wpadebug/src/w1/fi/wpadebug/CommandListActivity.java
libeap/wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java
libeap/wpadebug/src/w1/fi/wpadebug/MainActivity.java
libeap/wpadebug/src/w1/fi/wpadebug/WifiReceiver.java
libeap/wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java
libeap/wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java
libeap/wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java
libeap/wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java
libeap/wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java
libeap/wpaspy/Makefile
libeap/wpaspy/setup.py
libeap/wpaspy/test.py
libeap/wpaspy/wpaspy.c
libeap/wpaspy/wpaspy.py
mech_eap/gssapiP_eap.h
mech_eap/init_sec_context.c

diff --cc .gitignore
@@@ -1,16 -1,30 +1,46 @@@
 +Makefile.in
 +aclocal.m4
 +autom4te.cache
 +configure
 +config.*
 +ltmain.sh
 +libtool
 +depcomp
 +m4
 +!m4/minuso.m4
 +build-aux
 +!build-aux/compile
 +mech_eap.spec
 +mech_eap*tar*
 +*.lo
+ *.o
+ *.d
+ *.gcno
+ *.gcda
+ *.gcov
+ *.pyc
 +*#
+ *~
+ .config
+ tests/hwsim/logs
+ wpaspy/build
+ wpa_supplicant/eapol_test
+ wpa_supplicant/nfc_pw_token
+ 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
+ mac80211_hwsim/tools/hwsim_test
+ wlantest/libwlantest.a
+ wlantest/test_vectors
+ wlantest/wlantest
+ wlantest/wlantest_cli
index 0000000,bd7a409..bd7a409
mode 000000,100644..100644
--- /dev/null
diff --cc libeap/COPYING
Simple merge
index 77ee4c0,0000000..890a9ea
mode 100644,000000..100644
--- /dev/null
@@@ -1,199 -1,0 +1,212 @@@
-     src/crypto/md5-non-fips.c \
 +AUTOMAKE_OPTIONS = foreign
 +
 +AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils @OPENSSL_CFLAGS@
 +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 \
 +      wpa_supplicant/README
 +
 +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_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
 +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 \
 +      src/radius/radius.h
 +
 +
 +AM_CFLAGS = -DEAP_TLS
 +AM_CFLAGS += -DEAP_PEAP
 +AM_CFLAGS += -DEAP_TTLS
 +AM_CFLAGS += -DEAP_MD5
 +AM_CFLAGS += -DEAP_MSCHAPv2
 +AM_CFLAGS += -DEAP_GTC
 +AM_CFLAGS += -DEAP_OTP
 +AM_CFLAGS += -DEAP_LEAP
 +AM_CFLAGS += -DEAP_PSK
 +AM_CFLAGS += -DEAP_PAX
 +AM_CFLAGS += -DEAP_SAKE
 +AM_CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256
 +
 +AM_CFLAGS += -DEAP_SERVER_IDENTITY
 +AM_CFLAGS += -DEAP_SERVER_TLS
 +AM_CFLAGS += -DEAP_SERVER_PEAP
 +AM_CFLAGS += -DEAP_SERVER_TTLS
 +AM_CFLAGS += -DEAP_SERVER_MD5
 +AM_CFLAGS += -DEAP_SERVER_MSCHAPV2
 +AM_CFLAGS += -DEAP_SERVER_GTC
 +AM_CFLAGS += -DEAP_SERVER_PSK
 +AM_CFLAGS += -DEAP_SERVER_PAX
 +AM_CFLAGS += -DEAP_SERVER_SAKE
 +AM_CFLAGS += -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256
 +
 +AM_CFLAGS += -DIEEE8021X_EAPOL
 +AM_CFLAGS += -DCONFIG_IPV6
 +AM_CFLAGS += -DCONFIG_DEBUG_FILE
 +AM_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
 +AM_CFLAGS += -DCONFIG_INTERNAL_SHA1
 +AM_CFLAGS += -DEAP_TLS_OPENSSL
 +AM_CFLAGS += -DPKCS12_FUNCS
 +AM_CFLAGS += -DCONFIG_SHA256
 +
 +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/utils/os_unix.c \
 +      src/utils/radius_utils.c \
 +src/utils/radius_utils.h \
 +      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-ccm.c \
 +    src/crypto/aes-ctr.c \
 +    src/crypto/aes-eax.c \
 +    src/crypto/aes-encblock.c \
++    src/crypto/aes-gcm.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-siv.c \
++    src/crypto/aes-siv.h \
 +    src/crypto/aes-unwrap.c \
 +    src/crypto/aes-wrap.c \
++    src/crypto/aes.h \
++    src/crypto/aes_i.h \
++    src/crypto/aes_wrap.h \
++    src/crypto/crypto.h \
++    src/crypto/des-internal.c \
++    src/crypto/dh_group5.h \
++    src/crypto/dh_groups.h \
++    src/crypto/md4-internal.c \
 +    src/crypto/md5.c \
-     src/crypto/crypto_openssl.c \
-     src/crypto/tls_openssl.c \
-     src/crypto/aes.h \
-     src/crypto/aes_i.h \
-     src/crypto/aes_wrap.h \
-     src/crypto/crypto.h \
-       src/crypto/dh_group5.h \
-       src/crypto/dh_groups.h \
-     src/crypto/md5.h \
-     src/crypto/milenage.h \
-     src/crypto/ms_funcs.h \
-     src/crypto/sha1.h \
++    src/crypto/md5-internal.c \
++    src/crypto/md5.h \
 +    src/crypto/milenage.c \
++    src/crypto/milenage.h \
 +    src/crypto/ms_funcs.c \
++    src/crypto/ms_funcs.h \
++    src/crypto/rc4.c \
 +    src/crypto/sha1.c \
++    src/crypto/sha1-internal.c \
 +    src/crypto/sha1-pbkdf2.c \
++    src/crypto/sha1-prf.c \
 +    src/crypto/sha1-tlsprf.c \
 +    src/crypto/sha1-tprf.c \
++    src/crypto/sha256-prf.c \
++    src/crypto/sha256-tlsprf.c \
 +    src/crypto/sha256.c \
 +    src/crypto/sha256.h \
++    src/crypto/sha256_i.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)
 +
 +noinst_LTLIBRARIES = libeap.la
diff --cc libeap/README
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,c1a81db..c1a81db
mode 000000,100644..100644
--- /dev/null
index 0000000,27ae0e2..27ae0e2
mode 000000,100644..100644
--- /dev/null
index 0000000,9c7b4b5..9c7b4b5
mode 000000,100644..100644
--- /dev/null
index 0000000,640caef..640caef
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,7bc8325..7bc8325
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,5885f2b..5885f2b
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,0b1d7c7..0b1d7c7
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,f7887eb..f7887eb
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,097bbce..097bbce
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,826db34..826db34
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,2fc3012..2fc3012
mode 000000,100755..100755
--- /dev/null
index 0000000,b23ac17..b23ac17
mode 000000,100644..100644
--- /dev/null
index 0000000,94cd5f1..94cd5f1
mode 000000,100644..100644
--- /dev/null
index 0000000,6d0389e..6d0389e
mode 000000,100644..100644
--- /dev/null
index 0000000,d48a520..d48a520
mode 000000,100644..100644
--- /dev/null
index 0000000,ec05bc4..ec05bc4
mode 000000,100644..100644
--- /dev/null
index 0000000,5854b72..5854b72
mode 000000,100644..100644
--- /dev/null
index 0000000,0315f7b..0315f7b
mode 000000,100644..100644
--- /dev/null
index 0000000,9a7059e..9a7059e
mode 000000,100644..100644
--- /dev/null
index 0000000,c619541..c619541
mode 000000,100644..100644
--- /dev/null
index 0000000,248ed5c..248ed5c
mode 000000,100644..100644
--- /dev/null
index 0000000,c72dcbd..c72dcbd
mode 000000,100755..100755
--- /dev/null
index 0000000,b50ea00..b50ea00
mode 000000,100644..100644
--- /dev/null
index 0000000,0b73a04..0b73a04
mode 000000,100755..100755
--- /dev/null
index 0000000,a829ff2..a829ff2
mode 000000,100644..100644
--- /dev/null
index 0000000,931a206..931a206
mode 000000,100755..100755
--- /dev/null
index 0000000,5bc50be..5bc50be
mode 000000,100644..100644
--- /dev/null
index 0000000,6141013..6141013
mode 000000,100644..100644
--- /dev/null
index 0000000,78abccc..78abccc
mode 000000,100755..100755
--- /dev/null
index 0000000,ac7c259..ac7c259
mode 000000,100644..100644
Binary files differ
index 0000000,001d6f2..001d6f2
mode 000000,100644..100644
--- /dev/null
index 0000000,591f66b..591f66b
mode 000000,100644..100644
--- /dev/null
index 0000000,33e3fa1..33e3fa1
mode 000000,100644..100644
--- /dev/null
index 0000000,7b27be3..7b27be3
mode 000000,100644..100644
--- /dev/null
index 0000000,20dcf2f..20dcf2f
mode 000000,100644..100644
--- /dev/null
index 0000000,6609538..6609538
mode 000000,100644..100644
--- /dev/null
index 0000000,1efc655..1efc655
mode 000000,100644..100644
--- /dev/null
index 0000000,a3b4513..a3b4513
mode 000000,100644..100644
--- /dev/null
index 0000000,f023ca5..f023ca5
mode 000000,100644..100644
--- /dev/null
index 0000000,e3af435..e3af435
mode 000000,100644..100644
--- /dev/null
index 0000000,a45648b..a45648b
mode 000000,100644..100644
--- /dev/null
index 0000000,8195069..8195069
mode 000000,100644..100644
--- /dev/null
index 0000000,8fc9cd6..8fc9cd6
mode 000000,100644..100644
--- /dev/null
index 0000000,392a7bd..392a7bd
mode 000000,100644..100644
--- /dev/null
index 0000000,aeb2f68..aeb2f68
mode 000000,100644..100644
--- /dev/null
index 0000000,dde4434..dde4434
mode 000000,100644..100644
--- /dev/null
index 0000000,c340a33..c340a33
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,03d797f..03d797f
mode 000000,100644..100644
--- /dev/null
index 0000000,fc85259..fc85259
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,fb63942..fb63942
mode 000000,100644..100644
--- /dev/null
index 0000000,ac3c793..ac3c793
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,715f19b..715f19b
mode 000000,100644..100644
--- /dev/null
index 0000000,be8c0e6..be8c0e6
mode 000000,100644..100644
--- /dev/null
index 0000000,3a77225..3a77225
mode 000000,100644..100644
--- /dev/null
index 0000000,93d0050..93d0050
mode 000000,100644..100644
--- /dev/null
Simple merge
index 0000000,082d0f5..082d0f5
mode 000000,100644..100644
--- /dev/null
index 0000000,9d19f98..9d19f98
mode 000000,100644..100644
--- /dev/null
index 0000000,4ec3201..4ec3201
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,d7909fa..d7909fa
mode 000000,100644..100644
--- /dev/null
index 0000000,152439f..152439f
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,d462ac8..d462ac8
mode 000000,100644..100644
--- /dev/null
index 0000000,5bf1b5d..5bf1b5d
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,4a87721..4a87721
mode 000000,100644..100644
--- /dev/null
index 0000000,3cc9a55..3cc9a55
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,d4e0efb..d4e0efb
mode 000000,100644..100644
--- /dev/null
index 0000000,bef5a16..bef5a16
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,4c8bc10..4c8bc10
mode 000000,100644..100644
--- /dev/null
index 0000000,7789307..7789307
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,aef9a53..aef9a53
mode 000000,100644..100644
--- /dev/null
index 0000000,e43a78d..e43a78d
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,cff9254..cff9254
mode 000000,100644..100644
--- /dev/null
index 0000000,306adc5..306adc5
mode 000000,100644..100644
--- /dev/null
index 0000000,9c37ea6..9c37ea6
mode 000000,100644..100644
--- /dev/null
index 0000000,7360b4e..7360b4e
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,cc88caa..cc88caa
mode 000000,100644..100644
--- /dev/null
Simple merge
index 0000000,6f51803..6f51803
mode 000000,100644..100644
--- /dev/null
index 0000000,28985f5..28985f5
mode 000000,100644..100644
--- /dev/null
index 0000000,503fa1d..503fa1d
mode 000000,100644..100644
--- /dev/null
index 0000000,c07026c..c07026c
mode 000000,100644..100644
--- /dev/null
index 0000000,108acf9..108acf9
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,28913b9..28913b9
mode 000000,100644..100644
--- /dev/null
index 0000000,54c2872..54c2872
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,cf22778..cf22778
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,84294d2..84294d2
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,5ac82c2..5ac82c2
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,463cf65..463cf65
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,3a86a93..3a86a93
mode 000000,100644..100644
--- /dev/null
index 0000000,d13e1c4..d13e1c4
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,4b2d137..4b2d137
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,e7509ce..e7509ce
mode 000000,100644..100644
--- /dev/null
index 0000000,79791c0..79791c0
mode 000000,100644..100644
--- /dev/null
index 0000000,0528dad..0528dad
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,a502d2b..a502d2b
mode 000000,100644..100644
--- /dev/null
index 0000000,653920b..653920b
mode 000000,100644..100644
--- /dev/null
index 0000000,3deafa5..3deafa5
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
index d155c09,0000000..0a8ae57
mode 100644,000000..100644
--- /dev/null
@@@ -1,2919 -1,0 +1,4148 @@@
-  * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
 +/*
 + * SSL/TLS interface functions for OpenSSL
-  * 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.
++ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
 + *
- #if OPENSSL_VERSION_NUMBER >= 0x0090800fL
- #define OPENSSL_d2i_TYPE const unsigned char **
- #else
- #define OPENSSL_d2i_TYPE unsigned char **
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#include "includes.h"
 +
 +#ifndef CONFIG_SMARTCARD
 +#ifndef OPENSSL_NO_ENGINE
++#ifndef ANDROID
 +#define OPENSSL_NO_ENGINE
 +#endif
 +#endif
++#endif
 +
 +#include <openssl/ssl.h>
 +#include <openssl/err.h>
 +#include <openssl/pkcs12.h>
 +#include <openssl/x509v3.h>
 +#ifndef OPENSSL_NO_ENGINE
 +#include <openssl/engine.h>
 +#endif /* OPENSSL_NO_ENGINE */
++#ifndef OPENSSL_NO_DSA
++#include <openssl/dsa.h>
++#endif
++#ifndef OPENSSL_NO_DH
++#include <openssl/dh.h>
++#endif
 +
 +#include "common.h"
 +#include "crypto.h"
++#include "sha1.h"
++#include "sha256.h"
 +#include "tls.h"
 +
- #ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
- #ifdef SSL_OP_NO_TICKET
- /*
-  * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
-  * 2008-11-15. This version uses a bit different API compared to the old patch.
-  */
- #define CONFIG_OPENSSL_TICKET_OVERRIDE
- #endif
++#if OPENSSL_VERSION_NUMBER < 0x10000000L
++/* ERR_remove_thread_state replaces ERR_remove_state and the latter is
++ * deprecated. However, OpenSSL 0.9.8 doesn't include
++ * ERR_remove_thread_state. */
++#define ERR_remove_thread_state(tid) ERR_remove_state(0)
 +#endif
 +
- struct tls_global {
++#if defined(OPENSSL_IS_BORINGSSL)
++/* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
++typedef size_t stack_index_t;
++#else
++typedef int stack_index_t;
 +#endif
 +
++#ifdef SSL_set_tlsext_status_type
++#ifndef OPENSSL_NO_TLSEXT
++#define HAVE_OCSP
++#include <openssl/ocsp.h>
++#endif /* OPENSSL_NO_TLSEXT */
++#endif /* SSL_set_tlsext_status_type */
++
++#ifdef ANDROID
++#include <openssl/pem.h>
++#include <keystore/keystore_get.h>
++
++static BIO * BIO_from_keystore(const char *key)
++{
++      BIO *bio = NULL;
++      uint8_t *value = NULL;
++      int length = keystore_get(key, strlen(key), &value);
++      if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
++              BIO_write(bio, value, length);
++      free(value);
++      return bio;
++}
++#endif /* ANDROID */
++
 +static int tls_openssl_ref_count = 0;
++static int tls_ex_idx_session = -1;
 +
- static struct tls_global *tls_global = NULL;
++struct tls_context {
 +      void (*event_cb)(void *ctx, enum tls_event ev,
 +                       union tls_event_data *data);
 +      void *cb_ctx;
++      int cert_in_cb;
++      char *ocsp_stapling_response;
 +};
 +
-       char *subject_match, *altsubject_match;
++static struct tls_context *tls_global = NULL;
++
 +
++struct tls_data {
++      SSL_CTX *ssl;
++      unsigned int tls_session_lifetime;
++};
 +
 +struct tls_connection {
++      struct tls_context *context;
++      SSL_CTX *ssl_ctx;
 +      SSL *ssl;
 +      BIO *ssl_in, *ssl_out;
 +#ifndef OPENSSL_NO_ENGINE
 +      ENGINE *engine;        /* functional reference to the engine */
 +      EVP_PKEY *private_key; /* the private key if using engine */
 +#endif /* OPENSSL_NO_ENGINE */
-       cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded,
++      char *subject_match, *altsubject_match, *suffix_match, *domain_match;
 +      int read_alerts, write_alerts, failed;
 +
 +      tls_session_ticket_cb session_ticket_cb;
 +      void *session_ticket_cb_ctx;
 +
 +      /* SessionTicket received from OpenSSL hello_extension_cb (server) */
 +      u8 *session_ticket;
 +      size_t session_ticket_len;
 +
 +      unsigned int ca_cert_verify:1;
 +      unsigned int cert_probe:1;
 +      unsigned int server_cert_only:1;
++      unsigned int invalid_hb_used:1;
++      unsigned int success_data:1;
 +
 +      u8 srv_cert_hash[32];
++
++      unsigned int flags;
++
++      X509 *peer_cert;
++      X509 *peer_issuer;
++      X509 *peer_issuer_issuer;
++
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++      unsigned char client_random[SSL3_RANDOM_SIZE];
++      unsigned char server_random[SSL3_RANDOM_SIZE];
++#endif
 +};
 +
 +
++static struct tls_context * tls_context_new(const struct tls_config *conf)
++{
++      struct tls_context *context = os_zalloc(sizeof(*context));
++      if (context == NULL)
++              return NULL;
++      if (conf) {
++              context->event_cb = conf->event_cb;
++              context->cb_ctx = conf->cb_ctx;
++              context->cert_in_cb = conf->cert_in_cb;
++      }
++      return context;
++}
++
++
 +#ifdef CONFIG_NO_STDOUT_DEBUG
 +
 +static void _tls_show_errors(void)
 +{
 +      unsigned long err;
 +
 +      while ((err = ERR_get_error())) {
 +              /* Just ignore the errors, since stdout is disabled */
 +      }
 +}
 +#define tls_show_errors(l, f, t) _tls_show_errors()
 +
 +#else /* CONFIG_NO_STDOUT_DEBUG */
 +
 +static void tls_show_errors(int level, const char *func, const char *txt)
 +{
 +      unsigned long err;
 +
 +      wpa_printf(level, "OpenSSL: %s - %s %s",
 +                 func, txt, ERR_error_string(ERR_get_error(), NULL));
 +
 +      while ((err = ERR_get_error())) {
 +              wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
 +                         ERR_error_string(err, NULL));
 +      }
 +}
 +
 +#endif /* CONFIG_NO_STDOUT_DEBUG */
 +
 +
 +#ifdef CONFIG_NATIVE_WINDOWS
 +
 +/* Windows CryptoAPI and access to certificate stores */
 +#include <wincrypt.h>
 +
 +#ifdef __MINGW32_VERSION
 +/*
 + * MinGW does not yet include all the needed definitions for CryptoAPI, so
 + * define here whatever extra is needed.
 + */
 +#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
 +#define CERT_STORE_READONLY_FLAG 0x00008000
 +#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
 +
 +#endif /* __MINGW32_VERSION */
 +
 +
 +struct cryptoapi_rsa_data {
 +      const CERT_CONTEXT *cert;
 +      HCRYPTPROV crypt_prov;
 +      DWORD key_spec;
 +      BOOL free_crypt_prov;
 +};
 +
 +
 +static void cryptoapi_error(const char *msg)
 +{
 +      wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
 +                 msg, (unsigned int) GetLastError());
 +}
 +
 +
 +static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
 +                               unsigned char *to, RSA *rsa, int padding)
 +{
 +      wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
 +      return 0;
 +}
 +
 +
 +static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
 +                               unsigned char *to, RSA *rsa, int padding)
 +{
 +      wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
 +      return 0;
 +}
 +
 +
 +static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
 +                                unsigned char *to, RSA *rsa, int padding)
 +{
 +      struct cryptoapi_rsa_data *priv =
 +              (struct cryptoapi_rsa_data *) rsa->meth->app_data;
 +      HCRYPTHASH hash;
 +      DWORD hash_size, len, i;
 +      unsigned char *buf = NULL;
 +      int ret = 0;
 +
 +      if (priv == NULL) {
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
 +                     ERR_R_PASSED_NULL_PARAMETER);
 +              return 0;
 +      }
 +
 +      if (padding != RSA_PKCS1_PADDING) {
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
 +                     RSA_R_UNKNOWN_PADDING_TYPE);
 +              return 0;
 +      }
 +
 +      if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
 +              wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
 +                         __func__);
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
 +                     RSA_R_INVALID_MESSAGE_LENGTH);
 +              return 0;
 +      }
 +
 +      if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
 +      {
 +              cryptoapi_error("CryptCreateHash failed");
 +              return 0;
 +      }
 +
 +      len = sizeof(hash_size);
 +      if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
 +                             0)) {
 +              cryptoapi_error("CryptGetHashParam failed");
 +              goto err;
 +      }
 +
 +      if ((int) hash_size != flen) {
 +              wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
 +                         (unsigned) hash_size, flen);
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
 +                     RSA_R_INVALID_MESSAGE_LENGTH);
 +              goto err;
 +      }
 +      if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
 +              cryptoapi_error("CryptSetHashParam failed");
 +              goto err;
 +      }
 +
 +      len = RSA_size(rsa);
 +      buf = os_malloc(len);
 +      if (buf == NULL) {
 +              RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
 +              goto err;
 +      }
 +
 +      if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
 +              cryptoapi_error("CryptSignHash failed");
 +              goto err;
 +      }
 +
 +      for (i = 0; i < len; i++)
 +              to[i] = buf[len - i - 1];
 +      ret = len;
 +
 +err:
 +      os_free(buf);
 +      CryptDestroyHash(hash);
 +
 +      return ret;
 +}
 +
 +
 +static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
 +                                unsigned char *to, RSA *rsa, int padding)
 +{
 +      wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
 +      return 0;
 +}
 +
 +
 +static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
 +{
 +      if (priv == NULL)
 +              return;
 +      if (priv->crypt_prov && priv->free_crypt_prov)
 +              CryptReleaseContext(priv->crypt_prov, 0);
 +      if (priv->cert)
 +              CertFreeCertificateContext(priv->cert);
 +      os_free(priv);
 +}
 +
 +
 +static int cryptoapi_finish(RSA *rsa)
 +{
 +      cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
 +      os_free((void *) rsa->meth);
 +      rsa->meth = NULL;
 +      return 1;
 +}
 +
 +
 +static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
 +{
 +      HCERTSTORE cs;
 +      const CERT_CONTEXT *ret = NULL;
 +
 +      cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
 +                         store | CERT_STORE_OPEN_EXISTING_FLAG |
 +                         CERT_STORE_READONLY_FLAG, L"MY");
 +      if (cs == NULL) {
 +              cryptoapi_error("Failed to open 'My system store'");
 +              return NULL;
 +      }
 +
 +      if (strncmp(name, "cert://", 7) == 0) {
 +              unsigned short wbuf[255];
 +              MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
 +              ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
 +                                               PKCS_7_ASN_ENCODING,
 +                                               0, CERT_FIND_SUBJECT_STR,
 +                                               wbuf, NULL);
 +      } else if (strncmp(name, "hash://", 7) == 0) {
 +              CRYPT_HASH_BLOB blob;
 +              int len;
 +              const char *hash = name + 7;
 +              unsigned char *buf;
 +
 +              len = os_strlen(hash) / 2;
 +              buf = os_malloc(len);
 +              if (buf && hexstr2bin(hash, buf, len) == 0) {
 +                      blob.cbData = len;
 +                      blob.pbData = buf;
 +                      ret = CertFindCertificateInStore(cs,
 +                                                       X509_ASN_ENCODING |
 +                                                       PKCS_7_ASN_ENCODING,
 +                                                       0, CERT_FIND_HASH,
 +                                                       &blob, NULL);
 +              }
 +              os_free(buf);
 +      }
 +
 +      CertCloseStore(cs, 0);
 +
 +      return ret;
 +}
 +
 +
 +static int tls_cryptoapi_cert(SSL *ssl, const char *name)
 +{
 +      X509 *cert = NULL;
 +      RSA *rsa = NULL, *pub_rsa;
 +      struct cryptoapi_rsa_data *priv;
 +      RSA_METHOD *rsa_meth;
 +
 +      if (name == NULL ||
 +          (strncmp(name, "cert://", 7) != 0 &&
 +           strncmp(name, "hash://", 7) != 0))
 +              return -1;
 +
 +      priv = os_zalloc(sizeof(*priv));
 +      rsa_meth = os_zalloc(sizeof(*rsa_meth));
 +      if (priv == NULL || rsa_meth == NULL) {
 +              wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
 +                         "for CryptoAPI RSA method");
 +              os_free(priv);
 +              os_free(rsa_meth);
 +              return -1;
 +      }
 +
 +      priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
 +      if (priv->cert == NULL) {
 +              priv->cert = cryptoapi_find_cert(
 +                      name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
 +      }
 +      if (priv->cert == NULL) {
 +              wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
 +                         "'%s'", name);
 +              goto err;
 +      }
 +
-               cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded,
++      cert = d2i_X509(NULL,
++                      (const unsigned char **) &priv->cert->pbCertEncoded,
 +                      priv->cert->cbCertEncoded);
 +      if (cert == NULL) {
 +              wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
 +                         "encoding");
 +              goto err;
 +      }
 +
 +      if (!CryptAcquireCertificatePrivateKey(priv->cert,
 +                                             CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
 +                                             NULL, &priv->crypt_prov,
 +                                             &priv->key_spec,
 +                                             &priv->free_crypt_prov)) {
 +              cryptoapi_error("Failed to acquire a private key for the "
 +                              "certificate");
 +              goto err;
 +      }
 +
 +      rsa_meth->name = "Microsoft CryptoAPI RSA Method";
 +      rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
 +      rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
 +      rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
 +      rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
 +      rsa_meth->finish = cryptoapi_finish;
 +      rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
 +      rsa_meth->app_data = (char *) priv;
 +
 +      rsa = RSA_new();
 +      if (rsa == NULL) {
 +              SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
 +                     ERR_R_MALLOC_FAILURE);
 +              goto err;
 +      }
 +
 +      if (!SSL_use_certificate(ssl, cert)) {
 +              RSA_free(rsa);
 +              rsa = NULL;
 +              goto err;
 +      }
 +      pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
 +      X509_free(cert);
 +      cert = NULL;
 +
 +      rsa->n = BN_dup(pub_rsa->n);
 +      rsa->e = BN_dup(pub_rsa->e);
 +      if (!RSA_set_method(rsa, rsa_meth))
 +              goto err;
 +
 +      if (!SSL_use_RSAPrivateKey(ssl, rsa))
 +              goto err;
 +      RSA_free(rsa);
 +
 +      return 0;
 +
 +err:
 +      if (cert)
 +              X509_free(cert);
 +      if (rsa)
 +              RSA_free(rsa);
 +      else {
 +              os_free(rsa_meth);
 +              cryptoapi_free_data(priv);
 +      }
 +      return -1;
 +}
 +
 +
 +static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
 +{
 +      HCERTSTORE cs;
 +      PCCERT_CONTEXT ctx = NULL;
 +      X509 *cert;
 +      char buf[128];
 +      const char *store;
 +#ifdef UNICODE
 +      WCHAR *wstore;
 +#endif /* UNICODE */
 +
 +      if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
 +              return -1;
 +
 +      store = name + 13;
 +#ifdef UNICODE
 +      wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
 +      if (wstore == NULL)
 +              return -1;
 +      wsprintf(wstore, L"%S", store);
 +      cs = CertOpenSystemStore(0, wstore);
 +      os_free(wstore);
 +#else /* UNICODE */
 +      cs = CertOpenSystemStore(0, store);
 +#endif /* UNICODE */
 +      if (cs == NULL) {
 +              wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
 +                         "'%s': error=%d", __func__, store,
 +                         (int) GetLastError());
 +              return -1;
 +      }
 +
 +      while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
-                       struct tls_connection *conn =
-                               SSL_get_app_data((SSL *) ssl);
++              cert = d2i_X509(NULL,
++                              (const unsigned char **) &ctx->pbCertEncoded,
 +                              ctx->cbCertEncoded);
 +              if (cert == NULL) {
 +                      wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
 +                                 "X509 DER encoding for CA cert");
 +                      continue;
 +              }
 +
 +              X509_NAME_oneline(X509_get_subject_name(cert), buf,
 +                                sizeof(buf));
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
 +                         "system certificate store: subject='%s'", buf);
 +
 +              if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
 +                      tls_show_errors(MSG_WARNING, __func__,
 +                                      "Failed to add ca_cert to OpenSSL "
 +                                      "certificate store");
 +              }
 +
 +              X509_free(cert);
 +      }
 +
 +      if (!CertCloseStore(cs, 0)) {
 +              wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
 +                         "'%s': error=%d", __func__, name + 13,
 +                         (int) GetLastError());
 +      }
 +
 +      return 0;
 +}
 +
 +
 +#else /* CONFIG_NATIVE_WINDOWS */
 +
 +static int tls_cryptoapi_cert(SSL *ssl, const char *name)
 +{
 +      return -1;
 +}
 +
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +
 +
 +static void ssl_info_cb(const SSL *ssl, int where, int ret)
 +{
 +      const char *str;
 +      int w;
 +
 +      wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret);
 +      w = where & ~SSL_ST_MASK;
 +      if (w & SSL_ST_CONNECT)
 +              str = "SSL_connect";
 +      else if (w & SSL_ST_ACCEPT)
 +              str = "SSL_accept";
 +      else
 +              str = "undefined";
 +
 +      if (where & SSL_CB_LOOP) {
 +              wpa_printf(MSG_DEBUG, "SSL: %s:%s",
 +                         str, SSL_state_string_long(ssl));
 +      } else if (where & SSL_CB_ALERT) {
++              struct tls_connection *conn = SSL_get_app_data((SSL *) ssl);
 +              wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
 +                         where & SSL_CB_READ ?
 +                         "read (remote end reported an error)" :
 +                         "write (local SSL3 detected an error)",
 +                         SSL_alert_type_string_long(ret),
 +                         SSL_alert_desc_string_long(ret));
 +              if ((ret >> 8) == SSL3_AL_FATAL) {
-       if (!pkcs11_so_path || !pkcs11_module_path)
 +                      if (where & SSL_CB_READ)
 +                              conn->read_alerts++;
 +                      else
 +                              conn->write_alerts++;
 +              }
++              if (conn->context->event_cb != NULL) {
++                      union tls_event_data ev;
++                      struct tls_context *context = conn->context;
++                      os_memset(&ev, 0, sizeof(ev));
++                      ev.alert.is_local = !(where & SSL_CB_READ);
++                      ev.alert.type = SSL_alert_type_string_long(ret);
++                      ev.alert.description = SSL_alert_desc_string_long(ret);
++                      context->event_cb(context->cb_ctx, TLS_ALERT, &ev);
++              }
 +      } else if (where & SSL_CB_EXIT && ret <= 0) {
 +              wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
 +                         str, ret == 0 ? "failed" : "error",
 +                         SSL_state_string_long(ssl));
 +      }
 +}
 +
 +
 +#ifndef OPENSSL_NO_ENGINE
 +/**
 + * tls_engine_load_dynamic_generic - load any openssl engine
 + * @pre: an array of commands and values that load an engine initialized
 + *       in the engine specific function
 + * @post: an array of commands and values that initialize an already loaded
 + *        engine (or %NULL if not required)
 + * @id: the engine id of the engine to load (only required if post is not %NULL
 + *
 + * This function is a generic function that loads any openssl engine.
 + *
 + * Returns: 0 on success, -1 on failure
 + */
 +static int tls_engine_load_dynamic_generic(const char *pre[],
 +                                         const char *post[], const char *id)
 +{
 +      ENGINE *engine;
 +      const char *dynamic_id = "dynamic";
 +
 +      engine = ENGINE_by_id(id);
 +      if (engine) {
 +              ENGINE_free(engine);
 +              wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
 +                         "available", id);
 +              return 0;
 +      }
 +      ERR_clear_error();
 +
 +      engine = ENGINE_by_id(dynamic_id);
 +      if (engine == NULL) {
 +              wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
 +                         dynamic_id,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              return -1;
 +      }
 +
 +      /* Perform the pre commands. This will load the engine. */
 +      while (pre && pre[0]) {
 +              wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
 +              if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
 +                      wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
 +                                 "%s %s [%s]", pre[0], pre[1],
 +                                 ERR_error_string(ERR_get_error(), NULL));
 +                      ENGINE_free(engine);
 +                      return -1;
 +              }
 +              pre += 2;
 +      }
 +
 +      /*
 +       * Free the reference to the "dynamic" engine. The loaded engine can
 +       * now be looked up using ENGINE_by_id().
 +       */
 +      ENGINE_free(engine);
 +
 +      engine = ENGINE_by_id(id);
 +      if (engine == NULL) {
 +              wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
 +                         id, ERR_error_string(ERR_get_error(), NULL));
 +              return -1;
 +      }
 +
 +      while (post && post[0]) {
 +              wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
 +              if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
 +                      wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
 +                              " %s %s [%s]", post[0], post[1],
 +                                 ERR_error_string(ERR_get_error(), NULL));
 +                      ENGINE_remove(engine);
 +                      ENGINE_free(engine);
 +                      return -1;
 +              }
 +              post += 2;
 +      }
 +      ENGINE_free(engine);
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
 + * @pkcs11_so_path: pksc11_so_path from the configuration
 + * @pcks11_module_path: pkcs11_module_path from the configuration
 + */
 +static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
 +                                        const char *pkcs11_module_path)
 +{
 +      char *engine_id = "pkcs11";
 +      const char *pre_cmd[] = {
 +              "SO_PATH", NULL /* pkcs11_so_path */,
 +              "ID", NULL /* engine_id */,
 +              "LIST_ADD", "1",
 +              /* "NO_VCHECK", "1", */
 +              "LOAD", NULL,
 +              NULL, NULL
 +      };
 +      const char *post_cmd[] = {
 +              "MODULE_PATH", NULL /* pkcs11_module_path */,
 +              NULL, NULL
 +      };
 +
-       post_cmd[1] = pkcs11_module_path;
++      if (!pkcs11_so_path)
 +              return 0;
 +
 +      pre_cmd[1] = pkcs11_so_path;
 +      pre_cmd[3] = engine_id;
-               tls_global = os_zalloc(sizeof(*tls_global));
-               if (tls_global == NULL)
++      if (pkcs11_module_path)
++              post_cmd[1] = pkcs11_module_path;
++      else
++              post_cmd[0] = NULL;
 +
 +      wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
 +                 pkcs11_so_path);
 +
 +      return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
 +}
 +
 +
 +/**
 + * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
 + * @opensc_so_path: opensc_so_path from the configuration
 + */
 +static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
 +{
 +      char *engine_id = "opensc";
 +      const char *pre_cmd[] = {
 +              "SO_PATH", NULL /* opensc_so_path */,
 +              "ID", NULL /* engine_id */,
 +              "LIST_ADD", "1",
 +              "LOAD", NULL,
 +              NULL, NULL
 +      };
 +
 +      if (!opensc_so_path)
 +              return 0;
 +
 +      pre_cmd[1] = opensc_so_path;
 +      pre_cmd[3] = engine_id;
 +
 +      wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
 +                 opensc_so_path);
 +
 +      return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
 +}
 +#endif /* OPENSSL_NO_ENGINE */
 +
 +
++static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *sess)
++{
++      struct wpabuf *buf;
++
++      if (tls_ex_idx_session < 0)
++              return;
++      buf = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
++      if (!buf)
++              return;
++      wpa_printf(MSG_DEBUG,
++                 "OpenSSL: Free application session data %p (sess %p)",
++                 buf, sess);
++      wpabuf_free(buf);
++
++      SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, NULL);
++}
++
++
 +void * tls_init(const struct tls_config *conf)
 +{
++      struct tls_data *data;
 +      SSL_CTX *ssl;
++      struct tls_context *context;
++      const char *ciphers;
 +
 +      if (tls_openssl_ref_count == 0) {
-               if (conf) {
-                       tls_global->event_cb = conf->event_cb;
-                       tls_global->cb_ctx = conf->cb_ctx;
-               }
++              tls_global = context = tls_context_new(conf);
++              if (context == NULL)
 +                      return NULL;
-                       if (!FIPS_mode_set(1)) {
 +#ifdef CONFIG_FIPS
 +#ifdef OPENSSL_FIPS
 +              if (conf && conf->fips_mode) {
-                       } else
++                      static int fips_enabled = 0;
++
++                      if (!fips_enabled && !FIPS_mode_set(1)) {
 +                              wpa_printf(MSG_ERROR, "Failed to enable FIPS "
 +                                         "mode");
 +                              ERR_load_crypto_strings();
 +                              ERR_print_errors_fp(stderr);
++                              os_free(tls_global);
++                              tls_global = NULL;
 +                              return NULL;
-       ssl = SSL_CTX_new(TLSv1_method());
-       if (ssl == NULL)
++                      } else {
 +                              wpa_printf(MSG_INFO, "Running in FIPS mode");
++                              fips_enabled = 1;
++                      }
 +              }
 +#else /* OPENSSL_FIPS */
 +              if (conf && conf->fips_mode) {
 +                      wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
 +                                 "supported");
++                      os_free(tls_global);
++                      tls_global = NULL;
 +                      return NULL;
 +              }
 +#endif /* OPENSSL_FIPS */
 +#endif /* CONFIG_FIPS */
 +              SSL_load_error_strings();
 +              SSL_library_init();
 +#ifndef OPENSSL_NO_SHA256
 +              EVP_add_digest(EVP_sha256());
 +#endif /* OPENSSL_NO_SHA256 */
 +              /* TODO: if /dev/urandom is available, PRNG is seeded
 +               * automatically. If this is not the case, random data should
 +               * be added here. */
 +
 +#ifdef PKCS12_FUNCS
 +#ifndef OPENSSL_NO_RC2
 +              /*
 +               * 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
 +               * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
 +               * versions, but it looks like OpenSSL 1.0.0 does not do that
 +               * anymore.
 +               */
 +              EVP_add_cipher(EVP_rc2_40_cbc());
 +#endif /* OPENSSL_NO_RC2 */
 +              PKCS12_PBE_add();
 +#endif  /* PKCS12_FUNCS */
++      } else {
++              context = tls_context_new(conf);
++              if (context == NULL)
++                      return NULL;
 +      }
 +      tls_openssl_ref_count++;
 +
-               wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
-               ERR_load_ENGINE_strings();
-               ENGINE_load_dynamic();
++      data = os_zalloc(sizeof(*data));
++      if (data)
++              ssl = SSL_CTX_new(SSLv23_method());
++      else
++              ssl = NULL;
++      if (ssl == NULL) {
++              tls_openssl_ref_count--;
++              if (context != tls_global)
++                      os_free(context);
++              if (tls_openssl_ref_count == 0) {
++                      os_free(tls_global);
++                      tls_global = NULL;
++              }
 +              return NULL;
++      }
++      data->ssl = ssl;
++      if (conf)
++              data->tls_session_lifetime = conf->tls_session_lifetime;
++
++      SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
++      SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
 +
 +      SSL_CTX_set_info_callback(ssl, ssl_info_cb);
++      SSL_CTX_set_app_data(ssl, context);
++      if (data->tls_session_lifetime > 0) {
++              SSL_CTX_set_quiet_shutdown(ssl, 1);
++              /*
++               * Set default context here. In practice, this will be replaced
++               * by the per-EAP method context in tls_connection_set_verify().
++               */
++              SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7);
++              SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER);
++              SSL_CTX_set_timeout(ssl, data->tls_session_lifetime);
++              SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb);
++      } else {
++              SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF);
++      }
++
++      if (tls_ex_idx_session < 0) {
++              tls_ex_idx_session = SSL_SESSION_get_ex_new_index(
++                      0, NULL, NULL, NULL, NULL);
++              if (tls_ex_idx_session < 0) {
++                      tls_deinit(data);
++                      return NULL;
++              }
++      }
 +
 +#ifndef OPENSSL_NO_ENGINE
++      wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
++      ERR_load_ENGINE_strings();
++      ENGINE_load_dynamic();
++
 +      if (conf &&
 +          (conf->opensc_engine_path || conf->pkcs11_engine_path ||
 +           conf->pkcs11_module_path)) {
-                       tls_deinit(ssl);
 +              if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
 +                  tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
 +                                                 conf->pkcs11_module_path)) {
-       return ssl;
++                      tls_deinit(data);
 +                      return NULL;
 +              }
 +      }
 +#endif /* OPENSSL_NO_ENGINE */
 +
-       SSL_CTX *ssl = ssl_ctx;
++      if (conf && conf->openssl_ciphers)
++              ciphers = conf->openssl_ciphers;
++      else
++              ciphers = "DEFAULT:!EXP:!LOW";
++      if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
++              wpa_printf(MSG_ERROR,
++                         "OpenSSL: Failed to set cipher string '%s'",
++                         ciphers);
++              tls_deinit(data);
++              return NULL;
++      }
++
++      return data;
 +}
 +
 +
 +void tls_deinit(void *ssl_ctx)
 +{
-               ERR_remove_state(0);
++      struct tls_data *data = ssl_ctx;
++      SSL_CTX *ssl = data->ssl;
++      struct tls_context *context = SSL_CTX_get_app_data(ssl);
++      if (context != tls_global)
++              os_free(context);
++      if (data->tls_session_lifetime > 0)
++              SSL_CTX_flush_sessions(ssl, 0);
 +      SSL_CTX_free(ssl);
 +
 +      tls_openssl_ref_count--;
 +      if (tls_openssl_ref_count == 0) {
-       if (pin == NULL) {
-               wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
-               return -1;
-       }
-       if (key_id == NULL) {
-               wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
-               return -1;
-       }
++// The next four lines, and two more just below, deal with de-initializing
++// global state in the OpenSSL engine. We (Moonshot) don't want that, since
++// we use OpenSSL elsewhere in our apps (i.e., not only via hostap / libeap.)
++//// #ifndef OPENSSL_NO_ENGINE
++////          ENGINE_cleanup();
++//// #endif /* OPENSSL_NO_ENGINE */
++////          CRYPTO_cleanup_all_ex_data();
++              ERR_remove_thread_state(NULL);
++////          ERR_free_strings();
++////          EVP_cleanup();
++              os_free(tls_global->ocsp_stapling_response);
++              tls_global->ocsp_stapling_response = NULL;
 +              os_free(tls_global);
 +              tls_global = NULL;
 +      }
++
++      os_free(data);
++}
++
++
++#ifndef OPENSSL_NO_ENGINE
++
++/* Cryptoki return values */
++#define CKR_PIN_INCORRECT 0x000000a0
++#define CKR_PIN_INVALID 0x000000a1
++#define CKR_PIN_LEN_RANGE 0x000000a2
++
++/* libp11 */
++#define ERR_LIB_PKCS11        ERR_LIB_USER
++
++static int tls_is_pin_error(unsigned int err)
++{
++      return ERR_GET_LIB(err) == ERR_LIB_PKCS11 &&
++              (ERR_GET_REASON(err) == CKR_PIN_INCORRECT ||
++               ERR_GET_REASON(err) == CKR_PIN_INVALID ||
++               ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE);
 +}
 +
++#endif /* OPENSSL_NO_ENGINE */
++
 +
 +static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
 +                         const char *pin, const char *key_id,
 +                         const char *cert_id, const char *ca_cert_id)
 +{
 +#ifndef OPENSSL_NO_ENGINE
 +      int ret = -1;
 +      if (engine_id == NULL) {
 +              wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
 +              return -1;
 +      }
-       if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
 +
 +      ERR_clear_error();
++#ifdef ANDROID
++      ENGINE_load_dynamic();
++#endif
 +      conn->engine = ENGINE_by_id(engine_id);
 +      if (!conn->engine) {
 +              wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
 +                         engine_id, ERR_error_string(ERR_get_error(), NULL));
 +              goto err;
 +      }
 +      if (ENGINE_init(conn->engine) != 1) {
 +              wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
 +                         "(engine: %s) [%s]", engine_id,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              goto err;
 +      }
 +      wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
 +
-       /* load private key first in-case PIN is required for cert */
-       conn->private_key = ENGINE_load_private_key(conn->engine,
-                                                   key_id, NULL, NULL);
-       if (!conn->private_key) {
-               wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
-                               " '%s' [%s]", key_id,
-                          ERR_error_string(ERR_get_error(), NULL));
-               ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
-               goto err;
++#ifndef ANDROID
++      if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
 +              wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              goto err;
 +      }
-       SSL_CTX *ssl = ssl_ctx;
++#endif
++      if (key_id) {
++              /*
++               * Ensure that the ENGINE does not attempt to use the OpenSSL
++               * UI system to obtain a PIN, if we didn't provide one.
++               */
++              struct {
++                      const void *password;
++                      const char *prompt_info;
++              } key_cb = { "", NULL };
++
++              /* load private key first in-case PIN is required for cert */
++              conn->private_key = ENGINE_load_private_key(conn->engine,
++                                                          key_id, NULL,
++                                                          &key_cb);
++              if (!conn->private_key) {
++                      unsigned long err = ERR_get_error();
++
++                      wpa_printf(MSG_ERROR,
++                                 "ENGINE: cannot load private key with id '%s' [%s]",
++                                 key_id,
++                                 ERR_error_string(err, NULL));
++                      if (tls_is_pin_error(err))
++                              ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
++                      else
++                              ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
++                      goto err;
++              }
 +      }
 +
 +      /* handle a certificate and/or CA certificate */
 +      if (cert_id || ca_cert_id) {
 +              const char *cmd_name = "LOAD_CERT_CTRL";
 +
 +              /* test if the engine supports a LOAD_CERT_CTRL */
 +              if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
 +                               0, (void *)cmd_name, NULL)) {
 +                      wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
 +                                 " loading certificates");
 +                      ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
 +                      goto err;
 +              }
 +      }
 +
 +      return 0;
 +
 +err:
 +      if (conn->engine) {
 +              ENGINE_free(conn->engine);
 +              conn->engine = NULL;
 +      }
 +
 +      if (conn->private_key) {
 +              EVP_PKEY_free(conn->private_key);
 +              conn->private_key = NULL;
 +      }
 +
 +      return ret;
 +#else /* OPENSSL_NO_ENGINE */
 +      return 0;
 +#endif /* OPENSSL_NO_ENGINE */
 +}
 +
 +
 +static void tls_engine_deinit(struct tls_connection *conn)
 +{
 +#ifndef OPENSSL_NO_ENGINE
 +      wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
 +      if (conn->private_key) {
 +              EVP_PKEY_free(conn->private_key);
 +              conn->private_key = NULL;
 +      }
 +      if (conn->engine) {
 +              ENGINE_finish(conn->engine);
 +              conn->engine = NULL;
 +      }
 +#endif /* OPENSSL_NO_ENGINE */
 +}
 +
 +
 +int tls_get_errors(void *ssl_ctx)
 +{
 +      int count = 0;
 +      unsigned long err;
 +
 +      while ((err = ERR_get_error())) {
 +              wpa_printf(MSG_INFO, "TLS - SSL error: %s",
 +                         ERR_error_string(err, NULL));
 +              count++;
 +      }
 +
 +      return count;
 +}
 +
++
++static void tls_msg_cb(int write_p, int version, int content_type,
++                     const void *buf, size_t len, SSL *ssl, void *arg)
++{
++      struct tls_connection *conn = arg;
++      const u8 *pos = buf;
++
++      wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d",
++                 write_p ? "TX" : "RX", version, content_type);
++      wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len);
++      if (content_type == 24 && len >= 3 && pos[0] == 1) {
++              size_t payload_len = WPA_GET_BE16(pos + 1);
++              if (payload_len + 3 > len) {
++                      wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected");
++                      conn->invalid_hb_used = 1;
++              }
++      }
++}
++
++
 +struct tls_connection * tls_connection_init(void *ssl_ctx)
 +{
-       return 0;
++      struct tls_data *data = ssl_ctx;
++      SSL_CTX *ssl = data->ssl;
 +      struct tls_connection *conn;
 +      long options;
++      struct tls_context *context = SSL_CTX_get_app_data(ssl);
 +
 +      conn = os_zalloc(sizeof(*conn));
 +      if (conn == NULL)
 +              return NULL;
++      conn->ssl_ctx = ssl;
 +      conn->ssl = SSL_new(ssl);
 +      if (conn->ssl == NULL) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to initialize new SSL connection");
 +              os_free(conn);
 +              return NULL;
 +      }
 +
++      conn->context = context;
 +      SSL_set_app_data(conn->ssl, conn);
++      SSL_set_msg_callback(conn->ssl, tls_msg_cb);
++      SSL_set_msg_callback_arg(conn->ssl, conn);
 +      options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
 +              SSL_OP_SINGLE_DH_USE;
 +#ifdef SSL_OP_NO_COMPRESSION
 +      options |= SSL_OP_NO_COMPRESSION;
 +#endif /* SSL_OP_NO_COMPRESSION */
 +      SSL_set_options(conn->ssl, options);
 +
 +      conn->ssl_in = BIO_new(BIO_s_mem());
 +      if (!conn->ssl_in) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to create a new BIO for ssl_in");
 +              SSL_free(conn->ssl);
 +              os_free(conn);
 +              return NULL;
 +      }
 +
 +      conn->ssl_out = BIO_new(BIO_s_mem());
 +      if (!conn->ssl_out) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to create a new BIO for ssl_out");
 +              SSL_free(conn->ssl);
 +              BIO_free(conn->ssl_in);
 +              os_free(conn);
 +              return NULL;
 +      }
 +
 +      SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out);
 +
 +      return conn;
 +}
 +
 +
 +void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return;
++      if (conn->success_data) {
++              /*
++               * Make sure ssl_clear_bad_session() does not remove this
++               * session.
++               */
++              SSL_set_quiet_shutdown(conn->ssl, 1);
++              SSL_shutdown(conn->ssl);
++      }
 +      SSL_free(conn->ssl);
 +      tls_engine_deinit(conn);
 +      os_free(conn->subject_match);
 +      os_free(conn->altsubject_match);
++      os_free(conn->suffix_match);
++      os_free(conn->domain_match);
 +      os_free(conn->session_ticket);
 +      os_free(conn);
 +}
 +
 +
 +int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      return conn ? SSL_is_init_finished(conn->ssl) : 0;
 +}
 +
 +
 +int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return -1;
 +
 +      /* Shutdown previous TLS connection without notifying the peer
 +       * because the connection was already terminated in practice
 +       * and "close notify" shutdown alert would confuse AS. */
 +      SSL_set_quiet_shutdown(conn->ssl, 1);
 +      SSL_shutdown(conn->ssl);
-       int i, found = 0;
++      return SSL_clear(conn->ssl) == 1 ? 0 : -1;
 +}
 +
 +
 +static int tls_match_altsubject_component(X509 *cert, int type,
 +                                        const char *value, size_t len)
 +{
 +      GENERAL_NAME *gen;
 +      void *ext;
-       if (tls_global->event_cb == NULL)
++      int found = 0;
++      stack_index_t i;
 +
 +      ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
 +
 +      for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
 +              gen = sk_GENERAL_NAME_value(ext, i);
 +              if (gen->type != type)
 +                      continue;
 +              if (os_strlen((char *) gen->d.ia5->data) == len &&
 +                  os_memcmp(value, gen->d.ia5->data, len) == 0)
 +                      found++;
 +      }
 +
 +      return found;
 +}
 +
 +
 +static int tls_match_altsubject(X509 *cert, const char *match)
 +{
 +      int type;
 +      const char *pos, *end;
 +      size_t len;
 +
 +      pos = match;
 +      do {
 +              if (os_strncmp(pos, "EMAIL:", 6) == 0) {
 +                      type = GEN_EMAIL;
 +                      pos += 6;
 +              } else if (os_strncmp(pos, "DNS:", 4) == 0) {
 +                      type = GEN_DNS;
 +                      pos += 4;
 +              } else if (os_strncmp(pos, "URI:", 4) == 0) {
 +                      type = GEN_URI;
 +                      pos += 4;
 +              } else {
 +                      wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
 +                                 "match '%s'", pos);
 +                      return 0;
 +              }
 +              end = os_strchr(pos, ';');
 +              while (end) {
 +                      if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
 +                          os_strncmp(end + 1, "DNS:", 4) == 0 ||
 +                          os_strncmp(end + 1, "URI:", 4) == 0)
 +                              break;
 +                      end = os_strchr(end + 1, ';');
 +              }
 +              if (end)
 +                      len = end - pos;
 +              else
 +                      len = os_strlen(pos);
 +              if (tls_match_altsubject_component(cert, type, pos, len) > 0)
 +                      return 1;
 +              pos = end + 1;
 +      } while (end);
 +
 +      return 0;
 +}
 +
 +
++#ifndef CONFIG_NATIVE_WINDOWS
++static int domain_suffix_match(const u8 *val, size_t len, const char *match,
++                             int full)
++{
++      size_t i, match_len;
++
++      /* Check for embedded nuls that could mess up suffix matching */
++      for (i = 0; i < len; i++) {
++              if (val[i] == '\0') {
++                      wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject");
++                      return 0;
++              }
++      }
++
++      match_len = os_strlen(match);
++      if (match_len > len || (full && match_len != len))
++              return 0;
++
++      if (os_strncasecmp((const char *) val + len - match_len, match,
++                         match_len) != 0)
++              return 0; /* no match */
++
++      if (match_len == len)
++              return 1; /* exact match */
++
++      if (val[len - match_len - 1] == '.')
++              return 1; /* full label match completes suffix match */
++
++      wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match");
++      return 0;
++}
++#endif /* CONFIG_NATIVE_WINDOWS */
++
++
++static int tls_match_suffix(X509 *cert, const char *match, int full)
++{
++#ifdef CONFIG_NATIVE_WINDOWS
++      /* wincrypt.h has conflicting X509_NAME definition */
++      return -1;
++#else /* CONFIG_NATIVE_WINDOWS */
++      GENERAL_NAME *gen;
++      void *ext;
++      int i;
++      stack_index_t j;
++      int dns_name = 0;
++      X509_NAME *name;
++
++      wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s",
++                 full ? "": "suffix ", match);
++
++      ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
++
++      for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) {
++              gen = sk_GENERAL_NAME_value(ext, j);
++              if (gen->type != GEN_DNS)
++                      continue;
++              dns_name++;
++              wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName",
++                                gen->d.dNSName->data,
++                                gen->d.dNSName->length);
++              if (domain_suffix_match(gen->d.dNSName->data,
++                                      gen->d.dNSName->length, match, full) ==
++                  1) {
++                      wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found",
++                                 full ? "Match" : "Suffix match");
++                      return 1;
++              }
++      }
++
++      if (dns_name) {
++              wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched");
++              return 0;
++      }
++
++      name = X509_get_subject_name(cert);
++      i = -1;
++      for (;;) {
++              X509_NAME_ENTRY *e;
++              ASN1_STRING *cn;
++
++              i = X509_NAME_get_index_by_NID(name, NID_commonName, i);
++              if (i == -1)
++                      break;
++              e = X509_NAME_get_entry(name, i);
++              if (e == NULL)
++                      continue;
++              cn = X509_NAME_ENTRY_get_data(e);
++              if (cn == NULL)
++                      continue;
++              wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName",
++                                cn->data, cn->length);
++              if (domain_suffix_match(cn->data, cn->length, match, full) == 1)
++              {
++                      wpa_printf(MSG_DEBUG, "TLS: %s in commonName found",
++                                 full ? "Match" : "Suffix match");
++                      return 1;
++              }
++      }
++
++      wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found",
++                 full ? "": "suffix ");
++      return 0;
++#endif /* CONFIG_NATIVE_WINDOWS */
++}
++
++
 +static enum tls_fail_reason openssl_tls_fail_reason(int err)
 +{
 +      switch (err) {
 +      case X509_V_ERR_CERT_REVOKED:
 +              return TLS_FAIL_REVOKED;
 +      case X509_V_ERR_CERT_NOT_YET_VALID:
 +      case X509_V_ERR_CRL_NOT_YET_VALID:
 +              return TLS_FAIL_NOT_YET_VALID;
 +      case X509_V_ERR_CERT_HAS_EXPIRED:
 +      case X509_V_ERR_CRL_HAS_EXPIRED:
 +              return TLS_FAIL_EXPIRED;
 +      case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
 +      case X509_V_ERR_UNABLE_TO_GET_CRL:
 +      case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
 +      case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
 +      case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
 +      case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
 +      case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
 +      case X509_V_ERR_CERT_CHAIN_TOO_LONG:
 +      case X509_V_ERR_PATH_LENGTH_EXCEEDED:
 +      case X509_V_ERR_INVALID_CA:
 +              return TLS_FAIL_UNTRUSTED;
 +      case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
 +      case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
 +      case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
 +      case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
 +      case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
 +      case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
 +      case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
 +      case X509_V_ERR_CERT_UNTRUSTED:
 +      case X509_V_ERR_CERT_REJECTED:
 +              return TLS_FAIL_BAD_CERTIFICATE;
 +      default:
 +              return TLS_FAIL_UNSPECIFIED;
 +      }
 +}
 +
 +
 +static struct wpabuf * get_x509_cert(X509 *cert)
 +{
 +      struct wpabuf *buf;
 +      u8 *tmp;
 +
 +      int cert_len = i2d_X509(cert, NULL);
 +      if (cert_len <= 0)
 +              return NULL;
 +
 +      buf = wpabuf_alloc(cert_len);
 +      if (buf == NULL)
 +              return NULL;
 +
 +      tmp = wpabuf_put(buf, cert_len);
 +      i2d_X509(cert, &tmp);
 +      return buf;
 +}
 +
 +
 +static void openssl_tls_fail_event(struct tls_connection *conn,
 +                                 X509 *err_cert, int err, int depth,
 +                                 const char *subject, const char *err_str,
 +                                 enum tls_fail_reason reason)
 +{
 +      union tls_event_data ev;
 +      struct wpabuf *cert = NULL;
++      struct tls_context *context = conn->context;
 +
-       tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
++      if (context->event_cb == NULL)
 +              return;
 +
 +      cert = get_x509_cert(err_cert);
 +      os_memset(&ev, 0, sizeof(ev));
 +      ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
 +              reason : openssl_tls_fail_reason(err);
 +      ev.cert_fail.depth = depth;
 +      ev.cert_fail.subject = subject;
 +      ev.cert_fail.reason_txt = err_str;
 +      ev.cert_fail.cert = cert;
-       if (tls_global->event_cb == NULL)
++      context->event_cb(context->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
 +      wpabuf_free(cert);
 +}
 +
 +
 +static void openssl_tls_cert_event(struct tls_connection *conn,
 +                                 X509 *err_cert, int depth,
 +                                 const char *subject)
 +{
 +      struct wpabuf *cert = NULL;
 +      union tls_event_data ev;
++      struct tls_context *context = conn->context;
++      char *altsubject[TLS_MAX_ALT_SUBJECT];
++      int alt, num_altsubject = 0;
++      GENERAL_NAME *gen;
++      void *ext;
++      stack_index_t i;
 +#ifdef CONFIG_SHA256
 +      u8 hash[32];
 +#endif /* CONFIG_SHA256 */
 +
-       if (conn->cert_probe) {
++      if (context->event_cb == NULL)
 +              return;
 +
 +      os_memset(&ev, 0, sizeof(ev));
-       tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
++      if (conn->cert_probe || context->cert_in_cb) {
 +              cert = get_x509_cert(err_cert);
 +              ev.peer_cert.cert = cert;
 +      }
 +#ifdef CONFIG_SHA256
 +      if (cert) {
 +              const u8 *addr[1];
 +              size_t len[1];
 +              addr[0] = wpabuf_head(cert);
 +              len[0] = wpabuf_len(cert);
 +              if (sha256_vector(1, addr, len, hash) == 0) {
 +                      ev.peer_cert.hash = hash;
 +                      ev.peer_cert.hash_len = sizeof(hash);
 +              }
 +      }
 +#endif /* CONFIG_SHA256 */
 +      ev.peer_cert.depth = depth;
 +      ev.peer_cert.subject = subject;
-       char *match, *altmatch;
++
++      ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL);
++      for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
++              char *pos;
++
++              if (num_altsubject == TLS_MAX_ALT_SUBJECT)
++                      break;
++              gen = sk_GENERAL_NAME_value(ext, i);
++              if (gen->type != GEN_EMAIL &&
++                  gen->type != GEN_DNS &&
++                  gen->type != GEN_URI)
++                      continue;
++
++              pos = os_malloc(10 + gen->d.ia5->length + 1);
++              if (pos == NULL)
++                      break;
++              altsubject[num_altsubject++] = pos;
++
++              switch (gen->type) {
++              case GEN_EMAIL:
++                      os_memcpy(pos, "EMAIL:", 6);
++                      pos += 6;
++                      break;
++              case GEN_DNS:
++                      os_memcpy(pos, "DNS:", 4);
++                      pos += 4;
++                      break;
++              case GEN_URI:
++                      os_memcpy(pos, "URI:", 4);
++                      pos += 4;
++                      break;
++              }
++
++              os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length);
++              pos += gen->d.ia5->length;
++              *pos = '\0';
++      }
++
++      for (alt = 0; alt < num_altsubject; alt++)
++              ev.peer_cert.altsubject[alt] = altsubject[alt];
++      ev.peer_cert.num_altsubject = num_altsubject;
++
++      context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
 +      wpabuf_free(cert);
++      for (alt = 0; alt < num_altsubject; alt++)
++              os_free(altsubject[alt]);
 +}
 +
 +
 +static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
 +{
 +      char buf[256];
 +      X509 *err_cert;
 +      int err, depth;
 +      SSL *ssl;
 +      struct tls_connection *conn;
-       match = conn ? conn->subject_match : NULL;
-       altmatch = conn ? conn->altsubject_match : NULL;
++      struct tls_context *context;
++      char *match, *altmatch, *suffix_match, *domain_match;
 +      const char *err_str;
 +
 +      err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
++      if (!err_cert)
++              return 0;
++
 +      err = X509_STORE_CTX_get_error(x509_ctx);
 +      depth = X509_STORE_CTX_get_error_depth(x509_ctx);
 +      ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
 +                                       SSL_get_ex_data_X509_STORE_CTX_idx());
 +      X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
 +
 +      conn = SSL_get_app_data(ssl);
-       if (preverify_ok && depth == 0 && conn->server_cert_only) {
++      if (conn == NULL)
++              return 0;
++
++      if (depth == 0)
++              conn->peer_cert = err_cert;
++      else if (depth == 1)
++              conn->peer_issuer = err_cert;
++      else if (depth == 2)
++              conn->peer_issuer_issuer = err_cert;
++
++      context = conn->context;
++      match = conn->subject_match;
++      altmatch = conn->altsubject_match;
++      suffix_match = conn->suffix_match;
++      domain_match = conn->domain_match;
 +
 +      if (!preverify_ok && !conn->ca_cert_verify)
 +              preverify_ok = 1;
 +      if (!preverify_ok && depth > 0 && conn->server_cert_only)
 +              preverify_ok = 1;
++      if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
++          (err == X509_V_ERR_CERT_HAS_EXPIRED ||
++           err == X509_V_ERR_CERT_NOT_YET_VALID)) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
++                         "time mismatch");
++              preverify_ok = 1;
++      }
 +
 +      err_str = X509_verify_cert_error_string(err);
 +
 +#ifdef CONFIG_SHA256
- static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
++      /*
++       * Do not require preverify_ok so we can explicity allow otherwise
++       * invalid pinned server certificates.
++       */
++      if (depth == 0 && conn->server_cert_only) {
 +              struct wpabuf *cert;
 +              cert = get_x509_cert(err_cert);
 +              if (!cert) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
 +                                 "server certificate data");
 +                      preverify_ok = 0;
 +              } else {
 +                      u8 hash[32];
 +                      const u8 *addr[1];
 +                      size_t len[1];
 +                      addr[0] = wpabuf_head(cert);
 +                      len[0] = wpabuf_len(cert);
 +                      if (sha256_vector(1, addr, len, hash) < 0 ||
 +                          os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
 +                              err_str = "Server certificate mismatch";
 +                              err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
 +                              preverify_ok = 0;
++                      } else if (!preverify_ok) {
++                              /*
++                               * Certificate matches pinned certificate, allow
++                               * regardless of other problems.
++                               */
++                              wpa_printf(MSG_DEBUG,
++                                         "OpenSSL: Ignore validation issues for a pinned server certificate");
++                              preverify_ok = 1;
 +                      }
 +                      wpabuf_free(cert);
 +              }
 +      }
 +#endif /* CONFIG_SHA256 */
 +
 +      if (!preverify_ok) {
 +              wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
 +                         " error %d (%s) depth %d for '%s'", err, err_str,
 +                         depth, buf);
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     err_str, TLS_FAIL_UNSPECIFIED);
 +              return preverify_ok;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
 +                 "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
 +                 preverify_ok, err, err_str,
 +                 conn->ca_cert_verify, depth, buf);
 +      if (depth == 0 && match && os_strstr(buf, match) == NULL) {
 +              wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
 +                         "match with '%s'", buf, match);
 +              preverify_ok = 0;
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     "Subject mismatch",
 +                                     TLS_FAIL_SUBJECT_MISMATCH);
 +      } else if (depth == 0 && altmatch &&
 +                 !tls_match_altsubject(err_cert, altmatch)) {
 +              wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
 +                         "'%s' not found", altmatch);
 +              preverify_ok = 0;
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     "AltSubject mismatch",
 +                                     TLS_FAIL_ALTSUBJECT_MISMATCH);
++      } else if (depth == 0 && suffix_match &&
++                 !tls_match_suffix(err_cert, suffix_match, 0)) {
++              wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found",
++                         suffix_match);
++              preverify_ok = 0;
++              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
++                                     "Domain suffix mismatch",
++                                     TLS_FAIL_DOMAIN_SUFFIX_MISMATCH);
++      } else if (depth == 0 && domain_match &&
++                 !tls_match_suffix(err_cert, domain_match, 1)) {
++              wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found",
++                         domain_match);
++              preverify_ok = 0;
++              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
++                                     "Domain mismatch",
++                                     TLS_FAIL_DOMAIN_MISMATCH);
 +      } else
 +              openssl_tls_cert_event(conn, err_cert, depth, buf);
 +
 +      if (conn->cert_probe && preverify_ok && depth == 0) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
 +                         "on probe-only run");
 +              preverify_ok = 0;
 +              openssl_tls_fail_event(conn, err_cert, err, depth, buf,
 +                                     "Server certificate chain probe",
 +                                     TLS_FAIL_SERVER_CHAIN_PROBE);
 +      }
 +
++      if (preverify_ok && context->event_cb != NULL)
++              context->event_cb(context->cb_ctx,
++                                TLS_CERT_CHAIN_SUCCESS, NULL);
++
 +      return preverify_ok;
 +}
 +
 +
 +#ifndef OPENSSL_NO_STDIO
-       SSL_CTX *ssl_ctx = _ssl_ctx;
++static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
 +{
-       lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
++      SSL_CTX *ssl_ctx = data->ssl;
 +      X509_LOOKUP *lookup;
 +      int ret = 0;
 +
- static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
++      lookup = X509_STORE_add_lookup(SSL_CTX_get_cert_store(ssl_ctx),
 +                                     X509_LOOKUP_file());
 +      if (lookup == NULL) {
 +              tls_show_errors(MSG_WARNING, __func__,
 +                              "Failed add lookup for X509 store");
 +              return -1;
 +      }
 +
 +      if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
 +              unsigned long err = ERR_peek_error();
 +              tls_show_errors(MSG_WARNING, __func__,
 +                              "Failed load CA in DER format");
 +              if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
 +                  ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
 +                                 "cert already in hash table error",
 +                                 __func__);
 +              } else
 +                      ret = -1;
 +      }
 +
 +      return ret;
 +}
 +#endif /* OPENSSL_NO_STDIO */
 +
 +
-       SSL_CTX *ssl_ctx = _ssl_ctx;
++static int tls_connection_ca_cert(struct tls_data *data,
++                                struct tls_connection *conn,
 +                                const char *ca_cert, const u8 *ca_cert_blob,
 +                                size_t ca_cert_blob_len, const char *ca_path)
 +{
-       X509_STORE_free(ssl_ctx->cert_store);
-       ssl_ctx->cert_store = X509_STORE_new();
-       if (ssl_ctx->cert_store == NULL) {
++      SSL_CTX *ssl_ctx = data->ssl;
++      X509_STORE *store;
 +
 +      /*
 +       * Remove previously configured trusted CA certificates before adding
 +       * new ones.
 +       */
-               X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob,
++      store = X509_STORE_new();
++      if (store == NULL) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
 +                         "certificate store", __func__);
 +              return -1;
 +      }
++      SSL_CTX_set_cert_store(ssl_ctx, store);
 +
 +      SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
 +      conn->ca_cert_verify = 1;
 +
 +      if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
 +                         "chain");
 +              conn->cert_probe = 1;
 +              conn->ca_cert_verify = 0;
 +              return 0;
 +      }
 +
 +      if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
 +#ifdef CONFIG_SHA256
 +              const char *pos = ca_cert + 7;
 +              if (os_strncmp(pos, "server/sha256/", 14) != 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
 +                                 "hash value '%s'", ca_cert);
 +                      return -1;
 +              }
 +              pos += 14;
 +              if (os_strlen(pos) != 32 * 2) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
 +                                 "hash length in ca_cert '%s'", ca_cert);
 +                      return -1;
 +              }
 +              if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
 +                                 "value in ca_cert '%s'", ca_cert);
 +                      return -1;
 +              }
 +              conn->server_cert_only = 1;
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
 +                         "certificate match");
 +              return 0;
 +#else /* CONFIG_SHA256 */
 +              wpa_printf(MSG_INFO, "No SHA256 included in the build - "
 +                         "cannot validate server certificate hash");
 +              return -1;
 +#endif /* CONFIG_SHA256 */
 +      }
 +
 +      if (ca_cert_blob) {
-               if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
++              X509 *cert = d2i_X509(NULL,
++                                    (const unsigned char **) &ca_cert_blob,
 +                                    ca_cert_blob_len);
 +              if (cert == NULL) {
 +                      tls_show_errors(MSG_WARNING, __func__,
 +                                      "Failed to parse ca_cert_blob");
 +                      return -1;
 +              }
 +
-                           tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
++              if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
++                                       cert)) {
 +                      unsigned long err = ERR_peek_error();
 +                      tls_show_errors(MSG_WARNING, __func__,
 +                                      "Failed to add ca_cert_blob to "
 +                                      "certificate store");
 +                      if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
 +                          ERR_GET_REASON(err) ==
 +                          X509_R_CERT_ALREADY_IN_HASH_TABLE) {
 +                              wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
 +                                         "cert already in hash table error",
 +                                         __func__);
 +                      } else {
 +                              X509_free(cert);
 +                              return -1;
 +                      }
 +              }
 +              X509_free(cert);
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
 +                         "to certificate store", __func__);
 +              return 0;
 +      }
 +
++#ifdef ANDROID
++      if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
++              BIO *bio = BIO_from_keystore(&ca_cert[11]);
++              STACK_OF(X509_INFO) *stack = NULL;
++              stack_index_t i;
++
++              if (bio) {
++                      stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
++                      BIO_free(bio);
++              }
++              if (!stack)
++                      return -1;
++
++              for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
++                      X509_INFO *info = sk_X509_INFO_value(stack, i);
++                      if (info->x509) {
++                              X509_STORE_add_cert(ssl_ctx->cert_store,
++                                                  info->x509);
++                      }
++                      if (info->crl) {
++                              X509_STORE_add_crl(ssl_ctx->cert_store,
++                                                 info->crl);
++                      }
++              }
++              sk_X509_INFO_pop_free(stack, X509_INFO_free);
++              SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
++              return 0;
++      }
++#endif /* ANDROID */
++
 +#ifdef CONFIG_NATIVE_WINDOWS
 +      if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
 +          0) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
 +                         "system certificate store");
 +              return 0;
 +      }
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +
 +      if (ca_cert || ca_path) {
 +#ifndef OPENSSL_NO_STDIO
 +              if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
 +                  1) {
 +                      tls_show_errors(MSG_WARNING, __func__,
 +                                      "Failed to load root certificates");
 +                      if (ca_cert &&
-                       tls_get_errors(ssl_ctx);
++                          tls_load_ca_der(data, ca_cert) == 0) {
 +                              wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
 +                                         "DER format CA certificate",
 +                                         __func__);
 +                      } else
 +                              return -1;
 +              } else {
 +                      wpa_printf(MSG_DEBUG, "TLS: Trusted root "
 +                                 "certificate(s) loaded");
- static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
++                      tls_get_errors(data);
 +              }
 +#else /* OPENSSL_NO_STDIO */
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
 +                         __func__);
 +              return -1;
 +#endif /* OPENSSL_NO_STDIO */
 +      } else {
 +              /* No ca_cert configured - do not try to verify server
 +               * certificate */
 +              conn->ca_cert_verify = 0;
 +      }
 +
 +      return 0;
 +}
 +
 +
-               X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
++static int tls_global_ca_cert(struct tls_data *data, const char *ca_cert)
 +{
++      SSL_CTX *ssl_ctx = data->ssl;
++
 +      if (ca_cert) {
 +              if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
 +              {
 +                      tls_show_errors(MSG_WARNING, __func__,
 +                                      "Failed to load root certificates");
 +                      return -1;
 +              }
 +
 +              wpa_printf(MSG_DEBUG, "TLS: Trusted root "
 +                         "certificate(s) loaded");
 +
 +#ifndef OPENSSL_NO_STDIO
 +              /* Add the same CAs to the client certificate requests */
 +              SSL_CTX_set_client_CA_list(ssl_ctx,
 +                                         SSL_load_client_CA_file(ca_cert));
 +#endif /* OPENSSL_NO_STDIO */
 +      }
 +
 +      return 0;
 +}
 +
 +
 +int tls_global_set_verify(void *ssl_ctx, int check_crl)
 +{
 +      int flags;
 +
 +      if (check_crl) {
-                                           const char *altsubject_match)
++              struct tls_data *data = ssl_ctx;
++              X509_STORE *cs = SSL_CTX_get_cert_store(data->ssl);
 +              if (cs == NULL) {
 +                      tls_show_errors(MSG_INFO, __func__, "Failed to get "
 +                                      "certificate store when enabling "
 +                                      "check_crl");
 +                      return -1;
 +              }
 +              flags = X509_V_FLAG_CRL_CHECK;
 +              if (check_crl == 2)
 +                      flags |= X509_V_FLAG_CRL_CHECK_ALL;
 +              X509_STORE_set_flags(cs, flags);
 +      }
 +      return 0;
 +}
 +
 +
 +static int tls_connection_set_subject_match(struct tls_connection *conn,
 +                                          const char *subject_match,
-                             int verify_peer)
++                                          const char *altsubject_match,
++                                          const char *suffix_match,
++                                          const char *domain_match)
 +{
 +      os_free(conn->subject_match);
 +      conn->subject_match = NULL;
 +      if (subject_match) {
 +              conn->subject_match = os_strdup(subject_match);
 +              if (conn->subject_match == NULL)
 +                      return -1;
 +      }
 +
 +      os_free(conn->altsubject_match);
 +      conn->altsubject_match = NULL;
 +      if (altsubject_match) {
 +              conn->altsubject_match = os_strdup(altsubject_match);
 +              if (conn->altsubject_match == NULL)
 +                      return -1;
 +      }
 +
++      os_free(conn->suffix_match);
++      conn->suffix_match = NULL;
++      if (suffix_match) {
++              conn->suffix_match = os_strdup(suffix_match);
++              if (conn->suffix_match == NULL)
++                      return -1;
++      }
++
++      os_free(conn->domain_match);
++      conn->domain_match = NULL;
++      if (domain_match) {
++              conn->domain_match = os_strdup(domain_match);
++              if (conn->domain_match == NULL)
++                      return -1;
++      }
++
 +      return 0;
 +}
 +
 +
++static void tls_set_conn_flags(SSL *ssl, unsigned int flags)
++{
++#ifdef SSL_OP_NO_TICKET
++      if (flags & TLS_CONN_DISABLE_SESSION_TICKET)
++              SSL_set_options(ssl, SSL_OP_NO_TICKET);
++#ifdef SSL_clear_options
++      else
++              SSL_clear_options(ssl, SSL_OP_NO_TICKET);
++#endif /* SSL_clear_options */
++#endif /* SSL_OP_NO_TICKET */
++
++#ifdef SSL_OP_NO_TLSv1
++      if (flags & TLS_CONN_DISABLE_TLSv1_0)
++              SSL_set_options(ssl, SSL_OP_NO_TLSv1);
++      else
++              SSL_clear_options(ssl, SSL_OP_NO_TLSv1);
++#endif /* SSL_OP_NO_TLSv1 */
++#ifdef SSL_OP_NO_TLSv1_1
++      if (flags & TLS_CONN_DISABLE_TLSv1_1)
++              SSL_set_options(ssl, SSL_OP_NO_TLSv1_1);
++      else
++              SSL_clear_options(ssl, SSL_OP_NO_TLSv1_1);
++#endif /* SSL_OP_NO_TLSv1_1 */
++#ifdef SSL_OP_NO_TLSv1_2
++      if (flags & TLS_CONN_DISABLE_TLSv1_2)
++              SSL_set_options(ssl, SSL_OP_NO_TLSv1_2);
++      else
++              SSL_clear_options(ssl, SSL_OP_NO_TLSv1_2);
++#endif /* SSL_OP_NO_TLSv1_2 */
++}
++
++
 +int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
-       /*
-        * Set session id context in order to avoid fatal errors when client
-        * tries to resume a session. However, set the context to a unique
-        * value in order to effectively disable session resumption for now
-        * since not all areas of the server code are ready for it (e.g.,
-        * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
-        * handshake).
-        */
-       counter++;
-       SSL_set_session_id_context(conn->ssl,
-                                  (const unsigned char *) &counter,
-                                  sizeof(counter));
++                            int verify_peer, unsigned int flags,
++                            const u8 *session_ctx, size_t session_ctx_len)
 +{
 +      static int counter = 0;
++      struct tls_data *data = ssl_ctx;
 +
 +      if (conn == NULL)
 +              return -1;
 +
 +      if (verify_peer) {
 +              conn->ca_cert_verify = 1;
 +              SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
 +                             SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
 +                             SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
 +      } else {
 +              conn->ca_cert_verify = 0;
 +              SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
 +      }
 +
++      tls_set_conn_flags(conn->ssl, flags);
++      conn->flags = flags;
++
 +      SSL_set_accept_state(conn->ssl);
 +
-       } else {
-               tls_show_errors(MSG_DEBUG, __func__,
-                               "SSL_use_certificate_file (DER) failed");
++      if (data->tls_session_lifetime == 0) {
++              /*
++               * Set session id context to a unique value to make sure
++               * session resumption cannot be used either through session
++               * caching or TLS ticket extension.
++               */
++              counter++;
++              SSL_set_session_id_context(conn->ssl,
++                                         (const unsigned char *) &counter,
++                                         sizeof(counter));
++      } else if (session_ctx) {
++              SSL_set_session_id_context(conn->ssl, session_ctx,
++                                         session_ctx_len);
++      }
 +
 +      return 0;
 +}
 +
 +
 +static int tls_connection_client_cert(struct tls_connection *conn,
 +                                    const char *client_cert,
 +                                    const u8 *client_cert_blob,
 +                                    size_t client_cert_blob_len)
 +{
 +      if (client_cert == NULL && client_cert_blob == NULL)
 +              return 0;
 +
 +      if (client_cert_blob &&
 +          SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
 +                                   client_cert_blob_len) == 1) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
 +                         "OK");
 +              return 0;
 +      } else if (client_cert_blob) {
 +              tls_show_errors(MSG_DEBUG, __func__,
 +                              "SSL_use_certificate_ASN1 failed");
 +      }
 +
 +      if (client_cert == NULL)
 +              return -1;
 +
++#ifdef ANDROID
++      if (os_strncmp("keystore://", client_cert, 11) == 0) {
++              BIO *bio = BIO_from_keystore(&client_cert[11]);
++              X509 *x509 = NULL;
++              int ret = -1;
++              if (bio) {
++                      x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
++                      BIO_free(bio);
++              }
++              if (x509) {
++                      if (SSL_use_certificate(conn->ssl, x509) == 1)
++                              ret = 0;
++                      X509_free(x509);
++              }
++              return ret;
++      }
++#endif /* ANDROID */
++
 +#ifndef OPENSSL_NO_STDIO
 +      if (SSL_use_certificate_file(conn->ssl, client_cert,
 +                                   SSL_FILETYPE_ASN1) == 1) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
 +                         " --> OK");
 +              return 0;
-       } else {
-               tls_show_errors(MSG_DEBUG, __func__,
-                               "SSL_use_certificate_file (PEM) failed");
 +      }
 +
 +      if (SSL_use_certificate_file(conn->ssl, client_cert,
 +                                   SSL_FILETYPE_PEM) == 1) {
++              ERR_clear_error();
 +              wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
 +                         " --> OK");
 +              return 0;
- static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
 +      }
++
++      tls_show_errors(MSG_DEBUG, __func__,
++                      "SSL_use_certificate_file failed");
 +#else /* OPENSSL_NO_STDIO */
 +      wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
 +#endif /* OPENSSL_NO_STDIO */
 +
 +      return -1;
 +}
 +
 +
- static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
++static int tls_global_client_cert(struct tls_data *data,
++                                const char *client_cert)
 +{
 +#ifndef OPENSSL_NO_STDIO
++      SSL_CTX *ssl_ctx = data->ssl;
++
 +      if (client_cert == NULL)
 +              return 0;
 +
 +      if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
 +                                       SSL_FILETYPE_ASN1) != 1 &&
++          SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
 +          SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
 +                                       SSL_FILETYPE_PEM) != 1) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to load client certificate");
 +              return -1;
 +      }
 +      return 0;
 +#else /* OPENSSL_NO_STDIO */
 +      if (client_cert == NULL)
 +              return 0;
 +      wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
 +      return -1;
 +#endif /* OPENSSL_NO_STDIO */
 +}
 +
 +
 +static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
 +{
 +      if (password == NULL) {
 +              return 0;
 +      }
 +      os_strlcpy(buf, (char *) password, size);
 +      return os_strlen(buf);
 +}
 +
 +
 +#ifdef PKCS12_FUNCS
-                       if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1)
++static int tls_parse_pkcs12(struct tls_data *data, SSL *ssl, PKCS12 *p12,
 +                          const char *passwd)
 +{
 +      EVP_PKEY *pkey;
 +      X509 *cert;
 +      STACK_OF(X509) *certs;
 +      int res = 0;
 +      char buf[256];
 +
 +      pkey = NULL;
 +      cert = NULL;
 +      certs = NULL;
++      if (!passwd)
++              passwd = "";
 +      if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
 +              tls_show_errors(MSG_DEBUG, __func__,
 +                              "Failed to parse PKCS12 file");
 +              PKCS12_free(p12);
 +              return -1;
 +      }
 +      wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
 +
 +      if (cert) {
 +              X509_NAME_oneline(X509_get_subject_name(cert), buf,
 +                                sizeof(buf));
 +              wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
 +                         "subject='%s'", buf);
 +              if (ssl) {
 +                      if (SSL_use_certificate(ssl, cert) != 1)
 +                              res = -1;
 +              } else {
-                       if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1)
++                      if (SSL_CTX_use_certificate(data->ssl, cert) != 1)
 +                              res = -1;
 +              }
 +              X509_free(cert);
 +      }
 +
 +      if (pkey) {
 +              wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12");
 +              if (ssl) {
 +                      if (SSL_use_PrivateKey(ssl, pkey) != 1)
 +                              res = -1;
 +              } else {
-                       if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
++                      if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1)
 +                              res = -1;
 +              }
 +              EVP_PKEY_free(pkey);
 +      }
 +
 +      if (certs) {
++#if OPENSSL_VERSION_NUMBER >= 0x10002000L
++              SSL_clear_chain_certs(ssl);
++              while ((cert = sk_X509_pop(certs)) != NULL) {
++                      X509_NAME_oneline(X509_get_subject_name(cert), buf,
++                                        sizeof(buf));
++                      wpa_printf(MSG_DEBUG, "TLS: additional certificate"
++                                 " from PKCS12: subject='%s'", buf);
++                      if (SSL_add1_chain_cert(ssl, cert) != 1) {
++                              tls_show_errors(MSG_DEBUG, __func__,
++                                              "Failed to add additional certificate");
++                              res = -1;
++                              break;
++                      }
++              }
++              if (!res) {
++                      /* Try to continue anyway */
++              }
++              sk_X509_free(certs);
++#ifndef OPENSSL_IS_BORINGSSL
++              res = SSL_build_cert_chain(ssl,
++                                         SSL_BUILD_CHAIN_FLAG_CHECK |
++                                         SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
++              if (!res) {
++                      tls_show_errors(MSG_DEBUG, __func__,
++                                      "Failed to build certificate chain");
++              } else if (res == 2) {
++                      wpa_printf(MSG_DEBUG,
++                                 "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates");
++              }
++#endif /* OPENSSL_IS_BORINGSSL */
++              /*
++               * Try to continue regardless of result since it is possible for
++               * the extra certificates not to be required.
++               */
++              res = 0;
++#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
++#if OPENSSL_VERSION_NUMBER >= 0x10001000L
++              SSL_CTX_clear_extra_chain_certs(data->ssl);
++#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
 +              while ((cert = sk_X509_pop(certs)) != NULL) {
 +                      X509_NAME_oneline(X509_get_subject_name(cert), buf,
 +                                        sizeof(buf));
 +                      wpa_printf(MSG_DEBUG, "TLS: additional certificate"
 +                                 " from PKCS12: subject='%s'", buf);
 +                      /*
 +                       * There is no SSL equivalent for the chain cert - so
 +                       * always add it to the context...
 +                       */
-               tls_get_errors(ssl_ctx);
++                      if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
++                      {
 +                              res = -1;
 +                              break;
 +                      }
 +              }
 +              sk_X509_free(certs);
++#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
 +      }
 +
 +      PKCS12_free(p12);
 +
 +      if (res < 0)
- static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
-                          const char *passwd)
++              tls_get_errors(data);
 +
 +      return res;
 +}
 +#endif  /* PKCS12_FUNCS */
 +
 +
-       return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
++static int tls_read_pkcs12(struct tls_data *data, SSL *ssl,
++                         const char *private_key, const char *passwd)
 +{
 +#ifdef PKCS12_FUNCS
 +      FILE *f;
 +      PKCS12 *p12;
 +
 +      f = fopen(private_key, "rb");
 +      if (f == NULL)
 +              return -1;
 +
 +      p12 = d2i_PKCS12_fp(f, NULL);
 +      fclose(f);
 +
 +      if (p12 == NULL) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to use PKCS#12 file");
 +              return -1;
 +      }
 +
- static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
++      return tls_parse_pkcs12(data, ssl, p12, passwd);
 +
 +#else /* PKCS12_FUNCS */
 +      wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
 +                 "p12/pfx files");
 +      return -1;
 +#endif  /* PKCS12_FUNCS */
 +}
 +
 +
-       p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
++static int tls_read_pkcs12_blob(struct tls_data *data, SSL *ssl,
 +                              const u8 *blob, size_t len, const char *passwd)
 +{
 +#ifdef PKCS12_FUNCS
 +      PKCS12 *p12;
 +
-       return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
++      p12 = d2i_PKCS12(NULL, (const unsigned char **) &blob, len);
 +      if (p12 == NULL) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to use PKCS#12 blob");
 +              return -1;
 +      }
 +
-                          ERR_error_string(ERR_get_error(), NULL));
++      return tls_parse_pkcs12(data, ssl, p12, passwd);
 +
 +#else /* PKCS12_FUNCS */
 +      wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
 +                 "p12/pfx blobs");
 +      return -1;
 +#endif  /* PKCS12_FUNCS */
 +}
 +
 +
 +#ifndef OPENSSL_NO_ENGINE
 +static int tls_engine_get_cert(struct tls_connection *conn,
 +                             const char *cert_id,
 +                             X509 **cert)
 +{
 +      /* this runs after the private key is loaded so no PIN is required */
 +      struct {
 +              const char *cert_id;
 +              X509 *cert;
 +      } params;
 +      params.cert_id = cert_id;
 +      params.cert = NULL;
 +
 +      if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
 +                           0, &params, NULL, 1)) {
++              unsigned long err = ERR_get_error();
++
 +              wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
 +                         " '%s' [%s]", cert_id,
- static int tls_connection_engine_ca_cert(void *_ssl_ctx,
++                         ERR_error_string(err, NULL));
++              if (tls_is_pin_error(err))
++                      return TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN;
 +              return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
 +      }
 +      if (!params.cert) {
 +              wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
 +                         " '%s'", cert_id);
 +              return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
 +      }
 +      *cert = params.cert;
 +      return 0;
 +}
 +#endif /* OPENSSL_NO_ENGINE */
 +
 +
 +static int tls_connection_engine_client_cert(struct tls_connection *conn,
 +                                           const char *cert_id)
 +{
 +#ifndef OPENSSL_NO_ENGINE
 +      X509 *cert;
 +
 +      if (tls_engine_get_cert(conn, cert_id, &cert))
 +              return -1;
 +
 +      if (!SSL_use_certificate(conn->ssl, cert)) {
 +              tls_show_errors(MSG_ERROR, __func__,
 +                              "SSL_use_certificate failed");
 +                X509_free(cert);
 +              return -1;
 +      }
 +      X509_free(cert);
 +      wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
 +                 "OK");
 +      return 0;
 +
 +#else /* OPENSSL_NO_ENGINE */
 +      return -1;
 +#endif /* OPENSSL_NO_ENGINE */
 +}
 +
 +
-       SSL_CTX *ssl_ctx = _ssl_ctx;
++static int tls_connection_engine_ca_cert(struct tls_data *data,
 +                                       struct tls_connection *conn,
 +                                       const char *ca_cert_id)
 +{
 +#ifndef OPENSSL_NO_ENGINE
 +      X509 *cert;
-       X509_STORE_free(ssl_ctx->cert_store);
-       ssl_ctx->cert_store = X509_STORE_new();
-       if (ssl_ctx->cert_store == NULL) {
++      SSL_CTX *ssl_ctx = data->ssl;
++      X509_STORE *store;
 +
 +      if (tls_engine_get_cert(conn, ca_cert_id, &cert))
 +              return -1;
 +
 +      /* start off the same as tls_connection_ca_cert */
-       if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
++      store = X509_STORE_new();
++      if (store == NULL) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
 +                         "certificate store", __func__);
 +              X509_free(cert);
 +              return -1;
 +      }
- static int tls_connection_private_key(void *_ssl_ctx,
++      SSL_CTX_set_cert_store(ssl_ctx, store);
++      if (!X509_STORE_add_cert(store, cert)) {
 +              unsigned long err = ERR_peek_error();
 +              tls_show_errors(MSG_WARNING, __func__,
 +                              "Failed to add CA certificate from engine "
 +                              "to certificate store");
 +              if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
 +                  ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
 +                                 " already in hash table error",
 +                                 __func__);
 +              } else {
 +                      X509_free(cert);
 +                      return -1;
 +              }
 +      }
 +      X509_free(cert);
 +      wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
 +                 "to certificate store", __func__);
 +      SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
++      conn->ca_cert_verify = 1;
++
 +      return 0;
 +
 +#else /* OPENSSL_NO_ENGINE */
 +      return -1;
 +#endif /* OPENSSL_NO_ENGINE */
 +}
 +
 +
 +static int tls_connection_engine_private_key(struct tls_connection *conn)
 +{
 +#ifndef OPENSSL_NO_ENGINE
 +      if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
 +              tls_show_errors(MSG_ERROR, __func__,
 +                              "ENGINE: cannot use private key for TLS");
 +              return -1;
 +      }
 +      if (!SSL_check_private_key(conn->ssl)) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Private key failed verification");
 +              return -1;
 +      }
 +      return 0;
 +#else /* OPENSSL_NO_ENGINE */
 +      wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
 +                 "engine support was not compiled in");
 +      return -1;
 +#endif /* OPENSSL_NO_ENGINE */
 +}
 +
 +
-       SSL_CTX *ssl_ctx = _ssl_ctx;
++static int tls_connection_private_key(struct tls_data *data,
 +                                    struct tls_connection *conn,
 +                                    const char *private_key,
 +                                    const char *private_key_passwd,
 +                                    const u8 *private_key_blob,
 +                                    size_t private_key_blob_len)
 +{
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)"
-                                       " failed");
++      SSL_CTX *ssl_ctx = data->ssl;
 +      char *passwd;
 +      int ok;
 +
 +      if (private_key == NULL && private_key_blob == NULL)
 +              return 0;
 +
 +      if (private_key_passwd) {
 +              passwd = os_strdup(private_key_passwd);
 +              if (passwd == NULL)
 +                      return -1;
 +      } else
 +              passwd = NULL;
 +
 +      SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
 +      SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
 +
 +      ok = 0;
 +      while (private_key_blob) {
 +              if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
 +                                          (u8 *) private_key_blob,
 +                                          private_key_blob_len) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
 +                                 "ASN1(EVP_PKEY_RSA) --> OK");
 +                      ok = 1;
 +                      break;
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)"
-                                       " failed");
 +              }
 +
 +              if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
 +                                          (u8 *) private_key_blob,
 +                                          private_key_blob_len) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
 +                                 "ASN1(EVP_PKEY_DSA) --> OK");
 +                      ok = 1;
 +                      break;
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_RSAPrivateKey_ASN1 failed");
 +              }
 +
 +              if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
 +                                             (u8 *) private_key_blob,
 +                                             private_key_blob_len) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: "
 +                                 "SSL_use_RSAPrivateKey_ASN1 --> OK");
 +                      ok = 1;
 +                      break;
-               if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
 +              }
 +
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_PrivateKey_File (DER) "
-                                       "failed");
++              if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob,
 +                                       private_key_blob_len, passwd) == 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
 +                                 "OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              break;
 +      }
 +
 +      while (!ok && private_key) {
 +#ifndef OPENSSL_NO_STDIO
 +              if (SSL_use_PrivateKey_file(conn->ssl, private_key,
 +                                          SSL_FILETYPE_ASN1) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: "
 +                                 "SSL_use_PrivateKey_File (DER) --> OK");
 +                      ok = 1;
 +                      break;
-               } else {
-                       tls_show_errors(MSG_DEBUG, __func__,
-                                       "SSL_use_PrivateKey_File (PEM) "
-                                       "failed");
 +              }
 +
 +              if (SSL_use_PrivateKey_file(conn->ssl, private_key,
 +                                          SSL_FILETYPE_PEM) == 1) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: "
 +                                 "SSL_use_PrivateKey_File (PEM) --> OK");
 +                      ok = 1;
 +                      break;
-               if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
 +              }
 +#else /* OPENSSL_NO_STDIO */
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
 +                         __func__);
 +#endif /* OPENSSL_NO_STDIO */
 +
-               wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key");
++              if (tls_read_pkcs12(data, conn->ssl, private_key, passwd)
 +                  == 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
 +                                 "--> OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
 +                      wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
 +                                 "access certificate store --> OK");
 +                      ok = 1;
 +                      break;
 +              }
 +
 +              break;
 +      }
 +
 +      if (!ok) {
-               ERR_clear_error();
++              tls_show_errors(MSG_INFO, __func__,
++                              "Failed to load private key");
 +              os_free(passwd);
-       
 +              return -1;
 +      }
 +      ERR_clear_error();
 +      SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
 +      os_free(passwd);
- static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
++
 +      if (!SSL_check_private_key(conn->ssl)) {
 +              tls_show_errors(MSG_INFO, __func__, "Private key failed "
 +                              "verification");
 +              return -1;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
 +      return 0;
 +}
 +
 +
-           tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
++static int tls_global_private_key(struct tls_data *data,
++                                const char *private_key,
 +                                const char *private_key_passwd)
 +{
++      SSL_CTX *ssl_ctx = data->ssl;
 +      char *passwd;
 +
 +      if (private_key == NULL)
 +              return 0;
 +
 +      if (private_key_passwd) {
 +              passwd = os_strdup(private_key_passwd);
 +              if (passwd == NULL)
 +                      return -1;
 +      } else
 +              passwd = NULL;
 +
 +      SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
 +      SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
 +      if (
 +#ifndef OPENSSL_NO_STDIO
 +          SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
 +                                      SSL_FILETYPE_ASN1) != 1 &&
 +          SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
 +                                      SSL_FILETYPE_PEM) != 1 &&
 +#endif /* OPENSSL_NO_STDIO */
-       
++          tls_read_pkcs12(data, NULL, private_key, passwd)) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Failed to load private key");
 +              os_free(passwd);
 +              ERR_clear_error();
 +              return -1;
 +      }
 +      os_free(passwd);
 +      ERR_clear_error();
 +      SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
- static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
++
 +      if (!SSL_CTX_check_private_key(ssl_ctx)) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Private key failed verification");
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
 +{
 +#ifdef OPENSSL_NO_DH
 +      if (dh_file == NULL)
 +              return 0;
 +      wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
 +                 "dh_file specified");
 +      return -1;
 +#else /* OPENSSL_NO_DH */
 +      DH *dh;
 +      BIO *bio;
 +
 +      /* TODO: add support for dh_blob */
 +      if (dh_file == NULL)
 +              return 0;
 +      if (conn == NULL)
 +              return -1;
 +
 +      bio = BIO_new_file(dh_file, "r");
 +      if (bio == NULL) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
 +                         dh_file, ERR_error_string(ERR_get_error(), NULL));
 +              return -1;
 +      }
 +      dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
 +      BIO_free(bio);
 +#ifndef OPENSSL_NO_DSA
 +      while (dh == NULL) {
 +              DSA *dsa;
 +              wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
 +                         " trying to parse as DSA params", dh_file,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              bio = BIO_new_file(dh_file, "r");
 +              if (bio == NULL)
 +                      break;
 +              dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
 +              BIO_free(bio);
 +              if (!dsa) {
 +                      wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
 +                                 "'%s': %s", dh_file,
 +                                 ERR_error_string(ERR_get_error(), NULL));
 +                      break;
 +              }
 +
 +              wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
 +              dh = DSA_dup_DH(dsa);
 +              DSA_free(dsa);
 +              if (dh == NULL) {
 +                      wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
 +                                 "params into DH params");
 +                      break;
 +              }
 +              break;
 +      }
 +#endif /* !OPENSSL_NO_DSA */
 +      if (dh == NULL) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
 +                         "'%s'", dh_file);
 +              return -1;
 +      }
 +
 +      if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
 +                         "%s", dh_file,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              DH_free(dh);
 +              return -1;
 +      }
 +      DH_free(dh);
 +      return 0;
 +#endif /* OPENSSL_NO_DH */
 +}
 +
 +
- int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
-                           struct tls_keys *keys)
++static int tls_global_dh(struct tls_data *data, const char *dh_file)
 +{
 +#ifdef OPENSSL_NO_DH
 +      if (dh_file == NULL)
 +              return 0;
 +      wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
 +                 "dh_file specified");
 +      return -1;
 +#else /* OPENSSL_NO_DH */
++      SSL_CTX *ssl_ctx = data->ssl;
 +      DH *dh;
 +      BIO *bio;
 +
 +      /* TODO: add support for dh_blob */
 +      if (dh_file == NULL)
 +              return 0;
 +      if (ssl_ctx == NULL)
 +              return -1;
 +
 +      bio = BIO_new_file(dh_file, "r");
 +      if (bio == NULL) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
 +                         dh_file, ERR_error_string(ERR_get_error(), NULL));
 +              return -1;
 +      }
 +      dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
 +      BIO_free(bio);
 +#ifndef OPENSSL_NO_DSA
 +      while (dh == NULL) {
 +              DSA *dsa;
 +              wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
 +                         " trying to parse as DSA params", dh_file,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              bio = BIO_new_file(dh_file, "r");
 +              if (bio == NULL)
 +                      break;
 +              dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
 +              BIO_free(bio);
 +              if (!dsa) {
 +                      wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
 +                                 "'%s': %s", dh_file,
 +                                 ERR_error_string(ERR_get_error(), NULL));
 +                      break;
 +              }
 +
 +              wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
 +              dh = DSA_dup_DH(dsa);
 +              DSA_free(dsa);
 +              if (dh == NULL) {
 +                      wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
 +                                 "params into DH params");
 +                      break;
 +              }
 +              break;
 +      }
 +#endif /* !OPENSSL_NO_DSA */
 +      if (dh == NULL) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
 +                         "'%s'", dh_file);
 +              return -1;
 +      }
 +
 +      if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
 +                         "%s", dh_file,
 +                         ERR_error_string(ERR_get_error(), NULL));
 +              DH_free(dh);
 +              return -1;
 +      }
 +      DH_free(dh);
 +      return 0;
 +#endif /* OPENSSL_NO_DH */
 +}
 +
 +
-       keys->master_key = ssl->session->master_key;
-       keys->master_key_len = ssl->session->master_key_length;
++int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn,
++                            struct tls_random *keys)
 +{
 +      SSL *ssl;
 +
 +      if (conn == NULL || keys == NULL)
 +              return -1;
 +      ssl = conn->ssl;
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
 +      if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
 +              return -1;
 +
 +      os_memset(keys, 0, sizeof(*keys));
-                      u8 *out, size_t out_len)
 +      keys->client_random = ssl->s3->client_random;
 +      keys->client_random_len = SSL3_RANDOM_SIZE;
 +      keys->server_random = ssl->s3->server_random;
 +      keys->server_random_len = SSL3_RANDOM_SIZE;
++#else
++      if (ssl == NULL)
++              return -1;
++
++      os_memset(keys, 0, sizeof(*keys));
++      keys->client_random = conn->client_random;
++      keys->client_random_len = SSL_get_client_random(
++              ssl, conn->client_random, sizeof(conn->client_random));
++      keys->server_random = conn->server_random;
++      keys->server_random_len = SSL_get_server_random(
++              ssl, conn->server_random, sizeof(conn->server_random));
++#endif
 +
 +      return 0;
 +}
 +
 +
++#ifndef CONFIG_FIPS
++static int openssl_get_keyblock_size(SSL *ssl)
++{
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++      const EVP_CIPHER *c;
++      const EVP_MD *h;
++      int md_size;
++
++      if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL ||
++          ssl->read_hash == NULL)
++              return -1;
++
++      c = ssl->enc_read_ctx->cipher;
++#if OPENSSL_VERSION_NUMBER >= 0x00909000L
++      h = EVP_MD_CTX_md(ssl->read_hash);
++#else
++      h = ssl->read_hash;
++#endif
++      if (h)
++              md_size = EVP_MD_size(h);
++#if OPENSSL_VERSION_NUMBER >= 0x10000000L
++      else if (ssl->s3)
++              md_size = ssl->s3->tmp.new_mac_secret_size;
++#endif
++      else
++              return -1;
++
++      wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
++                 "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
++                 EVP_CIPHER_iv_length(c));
++      return 2 * (EVP_CIPHER_key_length(c) +
++                  md_size +
++                  EVP_CIPHER_iv_length(c));
++#else
++      const SSL_CIPHER *ssl_cipher;
++      int cipher, digest;
++      const EVP_CIPHER *c;
++      const EVP_MD *h;
++
++      ssl_cipher = SSL_get_current_cipher(ssl);
++      if (!ssl_cipher)
++              return -1;
++      cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher);
++      digest = SSL_CIPHER_get_digest_nid(ssl_cipher);
++      wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d",
++                 cipher, digest);
++      if (cipher < 0 || digest < 0)
++              return -1;
++      c = EVP_get_cipherbynid(cipher);
++      h = EVP_get_digestbynid(digest);
++      if (!c || !h)
++              return -1;
++
++      wpa_printf(MSG_DEBUG,
++                 "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d",
++                 EVP_CIPHER_key_length(c), EVP_MD_size(h),
++                 EVP_CIPHER_iv_length(c));
++      return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) +
++                  EVP_CIPHER_iv_length(c));
++#endif
++}
++#endif /* CONFIG_FIPS */
++
++
++static int openssl_tls_prf(struct tls_connection *conn,
++                         const char *label, int server_random_first,
++                         int skip_keyblock, u8 *out, size_t out_len)
++{
++#ifdef CONFIG_FIPS
++      wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
++                 "mode");
++      return -1;
++#else /* CONFIG_FIPS */
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++      SSL *ssl;
++      u8 *rnd;
++      int ret = -1;
++      int skip = 0;
++      u8 *tmp_out = NULL;
++      u8 *_out = out;
++      const char *ver;
++
++      /*
++       * TLS library did not support key generation, so get the needed TLS
++       * session parameters and use an internal implementation of TLS PRF to
++       * derive the key.
++       */
++
++      if (conn == NULL)
++              return -1;
++      ssl = conn->ssl;
++      if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL ||
++          ssl->session->master_key_length <= 0)
++              return -1;
++      ver = SSL_get_version(ssl);
++
++      if (skip_keyblock) {
++              skip = openssl_get_keyblock_size(ssl);
++              if (skip < 0)
++                      return -1;
++              tmp_out = os_malloc(skip + out_len);
++              if (!tmp_out)
++                      return -1;
++              _out = tmp_out;
++      }
++
++      rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
++      if (!rnd) {
++              os_free(tmp_out);
++              return -1;
++      }
++
++      if (server_random_first) {
++              os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE);
++              os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random,
++                      SSL3_RANDOM_SIZE);
++      } else {
++              os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE);
++              os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random,
++                      SSL3_RANDOM_SIZE);
++      }
++
++      if (os_strcmp(ver, "TLSv1.2") == 0) {
++              tls_prf_sha256(ssl->session->master_key,
++                             ssl->session->master_key_length,
++                             label, rnd, 2 * SSL3_RANDOM_SIZE,
++                             _out, skip + out_len);
++              ret = 0;
++      } else if (tls_prf_sha1_md5(ssl->session->master_key,
++                                  ssl->session->master_key_length,
++                                  label, rnd, 2 * SSL3_RANDOM_SIZE,
++                                  _out, skip + out_len) == 0) {
++              ret = 0;
++      }
++      os_free(rnd);
++      if (ret == 0 && skip_keyblock)
++              os_memcpy(out, _out + skip, out_len);
++      bin_clear_free(tmp_out, skip);
++
++      return ret;
++#else
++      SSL *ssl;
++      SSL_SESSION *sess;
++      u8 *rnd;
++      int ret = -1;
++      int skip = 0;
++      u8 *tmp_out = NULL;
++      u8 *_out = out;
++      unsigned char client_random[SSL3_RANDOM_SIZE];
++      unsigned char server_random[SSL3_RANDOM_SIZE];
++      unsigned char master_key[64];
++      size_t master_key_len;
++      const char *ver;
++
++      /*
++       * TLS library did not support key generation, so get the needed TLS
++       * session parameters and use an internal implementation of TLS PRF to
++       * derive the key.
++       */
++
++      if (conn == NULL)
++              return -1;
++      ssl = conn->ssl;
++      if (ssl == NULL)
++              return -1;
++      ver = SSL_get_version(ssl);
++      sess = SSL_get_session(ssl);
++      if (!ver || !sess)
++              return -1;
++
++      if (skip_keyblock) {
++              skip = openssl_get_keyblock_size(ssl);
++              if (skip < 0)
++                      return -1;
++              tmp_out = os_malloc(skip + out_len);
++              if (!tmp_out)
++                      return -1;
++              _out = tmp_out;
++      }
++
++      rnd = os_malloc(2 * SSL3_RANDOM_SIZE);
++      if (!rnd) {
++              os_free(tmp_out);
++              return -1;
++      }
++
++      SSL_get_client_random(ssl, client_random, sizeof(client_random));
++      SSL_get_server_random(ssl, server_random, sizeof(server_random));
++      master_key_len = SSL_SESSION_get_master_key(sess, master_key,
++                                                  sizeof(master_key));
++
++      if (server_random_first) {
++              os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
++              os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random,
++                        SSL3_RANDOM_SIZE);
++      } else {
++              os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE);
++              os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random,
++                        SSL3_RANDOM_SIZE);
++      }
++
++      if (os_strcmp(ver, "TLSv1.2") == 0) {
++              tls_prf_sha256(master_key, master_key_len,
++                             label, rnd, 2 * SSL3_RANDOM_SIZE,
++                             _out, skip + out_len);
++              ret = 0;
++      } else if (tls_prf_sha1_md5(master_key, master_key_len,
++                                  label, rnd, 2 * SSL3_RANDOM_SIZE,
++                                  _out, skip + out_len) == 0) {
++              ret = 0;
++      }
++      os_memset(master_key, 0, sizeof(master_key));
++      os_free(rnd);
++      if (ret == 0 && skip_keyblock)
++              os_memcpy(out, _out + skip, out_len);
++      bin_clear_free(tmp_out, skip);
++
++      return ret;
++#endif
++#endif /* CONFIG_FIPS */
++}
++
++
 +int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
 +                     const char *label, int server_random_first,
-       return -1;
++                     int skip_keyblock, u8 *out, size_t out_len)
 +{
-       if (in_data &&
++#if OPENSSL_VERSION_NUMBER >= 0x10001000L
++      SSL *ssl;
++      if (conn == NULL)
++              return -1;
++      if (server_random_first || skip_keyblock)
++              return openssl_tls_prf(conn, label,
++                                     server_random_first, skip_keyblock,
++                                     out, out_len);
++      ssl = conn->ssl;
++      if (SSL_export_keying_material(ssl, out, out_len, label,
++                                     os_strlen(label), NULL, 0, 0) == 1) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
++              return 0;
++      }
++#endif
++      return openssl_tls_prf(conn, label, server_random_first,
++                             skip_keyblock, out, out_len);
 +}
 +
 +
 +static struct wpabuf *
 +openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
 +                int server)
 +{
 +      int res;
 +      struct wpabuf *out_data;
 +
 +      /*
 +       * Give TLS handshake data from the server (if available) to OpenSSL
 +       * for processing.
 +       */
-       if (SSL_is_init_finished(conn->ssl) && appl_data && in_data)
-               *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data));
++      if (in_data && wpabuf_len(in_data) > 0 &&
 +          BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
 +          < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Handshake failed - BIO_write");
 +              return NULL;
 +      }
 +
 +      /* Initiate TLS handshake or continue the existing handshake */
 +      if (server)
 +              res = SSL_accept(conn->ssl);
 +      else
 +              res = SSL_connect(conn->ssl);
 +      if (res != 1) {
 +              int err = SSL_get_error(conn->ssl, res);
 +              if (err == SSL_ERROR_WANT_READ)
 +                      wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want "
 +                                 "more data");
 +              else if (err == SSL_ERROR_WANT_WRITE)
 +                      wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
 +                                 "write");
 +              else {
 +                      tls_show_errors(MSG_INFO, __func__, "SSL_connect");
 +                      conn->failed++;
 +              }
 +      }
 +
 +      /* Get the TLS handshake data to be sent to the server */
 +      res = BIO_ctrl_pending(conn->ssl_out);
 +      wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
 +      out_data = wpabuf_alloc(res);
 +      if (out_data == NULL) {
 +              wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
 +                         "handshake output (%d bytes)", res);
 +              if (BIO_reset(conn->ssl_out) < 0) {
 +                      tls_show_errors(MSG_INFO, __func__,
 +                                      "BIO_reset failed");
 +              }
 +              return NULL;
 +      }
 +      res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data),
 +                                    res);
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Handshake failed - BIO_read");
 +              if (BIO_reset(conn->ssl_out) < 0) {
 +                      tls_show_errors(MSG_INFO, __func__,
 +                                      "BIO_reset failed");
 +              }
 +              wpabuf_free(out_data);
 +              return NULL;
 +      }
 +      wpabuf_put(out_data, res);
 +
 +      return out_data;
 +}
 +
 +
 +static struct wpabuf *
 +openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
 +{
 +      struct wpabuf *appl_data;
 +      int res;
 +
 +      appl_data = wpabuf_alloc(max_len + 100);
 +      if (appl_data == NULL)
 +              return NULL;
 +
 +      res = SSL_read(conn->ssl, wpabuf_mhead(appl_data),
 +                     wpabuf_size(appl_data));
 +      if (res < 0) {
 +              int err = SSL_get_error(conn->ssl, res);
 +              if (err == SSL_ERROR_WANT_READ ||
 +                  err == SSL_ERROR_WANT_WRITE) {
 +                      wpa_printf(MSG_DEBUG, "SSL: No Application Data "
 +                                 "included");
 +              } else {
 +                      tls_show_errors(MSG_INFO, __func__,
 +                                      "Failed to read possible "
 +                                      "Application Data");
 +              }
 +              wpabuf_free(appl_data);
 +              return NULL;
 +      }
 +
 +      wpabuf_put(appl_data, res);
 +      wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
 +                          "message", appl_data);
 +
 +      return appl_data;
 +}
 +
 +
 +static struct wpabuf *
 +openssl_connection_handshake(struct tls_connection *conn,
 +                           const struct wpabuf *in_data,
 +                           struct wpabuf **appl_data, int server)
 +{
 +      struct wpabuf *out_data;
 +
 +      if (appl_data)
 +              *appl_data = NULL;
 +
 +      out_data = openssl_handshake(conn, in_data, server);
 +      if (out_data == NULL)
 +              return NULL;
++      if (conn->invalid_hb_used) {
++              wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
++              wpabuf_free(out_data);
++              return NULL;
++      }
 +
-               if (ret < 0 || ret >= end - pos)
++      if (SSL_is_init_finished(conn->ssl)) {
++              wpa_printf(MSG_DEBUG,
++                         "OpenSSL: Handshake finished - resumed=%d",
++                         tls_connection_resumed(conn->ssl_ctx, conn));
++              if (appl_data && in_data)
++                      *appl_data = openssl_get_appl_data(conn,
++                                                         wpabuf_len(in_data));
++      }
++
++      if (conn->invalid_hb_used) {
++              wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
++              if (appl_data) {
++                      wpabuf_free(*appl_data);
++                      *appl_data = NULL;
++              }
++              wpabuf_free(out_data);
++              return NULL;
++      }
 +
 +      return out_data;
 +}
 +
 +
 +struct wpabuf *
 +tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
 +                       const struct wpabuf *in_data,
 +                       struct wpabuf **appl_data)
 +{
 +      return openssl_connection_handshake(conn, in_data, appl_data, 0);
 +}
 +
 +
 +struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
 +                                              struct tls_connection *conn,
 +                                              const struct wpabuf *in_data,
 +                                              struct wpabuf **appl_data)
 +{
 +      return openssl_connection_handshake(conn, in_data, appl_data, 1);
 +}
 +
 +
 +struct wpabuf * tls_connection_encrypt(void *tls_ctx,
 +                                     struct tls_connection *conn,
 +                                     const struct wpabuf *in_data)
 +{
 +      int res;
 +      struct wpabuf *buf;
 +
 +      if (conn == NULL)
 +              return NULL;
 +
 +      /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
 +      if ((res = BIO_reset(conn->ssl_in)) < 0 ||
 +          (res = BIO_reset(conn->ssl_out)) < 0) {
 +              tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
 +              return NULL;
 +      }
 +      res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Encryption failed - SSL_write");
 +              return NULL;
 +      }
 +
 +      /* Read encrypted data to be sent to the server */
 +      buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
 +      if (buf == NULL)
 +              return NULL;
 +      res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf));
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Encryption failed - BIO_read");
 +              wpabuf_free(buf);
 +              return NULL;
 +      }
 +      wpabuf_put(buf, res);
 +
 +      return buf;
 +}
 +
 +
 +struct wpabuf * tls_connection_decrypt(void *tls_ctx,
 +                                     struct tls_connection *conn,
 +                                     const struct wpabuf *in_data)
 +{
 +      int res;
 +      struct wpabuf *buf;
 +
 +      /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
 +      res = BIO_write(conn->ssl_in, wpabuf_head(in_data),
 +                      wpabuf_len(in_data));
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Decryption failed - BIO_write");
 +              return NULL;
 +      }
 +      if (BIO_reset(conn->ssl_out) < 0) {
 +              tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
 +              return NULL;
 +      }
 +
 +      /* Read decrypted data for further processing */
 +      /*
 +       * Even though we try to disable TLS compression, it is possible that
 +       * this cannot be done with all TLS libraries. Add extra buffer space
 +       * to handle the possibility of the decrypted data being longer than
 +       * input data.
 +       */
 +      buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
 +      if (buf == NULL)
 +              return NULL;
 +      res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
 +      if (res < 0) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Decryption failed - SSL_read");
 +              wpabuf_free(buf);
 +              return NULL;
 +      }
 +      wpabuf_put(buf, res);
 +
++      if (conn->invalid_hb_used) {
++              wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response");
++              wpabuf_free(buf);
++              return NULL;
++      }
++
 +      return buf;
 +}
 +
 +
 +int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
 +{
++#if OPENSSL_VERSION_NUMBER >= 0x10001000L
++      return conn ? SSL_cache_hit(conn->ssl) : 0;
++#else
 +      return conn ? conn->ssl->hit : 0;
++#endif
 +}
 +
 +
 +int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 +                                 u8 *ciphers)
 +{
 +      char buf[100], *pos, *end;
 +      u8 *c;
 +      int ret;
 +
 +      if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
 +              return -1;
 +
 +      buf[0] = '\0';
 +      pos = buf;
 +      end = pos + sizeof(buf);
 +
 +      c = ciphers;
 +      while (*c != TLS_CIPHER_NONE) {
 +              const char *suite;
 +
 +              switch (*c) {
 +              case TLS_CIPHER_RC4_SHA:
 +                      suite = "RC4-SHA";
 +                      break;
 +              case TLS_CIPHER_AES128_SHA:
 +                      suite = "AES128-SHA";
 +                      break;
 +              case TLS_CIPHER_RSA_DHE_AES128_SHA:
 +                      suite = "DHE-RSA-AES128-SHA";
 +                      break;
 +              case TLS_CIPHER_ANON_DH_AES128_SHA:
 +                      suite = "ADH-AES128-SHA";
 +                      break;
 +              default:
 +                      wpa_printf(MSG_DEBUG, "TLS: Unsupported "
 +                                 "cipher selection: %d", *c);
 +                      return -1;
 +              }
 +              ret = os_snprintf(pos, end - pos, ":%s", suite);
- #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
++              if (os_snprintf_error(end - pos, ret))
 +                      break;
 +              pos += ret;
 +
 +              c++;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
 +
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L
++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
++      if (os_strstr(buf, ":ADH-")) {
++              /*
++               * Need to drop to security level 0 to allow anonymous
++               * cipher suites for EAP-FAST.
++               */
++              SSL_set_security_level(conn->ssl, 0);
++      } else if (SSL_get_security_level(conn->ssl) == 0) {
++              /* Force at least security level 1 */
++              SSL_set_security_level(conn->ssl, 1);
++      }
++#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
++#endif
++
 +      if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
 +              tls_show_errors(MSG_INFO, __func__,
 +                              "Cipher suite configuration failed");
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
++int tls_get_version(void *ssl_ctx, struct tls_connection *conn,
++                  char *buf, size_t buflen)
++{
++      const char *name;
++      if (conn == NULL || conn->ssl == NULL)
++              return -1;
++
++      name = SSL_get_version(conn->ssl);
++      if (name == NULL)
++              return -1;
++
++      os_strlcpy(buf, name, buflen);
++      return 0;
++}
++
++
 +int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
 +                 char *buf, size_t buflen)
 +{
 +      const char *name;
 +      if (conn == NULL || conn->ssl == NULL)
 +              return -1;
 +
 +      name = SSL_get_cipher(conn->ssl);
 +      if (name == NULL)
 +              return -1;
 +
 +      os_strlcpy(buf, name, buflen);
 +      return 0;
 +}
 +
 +
 +int tls_connection_enable_workaround(void *ssl_ctx,
 +                                   struct tls_connection *conn)
 +{
 +      SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
 +
 +      return 0;
 +}
 +
 +
 +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 +/* ClientHello TLS extensions require a patch to openssl, so this function is
 + * commented out unless explicitly needed for EAP-FAST in order to be able to
 + * build this file with unmodified openssl. */
 +int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
 +                                  int ext_type, const u8 *data,
 +                                  size_t data_len)
 +{
 +      if (conn == NULL || conn->ssl == NULL || ext_type != 35)
 +              return -1;
 +
- #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-       if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
-                                   data_len) != 1)
-               return -1;
- #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
 +      if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
 +                                     data_len) != 1)
 +              return -1;
-       if (params->engine) {
 +
 +      return 0;
 +}
 +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +
 +
 +int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return -1;
 +      return conn->failed;
 +}
 +
 +
 +int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return -1;
 +      return conn->read_alerts;
 +}
 +
 +
 +int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
 +{
 +      if (conn == NULL)
 +              return -1;
 +      return conn->write_alerts;
 +}
 +
 +
++#ifdef HAVE_OCSP
++
++static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp)
++{
++#ifndef CONFIG_NO_STDOUT_DEBUG
++      BIO *out;
++      size_t rlen;
++      char *txt;
++      int res;
++
++      if (wpa_debug_level > MSG_DEBUG)
++              return;
++
++      out = BIO_new(BIO_s_mem());
++      if (!out)
++              return;
++
++      OCSP_RESPONSE_print(out, rsp, 0);
++      rlen = BIO_ctrl_pending(out);
++      txt = os_malloc(rlen + 1);
++      if (!txt) {
++              BIO_free(out);
++              return;
++      }
++
++      res = BIO_read(out, txt, rlen);
++      if (res > 0) {
++              txt[res] = '\0';
++              wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt);
++      }
++      os_free(txt);
++      BIO_free(out);
++#endif /* CONFIG_NO_STDOUT_DEBUG */
++}
++
++
++static void debug_print_cert(X509 *cert, const char *title)
++{
++#ifndef CONFIG_NO_STDOUT_DEBUG
++      BIO *out;
++      size_t rlen;
++      char *txt;
++      int res;
++
++      if (wpa_debug_level > MSG_DEBUG)
++              return;
++
++      out = BIO_new(BIO_s_mem());
++      if (!out)
++              return;
++
++      X509_print(out, cert);
++      rlen = BIO_ctrl_pending(out);
++      txt = os_malloc(rlen + 1);
++      if (!txt) {
++              BIO_free(out);
++              return;
++      }
++
++      res = BIO_read(out, txt, rlen);
++      if (res > 0) {
++              txt[res] = '\0';
++              wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt);
++      }
++      os_free(txt);
++
++      BIO_free(out);
++#endif /* CONFIG_NO_STDOUT_DEBUG */
++}
++
++
++static int ocsp_resp_cb(SSL *s, void *arg)
++{
++      struct tls_connection *conn = arg;
++      const unsigned char *p;
++      int len, status, reason;
++      OCSP_RESPONSE *rsp;
++      OCSP_BASICRESP *basic;
++      OCSP_CERTID *id;
++      ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update;
++      X509_STORE *store;
++      STACK_OF(X509) *certs = NULL;
++
++      len = SSL_get_tlsext_status_ocsp_resp(s, &p);
++      if (!p) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received");
++              return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
++      }
++
++      wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len);
++
++      rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
++      if (!rsp) {
++              wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response");
++              return 0;
++      }
++
++      ocsp_debug_print_resp(rsp);
++
++      status = OCSP_response_status(rsp);
++      if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) {
++              wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)",
++                         status, OCSP_response_status_str(status));
++              return 0;
++      }
++
++      basic = OCSP_response_get1_basic(rsp);
++      if (!basic) {
++              wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse");
++              return 0;
++      }
++
++      store = SSL_CTX_get_cert_store(conn->ssl_ctx);
++      if (conn->peer_issuer) {
++              debug_print_cert(conn->peer_issuer, "Add OCSP issuer");
++
++              if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) {
++                      tls_show_errors(MSG_INFO, __func__,
++                                      "OpenSSL: Could not add issuer to certificate store");
++              }
++              certs = sk_X509_new_null();
++              if (certs) {
++                      X509 *cert;
++                      cert = X509_dup(conn->peer_issuer);
++                      if (cert && !sk_X509_push(certs, cert)) {
++                              tls_show_errors(
++                                      MSG_INFO, __func__,
++                                      "OpenSSL: Could not add issuer to OCSP responder trust store");
++                              X509_free(cert);
++                              sk_X509_free(certs);
++                              certs = NULL;
++                      }
++                      if (certs && conn->peer_issuer_issuer) {
++                              cert = X509_dup(conn->peer_issuer_issuer);
++                              if (cert && !sk_X509_push(certs, cert)) {
++                                      tls_show_errors(
++                                              MSG_INFO, __func__,
++                                              "OpenSSL: Could not add issuer's issuer to OCSP responder trust store");
++                                      X509_free(cert);
++                              }
++                      }
++              }
++      }
++
++      status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER);
++      sk_X509_pop_free(certs, X509_free);
++      if (status <= 0) {
++              tls_show_errors(MSG_INFO, __func__,
++                              "OpenSSL: OCSP response failed verification");
++              OCSP_BASICRESP_free(basic);
++              OCSP_RESPONSE_free(rsp);
++              return 0;
++      }
++
++      wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded");
++
++      if (!conn->peer_cert) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check");
++              OCSP_BASICRESP_free(basic);
++              OCSP_RESPONSE_free(rsp);
++              return 0;
++      }
++
++      if (!conn->peer_issuer) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check");
++              OCSP_BASICRESP_free(basic);
++              OCSP_RESPONSE_free(rsp);
++              return 0;
++      }
++
++      id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer);
++      if (!id) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier");
++              OCSP_BASICRESP_free(basic);
++              OCSP_RESPONSE_free(rsp);
++              return 0;
++      }
++
++      if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at,
++                                 &this_update, &next_update)) {
++              wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s",
++                         (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" :
++                         " (OCSP not required)");
++              OCSP_BASICRESP_free(basic);
++              OCSP_RESPONSE_free(rsp);
++              return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
++      }
++
++      if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) {
++              tls_show_errors(MSG_INFO, __func__,
++                              "OpenSSL: OCSP status times invalid");
++              OCSP_BASICRESP_free(basic);
++              OCSP_RESPONSE_free(rsp);
++              return 0;
++      }
++
++      OCSP_BASICRESP_free(basic);
++      OCSP_RESPONSE_free(rsp);
++
++      wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s",
++                 OCSP_cert_status_str(status));
++
++      if (status == V_OCSP_CERTSTATUS_GOOD)
++              return 1;
++      if (status == V_OCSP_CERTSTATUS_REVOKED)
++              return 0;
++      if (conn->flags & TLS_CONN_REQUIRE_OCSP) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required");
++              return 0;
++      }
++      wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue");
++      return 1;
++}
++
++
++static int ocsp_status_cb(SSL *s, void *arg)
++{
++      char *tmp;
++      char *resp;
++      size_t len;
++
++      if (tls_global->ocsp_stapling_response == NULL) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured");
++              return SSL_TLSEXT_ERR_OK;
++      }
++
++      resp = os_readfile(tls_global->ocsp_stapling_response, &len);
++      if (resp == NULL) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file");
++              /* TODO: Build OCSPResponse with responseStatus = internalError
++               */
++              return SSL_TLSEXT_ERR_OK;
++      }
++      wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response");
++      tmp = OPENSSL_malloc(len);
++      if (tmp == NULL) {
++              os_free(resp);
++              return SSL_TLSEXT_ERR_ALERT_FATAL;
++      }
++
++      os_memcpy(tmp, resp, len);
++      os_free(resp);
++      SSL_set_tlsext_status_ocsp_resp(s, tmp, len);
++
++      return SSL_TLSEXT_ERR_OK;
++}
++
++#endif /* HAVE_OCSP */
++
++
 +int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 +                            const struct tls_connection_params *params)
 +{
++      struct tls_data *data = tls_ctx;
 +      int ret;
 +      unsigned long err;
++      int can_pkcs11 = 0;
++      const char *key_id = params->key_id;
++      const char *cert_id = params->cert_id;
++      const char *ca_cert_id = params->ca_cert_id;
++      const char *engine_id = params->engine ? params->engine_id : NULL;
 +
 +      if (conn == NULL)
 +              return -1;
 +
++      /*
++       * If the engine isn't explicitly configured, and any of the
++       * cert/key fields are actually PKCS#11 URIs, then automatically
++       * use the PKCS#11 ENGINE.
++       */
++      if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
++              can_pkcs11 = 1;
++
++      if (!key_id && params->private_key && can_pkcs11 &&
++          os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
++              can_pkcs11 = 2;
++              key_id = params->private_key;
++      }
++
++      if (!cert_id && params->client_cert && can_pkcs11 &&
++          os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
++              can_pkcs11 = 2;
++              cert_id = params->client_cert;
++      }
++
++      if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
++          os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
++              can_pkcs11 = 2;
++              ca_cert_id = params->ca_cert;
++      }
++
++      /* If we need to automatically enable the PKCS#11 ENGINE, do so. */
++      if (can_pkcs11 == 2 && !engine_id)
++              engine_id = "pkcs11";
++
++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
++      if (params->flags & TLS_CONN_EAP_FAST) {
++              wpa_printf(MSG_DEBUG,
++                         "OpenSSL: Use TLSv1_method() for EAP-FAST");
++              if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
++                      tls_show_errors(MSG_INFO, __func__,
++                                      "Failed to set TLSv1_method() for EAP-FAST");
++                      return -1;
++              }
++      }
++#endif
++#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
++
 +      while ((err = ERR_get_error())) {
 +              wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
 +                         __func__, ERR_error_string(err, NULL));
 +      }
 +
-               ret = tls_engine_init(conn, params->engine_id, params->pin,
-                                     params->key_id, params->cert_id,
-                                     params->ca_cert_id);
++      if (engine_id) {
 +              wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
-                                            params->altsubject_match))
++              ret = tls_engine_init(conn, engine_id, params->pin,
++                                    key_id, cert_id, ca_cert_id);
 +              if (ret)
 +                      return ret;
 +      }
 +      if (tls_connection_set_subject_match(conn,
 +                                           params->subject_match,
-       if (params->engine && params->ca_cert_id) {
-               if (tls_connection_engine_ca_cert(tls_ctx, conn,
-                                                 params->ca_cert_id))
++                                           params->altsubject_match,
++                                           params->suffix_match,
++                                           params->domain_match))
 +              return -1;
 +
-       } else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
++      if (engine_id && ca_cert_id) {
++              if (tls_connection_engine_ca_cert(data, conn, ca_cert_id))
 +                      return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
-       if (params->engine && params->cert_id) {
-               if (tls_connection_engine_client_cert(conn, params->cert_id))
++      } else if (tls_connection_ca_cert(data, conn, params->ca_cert,
 +                                        params->ca_cert_blob,
 +                                        params->ca_cert_blob_len,
 +                                        params->ca_path))
 +              return -1;
 +
-       if (params->engine && params->key_id) {
++      if (engine_id && cert_id) {
++              if (tls_connection_engine_client_cert(conn, cert_id))
 +                      return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
 +      } else if (tls_connection_client_cert(conn, params->client_cert,
 +                                            params->client_cert_blob,
 +                                            params->client_cert_blob_len))
 +              return -1;
 +
-       } else if (tls_connection_private_key(tls_ctx, conn,
++      if (engine_id && key_id) {
 +              wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
 +              if (tls_connection_engine_private_key(conn))
 +                      return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
-       tls_get_errors(tls_ctx);
++      } else if (tls_connection_private_key(data, conn,
 +                                            params->private_key,
 +                                            params->private_key_passwd,
 +                                            params->private_key_blob,
 +                                            params->private_key_blob_len)) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
 +                         params->private_key);
 +              return -1;
 +      }
 +
 +      if (tls_connection_dh(conn, params->dh_file)) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
 +                         params->dh_file);
 +              return -1;
 +      }
 +
-       SSL_CTX *ssl_ctx = tls_ctx;
++      if (params->openssl_ciphers &&
++          SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
++              wpa_printf(MSG_INFO,
++                         "OpenSSL: Failed to set cipher string '%s'",
++                         params->openssl_ciphers);
++              return -1;
++      }
++
++      tls_set_conn_flags(conn->ssl, params->flags);
++
++#ifdef HAVE_OCSP
++      if (params->flags & TLS_CONN_REQUEST_OCSP) {
++              SSL_CTX *ssl_ctx = data->ssl;
++              SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp);
++              SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb);
++              SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn);
++      }
++#else /* HAVE_OCSP */
++      if (params->flags & TLS_CONN_REQUIRE_OCSP) {
++              wpa_printf(MSG_INFO,
++                         "OpenSSL: No OCSP support included - reject configuration");
++              return -1;
++      }
++      if (params->flags & TLS_CONN_REQUEST_OCSP) {
++              wpa_printf(MSG_DEBUG,
++                         "OpenSSL: No OCSP support included - allow optional OCSP case to continue");
++      }
++#endif /* HAVE_OCSP */
++
++      conn->flags = params->flags;
++
++      tls_get_errors(data);
 +
 +      return 0;
 +}
 +
 +
 +int tls_global_set_params(void *tls_ctx,
 +                        const struct tls_connection_params *params)
 +{
-       if (tls_global_ca_cert(ssl_ctx, params->ca_cert))
-               return -1;
-       if (tls_global_client_cert(ssl_ctx, params->client_cert))
-               return -1;
-       if (tls_global_private_key(ssl_ctx, params->private_key,
-                                  params->private_key_passwd))
-               return -1;
-       if (tls_global_dh(ssl_ctx, params->dh_file)) {
-               wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
-                          params->dh_file);
++      struct tls_data *data = tls_ctx;
++      SSL_CTX *ssl_ctx = data->ssl;
 +      unsigned long err;
 +
 +      while ((err = ERR_get_error())) {
 +              wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
 +                         __func__, ERR_error_string(err, NULL));
 +      }
 +
-       return 0;
- }
- int tls_connection_get_keyblock_size(void *tls_ctx,
-                                    struct tls_connection *conn)
- {
-       const EVP_CIPHER *c;
-       const EVP_MD *h;
-       if (conn == NULL || conn->ssl == NULL ||
-           conn->ssl->enc_read_ctx == NULL ||
-           conn->ssl->enc_read_ctx->cipher == NULL ||
-           conn->ssl->read_hash == NULL)
++      if (tls_global_ca_cert(data, params->ca_cert) ||
++          tls_global_client_cert(data, params->client_cert) ||
++          tls_global_private_key(data, params->private_key,
++                                 params->private_key_passwd) ||
++          tls_global_dh(data, params->dh_file)) {
++              wpa_printf(MSG_INFO, "TLS: Failed to set global parameters");
 +              return -1;
 +      }
 +
-       c = conn->ssl->enc_read_ctx->cipher;
- #if OPENSSL_VERSION_NUMBER >= 0x00909000L
-       h = EVP_MD_CTX_md(conn->ssl->read_hash);
- #else
-       h = conn->ssl->read_hash;
- #endif
-       return 2 * (EVP_CIPHER_key_length(c) +
-                   EVP_MD_size(h) +
-                   EVP_CIPHER_iv_length(c));
- }
++      if (params->openssl_ciphers &&
++          SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
++              wpa_printf(MSG_INFO,
++                         "OpenSSL: Failed to set cipher string '%s'",
++                         params->openssl_ciphers);
 +              return -1;
++      }
 +
- unsigned int tls_capabilities(void *tls_ctx)
- {
++#ifdef SSL_OP_NO_TICKET
++      if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
++              SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
++#ifdef SSL_CTX_clear_options
++      else
++              SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
++#endif /* SSL_clear_options */
++#endif /*  SSL_OP_NO_TICKET */
++
++#ifdef HAVE_OCSP
++      SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_status_cb);
++      SSL_CTX_set_tlsext_status_arg(ssl_ctx, ssl_ctx);
++      os_free(tls_global->ocsp_stapling_response);
++      if (params->ocsp_stapling_response)
++              tls_global->ocsp_stapling_response =
++                      os_strdup(params->ocsp_stapling_response);
++      else
++              tls_global->ocsp_stapling_response = NULL;
++#endif /* HAVE_OCSP */
 +
- int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-                         int tls_ia)
- {
-       return -1;
- }
- struct wpabuf * tls_connection_ia_send_phase_finished(
-       void *tls_ctx, struct tls_connection *conn, int final)
- {
-       return NULL;
- }
- int tls_connection_ia_final_phase_finished(void *tls_ctx,
-                                          struct tls_connection *conn)
- {
-       return -1;
- }
- int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-                                          struct tls_connection *conn,
-                                          const u8 *key, size_t key_len)
- {
-       return -1;
- }
 +      return 0;
 +}
 +
 +
- #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
 +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 +/* Pre-shared secred requires a patch to openssl, so this function is
 + * commented out unless explicitly needed for EAP-FAST in order to be able to
 + * build this file with unmodified openssl. */
 +
++#ifdef OPENSSL_IS_BORINGSSL
++static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
++                         STACK_OF(SSL_CIPHER) *peer_ciphers,
++                         const SSL_CIPHER **cipher, void *arg)
++#else /* OPENSSL_IS_BORINGSSL */
 +static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
 +                         STACK_OF(SSL_CIPHER) *peer_ciphers,
 +                         SSL_CIPHER **cipher, void *arg)
++#endif /* OPENSSL_IS_BORINGSSL */
 +{
 +      struct tls_connection *conn = arg;
 +      int ret;
 +
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
 +      if (conn == NULL || conn->session_ticket_cb == NULL)
 +              return 0;
 +
 +      ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
 +                                    conn->session_ticket,
 +                                    conn->session_ticket_len,
 +                                    s->s3->client_random,
 +                                    s->s3->server_random, secret);
++#else
++      unsigned char client_random[SSL3_RANDOM_SIZE];
++      unsigned char server_random[SSL3_RANDOM_SIZE];
++
++      if (conn == NULL || conn->session_ticket_cb == NULL)
++              return 0;
++
++      SSL_get_client_random(s, client_random, sizeof(client_random));
++      SSL_get_server_random(s, server_random, sizeof(server_random));
++
++      ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
++                                    conn->session_ticket,
++                                    conn->session_ticket_len,
++                                    client_random,
++                                    server_random, secret);
++#endif
++
 +      os_free(conn->session_ticket);
 +      conn->session_ticket = NULL;
 +
 +      if (ret <= 0)
 +              return 0;
 +
 +      *secret_len = SSL_MAX_MASTER_KEY_LENGTH;
 +      return 1;
 +}
 +
 +
- #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
- #ifdef SSL_OP_NO_TICKET
- static void tls_hello_ext_cb(SSL *s, int client_server, int type,
-                            unsigned char *data, int len, void *arg)
- {
-       struct tls_connection *conn = arg;
-       if (conn == NULL || conn->session_ticket_cb == NULL)
-               return;
-       wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
-                  type, len);
-       if (type == TLSEXT_TYPE_session_ticket && !client_server) {
-               os_free(conn->session_ticket);
-               conn->session_ticket = NULL;
-               wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
-                           "extension", data, len);
-               conn->session_ticket = os_malloc(len);
-               if (conn->session_ticket == NULL)
-                       return;
-               os_memcpy(conn->session_ticket, data, len);
-               conn->session_ticket_len = len;
-       }
- }
- #else /* SSL_OP_NO_TICKET */
- static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
- {
-       struct tls_connection *conn = arg;
-       if (conn == NULL || conn->session_ticket_cb == NULL)
-               return 0;
-       wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
-                  ext->type, ext->length);
-       os_free(conn->session_ticket);
-       conn->session_ticket = NULL;
-       if (ext->type == 35) {
-               wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
-                           "extension", ext->data, ext->length);
-               conn->session_ticket = os_malloc(ext->length);
-               if (conn->session_ticket == NULL)
-                       return SSL_AD_INTERNAL_ERROR;
-               os_memcpy(conn->session_ticket, ext->data, ext->length);
-               conn->session_ticket_len = ext->length;
-       }
-       return 0;
- }
- #endif /* SSL_OP_NO_TICKET */
- #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
 +static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
 +                                   int len, void *arg)
 +{
 +      struct tls_connection *conn = arg;
 +
 +      if (conn == NULL || conn->session_ticket_cb == NULL)
 +              return 0;
 +
 +      wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len);
 +
 +      os_free(conn->session_ticket);
 +      conn->session_ticket = NULL;
 +
 +      wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
 +                  "extension", data, len);
 +
 +      conn->session_ticket = os_malloc(len);
 +      if (conn->session_ticket == NULL)
 +              return 0;
 +
 +      os_memcpy(conn->session_ticket, data, len);
 +      conn->session_ticket_len = len;
 +
 +      return 1;
 +}
- #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
 +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +
 +
 +int tls_connection_set_session_ticket_cb(void *tls_ctx,
 +                                       struct tls_connection *conn,
 +                                       tls_session_ticket_cb cb,
 +                                       void *ctx)
 +{
 +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 +      conn->session_ticket_cb = cb;
 +      conn->session_ticket_cb_ctx = ctx;
 +
 +      if (cb) {
 +              if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
 +                                            conn) != 1)
 +                      return -1;
- #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
- #ifdef SSL_OP_NO_TICKET
-               SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
-               SSL_set_tlsext_debug_arg(conn->ssl, conn);
- #else /* SSL_OP_NO_TICKET */
-               if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
-                                              conn) != 1)
-                       return -1;
- #endif /* SSL_OP_NO_TICKET */
- #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
 +              SSL_set_session_ticket_ext_cb(conn->ssl,
 +                                            tls_session_ticket_ext_cb, conn);
- #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
 +      } else {
 +              if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
 +                      return -1;
- #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
- #ifdef SSL_OP_NO_TICKET
-               SSL_set_tlsext_debug_callback(conn->ssl, NULL);
-               SSL_set_tlsext_debug_arg(conn->ssl, conn);
- #else /* SSL_OP_NO_TICKET */
-               if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
-                       return -1;
- #endif /* SSL_OP_NO_TICKET */
- #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
 +              SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
 +      }
 +
 +      return 0;
 +#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +      return -1;
 +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 +}
++
++
++int tls_get_library_version(char *buf, size_t buf_len)
++{
++      return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
++                         OPENSSL_VERSION_TEXT,
++                         SSLeay_version(SSLEAY_VERSION));
++}
++
++
++void tls_connection_set_success_data(struct tls_connection *conn,
++                                   struct wpabuf *data)
++{
++      SSL_SESSION *sess;
++      struct wpabuf *old;
++
++      if (tls_ex_idx_session < 0)
++              goto fail;
++      sess = SSL_get_session(conn->ssl);
++      if (!sess)
++              goto fail;
++      old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
++      if (old) {
++              wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p",
++                         old);
++              wpabuf_free(old);
++      }
++      if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1)
++              goto fail;
++
++      wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data);
++      conn->success_data = 1;
++      return;
++
++fail:
++      wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data");
++      wpabuf_free(data);
++}
++
++
++void tls_connection_set_success_data_resumed(struct tls_connection *conn)
++{
++      wpa_printf(MSG_DEBUG,
++                 "OpenSSL: Success data accepted for resumed session");
++      conn->success_data = 1;
++}
++
++
++const struct wpabuf *
++tls_connection_get_success_data(struct tls_connection *conn)
++{
++      SSL_SESSION *sess;
++
++      if (tls_ex_idx_session < 0 ||
++          !(sess = SSL_get_session(conn->ssl)))
++              return NULL;
++      return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session);
++}
++
++
++void tls_connection_remove_session(struct tls_connection *conn)
++{
++      SSL_SESSION *sess;
++
++      sess = SSL_get_session(conn->ssl);
++      if (!sess)
++              return;
++
++      if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1)
++              wpa_printf(MSG_DEBUG,
++                         "OpenSSL: Session was not cached");
++      else
++              wpa_printf(MSG_DEBUG,
++                         "OpenSSL: Removed cached session to disable session resumption");
++}
Simple merge
index 0000000,31d9440..31d9440
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,aebea8c..aebea8c
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,3eae2f8..3eae2f8
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,5c21e0f..5c21e0f
mode 000000,100644..100644
--- /dev/null
Simple merge
index 0000000,e94eda0..e94eda0
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,8da4c53..8da4c53
mode 000000,100644..100644
--- /dev/null
index 0000000,a107479..a107479
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,e7c7001..e7c7001
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 9db77ed,0000000..91cf7d5
mode 100644,000000..100644
--- /dev/null
@@@ -1,36 -1,0 +1,41 @@@
-  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP common peer/server definitions
-  * 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.
++ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
 + *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_COMMON_H
 +#define EAP_COMMON_H
 +
 +#include "wpabuf.h"
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
++
++struct erp_tlvs {
++      const u8 *keyname;
++      const u8 *domain;
++      u8 keyname_len;
++      u8 domain_len;
++};
++
++int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
 +const u8 * eap_hdr_validate(int vendor, EapType eap_type,
 +                          const struct wpabuf *msg, size_t *plen);
 +struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
 +                            u8 code, u8 identifier);
 +void eap_update_len(struct wpabuf *msg);
 +u8 eap_get_id(const struct wpabuf *msg);
 +EapType eap_get_type(const struct wpabuf *msg);
++int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
++                 int stop_at_keyname);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_COMMON_H */
index 482f9d2,0000000..708e50d
mode 100644,000000..100644
--- /dev/null
@@@ -1,94 -1,0 +1,126 @@@
-  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP server/peer: Shared EAP definitions
-  * 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.
++ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
 + *
-        EAP_CODE_FAILURE = 4 };
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_DEFS_H
 +#define EAP_DEFS_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/* RFC 3748 - Extensible Authentication Protocol (EAP) */
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +struct eap_hdr {
 +      u8 code;
 +      u8 identifier;
 +      be16 length; /* including code and identifier; network byte order */
 +      /* followed by length-4 octets of data */
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
-       EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */,
++       EAP_CODE_FAILURE = 4, EAP_CODE_INITIATE = 5, EAP_CODE_FINISH = 6 };
 +
 +/* EAP Request and Response data begins with one octet Type. Success and
 + * Failure do not have additional data. */
 +
++/* Type field in EAP-Initiate and EAP-Finish messages */
++enum eap_erp_type {
++      EAP_ERP_TYPE_REAUTH_START = 1,
++      EAP_ERP_TYPE_REAUTH = 2,
++};
++
++/* ERP TV/TLV types */
++enum eap_erp_tlv_type {
++      EAP_ERP_TLV_KEYNAME_NAI = 1,
++      EAP_ERP_TV_RRK_LIFETIME = 2,
++      EAP_ERP_TV_RMSK_LIFETIME = 3,
++      EAP_ERP_TLV_DOMAIN_NAME = 4,
++      EAP_ERP_TLV_CRYPTOSUITES = 5,
++      EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6,
++      EAP_ERP_TLV_CALLED_STATION_ID = 128,
++      EAP_ERP_TLV_CALLING_STATION_ID = 129,
++      EAP_ERP_TLV_NAS_IDENTIFIER = 130,
++      EAP_ERP_TLV_NAS_IP_ADDRESS = 131,
++      EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132,
++};
++
++/* ERP Cryptosuite */
++enum eap_erp_cryptosuite {
++      EAP_ERP_CS_HMAC_SHA256_64 = 1,
++      EAP_ERP_CS_HMAC_SHA256_128 = 2,
++      EAP_ERP_CS_HMAC_SHA256_256 = 3,
++};
++
 +/*
 + * EAP Method Types as allocated by IANA:
 + * http://www.iana.org/assignments/eap-numbers
 + */
 +typedef enum {
 +      EAP_TYPE_NONE = 0,
 +      EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
 +      EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
 +      EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */,
 +      EAP_TYPE_MD5 = 4, /* RFC 3748 */
 +      EAP_TYPE_OTP = 5 /* RFC 3748 */,
 +      EAP_TYPE_GTC = 6, /* RFC 3748 */
 +      EAP_TYPE_TLS = 13 /* RFC 2716 */,
 +      EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
 +      EAP_TYPE_SIM = 18 /* RFC 4186 */,
 +      EAP_TYPE_TTLS = 21 /* RFC 5281 */,
 +      EAP_TYPE_AKA = 23 /* RFC 4187 */,
 +      EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */,
 +      EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
 +      EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
 +      EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment;
 +                         * type 38 has previously been allocated for
 +                         * EAP-HTTP Digest, (funk.com) */,
 +      EAP_TYPE_FAST = 43 /* RFC 4851 */,
 +      EAP_TYPE_PAX = 46 /* RFC 4746 */,
 +      EAP_TYPE_PSK = 47 /* RFC 4764 */,
 +      EAP_TYPE_SAKE = 48 /* RFC 4763 */,
 +      EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
-       EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */
++      EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */,
 +      EAP_TYPE_GPSK = 51 /* RFC 5433 */,
 +      EAP_TYPE_PWD = 52 /* RFC 5931 */,
++      EAP_TYPE_EKE = 53 /* RFC 6124 */,
 +      EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
 +} EapType;
 +
 +
 +/* SMI Network Management Private Enterprise Code for vendor specific types */
 +enum {
 +      EAP_VENDOR_IETF = 0,
 +      EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
++      EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance (moved to WBA) */,
++      EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */,
++      EAP_VENDOR_WFA_NEW = 40808 /* Wi-Fi Alliance */
 +};
 +
++#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP
++#define EAP_VENDOR_TYPE_UNAUTH_TLS 1
++
++#define EAP_VENDOR_WFA_UNAUTH_TLS 13
++
 +#define EAP_MSK_LEN 64
 +#define EAP_EMSK_LEN 64
++#define EAP_EMSK_NAME_LEN 8
++#define ERP_MAX_KEY_LEN 64
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_DEFS_H */
index 0000000,4dfdb3f..4dfdb3f
mode 000000,100644..100644
--- /dev/null
index 0000000,a4c0422..a4c0422
mode 000000,100644..100644
--- /dev/null
index c4f54ca,0000000..6d547fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,121 -1,0 +1,115 @@@
-  * 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.
 +/*
 + * EAP-FAST definitions (RFC 4851)
 + * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
 + *
-                      int tlv_type, u8 *pos, int len);
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_FAST_H
 +#define EAP_FAST_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#define EAP_FAST_VERSION 1
 +#define EAP_FAST_KEY_LEN 64
 +#define EAP_FAST_SIMCK_LEN 40
 +#define EAP_FAST_SKS_LEN 40
 +#define EAP_FAST_CMK_LEN 20
 +
 +#define TLS_EXT_PAC_OPAQUE 35
 +
 +/*
 + * RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
 + * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
 + * in the general PAC TLV format (Section 4.2).
 + */
 +#define PAC_TYPE_PAC_KEY 1
 +#define PAC_TYPE_PAC_OPAQUE 2
 +#define PAC_TYPE_CRED_LIFETIME 3
 +#define PAC_TYPE_A_ID 4
 +#define PAC_TYPE_I_ID 5
 +/*
 + * 6 was previous assigned for SERVER_PROTECTED_DATA, but
 + * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved.
 + */
 +#define PAC_TYPE_A_ID_INFO 7
 +#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8
 +#define PAC_TYPE_PAC_INFO 9
 +#define PAC_TYPE_PAC_TYPE 10
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +struct pac_tlv_hdr {
 +      be16 type;
 +      be16 len;
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +
 +#define EAP_FAST_PAC_KEY_LEN 32
 +
 +/* RFC 5422: 4.2.6 PAC-Type TLV */
 +#define PAC_TYPE_TUNNEL_PAC 1
 +/* Application Specific Short Lived PACs (only in volatile storage) */
 +/* User Authorization PAC */
 +#define PAC_TYPE_USER_AUTHORIZATION 3
 +/* Application Specific Long Lived PACs */
 +/* Machine Authentication PAC */
 +#define PAC_TYPE_MACHINE_AUTHENTICATION 2
 +
 +
 +/*
 + * RFC 5422:
 + * Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange
 + */
 +struct eap_fast_key_block_provisioning {
 +      /* Extra key material after TLS key_block */
 +      u8 session_key_seed[EAP_FAST_SKS_LEN];
 +      u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */
 +      u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */
 +};
 +
 +
 +struct wpabuf;
 +struct tls_connection;
 +
 +struct eap_fast_tlv_parse {
 +      u8 *eap_payload_tlv;
 +      size_t eap_payload_tlv_len;
 +      struct eap_tlv_crypto_binding_tlv *crypto_binding;
 +      size_t crypto_binding_len;
 +      int iresult;
 +      int result;
 +      int request_action;
 +      u8 *pac;
 +      size_t pac_len;
 +};
 +
 +void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len);
 +void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data,
 +                    u16 len);
 +void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type,
 +                        const struct wpabuf *data);
 +struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf);
 +void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random,
 +                                 const u8 *client_random, u8 *master_secret);
 +u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn,
 +                       const char *label, size_t len);
 +void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
 +void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk);
 +int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv,
++                     int tlv_type, u8 *pos, size_t len);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_FAST_H */
index 6766603,0000000..0e18ec2
mode 100644,000000..100644
--- /dev/null
@@@ -1,74 -1,0 +1,74 @@@
-  * 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.
 +/*
 + * EAP server/peer: EAP-GPSK shared routines
 + * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
 + *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_GPSK_COMMON_H
 +#define EAP_GPSK_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#define EAP_GPSK_OPCODE_GPSK_1 1
 +#define EAP_GPSK_OPCODE_GPSK_2 2
 +#define EAP_GPSK_OPCODE_GPSK_3 3
 +#define EAP_GPSK_OPCODE_GPSK_4 4
 +#define EAP_GPSK_OPCODE_FAIL 5
 +#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6
 +
 +/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */
 +#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001
 +#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002
 +#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003
 +
 +#define EAP_GPSK_RAND_LEN 32
 +#define EAP_GPSK_MAX_SK_LEN 32
 +#define EAP_GPSK_MAX_PK_LEN 32
 +#define EAP_GPSK_MAX_MIC_LEN 32
 +
 +#define EAP_GPSK_VENDOR_IETF          0x00000000
 +#define EAP_GPSK_CIPHER_RESERVED      0x000000
 +#define EAP_GPSK_CIPHER_AES           0x000001
 +#define EAP_GPSK_CIPHER_SHA256                0x000002
 +
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +struct eap_gpsk_csuite {
 +      u8 vendor[4];
 +      u8 specifier[2];
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +int eap_gpsk_supported_ciphersuite(int vendor, int specifier);
 +int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
 +                       int specifier,
 +                       const u8 *rand_client, const u8 *rand_server,
 +                       const u8 *id_client, size_t id_client_len,
 +                       const u8 *id_server, size_t id_server_len,
 +                       u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
 +                       u8 *pk, size_t *pk_len);
++int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor,
++                             int specifier,
++                             const u8 *rand_peer, const u8 *rand_server,
++                             const u8 *id_peer, size_t id_peer_len,
++                             const u8 *id_server, size_t id_server_len,
++                             u8 method_type, u8 *sid, size_t *sid_len);
 +size_t eap_gpsk_mic_len(int vendor, int specifier);
 +int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
 +                       int specifier, const u8 *data, size_t len, u8 *mic);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_GPSK_COMMON_H */
index a054b6a,0000000..e3bade5
mode 100644,000000..100644
--- /dev/null
@@@ -1,50 -1,0 +1,37 @@@
-  * 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.
 +/*
 + * EAP-IKEv2 definitions
 + * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
 + *
- #ifdef CCNS_PL
- /* incorrect bit order */
- #define IKEV2_FLAGS_LENGTH_INCLUDED 0x01
- #define IKEV2_FLAGS_MORE_FRAGMENTS 0x02
- #define IKEV2_FLAGS_ICV_INCLUDED 0x04
- #else /* CCNS_PL */
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_IKEV2_COMMON_H
 +#define EAP_IKEV2_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
- #endif /* CCNS_PL */
 +#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80
 +#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40
 +#define IKEV2_FLAGS_ICV_INCLUDED 0x20
 +
 +#define IKEV2_FRAGMENT_SIZE 1400
 +
 +struct ikev2_keys;
 +
 +int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys,
 +                          const u8 *i_nonce, size_t i_nonce_len,
 +                          const u8 *r_nonce, size_t r_nonce_len,
 +                          u8 *keymat);
 +struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code);
 +int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys,
 +                         int initiator, const struct wpabuf *msg,
 +                         const u8 *pos, const u8 *end);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_IKEV2_COMMON_H */
index ff9b903,0000000..cc38b17
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,100 @@@
-  * 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.
 +/*
 + * EAP server/peer: EAP-PAX shared routines
 + * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
 + *
-                                  u8 *mk, u8 *ck, u8 *ick);
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_PAX_COMMON_H
 +#define EAP_PAX_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +struct eap_pax_hdr {
 +      u8 op_code;
 +      u8 flags;
 +      u8 mac_id;
 +      u8 dh_group_id;
 +      u8 public_key_id;
 +      /* Followed by variable length payload and ICV */
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +
 +/* op_code: */
 +enum {
 +      EAP_PAX_OP_STD_1 = 0x01,
 +      EAP_PAX_OP_STD_2 = 0x02,
 +      EAP_PAX_OP_STD_3 = 0x03,
 +      EAP_PAX_OP_SEC_1 = 0x11,
 +      EAP_PAX_OP_SEC_2 = 0x12,
 +      EAP_PAX_OP_SEC_3 = 0x13,
 +      EAP_PAX_OP_SEC_4 = 0x14,
 +      EAP_PAX_OP_SEC_5 = 0x15,
 +      EAP_PAX_OP_ACK = 0x21
 +};
 +
 +/* flags: */
 +#define EAP_PAX_FLAGS_MF                      0x01
 +#define EAP_PAX_FLAGS_CE                      0x02
 +#define EAP_PAX_FLAGS_AI                      0x04
 +
 +/* mac_id: */
 +#define EAP_PAX_MAC_HMAC_SHA1_128             0x01
 +#define EAP_PAX_HMAC_SHA256_128                       0x02
 +
 +/* dh_group_id: */
 +#define EAP_PAX_DH_GROUP_NONE                 0x00
 +#define EAP_PAX_DH_GROUP_2048_MODP            0x01
 +#define EAP_PAX_DH_GROUP_3072_MODP            0x02
 +#define EAP_PAX_DH_GROUP_NIST_ECC_P_256               0x03
 +
 +/* public_key_id: */
 +#define EAP_PAX_PUBLIC_KEY_NONE                       0x00
 +#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP         0x01
 +#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5     0x02
 +#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC  0x03
 +
 +/* ADE type: */
 +#define EAP_PAX_ADE_VENDOR_SPECIFIC           0x01
 +#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING    0x02
 +#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING    0x03
 +
 +
 +#define EAP_PAX_RAND_LEN 32
 +#define EAP_PAX_MAC_LEN 16
 +#define EAP_PAX_ICV_LEN 16
 +#define EAP_PAX_AK_LEN 16
 +#define EAP_PAX_MK_LEN 16
 +#define EAP_PAX_CK_LEN 16
 +#define EAP_PAX_ICK_LEN 16
++#define EAP_PAX_MID_LEN 16
 +
 +
 +int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
 +              const char *identifier,
 +              const u8 *entropy, size_t entropy_len,
 +              size_t output_len, u8 *output);
 +int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
 +              const u8 *data1, size_t data1_len,
 +              const u8 *data2, size_t data2_len,
 +              const u8 *data3, size_t data3_len,
 +              u8 *mac);
 +int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
++                                 u8 *mk, u8 *ck, u8 *ick, u8 *mid);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_PAX_COMMON_H */
index b67de7e,0000000..069450e
mode 100644,000000..100644
--- /dev/null
@@@ -1,30 -1,0 +1,24 @@@
-  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP-PEAP common routines
-  * 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.
++ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
 + *
- void peap_prfplus(int version, const u8 *key, size_t key_len,
-                 const char *label, const u8 *seed, size_t seed_len,
-                 u8 *buf, size_t buf_len);
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_PEAP_COMMON_H
 +#define EAP_PEAP_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
++int peap_prfplus(int version, const u8 *key, size_t key_len,
++               const char *label, const u8 *seed, size_t seed_len,
++               u8 *buf, size_t buf_len);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_PEAP_COMMON_H */
index 0de2c75,0000000..e7c50b9
mode 100644,000000..100644
--- /dev/null
@@@ -1,85 -1,0 +1,79 @@@
-  * 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.
 +/*
 + * EAP server/peer: EAP-PSK shared routines
 + * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 + *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_PSK_COMMON_H
 +#define EAP_PSK_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#define EAP_PSK_RAND_LEN 16
 +#define EAP_PSK_MAC_LEN 16
 +#define EAP_PSK_TEK_LEN 16
 +#define EAP_PSK_PSK_LEN 16
 +#define EAP_PSK_AK_LEN 16
 +#define EAP_PSK_KDK_LEN 16
 +
 +#define EAP_PSK_R_FLAG_CONT 1
 +#define EAP_PSK_R_FLAG_DONE_SUCCESS 2
 +#define EAP_PSK_R_FLAG_DONE_FAILURE 3
 +#define EAP_PSK_E_FLAG 0x20
 +
 +#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6)
 +#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6)
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +/* EAP-PSK First Message (AS -> Supplicant) */
 +struct eap_psk_hdr_1 {
 +      u8 flags;
 +      u8 rand_s[EAP_PSK_RAND_LEN];
 +      /* Followed by variable length ID_S */
 +} STRUCT_PACKED;
 +
 +/* EAP-PSK Second Message (Supplicant -> AS) */
 +struct eap_psk_hdr_2 {
 +      u8 flags;
 +      u8 rand_s[EAP_PSK_RAND_LEN];
 +      u8 rand_p[EAP_PSK_RAND_LEN];
 +      u8 mac_p[EAP_PSK_MAC_LEN];
 +      /* Followed by variable length ID_P */
 +} STRUCT_PACKED;
 +
 +/* EAP-PSK Third Message (AS -> Supplicant) */
 +struct eap_psk_hdr_3 {
 +      u8 flags;
 +      u8 rand_s[EAP_PSK_RAND_LEN];
 +      u8 mac_s[EAP_PSK_MAC_LEN];
 +      /* Followed by variable length PCHANNEL */
 +} STRUCT_PACKED;
 +
 +/* EAP-PSK Fourth Message (Supplicant -> AS) */
 +struct eap_psk_hdr_4 {
 +      u8 flags;
 +      u8 rand_s[EAP_PSK_RAND_LEN];
 +      /* Followed by variable length PCHANNEL */
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +
 +int __must_check eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk);
 +int __must_check eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek,
 +                                   u8 *msk, u8 *emsk);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_PSK_COMMON_H */
index 03454ac,0000000..6562ea4
mode 100644,000000..100644
--- /dev/null
@@@ -1,87 -1,0 +1,80 @@@
-  * This program is free software; you can redistribute it and/or modify
-  * it under the terms of the BSD license.
-  *
-  * Alternatively, this software may be distributed under the terms of the
-  * GNU General Public License version 2 as published by the Free Software
-  * Foundation.
-  *
-  * See README and COPYING for more details.
 +/*
 + * EAP server/peer: EAP-pwd shared definitions
 + * Copyright (c) 2009, Dan Harkins <dharkins@lounge.org>
 + *
- #include <openssl/sha.h>
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_PWD_COMMON_H
 +#define EAP_PWD_COMMON_H
 +
 +#include <openssl/bn.h>
- #include <openssl/hmac.h>
 +#include <openssl/ec.h>
 +#include <openssl/evp.h>
- struct eap_pwd_hdr {
-       u8 l_bit:1;
-       u8 m_bit:1;
-       u8 exch:6;
-       u8 total_length[0];         /* included when l_bit is set */
- } STRUCT_PACKED;
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/*
 + * definition of a finite cyclic group
 + * TODO: support one based on a prime field
 + */
 +typedef struct group_definition_ {
 +      u16 group_num;
 +      EC_GROUP *group;
 +      EC_POINT *pwe;
 +      BIGNUM *order;
 +      BIGNUM *prime;
 +} EAP_PWD_group;
 +
 +/*
 + * EAP-pwd header, included on all payloads
++ * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set)
 + */
- #define EAP_PWD_GET_LENGTH_BIT(x)       ((x)->lm_exch & 0x80)
- #define EAP_PWD_SET_LENGTH_BIT(x)       ((x)->lm_exch |= 0x80)
- #define EAP_PWD_GET_MORE_BIT(x)         ((x)->lm_exch & 0x40)
- #define EAP_PWD_SET_MORE_BIT(x)         ((x)->lm_exch |= 0x40)
- #define EAP_PWD_GET_EXCHANGE(x)         ((x)->lm_exch & 0x3f)
- #define EAP_PWD_SET_EXCHANGE(x,y)       ((x)->lm_exch |= (y))
++#define EAP_PWD_HDR_SIZE                1
 +
 +#define EAP_PWD_OPCODE_ID_EXCH          1
 +#define EAP_PWD_OPCODE_COMMIT_EXCH      2
 +#define EAP_PWD_OPCODE_CONFIRM_EXCH     3
- int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *,
-                            int, u8 *);
- int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, EC_POINT *, EC_POINT *,
-                  BIGNUM *, BIGNUM *, u32 *, u8 *, u8 *);
- void H_Init(HMAC_CTX *);
- void H_Update(HMAC_CTX *, const u8 *, int);
- void H_Final(HMAC_CTX *, u8 *);
++#define EAP_PWD_GET_LENGTH_BIT(x)       ((x) & 0x80)
++#define EAP_PWD_SET_LENGTH_BIT(x)       ((x) |= 0x80)
++#define EAP_PWD_GET_MORE_BIT(x)         ((x) & 0x40)
++#define EAP_PWD_SET_MORE_BIT(x)         ((x) |= 0x40)
++#define EAP_PWD_GET_EXCHANGE(x)         ((x) & 0x3f)
++#define EAP_PWD_SET_EXCHANGE(x,y)       ((x) |= (y))
 +
 +/* EAP-pwd-ID payload */
 +struct eap_pwd_id {
 +      be16 group_num;
 +      u8 random_function;
 +#define EAP_PWD_DEFAULT_RAND_FUNC       1
 +      u8 prf;
 +#define EAP_PWD_DEFAULT_PRF             1
 +      u8 token[4];
 +      u8 prep;
 +#define EAP_PWD_PREP_NONE               0
 +#define EAP_PWD_PREP_MS                 1
 +      u8 identity[0];     /* length inferred from payload */
 +} STRUCT_PACKED;
 +
 +/* common routines */
++int compute_password_element(EAP_PWD_group *grp, u16 num,
++                           const u8 *password, size_t password_len,
++                           const u8 *id_server, size_t id_server_len,
++                           const u8 *id_peer, size_t id_peer_len,
++                           const u8 *token);
++int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k,
++               const BIGNUM *peer_scalar, const BIGNUM *server_scalar,
++               const u8 *confirm_peer, const u8 *confirm_server,
++               const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id);
++struct crypto_hash * eap_pwd_h_init(void);
++void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len);
++void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif  /* EAP_PWD_COMMON_H */
index 8a5b170,0000000..440badc
mode 100644,000000..100644
--- /dev/null
@@@ -1,110 -1,0 +1,104 @@@
-  * 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.
 +/*
 + * EAP server/peer: EAP-SAKE shared routines
 + * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
 + *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_SAKE_COMMON_H
 +#define EAP_SAKE_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#define EAP_SAKE_VERSION 2
 +
 +#define EAP_SAKE_SUBTYPE_CHALLENGE 1
 +#define EAP_SAKE_SUBTYPE_CONFIRM 2
 +#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3
 +#define EAP_SAKE_SUBTYPE_IDENTITY 4
 +
 +#define EAP_SAKE_AT_RAND_S 1
 +#define EAP_SAKE_AT_RAND_P 2
 +#define EAP_SAKE_AT_MIC_S 3
 +#define EAP_SAKE_AT_MIC_P 4
 +#define EAP_SAKE_AT_SERVERID 5
 +#define EAP_SAKE_AT_PEERID 6
 +#define EAP_SAKE_AT_SPI_S 7
 +#define EAP_SAKE_AT_SPI_P 8
 +#define EAP_SAKE_AT_ANY_ID_REQ 9
 +#define EAP_SAKE_AT_PERM_ID_REQ 10
 +#define EAP_SAKE_AT_ENCR_DATA 128
 +#define EAP_SAKE_AT_IV 129
 +#define EAP_SAKE_AT_PADDING 130
 +#define EAP_SAKE_AT_NEXT_TMPID 131
 +#define EAP_SAKE_AT_MSK_LIFE 132
 +
 +#define EAP_SAKE_RAND_LEN 16
 +#define EAP_SAKE_MIC_LEN 16
 +#define EAP_SAKE_ROOT_SECRET_LEN 16
 +#define EAP_SAKE_SMS_LEN 16
 +#define EAP_SAKE_TEK_AUTH_LEN 16
 +#define EAP_SAKE_TEK_CIPHER_LEN 16
 +#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN)
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +struct eap_sake_hdr {
 +      u8 version; /* EAP_SAKE_VERSION */
 +      u8 session_id;
 +      u8 subtype;
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +
 +struct eap_sake_parse_attr {
 +      const u8 *rand_s;
 +      const u8 *rand_p;
 +      const u8 *mic_s;
 +      const u8 *mic_p;
 +      const u8 *serverid;
 +      size_t serverid_len;
 +      const u8 *peerid;
 +      size_t peerid_len;
 +      const u8 *spi_s;
 +      size_t spi_s_len;
 +      const u8 *spi_p;
 +      size_t spi_p_len;
 +      const u8 *any_id_req;
 +      const u8 *perm_id_req;
 +      const u8 *encr_data;
 +      size_t encr_data_len;
 +      const u8 *iv;
 +      size_t iv_len;
 +      const u8 *next_tmpid;
 +      size_t next_tmpid_len;
 +      const u8 *msk_life;
 +};
 +
 +int eap_sake_parse_attributes(const u8 *buf, size_t len,
 +                            struct eap_sake_parse_attr *attr);
 +void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
 +                        const u8 *rand_s, const u8 *rand_p,
 +                        u8 *tek, u8 *msk, u8 *emsk);
 +int eap_sake_compute_mic(const u8 *tek_auth,
 +                       const u8 *rand_s, const u8 *rand_p,
 +                       const u8 *serverid, size_t serverid_len,
 +                       const u8 *peerid, size_t peerid_len,
 +                       int peer, const u8 *eap, size_t eap_len,
 +                       const u8 *mic_pos, u8 *mic);
 +void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data,
 +                     size_t len);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_SAKE_COMMON_H */
index b6359a9,0000000..7c2cff1
mode 100644,000000..100644
--- /dev/null
@@@ -1,243 -1,0 +1,238 @@@
-  * 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.
 +/*
 + * EAP peer/server: EAP-SIM/AKA/AKA' shared routines
 + * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
 + *
- struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut,
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_SIM_COMMON_H
 +#define EAP_SIM_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#define EAP_SIM_NONCE_S_LEN 16
 +#define EAP_SIM_NONCE_MT_LEN 16
 +#define EAP_SIM_MAC_LEN 16
 +#define EAP_SIM_MK_LEN 20
 +#define EAP_SIM_K_AUT_LEN 16
 +#define EAP_SIM_K_ENCR_LEN 16
 +#define EAP_SIM_KEYING_DATA_LEN 64
 +#define EAP_SIM_IV_LEN 16
 +#define EAP_SIM_KC_LEN 8
 +#define EAP_SIM_SRES_LEN 4
 +
 +#define GSM_RAND_LEN 16
 +
 +#define EAP_SIM_VERSION 1
 +
 +/* EAP-SIM Subtypes */
 +#define EAP_SIM_SUBTYPE_START 10
 +#define EAP_SIM_SUBTYPE_CHALLENGE 11
 +#define EAP_SIM_SUBTYPE_NOTIFICATION 12
 +#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
 +#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
 +
 +/* AT_CLIENT_ERROR_CODE error codes */
 +#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
 +#define EAP_SIM_UNSUPPORTED_VERSION 1
 +#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
 +#define EAP_SIM_RAND_NOT_FRESH 3
 +
 +#define EAP_SIM_MAX_FAST_REAUTHS 1000
 +
 +#define EAP_SIM_MAX_CHAL 3
 +
 +
 +/* EAP-AKA Subtypes */
 +#define EAP_AKA_SUBTYPE_CHALLENGE 1
 +#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2
 +#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4
 +#define EAP_AKA_SUBTYPE_IDENTITY 5
 +#define EAP_AKA_SUBTYPE_NOTIFICATION 12
 +#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13
 +#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14
 +
 +/* AT_CLIENT_ERROR_CODE error codes */
 +#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0
 +
 +#define EAP_AKA_RAND_LEN 16
 +#define EAP_AKA_AUTN_LEN 16
 +#define EAP_AKA_AUTS_LEN 14
 +#define EAP_AKA_RES_MAX_LEN 16
 +#define EAP_AKA_IK_LEN 16
 +#define EAP_AKA_CK_LEN 16
 +#define EAP_AKA_MAX_FAST_REAUTHS 1000
 +#define EAP_AKA_MIN_RES_LEN 4
 +#define EAP_AKA_MAX_RES_LEN 16
 +#define EAP_AKA_CHECKCODE_LEN 20
 +
 +#define EAP_AKA_PRIME_K_AUT_LEN 32
 +#define EAP_AKA_PRIME_CHECKCODE_LEN 32
 +#define EAP_AKA_PRIME_K_RE_LEN 32
 +
 +struct wpabuf;
 +
 +void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
 +                     const u8 *nonce_mt, u16 selected_version,
 +                     const u8 *ver_list, size_t ver_list_len,
 +                     int num_chal, const u8 *kc, u8 *mk);
 +void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
 +                     const u8 *ik, const u8 *ck, u8 *mk);
 +int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk,
 +                      u8 *emsk);
 +int eap_sim_derive_keys_reauth(u16 _counter,
 +                             const u8 *identity, size_t identity_len,
 +                             const u8 *nonce_s, const u8 *mk, u8 *msk,
 +                             u8 *emsk);
 +int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req,
 +                     const u8 *mac, const u8 *extra, size_t extra_len);
 +void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac,
 +                   const u8 *extra, size_t extra_len);
 +
 +#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME)
 +void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len,
 +                             const u8 *ik, const u8 *ck, u8 *k_encr,
 +                             u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk);
 +int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
 +                                   const u8 *identity, size_t identity_len,
 +                                   const u8 *nonce_s, u8 *msk, u8 *emsk);
 +int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req,
 +                            const u8 *mac, const u8 *extra,
 +                            size_t extra_len);
 +void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len,
 +                          u8 *mac, const u8 *extra, size_t extra_len);
 +
 +void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak,
 +                                    const u8 *network_name,
 +                                    size_t network_name_len);
 +#else /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
 +static inline void eap_aka_prime_derive_keys(const u8 *identity,
 +                                           size_t identity_len,
 +                                           const u8 *ik, const u8 *ck,
 +                                           u8 *k_encr, u8 *k_aut, u8 *k_re,
 +                                           u8 *msk, u8 *emsk)
 +{
 +}
 +
 +static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter,
 +                                                 const u8 *identity,
 +                                                 size_t identity_len,
 +                                                 const u8 *nonce_s, u8 *msk,
 +                                                 u8 *emsk)
 +{
 +      return -1;
 +}
 +
 +static inline int eap_sim_verify_mac_sha256(const u8 *k_aut,
 +                                          const struct wpabuf *req,
 +                                          const u8 *mac, const u8 *extra,
 +                                          size_t extra_len)
 +{
 +      return -1;
 +}
 +#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */
 +
 +
 +/* EAP-SIM/AKA Attributes (0..127 non-skippable) */
 +#define EAP_SIM_AT_RAND 1
 +#define EAP_SIM_AT_AUTN 2 /* only AKA */
 +#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */
 +#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */
 +#define EAP_SIM_AT_PADDING 6 /* only encrypted */
 +#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */
 +#define EAP_SIM_AT_PERMANENT_ID_REQ 10
 +#define EAP_SIM_AT_MAC 11
 +#define EAP_SIM_AT_NOTIFICATION 12
 +#define EAP_SIM_AT_ANY_ID_REQ 13
 +#define EAP_SIM_AT_IDENTITY 14 /* only send */
 +#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */
 +#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */
 +#define EAP_SIM_AT_FULLAUTH_ID_REQ 17
 +#define EAP_SIM_AT_COUNTER 19 /* only encrypted */
 +#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */
 +#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */
 +#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */
 +#define EAP_SIM_AT_KDF_INPUT 23 /* only AKA' */
 +#define EAP_SIM_AT_KDF 24 /* only AKA' */
 +#define EAP_SIM_AT_IV 129
 +#define EAP_SIM_AT_ENCR_DATA 130
 +#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */
 +#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */
 +#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */
 +#define EAP_SIM_AT_RESULT_IND 135
 +#define EAP_SIM_AT_BIDDING 136
 +
 +/* AT_NOTIFICATION notification code values */
 +#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0
 +#define EAP_SIM_TEMPORARILY_DENIED 1026
 +#define EAP_SIM_NOT_SUBSCRIBED 1031
 +#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384
 +#define EAP_SIM_SUCCESS 32768
 +
 +/* EAP-AKA' AT_KDF Key Derivation Function values */
 +#define EAP_AKA_PRIME_KDF 1
 +
 +/* AT_BIDDING flags */
 +#define EAP_AKA_BIDDING_FLAG_D 0x8000
 +
 +
 +enum eap_sim_id_req {
 +      NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID
 +};
 +
 +
 +struct eap_sim_attrs {
 +      const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
 +      const u8 *next_pseudonym, *next_reauth_id;
 +      const u8 *nonce_mt, *identity, *res, *auts;
 +      const u8 *checkcode;
 +      const u8 *kdf_input;
 +      const u8 *bidding;
 +      size_t num_chal, version_list_len, encr_data_len;
 +      size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len;
 +      size_t res_len_bits;
 +      size_t checkcode_len;
 +      size_t kdf_input_len;
 +      enum eap_sim_id_req id_req;
 +      int notification, counter, selected_version, client_error_code;
 +      int counter_too_small;
 +      int result_ind;
 +#define EAP_AKA_PRIME_KDF_MAX 10
 +      u16 kdf[EAP_AKA_PRIME_KDF_MAX];
 +      size_t kdf_count;
 +};
 +
 +int eap_sim_parse_attr(const u8 *start, const u8 *end,
 +                     struct eap_sim_attrs *attr, int aka, int encr);
 +u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
 +                      size_t encr_data_len, const u8 *iv,
 +                      struct eap_sim_attrs *attr, int aka);
 +
 +
 +struct eap_sim_msg;
 +
 +struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype);
++struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type,
++                                 const u8 *k_aut,
 +                                 const u8 *extra, size_t extra_len);
 +void eap_sim_msg_free(struct eap_sim_msg *msg);
 +u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
 +                        const u8 *data, size_t len);
 +u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr,
 +                   u16 value, const u8 *data, size_t len);
 +u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr);
 +int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv,
 +                             u8 attr_encr);
 +int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr,
 +                           int attr_pad);
 +
 +void eap_sim_report_notification(void *msg_ctx, int notification, int aka);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_SIM_COMMON_H */
index 25522ae,0000000..fcec4ce
mode 100644,000000..100644
--- /dev/null
@@@ -1,126 -1,0 +1,120 @@@
-  * 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.
 +/*
 + * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt)
 + * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
 + *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_TLV_COMMON_H
 +#define EAP_TLV_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */
 +#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
 +#define EAP_TLV_NAK_TLV 4
 +#define EAP_TLV_ERROR_CODE_TLV 5
 +#define EAP_TLV_CONNECTION_BINDING_TLV 6
 +#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
 +#define EAP_TLV_URI_TLV 8
 +#define EAP_TLV_EAP_PAYLOAD_TLV 9
 +#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
 +#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */
 +#define EAP_TLV_CRYPTO_BINDING_TLV 12
 +#define EAP_TLV_CALLING_STATION_ID_TLV 13
 +#define EAP_TLV_CALLED_STATION_ID_TLV 14
 +#define EAP_TLV_NAS_PORT_TYPE_TLV 15
 +#define EAP_TLV_SERVER_IDENTIFIER_TLV 16
 +#define EAP_TLV_IDENTITY_TYPE_TLV 17
 +#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18
 +#define EAP_TLV_REQUEST_ACTION_TLV 19
 +#define EAP_TLV_PKCS7_TLV 20
 +
 +#define EAP_TLV_RESULT_SUCCESS 1
 +#define EAP_TLV_RESULT_FAILURE 2
 +
 +#define EAP_TLV_TYPE_MANDATORY 0x8000
 +#define EAP_TLV_TYPE_MASK 0x3fff
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +struct eap_tlv_hdr {
 +      be16 tlv_type;
 +      be16 length;
 +} STRUCT_PACKED;
 +
 +struct eap_tlv_nak_tlv {
 +      be16 tlv_type;
 +      be16 length;
 +      be32 vendor_id;
 +      be16 nak_type;
 +} STRUCT_PACKED;
 +
 +struct eap_tlv_result_tlv {
 +      be16 tlv_type;
 +      be16 length;
 +      be16 status;
 +} STRUCT_PACKED;
 +
 +/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */
 +struct eap_tlv_intermediate_result_tlv {
 +      be16 tlv_type;
 +      be16 length;
 +      be16 status;
 +      /* Followed by optional TLVs */
 +} STRUCT_PACKED;
 +
 +/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
 +struct eap_tlv_crypto_binding_tlv {
 +      be16 tlv_type;
 +      be16 length;
 +      u8 reserved;
 +      u8 version;
 +      u8 received_version;
 +      u8 subtype;
 +      u8 nonce[32];
 +      u8 compound_mac[20];
 +} STRUCT_PACKED;
 +
 +struct eap_tlv_pac_ack_tlv {
 +      be16 tlv_type;
 +      be16 length;
 +      be16 pac_type;
 +      be16 pac_len;
 +      be16 result;
 +} STRUCT_PACKED;
 +
 +/* RFC 4851, Section 4.2.9 - Request-Action TLV */
 +struct eap_tlv_request_action_tlv {
 +      be16 tlv_type;
 +      be16 length;
 +      be16 action;
 +} STRUCT_PACKED;
 +
 +/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
 +struct eap_tlv_pac_type_tlv {
 +      be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
 +      be16 length;
 +      be16 pac_type;
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
 +#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
 +
 +#define EAP_TLV_ACTION_PROCESS_TLV 1
 +#define EAP_TLV_ACTION_NEGOTIATE_EAP 2
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_TLV_COMMON_H */
index 08f371c,0000000..f439da2
mode 100644,000000..100644
--- /dev/null
@@@ -1,84 -1,0 +1,78 @@@
-  * 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.
 +/*
 + * EAP server/peer: EAP-TTLS (RFC 5281)
 + * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 + *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_TTLS_H
 +#define EAP_TTLS_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +struct ttls_avp {
 +      be32 avp_code;
 +      be32 avp_length; /* 8-bit flags, 24-bit length;
 +                        * length includes AVP header */
 +      /* optional 32-bit Vendor-ID */
 +      /* Data */
 +};
 +
 +struct ttls_avp_vendor {
 +      be32 avp_code;
 +      be32 avp_length; /* 8-bit flags, 24-bit length;
 +                        * length includes AVP header */
 +      be32 vendor_id;
 +      /* Data */
 +};
 +
 +
 +#define AVP_FLAGS_VENDOR 0x80
 +#define AVP_FLAGS_MANDATORY 0x40
 +
 +#define AVP_PAD(start, pos) \
 +do { \
 +      int __pad; \
 +      __pad = (4 - (((pos) - (start)) & 3)) & 3; \
 +      os_memset((pos), 0, __pad); \
 +      pos += __pad; \
 +} while (0)
 +
 +
 +/* RFC 2865 */
 +#define RADIUS_ATTR_USER_NAME 1
 +#define RADIUS_ATTR_USER_PASSWORD 2
 +#define RADIUS_ATTR_CHAP_PASSWORD 3
 +#define RADIUS_ATTR_REPLY_MESSAGE 18
 +#define RADIUS_ATTR_VENDOR_SPECIFIC 26
 +#define RADIUS_ATTR_CHAP_CHALLENGE 60
 +#define RADIUS_ATTR_EAP_MESSAGE 79
 +
 +/* RFC 2548 */
 +#define RADIUS_VENDOR_ID_MICROSOFT 311
 +#define RADIUS_ATTR_MS_CHAP_RESPONSE 1
 +#define RADIUS_ATTR_MS_CHAP_ERROR 2
 +#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6
 +#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11
 +#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25
 +#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26
 +#define RADIUS_ATTR_MS_CHAP2_CPW 27
 +
 +#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16
 +#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50
 +#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8
 +#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50
 +#define EAP_TTLS_CHAP_CHALLENGE_LEN 16
 +#define EAP_TTLS_CHAP_PASSWORD_LEN 16
 +
 +#define RADIUS_VENDOR_ID_UKERNA 25622
 +#define RADIUS_ATTR_UKERNA_CHBIND 135
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_TTLS_H */
index 2d88b5a,0000000..6914216
mode 100644,000000..100644
--- /dev/null
@@@ -1,41 -1,0 +1,35 @@@
-  * 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.
 +/*
 + * EAP-WSC definitions for Wi-Fi Protected Setup
 + * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
 + *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_WSC_COMMON_H
 +#define EAP_WSC_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +#define EAP_VENDOR_TYPE_WSC 1
 +
 +#define WSC_FLAGS_MF 0x01
 +#define WSC_FLAGS_LF 0x02
 +
 +#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0"
 +#define WSC_ID_REGISTRAR_LEN 30
 +#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0"
 +#define WSC_ID_ENROLLEE_LEN 29
 +
 +#define WSC_FRAGMENT_SIZE 1400
 +
 +
 +struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_WSC_COMMON_H */
Simple merge
Simple merge
Simple merge
Simple merge
index 6a1b511,0000000..831db76
mode 100644,000000..100644
--- /dev/null
@@@ -1,299 -1,0 +1,362 @@@
-  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP peer state machine functions (RFC 4137)
-  * 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.
++ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
 + *
-       EAPOL_altReject
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_H
 +#define EAP_H
 +
 +#include "common/defs.h"
 +#include "eap_common/eap_defs.h"
 +#include "eap_peer/eap_methods.h"
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +struct eap_sm;
 +struct wpa_config_blob;
 +struct wpabuf;
 +
 +struct eap_method_type {
 +      int vendor;
 +      u32 method;
 +};
 +
 +#ifdef IEEE8021X_EAPOL
 +
 +/**
 + * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine
 + *
 + * These variables are used in the interface between EAP peer state machine and
 + * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
 + * expected to maintain these variables and register a callback functions for
 + * EAP state machine to get and set the variables.
 + */
 +enum eapol_bool_var {
 +      /**
 +       * EAPOL_eapSuccess - EAP SUCCESS state reached
 +       *
 +       * EAP state machine reads and writes this value.
 +       */
 +      EAPOL_eapSuccess,
 +
 +      /**
 +       * EAPOL_eapRestart - Lower layer request to restart authentication
 +       *
 +       * Set to TRUE in lower layer, FALSE in EAP state machine.
 +       */
 +      EAPOL_eapRestart,
 +
 +      /**
 +       * EAPOL_eapFail - EAP FAILURE state reached
 +       *
 +       * EAP state machine writes this value.
 +       */
 +      EAPOL_eapFail,
 +
 +      /**
 +       * EAPOL_eapResp - Response to send
 +       *
 +       * Set to TRUE in EAP state machine, FALSE in lower layer.
 +       */
 +      EAPOL_eapResp,
 +
 +      /**
 +       * EAPOL_eapNoResp - Request has been process; no response to send
 +       *
 +       * Set to TRUE in EAP state machine, FALSE in lower layer.
 +       */
 +      EAPOL_eapNoResp,
 +
 +      /**
 +       * EAPOL_eapReq - EAP request available from lower layer
 +       *
 +       * Set to TRUE in lower layer, FALSE in EAP state machine.
 +       */
 +      EAPOL_eapReq,
 +
 +      /**
 +       * EAPOL_portEnabled - Lower layer is ready for communication
 +       *
 +       * EAP state machines reads this value.
 +       */
 +      EAPOL_portEnabled,
 +
 +      /**
 +       * EAPOL_altAccept - Alternate indication of success (RFC3748)
 +       *
 +       * EAP state machines reads this value.
 +       */
 +      EAPOL_altAccept,
 +
 +      /**
 +       * EAPOL_altReject - Alternate indication of failure (RFC3748)
 +       *
 +       * EAP state machines reads this value.
 +       */
-        * @field: Field name (e.g., "IDENTITY")
++      EAPOL_altReject,
++
++      /**
++       * EAPOL_eapTriggerStart - EAP-based trigger to send EAPOL-Start
++       *
++       * EAP state machine writes this value.
++       */
++      EAPOL_eapTriggerStart
 +};
 +
 +/**
 + * enum eapol_int_var - EAPOL integer state variables for EAP state machine
 + *
 + * These variables are used in the interface between EAP peer state machine and
 + * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
 + * expected to maintain these variables and register a callback functions for
 + * EAP state machine to get and set the variables.
 + */
 +enum eapol_int_var {
 +      /**
 +       * EAPOL_idleWhile - Outside time for EAP peer timeout
 +       *
 +       * This integer variable is used to provide an outside timer that the
 +       * external (to EAP state machine) code must decrement by one every
 +       * second until the value reaches zero. This is used in the same way as
 +       * EAPOL state machine timers. EAP state machine reads and writes this
 +       * value.
 +       */
 +      EAPOL_idleWhile
 +};
 +
 +/**
 + * struct eapol_callbacks - Callback functions from EAP to lower layer
 + *
 + * This structure defines the callback functions that EAP state machine
 + * requires from the lower layer (usually EAPOL state machine) for updating
 + * state variables and requesting information. eapol_ctx from
 + * eap_peer_sm_init() call will be used as the ctx parameter for these
 + * callback functions.
 + */
 +struct eapol_callbacks {
 +      /**
 +       * get_config - Get pointer to the current network configuration
 +       * @ctx: eapol_ctx from eap_peer_sm_init() call
 +       */
 +      struct eap_peer_config * (*get_config)(void *ctx);
 +
 +      /**
 +       * get_bool - Get a boolean EAPOL state variable
 +       * @variable: EAPOL boolean variable to get
 +       * Returns: Value of the EAPOL variable
 +       */
 +      Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
 +
 +      /**
 +       * set_bool - Set a boolean EAPOL state variable
 +       * @ctx: eapol_ctx from eap_peer_sm_init() call
 +       * @variable: EAPOL boolean variable to set
 +       * @value: Value for the EAPOL variable
 +       */
 +      void (*set_bool)(void *ctx, enum eapol_bool_var variable,
 +                       Boolean value);
 +
 +      /**
 +       * get_int - Get an integer EAPOL state variable
 +       * @ctx: eapol_ctx from eap_peer_sm_init() call
 +       * @variable: EAPOL integer variable to get
 +       * Returns: Value of the EAPOL variable
 +       */
 +      unsigned int (*get_int)(void *ctx, enum eapol_int_var variable);
 +
 +      /**
 +       * set_int - Set an integer EAPOL state variable
 +       * @ctx: eapol_ctx from eap_peer_sm_init() call
 +       * @variable: EAPOL integer variable to set
 +       * @value: Value for the EAPOL variable
 +       */
 +      void (*set_int)(void *ctx, enum eapol_int_var variable,
 +                      unsigned int value);
 +
 +      /**
 +       * get_eapReqData - Get EAP-Request data
 +       * @ctx: eapol_ctx from eap_peer_sm_init() call
 +       * @len: Pointer to variable that will be set to eapReqDataLen
 +       * Returns: Reference to eapReqData (EAP state machine will not free
 +       * this) or %NULL if eapReqData not available.
 +       */
 +      struct wpabuf * (*get_eapReqData)(void *ctx);
 +
 +      /**
 +       * set_config_blob - Set named configuration blob
 +       * @ctx: eapol_ctx from eap_peer_sm_init() call
 +       * @blob: New value for the blob
 +       *
 +       * Adds a new configuration blob or replaces the current value of an
 +       * existing blob.
 +       */
 +      void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
 +
 +      /**
 +       * get_config_blob - Get a named configuration blob
 +       * @ctx: eapol_ctx from eap_peer_sm_init() call
 +       * @name: Name of the blob
 +       * Returns: Pointer to blob data or %NULL if not found
 +       */
 +      const struct wpa_config_blob * (*get_config_blob)(void *ctx,
 +                                                        const char *name);
 +
 +      /**
 +       * notify_pending - Notify that a pending request can be retried
 +       * @ctx: eapol_ctx from eap_peer_sm_init() call
 +       *
 +       * An EAP method can perform a pending operation (e.g., to get a
 +       * response from an external process). Once the response is available,
 +       * this callback function can be used to request EAPOL state machine to
 +       * retry delivering the previously received (and still unanswered) EAP
 +       * request to EAP state machine.
 +       */
 +      void (*notify_pending)(void *ctx);
 +
 +      /**
 +       * eap_param_needed - Notify that EAP parameter is needed
 +       * @ctx: eapol_ctx from eap_peer_sm_init() call
-       void (*eap_param_needed)(void *ctx, const char *field,
++       * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
 +       * @txt: User readable text describing the required parameter
 +       */
-                                struct eapol_callbacks *eapol_cb,
++      void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
 +                               const char *txt);
++
++      /**
++       * notify_cert - Notification of a peer certificate
++       * @ctx: eapol_ctx from eap_peer_sm_init() call
++       * @depth: Depth in certificate chain (0 = server)
++       * @subject: Subject of the peer certificate
++       * @altsubject: Select fields from AltSubject of the peer certificate
++       * @num_altsubject: Number of altsubject values
++       * @cert_hash: SHA-256 hash of the certificate
++       * @cert: Peer certificate
++       */
++      void (*notify_cert)(void *ctx, int depth, const char *subject,
++                          const char *altsubject[], int num_altsubject,
++                          const char *cert_hash, const struct wpabuf *cert);
++
++      /**
++       * notify_status - Notification of the current EAP state
++       * @ctx: eapol_ctx from eap_peer_sm_init() call
++       * @status: Step in the process of EAP authentication
++       * @parameter: Step-specific parameter, e.g., EAP method name
++       */
++      void (*notify_status)(void *ctx, const char *status,
++                            const char *parameter);
++
++#ifdef CONFIG_EAP_PROXY
++      /**
++       * eap_proxy_cb - Callback signifying any updates from eap_proxy
++       * @ctx: eapol_ctx from eap_peer_sm_init() call
++       */
++      void (*eap_proxy_cb)(void *ctx);
++#endif /* CONFIG_EAP_PROXY */
++
++      /**
++       * set_anon_id - Set or add anonymous identity
++       * @ctx: eapol_ctx from eap_peer_sm_init() call
++       * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
++       * @len: Length of anonymous identity in octets
++       */
++      void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
 +};
 +
 +/**
 + * struct eap_config - Configuration for EAP state machine
 + */
 +struct eap_config {
 +      /**
 +       * opensc_engine_path - OpenSC engine for OpenSSL engine support
 +       *
 +       * Usually, path to engine_opensc.so.
 +       */
 +      const char *opensc_engine_path;
 +      /**
 +       * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support
 +       *
 +       * Usually, path to engine_pkcs11.so.
 +       */
 +      const char *pkcs11_engine_path;
 +      /**
 +       * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine
 +       *
 +       * Usually, path to opensc-pkcs11.so.
 +       */
 +      const char *pkcs11_module_path;
 +      /**
++       * openssl_ciphers - OpenSSL cipher string
++       *
++       * This is an OpenSSL specific configuration option for configuring the
++       * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the
++       * default.
++       */
++      const char *openssl_ciphers;
++      /**
 +       * wps - WPS context data
 +       *
 +       * This is only used by EAP-WSC and can be left %NULL if not available.
 +       */
 +      struct wps_context *wps;
++
++      /**
++       * cert_in_cb - Include server certificates in callback
++       */
++      int cert_in_cb;
 +};
 +
 +struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
++                               const struct eapol_callbacks *eapol_cb,
 +                               void *msg_ctx, struct eap_config *conf);
 +void eap_peer_sm_deinit(struct eap_sm *sm);
 +int eap_peer_sm_step(struct eap_sm *sm);
 +void eap_sm_abort(struct eap_sm *sm);
 +int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen,
 +                    int verbose);
++const char * eap_sm_get_method_name(struct eap_sm *sm);
 +struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted);
 +void eap_sm_request_identity(struct eap_sm *sm);
 +void eap_sm_request_password(struct eap_sm *sm);
 +void eap_sm_request_new_password(struct eap_sm *sm);
 +void eap_sm_request_pin(struct eap_sm *sm);
 +void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len);
 +void eap_sm_request_passphrase(struct eap_sm *sm);
++void eap_sm_request_sim(struct eap_sm *sm, const char *req);
 +void eap_sm_notify_ctrl_attached(struct eap_sm *sm);
 +u32 eap_get_phase2_type(const char *name, int *vendor);
 +struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
 +                                            size_t *count);
 +void eap_set_fast_reauth(struct eap_sm *sm, int enabled);
 +void eap_set_workaround(struct eap_sm *sm, unsigned int workaround);
 +void eap_set_force_disabled(struct eap_sm *sm, int disabled);
++void eap_set_external_sim(struct eap_sm *sm, int external_sim);
 +int eap_key_available(struct eap_sm *sm);
 +void eap_notify_success(struct eap_sm *sm);
 +void eap_notify_lower_layer_success(struct eap_sm *sm);
++const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len);
 +const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
 +struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
 +void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
 +void eap_invalidate_cached_session(struct eap_sm *sm);
 +
 +int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf);
 +int eap_is_wps_pin_enrollee(struct eap_peer_config *conf);
 +
++struct ext_password_data;
++void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
++void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
++int eap_peer_was_failure_expected(struct eap_sm *sm);
++void eap_peer_erp_free_keys(struct eap_sm *sm);
++
 +#endif /* IEEE8021X_EAPOL */
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_H */
Simple merge
index c78fba1,0000000..0b0824b
mode 100644,000000..100644
--- /dev/null
@@@ -1,711 -1,0 +1,816 @@@
-  * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP peer configuration data
-  * 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.
++ * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
 + *
-       u8 *private_key_passwd;
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_CONFIG_H
 +#define EAP_CONFIG_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/* http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3.1 */
 +#define CHBIND_CODE_REQUEST 1
 +#define CHBIND_CODE_SUCCESS 2
 +#define CHBIND_CODE_FAILURE 3
 +/* http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3. */
 +#define CHBIND_NSID_RADIUS 1
 +
 +struct eap_peer_chbind_config
 +{
 +    /* namespace id for this channel binding info */
 +    int nsid;
 +
 +    /* data to be sent in channel binding request */
 +    u8 *req_data;
 +
 +    size_t req_data_len;
 +
 +    /* lower level callback invoked when response is received */
 +    void (*response_cb)(void *ctx, int code, int nsid, u8 *resp_data, size_t resp_data_len);
 +
 +    /* context for response callback */
 +    void *ctx;
 +};
 +
 +/**
 + * struct eap_peer_config - EAP peer configuration/credentials
 + */
 +struct eap_peer_config {
 +      /**
 +       * identity - EAP Identity
 +       *
 +       * This field is used to set the real user identity or NAI (for
 +       * EAP-PSK/PAX/SAKE/GPSK).
 +       */
 +      u8 *identity;
 +
 +      /**
 +       * identity_len - EAP Identity length
 +       */
 +      size_t identity_len;
 +
 +      /**
 +       * anonymous_identity -  Anonymous EAP Identity
 +       *
 +       * This field is used for unencrypted use with EAP types that support
 +       * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
 +       * real identity (identity field) only to the authentication server.
 +       *
 +       * If not set, the identity field will be used for both unencrypted and
 +       * protected fields.
++       *
++       * This field can also be used with EAP-SIM/AKA/AKA' to store the
++       * pseudonym identity.
 +       */
 +      u8 *anonymous_identity;
 +
 +      /**
 +       * anonymous_identity_len - Length of anonymous_identity
 +       */
 +      size_t anonymous_identity_len;
 +
 +      /**
 +       * password - Password string for EAP
 +       *
 +       * This field can include either the plaintext password (default
 +       * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
 +       * presentation of the password) if flags field has
 +       * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
 +       * only be used with authentication mechanism that use this hash as the
 +       * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
 +       * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
 +       *
 +       * In addition, this field is used to configure a pre-shared key for
 +       * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
 +       * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
 +       * PSK.
 +       */
 +      u8 *password;
 +
 +      /**
 +       * password_len - Length of password field
 +       */
 +      size_t password_len;
 +
 +      /**
 +       * ca_cert - File path to CA certificate file (PEM/DER)
 +       *
 +       * This file can have one or more trusted CA certificates. If ca_cert
 +       * and ca_path are not included, server certificate will not be
 +       * verified. This is insecure and a trusted CA certificate should
 +       * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       *
 +       * Alternatively, this can be used to only perform matching of the
 +       * server certificate (SHA-256 hash of the DER encoded X.509
 +       * certificate). In this case, the possible CA certificates in the
 +       * server certificate chain are ignored and only the server certificate
 +       * is verified. This is configured with the following format:
 +       * hash:://server/sha256/cert_hash_in_hex
 +       * For example: "hash://server/sha256/
 +       * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a"
 +       *
 +       * On Windows, trusted CA certificates can be loaded from the system
 +       * certificate store by setting this to cert_store://name, e.g.,
 +       * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
 +       * Note that when running wpa_supplicant as an application, the user
 +       * certificate store (My user account) is used, whereas computer store
 +       * (Computer account) is used when running wpasvc as a service.
 +       */
 +      u8 *ca_cert;
 +
 +      /**
 +       * ca_path - Directory path for CA certificate files (PEM)
 +       *
 +       * This path may contain multiple CA certificates in OpenSSL format.
 +       * Common use for this is to point to system trusted CA list which is
 +       * often installed into directory like /etc/ssl/certs. If configured,
 +       * these certificates are added to the list of trusted CAs. ca_cert
 +       * may also be included in that case, but it is not required.
 +       */
 +      u8 *ca_path;
 +
 +      /**
 +       * client_cert - File path to client certificate file (PEM/DER)
 +       *
 +       * This field is used with EAP method that use TLS authentication.
 +       * Usually, this is only configured for EAP-TLS, even though this could
 +       * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *client_cert;
 +
 +      /**
 +       * private_key - File path to client private key file (PEM/DER/PFX)
 +       *
 +       * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
 +       * commented out. Both the private key and certificate will be read
 +       * from the PKCS#12 file in this case. Full path to the file should be
 +       * used since working directory may change when wpa_supplicant is run
 +       * in the background.
 +       *
 +       * Windows certificate store can be used by leaving client_cert out and
 +       * configuring private_key in one of the following formats:
 +       *
 +       * cert://substring_to_match
 +       *
 +       * hash://certificate_thumbprint_in_hex
 +       *
 +       * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
 +       *
 +       * Note that when running wpa_supplicant as an application, the user
 +       * certificate store (My user account) is used, whereas computer store
 +       * (Computer account) is used when running wpasvc as a service.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *private_key;
 +
 +      /**
 +       * private_key_passwd - Password for private key file
 +       *
 +       * If left out, this will be asked through control interface.
 +       */
-       u8 *private_key2_passwd;
++      char *private_key_passwd;
 +
 +      /**
 +       * dh_file - File path to DH/DSA parameters file (in PEM format)
 +       *
 +       * This is an optional configuration file for setting parameters for an
 +       * ephemeral DH key exchange. In most cases, the default RSA
 +       * authentication does not use this configuration. However, it is
 +       * possible setup RSA to use ephemeral DH key exchange. In addition,
 +       * ciphers with DSA keys always use ephemeral DH keys. This can be used
 +       * to achieve forward secrecy. If the file is in DSA parameters format,
 +       * it will be automatically converted into DH params. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *dh_file;
 +
 +      /**
 +       * subject_match - Constraint for server certificate subject
 +       *
 +       * This substring is matched against the subject of the authentication
 +       * server certificate. If this string is set, the server sertificate is
 +       * only accepted if it contains this string in the subject. The subject
 +       * string is in following format:
 +       *
 +       * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com
++       *
++       * Note: Since this is a substring match, this cannot be used securily
++       * to do a suffix match against a possible domain name in the CN entry.
++       * For such a use case, domain_suffix_match should be used instead.
 +       */
 +      u8 *subject_match;
 +
 +      /**
 +       * altsubject_match - Constraint for server certificate alt. subject
 +       *
 +       * Semicolon separated string of entries to be matched against the
 +       * alternative subject name of the authentication server certificate.
 +       * If this string is set, the server sertificate is only accepted if it
 +       * contains one of the entries in an alternative subject name
 +       * extension.
 +       *
 +       * altSubjectName string is in following format: TYPE:VALUE
 +       *
 +       * Example: EMAIL:server@example.com
 +       * Example: DNS:server.example.com;DNS:server2.example.com
 +       *
 +       * Following types are supported: EMAIL, DNS, URI
 +       */
 +      u8 *altsubject_match;
 +
 +      /**
++       * domain_suffix_match - Constraint for server domain name
++       *
++       * If set, this FQDN is used as a suffix match requirement for the
++       * server certificate in SubjectAltName dNSName element(s). If a
++       * matching dNSName is found, this constraint is met. If no dNSName
++       * values are present, this constraint is matched against SubjectName CN
++       * using same suffix match comparison. Suffix match here means that the
++       * host/domain name is compared one label at a time starting from the
++       * top-level domain and all the labels in domain_suffix_match shall be
++       * included in the certificate. The certificate may include additional
++       * sub-level labels in addition to the required labels.
++       *
++       * For example, domain_suffix_match=example.com would match
++       * test.example.com but would not match test-example.com.
++       */
++      char *domain_suffix_match;
++
++      /**
++       * domain_match - Constraint for server domain name
++       *
++       * If set, this FQDN is used as a full match requirement for the
++       * server certificate in SubjectAltName dNSName element(s). If a
++       * matching dNSName is found, this constraint is met. If no dNSName
++       * values are present, this constraint is matched against SubjectName CN
++       * using same full match comparison. This behavior is similar to
++       * domain_suffix_match, but has the requirement of a full match, i.e.,
++       * no subdomains or wildcard matches are allowed. Case-insensitive
++       * comparison is used, so "Example.com" matches "example.com", but would
++       * not match "test.Example.com".
++       */
++      char *domain_match;
++
++      /**
 +       * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
 +       *
 +       * This file can have one or more trusted CA certificates. If ca_cert2
 +       * and ca_path2 are not included, server certificate will not be
 +       * verified. This is insecure and a trusted CA certificate should
 +       * always be configured. Full path to the file should be used since
 +       * working directory may change when wpa_supplicant is run in the
 +       * background.
 +       *
 +       * This field is like ca_cert, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *ca_cert2;
 +
 +      /**
 +       * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
 +       *
 +       * This path may contain multiple CA certificates in OpenSSL format.
 +       * Common use for this is to point to system trusted CA list which is
 +       * often installed into directory like /etc/ssl/certs. If configured,
 +       * these certificates are added to the list of trusted CAs. ca_cert
 +       * may also be included in that case, but it is not required.
 +       *
 +       * This field is like ca_path, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      u8 *ca_path2;
 +
 +      /**
 +       * client_cert2 - File path to client certificate file
 +       *
 +       * This field is like client_cert, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *client_cert2;
 +
 +      /**
 +       * private_key2 - File path to client private key file
 +       *
 +       * This field is like private_key, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *private_key2;
 +
 +      /**
 +       * private_key2_passwd -  Password for private key file
 +       *
 +       * This field is like private_key_passwd, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
-        * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS.
++      char *private_key2_passwd;
 +
 +      /**
 +       * dh_file2 - File path to DH/DSA parameters file (in PEM format)
 +       *
 +       * This field is like dh_file, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
 +       * file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       *
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      u8 *dh_file2;
 +
 +      /**
 +       * subject_match2 - Constraint for server certificate subject
 +       *
 +       * This field is like subject_match, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      u8 *subject_match2;
 +
 +      /**
 +       * altsubject_match2 - Constraint for server certificate alt. subject
 +       *
 +       * This field is like altsubject_match, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      u8 *altsubject_match2;
 +
 +      /**
++       * domain_suffix_match2 - Constraint for server domain name
++       *
++       * This field is like domain_suffix_match, but used for phase 2 (inside
++       * EAP-TTLS/PEAP/FAST tunnel) authentication.
++       */
++      char *domain_suffix_match2;
++
++      /**
++       * domain_match2 - Constraint for server domain name
++       *
++       * This field is like domain_match, but used for phase 2 (inside
++       * EAP-TTLS/PEAP/FAST tunnel) authentication.
++       */
++      char *domain_match2;
++
++      /**
 +       * eap_methods - Allowed EAP methods
 +       *
 +       * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
 +       * allowed EAP methods or %NULL if all methods are accepted.
 +       */
 +      struct eap_method_type *eap_methods;
 +
 +      /**
 +       * phase1 - Phase 1 (outer authentication) parameters
 +       *
 +       * String with field-value pairs, e.g., "peapver=0" or
 +       * "peapver=1 peaplabel=1".
 +       *
 +       * 'peapver' can be used to force which PEAP version (0 or 1) is used.
 +       *
 +       * 'peaplabel=1' can be used to force new label, "client PEAP
 +       * encryption", to be used during key derivation when PEAPv1 or newer.
 +       *
 +       * Most existing PEAPv1 implementation seem to be using the old label,
 +       * "client EAP encryption", and wpa_supplicant is now using that as the
 +       * default value.
 +       *
 +       * Some servers, e.g., Radiator, may require peaplabel=1 configuration
 +       * to interoperate with PEAPv1; see eap_testing.txt for more details.
 +       *
 +       * 'peap_outer_success=0' can be used to terminate PEAP authentication
 +       * on tunneled EAP-Success. This is required with some RADIUS servers
 +       * that implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g.,
 +       * Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode).
 +       *
 +       * include_tls_length=1 can be used to force wpa_supplicant to include
 +       * TLS Message Length field in all TLS messages even if they are not
 +       * fragmented.
 +       *
 +       * sim_min_num_chal=3 can be used to configure EAP-SIM to require three
 +       * challenges (by default, it accepts 2 or 3).
 +       *
 +       * result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use
 +       * protected result indication.
 +       *
 +       * fast_provisioning option can be used to enable in-line provisioning
 +       * of EAP-FAST credentials (PAC):
 +       * 0 = disabled,
 +       * 1 = allow unauthenticated provisioning,
 +       * 2 = allow authenticated provisioning,
 +       * 3 = allow both unauthenticated and authenticated provisioning
 +       *
 +       * fast_max_pac_list_len=num option can be used to set the maximum
 +       * number of PAC entries to store in a PAC list (default: 10).
 +       *
 +       * fast_pac_format=binary option can be used to select binary format
 +       * for storing PAC entries in order to save some space (the default
 +       * text format uses about 2.5 times the size of minimal binary format).
 +       *
 +       * crypto_binding option can be used to control PEAPv0 cryptobinding
 +       * behavior:
 +       * 0 = do not use cryptobinding (default)
 +       * 1 = use cryptobinding if server supports it
 +       * 2 = require cryptobinding
 +       *
 +       * EAP-WSC (WPS) uses following options: pin=Device_Password and
 +       * uuid=Device_UUID
++       *
++       * For wired IEEE 802.1X authentication, "allow_canned_success=1" can be
++       * used to configure a mode that allows EAP-Success (and EAP-Failure)
++       * without going through authentication step. Some switches use such
++       * sequence when forcing the port to be authorized/unauthorized or as a
++       * fallback option if the authentication server is unreachable. By
++       * default, wpa_supplicant discards such frames to protect against
++       * potential attacks by rogue devices, but this option can be used to
++       * disable that protection for cases where the server/authenticator does
++       * not need to be authenticated.
 +       */
 +      char *phase1;
 +
 +      /**
 +       * phase2 - Phase2 (inner authentication with TLS tunnel) parameters
 +       *
 +       * String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
++       * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. "mschapv2_retry=0" can
++       * be used to disable MSCHAPv2 password retry in authentication failure
++       * cases.
 +       */
 +      char *phase2;
 +
 +      /**
 +       * pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
 +       *
 +       * This field is used to configure PC/SC smartcard interface.
 +       * Currently, the only configuration is whether this field is %NULL (do
 +       * not use PC/SC) or non-NULL (e.g., "") to enable PC/SC.
 +       *
 +       * This field is used for EAP-SIM and EAP-AKA.
 +       */
 +      char *pcsc;
 +
 +      /**
 +       * pin - PIN for USIM, GSM SIM, and smartcards
 +       *
 +       * This field is used to configure PIN for SIM and smartcards for
 +       * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
 +       * smartcard is used for private key operations.
 +       *
 +       * If left out, this will be asked through control interface.
 +       */
 +      char *pin;
 +
 +      /**
 +       * engine - Enable OpenSSL engine (e.g., for smartcard access)
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      int engine;
 +
 +      /**
 +       * engine_id - Engine ID for OpenSSL engine
 +       *
 +       * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
 +       * engine.
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *engine_id;
 +
 +      /**
 +       * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2)
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       *
 +       * This field is like engine, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      int engine2;
 +
 +
 +      /**
 +       * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2)
 +       *
 +       * This field is used to configure PIN for SIM and smartcards for
 +       * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
 +       * smartcard is used for private key operations.
 +       *
 +       * This field is like pin2, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       *
 +       * If left out, this will be asked through control interface.
 +       */
 +      char *pin2;
 +
 +      /**
 +       * engine2_id - Engine ID for OpenSSL engine (Phase 2)
 +       *
 +       * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
 +       * engine.
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       *
 +       * This field is like engine_id, but used for phase 2 (inside
 +       * EAP-TTLS/PEAP/FAST tunnel) authentication.
 +       */
 +      char *engine2_id;
 +
 +
 +      /**
 +       * key_id - Key ID for OpenSSL engine
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *key_id;
 +
 +      /**
 +       * cert_id - Cert ID for OpenSSL engine
 +       *
 +       * This is used if the certificate operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *cert_id;
 +
 +      /**
 +       * ca_cert_id - CA Cert ID for OpenSSL engine
 +       *
 +       * This is used if the CA certificate for EAP-TLS is on a smartcard.
 +       */
 +      char *ca_cert_id;
 +
 +      /**
 +       * key2_id - Key ID for OpenSSL engine (phase2)
 +       *
 +       * This is used if private key operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *key2_id;
 +
 +      /**
 +       * cert2_id - Cert ID for OpenSSL engine (phase2)
 +       *
 +       * This is used if the certificate operations for EAP-TLS are performed
 +       * using a smartcard.
 +       */
 +      char *cert2_id;
 +
 +      /**
 +       * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2)
 +       *
 +       * This is used if the CA certificate for EAP-TLS is on a smartcard.
 +       */
 +      char *ca_cert2_id;
 +
 +      /**
 +       * otp - One-time-password
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when OTP is entered through the control interface.
 +       */
 +      u8 *otp;
 +
 +      /**
 +       * otp_len - Length of the otp field
 +       */
 +      size_t otp_len;
 +
 +      /**
 +       * pending_req_identity - Whether there is a pending identity request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_identity;
 +
 +      /**
 +       * pending_req_password - Whether there is a pending password request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_password;
 +
 +      /**
 +       * pending_req_pin - Whether there is a pending PIN request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_pin;
 +
 +      /**
 +       * pending_req_new_password - Pending password update request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_new_password;
 +
 +      /**
 +       * pending_req_passphrase - Pending passphrase request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      int pending_req_passphrase;
 +
 +      /**
 +       * pending_req_otp - Whether there is a pending OTP request
 +       *
 +       * This field should not be set in configuration step. It is only used
 +       * internally when control interface is used to request needed
 +       * information.
 +       */
 +      char *pending_req_otp;
 +
 +      /**
 +       * pending_req_otp_len - Length of the pending OTP request
 +       */
 +      size_t pending_req_otp_len;
 +
 +      /**
 +       * pac_file - File path or blob name for the PAC entries (EAP-FAST)
 +       *
 +       * wpa_supplicant will need to be able to create this file and write
 +       * updates to it when PAC is being provisioned or refreshed. Full path
 +       * to the file should be used since working directory may change when
 +       * wpa_supplicant is run in the background.
 +       * Alternatively, a named configuration blob can be used by setting
 +       * this to blob://blob_name.
 +       */
 +      char *pac_file;
 +
 +      /**
 +       * mschapv2_retry - MSCHAPv2 retry in progress
 +       *
 +       * This field is used internally by EAP-MSCHAPv2 and should not be set
 +       * as part of configuration.
 +       */
 +      int mschapv2_retry;
 +
 +      /**
 +       * new_password - New password for password update
 +       *
 +       * This field is used during MSCHAPv2 password update. This is normally
 +       * requested from the user through the control interface and not set
 +       * from configuration.
 +       */
 +      u8 *new_password;
 +
 +      /**
 +       * new_password_len - Length of new_password field
 +       */
 +      size_t new_password_len;
 +
 +      /**
 +       * fragment_size - Maximum EAP fragment size in bytes (default 1398)
 +       *
 +       * This value limits the fragment size for EAP methods that support
 +       * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set
 +       * small enough to make the EAP messages fit in MTU of the network
 +       * interface used for EAPOL. The default value is suitable for most
 +       * cases.
 +       */
 +      int fragment_size;
 +
 +    /**
 +     * chbind_config - eap channel binding config data
 +     */
 +    struct eap_peer_chbind_config *chbind_config;
 +
 +    /**
 +     * chbind_config_len - channel binding config data count
 +     */
 +    size_t chbind_config_len;
 +
 +#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
++#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
 +      /**
 +       * flags - Network configuration flags (bitfield)
 +       *
 +       * This variable is used for internal flags to describe further details
 +       * for the network parameters.
 +       * bit 0 = password is represented as a 16-byte NtPasswordHash value
 +       *         instead of plaintext password
++       * bit 1 = password is stored in external storage; the value in the
++       *         password field is the name of that external entry
 +       */
 +      u32 flags;
++
++      /**
++       * ocsp - Whether to use/require OCSP to check server certificate
++       *
++       * 0 = do not use OCSP stapling (TLS certificate status extension)
++       * 1 = try to use OCSP stapling, but not require response
++       * 2 = require valid OCSP stapling response
++       */
++      int ocsp;
++
++      /**
++       * external_sim_resp - Response from external SIM processing
++       *
++       * This field should not be set in configuration step. It is only used
++       * internally when control interface is used to request external
++       * SIM/USIM processing.
++       */
++      char *external_sim_resp;
++
++      /**
++       * sim_num - User selected SIM identifier
++       *
++       * This variable is used for identifying which SIM is used if the system
++       * has more than one.
++       */
++      int sim_num;
++
++      /**
++       * openssl_ciphers - OpenSSL cipher string
++       *
++       * This is an OpenSSL specific configuration option for configuring the
++       * ciphers for this connection. If not set, the default cipher suite
++       * list is used.
++       */
++      char *openssl_ciphers;
++
++      /**
++       * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
++       */
++      int erp;
 +};
 +
 +
 +/**
 + * struct wpa_config_blob - Named configuration blob
 + *
 + * This data structure is used to provide storage for binary objects to store
 + * abstract information like certificates and private keys inlined with the
 + * configuration data.
 + */
 +struct wpa_config_blob {
 +      /**
 +       * name - Blob name
 +       */
 +      char *name;
 +
 +      /**
 +       * data - Pointer to binary data
 +       */
 +      u8 *data;
 +
 +      /**
 +       * len - Length of binary data
 +       */
 +      size_t len;
 +
 +      /**
 +       * next - Pointer to next blob in the configuration
 +       */
 +      struct wpa_config_blob *next;
 +};
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_CONFIG_H */
index 0000000,dfbda56..dfbda56
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index d6c391c,0000000..5d915fa
mode 100644,000000..100644
--- /dev/null
@@@ -1,364 -1,0 +1,397 @@@
-  * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP peer state machines internal structures (RFC 4137)
-  * 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.
++ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
 + *
-       struct eapol_callbacks *eapol_cb;
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_I_H
 +#define EAP_I_H
 +
 +#include "wpabuf.h"
++#include "utils/list.h"
 +#include "eap_peer/eap.h"
 +#include "eap_common/eap_common.h"
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/* RFC 4137 - EAP Peer state machine */
 +
 +typedef enum {
 +      DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC
 +} EapDecision;
 +
 +typedef enum {
 +      METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE
 +} EapMethodState;
 +
 +/**
 + * struct eap_method_ret - EAP return values from struct eap_method::process()
 + *
 + * These structure contains OUT variables for the interface between peer state
 + * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as
 + * the return value of struct eap_method::process() so it is not included in
 + * this structure.
 + */
 +struct eap_method_ret {
 +      /**
 +       * ignore - Whether method decided to drop the current packed (OUT)
 +       */
 +      Boolean ignore;
 +
 +      /**
 +       * methodState - Method-specific state (IN/OUT)
 +       */
 +      EapMethodState methodState;
 +
 +      /**
 +       * decision - Authentication decision (OUT)
 +       */
 +      EapDecision decision;
 +
 +      /**
 +       * allowNotifications - Whether method allows notifications (OUT)
 +       */
 +      Boolean allowNotifications;
 +};
 +
 +
 +/**
 + * struct eap_method - EAP method interface
 + * This structure defines the EAP method interface. Each method will need to
 + * register its own EAP type, EAP name, and set of function pointers for method
 + * specific operations. This interface is based on section 4.4 of RFC 4137.
 + */
 +struct eap_method {
 +      /**
 +       * vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
 +       */
 +      int vendor;
 +
 +      /**
 +       * method - EAP type number (EAP_TYPE_*)
 +       */
 +      EapType method;
 +
 +      /**
 +       * name - Name of the method (e.g., "TLS")
 +       */
 +      const char *name;
 +
 +      /**
 +       * init - Initialize an EAP method
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * Returns: Pointer to allocated private data, or %NULL on failure
 +       *
 +       * This function is used to initialize the EAP method explicitly
 +       * instead of using METHOD_INIT state as specific in RFC 4137. The
 +       * method is expected to initialize it method-specific state and return
 +       * a pointer that will be used as the priv argument to other calls.
 +       */
 +      void * (*init)(struct eap_sm *sm);
 +
 +      /**
 +       * deinit - Deinitialize an EAP method
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       *
 +       * Deinitialize the EAP method and free any allocated private data.
 +       */
 +      void (*deinit)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * process - Process an EAP request
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @ret: Return values from EAP request validation and processing
 +       * @reqData: EAP request to be processed (eapReqData)
 +       * Returns: Pointer to allocated EAP response packet (eapRespData)
 +       *
 +       * This function is a combination of m.check(), m.process(), and
 +       * m.buildResp() procedures defined in section 4.4 of RFC 4137 In other
 +       * words, this function validates the incoming request, processes it,
 +       * and build a response packet. m.check() and m.process() return values
 +       * are returned through struct eap_method_ret *ret variable. Caller is
 +       * responsible for freeing the returned EAP response packet.
 +       */
 +      struct wpabuf * (*process)(struct eap_sm *sm, void *priv,
 +                                 struct eap_method_ret *ret,
 +                                 const struct wpabuf *reqData);
 +
 +      /**
 +       * isKeyAvailable - Find out whether EAP method has keying material
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * Returns: %TRUE if key material (eapKeyData) is available
 +       */
 +      Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * getKey - Get EAP method specific keying material (eapKeyData)
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @len: Pointer to variable to store key length (eapKeyDataLen)
 +       * Returns: Keying material (eapKeyData) or %NULL if not available
 +       *
 +       * This function can be used to get the keying material from the EAP
 +       * method. The key may already be stored in the method-specific private
 +       * data or this function may derive the key.
 +       */
 +      u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
 +
 +      /**
 +       * get_status - Get EAP method status
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @buf: Buffer for status information
 +       * @buflen: Maximum buffer length
 +       * @verbose: Whether to include verbose status information
 +       * Returns: Number of bytes written to buf
 +       *
 +       * Query EAP method for status information. This function fills in a
 +       * text area with current status information from the EAP method. If
 +       * the buffer (buf) is not large enough, status information will be
 +       * truncated to fit the buffer.
 +       */
 +      int (*get_status)(struct eap_sm *sm, void *priv, char *buf,
 +                        size_t buflen, int verbose);
 +
 +      /**
 +       * has_reauth_data - Whether method is ready for fast reauthentication
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * Returns: %TRUE or %FALSE based on whether fast reauthentication is
 +       * possible
 +       *
 +       * This function is an optional handler that only EAP methods
 +       * supporting fast re-authentication need to implement.
 +       */
 +      Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * deinit_for_reauth - Release data that is not needed for fast re-auth
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       *
 +       * This function is an optional handler that only EAP methods
 +       * supporting fast re-authentication need to implement. This is called
 +       * when authentication has been completed and EAP state machine is
 +       * requesting that enough state information is maintained for fast
 +       * re-authentication
 +       */
 +      void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * init_for_reauth - Prepare for start of fast re-authentication
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       *
 +       * This function is an optional handler that only EAP methods
 +       * supporting fast re-authentication need to implement. This is called
 +       * when EAP authentication is started and EAP state machine is
 +       * requesting fast re-authentication to be used.
 +       */
 +      void * (*init_for_reauth)(struct eap_sm *sm, void *priv);
 +
 +      /**
 +       * get_identity - Get method specific identity for re-authentication
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @len: Length of the returned identity
 +       * Returns: Pointer to the method specific identity or %NULL if default
 +       * identity is to be used
 +       *
 +       * This function is an optional handler that only EAP methods
 +       * that use method specific identity need to implement.
 +       */
 +      const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
 +
 +      /**
 +       * free - Free EAP method data
 +       * @method: Pointer to the method data registered with
 +       * eap_peer_method_register().
 +       *
 +       * This function will be called when the EAP method is being
 +       * unregistered. If the EAP method allocated resources during
 +       * registration (e.g., allocated struct eap_method), they should be
 +       * freed in this function. No other method functions will be called
 +       * after this call. If this function is not defined (i.e., function
 +       * pointer is %NULL), a default handler is used to release the method
 +       * data with free(method). This is suitable for most cases.
 +       */
 +      void (*free)(struct eap_method *method);
 +
 +#define EAP_PEER_METHOD_INTERFACE_VERSION 1
 +      /**
 +       * version - Version of the EAP peer method interface
 +       *
 +       * The EAP peer method implementation should set this variable to
 +       * EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the
 +       * EAP method is using supported API version when using dynamically
 +       * loadable EAP methods.
 +       */
 +      int version;
 +
 +      /**
 +       * next - Pointer to the next EAP method
 +       *
 +       * This variable is used internally in the EAP method registration code
 +       * to create a linked list of registered EAP methods.
 +       */
 +      struct eap_method *next;
 +
 +#ifdef CONFIG_DYNAMIC_EAP_METHODS
 +      /**
 +       * dl_handle - Handle for the dynamic library
 +       *
 +       * This variable is used internally in the EAP method registration code
 +       * to store a handle for the dynamic library. If the method is linked
 +       * in statically, this is %NULL.
 +       */
 +      void *dl_handle;
 +#endif /* CONFIG_DYNAMIC_EAP_METHODS */
 +
 +      /**
 +       * get_emsk - Get EAP method specific keying extended material (EMSK)
 +       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 +       * @priv: Pointer to private EAP method data from eap_method::init()
 +       * @len: Pointer to a variable to store EMSK length
 +       * Returns: EMSK or %NULL if not available
 +       *
 +       * This function can be used to get the extended keying material from
 +       * the EAP method. The key may already be stored in the method-specific
 +       * private data or this function may derive the key.
 +       */
 +      u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
++
++      /**
++       * getSessionId - Get EAP method specific Session-Id
++       * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
++       * @priv: Pointer to private EAP method data from eap_method::init()
++       * @len: Pointer to a variable to store Session-Id length
++       * Returns: Session-Id or %NULL if not available
++       *
++       * This function can be used to get the Session-Id from the EAP method.
++       * The Session-Id may already be stored in the method-specific private
++       * data or this function may derive the Session-Id.
++       */
++      u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
 +};
 +
 +
++struct eap_erp_key {
++      struct dl_list list;
++      size_t rRK_len;
++      size_t rIK_len;
++      u8 rRK[ERP_MAX_KEY_LEN];
++      u8 rIK[ERP_MAX_KEY_LEN];
++      u32 next_seq;
++      char keyname_nai[];
++};
++
 +/**
 + * struct eap_sm - EAP state machine data
 + */
 +struct eap_sm {
 +      enum {
 +              EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED,
 +              EAP_GET_METHOD, EAP_METHOD, EAP_SEND_RESPONSE, EAP_DISCARD,
 +              EAP_IDENTITY, EAP_NOTIFICATION, EAP_RETRANSMIT, EAP_SUCCESS,
 +              EAP_FAILURE
 +      } EAP_state;
 +      /* Long-term local variables */
 +      EapType selectedMethod;
 +      EapMethodState methodState;
 +      int lastId;
 +      struct wpabuf *lastRespData;
 +      EapDecision decision;
 +      /* Short-term local variables */
 +      Boolean rxReq;
 +      Boolean rxSuccess;
 +      Boolean rxFailure;
 +      int reqId;
 +      EapType reqMethod;
 +      int reqVendor;
 +      u32 reqVendorMethod;
 +      Boolean ignore;
 +      /* Constants */
 +      int ClientTimeout;
 +
 +      /* Miscellaneous variables */
 +      Boolean allowNotifications; /* peer state machine <-> methods */
 +      struct wpabuf *eapRespData; /* peer to lower layer */
 +      Boolean eapKeyAvailable; /* peer to lower layer */
 +      u8 *eapKeyData; /* peer to lower layer */
 +      size_t eapKeyDataLen; /* peer to lower layer */
++      u8 *eapSessionId; /* peer to lower layer */
++      size_t eapSessionIdLen; /* peer to lower layer */
 +      const struct eap_method *m; /* selected EAP method */
 +      /* not defined in RFC 4137 */
 +      Boolean changed;
 +      void *eapol_ctx;
-       u8 req_md5[16]; /* MD5() of the current EAP packet */
-       u8 last_md5[16]; /* MD5() of the previously received EAP packet; used
-                         * in duplicate request detection. */
++      const struct eapol_callbacks *eapol_cb;
 +      void *eap_method_priv;
 +      int init_phase2;
 +      int fast_reauth;
++      Boolean reauthInit; /* send EAP-Identity/Re-auth */
++      u32 erp_seq;
 +
 +      Boolean rxResp /* LEAP only */;
 +      Boolean leap_done;
 +      Boolean peap_done;
++      u8 req_sha1[20]; /* SHA1() of the current EAP packet */
++      u8 last_sha1[20]; /* SHA1() of the previously received EAP packet; used
++                         * in duplicate request detection. */
 +
 +      void *msg_ctx;
 +      void *scard_ctx;
 +      void *ssl_ctx;
++      void *ssl_ctx2;
 +
 +      unsigned int workaround;
 +
 +      /* Optional challenges generated in Phase 1 (EAP-FAST) */
 +      u8 *peer_challenge, *auth_challenge;
 +
 +      int num_rounds;
 +      int force_disabled;
 +
 +      struct wps_context *wps;
 +
 +      int prev_failure;
++      struct eap_peer_config *last_config;
++
++      struct ext_password_data *ext_pw;
++      struct wpabuf *ext_pw_buf;
++
++      int external_sim;
++
++      unsigned int expected_failure:1;
++
++      struct dl_list erp_keys; /* struct eap_erp_key */
 +};
 +
 +const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
 +const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len);
 +const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash);
 +const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len);
 +const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len);
 +void eap_clear_config_otp(struct eap_sm *sm);
 +const char * eap_get_config_phase1(struct eap_sm *sm);
 +const char * eap_get_config_phase2(struct eap_sm *sm);
 +int eap_get_config_fragment_size(struct eap_sm *sm);
 +struct eap_peer_config * eap_get_config(struct eap_sm *sm);
 +void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob);
 +const struct wpa_config_blob *
 +eap_get_config_blob(struct eap_sm *sm, const char *name);
 +void eap_notify_pending(struct eap_sm *sm);
 +int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_I_H */
Simple merge
Simple merge
Simple merge
Simple merge
index 8045a4d,0000000..11c3278
mode 100644,000000..100644
--- /dev/null
@@@ -1,122 -1,0 +1,119 @@@
-  * 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.
 +/*
 + * EAP peer: Method registration
 + * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
 + *
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_METHODS_H
 +#define EAP_METHODS_H
 +
 +#include "eap_common/eap_defs.h"
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method);
 +const struct eap_method * eap_peer_get_methods(size_t *count);
 +
 +struct eap_method * eap_peer_method_alloc(int version, int vendor,
 +                                        EapType method, const char *name);
 +void eap_peer_method_free(struct eap_method *method);
 +int eap_peer_method_register(struct eap_method *method);
 +
 +
 +#ifdef IEEE8021X_EAPOL
 +
 +EapType eap_peer_get_type(const char *name, int *vendor);
 +const char * eap_get_name(int vendor, EapType type);
 +size_t eap_get_names(char *buf, size_t buflen);
 +char ** eap_get_names_as_string_array(size_t *num);
 +void eap_peer_unregister_methods(void);
 +
 +#else /* IEEE8021X_EAPOL */
 +
 +static inline EapType eap_peer_get_type(const char *name, int *vendor)
 +{
 +      *vendor = EAP_VENDOR_IETF;
 +      return EAP_TYPE_NONE;
 +}
 +
 +static inline const char * eap_get_name(int vendor, EapType type)
 +{
 +      return NULL;
 +}
 +
 +static inline size_t eap_get_names(char *buf, size_t buflen)
 +{
 +      return 0;
 +}
 +
 +static inline int eap_peer_register_methods(void)
 +{
 +      return 0;
 +}
 +
 +static inline void eap_peer_unregister_methods(void)
 +{
 +}
 +
 +static inline char ** eap_get_names_as_string_array(size_t *num)
 +{
 +      return NULL;
 +}
 +
 +#endif /* IEEE8021X_EAPOL */
 +
 +
 +#ifdef CONFIG_DYNAMIC_EAP_METHODS
 +
 +int eap_peer_method_load(const char *so);
 +int eap_peer_method_unload(struct eap_method *method);
 +
 +#else /* CONFIG_DYNAMIC_EAP_METHODS */
 +
 +static inline int eap_peer_method_load(const char *so UNUSED)
 +{
 +      return 0;
 +}
 +
 +static inline int eap_peer_method_unload(struct eap_method *method UNUSED)
 +{
 +      return 0;
 +}
 +
 +#endif /* CONFIG_DYNAMIC_EAP_METHODS */
 +
 +/* EAP peer method registration calls for statically linked in methods */
 +int eap_peer_md5_register(void);
 +int eap_peer_tls_register(void);
++int eap_peer_unauth_tls_register(void);
++int eap_peer_wfa_unauth_tls_register(void);
 +int eap_peer_mschapv2_register(void);
 +int eap_peer_peap_register(void);
 +int eap_peer_ttls_register(void);
 +int eap_peer_gtc_register(void);
 +int eap_peer_otp_register(void);
 +int eap_peer_sim_register(void);
 +int eap_peer_leap_register(void);
 +int eap_peer_psk_register(void);
 +int eap_peer_aka_register(void);
 +int eap_peer_aka_prime_register(void);
 +int eap_peer_fast_register(void);
 +int eap_peer_pax_register(void);
 +int eap_peer_sake_register(void);
 +int eap_peer_gpsk_register(void);
 +int eap_peer_wsc_register(void);
 +int eap_peer_ikev2_register(void);
 +int eap_peer_vendor_test_register(void);
 +int eap_peer_tnc_register(void);
 +int eap_peer_pwd_register(void);
++int eap_peer_eke_register(void);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_METHODS_H */
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,23cdbe6..23cdbe6
mode 000000,100644..100644
--- /dev/null
index 0000000,d84f012..d84f012
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 8559c4d,0000000..b1f9300
mode 100644,000000..100644
--- /dev/null
@@@ -1,1016 -1,0 +1,1111 @@@
-  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
-  * 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.
++ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
 + *
-       params->tls_ia = data->tls_ia;
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#include "includes.h"
 +
 +#include "common.h"
 +#include "crypto/sha1.h"
 +#include "crypto/tls.h"
 +#include "eap_i.h"
 +#include "eap_tls_common.h"
 +#include "eap_config.h"
 +
 +
++static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
++                                       u8 code, u8 identifier)
++{
++      if (type == EAP_UNAUTH_TLS_TYPE)
++              return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
++                                   EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
++                                   code, identifier);
++      if (type == EAP_WFA_UNAUTH_TLS_TYPE)
++              return eap_msg_alloc(EAP_VENDOR_WFA_NEW,
++                                   EAP_VENDOR_WFA_UNAUTH_TLS, payload_len,
++                                   code, identifier);
++      return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
++                           identifier);
++}
++
++
 +static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
 +                            const u8 **data, size_t *data_len)
 +{
 +      const struct wpa_config_blob *blob;
 +
 +      if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)
 +              return 0;
 +
 +      blob = eap_get_config_blob(sm, *name + 7);
 +      if (blob == NULL) {
 +              wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
 +                         "found", __func__, *name + 7);
 +              return -1;
 +      }
 +
 +      *name = NULL;
 +      *data = blob->data;
 +      *data_len = blob->len;
 +
 +      return 0;
 +}
 +
 +
 +static void eap_tls_params_flags(struct tls_connection_params *params,
 +                               const char *txt)
 +{
 +      if (txt == NULL)
 +              return;
 +      if (os_strstr(txt, "tls_allow_md5=1"))
 +              params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
 +      if (os_strstr(txt, "tls_disable_time_checks=1"))
 +              params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
++      if (os_strstr(txt, "tls_disable_session_ticket=1"))
++              params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
++      if (os_strstr(txt, "tls_disable_session_ticket=0"))
++              params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
++      if (os_strstr(txt, "tls_disable_tlsv1_0=1"))
++              params->flags |= TLS_CONN_DISABLE_TLSv1_0;
++      if (os_strstr(txt, "tls_disable_tlsv1_0=0"))
++              params->flags &= ~TLS_CONN_DISABLE_TLSv1_0;
++      if (os_strstr(txt, "tls_disable_tlsv1_1=1"))
++              params->flags |= TLS_CONN_DISABLE_TLSv1_1;
++      if (os_strstr(txt, "tls_disable_tlsv1_1=0"))
++              params->flags &= ~TLS_CONN_DISABLE_TLSv1_1;
++      if (os_strstr(txt, "tls_disable_tlsv1_2=1"))
++              params->flags |= TLS_CONN_DISABLE_TLSv1_2;
++      if (os_strstr(txt, "tls_disable_tlsv1_2=0"))
++              params->flags &= ~TLS_CONN_DISABLE_TLSv1_2;
 +}
 +
 +
 +static void eap_tls_params_from_conf1(struct tls_connection_params *params,
 +                                    struct eap_peer_config *config)
 +{
 +      params->ca_cert = (char *) config->ca_cert;
 +      params->ca_path = (char *) config->ca_path;
 +      params->client_cert = (char *) config->client_cert;
 +      params->private_key = (char *) config->private_key;
 +      params->private_key_passwd = (char *) config->private_key_passwd;
 +      params->dh_file = (char *) config->dh_file;
 +      params->subject_match = (char *) config->subject_match;
 +      params->altsubject_match = (char *) config->altsubject_match;
++      params->suffix_match = config->domain_suffix_match;
++      params->domain_match = config->domain_match;
 +      params->engine = config->engine;
 +      params->engine_id = config->engine_id;
 +      params->pin = config->pin;
 +      params->key_id = config->key_id;
 +      params->cert_id = config->cert_id;
 +      params->ca_cert_id = config->ca_cert_id;
 +      eap_tls_params_flags(params, config->phase1);
 +}
 +
 +
 +static void eap_tls_params_from_conf2(struct tls_connection_params *params,
 +                                    struct eap_peer_config *config)
 +{
 +      params->ca_cert = (char *) config->ca_cert2;
 +      params->ca_path = (char *) config->ca_path2;
 +      params->client_cert = (char *) config->client_cert2;
 +      params->private_key = (char *) config->private_key2;
 +      params->private_key_passwd = (char *) config->private_key2_passwd;
 +      params->dh_file = (char *) config->dh_file2;
 +      params->subject_match = (char *) config->subject_match2;
 +      params->altsubject_match = (char *) config->altsubject_match2;
++      params->suffix_match = config->domain_suffix_match2;
++      params->domain_match = config->domain_match2;
 +      params->engine = config->engine2;
 +      params->engine_id = config->engine2_id;
 +      params->pin = config->pin2;
 +      params->key_id = config->key2_id;
 +      params->cert_id = config->cert2_id;
 +      params->ca_cert_id = config->ca_cert2_id;
 +      eap_tls_params_flags(params, config->phase2);
 +}
 +
 +
 +static int eap_tls_params_from_conf(struct eap_sm *sm,
 +                                  struct eap_ssl_data *data,
 +                                  struct tls_connection_params *params,
 +                                  struct eap_peer_config *config, int phase2)
 +{
 +      os_memset(params, 0, sizeof(*params));
++      if (sm->workaround && data->eap_type != EAP_TYPE_FAST) {
++              /*
++               * Some deployed authentication servers seem to be unable to
++               * handle the TLS Session Ticket extension (they are supposed
++               * to ignore unrecognized TLS extensions, but end up rejecting
++               * the ClientHello instead). As a workaround, disable use of
++               * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and
++               * EAP-TTLS (EAP-FAST uses session ticket, so any server that
++               * supports EAP-FAST does not need this workaround).
++               */
++              params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
++      }
 +      if (phase2) {
 +              wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
 +              eap_tls_params_from_conf2(params, config);
 +      } else {
 +              wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
 +              eap_tls_params_from_conf1(params, config);
++              if (data->eap_type == EAP_TYPE_FAST)
++                      params->flags |= TLS_CONN_EAP_FAST;
 +      }
-       data->conn = tls_connection_init(sm->ssl_ctx);
 +
 +      /*
 +       * Use blob data, if available. Otherwise, leave reference to external
 +       * file as-is.
 +       */
 +      if (eap_tls_check_blob(sm, &params->ca_cert, &params->ca_cert_blob,
 +                             &params->ca_cert_blob_len) ||
 +          eap_tls_check_blob(sm, &params->client_cert,
 +                             &params->client_cert_blob,
 +                             &params->client_cert_blob_len) ||
 +          eap_tls_check_blob(sm, &params->private_key,
 +                             &params->private_key_blob,
 +                             &params->private_key_blob_len) ||
 +          eap_tls_check_blob(sm, &params->dh_file, &params->dh_blob,
 +                             &params->dh_blob_len)) {
 +              wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
 +              return -1;
 +      }
 +
++      params->openssl_ciphers = config->openssl_ciphers;
++
 +      return 0;
 +}
 +
 +
 +static int eap_tls_init_connection(struct eap_sm *sm,
 +                                 struct eap_ssl_data *data,
 +                                 struct eap_peer_config *config,
 +                                 struct tls_connection_params *params)
 +{
 +      int res;
 +
-       res = tls_connection_set_params(sm->ssl_ctx, data->conn, params);
-       if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
++      if (config->ocsp)
++              params->flags |= TLS_CONN_REQUEST_OCSP;
++      if (config->ocsp == 2)
++              params->flags |= TLS_CONN_REQUIRE_OCSP;
++      data->conn = tls_connection_init(data->ssl_ctx);
 +      if (data->conn == NULL) {
 +              wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
 +                         "connection");
 +              return -1;
 +      }
 +
-                * At this point with the pkcs11 engine the PIN might be wrong.
-                * We reset the PIN in the configuration to be sure to not use
-                * it again and the calling function must request a new one.
++      res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
++      if (res == TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN) {
 +              /*
-               /*
-                * We do not know exactly but maybe the PIN was wrong,
-                * so ask for a new one.
-                */
-               os_free(config->pin);
-               config->pin = NULL;
-               eap_sm_request_pin(sm);
++               * At this point with the pkcs11 engine the PIN is wrong. We
++               * reset the PIN in the configuration to be sure to not use it
++               * again and the calling function must request a new one.
 +               */
++              wpa_printf(MSG_INFO,
++                         "TLS: Bad PIN provided, requesting a new one");
 +              os_free(config->pin);
 +              config->pin = NULL;
++              eap_sm_request_pin(sm);
++              sm->ignore = TRUE;
++      } else if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
++              wpa_printf(MSG_INFO, "TLS: Failed to initialize engine");
 +      } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to load private key");
-               tls_connection_deinit(sm->ssl_ctx, data->conn);
-               data->conn = NULL;
-               return -1;
-       } else if (res) {
 +              sm->ignore = TRUE;
-               tls_connection_deinit(sm->ssl_ctx, data->conn);
++      }
++      if (res) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
 +                         "parameters");
-                         struct eap_peer_config *config)
++              tls_connection_deinit(data->ssl_ctx, data->conn);
 +              data->conn = NULL;
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_ssl_init - Initialize shared TLS functionality
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @config: Pointer to the network configuration
++ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is used to initialize shared TLS functionality for EAP-TLS,
 + * EAP-PEAP, EAP-TTLS, and EAP-FAST.
 + */
 +int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
-       tls_connection_deinit(sm->ssl_ctx, data->conn);
++                        struct eap_peer_config *config, u8 eap_type)
 +{
 +      struct tls_connection_params params;
 +
 +      if (config == NULL)
 +              return -1;
 +
 +      data->eap = sm;
++      data->eap_type = eap_type;
 +      data->phase2 = sm->init_phase2;
++      data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
++              sm->ssl_ctx;
 +      if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
 +          0)
 +              return -1;
 +
 +      if (eap_tls_init_connection(sm, data, config, &params) < 0)
 +              return -1;
 +
 +      data->tls_out_limit = config->fragment_size;
 +      if (data->phase2) {
 +              /* Limit the fragment size in the inner TLS authentication
 +               * since the outer authentication with EAP-PEAP does not yet
 +               * support fragmentation */
 +              if (data->tls_out_limit > 100)
 +                      data->tls_out_limit -= 100;
 +      }
 +
 +      if (config->phase1 &&
 +          os_strstr(config->phase1, "include_tls_length=1")) {
 +              wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
 +                         "unfragmented packets");
 +              data->include_tls_length = 1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + *
 + * This function deinitializes shared TLS functionality that was initialized
 + * with eap_peer_tls_ssl_init().
 + */
 +void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
 +{
-       struct tls_keys keys;
-       u8 *rnd = NULL, *out;
++      tls_connection_deinit(data->ssl_ctx, data->conn);
 +      eap_peer_tls_reset_input(data);
 +      eap_peer_tls_reset_output(data);
 +}
 +
 +
 +/**
 + * eap_peer_tls_derive_key - Derive a key based on TLS session data
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @label: Label string for deriving the keys, e.g., "client EAP encryption"
 + * @len: Length of the key material to generate (usually 64 for MSK)
 + * Returns: Pointer to allocated key on success or %NULL on failure
 + *
 + * This function uses TLS-PRF to generate pseudo-random data based on the TLS
 + * session data (client/server random and master key). Each key type may use a
 + * different label to bind the key usage into the generated material.
 + *
 + * The caller is responsible for freeing the returned buffer.
 + */
 +u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
 +                           const char *label, size_t len)
 +{
-       /* First, try to use TLS library function for PRF, if available. */
-       if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
-           0)
-               return out;
++      u8 *out;
 +
 +      out = os_malloc(len);
 +      if (out == NULL)
 +              return NULL;
 +
-       /*
-        * TLS library did not support key generation, so get the needed TLS
-        * session parameters and use an internal implementation of TLS PRF to
-        * derive the key.
-        */
-       if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
-               goto fail;
-       if (keys.client_random == NULL || keys.server_random == NULL ||
-           keys.master_key == NULL)
-               goto fail;
-       rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-       if (rnd == NULL)
-               goto fail;
-       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_connection_prf(data->ssl_ctx, data->conn, label, 0, 0,
++                             out, len)) {
++              os_free(out);
++              return NULL;
++      }
 +
-       if (tls_prf(keys.master_key, keys.master_key_len,
-                   label, rnd, keys.client_random_len +
-                   keys.server_random_len, out, len))
-               goto fail;
++      return out;
++}
 +
-       os_free(rnd);
-       return out;
 +
- fail:
-       os_free(out);
-       os_free(rnd);
-       return NULL;
++/**
++ * eap_peer_tls_derive_session_id - Derive a Session-Id based on TLS data
++ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
++ * @data: Data for TLS processing
++ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
++ * @len: Pointer to length of the session ID generated
++ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
++ *
++ * This function derive the Session-Id based on the TLS session data
++ * (client/server random and method type).
++ *
++ * The caller is responsible for freeing the returned buffer.
++ */
++u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
++                                  struct eap_ssl_data *data, u8 eap_type,
++                                  size_t *len)
++{
++      struct tls_random keys;
++      u8 *out;
++
++      if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
++              return NULL;
++
++      if (keys.client_random == NULL || keys.server_random == NULL)
++              return NULL;
++
++      *len = 1 + keys.client_random_len + keys.server_random_len;
++      out = os_malloc(*len);
++      if (out == NULL)
++              return NULL;
++
++      /* Session-Id = EAP type || client.random || server.random */
++      out[0] = eap_type;
++      os_memcpy(out + 1, keys.client_random, keys.client_random_len);
++      os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
++                keys.server_random_len);
 +
-       wpabuf_put_buf(data->tls_in, in_data);
++      return out;
 +}
 +
 +
 +/**
 + * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
 + * @data: Data for TLS processing
 + * @in_data: Next incoming TLS segment
 + * Returns: 0 on success, 1 if more data is needed for the full message, or
 + * -1 on error
 + */
 +static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,
 +                                          const struct wpabuf *in_data)
 +{
 +      size_t tls_in_len, in_len;
 +
 +      tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0;
 +      in_len = in_data ? wpabuf_len(in_data) : 0;
 +
 +      if (tls_in_len + in_len == 0) {
 +              /* No message data received?! */
 +              wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: "
 +                         "tls_in_left=%lu tls_in_len=%lu in_len=%lu",
 +                         (unsigned long) data->tls_in_left,
 +                         (unsigned long) tls_in_len,
 +                         (unsigned long) in_len);
 +              eap_peer_tls_reset_input(data);
 +              return -1;
 +      }
 +
 +      if (tls_in_len + in_len > 65536) {
 +              /*
 +               * Limit length to avoid rogue servers from causing large
 +               * memory allocations.
 +               */
 +              wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over "
 +                         "64 kB)");
 +              eap_peer_tls_reset_input(data);
 +              return -1;
 +      }
 +
 +      if (in_len > data->tls_in_left) {
 +              /* Sender is doing something odd - reject message */
 +              wpa_printf(MSG_INFO, "SSL: more data than TLS message length "
 +                         "indicated");
 +              eap_peer_tls_reset_input(data);
 +              return -1;
 +      }
 +
 +      if (wpabuf_resize(&data->tls_in, in_len) < 0) {
 +              wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS "
 +                         "data");
 +              eap_peer_tls_reset_input(data);
 +              return -1;
 +      }
-  * @in_len: Length of in_data
++      if (in_data)
++              wpabuf_put_buf(data->tls_in, in_data);
 +      data->tls_in_left -= in_len;
 +
 +      if (data->tls_in_left > 0) {
 +              wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
 +                         "data", (unsigned long) data->tls_in_left);
 +              return 1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_data_reassemble - Reassemble TLS data
 + * @data: Data for TLS processing
 + * @in_data: Next incoming TLS segment
 + * @need_more_input: Variable for returning whether more input data is needed
 + * to reassemble this TLS packet
 + * Returns: Pointer to output data, %NULL on error or when more data is needed
 + * for the full message (in which case, *need_more_input is also set to 1).
 + *
 + * This function reassembles TLS fragments. Caller must not free the returned
 + * data buffer since an internal pointer to it is maintained.
 + */
 +static const struct wpabuf * eap_peer_tls_data_reassemble(
 +      struct eap_ssl_data *data, const struct wpabuf *in_data,
 +      int *need_more_input)
 +{
 +      *need_more_input = 0;
 +
 +      if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) {
 +              /* Message has fragments */
 +              int res = eap_peer_tls_reassemble_fragment(data, in_data);
 +              if (res) {
 +                      if (res == 1)
 +                              *need_more_input = 1;
 +                      return NULL;
 +              }
 +
 +              /* Message is now fully reassembled. */
 +      } else {
 +              /* No fragments in this message, so just make a copy of it. */
 +              data->tls_in_left = 0;
 +              data->tls_in = wpabuf_dup(in_data);
 +              if (data->tls_in == NULL)
 +                      return NULL;
 +      }
 +
 +      return data->tls_in;
 +}
 +
 +
 +/**
 + * eap_tls_process_input - Process incoming TLS message
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @in_data: Message received from the server
-                                const u8 *in_data, size_t in_len,
 + * @out_data: Buffer for returning a pointer to application data (if available)
 + * Returns: 0 on success, 1 if more input data is needed, 2 if application data
 + * is available, -1 on failure
 + */
 +static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
-       struct wpabuf buf;
++                               const struct wpabuf *in_data,
 +                               struct wpabuf **out_data)
 +{
 +      const struct wpabuf *msg;
 +      int need_more_input;
 +      struct wpabuf *appl_data;
-       wpabuf_set(&buf, in_data, in_len);
-       msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input);
 +
-       data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn,
++      msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input);
 +      if (msg == NULL)
 +              return need_more_input ? 1 : -1;
 +
 +      /* Full TLS message reassembled - continue handshake processing */
 +      if (data->tls_out) {
 +              /* This should not happen.. */
 +              wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending "
 +                         "tls_out data even though tls_out_len = 0");
 +              wpabuf_free(data->tls_out);
 +              WPA_ASSERT(data->tls_out == NULL);
 +      }
 +      appl_data = NULL;
-           tls_connection_established(sm->ssl_ctx, data->conn) &&
-           !tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
++      data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
 +                                               msg, &appl_data);
 +
 +      eap_peer_tls_reset_input(data);
 +
 +      if (appl_data &&
-       *out_data = eap_msg_alloc(EAP_VENDOR_IETF, eap_type,
-                                 1 + length_included * 4 + len,
-                                 EAP_CODE_RESPONSE, id);
++          tls_connection_established(data->ssl_ctx, data->conn) &&
++          !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
 +              wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
 +                                  appl_data);
 +              *out_data = appl_data;
 +              return 2;
 +      }
 +
 +      wpabuf_free(appl_data);
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_tls_process_output - Process outgoing TLS message
 + * @data: Data for TLS processing
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @peap_version: Version number for EAP-PEAP/TTLS
 + * @id: EAP identifier for the response
 + * @ret: Return value to use on success
 + * @out_data: Buffer for returning the allocated output buffer
 + * Returns: ret (0 or 1) on success, -1 on failure
 + */
 +static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
 +                                int peap_version, u8 id, int ret,
 +                                struct wpabuf **out_data)
 +{
 +      size_t len;
 +      u8 *flags;
 +      int more_fragments, length_included;
 +
 +      if (data->tls_out == NULL)
 +              return -1;
 +      len = wpabuf_len(data->tls_out) - data->tls_out_pos;
 +      wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
 +                 "%lu bytes)",
 +                 (unsigned long) len,
 +                 (unsigned long) wpabuf_len(data->tls_out));
 +
 +      /*
 +       * Limit outgoing message to the configured maximum size. Fragment
 +       * message if needed.
 +       */
 +      if (len > data->tls_out_limit) {
 +              more_fragments = 1;
 +              len = data->tls_out_limit;
 +              wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
 +                         "will follow", (unsigned long) len);
 +      } else
 +              more_fragments = 0;
 +
 +      length_included = data->tls_out_pos == 0 &&
 +              (wpabuf_len(data->tls_out) > data->tls_out_limit ||
 +               data->include_tls_length);
 +      if (!length_included &&
 +          eap_type == EAP_TYPE_PEAP && peap_version == 0 &&
 +          !tls_connection_established(data->eap->ssl_ctx, data->conn)) {
 +              /*
 +               * Windows Server 2008 NPS really wants to have the TLS Message
 +               * length included in phase 0 even for unfragmented frames or
 +               * it will get very confused with Compound MAC calculation and
 +               * Outer TLVs.
 +               */
 +              length_included = 1;
 +      }
 +
-  * @in_len: Length of in_data
++      *out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len,
++                                    EAP_CODE_RESPONSE, id);
 +      if (*out_data == NULL)
 +              return -1;
 +
 +      flags = wpabuf_put(*out_data, 1);
 +      *flags = peap_version;
 +      if (more_fragments)
 +              *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
 +      if (length_included) {
 +              *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
 +              wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out));
 +      }
 +
 +      wpabuf_put_data(*out_data,
 +                      wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
 +                      len);
 +      data->tls_out_pos += len;
 +
 +      if (!more_fragments)
 +              eap_peer_tls_reset_output(data);
 +
 +      return ret;
 +}
 +
 +
 +/**
 + * eap_peer_tls_process_helper - Process TLS handshake message
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @peap_version: Version number for EAP-PEAP/TTLS
 + * @id: EAP identifier for the response
 + * @in_data: Message received from the server
-                               u8 id, const u8 *in_data, size_t in_len,
 + * @out_data: Buffer for returning a pointer to the response message
 + * Returns: 0 on success, 1 if more input data is needed, 2 if application data
 + * is available, or -1 on failure
 + *
 + * This function can be used to process TLS handshake messages. It reassembles
 + * the received fragments and uses a TLS library to process the messages. The
 + * response data from the TLS library is fragmented to suitable output messages
 + * that the caller can send out.
 + *
 + * out_data is used to return the response message if the return value of this
 + * function is 0, 2, or -1. In case of failure, the message is likely a TLS
 + * alarm message. The caller is responsible for freeing the allocated buffer if
 + * *out_data is not %NULL.
 + *
 + * This function is called for each received TLS message during the TLS
 + * handshake after eap_peer_tls_process_init() call and possible processing of
 + * TLS Flags field. Once the handshake has been completed, i.e., when
 + * tls_connection_established() returns 1, EAP method specific decrypting of
 + * the tunneled data is used.
 + */
 +int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
 +                              EapType eap_type, int peap_version,
-       if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) {
++                              u8 id, const struct wpabuf *in_data,
 +                              struct wpabuf **out_data)
 +{
 +      int ret = 0;
 +
 +      *out_data = NULL;
 +
-               int res = eap_tls_process_input(sm, data, in_data, in_len,
-                                               out_data);
++      if (data->tls_out && wpabuf_len(data->tls_out) > 0 &&
++          wpabuf_len(in_data) > 0) {
 +              wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output "
 +                         "fragments are waiting to be sent out");
 +              return -1;
 +      }
 +
 +      if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
 +              /*
 +               * No more data to send out - expect to receive more data from
 +               * the AS.
 +               */
-       if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
++              int res = eap_tls_process_input(sm, data, in_data, out_data);
 +              if (res) {
 +                      /*
 +                       * Input processing failed (res = -1) or more data is
 +                       * needed (res = 1).
 +                       */
 +                      return res;
 +              }
 +
 +              /*
 +               * The incoming message has been reassembled and processed. The
 +               * response was allocated into data->tls_out buffer.
 +               */
 +      }
 +
 +      if (data->tls_out == NULL) {
 +              /*
 +               * No outgoing fragments remaining from the previous message
 +               * and no new message generated. This indicates an error in TLS
 +               * processing.
 +               */
 +              eap_peer_tls_reset_output(data);
 +              return -1;
 +      }
 +
-                          "report error");
++      if (tls_connection_get_failed(data->ssl_ctx, data->conn)) {
 +              /* TLS processing has failed - return error */
 +              wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
-       if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
++                         "report error (len=%u)",
++                         (unsigned int) wpabuf_len(data->tls_out));
 +              ret = -1;
 +              /* TODO: clean pin if engine used? */
++              if (wpabuf_len(data->tls_out) == 0) {
++                      wpabuf_free(data->tls_out);
++                      data->tls_out = NULL;
++                      return -1;
++              }
 +      }
 +
-       resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_RESPONSE,
-                            id);
++      if (wpabuf_len(data->tls_out) == 0) {
 +              /*
 +               * TLS negotiation should now be complete since all other cases
 +               * needing more data should have been caught above based on
 +               * the TLS Message Length field.
 +               */
 +              wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
 +              wpabuf_free(data->tls_out);
 +              data->tls_out = NULL;
 +              return 1;
 +      }
 +
 +      /* Send the pending message (in fragments, if needed). */
 +      return eap_tls_process_output(data, eap_type, peap_version, id, ret,
 +                                    out_data);
 +}
 +
 +
 +/**
 + * eap_peer_tls_build_ack - Build a TLS ACK frame
 + * @id: EAP identifier for the response
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @peap_version: Version number for EAP-PEAP/TTLS
 + * Returns: Pointer to the allocated ACK frame or %NULL on failure
 + */
 +struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
 +                                     int peap_version)
 +{
 +      struct wpabuf *resp;
 +
-       return tls_connection_shutdown(sm->ssl_ctx, data->conn);
++      resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id);
 +      if (resp == NULL)
 +              return NULL;
 +      wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)",
 +                 (int) eap_type, id, peap_version);
 +      wpabuf_put_u8(resp, peap_version); /* Flags */
 +      return resp;
 +}
 +
 +
 +/**
 + * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * Returns: 0 on success, -1 on failure
 + */
 +int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
 +{
 +      eap_peer_tls_reset_input(data);
 +      eap_peer_tls_reset_output(data);
-       char name[128];
++      return tls_connection_shutdown(data->ssl_ctx, data->conn);
 +}
 +
 +
 +/**
 + * eap_peer_tls_status - Get TLS status
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @buf: Buffer for status information
 + * @buflen: Maximum buffer length
 + * @verbose: Whether to include verbose status information
 + * Returns: Number of bytes written to buf.
 + */
 +int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
 +                      char *buf, size_t buflen, int verbose)
 +{
-       if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
-               ret = os_snprintf(buf + len, buflen - len,
-                                 "EAP TLS cipher=%s\n", name);
-               if (ret < 0 || (size_t) ret >= buflen - len)
-                       return len;
-               len += ret;
-       }
++      char version[20], name[128];
 +      int len = 0, ret;
 +
-       pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, &left);
++      if (tls_get_version(data->ssl_ctx, data->conn, version,
++                          sizeof(version)) < 0)
++              version[0] = '\0';
++      if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) < 0)
++              name[0] = '\0';
++
++      ret = os_snprintf(buf + len, buflen - len,
++                        "eap_tls_version=%s\n"
++                        "EAP TLS cipher=%s\n"
++                        "tls_session_reused=%d\n",
++                        version, name,
++                        tls_connection_resumed(data->ssl_ctx, data->conn));
++      if (os_snprintf_error(buflen - len, ret))
++              return len;
++      len += ret;
 +
 +      return len;
 +}
 +
 +
 +/**
 + * eap_peer_tls_process_init - Initial validation/processing of EAP requests
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @ret: Return values from EAP request validation and processing
 + * @reqData: EAP request to be processed (eapReqData)
 + * @len: Buffer for returning length of the remaining payload
 + * @flags: Buffer for returning TLS flags
 + * Returns: Pointer to payload after TLS flags and length or %NULL on failure
 + *
 + * This function validates the EAP header and processes the optional TLS
 + * Message Length field. If this is the first fragment of a TLS message, the
 + * TLS reassembly code is initialized to receive the indicated number of bytes.
 + *
 + * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this
 + * function as the first step in processing received messages. They will need
 + * to process the flags (apart from Message Length Included) that are returned
 + * through the flags pointer and the message payload that will be returned (and
 + * the length is returned through the len pointer). Return values (ret) are set
 + * for continuation of EAP method processing. The caller is responsible for
 + * setting these to indicate completion (either success or failure) based on
 + * the authentication result.
 + */
 +const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
 +                                   struct eap_ssl_data *data,
 +                                   EapType eap_type,
 +                                   struct eap_method_ret *ret,
 +                                   const struct wpabuf *reqData,
 +                                   size_t *len, u8 *flags)
 +{
 +      const u8 *pos;
 +      size_t left;
 +      unsigned int tls_msg_len;
 +
 +      /* Ignore errors before we do anything*/
 +      (void) tls_get_errors(sm->ssl_ctx);
-       *in_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->conn, msg);
++
++      //// if (tls_get_errors(data->ssl_ctx)) {
++      ////    wpa_printf(MSG_INFO, "SSL: TLS errors detected");
++      ////    ret->ignore = TRUE;
++      ////    return NULL;
++      //// }
++
++      if (eap_type == EAP_UNAUTH_TLS_TYPE)
++              pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
++                                     EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
++                                     &left);
++      else if (eap_type == EAP_WFA_UNAUTH_TLS_TYPE)
++              pos = eap_hdr_validate(EAP_VENDOR_WFA_NEW,
++                                     EAP_VENDOR_WFA_UNAUTH_TLS, reqData,
++                                     &left);
++      else
++              pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
++                                     &left);
 +      if (pos == NULL) {
 +              ret->ignore = TRUE;
 +              return NULL;
 +      }
 +      if (left == 0) {
 +              wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags "
 +                         "octet included");
 +              if (!sm->workaround) {
 +                      ret->ignore = TRUE;
 +                      return NULL;
 +              }
 +
 +              wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags "
 +                         "indicates ACK frame");
 +              *flags = 0;
 +      } else {
 +              *flags = *pos++;
 +              left--;
 +      }
 +      wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
 +                 "Flags 0x%02x", (unsigned long) wpabuf_len(reqData),
 +                 *flags);
 +      if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
 +              if (left < 4) {
 +                      wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
 +                                 "length");
 +                      ret->ignore = TRUE;
 +                      return NULL;
 +              }
 +              tls_msg_len = WPA_GET_BE32(pos);
 +              wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
 +                         tls_msg_len);
 +              if (data->tls_in_left == 0) {
 +                      data->tls_in_total = tls_msg_len;
 +                      data->tls_in_left = tls_msg_len;
 +                      wpabuf_free(data->tls_in);
 +                      data->tls_in = NULL;
 +              }
 +              pos += 4;
 +              left -= 4;
++
++              if (left > tls_msg_len) {
++                      wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
++                                 "bytes) smaller than this fragment (%d "
++                                 "bytes)", (int) tls_msg_len, (int) left);
++                      ret->ignore = TRUE;
++                      return NULL;
++              }
 +      }
 +
 +      ret->ignore = FALSE;
 +      ret->methodState = METHOD_MAY_CONT;
 +      ret->decision = DECISION_FAIL;
 +      ret->allowNotifications = TRUE;
 +
 +      *len = left;
 +      return pos;
 +}
 +
 +
 +/**
 + * eap_peer_tls_reset_input - Reset input buffers
 + * @data: Data for TLS processing
 + *
 + * This function frees any allocated memory for input buffers and resets input
 + * state.
 + */
 +void eap_peer_tls_reset_input(struct eap_ssl_data *data)
 +{
 +      data->tls_in_left = data->tls_in_total = 0;
 +      wpabuf_free(data->tls_in);
 +      data->tls_in = NULL;
 +}
 +
 +
 +/**
 + * eap_peer_tls_reset_output - Reset output buffers
 + * @data: Data for TLS processing
 + *
 + * This function frees any allocated memory for output buffers and resets
 + * output state.
 + */
 +void eap_peer_tls_reset_output(struct eap_ssl_data *data)
 +{
 +      data->tls_out_pos = 0;
 +      wpabuf_free(data->tls_out);
 +      data->tls_out = NULL;
 +}
 +
 +
 +/**
 + * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @in_data: Message received from the server
 + * @in_decrypted: Buffer for returning a pointer to the decrypted message
 + * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
 + */
 +int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
 +                       const struct wpabuf *in_data,
 +                       struct wpabuf **in_decrypted)
 +{
 +      const struct wpabuf *msg;
 +      int need_more_input;
 +
 +      msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input);
 +      if (msg == NULL)
 +              return need_more_input ? 1 : -1;
 +
-               data->tls_out = tls_connection_encrypt(sm->ssl_ctx, data->conn,
-                                                      in_data);
++      *in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg);
 +      eap_peer_tls_reset_input(data);
 +      if (*in_decrypted == NULL) {
 +              wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
 +              return -1;
 +      }
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_encrypt - Encrypt phase 2 TLS message
 + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
 + * @data: Data for TLS processing
 + * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
 + * @peap_version: Version number for EAP-PEAP/TTLS
 + * @id: EAP identifier for the response
 + * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments
 + * @out_data: Buffer for returning a pointer to the encrypted response message
 + * Returns: 0 on success, -1 on failure
 + */
 +int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
 +                       EapType eap_type, int peap_version, u8 id,
 +                       const struct wpabuf *in_data,
 +                       struct wpabuf **out_data)
 +{
 +      if (in_data) {
 +              eap_peer_tls_reset_output(data);
-       u8 method;
++              data->tls_out = tls_connection_encrypt(data->ssl_ctx,
++                                                     data->conn, in_data);
 +              if (data->tls_out == NULL) {
 +                      wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 "
 +                                 "data (in_len=%lu)",
 +                                 (unsigned long) wpabuf_len(in_data));
 +                      eap_peer_tls_reset_output(data);
 +                      return -1;
 +              }
 +      }
 +
 +      return eap_tls_process_output(data, eap_type, peap_version, id, 0,
 +                                    out_data);
 +}
 +
 +
 +/**
 + * eap_peer_select_phase2_methods - Select phase 2 EAP method
 + * @config: Pointer to the network configuration
 + * @prefix: 'phase2' configuration prefix, e.g., "auth="
 + * @types: Buffer for returning allocated list of allowed EAP methods
 + * @num_types: Buffer for returning number of allocated EAP methods
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is used to parse EAP method list and select allowed methods
 + * for Phase2 authentication.
 + */
 +int eap_peer_select_phase2_methods(struct eap_peer_config *config,
 +                                 const char *prefix,
 +                                 struct eap_method_type **types,
 +                                 size_t *num_types)
 +{
 +      char *start, *pos, *buf;
 +      struct eap_method_type *methods = NULL, *_methods;
-                       _methods = os_realloc(methods,
-                                             num_methods * sizeof(*methods));
++      u32 method;
 +      size_t num_methods = 0, prefix_len;
 +
 +      if (config == NULL || config->phase2 == NULL)
 +              goto get_defaults;
 +
 +      start = buf = os_strdup(config->phase2);
 +      if (buf == NULL)
 +              return -1;
 +
 +      prefix_len = os_strlen(prefix);
 +
 +      while (start && *start != '\0') {
 +              int vendor;
 +              pos = os_strstr(start, prefix);
 +              if (pos == NULL)
 +                      break;
 +              if (start != pos && *(pos - 1) != ' ') {
 +                      start = pos + prefix_len;
 +                      continue;
 +              }
 +
 +              start = pos + prefix_len;
 +              pos = os_strchr(start, ' ');
 +              if (pos)
 +                      *pos++ = '\0';
 +              method = eap_get_phase2_type(start, &vendor);
 +              if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) {
 +                      wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP "
 +                                 "method '%s'", start);
 +              } else {
 +                      num_methods++;
++                      _methods = os_realloc_array(methods, num_methods,
++                                                  sizeof(*methods));
 +                      if (_methods == NULL) {
 +                              os_free(methods);
 +                              os_free(buf);
 +                              return -1;
 +                      }
 +                      methods = _methods;
 +                      methods[num_methods - 1].vendor = vendor;
 +                      methods[num_methods - 1].method = method;
 +              }
 +
 +              start = pos;
 +      }
 +
 +      os_free(buf);
 +
 +get_defaults:
 +      if (methods == NULL)
 +              methods = eap_get_phase2_types(config, &num_methods);
 +
 +      if (methods == NULL) {
 +              wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available");
 +              return -1;
 +      }
 +      wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types",
 +                  (u8 *) methods,
 +                  num_methods * sizeof(struct eap_method_type));
 +
 +      *types = methods;
 +      *num_types = num_methods;
 +
 +      return 0;
 +}
 +
 +
 +/**
 + * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2
 + * @types: Buffer for returning allocated list of allowed EAP methods
 + * @num_types: Buffer for returning number of allocated EAP methods
 + * @hdr: EAP-Request header (and the following EAP type octet)
 + * @resp: Buffer for returning the EAP-Nak message
 + * Returns: 0 on success, -1 on failure
 + */
 +int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
 +                          struct eap_hdr *hdr, struct wpabuf **resp)
 +{
 +      u8 *pos = (u8 *) (hdr + 1);
 +      size_t i;
 +
 +      /* TODO: add support for expanded Nak */
 +      wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos);
 +      wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types",
 +                  (u8 *) types, num_types * sizeof(struct eap_method_type));
 +      *resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types,
 +                            EAP_CODE_RESPONSE, hdr->identifier);
 +      if (*resp == NULL)
 +              return -1;
 +
 +      for (i = 0; i < num_types; i++) {
 +              if (types[i].vendor == EAP_VENDOR_IETF &&
 +                  types[i].method < 256)
 +                      wpabuf_put_u8(*resp, types[i].method);
 +      }
 +
 +      eap_update_len(*resp);
 +
 +      return 0;
 +}
index 53ed1a9,0000000..3f7f003
mode 100644,000000..100644
--- /dev/null
@@@ -1,134 -1,0 +1,140 @@@
-  * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
-  * 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.
++ * Copyright (c) 2004-2009, 2012, Jouni Malinen <j@w1.fi>
 + *
-        * tls_ia - Whether TLS/IA is enabled for this TLS connection
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef EAP_TLS_COMMON_H
 +#define EAP_TLS_COMMON_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/**
 + * struct eap_ssl_data - TLS data for EAP methods
 + */
 +struct eap_ssl_data {
 +      /**
 +       * conn - TLS connection context data from tls_connection_init()
 +       */
 +      struct tls_connection *conn;
 +
 +      /**
 +       * tls_out - TLS message to be sent out in fragments
 +       */
 +      struct wpabuf *tls_out;
 +
 +      /**
 +       * tls_out_pos - The current position in the outgoing TLS message
 +       */
 +      size_t tls_out_pos;
 +
 +      /**
 +       * tls_out_limit - Maximum fragment size for outgoing TLS messages
 +       */
 +      size_t tls_out_limit;
 +
 +      /**
 +       * tls_in - Received TLS message buffer for re-assembly
 +       */
 +      struct wpabuf *tls_in;
 +
 +      /**
 +       * tls_in_left - Number of remaining bytes in the incoming TLS message
 +       */
 +      size_t tls_in_left;
 +
 +      /**
 +       * tls_in_total - Total number of bytes in the incoming TLS message
 +       */
 +      size_t tls_in_total;
 +
 +      /**
 +       * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel)
 +       */
 +      int phase2;
 +
 +      /**
 +       * include_tls_length - Whether the TLS length field is included even
 +       * if the TLS data is not fragmented
 +       */
 +      int include_tls_length;
 +
 +      /**
-       int tls_ia;
++       * eap - EAP state machine allocated with eap_peer_sm_init()
 +       */
-        * eap - EAP state machine allocated with eap_peer_sm_init()
++      struct eap_sm *eap;
 +
 +      /**
-       struct eap_sm *eap;
++       * ssl_ctx - TLS library context to use for the connection
 +       */
-                         struct eap_peer_config *config);
++      void *ssl_ctx;
++
++      /**
++       * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
++       */
++      u8 eap_type;
 +};
 +
 +
 +/* EAP TLS Flags */
 +#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
 +#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
 +#define EAP_TLS_FLAGS_START 0x20
 +#define EAP_TLS_VERSION_MASK 0x07
 +
 + /* could be up to 128 bytes, but only the first 64 bytes are used */
 +#define EAP_TLS_KEY_LEN 64
 +
++/* dummy type used as a flag for UNAUTH-TLS */
++#define EAP_UNAUTH_TLS_TYPE 255
++#define EAP_WFA_UNAUTH_TLS_TYPE 254
++
 +
 +int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
-                               u8 id, const u8 *in_data, size_t in_len,
++                        struct eap_peer_config *config, u8 eap_type);
 +void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
 +u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
 +                           const char *label, size_t len);
++u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm,
++                                  struct eap_ssl_data *data, u8 eap_type,
++                                  size_t *len);
 +int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
 +                              EapType eap_type, int peap_version,
++                              u8 id, const struct wpabuf *in_data,
 +                              struct wpabuf **out_data);
 +struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
 +                                     int peap_version);
 +int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
 +int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
 +                      char *buf, size_t buflen, int verbose);
 +const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
 +                                   struct eap_ssl_data *data,
 +                                   EapType eap_type,
 +                                   struct eap_method_ret *ret,
 +                                   const struct wpabuf *reqData,
 +                                   size_t *len, u8 *flags);
 +void eap_peer_tls_reset_input(struct eap_ssl_data *data);
 +void eap_peer_tls_reset_output(struct eap_ssl_data *data);
 +int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
 +                       const struct wpabuf *in_data,
 +                       struct wpabuf **in_decrypted);
 +int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
 +                       EapType eap_type, int peap_version, u8 id,
 +                       const struct wpabuf *in_data,
 +                       struct wpabuf **out_data);
 +int eap_peer_select_phase2_methods(struct eap_peer_config *config,
 +                                 const char *prefix,
 +                                 struct eap_method_type **types,
 +                                 size_t *num_types);
 +int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
 +                          struct eap_hdr *hdr, struct wpabuf **resp);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* EAP_TLS_COMMON_H */
Simple merge
index 37e6bf3,0000000..c174fe5
mode 100644,000000..100644
--- /dev/null
@@@ -1,2221 -1,0 +1,1956 @@@
-  * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP peer method: EAP-TTLS (RFC 5281)
-  * 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.
++ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
 + *
- /* 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
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#include "includes.h"
 +
 +#include "common.h"
 +#include "radius/radius.h"
 +#include "crypto/ms_funcs.h"
 +#include "crypto/sha1.h"
 +#include "crypto/tls.h"
 +#include "eap_common/chap.h"
 +#include "eap_common/eap_ttls.h"
 +#include "mschapv2.h"
 +#include "eap_i.h"
 +#include "eap_tls_common.h"
 +#include "eap_config.h"
 +
 +
-       int ssl_initialized;
++#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 ttls_version, force_ttls_version;
 +
-       data->force_ttls_version = -1;
++      int ttls_version;
 +
 +      const struct eap_method *phase2_method;
 +      void *phase2_priv;
 +      int phase2_success;
 +      int phase2_start;
 +
 +      enum phase2_types {
 +              EAP_TTLS_PHASE2_EAP,
 +              EAP_TTLS_PHASE2_MSCHAPV2,
 +              EAP_TTLS_PHASE2_MSCHAP,
 +              EAP_TTLS_PHASE2_PAP,
 +              EAP_TTLS_PHASE2_CHAP
 +      } phase2_type;
 +      struct eap_method_type phase2_eap_type;
 +      struct eap_method_type *phase2_eap_types;
 +      size_t num_phase2_eap_types;
 +
 +      u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
 +      int auth_response_valid;
 +      u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */
 +      u8 ident;
 +      int resuming; /* starting a resumed session */
 +      int reauth; /* reauthentication */
 +      u8 *key_data;
++      u8 *session_id;
++      size_t id_len;
 +
 +      struct wpabuf *pending_phase2_req;
 +      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;
 +#ifdef EAP_TNC
 +      int ready_for_tnc;
 +      int tnc_started;
 +#endif /* EAP_TNC */
 +};
 +
 +
 +/* draft-ietf-emu-chbind-13 section 5.3 */
 +
 +#ifdef _MSC_VER
 +#pragma pack(push, 1)
 +#endif /* _MSC_VER */
 +
 +struct chbind_hdr {
 +      u16 len;
 +      u8 nsid;
 +} STRUCT_PACKED;
 +
 +#ifdef _MSC_VER
 +#pragma pack(pop)
 +#endif /* _MSC_VER */
 +
 +
 +
 +static void * eap_ttls_init(struct eap_sm *sm)
 +{
 +      struct eap_ttls_data *data;
 +      struct eap_peer_config *config = eap_get_config(sm);
 +      char *selected;
 +
 +      data = os_zalloc(sizeof(*data));
 +      if (data == NULL)
 +              return NULL;
 +      data->ttls_version = EAP_TTLS_VERSION;
- #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);
-               }
-       }
- #endif /* EAP_TTLS_VERSION */
 +      selected = "EAP";
 +      data->phase2_type = EAP_TTLS_PHASE2_EAP;
 +
- #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 (config && config->phase2) {
 +              if (os_strstr(config->phase2, "autheap=")) {
 +                      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) {
 +              if (eap_peer_select_phase2_methods(config, "autheap=",
 +                                                 &data->phase2_eap_types,
 +                                                 &data->num_phase2_eap_types)
 +                  < 0) {
 +                      eap_ttls_deinit(sm, data);
 +                      return NULL;
 +              }
 +
 +              data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
 +              data->phase2_eap_type.method = EAP_TYPE_NONE;
 +      }
 +
- #endif /* EAP_TTLS_VERSION */
++      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;
 +      }
-       if (data->ssl_initialized)
-               eap_peer_tls_ssl_deinit(sm, &data->ssl);
-       os_free(data->key_data);
 +
 +      return data;
 +}
 +
 +
 +static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data)
 +{
 +      if (data->phase2_priv && data->phase2_method) {
 +              data->phase2_method->deinit(sm, data->phase2_priv);
 +              data->phase2_method = NULL;
 +              data->phase2_priv = NULL;
 +      }
 +}
 +
 +
++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;
 +      if (data == NULL)
 +              return;
 +      eap_ttls_phase2_eap_deinit(sm, data);
 +      os_free(data->phase2_eap_types);
-       avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
++      eap_peer_tls_ssl_deinit(sm, &data->ssl);
++      eap_ttls_free_key(data);
++      os_free(data->session_id);
 +      wpabuf_free(data->pending_phase2_req);
 +      os_free(data);
 +}
 +
 +
 +static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
 +                           int mandatory, size_t len)
 +{
 +      struct ttls_avp_vendor *avp;
 +      u8 flags;
 +      size_t hdrlen;
 +
 +      avp = (struct ttls_avp_vendor *) avphdr;
 +      flags = mandatory ? AVP_FLAGS_MANDATORY : 0;
 +      if (vendor_id) {
 +              flags |= AVP_FLAGS_VENDOR;
 +              hdrlen = sizeof(*avp);
 +              avp->vendor_id = host_to_be32(vendor_id);
 +      } else {
 +              hdrlen = sizeof(struct ttls_avp);
 +      }
 +
 +      avp->avp_code = host_to_be32(avp_code);
- #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 */
++      avp->avp_length = host_to_be32(((u32) flags << 24) |
++                                     (u32) (hdrlen + len));
 +
 +      return avphdr + hdrlen;
 +}
 +
 +
 +static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
 +                           u32 vendor_id, int mandatory,
 +                           const u8 *data, size_t len)
 +{
 +      u8 *pos;
 +      pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len);
 +      os_memcpy(pos, data, len);
 +      pos += len;
 +      AVP_PAD(start, pos);
 +      return pos;
 +}
 +
 +
 +static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
 +                                  int mandatory)
 +{
 +      struct wpabuf *msg;
 +      u8 *avp, *pos;
 +
 +      msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4);
 +      if (msg == NULL) {
 +              wpabuf_free(*resp);
 +              *resp = NULL;
 +              return -1;
 +      }
 +
 +      avp = wpabuf_mhead(msg);
 +      pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp));
 +      os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp));
 +      pos += wpabuf_len(*resp);
 +      AVP_PAD(avp, pos);
 +      wpabuf_free(*resp);
 +      wpabuf_put(msg, pos - avp);
 +      *resp = msg;
 +      return 0;
 +}
 +
 +/* chop up resp into multiple vsa's as necessary*/
 +static int eap_ttls_avp_radius_vsa_encapsulate(struct wpabuf **resp, u32 vendor,
 +                                      u8 attr, int mandatory)
 +{
 +      struct wpabuf *msg;
 +      u8 *avp, *pos, *src, *final;
 +      size_t size = wpabuf_len(*resp);
 +      size_t num_msgs = 1 + (size / 248);
 +      size_t msg_wrapper_size = sizeof(struct ttls_avp_vendor) + 6;
 +      size_t allocated_total = num_msgs * (4 + msg_wrapper_size) + size;
 +
 +      msg = wpabuf_alloc(allocated_total);
 +      if (msg == NULL) {
 +              wpabuf_free(*resp);
 +              *resp = NULL;
 +              return -1;
 +      }
 +      src = wpabuf_mhead(*resp);
 +      avp = wpabuf_mhead(msg);
 +      while (size > 0) {
 +              int avp_size = size > 248 ? 248 : size;
 +              size -= avp_size;
 +              pos = eap_ttls_avp_hdr(avp, RADIUS_ATTR_VENDOR_SPECIFIC, 0, mandatory,
 +                                     avp_size+6);
 +              wpabuf_put(msg, pos-avp);
 +              wpabuf_put_be32(msg, vendor);
 +              wpabuf_put_u8(msg, (u8) attr);
 +              wpabuf_put_u8(msg, (u8) avp_size+2);
 +              wpabuf_put_data(msg, src, avp_size);
 +              src += avp_size;
 +              pos = wpabuf_mhead_u8(msg) + wpabuf_len(msg);
 +              final = pos; /*keep pos so we know how much padding is added*/
 +              AVP_PAD(avp, final); /*final modified*/
 +              if (final > pos)
 +                      wpabuf_put(msg, final-pos);
 +              avp = final;
 +      }
 +      /* check avp-wpabuf_mhead(msg) < allocated_total */
 +      wpabuf_free(*resp);
 +      *resp = msg;
 +      return 0;
 +}
 +
-       os_free(data->key_data);
 +static int eap_ttls_v0_derive_key(struct eap_sm *sm,
 +                                struct eap_ttls_data *data)
 +{
-                                                EAP_TLS_KEY_LEN);
++      eap_ttls_free_key(data);
 +      data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
 +                                               "ttls keying material",
-       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;
++                                               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);
-       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);
++      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");
 +      }
 +
- #endif /* EAP_TTLS_VERSION */
 +      return 0;
 +}
- #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 */
 +
 +
++#ifndef CONFIG_FIPS
 +static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
 +                                      struct eap_ttls_data *data, size_t len)
 +{
-       eap_ttlsv1_phase2_eap_finish(sm, data, ret);
++      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,
 +                                            u8 method)
 +{
 +      size_t i;
 +      for (i = 0; i < data->num_phase2_eap_types; i++) {
 +              if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF ||
 +                  data->phase2_eap_types[i].method != method)
 +                      continue;
 +
 +              data->phase2_eap_type.vendor =
 +                      data->phase2_eap_types[i].vendor;
 +              data->phase2_eap_type.method =
 +                      data->phase2_eap_types[i].method;
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
 +                         "Phase 2 EAP vendor %d method %d",
 +                         data->phase2_eap_type.vendor,
 +                         data->phase2_eap_type.method);
 +              break;
 +      }
 +}
 +
 +
 +static int eap_ttls_phase2_eap_process(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret,
 +                                     struct eap_hdr *hdr, size_t len,
 +                                     struct wpabuf **resp)
 +{
 +      struct wpabuf msg;
 +      struct eap_method_ret iret;
 +
 +      os_memset(&iret, 0, sizeof(iret));
 +      wpabuf_set(&msg, hdr, len);
 +      *resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
 +                                           &msg);
 +      if ((iret.methodState == METHOD_DONE ||
 +           iret.methodState == METHOD_MAY_CONT) &&
 +          (iret.decision == DECISION_UNCOND_SUCC ||
 +           iret.decision == DECISION_COND_SUCC ||
 +           iret.decision == DECISION_FAIL)) {
 +              ret->methodState = iret.methodState;
 +              ret->decision = iret.decision;
 +      }
- 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 */
- }
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
 +                                            struct eap_ttls_data *data,
 +                                            struct eap_method_ret *ret,
 +                                            struct eap_hdr *hdr, size_t len,
 +                                            u8 method, struct wpabuf **resp)
 +{
 +#ifdef EAP_TNC
 +      if (data->tnc_started && data->phase2_method &&
 +          data->phase2_priv && method == EAP_TYPE_TNC &&
 +          data->phase2_eap_type.method == EAP_TYPE_TNC)
 +              return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
 +                                                 resp);
 +
 +      if (data->ready_for_tnc && !data->tnc_started &&
 +          method == EAP_TYPE_TNC) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
 +                         "EAP method");
 +              data->tnc_started = 1;
 +      }
 +
 +      if (data->tnc_started) {
 +              if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF ||
 +                  data->phase2_eap_type.method == EAP_TYPE_TNC) {
 +                      wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP "
 +                                 "type %d for TNC", method);
 +                      return -1;
 +              }
 +
 +              data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
 +              data->phase2_eap_type.method = method;
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
 +                         "Phase 2 EAP vendor %d method %d (TNC)",
 +                         data->phase2_eap_type.vendor,
 +                         data->phase2_eap_type.method);
 +
 +              if (data->phase2_type == EAP_TTLS_PHASE2_EAP)
 +                      eap_ttls_phase2_eap_deinit(sm, data);
 +      }
 +#endif /* EAP_TNC */
 +
 +      if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
 +          data->phase2_eap_type.method == EAP_TYPE_NONE)
 +              eap_ttls_phase2_select_eap_method(data, method);
 +
 +      if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE)
 +      {
 +              if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
 +                                          data->num_phase2_eap_types,
 +                                          hdr, resp))
 +                      return -1;
 +              return 0;
 +      }
 +
 +      if (data->phase2_priv == NULL) {
 +              data->phase2_method = eap_peer_get_eap_method(
 +                      EAP_VENDOR_IETF, method);
 +              if (data->phase2_method) {
 +                      sm->init_phase2 = 1;
 +                      data->phase2_priv = data->phase2_method->init(sm);
 +                      sm->init_phase2 = 0;
 +              }
 +      }
 +      if (data->phase2_priv == NULL || data->phase2_method == NULL) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize "
 +                         "Phase 2 EAP method %d", method);
 +              return -1;
 +      }
 +
 +      return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp);
 +}
 +
 +
 +static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret,
 +                                     struct eap_hdr *hdr,
 +                                     struct wpabuf **resp)
 +{
 +      size_t len = be_to_host16(hdr->length);
 +      u8 *pos;
 +      struct eap_peer_config *config = eap_get_config(sm);
 +
 +      if (len <= sizeof(struct eap_hdr)) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: too short "
 +                         "Phase 2 request (len=%lu)", (unsigned long) len);
 +              return -1;
 +      }
 +      pos = (u8 *) (hdr + 1);
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos);
 +      switch (*pos) {
 +      case EAP_TYPE_IDENTITY:
 +              *resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
 +              break;
 +      default:
 +              if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
 +                                                     *pos, resp) < 0)
 +                      return -1;
 +              break;
 +      }
 +
 +      if (*resp == NULL &&
 +          (config->pending_req_identity || config->pending_req_password ||
 +           config->pending_req_otp)) {
 +              return 0;
 +      }
 +
 +      if (*resp == NULL)
 +              return -1;
 +
 +      wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response",
 +                      *resp);
 +      return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1);
 +}
 +
 +
-       peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
 +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;
 +      size_t identity_len, password_len;
 +      int pwhash;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request");
 +
 +      identity = eap_get_config_identity(sm, &identity_len);
 +      password = eap_get_config_password2(sm, &password_len, &pwhash);
 +      if (identity == NULL || password == NULL)
 +              return -1;
 +
 +      msg = wpabuf_alloc(identity_len + 1000);
 +      if (msg == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "EAP-TTLS/MSCHAPV2: Failed to allocate memory");
 +              return -1;
 +      }
 +      pos = buf = wpabuf_mhead(msg);
 +
 +      /* User-Name */
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
 +                             identity, identity_len);
 +
 +      /* MS-CHAP-Challenge */
 +      challenge = eap_ttls_implicit_challenge(
 +              sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
 +      if (challenge == NULL) {
 +              wpabuf_free(msg);
 +              wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
 +                         "implicit challenge");
 +              return -1;
 +      }
-       os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
 +
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
 +                             RADIUS_VENDOR_ID_MICROSOFT, 1,
 +                             challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
 +
 +      /* MS-CHAP2-Response */
 +      pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE,
 +                             RADIUS_VENDOR_ID_MICROSOFT, 1,
 +                             EAP_TTLS_MSCHAPV2_RESPONSE_LEN);
 +      data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
 +      *pos++ = data->ident;
 +      *pos++ = 0; /* Flags */
-       eap_ttlsv1_permute_inner(sm, data);
++      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;
 +      if (mschapv2_derive_response(identity, identity_len, password,
 +                                   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");
 +              return -1;
 +      }
 +      data->auth_response_valid = 1;
 +
-       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;
-       }
 +      pos += 24;
 +      os_free(challenge);
 +      AVP_PAD(buf, pos);
 +
 +      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;
-       }
 +      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 */
 +}
 +
 +
 +static int eap_ttls_phase2_request_mschap(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: MSCHAP not supported in FIPS build");
++      return -1;
++#else /* CONFIG_FIPS */
 +      struct wpabuf *msg;
 +      u8 *buf, *pos, *challenge;
 +      const u8 *identity, *password;
 +      size_t identity_len, password_len;
 +      int pwhash;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request");
 +
 +      identity = eap_get_config_identity(sm, &identity_len);
 +      password = eap_get_config_password2(sm, &password_len, &pwhash);
 +      if (identity == NULL || password == NULL)
 +              return -1;
 +
 +      msg = wpabuf_alloc(identity_len + 1000);
 +      if (msg == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "EAP-TTLS/MSCHAP: Failed to allocate memory");
 +              return -1;
 +      }
 +      pos = buf = wpabuf_mhead(msg);
 +
 +      /* User-Name */
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
 +                             identity, identity_len);
 +
 +      /* MS-CHAP-Challenge */
 +      challenge = eap_ttls_implicit_challenge(
 +              sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
 +      if (challenge == NULL) {
 +              wpabuf_free(msg);
 +              wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
 +                         "implicit challenge");
 +              return -1;
 +      }
 +
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
 +                             RADIUS_VENDOR_ID_MICROSOFT, 1,
 +                             challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
 +
 +      /* MS-CHAP-Response */
 +      pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE,
 +                             RADIUS_VENDOR_ID_MICROSOFT, 1,
 +                             EAP_TTLS_MSCHAP_RESPONSE_LEN);
 +      data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN];
 +      *pos++ = data->ident;
 +      *pos++ = 1; /* Flags: Use NT style passwords */
 +      os_memset(pos, 0, 24); /* LM-Response */
 +      pos += 24;
 +      if (pwhash) {
 +              challenge_response(challenge, password, pos); /* NT-Response */
 +              wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash",
 +                              password, 16);
 +      } else {
 +              nt_challenge_response(challenge, password, password_len,
 +                                    pos); /* NT-Response */
 +              wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
 +                                    password, password_len);
 +      }
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge",
 +                  challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24);
 +      pos += 24;
 +      os_free(challenge);
 +      AVP_PAD(buf, pos);
 +
 +      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/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 */
 +}
 +
 +
 +static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret,
 +                                     struct wpabuf **resp)
 +{
 +      struct wpabuf *msg;
 +      u8 *buf, *pos;
 +      size_t pad;
 +      const u8 *identity, *password;
 +      size_t identity_len, password_len;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request");
 +
 +      identity = eap_get_config_identity(sm, &identity_len);
 +      password = eap_get_config_password(sm, &password_len);
 +      if (identity == NULL || password == NULL)
 +              return -1;
 +
 +      msg = wpabuf_alloc(identity_len + password_len + 100);
 +      if (msg == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "EAP-TTLS/PAP: Failed to allocate memory");
 +              return -1;
 +      }
 +      pos = buf = wpabuf_mhead(msg);
 +
 +      /* User-Name */
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
 +                             identity, identity_len);
 +
 +      /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts
 +       * the data, so no separate encryption is used in the AVP itself.
 +       * However, the password is padded to obfuscate its length. */
 +      pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15;
 +      pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1,
 +                             password_len + pad);
 +      os_memcpy(pos, password, password_len);
 +      pos += password_len;
 +      os_memset(pos, 0, pad);
 +      pos += pad;
 +      AVP_PAD(buf, pos);
 +
 +      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/PAP does not provide tunneled success notification,
++       * so assume that Phase2 succeeds. */
++      ret->methodState = METHOD_DONE;
++      ret->decision = DECISION_COND_SUCC;
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_phase2_request_chap(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: CHAP not supported in FIPS build");
++      return -1;
++#else /* CONFIG_FIPS */
 +      struct wpabuf *msg;
 +      u8 *buf, *pos, *challenge;
 +      const u8 *identity, *password;
 +      size_t identity_len, password_len;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
 +
 +      identity = eap_get_config_identity(sm, &identity_len);
 +      password = eap_get_config_password(sm, &password_len);
 +      if (identity == NULL || password == NULL)
 +              return -1;
 +
 +      msg = wpabuf_alloc(identity_len + 1000);
 +      if (msg == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "EAP-TTLS/CHAP: Failed to allocate memory");
 +              return -1;
 +      }
 +      pos = buf = wpabuf_mhead(msg);
 +
 +      /* User-Name */
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
 +                             identity, identity_len);
 +
 +      /* CHAP-Challenge */
 +      challenge = eap_ttls_implicit_challenge(
 +              sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
 +      if (challenge == NULL) {
 +              wpabuf_free(msg);
 +              wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
 +                         "implicit challenge");
 +              return -1;
 +      }
 +
 +      pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1,
 +                             challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
 +
 +      /* CHAP-Password */
 +      pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1,
 +                             1 + EAP_TTLS_CHAP_PASSWORD_LEN);
 +      data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN];
 +      *pos++ = data->ident;
 +
 +      /* MD5(Ident + Password + Challenge) */
 +      chap_md5(data->ident, password, password_len, challenge,
 +               EAP_TTLS_CHAP_CHALLENGE_LEN, pos);
 +
 +      wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
 +                        identity, identity_len);
 +      wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password",
 +                            password, password_len);
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge",
 +                  challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password",
 +                  pos, EAP_TTLS_CHAP_PASSWORD_LEN);
 +      pos += EAP_TTLS_CHAP_PASSWORD_LEN;
 +      os_free(challenge);
 +      AVP_PAD(buf, pos);
 +
 +      wpabuf_put(msg, pos - buf);
 +      *resp = msg;
 +
- #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 */
++      /* 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 */
 +}
 +
 +
 +static int eap_ttls_phase2_request(struct eap_sm *sm,
 +                                 struct eap_ttls_data *data,
 +                                 struct eap_method_ret *ret,
 +                                 struct eap_hdr *hdr,
 +                                 struct wpabuf **resp)
 +{
 +      int res = 0;
 +      size_t len;
 +      enum phase2_types phase2_type = data->phase2_type;
 +
 +#ifdef EAP_TNC
 +      if (data->tnc_started) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC");
 +              phase2_type = EAP_TTLS_PHASE2_EAP;
 +      }
 +#endif /* EAP_TNC */
 +
 +      if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 ||
 +          phase2_type == EAP_TTLS_PHASE2_MSCHAP ||
 +          phase2_type == EAP_TTLS_PHASE2_PAP ||
 +          phase2_type == EAP_TTLS_PHASE2_CHAP) {
 +              if (eap_get_config_identity(sm, &len) == NULL) {
 +                      wpa_printf(MSG_INFO,
 +                                 "EAP-TTLS: Identity not configured");
 +                      eap_sm_request_identity(sm);
 +                      if (eap_get_config_password(sm, &len) == NULL)
 +                              eap_sm_request_password(sm);
 +                      return 0;
 +              }
 +
 +              if (eap_get_config_password(sm, &len) == NULL) {
 +                      wpa_printf(MSG_INFO,
 +                                 "EAP-TTLS: Password not configured");
 +                      eap_sm_request_password(sm);
 +                      return 0;
 +              }
 +      }
 +
 +      switch (phase2_type) {
 +      case EAP_TTLS_PHASE2_EAP:
 +              res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp);
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAPV2:
 +              res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp);
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAP:
 +              res = eap_ttls_phase2_request_mschap(sm, data, ret, resp);
 +              break;
 +      case EAP_TTLS_PHASE2_PAP:
 +              res = eap_ttls_phase2_request_pap(sm, data, ret, resp);
 +              break;
 +      case EAP_TTLS_PHASE2_CHAP:
 +              res = eap_ttls_phase2_request_chap(sm, data, ret, resp);
 +              break;
 +      default:
 +              wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown");
 +              res = -1;
 +              break;
 +      }
 +
 +      if (res < 0) {
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +      }
 +
 +      return res;
 +}
 +
 +
-       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;
-       }
 +struct ttls_parse_avp {
 +      u8 *mschapv2;
 +      u8 *eapdata;
 +      size_t eap_len;
 +      u8 *chbind_data;
 +      size_t chbind_len;
 +      int mschapv2_error;
 +};
 +
 +
 +static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen,
 +                                 struct ttls_parse_avp *parse)
 +{
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
 +      if (parse->eapdata == NULL) {
 +              parse->eapdata = os_malloc(dlen);
 +              if (parse->eapdata == NULL) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
 +                                 "memory for Phase 2 EAP data");
 +                      return -1;
 +              }
 +              os_memcpy(parse->eapdata, dpos, dlen);
 +              parse->eap_len = dlen;
 +      } else {
 +              u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen);
 +              if (neweap == NULL) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
 +                                 "memory for Phase 2 EAP data");
 +                      return -1;
 +              }
 +              os_memcpy(neweap + parse->eap_len, dpos, dlen);
 +              parse->eapdata = neweap;
 +              parse->eap_len += dlen;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_parse_attr_chbind(const u8 *dpos, size_t dlen,
 +                                 struct ttls_parse_avp *parse)
 +{
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - Channel Binding Message");
 +
 +      if (parse->chbind_data == NULL) {
 +              parse->chbind_data = os_malloc(dlen);
 +              if (parse->chbind_data == NULL) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
 +                                 "memory for Phase 2 channel binding data");
 +                      return -1;
 +              }
 +              os_memcpy(parse->chbind_data, dpos, dlen);
 +              parse->chbind_len = dlen;
 +      } else {
 +        /* TODO: can this really happen?  maybe just make this an error? */
 +              u8 *newchbind = os_realloc(parse->chbind_data,
 +                                         parse->chbind_len + dlen);
 +              if (newchbind == NULL) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
 +                                 "memory for Phase 2 channel binding data");
 +                      return -1;
 +              }
 +              os_memcpy(newchbind + parse->chbind_len, dpos, dlen);
 +              parse->chbind_data = newchbind;
 +              parse->chbind_len += dlen;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_parse_avp(u8 *pos, size_t left,
 +                            struct ttls_parse_avp *parse)
 +{
 +      struct ttls_avp *avp;
 +      u32 avp_code, avp_length, vendor_id = 0;
 +      u8 avp_flags, *dpos;
 +      size_t dlen;
 +
 +      avp = (struct ttls_avp *) pos;
 +      avp_code = be_to_host32(avp->avp_code);
 +      avp_length = be_to_host32(avp->avp_length);
 +      avp_flags = (avp_length >> 24) & 0xff;
 +      avp_length &= 0xffffff;
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x "
 +                 "length=%d", (int) avp_code, avp_flags,
 +                 (int) avp_length);
 +
 +      if (avp_length > left) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
 +                         "(len=%d, left=%lu) - dropped",
 +                         (int) avp_length, (unsigned long) left);
 +              return -1;
 +      }
 +
 +      if (avp_length < sizeof(*avp)) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d",
 +                         avp_length);
 +              return -1;
 +      }
 +
 +      dpos = (u8 *) (avp + 1);
 +      dlen = avp_length - sizeof(*avp);
 +      if (avp_flags & AVP_FLAGS_VENDOR) {
 +              if (dlen < 4) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP "
 +                                 "underflow");
 +                      return -1;
 +              }
 +              vendor_id = WPA_GET_BE32(dpos);
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d",
 +                         (int) vendor_id);
 +              dpos += 4;
 +              dlen -= 4;
 +      }
 +
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen);
 +
 +      if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
 +              if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0)
 +                      return -1;
 +      } else if (vendor_id == RADIUS_VENDOR_ID_UKERNA &&
 +                 avp_code == RADIUS_ATTR_UKERNA_CHBIND) {
 +              /* message containing channel binding data */
 +              if (eap_ttls_parse_attr_chbind(dpos, dlen, parse) < 0)
 +                      return -1;
 +      } else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) {
 +              /* This is an optional message that can be displayed to
 +               * the user. */
 +              wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message",
 +                                dpos, dlen);
 +      } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
 +                 avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) {
 +              wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success",
 +                                dpos, dlen);
 +              if (dlen != 43) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected "
 +                                 "MS-CHAP2-Success length "
 +                                 "(len=%lu, expected 43)",
 +                                 (unsigned long) dlen);
 +                      return -1;
 +              }
 +              parse->mschapv2 = dpos;
 +      } else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
 +                 avp_code == RADIUS_ATTR_MS_CHAP_ERROR) {
 +              wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error",
 +                                dpos, dlen);
 +              parse->mschapv2_error = 1;
 +      } else if (avp_flags & AVP_FLAGS_MANDATORY) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP "
 +                         "code %d vendor_id %d - dropped",
 +                         (int) avp_code, (int) vendor_id);
 +              return -1;
 +      } else {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP "
 +                         "code %d vendor_id %d",
 +                         (int) avp_code, (int) vendor_id);
 +      }
 +
 +      return avp_length;
 +}
 +
 +
 +static int eap_ttls_parse_avps(struct wpabuf *in_decrypted,
 +                             struct ttls_parse_avp *parse)
 +{
 +      u8 *pos;
 +      size_t left, pad;
 +      int avp_length;
 +
 +      pos = wpabuf_mhead(in_decrypted);
 +      left = wpabuf_len(in_decrypted);
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left);
 +      if (left < sizeof(struct ttls_avp)) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame"
 +                         " len=%lu expected %lu or more - dropped",
 +                         (unsigned long) left,
 +                         (unsigned long) sizeof(struct ttls_avp));
 +              return -1;
 +      }
 +
 +      /* Parse AVPs */
 +      os_memset(parse, 0, sizeof(*parse));
 +
 +      while (left > 0) {
 +              avp_length = eap_ttls_parse_avp(pos, left, parse);
 +              if (avp_length < 0)
 +                      return -1;
 +
 +              pad = (4 - (avp_length & 3)) & 3;
 +              pos += avp_length + pad;
 +              if (left < avp_length + pad)
 +                      left = 0;
 +              else
 +                      left -= avp_length + pad;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static u8 * eap_ttls_fake_identity_request(void)
 +{
 +      struct eap_hdr *hdr;
 +      u8 *buf;
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of "
 +                 "Phase 2 - use fake EAP-Request Identity");
 +      buf = os_malloc(sizeof(*hdr) + 1);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate "
 +                         "memory for fake EAP-Identity Request");
 +              return NULL;
 +      }
 +
 +      hdr = (struct eap_hdr *) buf;
 +      hdr->code = EAP_CODE_REQUEST;
 +      hdr->identifier = 0;
 +      hdr->length = host_to_be16(sizeof(*hdr) + 1);
 +      buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY;
 +
 +      return buf;
 +}
 +
 +
 +static int eap_ttls_encrypt_response(struct eap_sm *sm,
 +                                   struct eap_ttls_data *data,
 +                                   struct wpabuf *resp, u8 identifier,
 +                                   struct wpabuf **out_data)
 +{
 +      if (resp == NULL)
 +              return 0;
 +
 +      wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data",
 +                          resp);
 +      if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
 +                               data->ttls_version, identifier,
 +                               resp, out_data)) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
 +                         "frame");
++              wpabuf_free(resp);
 +              return -1;
 +      }
 +      wpabuf_free(resp);
 +
 +      return 0;
 +}
 +
 +static int eap_ttls_add_chbind_request(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct wpabuf **resp)
 +{
 +      struct wpabuf *chbind_req, *res;
 +      int length = 1, i;
 +      struct eap_peer_config *config = eap_get_config(sm);
 +
 +      if (!config->chbind_config || config->chbind_config_len <= 0)
 +              return -1;
 +
 +      for (i=0; i<config->chbind_config_len; i++) {
 +              length += 3 + config->chbind_config[i].req_data_len;
 +      }
 +
 +      chbind_req = wpabuf_alloc(length);
 +      if (!chbind_req)
 +              return -1;
 +
 +      wpabuf_put_u8(chbind_req, CHBIND_CODE_REQUEST);
 +      for (i=0; i<config->chbind_config_len; i++) {
 +              struct eap_peer_chbind_config *chbind_config =
 +                      &config->chbind_config[i];
 +              wpabuf_put_be16(chbind_req, chbind_config->req_data_len);
 +              wpabuf_put_u8(chbind_req, chbind_config->nsid);
 +              wpabuf_put_data(chbind_req, chbind_config->req_data,
 +                              chbind_config->req_data_len);
 +      }
 +      if (eap_ttls_avp_radius_vsa_encapsulate(&chbind_req,
 +                                       RADIUS_VENDOR_ID_UKERNA,
 +                                       RADIUS_ATTR_UKERNA_CHBIND, 0) < 0)
 +              return -1;
 +
 +      /* bleh. This will free *resp regardless of whether combined buffer
 +         alloc succeeds, which is not consistent with the other error
 +         condition behavior in this function */
 +      *resp = wpabuf_concat(chbind_req, *resp);
 +
 +      return (*resp) ? 0 : -1;
 +}
 +
 +
 +static int eap_ttls_process_chbind(struct eap_sm *sm,
 +                                 struct eap_ttls_data *data,
 +                                 struct eap_method_ret *ret,
 +                                 struct ttls_parse_avp *parse,
 +                                 struct wpabuf **resp)
 +{
 +      size_t pos=0;
 +      u8 code;
 +      u16 len;
 +      struct chbind_hdr *hdr;
 +      struct eap_peer_config *config = eap_get_config(sm);
 +      int i, found;
 +
 +
 +      if (parse->chbind_data == NULL) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: No channel binding message "
 +                         "in the packet - dropped");
 +              return -1;
 +      }
 +      if (parse->chbind_len < 1 ) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response "
 +                         "frame (len=%lu, expected %lu or more) - dropped",
 +                         (unsigned long) parse->chbind_len,
 +                         (unsigned long) 1);
 +              return -1;
 +      }
 +      code = parse->chbind_data[pos++];
 +      for (i=0; i<config->chbind_config_len; i++) {
 +              struct eap_peer_chbind_config *chbind_config =
 +                      &config->chbind_config[i];
 +              pos = 1;
 +              found = 0;
 +              while (pos+sizeof(*hdr) < parse->chbind_len) {
 +                      hdr = (struct chbind_hdr *)(&parse->chbind_data[pos]);
 +                      pos += sizeof(*hdr);
 +                      len = be_to_host16(hdr->len);
 +                      if (pos + len <= parse->chbind_len) {
 +                              if (chbind_config->nsid == hdr->nsid)
 +                                      chbind_config->response_cb(
 +                                                                 chbind_config->ctx,
 +                                                                 code, hdr->nsid,
 +                                                                 &parse->chbind_data[pos], len);
 +                              found  = 1;
 +                      }
 +                      pos += len;
 +              }
 +              if (pos != parse->chbind_len) {
 +                      wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response "
 +                                 "frame (parsed len=%lu, expected %lu) - dropped",
 +                                 (unsigned long) pos,
 +                                 (unsigned long) parse->chbind_len);
 +                      return -1;
 +              }
 +              if (!found) {
 +                      chbind_config->response_cb(
 +                                                 chbind_config->ctx,
 +                                                 code, chbind_config->nsid,
 +                                                 NULL, 0);
 +              }
 +
 +      }
 +      return 0;
 +}
 +
 +static int eap_ttls_process_phase2_eap(struct eap_sm *sm,
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret,
 +                                     struct ttls_parse_avp *parse,
 +                                     struct wpabuf **resp)
 +{
 +      struct eap_hdr *hdr;
 +      size_t len;
 +
 +      if (parse->eapdata == NULL) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the "
 +                         "packet - dropped");
 +              return -1;
 +      }
 +
 +      wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP",
 +                  parse->eapdata, parse->eap_len);
 +      hdr = (struct eap_hdr *) parse->eapdata;
 +
 +      if (parse->eap_len < sizeof(*hdr)) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP "
 +                         "frame (len=%lu, expected %lu or more) - dropped",
 +                         (unsigned long) parse->eap_len,
 +                         (unsigned long) sizeof(*hdr));
 +              return -1;
 +      }
 +      len = be_to_host16(hdr->length);
 +      if (len > parse->eap_len) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 "
 +                         "EAP frame (EAP hdr len=%lu, EAP data len in "
 +                         "AVP=%lu)",
 +                         (unsigned long) len,
 +                         (unsigned long) parse->eap_len);
 +              return -1;
 +      }
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d "
 +                 "identifier=%d length=%lu",
 +                 hdr->code, hdr->identifier, (unsigned long) len);
 +      switch (hdr->code) {
 +      case EAP_CODE_REQUEST:
 +              if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) {
 +                      wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
 +                                 "processing failed");
 +                      return -1;
 +              }
 +              break;
 +      default:
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in "
 +                         "Phase 2 EAP header", hdr->code);
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
 +                                          struct eap_ttls_data *data,
 +                                          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");
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +              /* Reply with empty data to ACK error */
 +              return 1;
 +      }
 +
 +      if (parse->mschapv2 == NULL) {
 +#ifdef EAP_TNC
 +              if (data->phase2_success && parse->eapdata) {
 +                      /*
 +                       * Allow EAP-TNC to be started after successfully
 +                       * completed MSCHAPV2.
 +                       */
 +                      return 1;
 +              }
 +#endif /* EAP_TNC */
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP "
 +                         "received for Phase2 MSCHAPV2");
 +              return -1;
 +      }
 +      if (parse->mschapv2[0] != data->ident) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 "
 +                         "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)",
 +                         parse->mschapv2[0], data->ident);
 +              return -1;
 +      }
 +      if (!data->auth_response_valid ||
 +          mschapv2_verify_auth_response(data->auth_response,
 +                                        parse->mschapv2 + 1, 42)) {
 +              wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator "
 +                         "response in Phase 2 MSCHAPV2 success request");
 +              return -1;
 +      }
 +
 +      wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
 +                 "authentication succeeded");
- #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 */
++      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 */
 +}
 +
 +
 +#ifdef EAP_TNC
 +static int eap_ttls_process_tnc_start(struct eap_sm *sm,
 +                                    struct eap_ttls_data *data,
 +                                    struct eap_method_ret *ret,
 +                                    struct ttls_parse_avp *parse,
 +                                    struct wpabuf **resp)
 +{
 +      /* TNC uses inner EAP method after non-EAP TTLS phase 2. */
 +      if (parse->eapdata == NULL) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
 +                         "unexpected tunneled data (no EAP)");
 +              return -1;
 +      }
 +
 +      if (!data->ready_for_tnc) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
 +                         "EAP after non-EAP, but not ready for TNC");
 +              return -1;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
 +                 "non-EAP method");
 +      data->tnc_started = 1;
 +
 +      if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0)
 +              return -1;
 +
 +      return 0;
 +}
 +#endif /* EAP_TNC */
 +
 +
 +static int eap_ttls_process_decrypted(struct eap_sm *sm,
 +                                    struct eap_ttls_data *data,
 +                                    struct eap_method_ret *ret,
 +                                    u8 identifier,
 +                                    struct ttls_parse_avp *parse,
 +                                    struct wpabuf *in_decrypted,
 +                                    struct wpabuf **out_data)
 +{
 +      struct wpabuf *resp = NULL;
 +      struct eap_peer_config *config = eap_get_config(sm);
 +      int res;
 +      enum phase2_types phase2_type = data->phase2_type;
 +
 +#ifdef EAP_TNC
 +      if (data->tnc_started)
 +              phase2_type = EAP_TTLS_PHASE2_EAP;
 +#endif /* EAP_TNC */
 +
 +      /* handle channel binding response here */
 +      if (parse->chbind_data) {
 +              /* received channel binding repsonse */
 +              if (eap_ttls_process_chbind(sm, data, ret, parse, &resp) < 0)
 +                      return -1;
 +              if (data->done_butfor_cb) {
 +                      ret->methodState = METHOD_DONE;
 +                      ret->decision = data->cbDecision;
 +                      data->phase2_success = 1;
 +                      return 1; /*request ack*/
 +              }
 +      }
 +
 +      switch (phase2_type) {
 +      case EAP_TTLS_PHASE2_EAP:
 +              if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) <
 +                  0)
 +                      return -1;
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAPV2:
 +              res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse);
 +#ifdef EAP_TNC
 +              if (res == 1 && parse->eapdata && data->phase2_success) {
 +                      /*
 +                       * TNC may be required as the next
 +                       * authentication method within the tunnel.
 +                       */
 +                      ret->methodState = METHOD_MAY_CONT;
 +                      data->ready_for_tnc = 1;
 +                      if (eap_ttls_process_tnc_start(sm, data, ret, parse,
 +                                                     &resp) == 0)
 +                              break;
 +              }
 +#endif /* EAP_TNC */
 +              return res;
 +      case EAP_TTLS_PHASE2_MSCHAP:
 +      case EAP_TTLS_PHASE2_PAP:
 +      case EAP_TTLS_PHASE2_CHAP:
 +#ifdef EAP_TNC
 +              if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) <
 +                  0)
 +                      return -1;
 +              break;
 +#else /* EAP_TNC */
 +              /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled
 +               * requests to the supplicant */
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected "
 +                         "tunneled data");
 +              return -1;
 +#endif /* EAP_TNC */
 +      }
 +
 +      if (!resp && (config->pending_req_identity ||
 +                      config->pending_req_password ||
 +                      config->pending_req_otp ||
 +                      config->pending_req_new_password)) {
 +              wpabuf_free(data->pending_phase2_req);
 +              data->pending_phase2_req = wpabuf_dup(in_decrypted);
 +              return 0;
 +      }
 +
 +      /* issue channel binding request when appropriate */
 +      if (config->chbind_config && config->chbind_config_len > 0 &&
 +              !data->chbind_req_sent) {
 +              if (eap_ttls_add_chbind_request(sm, data, &resp) < 0)
 +                      return -1;
 +              data->chbind_req_sent = 1;
 +              if (ret->methodState == METHOD_DONE) {
 +                      data->done_butfor_cb = 1;
 +                      data->cbDecision = ret->decision;
 +                      ret->methodState = METHOD_MAY_CONT;
 +              }
 +      }
 +
 +      if (resp) {
 +              if (eap_ttls_encrypt_response(sm, data, resp, identifier,
 +                                            out_data) < 0)
 +                      return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
- #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 */
 +static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
 +                                            struct eap_ttls_data *data,
 +                                            struct eap_method_ret *ret,
 +                                            u8 identifier,
 +                                            struct wpabuf **out_data)
 +{
 +      int retval = 0;
 +      struct eap_hdr *hdr;
 +      struct wpabuf *resp;
 +
 +      hdr = (struct eap_hdr *) eap_ttls_fake_identity_request();
 +      if (hdr == NULL) {
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +              return -1;
 +      }
 +
 +      resp = NULL;
 +      if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) {
 +              wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
 +                         "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);
 +      }
 +
 +      os_free(hdr);
 +
 +      if (retval < 0) {
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +      }
 +
 +      return retval;
 +}
 +
 +
 +static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data,
 +                               struct eap_method_ret *ret, u8 identifier,
 +                               struct wpabuf **out_data)
 +{
 +      data->phase2_start = 0;
 +
 +      /*
 +       * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only
 +       * if TLS part was indeed resuming a previous session. Most
 +       * Authentication Servers terminate EAP-TTLS before reaching this
 +       * point, but some do not. Make wpa_supplicant stop phase 2 here, if
 +       * needed.
 +       */
 +      if (data->reauth &&
 +          tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - "
 +                         "skip phase 2");
 +              *out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS,
 +                                                 data->ttls_version);
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_UNCOND_SUCC;
 +              data->phase2_success = 1;
 +              return 0;
 +      }
 +
 +      return eap_ttls_implicit_identity_request(sm, data, ret, identifier,
 +                                                out_data);
 +}
 +
 +
 +static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
 +                          struct eap_method_ret *ret, u8 identifier,
 +                          const struct wpabuf *in_data,
 +                          struct wpabuf **out_data)
 +{
 +      struct wpabuf *in_decrypted = NULL;
 +      int retval = 0;
 +      struct ttls_parse_avp parse;
 +
 +      os_memset(&parse, 0, sizeof(parse));
 +
 +      wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
 +                 " Phase 2",
 +                 in_data ? (unsigned long) wpabuf_len(in_data) : 0);
 +
 +      if (data->pending_phase2_req) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - "
 +                         "skip decryption and use old data");
 +              /* Clear TLS reassembly state. */
 +              eap_peer_tls_reset_input(&data->ssl);
 +
 +              in_decrypted = data->pending_phase2_req;
 +              data->pending_phase2_req = NULL;
 +              if (wpabuf_len(in_decrypted) == 0) {
 +                      wpabuf_free(in_decrypted);
 +                      return eap_ttls_implicit_identity_request(
 +                              sm, data, ret, identifier, out_data);
 +              }
 +              goto continue_req;
 +      }
 +
 +      if ((in_data == NULL || wpabuf_len(in_data) == 0) &&
 +          data->phase2_start) {
 +              return eap_ttls_phase2_start(sm, data, ret, identifier,
 +                                           out_data);
 +      }
 +
 +      if (in_data == NULL || wpabuf_len(in_data) == 0) {
 +              /* Received TLS ACK - requesting more fragments */
 +              return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
 +                                          data->ttls_version,
 +                                          identifier, NULL, out_data);
 +      }
 +
 +      retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
 +      if (retval)
 +              goto 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;
- }
 +continue_req:
 +      data->phase2_start = 0;
 +
 +      if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) {
 +              retval = -1;
 +              goto done;
 +      }
 +
 +      retval = eap_ttls_process_decrypted(sm, data, ret, identifier,
 +                                          &parse, in_decrypted, out_data);
 +
 +done:
 +      wpabuf_free(in_decrypted);
 +      os_free(parse.eapdata);
 +
 +      if (retval < 0) {
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +      }
 +
 +      return retval;
 +}
 +
 +
-                                     const u8 *in_data, size_t in_len,
 +static int eap_ttls_process_handshake(struct eap_sm *sm,
 +                                    struct eap_ttls_data *data,
 +                                    struct eap_method_ret *ret,
 +                                    u8 identifier,
-                                         in_data, in_len, out_data);
++                                    const struct wpabuf *in_data,
 +                                    struct wpabuf **out_data)
 +{
 +      int res;
 +
 +      res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
 +                                        data->ttls_version, identifier,
-               if (data->ttls_version == 0)
-                       eap_ttls_v0_derive_key(sm, 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 (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
 +                         "Phase 2");
 +              if (data->resuming) {
 +                      wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may "
 +                                 "skip Phase 2");
 +                      ret->decision = DECISION_COND_SUCC;
 +                      ret->methodState = METHOD_MAY_CONT;
 +              }
 +              data->phase2_start = 1;
-               struct wpabuf msg;
++              eap_ttls_v0_derive_key(sm, data);
 +
 +              if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
 +                      if (eap_ttls_decrypt(sm, data, ret, identifier,
 +                                           NULL, out_data)) {
 +                              wpa_printf(MSG_WARNING, "EAP-TTLS: "
 +                                         "failed to process early "
 +                                         "start for Phase 2");
 +                      }
 +                      res = 0;
 +              }
 +              data->resuming = 0;
 +      }
 +
 +      if (res == 2) {
-               wpabuf_set(&msg, in_data, in_len);
-               res = eap_ttls_decrypt(sm, data, ret, identifier, &msg,
 +              /*
 +               * Application data included in the handshake message.
 +               */
 +              wpabuf_free(data->pending_phase2_req);
 +              data->pending_phase2_req = *out_data;
 +              *out_data = NULL;
-       if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) {
++              res = eap_ttls_decrypt(sm, data, ret, identifier, in_data,
 +                                     out_data);
 +      }
 +
 +      return res;
 +}
 +
 +
 +static void eap_ttls_check_auth_status(struct eap_sm *sm, 
 +                                     struct eap_ttls_data *data,
 +                                     struct eap_method_ret *ret)
 +{
-       } else if (data->ttls_version == 0 &&
-                  ret->methodState == METHOD_MAY_CONT &&
++      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;
 +#ifdef EAP_TNC
 +                      if (!data->ready_for_tnc && !data->tnc_started) {
 +                              /*
 +                               * TNC may be required as the next
 +                               * authentication method within the tunnel.
 +                               */
 +                              ret->methodState = METHOD_MAY_CONT;
 +                              data->ready_for_tnc = 1;
 +                      }
 +#endif /* EAP_TNC */
 +              }
-               if (eap_ttls_process_start(sm, data, flags, ret) < 0)
-                       return NULL;
++      } 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;
 +      }
 +}
 +
 +
 +static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
 +                                      struct eap_method_ret *ret,
 +                                      const struct wpabuf *reqData)
 +{
 +      size_t left;
 +      int res;
 +      u8 flags, id;
 +      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);
 +      if (pos == NULL)
 +              return NULL;
 +      id = eap_get_id(reqData);
 +
 +      if (flags & EAP_TLS_FLAGS_START) {
-       } 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;
++              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
 +               * of AVPs, which may provide useful hints to the client"
 +               * For now, ignore any potential extra data.
 +               */
 +              left = 0;
-               struct wpabuf msg;
-               wpabuf_set(&msg, pos, left);
 +      }
 +
++      wpabuf_set(&msg, pos, left);
++
 +      resp = NULL;
 +      if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
 +          !data->resuming) {
-                                                pos, left, &resp);
 +              res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp);
 +      } else {
 +              res = eap_ttls_process_handshake(sm, data, ret, id,
-       os_free(data->key_data);
-       data->key_data = NULL;
++                                               &msg, &resp);
 +      }
 +
 +      eap_ttls_check_auth_status(sm, data, ret);
 +
 +      /* FIX: what about res == -1? Could just move all error processing into
 +       * the other functions and get rid of this res==1 case here. */
 +      if (res == 1) {
 +              wpabuf_free(resp);
 +              return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS,
 +                                            data->ttls_version);
 +      }
 +      return resp;
 +}
 +
 +
 +static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
 +{
 +      struct eap_ttls_data *data = priv;
 +      return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
 +              data->phase2_success;
 +}
 +
 +
 +static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
 +{
 +      struct eap_ttls_data *data = priv;
 +      wpabuf_free(data->pending_phase2_req);
 +      data->pending_phase2_req = NULL;
 +#ifdef EAP_TNC
 +      data->ready_for_tnc = 0;
 +      data->tnc_started = 0;
 +#endif /* EAP_TNC */
 +}
 +
 +
 +static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
 +{
 +      struct eap_ttls_data *data = priv;
-       if (ret < 0 || (size_t) ret >= buflen - len)
++      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;
 +      }
 +      if (data->phase2_priv && data->phase2_method &&
 +          data->phase2_method->init_for_reauth)
 +              data->phase2_method->init_for_reauth(sm, data->phase2_priv);
 +      data->phase2_start = 0;
 +      data->phase2_success = 0;
 +      data->resuming = 1;
 +      data->reauth = 1;
 +      return priv;
 +}
 +
 +
 +static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
 +                             size_t buflen, int verbose)
 +{
 +      struct eap_ttls_data *data = priv;
 +      int len, ret;
 +
 +      len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
 +      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) {
 +      case EAP_TTLS_PHASE2_EAP:
 +              ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n",
 +                                data->phase2_method ?
 +                                data->phase2_method->name : "?");
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAPV2:
 +              ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n");
 +              break;
 +      case EAP_TTLS_PHASE2_MSCHAP:
 +              ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n");
 +              break;
 +      case EAP_TTLS_PHASE2_PAP:
 +              ret = os_snprintf(buf + len, buflen - len, "PAP\n");
 +              break;
 +      case EAP_TTLS_PHASE2_CHAP:
 +              ret = os_snprintf(buf + len, buflen - len, "CHAP\n");
 +              break;
 +      default:
 +              ret = 0;
 +              break;
 +      }
++      if (os_snprintf_error(buflen - len, ret))
 +              return len;
 +      len += ret;
 +
 +      return len;
 +}
 +
 +
 +static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)
 +{
 +      struct eap_ttls_data *data = priv;
 +      return data->key_data != NULL && data->phase2_success;
 +}
 +
 +
 +static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
 +{
 +      struct eap_ttls_data *data = priv;
 +      u8 *key;
 +
 +      if (data->key_data == NULL || !data->phase2_success)
 +              return NULL;
 +
 +      key = os_malloc(EAP_TLS_KEY_LEN);
 +      if (key == NULL)
 +              return NULL;
 +
 +      *len = EAP_TLS_KEY_LEN;
 +      os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
 +
 +      return key;
 +}
 +
 +
++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");
 +      if (eap == NULL)
 +              return -1;
 +
 +      eap->init = eap_ttls_init;
 +      eap->deinit = eap_ttls_deinit;
 +      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;
 +}
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,ba82be9..ba82be9
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,9c41962..9c41962
mode 000000,100644..100644
--- /dev/null
index 0000000,2880870..2880870
mode 000000,100644..100644
--- /dev/null
index 0000000,0c0e435..0c0e435
mode 000000,100644..100644
--- /dev/null
index 0000000,dc7b2a7..dc7b2a7
mode 000000,100644..100644
--- /dev/null
index 0000000,e2133f5..e2133f5
mode 000000,100644..100644
--- /dev/null
index 0000000,6735389..6735389
mode 000000,100644..100644
--- /dev/null
index 0000000,d090718..d090718
mode 000000,100644..100644
--- /dev/null
index 0000000,4d0cd9f..4d0cd9f
mode 000000,100644..100644
--- /dev/null
index 0000000,8ddcc61..8ddcc61
mode 000000,100644..100644
--- /dev/null
index 0000000,f6c7be9..f6c7be9
mode 000000,100644..100644
--- /dev/null
index 0000000,3a87c0b..3a87c0b
mode 000000,100644..100644
--- /dev/null
index 0000000,5a92d2c..5a92d2c
mode 000000,100644..100644
--- /dev/null
index 0000000,4670d89..4670d89
mode 000000,100644..100644
--- /dev/null
index 0000000,9fe32b8..9fe32b8
mode 000000,100644..100644
--- /dev/null
index 0000000,55fa694..55fa694
mode 000000,100644..100644
--- /dev/null
index 0000000,1162de4..1162de4
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,9c41962..9c41962
mode 000000,100644..100644
--- /dev/null
index 0000000,cf43c59..cf43c59
mode 000000,100644..100644
--- /dev/null
index 0000000,773c930..773c930
mode 000000,100644..100644
--- /dev/null
index 0000000,ef74430..ef74430
mode 000000,100644..100644
--- /dev/null
index 0000000,064417e..064417e
mode 000000,100644..100644
--- /dev/null
index 0000000,bdad3a5..bdad3a5
mode 000000,100644..100644
--- /dev/null
index 0000000,9a8d923..9a8d923
mode 000000,100644..100644
--- /dev/null
index 0000000,ea318ea..ea318ea
mode 000000,100644..100644
--- /dev/null
index 0000000,fbe05dc..fbe05dc
mode 000000,100644..100644
--- /dev/null
index 0000000,295b823..295b823
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,b7d991b..b7d991b
mode 000000,100644..100644
--- /dev/null
index 0000000,ce731d4..ce731d4
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,722c20a..722c20a
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,8dcec39..8dcec39
mode 000000,100644..100644
--- /dev/null
index 0000000,7050a20..7050a20
mode 000000,100644..100644
--- /dev/null
index 0000000,9ce1a5c..9ce1a5c
mode 000000,100644..100644
--- /dev/null
index 0000000,aed3970..aed3970
mode 000000,100644..100644
--- /dev/null
index 0000000,59ba4d1..59ba4d1
mode 000000,100644..100644
--- /dev/null
index 0000000,9cf6152..9cf6152
mode 000000,100644..100644
--- /dev/null
index 0000000,aaa0eed..aaa0eed
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 2868df7,0000000..13aa941
mode 100644,000000..100644
--- /dev/null
@@@ -1,486 -1,0 +1,568 @@@
-  * 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.
 +/*
 + * wpa_supplicant/hostapd / common helper functions, etc.
 + * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
 + *
- #ifdef CONFIG_TI_COMPILER
- #define __BIG_ENDIAN 4321
- #define __LITTLE_ENDIAN 1234
- #ifdef __big_endian__
- #define __BYTE_ORDER __BIG_ENDIAN
- #else
- #define __BYTE_ORDER __LITTLE_ENDIAN
- #endif
- #endif /* CONFIG_TI_COMPILER */
- #ifdef __SYMBIAN32__
- #define __BIG_ENDIAN 4321
- #define __LITTLE_ENDIAN 1234
- #define __BYTE_ORDER __LITTLE_ENDIAN
- #endif /* __SYMBIAN32__ */
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef COMMON_H
 +#define COMMON_H
 +
 +#include "os.h"
 +
 +#if defined(__linux__) || defined(__GLIBC__)
 +#include <endian.h>
 +#include <byteswap.h>
 +#endif /* __linux__ */
 +
 +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
 +    defined(__OpenBSD__)
 +#include <sys/types.h>
 +#include <sys/endian.h>
 +#define __BYTE_ORDER  _BYTE_ORDER
 +#define       __LITTLE_ENDIAN _LITTLE_ENDIAN
 +#define       __BIG_ENDIAN    _BIG_ENDIAN
 +#ifdef __OpenBSD__
 +#define bswap_16 swap16
 +#define bswap_32 swap32
 +#define bswap_64 swap64
 +#else /* __OpenBSD__ */
 +#define bswap_16 bswap16
 +#define bswap_32 bswap32
 +#define bswap_64 bswap64
 +#endif /* __OpenBSD__ */
 +#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
 +      * defined(__DragonFly__) || defined(__OpenBSD__) */
 +
 +#ifdef __APPLE__
 +#include <sys/types.h>
 +#include <machine/endian.h>
 +#define __BYTE_ORDER  _BYTE_ORDER
 +#define __LITTLE_ENDIAN       _LITTLE_ENDIAN
 +#define __BIG_ENDIAN  _BIG_ENDIAN
 +static inline unsigned short bswap_16(unsigned short v)
 +{
 +      return ((v & 0xff) << 8) | (v >> 8);
 +}
 +
 +static inline unsigned int bswap_32(unsigned int v)
 +{
 +      return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
 +              ((v & 0xff0000) >> 8) | (v >> 24);
 +}
 +#endif /* __APPLE__ */
 +
- #ifdef CONFIG_TI_COMPILER
- #ifdef _LLONG_AVAILABLE
- typedef unsigned long long u64;
- #else
- /*
-  * TODO: 64-bit variable not available. Using long as a workaround to test the
-  * build, but this will likely not work for all operations.
-  */
- typedef unsigned long u64;
- #endif
- typedef unsigned int u32;
- typedef unsigned short u16;
- typedef unsigned char u8;
- #define WPA_TYPES_DEFINED
- #endif /* CONFIG_TI_COMPILER */
- #ifdef __SYMBIAN32__
- #define __REMOVE_PLATSEC_DIAGNOSTICS__
- #include <e32def.h>
- typedef TUint64 u64;
- typedef TUint32 u32;
- typedef TUint16 u16;
- typedef TUint8 u8;
- #define WPA_TYPES_DEFINED
- #endif /* __SYMBIAN32__ */
 +#ifdef CONFIG_NATIVE_WINDOWS
 +#ifdef CONFIG_IPV6
 +#include <winsock2.h>
 +#include <ws2tcpip.h>
 +#else
 +#include <winsock.h>
 +#endif
 +
 +typedef int socklen_t;
 +
 +#ifndef MSG_DONTWAIT
 +#define MSG_DONTWAIT 0 /* not supported */
 +#endif
 +
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +
 +#ifdef _MSC_VER
 +#ifndef __cplusplus
 +#define inline __inline
 +#endif
 +
 +#undef vsnprintf
 +#define vsnprintf _vsnprintf
 +#undef close
 +#define close closesocket
 +#endif /* _MSC_VER */
 +
 +
 +/* Define platform specific integer types */
 +
 +#ifdef _MSC_VER
 +typedef UINT64 u64;
 +typedef UINT32 u32;
 +typedef UINT16 u16;
 +typedef UINT8 u8;
 +typedef INT64 s64;
 +typedef INT32 s32;
 +typedef INT16 s16;
 +typedef INT8 s8;
 +#define WPA_TYPES_DEFINED
 +#endif /* _MSC_VER */
 +
 +#ifdef __vxworks
 +typedef unsigned long long u64;
 +typedef UINT32 u32;
 +typedef UINT16 u16;
 +typedef UINT8 u8;
 +typedef long long s64;
 +typedef INT32 s32;
 +typedef INT16 s16;
 +typedef INT8 s8;
 +#define WPA_TYPES_DEFINED
 +#endif /* __vxworks */
 +
- #define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
- #define WPA_PUT_BE16(a, val)                  \
-       do {                                    \
-               (a)[0] = ((u16) (val)) >> 8;    \
-               (a)[1] = ((u16) (val)) & 0xff;  \
-       } while (0)
- #define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
- #define WPA_PUT_LE16(a, val)                  \
-       do {                                    \
-               (a)[1] = ((u16) (val)) >> 8;    \
-               (a)[0] = ((u16) (val)) & 0xff;  \
-       } while (0)
- #define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
-                        ((u32) (a)[2]))
- #define WPA_PUT_BE24(a, val)                                  \
-       do {                                                    \
-               (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff);   \
-               (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);    \
-               (a)[2] = (u8) (((u32) (val)) & 0xff);           \
-       } while (0)
- #define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
-                        (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
- #define WPA_PUT_BE32(a, val)                                  \
-       do {                                                    \
-               (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff);   \
-               (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff);   \
-               (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff);    \
-               (a)[3] = (u8) (((u32) (val)) & 0xff);           \
-       } while (0)
- #define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
-                        (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
- #define WPA_PUT_LE32(a, val)                                  \
-       do {                                                    \
-               (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff);   \
-               (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff);   \
-               (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);    \
-               (a)[0] = (u8) (((u32) (val)) & 0xff);           \
-       } while (0)
- #define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
-                        (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
-                        (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
-                        (((u64) (a)[6]) << 8) | ((u64) (a)[7]))
- #define WPA_PUT_BE64(a, val)                          \
-       do {                                            \
-               (a)[0] = (u8) (((u64) (val)) >> 56);    \
-               (a)[1] = (u8) (((u64) (val)) >> 48);    \
-               (a)[2] = (u8) (((u64) (val)) >> 40);    \
-               (a)[3] = (u8) (((u64) (val)) >> 32);    \
-               (a)[4] = (u8) (((u64) (val)) >> 24);    \
-               (a)[5] = (u8) (((u64) (val)) >> 16);    \
-               (a)[6] = (u8) (((u64) (val)) >> 8);     \
-               (a)[7] = (u8) (((u64) (val)) & 0xff);   \
-       } while (0)
- #define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
-                        (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
-                        (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
-                        (((u64) (a)[1]) << 8) | ((u64) (a)[0]))
 +#ifndef WPA_TYPES_DEFINED
 +#ifdef CONFIG_USE_INTTYPES_H
 +#include <inttypes.h>
 +#else
 +#include <stdint.h>
 +#endif
 +typedef uint64_t u64;
 +typedef uint32_t u32;
 +typedef uint16_t u16;
 +typedef uint8_t u8;
 +typedef int64_t s64;
 +typedef int32_t s32;
 +typedef int16_t s16;
 +typedef int8_t s8;
 +#define WPA_TYPES_DEFINED
 +#endif /* !WPA_TYPES_DEFINED */
 +
 +
 +/* Define platform specific byte swapping macros */
 +
 +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
 +
 +static inline unsigned short wpa_swap_16(unsigned short v)
 +{
 +      return ((v & 0xff) << 8) | (v >> 8);
 +}
 +
 +static inline unsigned int wpa_swap_32(unsigned int v)
 +{
 +      return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
 +              ((v & 0xff0000) >> 8) | (v >> 24);
 +}
 +
 +#define le_to_host16(n) (n)
 +#define host_to_le16(n) (n)
 +#define be_to_host16(n) wpa_swap_16(n)
 +#define host_to_be16(n) wpa_swap_16(n)
 +#define le_to_host32(n) (n)
++#define host_to_le32(n) (n)
 +#define be_to_host32(n) wpa_swap_32(n)
 +#define host_to_be32(n) wpa_swap_32(n)
 +
 +#define WPA_BYTE_SWAP_DEFINED
 +
 +#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */
 +
 +
 +#ifndef WPA_BYTE_SWAP_DEFINED
 +
 +#ifndef __BYTE_ORDER
 +#ifndef __LITTLE_ENDIAN
 +#ifndef __BIG_ENDIAN
 +#define __LITTLE_ENDIAN 1234
 +#define __BIG_ENDIAN 4321
 +#if defined(sparc)
 +#define __BYTE_ORDER __BIG_ENDIAN
 +#endif
 +#endif /* __BIG_ENDIAN */
 +#endif /* __LITTLE_ENDIAN */
 +#endif /* __BYTE_ORDER */
 +
 +#if __BYTE_ORDER == __LITTLE_ENDIAN
 +#define le_to_host16(n) ((__force u16) (le16) (n))
 +#define host_to_le16(n) ((__force le16) (u16) (n))
 +#define be_to_host16(n) bswap_16((__force u16) (be16) (n))
 +#define host_to_be16(n) ((__force be16) bswap_16((n)))
 +#define le_to_host32(n) ((__force u32) (le32) (n))
 +#define host_to_le32(n) ((__force le32) (u32) (n))
 +#define be_to_host32(n) bswap_32((__force u32) (be32) (n))
 +#define host_to_be32(n) ((__force be32) bswap_32((n)))
 +#define le_to_host64(n) ((__force u64) (le64) (n))
 +#define host_to_le64(n) ((__force le64) (u64) (n))
 +#define be_to_host64(n) bswap_64((__force u64) (be64) (n))
 +#define host_to_be64(n) ((__force be64) bswap_64((n)))
 +#elif __BYTE_ORDER == __BIG_ENDIAN
 +#define le_to_host16(n) bswap_16(n)
 +#define host_to_le16(n) bswap_16(n)
 +#define be_to_host16(n) (n)
 +#define host_to_be16(n) (n)
 +#define le_to_host32(n) bswap_32(n)
++#define host_to_le32(n) bswap_32(n)
 +#define be_to_host32(n) (n)
 +#define host_to_be32(n) (n)
 +#define le_to_host64(n) bswap_64(n)
 +#define host_to_le64(n) bswap_64(n)
 +#define be_to_host64(n) (n)
 +#define host_to_be64(n) (n)
 +#ifndef WORDS_BIGENDIAN
 +#define WORDS_BIGENDIAN
 +#endif
 +#else
 +#error Could not determine CPU byte order
 +#endif
 +
 +#define WPA_BYTE_SWAP_DEFINED
 +#endif /* !WPA_BYTE_SWAP_DEFINED */
 +
 +
 +/* Macros for handling unaligned memory accesses */
 +
- #define BIT(x) (1 << (x))
++static inline u16 WPA_GET_BE16(const u8 *a)
++{
++      return (a[0] << 8) | a[1];
++}
++
++static inline void WPA_PUT_BE16(u8 *a, u16 val)
++{
++      a[0] = val >> 8;
++      a[1] = val & 0xff;
++}
++
++static inline u16 WPA_GET_LE16(const u8 *a)
++{
++      return (a[1] << 8) | a[0];
++}
++
++static inline void WPA_PUT_LE16(u8 *a, u16 val)
++{
++      a[1] = val >> 8;
++      a[0] = val & 0xff;
++}
++
++static inline u32 WPA_GET_BE24(const u8 *a)
++{
++      return (a[0] << 16) | (a[1] << 8) | a[2];
++}
++
++static inline void WPA_PUT_BE24(u8 *a, u32 val)
++{
++      a[0] = (val >> 16) & 0xff;
++      a[1] = (val >> 8) & 0xff;
++      a[2] = val & 0xff;
++}
++
++static inline u32 WPA_GET_BE32(const u8 *a)
++{
++      return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3];
++}
++
++static inline void WPA_PUT_BE32(u8 *a, u32 val)
++{
++      a[0] = (val >> 24) & 0xff;
++      a[1] = (val >> 16) & 0xff;
++      a[2] = (val >> 8) & 0xff;
++      a[3] = val & 0xff;
++}
++
++static inline u32 WPA_GET_LE32(const u8 *a)
++{
++      return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
++}
++
++static inline void WPA_PUT_LE32(u8 *a, u32 val)
++{
++      a[3] = (val >> 24) & 0xff;
++      a[2] = (val >> 16) & 0xff;
++      a[1] = (val >> 8) & 0xff;
++      a[0] = val & 0xff;
++}
++
++static inline u64 WPA_GET_BE64(const u8 *a)
++{
++      return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) |
++              (((u64) a[2]) << 40) | (((u64) a[3]) << 32) |
++              (((u64) a[4]) << 24) | (((u64) a[5]) << 16) |
++              (((u64) a[6]) << 8) | ((u64) a[7]);
++}
++
++static inline void WPA_PUT_BE64(u8 *a, u64 val)
++{
++      a[0] = val >> 56;
++      a[1] = val >> 48;
++      a[2] = val >> 40;
++      a[3] = val >> 32;
++      a[4] = val >> 24;
++      a[5] = val >> 16;
++      a[6] = val >> 8;
++      a[7] = val & 0xff;
++}
++
++static inline u64 WPA_GET_LE64(const u8 *a)
++{
++      return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) |
++              (((u64) a[5]) << 40) | (((u64) a[4]) << 32) |
++              (((u64) a[3]) << 24) | (((u64) a[2]) << 16) |
++              (((u64) a[1]) << 8) | ((u64) a[0]);
++}
++
++static inline void WPA_PUT_LE64(u8 *a, u64 val)
++{
++      a[7] = val >> 56;
++      a[6] = val >> 48;
++      a[5] = val >> 40;
++      a[4] = val >> 32;
++      a[3] = val >> 24;
++      a[2] = val >> 16;
++      a[1] = val >> 8;
++      a[0] = val & 0xff;
++}
 +
 +
 +#ifndef ETH_ALEN
 +#define ETH_ALEN 6
 +#endif
++#ifndef ETH_HLEN
++#define ETH_HLEN 14
++#endif
 +#ifndef IFNAMSIZ
 +#define IFNAMSIZ 16
 +#endif
 +#ifndef ETH_P_ALL
 +#define ETH_P_ALL 0x0003
 +#endif
++#ifndef ETH_P_80211_ENCAP
++#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
++#endif
 +#ifndef ETH_P_PAE
 +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
 +#endif /* ETH_P_PAE */
 +#ifndef ETH_P_EAPOL
 +#define ETH_P_EAPOL ETH_P_PAE
 +#endif /* ETH_P_EAPOL */
 +#ifndef ETH_P_RSN_PREAUTH
 +#define ETH_P_RSN_PREAUTH 0x88c7
 +#endif /* ETH_P_RSN_PREAUTH */
 +#ifndef ETH_P_RRB
 +#define ETH_P_RRB 0x890D
 +#endif /* ETH_P_RRB */
 +
 +
 +#ifdef __GNUC__
 +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b))))
 +#define STRUCT_PACKED __attribute__ ((packed))
 +#define UNUSED __attribute__ ((unused))
 +#else
 +#define PRINTF_FORMAT(a,b)
 +#define STRUCT_PACKED
 +#define UNUSED
 +#endif
 +
 +
 +#ifdef CONFIG_ANSI_C_EXTRA
 +
 +#if !defined(_MSC_VER) || _MSC_VER < 1400
 +/* snprintf - used in number of places; sprintf() is _not_ a good replacement
 + * due to possible buffer overflow; see, e.g.,
 + * http://www.ijs.si/software/snprintf/ for portable implementation of
 + * snprintf. */
 +int snprintf(char *str, size_t size, const char *format, ...);
 +
 +/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */
 +int vsnprintf(char *str, size_t size, const char *format, va_list ap);
 +#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */
 +
 +/* getopt - only used in main.c */
 +int getopt(int argc, char *const argv[], const char *optstring);
 +extern char *optarg;
 +extern int optind;
 +
 +#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF
 +#ifndef __socklen_t_defined
 +typedef int socklen_t;
 +#endif
 +#endif
 +
 +/* inline - define as __inline or just define it to be empty, if needed */
 +#ifdef CONFIG_NO_INLINE
 +#define inline
 +#else
 +#define inline __inline
 +#endif
 +
 +#ifndef __func__
 +#define __func__ "__func__ not defined"
 +#endif
 +
 +#ifndef bswap_16
 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff))
 +#endif
 +
 +#ifndef bswap_32
 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \
 +                   (((u32) (a) << 8) & 0xff0000) | \
 +                   (((u32) (a) >> 8) & 0xff00) | \
 +                   (((u32) (a) >> 24) & 0xff))
 +#endif
 +
 +#ifndef MSG_DONTWAIT
 +#define MSG_DONTWAIT 0
 +#endif
 +
 +#ifdef _WIN32_WCE
 +void perror(const char *s);
 +#endif /* _WIN32_WCE */
 +
 +#endif /* CONFIG_ANSI_C_EXTRA */
 +
 +#ifndef MAC2STR
 +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
 +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
++
++/*
++ * Compact form for string representation of MAC address
++ * To be used, e.g., for constructing dbus paths for P2P Devices
++ */
++#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x"
 +#endif
 +
 +#ifndef BIT
++#define BIT(x) (1U << (x))
 +#endif
 +
 +/*
 + * Definitions for sparse validation
 + * (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
 + */
 +#ifdef __CHECKER__
 +#define __force __attribute__((force))
 +#define __bitwise __attribute__((bitwise))
 +#else
 +#define __force
 +#define __bitwise
 +#endif
 +
 +typedef u16 __bitwise be16;
 +typedef u16 __bitwise le16;
 +typedef u32 __bitwise be32;
 +typedef u32 __bitwise le32;
 +typedef u64 __bitwise be64;
 +typedef u64 __bitwise le64;
 +
 +#ifndef __must_check
 +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
 +#define __must_check __attribute__((__warn_unused_result__))
 +#else
 +#define __must_check
 +#endif /* __GNUC__ */
 +#endif /* __must_check */
 +
++#ifndef __maybe_unused
++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
++#define __maybe_unused __attribute__((unused))
++#else
++#define __maybe_unused
++#endif /* __GNUC__ */
++#endif /* __must_check */
++
 +int hwaddr_aton(const char *txt, u8 *addr);
++int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable);
++int hwaddr_compact_aton(const char *txt, u8 *addr);
 +int hwaddr_aton2(const char *txt, u8 *addr);
++int hex2byte(const char *hex);
 +int hexstr2bin(const char *hex, u8 *buf, size_t len);
 +void inc_byte_array(u8 *counter, size_t len);
 +void wpa_get_ntp_timestamp(u8 *buf);
++int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
++int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len,
++                       char sep);
 +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
 +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
 +                             size_t len);
 +
++int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask);
++
 +#ifdef CONFIG_NATIVE_WINDOWS
 +void wpa_unicode2ascii_inplace(TCHAR *str);
 +TCHAR * wpa_strdup_tchar(const char *str);
 +#else /* CONFIG_NATIVE_WINDOWS */
 +#define wpa_unicode2ascii_inplace(s) do { } while (0)
 +#define wpa_strdup_tchar(s) strdup((s))
 +#endif /* CONFIG_NATIVE_WINDOWS */
 +
++void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len);
++size_t printf_decode(u8 *buf, size_t maxlen, const char *str);
++
 +const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
 +
++char * wpa_config_parse_string(const char *value, size_t *len);
++int is_hex(const u8 *data, size_t len);
++size_t merge_byte_arrays(u8 *res, size_t res_len,
++                       const u8 *src1, size_t src1_len,
++                       const u8 *src2, size_t src2_len);
++char * dup_binstr(const void *src, size_t len);
++
 +static inline int is_zero_ether_addr(const u8 *a)
 +{
 +      return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
 +}
 +
++static inline int is_broadcast_ether_addr(const u8 *a)
++{
++      return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
++}
++
++static inline int is_multicast_ether_addr(const u8 *a)
++{
++      return a[0] & 0x01;
++}
++
++#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
++
 +#include "wpa_debug.h"
 +
 +
++struct wpa_freq_range_list {
++      struct wpa_freq_range {
++              unsigned int min;
++              unsigned int max;
++      } *range;
++      unsigned int num;
++};
++
++int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value);
++int freq_range_list_includes(const struct wpa_freq_range_list *list,
++                           unsigned int freq);
++char * freq_range_list_str(const struct wpa_freq_range_list *list);
++
++int int_array_len(const int *a);
++void int_array_concat(int **res, const int *a);
++void int_array_sort_unique(int *a);
++void int_array_add_unique(int **res, int a);
++
++#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
++
++void str_clear_free(char *str);
++void bin_clear_free(void *bin, size_t len);
++
++int random_mac_addr(u8 *addr);
++int random_mac_addr_keep_oui(u8 *addr);
++
++const char * cstr_token(const char *str, const char *delim, const char **last);
++char * str_token(char *str, const char *delim, char **context);
++size_t utf8_escape(const char *inp, size_t in_size,
++                 char *outp, size_t out_size);
++size_t utf8_unescape(const char *inp, size_t in_size,
++                   char *outp, size_t out_size);
++int is_ctrl_char(char c);
++
++
 +/*
 + * gcc 4.4 ends up generating strict-aliasing warnings about some very common
 + * networking socket uses that do not really result in a real problem and
 + * cannot be easily avoided with union-based type-punning due to struct
 + * definitions including another struct in system header files. To avoid having
 + * to fully disable strict-aliasing warnings, provide a mechanism to hide the
 + * typecast from aliasing for now. A cleaner solution will hopefully be found
 + * in the future to handle these cases.
 + */
 +void * __hide_aliasing_typecast(void *foo);
 +#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
 +
++#ifdef CONFIG_VALGRIND
++#include <valgrind/memcheck.h>
++#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len))
++#else /* CONFIG_VALGRIND */
++#define WPA_MEM_DEFINED(ptr, len) do { } while (0)
++#endif /* CONFIG_VALGRIND */
++
 +#endif /* COMMON_H */
index 0000000,d340bfa..d340bfa
mode 000000,100644..100644
--- /dev/null
index 0000000,ad27f1c..ad27f1c
mode 000000,100644..100644
--- /dev/null
index 0000000,c2a5bca..c2a5bca
mode 000000,100644..100644
--- /dev/null
index 0000000,13173cb..13173cb
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,0613119..0613119
mode 000000,100644..100644
--- /dev/null
index 0000000,e3e46ea..e3e46ea
mode 000000,100644..100644
--- /dev/null
index 0000000,043e731..043e731
mode 000000,100644..100644
--- /dev/null
index 0000000,b3a4552..b3a4552
mode 000000,100644..100644
--- /dev/null
index 0000000,8d4399a..8d4399a
mode 000000,100644..100644
--- /dev/null
index 0000000,653eb54..653eb54
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,46cfe78..46cfe78
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,41511b9..41511b9
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0f7bf28,0000000..2dfc388
mode 100644,000000..100644
--- /dev/null
@@@ -1,266 -1,0 +1,383 @@@
-  * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
 +/*
 + * wpa_supplicant/hostapd / Debug prints
-  * 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.
++ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
 + *
- void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef WPA_DEBUG_H
 +#define WPA_DEBUG_H
 +
 +#include "wpabuf.h"
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
++extern int wpa_debug_level;
++extern int wpa_debug_show_keys;
++extern int wpa_debug_timestamp;
++
++
 +/* Debugging function - conditional printf and hex dump. Driver wrappers can
 + * use these for debugging purposes. */
 +
 +enum {
 +      MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
 +};
 +
 +#ifdef CONFIG_NO_STDOUT_DEBUG
 +
 +#define wpa_debug_print_timestamp() do { } while (0)
 +#define wpa_printf(args...) do { } while (0)
 +#define wpa_hexdump(l,t,b,le) do { } while (0)
 +#define wpa_hexdump_buf(l,t,b) do { } while (0)
 +#define wpa_hexdump_key(l,t,b,le) do { } while (0)
 +#define wpa_hexdump_buf_key(l,t,b) do { } while (0)
 +#define wpa_hexdump_ascii(l,t,b,le) do { } while (0)
 +#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
 +#define wpa_debug_open_file(p) do { } while (0)
 +#define wpa_debug_close_file() do { } while (0)
++#define wpa_debug_setup_stdout() do { } while (0)
++#define wpa_dbg(args...) do { } while (0)
++
++static inline int wpa_debug_reopen_file(void)
++{
++      return 0;
++}
 +
 +#else /* CONFIG_NO_STDOUT_DEBUG */
 +
 +int wpa_debug_open_file(const char *path);
++int wpa_debug_reopen_file(void);
 +void wpa_debug_close_file(void);
++void wpa_debug_setup_stdout(void);
 +
 +/**
 + * wpa_debug_printf_timestamp - Print timestamp for debug output
 + *
 + * This function prints a timestamp in seconds_from_1970.microsoconds
 + * format if debug output has been configured to include timestamps in debug
 + * messages.
 + */
 +void wpa_debug_print_timestamp(void);
 +
 +/**
 + * wpa_printf - conditional printf
 + * @level: priority level (MSG_*) of the message
 + * @fmt: printf format string, followed by optional arguments
 + *
 + * This function is used to print conditional debugging and error messages. The
 + * output may be directed to stdout, stderr, and/or syslog based on
 + * configuration.
 + *
 + * Note: New line '\n' is added to the end of the text when printing to stdout.
 + */
 +void wpa_printf(int level, const char *fmt, ...)
 +PRINTF_FORMAT(2, 3);
 +
 +/**
 + * wpa_hexdump - conditional hex dump
 + * @level: priority level (MSG_*) of the message
 + * @title: title of for the message
 + * @buf: data buffer to be dumped
 + * @len: length of the buf
 + *
 + * This function is used to print conditional debugging and error messages. The
 + * output may be directed to stdout, stderr, and/or syslog based on
 + * configuration. The contents of buf is printed out has hex dump.
 + */
-       wpa_hexdump(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf));
++void wpa_hexdump(int level, const char *title, const void *buf, size_t len);
 +
 +static inline void wpa_hexdump_buf(int level, const char *title,
 +                                 const struct wpabuf *buf)
 +{
- void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
++//!!LOCAL     wpa_hexdump(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf));
++
++      wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL,
++                  buf ? wpabuf_len(buf) : 0);
 +}
 +
 +/**
 + * wpa_hexdump_key - conditional hex dump, hide keys
 + * @level: priority level (MSG_*) of the message
 + * @title: title of for the message
 + * @buf: data buffer to be dumped
 + * @len: length of the buf
 + *
 + * This function is used to print conditional debugging and error messages. The
 + * output may be directed to stdout, stderr, and/or syslog based on
 + * configuration. The contents of buf is printed out has hex dump. This works
 + * like wpa_hexdump(), but by default, does not include secret keys (passwords,
 + * etc.) in debug output.
 + */
-       wpa_hexdump_key(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf));
++void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len);
 +
 +static inline void wpa_hexdump_buf_key(int level, const char *title,
 +                                     const struct wpabuf *buf)
 +{
- void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
++//!! LOCAL    wpa_hexdump_key(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf));
++
++      wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL,
++                      buf ? wpabuf_len(buf) : 0);
 +}
 +
 +/**
 + * wpa_hexdump_ascii - conditional hex dump
 + * @level: priority level (MSG_*) of the message
 + * @title: title of for the message
 + * @buf: data buffer to be dumped
 + * @len: length of the buf
 + *
 + * This function is used to print conditional debugging and error messages. The
 + * output may be directed to stdout, stderr, and/or syslog based on
 + * configuration. The contents of buf is printed out has hex dump with both
 + * the hex numbers and ASCII characters (for printable range) are shown. 16
 + * bytes per line will be shown.
 + */
- void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
++void wpa_hexdump_ascii(int level, const char *title, const void *buf,
 +                     size_t len);
 +
 +/**
 + * wpa_hexdump_ascii_key - conditional hex dump, hide keys
 + * @level: priority level (MSG_*) of the message
 + * @title: title of for the message
 + * @buf: data buffer to be dumped
 + * @len: length of the buf
 + *
 + * This function is used to print conditional debugging and error messages. The
 + * output may be directed to stdout, stderr, and/or syslog based on
 + * configuration. The contents of buf is printed out has hex dump with both
 + * the hex numbers and ASCII characters (for printable range) are shown. 16
 + * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
 + * default, does not include secret keys (passwords, etc.) in debug output.
 + */
- typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
-                               size_t len);
++void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
 +                         size_t len);
 +
++/*
++ * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce
++ * binary size. As such, it should be used with debugging messages that are not
++ * needed in the control interface while wpa_msg() has to be used for anything
++ * that needs to shown to control interface monitors.
++ */
++#define wpa_dbg(args...) wpa_msg(args)
++
 +#endif /* CONFIG_NO_STDOUT_DEBUG */
 +
 +
 +#ifdef CONFIG_NO_WPA_MSG
 +#define wpa_msg(args...) do { } while (0)
 +#define wpa_msg_ctrl(args...) do { } while (0)
++#define wpa_msg_global(args...) do { } while (0)
++#define wpa_msg_global_ctrl(args...) do { } while (0)
++#define wpa_msg_no_global(args...) do { } while (0)
++#define wpa_msg_global_only(args...) do { } while (0)
 +#define wpa_msg_register_cb(f) do { } while (0)
++#define wpa_msg_register_ifname_cb(f) do { } while (0)
 +#else /* CONFIG_NO_WPA_MSG */
 +/**
 + * wpa_msg - Conditional printf for default target and ctrl_iface monitors
 + * @ctx: Pointer to context data; this is the ctx variable registered
 + *    with struct wpa_driver_ops::init()
 + * @level: priority level (MSG_*) of the message
 + * @fmt: printf format string, followed by optional arguments
 + *
 + * This function is used to print conditional debugging and error messages. The
 + * output may be directed to stdout, stderr, and/or syslog based on
 + * configuration. This function is like wpa_printf(), but it also sends the
 + * same message to all attached ctrl_iface monitors.
 + *
 + * Note: New line '\n' is added to the end of the text when printing to stdout.
 + */
 +void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
 +
 +/**
 + * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors
 + * @ctx: Pointer to context data; this is the ctx variable registered
 + *    with struct wpa_driver_ops::init()
 + * @level: priority level (MSG_*) of the message
 + * @fmt: printf format string, followed by optional arguments
 + *
 + * This function is used to print conditional debugging and error messages.
 + * This function is like wpa_msg(), but it sends the output only to the
 + * attached ctrl_iface monitors. In other words, it can be used for frequent
 + * events that do not need to be sent to syslog.
 + */
 +void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
 +PRINTF_FORMAT(3, 4);
 +
- #endif /* CONFIG_NO_WPA_MSG */
++/**
++ * wpa_msg_global - Global printf for ctrl_iface monitors
++ * @ctx: Pointer to context data; this is the ctx variable registered
++ *    with struct wpa_driver_ops::init()
++ * @level: priority level (MSG_*) of the message
++ * @fmt: printf format string, followed by optional arguments
++ *
++ * This function is used to print conditional debugging and error messages.
++ * This function is like wpa_msg(), but it sends the output as a global event,
++ * i.e., without being specific to an interface. For backwards compatibility,
++ * an old style event is also delivered on one of the interfaces (the one
++ * specified by the context data).
++ */
++void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
++PRINTF_FORMAT(3, 4);
++
++/**
++ * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors
++ * @ctx: Pointer to context data; this is the ctx variable registered
++ *    with struct wpa_driver_ops::init()
++ * @level: priority level (MSG_*) of the message
++ * @fmt: printf format string, followed by optional arguments
++ *
++ * This function is used to print conditional debugging and error messages.
++ * This function is like wpa_msg_global(), but it sends the output only to the
++ * attached global ctrl_iface monitors. In other words, it can be used for
++ * frequent events that do not need to be sent to syslog.
++ */
++void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
++PRINTF_FORMAT(3, 4);
++
++/**
++ * wpa_msg_no_global - Conditional printf for ctrl_iface monitors
++ * @ctx: Pointer to context data; this is the ctx variable registered
++ *    with struct wpa_driver_ops::init()
++ * @level: priority level (MSG_*) of the message
++ * @fmt: printf format string, followed by optional arguments
++ *
++ * This function is used to print conditional debugging and error messages.
++ * This function is like wpa_msg(), but it does not send the output as a global
++ * event.
++ */
++void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
++PRINTF_FORMAT(3, 4);
++
++/**
++ * wpa_msg_global_only - Conditional printf for ctrl_iface monitors
++ * @ctx: Pointer to context data; this is the ctx variable registered
++ *    with struct wpa_driver_ops::init()
++ * @level: priority level (MSG_*) of the message
++ * @fmt: printf format string, followed by optional arguments
++ *
++ * This function is used to print conditional debugging and error messages.
++ * This function is like wpa_msg_global(), but it sends the output only as a
++ * global event.
++ */
++void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...)
++PRINTF_FORMAT(3, 4);
++
++enum wpa_msg_type {
++      WPA_MSG_PER_INTERFACE,
++      WPA_MSG_GLOBAL,
++      WPA_MSG_NO_GLOBAL,
++      WPA_MSG_ONLY_GLOBAL,
++};
++
++typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type,
++                              const char *txt, size_t len);
 +
 +/**
 + * wpa_msg_register_cb - Register callback function for wpa_msg() messages
 + * @func: Callback function (%NULL to unregister)
 + */
 +void wpa_msg_register_cb(wpa_msg_cb_func func);
 +
++typedef const char * (*wpa_msg_get_ifname_func)(void *ctx);
++void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func);
++
++#endif /* CONFIG_NO_WPA_MSG */
 +
 +#ifdef CONFIG_NO_HOSTAPD_LOGGER
 +#define hostapd_logger(args...) do { } while (0)
 +#define hostapd_logger_register_cb(f) do { } while (0)
 +#else /* CONFIG_NO_HOSTAPD_LOGGER */
 +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
 +                  const char *fmt, ...) PRINTF_FORMAT(5, 6);
 +
 +typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr,
 +                                     unsigned int module, int level,
 +                                     const char *txt, size_t len);
 +
 +/**
 + * hostapd_logger_register_cb - Register callback function for hostapd_logger()
 + * @func: Callback function (%NULL to unregister)
 + */
 +void hostapd_logger_register_cb(hostapd_logger_cb_func func);
 +#endif /* CONFIG_NO_HOSTAPD_LOGGER */
 +
 +#define HOSTAPD_MODULE_IEEE80211      0x00000001
 +#define HOSTAPD_MODULE_IEEE8021X      0x00000002
 +#define HOSTAPD_MODULE_RADIUS         0x00000004
 +#define HOSTAPD_MODULE_WPA            0x00000008
 +#define HOSTAPD_MODULE_DRIVER         0x00000010
 +#define HOSTAPD_MODULE_IAPP           0x00000020
 +#define HOSTAPD_MODULE_MLME           0x00000040
 +
 +enum hostapd_logger_level {
 +      HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
 +      HOSTAPD_LEVEL_DEBUG = 1,
 +      HOSTAPD_LEVEL_INFO = 2,
 +      HOSTAPD_LEVEL_NOTICE = 3,
 +      HOSTAPD_LEVEL_WARNING = 4
 +};
 +
 +
 +#ifdef CONFIG_DEBUG_SYSLOG
 +
 +void wpa_debug_open_syslog(void);
 +void wpa_debug_close_syslog(void);
 +
 +#else /* CONFIG_DEBUG_SYSLOG */
 +
 +static inline void wpa_debug_open_syslog(void)
 +{
 +}
 +
 +static inline void wpa_debug_close_syslog(void)
 +{
 +}
 +
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +
++#ifdef CONFIG_DEBUG_LINUX_TRACING
++
++int wpa_debug_open_linux_tracing(void);
++void wpa_debug_close_linux_tracing(void);
++
++#else /* CONFIG_DEBUG_LINUX_TRACING */
++
++static inline int wpa_debug_open_linux_tracing(void)
++{
++      return 0;
++}
++
++static inline void wpa_debug_close_linux_tracing(void)
++{
++}
++
++#endif /* CONFIG_DEBUG_LINUX_TRACING */
++
 +
 +#ifdef EAPOL_TEST
 +#define WPA_ASSERT(a)                                                \
 +      do {                                                           \
 +              if (!(a)) {                                            \
 +                      printf("WPA_ASSERT FAILED '" #a "' "           \
 +                             "%s %s:%d\n",                           \
 +                             __FUNCTION__, __FILE__, __LINE__);      \
 +                      exit(1);                                       \
 +              }                                                      \
 +      } while (0)
 +#else
 +#define WPA_ASSERT(a) do { } while (0)
 +#endif
 +
++const char * debug_level_str(int level);
++int str_to_debug_level(const char *s);
++
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* WPA_DEBUG_H */
Simple merge
index 44c0510,0000000..64b3d8d
mode 100644,000000..100644
--- /dev/null
@@@ -1,176 -1,0 +1,171 @@@
-  * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
 +/*
 + * Dynamic data buffer
-  * 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.
++ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
 + *
-       u8 *ext_data; /* pointer to external data; NULL if data follows
-                      * struct wpabuf */
++ * This software may be distributed under the terms of the BSD license.
++ * See README for more details.
 + */
 +
 +#ifndef WPABUF_H
 +#define WPABUF_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
++/* wpabuf::buf is a pointer to external data */
++#define WPABUF_FLAG_EXT_DATA BIT(0)
++
 +/*
 + * Internal data structure for wpabuf. Please do not touch this directly from
 + * elsewhere. This is only defined in header file to allow inline functions
 + * from this file to access data.
 + */
 +struct wpabuf {
 +      size_t size; /* total size of the allocated buffer */
 +      size_t used; /* length of data in the buffer */
-       if (buf->ext_data)
-               return buf->ext_data;
-       return buf + 1;
++      u8 *buf; /* pointer to the head of the buffer */
++      unsigned int flags;
 +      /* optionally followed by the allocated buffer */
 +};
 +
 +
 +int wpabuf_resize(struct wpabuf **buf, size_t add_len);
 +struct wpabuf * wpabuf_alloc(size_t len);
 +struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len);
 +struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
 +struct wpabuf * wpabuf_dup(const struct wpabuf *src);
 +void wpabuf_free(struct wpabuf *buf);
++void wpabuf_clear_free(struct wpabuf *buf);
 +void * wpabuf_put(struct wpabuf *buf, size_t len);
 +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
 +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
 +void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
 +
 +
 +/**
 + * wpabuf_size - Get the currently allocated size of a wpabuf buffer
 + * @buf: wpabuf buffer
 + * Returns: Currently allocated size of the buffer
 + */
 +static inline size_t wpabuf_size(const struct wpabuf *buf)
 +{
 +      return buf->size;
 +}
 +
 +/**
 + * wpabuf_len - Get the current length of a wpabuf buffer data
 + * @buf: wpabuf buffer
 + * Returns: Currently used length of the buffer
 + */
 +static inline size_t wpabuf_len(const struct wpabuf *buf)
 +{
 +      return buf->used;
 +}
 +
 +/**
 + * wpabuf_tailroom - Get size of available tail room in the end of the buffer
 + * @buf: wpabuf buffer
 + * Returns: Tail room (in bytes) of available space in the end of the buffer
 + */
 +static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
 +{
 +      return buf->size - buf->used;
 +}
 +
 +/**
 + * wpabuf_head - Get pointer to the head of the buffer data
 + * @buf: wpabuf buffer
 + * Returns: Pointer to the head of the buffer data
 + */
 +static inline const void * wpabuf_head(const struct wpabuf *buf)
 +{
-       if (buf->ext_data)
-               return buf->ext_data;
-       return buf + 1;
++      return buf->buf;
 +}
 +
 +static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
 +{
 +      return (const u8 *)wpabuf_head(buf);
 +}
 +
 +/**
 + * wpabuf_mhead - Get modifiable pointer to the head of the buffer data
 + * @buf: wpabuf buffer
 + * Returns: Pointer to the head of the buffer data
 + */
 +static inline void * wpabuf_mhead(struct wpabuf *buf)
 +{
-       buf->ext_data = (u8 *) data;
++      return buf->buf;
 +}
 +
 +static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
 +{
 +      return (u8 *)wpabuf_mhead(buf);
 +}
 +
 +static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
 +{
 +      u8 *pos = (u8 *)wpabuf_put(buf, 1);
 +      *pos = data;
 +}
 +
 +static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
 +{
 +      u8 *pos = (u8 *)wpabuf_put(buf, 2);
 +      WPA_PUT_LE16(pos, data);
 +}
 +
 +static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
 +{
 +      u8 *pos = (u8 *)wpabuf_put(buf, 4);
 +      WPA_PUT_LE32(pos, data);
 +}
 +
 +static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
 +{
 +      u8 *pos = (u8 *)wpabuf_put(buf, 2);
 +      WPA_PUT_BE16(pos, data);
 +}
 +
 +static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
 +{
 +      u8 *pos = (u8 *)wpabuf_put(buf, 3);
 +      WPA_PUT_BE24(pos, data);
 +}
 +
 +static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
 +{
 +      u8 *pos = (u8 *)wpabuf_put(buf, 4);
 +      WPA_PUT_BE32(pos, data);
 +}
 +
 +static inline void wpabuf_put_data(struct wpabuf *buf, const void *data,
 +                                 size_t len)
 +{
 +      if (data)
 +              os_memcpy(wpabuf_put(buf, len), data, len);
 +}
 +
 +static inline void wpabuf_put_buf(struct wpabuf *dst,
 +                                const struct wpabuf *src)
 +{
 +      wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src));
 +}
 +
 +static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)
 +{
++      buf->buf = (u8 *) data;
++      buf->flags = WPABUF_FLAG_EXT_DATA;
 +      buf->size = buf->used = len;
 +}
 +
 +static inline void wpabuf_put_str(struct wpabuf *dst, const char *str)
 +{
 +      wpabuf_put_data(dst, str, os_strlen(str));
 +}
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* WPABUF_H */
index 0000000,4916d29..4916d29
mode 000000,100644..100644
--- /dev/null
index 0000000,fb6208c..fb6208c
mode 000000,100644..100644
--- /dev/null
index 0000000,c928394..c928394
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,8188fe9..8188fe9
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,3506307..3506307
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,141a6f6..141a6f6
mode 000000,100644..100644
--- /dev/null
index 0000000,0eb36e5..0eb36e5
mode 000000,100644..100644
Binary files differ
index 0000000,a5fba77..a5fba77
mode 000000,100644..100644
Binary files differ
index 0000000,f5a9a57..f5a9a57
mode 000000,100644..100644
--- /dev/null
index 0000000,768b277..768b277
mode 000000,100644..100644
Binary files differ
index 0000000,eb854aa..eb854aa
mode 000000,100644..100644
Binary files differ
index 0000000,937721c..937721c
mode 000000,100644..100644
Binary files differ
index 0000000,e68b0dc..e68b0dc
mode 000000,100644..100644
--- /dev/null
index 0000000,0d89b92..0d89b92
mode 000000,100644..100644
--- /dev/null
index 0000000,d9ee031..d9ee031
mode 000000,100644..100644
--- /dev/null
index 0000000,09d5fa0..09d5fa0
mode 000000,100644..100644
Binary files differ
index 0000000,b128893..b128893
mode 000000,100644..100644
--- /dev/null
index 0000000,7bc8325..7bc8325
mode 000000,100644..100644
--- /dev/null
index 0000000,5532efe..5532efe
mode 000000,100644..100644
--- /dev/null
index 0000000,a04b886..a04b886
mode 000000,100644..100644
--- /dev/null
index 0000000,52c8e0c..52c8e0c
mode 000000,100644..100644
--- /dev/null
index 0000000,20999b9..20999b9
mode 000000,100644..100644
Binary files differ
index 0000000,33e6753..33e6753
mode 000000,100644..100644
Binary files differ
index 0000000,218bd03..218bd03
mode 000000,100644..100644
Binary files differ
index 0000000,7061fd7..7061fd7
mode 000000,100644..100644
Binary files differ
index 0000000,b9fd702..b9fd702
mode 000000,100644..100644
--- /dev/null
index 0000000,4bc2e1a..4bc2e1a
mode 000000,100644..100644
--- /dev/null
index 0000000,0d50201..0d50201
mode 000000,100644..100644
Binary files differ
index 0000000,eb17d9c..eb17d9c
mode 000000,100644..100644
Binary files differ
index 0000000,953d7cb..953d7cb
mode 000000,100644..100644
Binary files differ
index 0000000,b465dcb..b465dcb
mode 000000,100644..100644
--- /dev/null
index 0000000,7a8c64c..7a8c64c
mode 000000,100644..100644
--- /dev/null
index 0000000,fe671de..fe671de
mode 000000,100644..100644
--- /dev/null
index 0000000,a338c6b..a338c6b
mode 000000,100644..100644
--- /dev/null
index 0000000,c7e27ce..c7e27ce
mode 000000,100644..100644
--- /dev/null
index 0000000,b35e0f1..b35e0f1
mode 000000,100755..100755
--- /dev/null
index 0000000,15e5856..15e5856
mode 000000,100644..100644
--- /dev/null
index 0000000,295ccd3..295ccd3
mode 000000,100644..100644
--- /dev/null
index 0000000,2396b97..2396b97
mode 000000,100644..100644
--- /dev/null
index 0000000,286fa85..286fa85
mode 000000,100644..100644
--- /dev/null
index 0000000,22d0ff6..22d0ff6
mode 000000,100644..100644
--- /dev/null
index 0000000,ce455b1..ce455b1
mode 000000,100644..100644
--- /dev/null
index 0000000,b39390d..b39390d
mode 000000,100644..100644
--- /dev/null
index 0000000,33cfa62..33cfa62
mode 000000,100644..100644
--- /dev/null
index 0000000,b0e905b..b0e905b
mode 000000,100644..100644
--- /dev/null
index 0000000,3155e26..3155e26
mode 000000,100644..100644
--- /dev/null
index 0000000,75ac704..75ac704
mode 000000,100644..100644
--- /dev/null
index 0000000,7644f89..7644f89
mode 000000,100644..100644
--- /dev/null
index 0000000,e21c814..e21c814
mode 000000,100644..100644
--- /dev/null
index 0000000,85f54a2..85f54a2
mode 000000,100644..100644
--- /dev/null
index 0000000,4e1db46..4e1db46
mode 000000,100644..100644
--- /dev/null
index 0000000,64584b6..64584b6
mode 000000,100644..100644
--- /dev/null
index 0000000,82b6fa2..82b6fa2
mode 000000,100644..100644
--- /dev/null
index 0000000,440c820..440c820
mode 000000,100644..100644
--- /dev/null
index 0000000,9482bdc..9482bdc
mode 000000,100644..100644
--- /dev/null
index 0000000,3622b15..3622b15
mode 000000,100644..100644
--- /dev/null
index 0000000,eda52e1..eda52e1
mode 000000,100644..100644
--- /dev/null
index 0000000,300681a..300681a
mode 000000,100644..100644
--- /dev/null
index 0000000,cf73f4f..cf73f4f
mode 000000,100755..100755
--- /dev/null
index 0000000,5cf56a9..5cf56a9
mode 000000,100755..100755
--- /dev/null
index 0000000,13e360b..13e360b
mode 000000,100755..100755
--- /dev/null
index 0000000,f71f64f..f71f64f
mode 000000,100755..100755
--- /dev/null
index 0000000,5d23b5b..5d23b5b
mode 000000,100755..100755
--- /dev/null
index 0000000,a4a4e30..a4a4e30
mode 000000,100644..100644
--- /dev/null
index 0000000,9d4e868..9d4e868
mode 000000,100644..100644
--- /dev/null
index 0000000,aec70f7..aec70f7
mode 000000,100644..100644
--- /dev/null
index 0000000,c88e517..c88e517
mode 000000,100644..100644
--- /dev/null
index 0000000,19eb9c4..19eb9c4
mode 000000,100644..100644
--- /dev/null
index 0000000,f7d910e..f7d910e
mode 000000,100644..100644
--- /dev/null
index 0000000,f95966c..f95966c
mode 000000,100644..100644
--- /dev/null
index 0000000,27f9e87..27f9e87
mode 000000,100644..100644
--- /dev/null
index 0000000,8a8aa9f..8a8aa9f
mode 000000,100644..100644
--- /dev/null
index 0000000,c342d39..c342d39
mode 000000,100644..100644
--- /dev/null
index 0000000,139756e..139756e
mode 000000,100644..100644
--- /dev/null
index 0000000,517f2a7..517f2a7
mode 000000,100644..100644
--- /dev/null
index 0000000,62306b5..62306b5
mode 000000,100644..100644
--- /dev/null
index 0000000,281d54b..281d54b
mode 000000,100644..100644
--- /dev/null
index 0000000,67604b2..67604b2
mode 000000,100644..100644
--- /dev/null
index 0000000,f41e272..f41e272
mode 000000,100644..100644
--- /dev/null
index 0000000,bcfa3cc..bcfa3cc
mode 000000,100644..100644
--- /dev/null
index 0000000,5ca2b60..5ca2b60
mode 000000,100644..100644
--- /dev/null
index 0000000,d883114..d883114
mode 000000,100644..100644
--- /dev/null
index 0000000,822bf99..822bf99
mode 000000,100644..100644
--- /dev/null
index 0000000,1561792..1561792
mode 000000,100644..100644
--- /dev/null
index 0000000,97d29e9..97d29e9
mode 000000,100644..100644
--- /dev/null
index 0000000,c73fdeb..c73fdeb
mode 000000,100644..100644
--- /dev/null
index 0000000,e67ad98..e67ad98
mode 000000,100644..100644
--- /dev/null
index 0000000,3f4c42b..3f4c42b
mode 000000,100644..100644
--- /dev/null
index 0000000,dba899e..dba899e
mode 000000,100644..100644
--- /dev/null
index 0000000,c7c7e19..c7c7e19
mode 000000,100644..100644
--- /dev/null
index 0000000,592736e..592736e
mode 000000,100644..100644
--- /dev/null
index 0000000,f0c8a52..f0c8a52
mode 000000,100644..100644
--- /dev/null
index 0000000,c4f2fa5..c4f2fa5
mode 000000,100644..100644
--- /dev/null
index 0000000,938cf9a..938cf9a
mode 000000,100644..100644
--- /dev/null
index 0000000,1f62db1..1f62db1
mode 000000,100644..100644
--- /dev/null
index 0000000,416d616..416d616
mode 000000,100644..100644
--- /dev/null
index 0000000,e45eca0..e45eca0
mode 000000,100644..100644
--- /dev/null
index 0000000,cb91225..cb91225
mode 000000,100644..100644
--- /dev/null
index 0000000,59faa8c..59faa8c
mode 000000,100644..100644
--- /dev/null
index 0000000,d35a4d4..d35a4d4
mode 000000,100644..100644
--- /dev/null
index 0000000,7b5ddae..7b5ddae
mode 000000,100644..100644
--- /dev/null
index 0000000,22d599b..22d599b
mode 000000,100644..100644
--- /dev/null
index 0000000,c92119b..c92119b
mode 000000,100644..100644
--- /dev/null
index 0000000,8fa80a4..8fa80a4
mode 000000,100644..100644
--- /dev/null
index 0000000,c7e6299..c7e6299
mode 000000,100644..100644
--- /dev/null
index 0000000,7385e97..7385e97
mode 000000,100644..100644
--- /dev/null
index 0000000,f86637d..f86637d
mode 000000,100644..100644
--- /dev/null
index 0000000,ea7a8f4..ea7a8f4
mode 000000,100644..100644
--- /dev/null
index 0000000,ba1e7ce..ba1e7ce
mode 000000,100644..100644
--- /dev/null
index 0000000,5f0b13b..5f0b13b
mode 000000,100644..100644
--- /dev/null
index 0000000,aac4473..aac4473
mode 000000,100644..100644
--- /dev/null
index 0000000,0899c84..0899c84
mode 000000,100644..100644
--- /dev/null
index 0000000,83eb8f4..83eb8f4
mode 000000,100644..100644
--- /dev/null
index 0000000,662285c..662285c
mode 000000,100644..100644
--- /dev/null
index 0000000,425b40f..425b40f
mode 000000,100644..100644
--- /dev/null
index 0000000,ba70f75..ba70f75
mode 000000,100644..100644
--- /dev/null
index 0000000,fa1bcc9..fa1bcc9
mode 000000,100644..100644
--- /dev/null
index 0000000,ca0479e..ca0479e
mode 000000,100644..100644
--- /dev/null
index 0000000,49c1ae4..49c1ae4
mode 000000,100644..100644
--- /dev/null
index 0000000,1a32c69..1a32c69
mode 000000,100644..100644
--- /dev/null
index 0000000,ba9e8e9..ba9e8e9
mode 000000,100644..100644
--- /dev/null
index 0000000,bd8fec0..bd8fec0
mode 000000,100644..100644
--- /dev/null
index 0000000,83bd8dd..83bd8dd
mode 000000,100644..100644
--- /dev/null
index 0000000,c30436e..c30436e
mode 000000,100644..100644
--- /dev/null
index 0000000,53de399..53de399
mode 000000,100644..100644
--- /dev/null
index 0000000,0af31da..0af31da
mode 000000,100644..100644
--- /dev/null
index 0000000,de7cde4..de7cde4
mode 000000,100644..100644
--- /dev/null
index 0000000,b6188d1..b6188d1
mode 000000,100644..100644
--- /dev/null
index 0000000,d2d5596..d2d5596
mode 000000,100644..100644
--- /dev/null
index 0000000,2f88962..2f88962
mode 000000,100644..100644
--- /dev/null
index 0000000,64ba0ca..64ba0ca
mode 000000,100644..100644
--- /dev/null
index 0000000,3818c17..3818c17
mode 000000,100644..100644
--- /dev/null
index 0000000,652888a..652888a
mode 000000,100644..100644
--- /dev/null
index 0000000,d28183a..d28183a
mode 000000,100644..100644
--- /dev/null
index 0000000,0f4f9c8..0f4f9c8
mode 000000,100644..100644
--- /dev/null
index 0000000,613783a..613783a
mode 000000,100644..100644
--- /dev/null
index 0000000,ee70cfd..ee70cfd
mode 000000,100644..100644
--- /dev/null
index 0000000,daed84f..daed84f
mode 000000,100644..100644
--- /dev/null
index 0000000,b1ce1b1..b1ce1b1
mode 000000,100644..100644
--- /dev/null
index 0000000,8fef72c..8fef72c
mode 000000,100644..100644
--- /dev/null
index 0000000,e67ef2e..e67ef2e
mode 000000,100755..100755
--- /dev/null
index 0000000,e64e44f..e64e44f
mode 000000,100644..100644
--- /dev/null
index 0000000,ffab4ee..ffab4ee
mode 000000,100755..100755
--- /dev/null
index 0000000,08fc7a9..08fc7a9
mode 000000,100644..100644
--- /dev/null
index 0000000,40ab5e3..40ab5e3
mode 000000,100755..100755
--- /dev/null
index 0000000,b2fd078..b2fd078
mode 000000,100755..100755
--- /dev/null
index 0000000,d52f7fc..d52f7fc
mode 000000,100755..100755
--- /dev/null
index 0000000,9993043..9993043
mode 000000,100755..100755
--- /dev/null
index 0000000,ac7c259..ac7c259
mode 000000,100644..100644
Binary files differ
index 0000000,5f6b4ac..5f6b4ac
mode 000000,100644..100644
--- /dev/null
index 0000000,8e79c8b..8e79c8b
mode 000000,100644..100644
--- /dev/null
index 0000000,fca2871..fca2871
mode 000000,100644..100644
Binary files differ
index 0000000,407cf41..407cf41
mode 000000,100644..100644
Binary files differ
index 0000000,4f81ef1..4f81ef1
mode 000000,100644..100644
--- /dev/null
index 0000000,ed06834..ed06834
mode 000000,100644..100644
Binary files differ
index 0000000,5991f3e..5991f3e
mode 000000,100644..100644
Binary files differ
index 0000000,dcc1d72..dcc1d72
mode 000000,100644..100644
--- /dev/null
index 0000000,7e1b6d9..7e1b6d9
mode 000000,100644..100644
Binary files differ
index 0000000,8541652..8541652
mode 000000,100644..100644
Binary files differ
index 0000000,8d997d1..8d997d1
mode 000000,100644..100644
Binary files differ
Simple merge
Simple merge
Simple merge
index 0000000,a72e56f..a72e56f
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,99f5592..99f5592
mode 000000,100644..100644
--- /dev/null
index 0000000,6fad5b1..6fad5b1
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,dede75b..dede75b
mode 000000,100644..100644
--- /dev/null
index 0000000,14510bb..14510bb
mode 000000,100644..100644
Binary files differ
index 0000000,8efa311..8efa311
mode 000000,100644..100644
--- /dev/null
index 0000000,c234d3a..c234d3a
mode 000000,100644..100644
Binary files differ
index 0000000,320fdbb..320fdbb
mode 000000,100644..100644
--- /dev/null
index 0000000,bda8036..bda8036
mode 000000,100644..100644
--- /dev/null
index 0000000,f021956..f021956
mode 000000,100644..100644
--- /dev/null
index 0000000,ee1f1a6..ee1f1a6
mode 000000,100644..100644
--- /dev/null
index 0000000,adbbda5..adbbda5
mode 000000,100644..100644
--- /dev/null
index 0000000,7de0a8a..7de0a8a
mode 000000,100644..100644
--- /dev/null
index 0000000,d92f4ed..d92f4ed
mode 000000,100644..100644
--- /dev/null
index 0000000,ed25033..ed25033
mode 000000,100644..100644
--- /dev/null
index 0000000,afcc380..afcc380
mode 000000,100644..100644
--- /dev/null
index 0000000,802d0af..802d0af
mode 000000,100644..100644
--- /dev/null
index 0000000,7c3ce18..7c3ce18
mode 000000,100644..100644
--- /dev/null
index 0000000,4c55e7d..4c55e7d
mode 000000,100644..100644
--- /dev/null
index 0000000,75bfa7d..75bfa7d
mode 000000,100644..100644
--- /dev/null
index 0000000,19b338b..19b338b
mode 000000,100644..100644
--- /dev/null
index 0000000,6242bc6..6242bc6
mode 000000,100644..100644
--- /dev/null
index 0000000,0c012a9..0c012a9
mode 000000,100644..100644
--- /dev/null
index 0000000,1268b8a..1268b8a
mode 000000,100644..100644
--- /dev/null
index 0000000,36f2f5d..36f2f5d
mode 000000,100644..100644
--- /dev/null
index 0000000,ed3d601..ed3d601
mode 000000,100644..100644
--- /dev/null
index 0000000,c4137f3..c4137f3
mode 000000,100644..100644
--- /dev/null
index 0000000,77a395f..77a395f
mode 000000,100644..100644
--- /dev/null
index 0000000,ab3b2fc..ab3b2fc
mode 000000,100644..100644
--- /dev/null
index 0000000,ced9baa..ced9baa
mode 000000,100644..100644
--- /dev/null
index 0000000,ad5a48d..ad5a48d
mode 000000,100644..100644
--- /dev/null
index 0000000,1af6838..1af6838
mode 000000,100644..100644
--- /dev/null
index 0000000,28b306b..28b306b
mode 000000,100644..100644
--- /dev/null
Simple merge
index 0000000,0d818ed..0d818ed
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
index 0000000,161dc06..161dc06
mode 000000,100644..100644
--- /dev/null
index 0000000,6a5b032..6a5b032
mode 000000,100644..100644
--- /dev/null
Simple merge
index 0000000,6c3ee6d..6c3ee6d
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,a2cf7a5..a2cf7a5
mode 000000,100644..100644
--- /dev/null
index 0000000,e2a7652..e2a7652
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,80e7dfc..80e7dfc
mode 000000,100755..100755
--- /dev/null
Simple merge
index 0000000,10ecce7..10ecce7
mode 000000,100644..100644
--- /dev/null
index 0000000,ad13490..ad13490
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,fd47c17..fd47c17
mode 000000,100644..100644
--- /dev/null
index 0000000,3743dc0..3743dc0
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,77f708b..77f708b
mode 000000,100644..100644
--- /dev/null
index 0000000,3cb7f1b..3cb7f1b
mode 000000,100644..100644
--- /dev/null
index 0000000,f81b88c..f81b88c
mode 000000,100644..100644
--- /dev/null
index 0000000,7ebaef0..7ebaef0
mode 000000,100644..100644
--- /dev/null
index 0000000,747f1ae..747f1ae
mode 000000,100644..100644
--- /dev/null
index 0000000,b1471b2..b1471b2
mode 000000,100644..100644
--- /dev/null
index 0000000,11afb5b..11afb5b
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,63af83a..63af83a
mode 000000,100644..100644
--- /dev/null
index 0000000,0ad7e18..0ad7e18
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,c363b21..c363b21
mode 000000,100644..100644
--- /dev/null
index 0000000,0966bdb..0966bdb
mode 000000,100644..100644
--- /dev/null
Simple merge
index 0000000,5625d36..5625d36
mode 000000,100644..100644
--- /dev/null
index 0000000,5171b16..5171b16
mode 000000,100644..100644
--- /dev/null
index 0000000,954de67..954de67
mode 000000,100644..100644
--- /dev/null
index 0000000,8de4348..8de4348
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,354decf..354decf
mode 000000,100644..100644
--- /dev/null
index 0000000,b7236d0..b7236d0
mode 000000,100644..100644
--- /dev/null
index 0000000,9f3ca68..9f3ca68
mode 000000,100644..100644
--- /dev/null
index 0000000,843b99b..843b99b
mode 000000,100644..100644
--- /dev/null
index 0000000,5301e69..5301e69
mode 000000,100644..100644
--- /dev/null
index 0000000,7c6ac05..7c6ac05
mode 000000,100644..100644
--- /dev/null
index 0000000,6fdd565..6fdd565
mode 000000,100644..100644
--- /dev/null
index 0000000,bc920e0..bc920e0
mode 000000,100644..100644
--- /dev/null
index 0000000,4dbf765..4dbf765
mode 000000,100644..100644
--- /dev/null
index 0000000,493af7a..493af7a
mode 000000,100755..100755
--- /dev/null
index 0000000,278089b..278089b
mode 000000,100644..100644
--- /dev/null
index 0000000,2f57d74..2f57d74
mode 000000,100644..100644
--- /dev/null
index 40d937b,0000000..1e8a360
mode 100644,000000..100644
--- /dev/null
@@@ -1,449 -1,0 +1,450 @@@
 +/*
 + * 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.
 + */
 +
 +#ifndef _GSSAPIP_EAP_H_
 +#define _GSSAPIP_EAP_H_ 1
 +
 +#include "config.h"
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +#define KRB5_DEPRECATED         /* so we can use krb5_free_unparsed_name() */
 +#endif
 +
 +#include <assert.h>
 +#include <string.h>
 +#include <errno.h>
 +#ifdef HAVE_UNISTD_H
 +#include <unistd.h>
 +#endif
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STDARG_H
 +#include <stdarg.h>
 +#endif
 +#include <time.h>
 +#ifdef HAVE_SYS_PARAM_H
 +#include <sys/param.h>
 +#endif
 +
 +#ifdef WIN32
 +#ifndef MAXHOSTNAMELEN
 +# include <WinSock2.h>
 +# define MAXHOSTNAMELEN NI_MAXHOST
 +#endif
 +#endif
 +
 +/* GSS headers */
 +#include <gssapi/gssapi.h>
 +#include <gssapi/gssapi_krb5.h>
 +#ifdef HAVE_HEIMDAL_VERSION
 +typedef struct gss_any *gss_any_t;
 +#else
 +#include <gssapi/gssapi_ext.h>
 +#endif
 +#include "gssapi_eap.h"
 +
 +#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH
 +typedef const gss_OID_desc *gss_const_OID;
 +#endif
 +
 +/* Kerberos headers */
 +#include <krb5.h>
 +
 +/* EAP headers */
 +#include <includes.h>
 +#include <common.h>
 +#include <eap_peer/eap.h>
 +#include <eap_peer/eap_config.h>
 +#include <eap_peer/eap_methods.h>
 +#include <eap_common/eap_common.h>
 +#include <wpabuf.h>
 +
 +#ifdef GSSEAP_ENABLE_ACCEPTOR
 +/* libradsec headers */
 +#include <radsec/radsec.h>
 +#include <radsec/request.h>
 +#include <radsec/radius.h>
 +#endif
 +
 +#include "gsseap_err.h"
 +#include "radsec_err.h"
 +#include "util.h"
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +/* These name flags are informative and not actually used by anything yet */
 +#define NAME_FLAG_NAI                       0x00000001
 +#define NAME_FLAG_SERVICE                   0x00000002
 +#define NAME_FLAG_COMPOSITE                 0x00000004
 +
 +struct gss_eap_saml_attr_ctx;
 +struct gss_eap_attr_ctx;
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +struct gss_name_t_desc_struct
 +#else
 +struct gss_name_struct
 +#endif
 +{
 +    GSSEAP_MUTEX mutex; /* mutex protects attrCtx */
 +    OM_uint32 flags;
 +    gss_OID mechanismUsed; /* this is immutable */
 +    krb5_principal krbPrincipal; /* this is immutable */
 +#ifdef GSSEAP_ENABLE_ACCEPTOR
 +    struct gss_eap_attr_ctx *attrCtx;
 +#endif
 +};
 +
 +#define CRED_FLAG_INITIATE                  0x00010000
 +#define CRED_FLAG_ACCEPT                    0x00020000
 +#define CRED_FLAG_PASSWORD                  0x00040000
 +#define CRED_FLAG_DEFAULT_CCACHE            0x00080000
 +#define CRED_FLAG_RESOLVED                  0x00100000
 +#define CRED_FLAG_TARGET                    0x00200000
 +#define CRED_FLAG_CERTIFICATE               0x00400000
 +#define CRED_FLAG_CONFIG_BLOB               0x00800000
 +#define CRED_FLAG_PUBLIC_MASK               0x0000FFFF
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +struct gss_cred_id_t_desc_struct
 +#else
 +struct gss_cred_id_struct
 +#endif
 +{
 +    GSSEAP_MUTEX mutex;
 +    OM_uint32 flags;
 +    gss_name_t name;
 +    gss_name_t target; /* for initiator */
 +    gss_buffer_desc password;
 +    gss_OID_set mechanisms;
 +    time_t expiryTime;
 +    gss_buffer_desc radiusConfigFile;
 +    gss_buffer_desc radiusConfigStanza;
 +    gss_buffer_desc caCertificate;
 +    gss_buffer_desc subjectNameConstraint;
 +    gss_buffer_desc subjectAltNameConstraint;
 +    gss_buffer_desc clientCertificate;
 +    gss_buffer_desc privateKey;
 +    gss_buffer_desc caCertificateBlob;
 +#ifdef GSSEAP_ENABLE_REAUTH
 +    krb5_ccache krbCredCache;
 +    gss_cred_id_t reauthCred;
 +#endif
 +};
 +
 +#define CTX_FLAG_INITIATOR                  0x00000001
 +#define CTX_FLAG_KRB_REAUTH                 0x00000002
 +#define CTX_FLAG_CHANNEL_BINDINGS_VERIFIED  0x00000004
 +
 +#define CTX_IS_INITIATOR(ctx)               (((ctx)->flags & CTX_FLAG_INITIATOR) != 0)
 +
 +#define CTX_IS_ESTABLISHED(ctx)             ((ctx)->state == GSSEAP_STATE_ESTABLISHED)
 +
 +/* Initiator context flags */
 +#define CTX_FLAG_EAP_SUCCESS                0x00010000
 +#define CTX_FLAG_EAP_RESTART                0x00020000
 +#define CTX_FLAG_EAP_FAIL                   0x00040000
 +#define CTX_FLAG_EAP_RESP                   0x00080000
 +#define CTX_FLAG_EAP_NO_RESP                0x00100000
 +#define CTX_FLAG_EAP_REQ                    0x00200000
 +#define CTX_FLAG_EAP_PORT_ENABLED           0x00400000
 +#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
 +#define CONFIG_BLOB_PRIVATE_KEY             1
 +#define CONFIG_BLOB_CA_CERT                 2
 +#define CONFIG_BLOB_MAX                     3
 +
 +struct gss_eap_initiator_ctx {
 +    unsigned int idleWhile;
 +    struct eap_peer_config eapPeerConfig;
 +    struct eap_sm *eap;
 +    struct wpabuf reqData;
 +    struct wpabuf *chbindData;
 +    unsigned int chbindReqFlags;
 +    struct wpa_config_blob configBlobs[CONFIG_BLOB_MAX];
 +};
 +
 +#ifdef GSSEAP_ENABLE_ACCEPTOR
 +struct gss_eap_acceptor_ctx {
 +    struct rs_context *radContext;
 +    struct rs_connection *radConn;
 +    char *radServer;
 +    gss_buffer_desc state;
 +    rs_avp *vps;
 +};
 +#endif
 +
 +#ifdef HAVE_HEIMDAL_VERSION
 +struct gss_ctx_id_t_desc_struct
 +#else
 +struct gss_ctx_id_struct
 +#endif
 +{
 +    GSSEAP_MUTEX mutex;
 +    enum gss_eap_state state;
 +    OM_uint32 flags;
 +    OM_uint32 gssFlags;
 +    gss_OID mechanismUsed;
 +    krb5_cksumtype checksumType;
 +    krb5_enctype encryptionType;
 +    krb5_keyblock rfc3961Key;
 +    gss_name_t initiatorName;
 +    gss_name_t acceptorName;
 +    time_t expiryTime;
 +    uint64_t sendSeq, recvSeq;
 +    void *seqState;
 +    gss_cred_id_t cred;
 +    union {
 +        struct gss_eap_initiator_ctx initiator;
 +        #define initiatorCtx         ctxU.initiator
 +#ifdef GSSEAP_ENABLE_ACCEPTOR
 +        struct gss_eap_acceptor_ctx  acceptor;
 +        #define acceptorCtx          ctxU.acceptor
 +#endif
 +#ifdef GSSEAP_ENABLE_REAUTH
 +        gss_ctx_id_t                 reauth;
 +        #define reauthCtx            ctxU.reauth
 +#endif
 +    } ctxU;
 +    const struct gss_eap_token_buffer_set *inputTokens;
 +    const struct gss_eap_token_buffer_set *outputTokens;
 +};
 +
 +#define TOK_FLAG_SENDER_IS_ACCEPTOR         0x01
 +#define TOK_FLAG_WRAP_CONFIDENTIAL          0x02
 +#define TOK_FLAG_ACCEPTOR_SUBKEY            0x04
 +
 +#define KEY_USAGE_ACCEPTOR_SEAL             22
 +#define KEY_USAGE_ACCEPTOR_SIGN             23
 +#define KEY_USAGE_INITIATOR_SEAL            24
 +#define KEY_USAGE_INITIATOR_SIGN            25
 +
 +#define KEY_USAGE_GSSEAP_CHBIND_MIC         60
 +#define KEY_USAGE_GSSEAP_ACCTOKEN_MIC       61
 +#define KEY_USAGE_GSSEAP_INITOKEN_MIC       62
 +
 +/* accept_sec_context.c */
 +OM_uint32
 +gssEapAcceptSecContext(OM_uint32 *minor,
 +                       gss_ctx_id_t ctx,
 +                       gss_cred_id_t cred,
 +                       gss_buffer_t input_token,
 +                       gss_channel_bindings_t input_chan_bindings,
 +                       gss_name_t *src_name,
 +                       gss_OID *mech_type,
 +                       gss_buffer_t output_token,
 +                       OM_uint32 *ret_flags,
 +                       OM_uint32 *time_rec,
 +                       gss_cred_id_t *delegated_cred_handle);
 +
 +/* init_sec_context.c */
 +OM_uint32
 +gssEapInitSecContext(OM_uint32 *minor,
 +                     gss_cred_id_t cred,
 +                     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);
 +
 +/* wrap_iov.c */
 +OM_uint32
 +gssEapWrapOrGetMIC(OM_uint32 *minor,
 +                   gss_ctx_id_t ctx,
 +                   int conf_req_flag,
 +                   int *conf_state,
 +                   gss_iov_buffer_desc *iov,
 +                   int iov_count,
 +                   enum gss_eap_token_type toktype);
 +
 +OM_uint32
 +gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status,
 +                        gss_ctx_id_t ctx,
 +                        int *conf_state,
 +                        gss_qop_t *qop_state,
 +                        gss_iov_buffer_desc *iov,
 +                        int iov_count,
 +                        enum gss_eap_token_type toktype);
 +
 +OM_uint32
 +gssEapWrapIovLength(OM_uint32 *minor,
 +                    gss_ctx_id_t ctx,
 +                    int conf_req_flag,
 +                    gss_qop_t qop_req,
 +                    int *conf_state,
 +                    gss_iov_buffer_desc *iov,
 +                    int iov_count);
 +OM_uint32
 +gssEapWrap(OM_uint32 *minor,
 +           gss_ctx_id_t ctx,
 +           int conf_req_flag,
 +           gss_qop_t qop_req,
 +           gss_buffer_t input_message_buffer,
 +           int *conf_state,
 +           gss_buffer_t output_message_buffer);
 +
 +unsigned char
 +rfc4121Flags(gss_ctx_id_t ctx, int receiving);
 +
 +/* display_status.c */
 +void
 +gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...);
 +
 +OM_uint32
 +gssEapDisplayStatus(OM_uint32 *minor,
 +                    OM_uint32 status_value,
 +                    gss_buffer_t status_string);
 +
 +#define IS_WIRE_ERROR(err)              ((err) >= GSSEAP_RESERVED && \
 +                                         (err) <= GSSEAP_RADIUS_PROT_FAILURE)
 +
 +#ifdef GSSEAP_ENABLE_ACCEPTOR
 +#define IS_RADIUS_ERROR(err)            ((err) >= ERROR_TABLE_BASE_rse && \
 +                                         (err) <= ERROR_TABLE_BASE_rse + RSE_MAX)
 +#else
 +#define IS_RADIUS_ERROR(err)            (0)
 +#endif
 +
 +/* exchange_meta_data.c */
 +OM_uint32 GSSAPI_CALLCONV
 +gssEapExchangeMetaData(OM_uint32 *minor,
 +                       gss_const_OID mech,
 +                       gss_cred_id_t cred,
 +                       gss_ctx_id_t *ctx,
 +                       const gss_name_t name,
 +                       OM_uint32 req_flags,
 +                       gss_const_buffer_t meta_data);
 +
 +/* export_sec_context.c */
 +OM_uint32
 +gssEapExportSecContext(OM_uint32 *minor,
 +                       gss_ctx_id_t ctx,
 +                       gss_buffer_t token);
 +
 +/* import_sec_context.c */
 +OM_uint32
 +gssEapImportContext(OM_uint32 *minor,
 +                    gss_buffer_t token,
 +                    gss_ctx_id_t ctx);
 +
 +/* inquire_sec_context_by_oid.c */
 +#define NEGOEX_INITIATOR_SALT      "gss-eap-negoex-initiator"
 +#define NEGOEX_INITIATOR_SALT_LEN  (sizeof(NEGOEX_INITIATOR_SALT) - 1)
 +
 +#define NEGOEX_ACCEPTOR_SALT       "gss-eap-negoex-acceptor"
 +#define NEGOEX_ACCEPTOR_SALT_LEN   (sizeof(NEGOEX_ACCEPTOR_SALT) - 1)
 +
 +/* pseudo_random.c */
 +OM_uint32
 +gssEapPseudoRandom(OM_uint32 *minor,
 +                   gss_ctx_id_t ctx,
 +                   int prf_key,
 +                   const gss_buffer_t prf_in,
 +                   gss_buffer_t prf_out);
 +
 +/* query_mechanism_info.c */
 +OM_uint32
 +gssQueryMechanismInfo(OM_uint32 *minor,
 +                      gss_const_OID mech_oid,
 +                      unsigned char auth_scheme[16]);
 +
 +/* query_meta_data.c */
 +OM_uint32
 +gssEapQueryMetaData(OM_uint32 *minor,
 +                    gss_const_OID mech GSSEAP_UNUSED,
 +                    gss_cred_id_t cred,
 +                    gss_ctx_id_t *context_handle,
 +                    const gss_name_t name,
 +                    OM_uint32 req_flags GSSEAP_UNUSED,
 +                    gss_buffer_t meta_data);
 +
 +/* eap_mech.c */
 +OM_uint32
 +gssEapInitiatorInit(OM_uint32 *minor);
 +
 +void
 +gssEapFinalize(void);
 +
 +  /* Debugging and tracing*/
 +  #define gssEapTrace(_fmt, ...) wpa_printf(MSG_INFO, _fmt, __VA_ARGS__);
 +
 +static inline void
 +gssEapTraceStatus(const char *function,
 +                OM_uint32 major, OM_uint32 minor)
 +{
 +    gss_buffer_desc  gss_code_buf, mech_buf;
 +    OM_uint32 tmpmaj, tmpmin, ctx = 0;
 +    gss_code_buf.value = NULL;
 +    mech_buf.value = NULL;
 +    tmpmaj = gss_display_status(&tmpmin,  major,
 +                              GSS_C_GSS_CODE, GSS_C_NO_OID, &ctx,
 +                              &gss_code_buf);
 +  if (!GSS_ERROR(tmpmaj)) {
 +if (minor == 0)
 +    tmpmaj = makeStringBuffer(&tmpmin, "no minor", &mech_buf);
 +else tmpmaj = gssEapDisplayStatus(&tmpmin, minor, &mech_buf);
 +}
 +    if (!GSS_ERROR(tmpmaj))
 +      wpa_printf(MSG_INFO, "%s: %.*s/%.*s",
 +                 function, (int) gss_code_buf.length, (char *) gss_code_buf.value,
 +                 (int) mech_buf.length, (char *) mech_buf.value);
 +    else wpa_printf(MSG_INFO, "%s: %u/%u",
 +                  function, major, minor);
 +    tmpmaj = gss_release_buffer(&tmpmin, &gss_code_buf);
 +    tmpmaj = gss_release_buffer(&tmpmin, &mech_buf);
 + }
 +
 +
 +  /*If built as a library on Linux, don't respect environment when set*uid*/
 +#ifdef HAVE_SECURE_GETENV
 +#define getenv secure_getenv
 +#endif
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* _GSSAPIP_EAP_H_ */
index f6d7269,0000000..a9d8891
mode 100644,000000..100644
--- /dev/null
@@@ -1,1367 -1,0 +1,1370 @@@
-         eapPeerConfig->private_key_passwd = (unsigned char *)cred->password.value;
 +/*
 + * 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"
 +#include "radius/radius.h"
 +#include "util_radius.h"
 +#include "utils/radius_utils.h"
 +
 +/* methods allowed for phase1 authentication*/
 +static const struct eap_method_type allowed_eap_method_types[] = {
 +    {EAP_VENDOR_IETF, EAP_TYPE_TTLS},
 +    {EAP_VENDOR_IETF, EAP_TYPE_NONE}};
 +
 +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;
++    case EAPOL_eapTriggerStart:
++        flag = CTX_FLAG_EAP_TRIGGER_START;
++        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;
 +
 +    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;
 +
 +    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,
 +                  const char *name)
 +{
 +    gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx;
 +    size_t index;
 +
 +    if (strcmp(name, "client-cert") == 0)
 +        index = CONFIG_BLOB_CLIENT_CERT;
 +    else if (strcmp(name, "private-key") == 0)
 +        index = CONFIG_BLOB_PRIVATE_KEY;
 +    else if (strcmp(name, "ca-cert") == 0)
 +        index = CONFIG_BLOB_CA_CERT;
 +    else
 +        return NULL;
 +
 +    return &gssCtx->initiatorCtx.configBlobs[index];
 +}
 +
 +static void
 +peerNotifyPending(void *ctx GSSEAP_UNUSED)
 +{
 +}
 +
 +static struct eapol_callbacks gssEapPolicyCallbacks = {
 +    peerGetConfig,
 +    peerGetBool,
 +    peerSetBool,
 +    peerGetInt,
 +    peerSetInt,
 +    peerGetEapReqData,
 +    peerSetConfigBlob,
 +    peerGetConfigBlob,
 +    peerNotifyPending,
 +};
 +
 +
 +#define CHBIND_SERVICE_NAME_FLAG        0x01
 +#define CHBIND_HOST_NAME_FLAG           0x02
 +#define CHBIND_SERVICE_SPECIFIC_FLAG    0x04
 +#define CHBIND_REALM_NAME_FLAG          0x08
 +
 +static OM_uint32
 +peerInitEapChannelBinding(OM_uint32 *minor, gss_ctx_id_t ctx)
 +{
 +    struct wpabuf *buf = NULL;
 +    unsigned int chbindReqFlags = 0;
 +    krb5_principal princ = NULL;
 +    gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER;
 +    OM_uint32 major = GSS_S_COMPLETE;
 +    krb5_context krbContext = NULL;
 +
 +    /* XXX is this check redundant? */
 +    if (ctx->acceptorName == GSS_C_NO_NAME) {
 +        major = GSS_S_BAD_NAME;
 +        *minor = GSSEAP_NO_ACCEPTOR_NAME;
 +        goto cleanup;
 +    }
 +
 +    princ = ctx->acceptorName->krbPrincipal;
 +
 +    krbPrincComponentToGssBuffer(princ, 0, &nameBuf);
 +    if (nameBuf.length > 0) {
 +        major = gssEapRadiusAddAttr(minor, &buf, PW_GSS_ACCEPTOR_SERVICE_NAME,
 +                                    0, &nameBuf);
 +        if (GSS_ERROR(major))
 +            goto cleanup;
 +
 +        chbindReqFlags |= CHBIND_SERVICE_NAME_FLAG;
 +    }
 +
 +    krbPrincComponentToGssBuffer(princ, 1, &nameBuf);
 +    if (nameBuf.length > 0) {
 +        major = gssEapRadiusAddAttr(minor, &buf, PW_GSS_ACCEPTOR_HOST_NAME,
 +                                    0, &nameBuf);
 +        if (GSS_ERROR(major))
 +            goto cleanup;
 +
 +        chbindReqFlags |= CHBIND_HOST_NAME_FLAG;
 +    }
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    *minor = krbPrincUnparseServiceSpecifics(krbContext, princ, &nameBuf);
 +    if (*minor != 0)
 +        goto cleanup;
 +
 +    if (nameBuf.length > 0) {
 +        major = gssEapRadiusAddAttr(minor, &buf,
 +                                    PW_GSS_ACCEPTOR_SERVICE_SPECIFICS,
 +                                    0, &nameBuf);
 +        if (GSS_ERROR(major))
 +            goto cleanup;
 +
 +        chbindReqFlags |= CHBIND_SERVICE_SPECIFIC_FLAG;
 +    }
 +
 +    krbFreeUnparsedName(krbContext, &nameBuf);
 +    krbPrincRealmToGssBuffer(princ, &nameBuf);
 +
 +    if (nameBuf.length > 0) {
 +        major = gssEapRadiusAddAttr(minor, &buf,
 +                                    PW_GSS_ACCEPTOR_REALM_NAME,
 +                                    0, &nameBuf);
 +        if (GSS_ERROR(major))
 +            goto cleanup;
 +
 +        chbindReqFlags |= CHBIND_REALM_NAME_FLAG;
 +    }
 +
 +    if (chbindReqFlags == 0) {
 +        major = GSS_S_BAD_NAME;
 +        *minor = GSSEAP_BAD_ACCEPTOR_NAME;
 +        goto cleanup;
 +    }
 +
 +    ctx->initiatorCtx.chbindData = buf;
 +    ctx->initiatorCtx.chbindReqFlags = chbindReqFlags;
 +
 +    buf = NULL;
 +
 +    major = GSS_S_COMPLETE;
 +    *minor = 0;
 +
 +cleanup:
 +    /*namebuf is freed when used and may be left with a unowned pointer*/
 +    wpabuf_free(buf);
 +
 +    return major;
 +}
 +
 +static void
 +peerProcessChbindResponse(void *context, int code, int nsid,
 +                          u8 *data, size_t len)
 +{
 +    radius_parser msg;
 +    gss_ctx_id_t ctx = (gss_ctx_id_t )context;
 +    void *vsadata;
 +    u8 type;
 +    u32 vendor_id;
 +    u32 chbindRetFlags = 0;
 +    size_t vsadata_len;
 +
 +    if (nsid != CHBIND_NSID_RADIUS)
 +        return;
 +
 +    if (data == NULL)
 +        return;
 +    msg = radius_parser_start(data, len);
 +    if (msg == NULL)
 +        return;
 +
 +    while (radius_parser_parse_tlv(msg, &type, &vendor_id, &vsadata,
 +                                   &vsadata_len) == 0) {
 +        switch (type) {
 +        case PW_GSS_ACCEPTOR_SERVICE_NAME:
 +            chbindRetFlags |= CHBIND_SERVICE_NAME_FLAG;
 +            break;
 +        case PW_GSS_ACCEPTOR_HOST_NAME:
 +            chbindRetFlags |= CHBIND_HOST_NAME_FLAG;
 +            break;
 +        case PW_GSS_ACCEPTOR_SERVICE_SPECIFICS:
 +            chbindRetFlags |= CHBIND_SERVICE_SPECIFIC_FLAG;
 +            break;
 +        case PW_GSS_ACCEPTOR_REALM_NAME:
 +            chbindRetFlags |= CHBIND_REALM_NAME_FLAG;
 +            break;
 +        }
 +    }
 +
 +    radius_parser_finish(msg);
 +
 +    if (code == CHBIND_CODE_SUCCESS &&
 +        ((chbindRetFlags & ctx->initiatorCtx.chbindReqFlags) == ctx->initiatorCtx.chbindReqFlags)) {
 +        ctx->flags |= CTX_FLAG_EAP_CHBIND_ACCEPT;
 +        ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
 +    } /* else log failures? */
 +}
 +
 +static OM_uint32
 +peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx)
 +{
 +    OM_uint32 major;
 +    krb5_context krbContext;
 +    struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig;
 +    struct wpa_config_blob *configBlobs = ctx->initiatorCtx.configBlobs;
 +    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;
 +    eapPeerConfig->eap_methods = (struct eap_method_type *) allowed_eap_method_types;
 +
 +    GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL);
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    eapPeerConfig->fragment_size = 1024;
 +    
 +    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 */
 +    if ((cred->flags & CRED_FLAG_CERTIFICATE) == 0) {
 +        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;
 +    configBlobs[CONFIG_BLOB_CA_CERT].data = cred->caCertificateBlob.value;
 +    configBlobs[CONFIG_BLOB_CA_CERT].len = cred->caCertificateBlob.length;
 +
 +    /* eap channel binding */
 +    if (ctx->initiatorCtx.chbindData != NULL) {
 +        struct eap_peer_chbind_config *chbind_config =
 +            (struct eap_peer_chbind_config *)GSSEAP_MALLOC(sizeof(struct eap_peer_chbind_config));
 +        if (chbind_config == NULL) {
 +            *minor = ENOMEM;
 +            return GSS_S_FAILURE;
 +        }
 +
 +        chbind_config->req_data = wpabuf_mhead_u8(ctx->initiatorCtx.chbindData);
 +        chbind_config->req_data_len = wpabuf_len(ctx->initiatorCtx.chbindData);
 +        chbind_config->nsid = CHBIND_NSID_RADIUS;
 +        chbind_config->response_cb = &peerProcessChbindResponse;
 +        chbind_config->ctx = ctx;
 +        eapPeerConfig->chbind_config = chbind_config;
 +        eapPeerConfig->chbind_config_len = 1;
 +    } else {
 +        eapPeerConfig->chbind_config = NULL;
 +        eapPeerConfig->chbind_config_len = 0;
 +    }
 +    if (cred->flags & CRED_FLAG_CERTIFICATE) {
 +        /*
 +         * CRED_FLAG_CONFIG_BLOB is an internal flag which will be used in the
 +         * future to directly pass certificate and private key data to the
 +         * EAP implementation, rather than an indirected string pointer.
 +         */
 +        if (cred->flags & CRED_FLAG_CONFIG_BLOB) {
 +            eapPeerConfig->client_cert = (unsigned char *)"blob://client-cert";
 +            configBlobs[CONFIG_BLOB_CLIENT_CERT].data = cred->clientCertificate.value;
 +            configBlobs[CONFIG_BLOB_CLIENT_CERT].len  = cred->clientCertificate.length;
 +
 +            eapPeerConfig->client_cert = (unsigned char *)"blob://private-key";
 +            configBlobs[CONFIG_BLOB_PRIVATE_KEY].data = cred->clientCertificate.value;
 +            configBlobs[CONFIG_BLOB_PRIVATE_KEY].len  = cred->privateKey.length;
 +        } else {
 +            eapPeerConfig->client_cert = (unsigned char *)cred->clientCertificate.value;
 +            eapPeerConfig->private_key = (unsigned char *)cred->privateKey.value;
 +        }
++        eapPeerConfig->private_key_passwd = (char *)cred->password.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 major;
 +    const unsigned char *key;
 +    size_t keyLength;
 +
 +    /* 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,
 +          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;
 +
 +    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 =  load_uint32_be(&p[4]);
 +    if ((*minor >0) && (*minor < 128))
 +      * minor += ERROR_TABLE_BASE_eapg;
 +    else *minor = 0;
 +
 +    if (!GSS_ERROR(major) || !IS_WIRE_ERROR(*minor)) {
 +        major = GSS_S_FAILURE;
 +        *minor = GSSEAP_BAD_ERROR_TOKEN;
 +    }
 +
 +    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;
 +
 +    /*
 +     * 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) {
 +        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) {
 +        OM_uint32 tmpMinor;
 +        gss_name_t nameHint;
 +        int equal;
 +
 +        /* Accept target name hint from acceptor or verify acceptor */
 +        major = gssEapImportName(minor, inputToken,
 +                                 GSS_C_NT_USER_NAME,
 +                                 ctx->mechanismUsed,
 +                                 &nameHint);
 +        if (GSS_ERROR(major))
 +            return major;
 +
 +        if (ctx->acceptorName != GSS_C_NO_NAME) {
 +            /* verify name hint matched asserted acceptor name  */
 +            major = gssEapCompareName(minor,
 +                                      nameHint,
 +                                      ctx->acceptorName,
 +                                      COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS,
 +                                      &equal);
 +            if (GSS_ERROR(major)) {
 +                gssEapReleaseName(&tmpMinor, &nameHint);
 +                return major;
 +            }
 +
 +            gssEapReleaseName(&tmpMinor, &nameHint);
 +
 +            if (!equal) {
 +                *minor = GSSEAP_WRONG_ACCEPTOR_NAME;
 +                return GSS_S_DEFECTIVE_TOKEN;
 +            }
 +        } else { /* acceptor name is no_name */
 +            /* accept acceptor name hint */
 +            ctx->acceptorName = nameHint;
 +            nameHint = GSS_C_NO_NAME;
 +        }
 +    }
 +
 +
 +    /*
 +     * 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;
 +    }
 +
 +    /*
 +     * Generate channel binding data
 +     */
 +    if (ctx->initiatorCtx.chbindData == NULL) {
 +        major = peerInitEapChannelBinding(minor, ctx);
 +        if (GSS_ERROR(major))
 +            return major;
 +    }
 +
 +    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;
 +
 +    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,
 +                         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;
 +
 +    GSSEAP_ASSERT(inputToken != GSS_C_NO_BUFFER);
 +
 +    major = peerConfigInit(minor, ctx);
 +    if (GSS_ERROR(major))
 +        goto cleanup;
 +
 +    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;
 +
 +    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);
 +        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;
 +
 +        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;
 +
 +    /*
 +     * As a temporary measure, force mutual authentication until channel binding is
 +     * more widely deployed.
 +     */
 +    ctx->gssFlags |= GSS_C_MUTUAL_FLAG;
 +    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;
 +    krb5_error_code code;
 +    krb5_context krbContext;
 +    krb5_data data;
 +    krb5_checksum cksum;
 +    gss_buffer_desc cksumBuffer;
 +
 +    if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS ||
 +        chanBindings->application_data.length == 0)
 +        return GSS_S_CONTINUE_NEEDED;
 +
 +    GSSEAP_KRB_INIT(&krbContext);
 +
 +    KRB_DATA_INIT(&data);
 +
 +    gssBufferToKrbData(&chanBindings->application_data, &data);
 +
 +    code = krb5_c_make_checksum(krbContext, ctx->checksumType,
 +                                &ctx->rfc3961Key,
 +                                KEY_USAGE_GSSEAP_CHBIND_MIC,
 +                                &data, &cksum);
 +    if (code != 0) {
 +        *minor = code;
 +        return GSS_S_FAILURE;
 +    }
 +
 +    cksumBuffer.length = KRB_CHECKSUM_LENGTH(&cksum);
 +    cksumBuffer.value  = KRB_CHECKSUM_DATA(&cksum);
 +
 +    major = duplicateBuffer(minor, &cksumBuffer, outputToken);
 +    if (GSS_ERROR(major)) {
 +        krb5_free_checksum_contents(krbContext, &cksum);
 +        return major;
 +    }
 +
 +    *minor = 0;
 +    *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL;
 +
 +    krb5_free_checksum_contents(krbContext, &cksum);
 +
 +    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 |
 +        GSSEAP_STATE_ACCEPTOR_EXTS,
 +        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,
 +        0,
 +        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
 +gssEapInitSecContext(OM_uint32 *minor,
 +                     gss_cred_id_t cred,
 +                     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;
 +    int initialContextToken = (ctx->mechanismUsed == GSS_C_NO_OID);
 +
 +    /*
 +     * 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);
 +
 +    if (ctx->cred == GSS_C_NO_CREDENTIAL) {
 +        major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred);
 +        if (GSS_ERROR(major))
 +            goto cleanup;
 +
 +        GSSEAP_ASSERT(ctx->cred != GSS_C_NO_CREDENTIAL);
 +    }
 +
 +    GSSEAP_MUTEX_LOCK(&ctx->cred->mutex);
 +
 +    GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_RESOLVED);
 +    GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_INITIATE);
 +
 +    if (initialContextToken) {
 +        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);
 +
 +    gssEapTraceStatus( "gss_init_sec_context", major, *minor);
 +    return major;
 +}