Updated to hostap_2_6
authorDan Breslau <dbreslau@painless-security.com>
Mon, 10 Oct 2016 18:15:24 +0000 (14:15 -0400)
committerDan Breslau <dbreslau@painless-security.com>
Mon, 10 Oct 2016 18:15:24 +0000 (14:15 -0400)
553 files changed:
1  2 
.gitignore
libeap/COPYING
libeap/README
libeap/build_release
libeap/doc/ctrl_iface.doxygen
libeap/doc/dbus.doxygen
libeap/doc/doxygen.conf
libeap/doc/p2p.doxygen
libeap/hostapd/Android.mk
libeap/hostapd/ChangeLog
libeap/hostapd/Makefile
libeap/hostapd/README
libeap/hostapd/android.config
libeap/hostapd/config_file.c
libeap/hostapd/ctrl_iface.c
libeap/hostapd/defconfig
libeap/hostapd/hapd_module_tests.c
libeap/hostapd/hlr_auc_gw.c
libeap/hostapd/hostapd.conf
libeap/hostapd/hostapd_cli.c
libeap/hostapd/main.c
libeap/hs20/client/Android.mk
libeap/hs20/client/Makefile
libeap/hs20/client/est.c
libeap/hs20/client/osu_client.c
libeap/hs20/server/www/spp.php
libeap/radius_example/radius_example.c
libeap/src/ap/accounting.c
libeap/src/ap/accounting.h
libeap/src/ap/acs.c
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_mlme.c
libeap/src/ap/authsrv.c
libeap/src/ap/beacon.c
libeap/src/ap/beacon.h
libeap/src/ap/ctrl_iface_ap.c
libeap/src/ap/ctrl_iface_ap.h
libeap/src/ap/dfs.c
libeap/src/ap/dhcp_snoop.c
libeap/src/ap/drv_callbacks.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/hw_features.c
libeap/src/ap/iapp.c
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/mbo_ap.c
libeap/src/ap/mbo_ap.h
libeap/src/ap/ndisc_snoop.c
libeap/src/ap/neighbor_db.c
libeap/src/ap/neighbor_db.h
libeap/src/ap/pmksa_cache_auth.c
libeap/src/ap/pmksa_cache_auth.h
libeap/src/ap/rrm.c
libeap/src/ap/rrm.h
libeap/src/ap/sta_info.c
libeap/src/ap/sta_info.h
libeap/src/ap/taxonomy.c
libeap/src/ap/taxonomy.h
libeap/src/ap/vlan.c
libeap/src/ap/vlan.h
libeap/src/ap/vlan_full.c
libeap/src/ap/vlan_ifconfig.c
libeap/src/ap/vlan_init.c
libeap/src/ap/vlan_init.h
libeap/src/ap/vlan_ioctl.c
libeap/src/ap/vlan_util.c
libeap/src/ap/vlan_util.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_i.h
libeap/src/ap/wpa_auth_ie.c
libeap/src/ap/wps_hostapd.c
libeap/src/common/cli.c
libeap/src/common/cli.h
libeap/src/common/common_module_tests.c
libeap/src/common/ctrl_iface_common.c
libeap/src/common/ctrl_iface_common.h
libeap/src/common/defs.h
libeap/src/common/eapol_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/linux_bridge.h
libeap/src/common/linux_vlan.h
libeap/src/common/qca-vendor.h
libeap/src/common/sae.c
libeap/src/common/sae.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/crypto/Makefile
libeap/src/crypto/aes-cbc.c
libeap/src/crypto/aes-omac1.c
libeap/src/crypto/crypto.h
libeap/src/crypto/crypto_internal.c
libeap/src/crypto/crypto_module_tests.c
libeap/src/crypto/crypto_openssl.c
libeap/src/crypto/dh_group5.c
libeap/src/crypto/dh_groups.c
libeap/src/crypto/fips_prf_openssl.c
libeap/src/crypto/md4-internal.c
libeap/src/crypto/md5-internal.c
libeap/src/crypto/ms_funcs.c
libeap/src/crypto/sha1-internal.c
libeap/src/crypto/sha256-internal.c
libeap/src/crypto/sha256-prf.c
libeap/src/crypto/sha256.h
libeap/src/crypto/sha384-internal.c
libeap/src/crypto/sha384_i.h
libeap/src/crypto/sha512-internal.c
libeap/src/crypto/sha512_i.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/crypto/tls_openssl.h
libeap/src/crypto/tls_openssl_ocsp.c
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_macsec_qca.c
libeap/src/drivers/driver_ndis.c
libeap/src/drivers/driver_nl80211.c
libeap/src/drivers/driver_nl80211.h
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_privsep.c
libeap/src/drivers/driver_roboswitch.c
libeap/src/drivers/driver_wext.c
libeap/src/drivers/driver_wired.c
libeap/src/drivers/drivers.c
libeap/src/drivers/drivers.mak
libeap/src/drivers/drivers.mk
libeap/src/drivers/nl80211_copy.h
libeap/src/drivers/rfkill.c
libeap/src/eap_common/eap_eke_common.c
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_pax_common.c
libeap/src/eap_common/eap_pwd_common.c
libeap/src/eap_common/eap_sake_common.c
libeap/src/eap_common/ikev2_common.c
libeap/src/eap_peer/eap.c
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_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_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_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/tncc.c
libeap/src/eap_server/eap_methods.h
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/ikev2.c
libeap/src/eap_server/tncs.c
libeap/src/eapol_auth/eapol_auth_sm.c
libeap/src/eapol_auth/eapol_auth_sm_i.h
libeap/src/eapol_supp/eapol_supp_sm.c
libeap/src/fst/fst.c
libeap/src/fst/fst_ctrl_aux.c
libeap/src/fst/fst_ctrl_iface.c
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_session.c
libeap/src/l2_packet/l2_packet_linux.c
libeap/src/l2_packet/l2_packet_pcap.c
libeap/src/p2p/p2p.c
libeap/src/p2p/p2p.h
libeap/src/p2p/p2p_build.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/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_secy_ops.c
libeap/src/pae/ieee802_1x_secy_ops.h
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/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_i.h
libeap/src/rsn_supp/wpa_ie.c
libeap/src/tls/Makefile
libeap/src/tls/asn1.h
libeap/src/tls/pkcs5.c
libeap/src/tls/tlsv1_client.c
libeap/src/tls/tlsv1_client.h
libeap/src/tls/tlsv1_client_i.h
libeap/src/tls/tlsv1_client_ocsp.c
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_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/browser-android.c
libeap/src/utils/common.c
libeap/src/utils/common.h
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_i.h
libeap/src/utils/http_curl.c
libeap/src/utils/module_tests.h
libeap/src/utils/os.h
libeap/src/utils/os_unix.c
libeap/src/utils/pcsc_funcs.c
libeap/src/utils/platform.h
libeap/src/utils/radiotap.c
libeap/src/utils/radiotap.h
libeap/src/utils/radiotap_iter.h
libeap/src/utils/trace.c
libeap/src/utils/trace.h
libeap/src/utils/utils_module_tests.c
libeap/src/utils/wpa_debug.c
libeap/src/utils/wpabuf.c
libeap/src/utils/wpabuf.h
libeap/src/utils/xml_libxml2.c
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_process.c
libeap/src/wps/wps_common.c
libeap/src/wps/wps_defs.h
libeap/src/wps/wps_enrollee.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_i.h
libeap/src/wps/wps_upnp_ssdp.c
libeap/src/wps/wps_upnp_web.c
libeap/tests/hwsim/auth_serv/as.conf
libeap/tests/hwsim/auth_serv/as2.conf
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-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-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.milenage_db
libeap/tests/hwsim/auth_serv/index-revoked.txt
libeap/tests/hwsim/auth_serv/index.txt
libeap/tests/hwsim/auth_serv/ocsp-req.der
libeap/tests/hwsim/auth_serv/ocsp-responder.pem
libeap/tests/hwsim/auth_serv/ocsp-server-cache.der
libeap/tests/hwsim/auth_serv/server-eku-client-server.pem
libeap/tests/hwsim/auth_serv/server-eku-client.pem
libeap/tests/hwsim/auth_serv/server-no-dnsname.pem
libeap/tests/hwsim/auth_serv/server.pem
libeap/tests/hwsim/auth_serv/server.pkcs12
libeap/tests/hwsim/auth_serv/user.pem
libeap/tests/hwsim/auth_serv/user.pkcs12
libeap/tests/hwsim/auth_serv/user2.pkcs12
libeap/tests/hwsim/auth_serv/user3.pkcs12
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/hostapd.py
libeap/tests/hwsim/hostapd.wlan3.vlan
libeap/tests/hwsim/hostapd.wlan4.vlan
libeap/tests/hwsim/hwsim_utils.py
libeap/tests/hwsim/nl80211.py
libeap/tests/hwsim/run-tests.py
libeap/tests/hwsim/start.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_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/tshark.py
libeap/tests/hwsim/utils.py
libeap/tests/hwsim/vm/inside.sh
libeap/tests/hwsim/vm/parallel-vm.py
libeap/tests/hwsim/vm/parallel-vm.sh
libeap/tests/hwsim/vm/uevent.sh
libeap/tests/hwsim/vm/vm-run.sh
libeap/tests/hwsim/wlantest.py
libeap/tests/hwsim/wpasupplicant.py
libeap/wlantest/bip.c
libeap/wlantest/ccmp.c
libeap/wlantest/readpcap.c
libeap/wlantest/rx_data.c
libeap/wlantest/test_vectors.c
libeap/wlantest/wlantest.c
libeap/wlantest/wlantest.h
libeap/wlantest/writepcap.c
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/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/bgscan.c
libeap/wpa_supplicant/bgscan.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_ssid.h
libeap/wpa_supplicant/config_winreg.c
libeap/wpa_supplicant/ctrl_iface.c
libeap/wpa_supplicant/ctrl_iface_udp.c
libeap/wpa_supplicant/ctrl_iface_unix.c
libeap/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
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_handlers.c
libeap/wpa_supplicant/defconfig
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/eapol_test.c
libeap/wpa_supplicant/events.c
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/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/notify.c
libeap/wpa_supplicant/notify.h
libeap/wpa_supplicant/offchannel.c
libeap/wpa_supplicant/p2p_supplicant.c
libeap/wpa_supplicant/p2p_supplicant.h
libeap/wpa_supplicant/p2p_supplicant_sd.c
libeap/wpa_supplicant/scan.c
libeap/wpa_supplicant/scan.h
libeap/wpa_supplicant/sme.c
libeap/wpa_supplicant/systemd/wpa_supplicant.service.in
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_priv.c
libeap/wpa_supplicant/wpa_supplicant.c
libeap/wpa_supplicant/wpa_supplicant.conf
libeap/wpa_supplicant/wpa_supplicant_i.h
libeap/wpa_supplicant/wpas_glue.c
libeap/wpa_supplicant/wpas_kay.c
libeap/wpa_supplicant/wpas_module_tests.c
libeap/wpa_supplicant/wps_supplicant.c
libeap/wpa_supplicant/wps_supplicant.h
libeap/wpaspy/test.py
libeap/wpaspy/wpaspy.py

diff --cc .gitignore
@@@ -1,19 -1,4 +1,20 @@@
 +Makefile.in
 +Makefile
 +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
+ *.a
  *.o
  *.d
  *.gcno
diff --cc libeap/COPYING
Simple merge
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
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,43b0bf1..43b0bf1
mode 000000,100644..100644
--- /dev/null
index 0000000,9f37f28..9f37f28
mode 000000,100644..100644
--- /dev/null
Simple merge
index 0000000,a2efff6..a2efff6
mode 000000,100644..100644
--- /dev/null
index 0000000,c22e043..c22e043
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,3569f95..3569f95
mode 000000,100644..100644
--- /dev/null
index 0000000,f07fd41..f07fd41
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,cea8b72..cea8b72
mode 000000,100644..100644
--- /dev/null
index 0000000,80f245c..80f245c
mode 000000,100644..100644
--- /dev/null
index 0000000,b6f6bb1..b6f6bb1
mode 000000,100644..100644
--- /dev/null
index 0000000,af84929..af84929
mode 000000,100644..100644
--- /dev/null
index 0000000,aa42335..aa42335
mode 000000,100644..100644
--- /dev/null
index 0000000,ef953a5..ef953a5
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
index 0000000,987b612..987b612
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,b583d1c..b583d1c
mode 000000,100644..100644
--- /dev/null
index 0000000,41ef329..41ef329
mode 000000,100644..100644
--- /dev/null
index 0000000,ebbe6ff..ebbe6ff
mode 000000,100644..100644
--- /dev/null
index 0000000,0b6e3e7..0b6e3e7
mode 000000,100644..100644
--- /dev/null
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,7b76846..7b76846
mode 000000,100644..100644
--- /dev/null
index 0000000,8a1dd6e..8a1dd6e
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 368bacf,0000000..0dc073d
mode 100644,000000..100644
--- /dev/null
@@@ -1,819 -1,0 +1,842 @@@
-       CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
 +/*
 + * Wrapper functions for crypto libraries
 + * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + *
 + * This file defines the cryptographic functions that need to be implemented
 + * for wpa_supplicant and hostapd. When TLS is not used, internal
 + * implementation of MD5, SHA1, and AES is used and no external libraries are
 + * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the
 + * crypto library used by the TLS implementation is expected to be used for
 + * non-TLS needs, too, in order to save space by not implementing these
 + * functions twice.
 + *
 + * Wrapper code for using each crypto library is in its own file (crypto*.c)
 + * and one of these files is build and linked in to provide the functions
 + * defined here.
 + */
 +
 +#ifndef CRYPTO_H
 +#define CRYPTO_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +
 +/**
 + * md4_vector - MD4 hash for data vector
 + * @num_elem: Number of elements in the data vector
 + * @addr: Pointers to the data areas
 + * @len: Lengths of the data blocks
 + * @mac: Buffer for the hash
 + * Returns: 0 on success, -1 on failure
 + */
 +int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
 +
 +/**
 + * md5_vector - MD5 hash for data vector
 + * @num_elem: Number of elements in the data vector
 + * @addr: Pointers to the data areas
 + * @len: Lengths of the data blocks
 + * @mac: Buffer for the hash
 + * Returns: 0 on success, -1 on failure
 + */
 +int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
 +
 +
 +/**
 + * sha1_vector - SHA-1 hash for data vector
 + * @num_elem: Number of elements in the data vector
 + * @addr: Pointers to the data areas
 + * @len: Lengths of the data blocks
 + * @mac: Buffer for the hash
 + * Returns: 0 on success, -1 on failure
 + */
 +int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 +              u8 *mac);
 +
 +/**
 + * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF
 + * @seed: Seed/key for the PRF
 + * @seed_len: Seed length in bytes
 + * @x: Buffer for PRF output
 + * @xlen: Output length in bytes
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function implements random number generation specified in NIST FIPS
 + * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to
 + * SHA-1, but has different message padding.
 + */
 +int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x,
 +                             size_t xlen);
 +
 +/**
 + * sha256_vector - SHA256 hash for data vector
 + * @num_elem: Number of elements in the data vector
 + * @addr: Pointers to the data areas
 + * @len: Lengths of the data blocks
 + * @mac: Buffer for the hash
 + * Returns: 0 on success, -1 on failure
 + */
 +int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
 +                u8 *mac);
 +
 +/**
++ * sha384_vector - SHA384 hash for data vector
++ * @num_elem: Number of elements in the data vector
++ * @addr: Pointers to the data areas
++ * @len: Lengths of the data blocks
++ * @mac: Buffer for the hash
++ * Returns: 0 on success, -1 on failure
++ */
++int sha384_vector(size_t num_elem, const u8 *addr[], const size_t *len,
++                u8 *mac);
++
++/**
++ * sha512_vector - SHA512 hash for data vector
++ * @num_elem: Number of elements in the data vector
++ * @addr: Pointers to the data areas
++ * @len: Lengths of the data blocks
++ * @mac: Buffer for the hash
++ * Returns: 0 on success, -1 on failure
++ */
++int sha512_vector(size_t num_elem, const u8 *addr[], const size_t *len,
++                u8 *mac);
++
++/**
 + * des_encrypt - Encrypt one block with DES
 + * @clear: 8 octets (in)
 + * @key: 7 octets (in) (no parity bits included)
 + * @cypher: 8 octets (out)
 + */
 +void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
 +
 +/**
 + * aes_encrypt_init - Initialize AES for encryption
 + * @key: Encryption key
 + * @len: Key length in bytes (usually 16, i.e., 128 bits)
 + * Returns: Pointer to context data or %NULL on failure
 + */
 +void * aes_encrypt_init(const u8 *key, size_t len);
 +
 +/**
 + * aes_encrypt - Encrypt one AES block
 + * @ctx: Context pointer from aes_encrypt_init()
 + * @plain: Plaintext data to be encrypted (16 bytes)
 + * @crypt: Buffer for the encrypted data (16 bytes)
 + */
 +void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
 +
 +/**
 + * aes_encrypt_deinit - Deinitialize AES encryption
 + * @ctx: Context pointer from aes_encrypt_init()
 + */
 +void aes_encrypt_deinit(void *ctx);
 +
 +/**
 + * aes_decrypt_init - Initialize AES for decryption
 + * @key: Decryption key
 + * @len: Key length in bytes (usually 16, i.e., 128 bits)
 + * Returns: Pointer to context data or %NULL on failure
 + */
 +void * aes_decrypt_init(const u8 *key, size_t len);
 +
 +/**
 + * aes_decrypt - Decrypt one AES block
 + * @ctx: Context pointer from aes_encrypt_init()
 + * @crypt: Encrypted data (16 bytes)
 + * @plain: Buffer for the decrypted data (16 bytes)
 + */
 +void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
 +
 +/**
 + * aes_decrypt_deinit - Deinitialize AES decryption
 + * @ctx: Context pointer from aes_encrypt_init()
 + */
 +void aes_decrypt_deinit(void *ctx);
 +
 +
 +enum crypto_hash_alg {
 +      CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
 +      CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
++      CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256,
++      CRYPTO_HASH_ALG_SHA384, CRYPTO_HASH_ALG_SHA512
 +};
 +
 +struct crypto_hash;
 +
 +/**
 + * crypto_hash_init - Initialize hash/HMAC function
 + * @alg: Hash algorithm
 + * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed
 + * @key_len: Length of the key in bytes
 + * Returns: Pointer to hash context to use with other hash functions or %NULL
 + * on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
 +                                    size_t key_len);
 +
 +/**
 + * crypto_hash_update - Add data to hash calculation
 + * @ctx: Context pointer from crypto_hash_init()
 + * @data: Data buffer to add
 + * @len: Length of the buffer
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len);
 +
 +/**
 + * crypto_hash_finish - Complete hash calculation
 + * @ctx: Context pointer from crypto_hash_init()
 + * @hash: Buffer for hash value or %NULL if caller is just freeing the hash
 + * context
 + * @len: Pointer to length of the buffer or %NULL if caller is just freeing the
 + * hash context; on return, this is set to the actual length of the hash value
 + * Returns: 0 on success, -1 if buffer is too small (len set to needed length),
 + * or -2 on other failures (including failed crypto_hash_update() operations)
 + *
 + * This function calculates the hash value and frees the context buffer that
 + * was used for hash calculation.
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len);
 +
 +
 +enum crypto_cipher_alg {
 +      CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,
 +      CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4
 +};
 +
 +struct crypto_cipher;
 +
 +/**
 + * crypto_cipher_init - Initialize block/stream cipher function
 + * @alg: Cipher algorithm
 + * @iv: Initialization vector for block ciphers or %NULL for stream ciphers
 + * @key: Cipher key
 + * @key_len: Length of key in bytes
 + * Returns: Pointer to cipher context to use with other cipher functions or
 + * %NULL on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
 +                                        const u8 *iv, const u8 *key,
 +                                        size_t key_len);
 +
 +/**
 + * crypto_cipher_encrypt - Cipher encrypt
 + * @ctx: Context pointer from crypto_cipher_init()
 + * @plain: Plaintext to cipher
 + * @crypt: Resulting ciphertext
 + * @len: Length of the plaintext
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx,
 +                                     const u8 *plain, u8 *crypt, size_t len);
 +
 +/**
 + * crypto_cipher_decrypt - Cipher decrypt
 + * @ctx: Context pointer from crypto_cipher_init()
 + * @crypt: Ciphertext to decrypt
 + * @plain: Resulting plaintext
 + * @len: Length of the cipher text
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx,
 +                                     const u8 *crypt, u8 *plain, size_t len);
 +
 +/**
 + * crypto_cipher_decrypt - Free cipher context
 + * @ctx: Context pointer from crypto_cipher_init()
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_cipher_deinit(struct crypto_cipher *ctx);
 +
 +
 +struct crypto_public_key;
 +struct crypto_private_key;
 +
 +/**
 + * crypto_public_key_import - Import an RSA public key
 + * @key: Key buffer (DER encoded RSA public key)
 + * @len: Key buffer length in bytes
 + * Returns: Pointer to the public key or %NULL on failure
 + *
 + * This function can just return %NULL if the crypto library supports X.509
 + * parsing. In that case, crypto_public_key_from_cert() is used to import the
 + * public key from a certificate.
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
 +
 +struct crypto_public_key *
 +crypto_public_key_import_parts(const u8 *n, size_t n_len,
 +                             const u8 *e, size_t e_len);
 +
 +/**
 + * crypto_private_key_import - Import an RSA private key
 + * @key: Key buffer (DER encoded RSA private key)
 + * @len: Key buffer length in bytes
 + * @passwd: Key encryption password or %NULL if key is not encrypted
 + * Returns: Pointer to the private key or %NULL on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_private_key * crypto_private_key_import(const u8 *key,
 +                                                    size_t len,
 +                                                    const char *passwd);
 +
 +/**
 + * crypto_public_key_from_cert - Import an RSA public key from a certificate
 + * @buf: DER encoded X.509 certificate
 + * @len: Certificate buffer length in bytes
 + * Returns: Pointer to public key or %NULL on failure
 + *
 + * This function can just return %NULL if the crypto library does not support
 + * X.509 parsing. In that case, internal code will be used to parse the
 + * certificate and public key is imported using crypto_public_key_import().
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
 +                                                     size_t len);
 +
 +/**
 + * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5)
 + * @key: Public key
 + * @in: Plaintext buffer
 + * @inlen: Length of plaintext buffer in bytes
 + * @out: Output buffer for encrypted data
 + * @outlen: Length of output buffer in bytes; set to used length on success
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_public_key_encrypt_pkcs1_v15(
 +      struct crypto_public_key *key, const u8 *in, size_t inlen,
 +      u8 *out, size_t *outlen);
 +
 +/**
 + * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5)
 + * @key: Private key
 + * @in: Encrypted buffer
 + * @inlen: Length of encrypted buffer in bytes
 + * @out: Output buffer for encrypted data
 + * @outlen: Length of output buffer in bytes; set to used length on success
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_private_key_decrypt_pkcs1_v15(
 +      struct crypto_private_key *key, const u8 *in, size_t inlen,
 +      u8 *out, size_t *outlen);
 +
 +/**
 + * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
 + * @key: Private key from crypto_private_key_import()
 + * @in: Plaintext buffer
 + * @inlen: Length of plaintext buffer in bytes
 + * @out: Output buffer for encrypted (signed) data
 + * @outlen: Length of output buffer in bytes; set to used length on success
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
 +                                             const u8 *in, size_t inlen,
 +                                             u8 *out, size_t *outlen);
 +
 +/**
 + * crypto_public_key_free - Free public key
 + * @key: Public key
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_public_key_free(struct crypto_public_key *key);
 +
 +/**
 + * crypto_private_key_free - Free private key
 + * @key: Private key from crypto_private_key_import()
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_private_key_free(struct crypto_private_key *key);
 +
 +/**
 + * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature
 + * @key: Public key
 + * @crypt: Encrypted signature data (using the private key)
 + * @crypt_len: Encrypted signature data length
 + * @plain: Buffer for plaintext (at least crypt_len bytes)
 + * @plain_len: Plaintext length (max buffer size on input, real len on output);
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check crypto_public_key_decrypt_pkcs1(
 +      struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
 +      u8 *plain, size_t *plain_len);
 +
 +/**
 + * crypto_global_init - Initialize crypto wrapper
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_global_init(void);
 +
 +/**
 + * crypto_global_deinit - Deinitialize crypto wrapper
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +void crypto_global_deinit(void);
 +
 +/**
 + * crypto_mod_exp - Modular exponentiation of large integers
 + * @base: Base integer (big endian byte array)
 + * @base_len: Length of base integer in bytes
 + * @power: Power integer (big endian byte array)
 + * @power_len: Length of power integer in bytes
 + * @modulus: Modulus integer (big endian byte array)
 + * @modulus_len: Length of modulus integer in bytes
 + * @result: Buffer for the result
 + * @result_len: Result length (max buffer size on input, real len on output)
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function calculates result = base ^ power mod modulus. modules_len is
 + * used as the maximum size of modulus buffer. It is set to the used size on
 + * success.
 + *
 + * This function is only used with internal TLSv1 implementation
 + * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
 + * to implement this.
 + */
 +int __must_check crypto_mod_exp(const u8 *base, size_t base_len,
 +                              const u8 *power, size_t power_len,
 +                              const u8 *modulus, size_t modulus_len,
 +                              u8 *result, size_t *result_len);
 +
 +/**
 + * rc4_skip - XOR RC4 stream to given data with skip-stream-start
 + * @key: RC4 key
 + * @keylen: RC4 key length
 + * @skip: number of bytes to skip from the beginning of the RC4 stream
 + * @data: data to be XOR'ed with RC4 stream
 + * @data_len: buf length
 + * Returns: 0 on success, -1 on failure
 + *
 + * Generate RC4 pseudo random stream for the given key, skip beginning of the
 + * stream, and XOR the end result with the data buffer to perform RC4
 + * encryption/decryption.
 + */
 +int rc4_skip(const u8 *key, size_t keylen, size_t skip,
 +           u8 *data, size_t data_len);
 +
 +/**
 + * crypto_get_random - Generate cryptographically strong pseudy-random bytes
 + * @buf: Buffer for data
 + * @len: Number of bytes to generate
 + * Returns: 0 on success, -1 on failure
 + *
 + * If the PRNG does not have enough entropy to ensure unpredictable byte
 + * sequence, this functions must return -1.
 + */
 +int crypto_get_random(void *buf, size_t len);
 +
 +
 +/**
 + * struct crypto_bignum - bignum
 + *
 + * Internal data structure for bignum implementation. The contents is specific
 + * to the used crypto library.
 + */
 +struct crypto_bignum;
 +
 +/**
 + * crypto_bignum_init - Allocate memory for bignum
 + * Returns: Pointer to allocated bignum or %NULL on failure
 + */
 +struct crypto_bignum * crypto_bignum_init(void);
 +
 +/**
 + * crypto_bignum_init_set - Allocate memory for bignum and set the value
 + * @buf: Buffer with unsigned binary value
 + * @len: Length of buf in octets
 + * Returns: Pointer to allocated bignum or %NULL on failure
 + */
 +struct crypto_bignum * crypto_bignum_init_set(const u8 *buf, size_t len);
 +
 +/**
 + * crypto_bignum_deinit - Free bignum
 + * @n: Bignum from crypto_bignum_init() or crypto_bignum_init_set()
 + * @clear: Whether to clear the value from memory
 + */
 +void crypto_bignum_deinit(struct crypto_bignum *n, int clear);
 +
 +/**
 + * crypto_bignum_to_bin - Set binary buffer to unsigned bignum
 + * @a: Bignum
 + * @buf: Buffer for the binary number
 + * @len: Length of @buf in octets
 + * @padlen: Length in octets to pad the result to or 0 to indicate no padding
 + * Returns: Number of octets written on success, -1 on failure
 + */
 +int crypto_bignum_to_bin(const struct crypto_bignum *a,
 +                       u8 *buf, size_t buflen, size_t padlen);
 +
 +/**
 + * crypto_bignum_add - c = a + b
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a + b
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_add(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b,
 +                    struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_mod - c = a % b
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a % b
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_mod(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b,
 +                    struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_exptmod - Modular exponentiation: d = a^b (mod c)
 + * @a: Bignum; base
 + * @b: Bignum; exponent
 + * @c: Bignum; modulus
 + * @d: Bignum; used to store the result of a^b (mod c)
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_exptmod(const struct crypto_bignum *a,
 +                        const struct crypto_bignum *b,
 +                        const struct crypto_bignum *c,
 +                        struct crypto_bignum *d);
 +
 +/**
 + * crypto_bignum_inverse - Inverse a bignum so that a * c = 1 (mod b)
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_inverse(const struct crypto_bignum *a,
 +                        const struct crypto_bignum *b,
 +                        struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_sub - c = a - b
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a - b
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_sub(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b,
 +                    struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_div - c = a / b
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a / b
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_div(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b,
 +                    struct crypto_bignum *c);
 +
 +/**
 + * crypto_bignum_mulmod - d = a * b (mod c)
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum
 + * @d: Bignum; used to store the result of (a * b) % c
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_bignum_mulmod(const struct crypto_bignum *a,
 +                       const struct crypto_bignum *b,
 +                       const struct crypto_bignum *c,
 +                       struct crypto_bignum *d);
 +
 +/**
 + * crypto_bignum_cmp - Compare two bignums
 + * @a: Bignum
 + * @b: Bignum
 + * Returns: -1 if a < b, 0 if a == b, or 1 if a > b
 + */
 +int crypto_bignum_cmp(const struct crypto_bignum *a,
 +                    const struct crypto_bignum *b);
 +
 +/**
 + * crypto_bignum_bits - Get size of a bignum in bits
 + * @a: Bignum
 + * Returns: Number of bits in the bignum
 + */
 +int crypto_bignum_bits(const struct crypto_bignum *a);
 +
 +/**
 + * crypto_bignum_is_zero - Is the given bignum zero
 + * @a: Bignum
 + * Returns: 1 if @a is zero or 0 if not
 + */
 +int crypto_bignum_is_zero(const struct crypto_bignum *a);
 +
 +/**
 + * crypto_bignum_is_one - Is the given bignum one
 + * @a: Bignum
 + * Returns: 1 if @a is one or 0 if not
 + */
 +int crypto_bignum_is_one(const struct crypto_bignum *a);
 +
 +/**
 + * crypto_bignum_legendre - Compute the Legendre symbol (a/p)
 + * @a: Bignum
 + * @p: Bignum
 + * Returns: Legendre symbol -1,0,1 on success; -2 on calculation failure
 + */
 +int crypto_bignum_legendre(const struct crypto_bignum *a,
 +                         const struct crypto_bignum *p);
 +
 +/**
 + * struct crypto_ec - Elliptic curve context
 + *
 + * Internal data structure for EC implementation. The contents is specific
 + * to the used crypto library.
 + */
 +struct crypto_ec;
 +
 +/**
 + * crypto_ec_init - Initialize elliptic curve context
 + * @group: Identifying number for the ECC group (IANA "Group Description"
 + *    attribute registrty for RFC 2409)
 + * Returns: Pointer to EC context or %NULL on failure
 + */
 +struct crypto_ec * crypto_ec_init(int group);
 +
 +/**
 + * crypto_ec_deinit - Deinitialize elliptic curve context
 + * @e: EC context from crypto_ec_init()
 + */
 +void crypto_ec_deinit(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_prime_len - Get length of the prime in octets
 + * @e: EC context from crypto_ec_init()
 + * Returns: Length of the prime defining the group
 + */
 +size_t crypto_ec_prime_len(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_prime_len_bits - Get length of the prime in bits
 + * @e: EC context from crypto_ec_init()
 + * Returns: Length of the prime defining the group in bits
 + */
 +size_t crypto_ec_prime_len_bits(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_get_prime - Get prime defining an EC group
 + * @e: EC context from crypto_ec_init()
 + * Returns: Prime (bignum) defining the group
 + */
 +const struct crypto_bignum * crypto_ec_get_prime(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_get_order - Get order of an EC group
 + * @e: EC context from crypto_ec_init()
 + * Returns: Order (bignum) of the group
 + */
 +const struct crypto_bignum * crypto_ec_get_order(struct crypto_ec *e);
 +
 +/**
 + * struct crypto_ec_point - Elliptic curve point
 + *
 + * Internal data structure for EC implementation to represent a point. The
 + * contents is specific to the used crypto library.
 + */
 +struct crypto_ec_point;
 +
 +/**
 + * crypto_ec_point_init - Initialize data for an EC point
 + * @e: EC context from crypto_ec_init()
 + * Returns: Pointer to EC point data or %NULL on failure
 + */
 +struct crypto_ec_point * crypto_ec_point_init(struct crypto_ec *e);
 +
 +/**
 + * crypto_ec_point_deinit - Deinitialize EC point data
 + * @p: EC point data from crypto_ec_point_init()
 + * @clear: Whether to clear the EC point value from memory
 + */
 +void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear);
 +
 +/**
 + * crypto_ec_point_to_bin - Write EC point value as binary data
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point data from crypto_ec_point_init()
 + * @x: Buffer for writing the binary data for x coordinate or %NULL if not used
 + * @y: Buffer for writing the binary data for y coordinate or %NULL if not used
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function can be used to write an EC point as binary data in a format
 + * that has the x and y coordinates in big endian byte order fields padded to
 + * the length of the prime defining the group.
 + */
 +int crypto_ec_point_to_bin(struct crypto_ec *e,
 +                         const struct crypto_ec_point *point, u8 *x, u8 *y);
 +
 +/**
 + * crypto_ec_point_from_bin - Create EC point from binary data
 + * @e: EC context from crypto_ec_init()
 + * @val: Binary data to read the EC point from
 + * Returns: Pointer to EC point data or %NULL on failure
 + *
 + * This function readers x and y coordinates of the EC point from the provided
 + * buffer assuming the values are in big endian byte order with fields padded to
 + * the length of the prime defining the group.
 + */
 +struct crypto_ec_point * crypto_ec_point_from_bin(struct crypto_ec *e,
 +                                                const u8 *val);
 +
 +/**
 + * crypto_bignum_add - c = a + b
 + * @e: EC context from crypto_ec_init()
 + * @a: Bignum
 + * @b: Bignum
 + * @c: Bignum; used to store the result of a + b
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
 +                      const struct crypto_ec_point *b,
 +                      struct crypto_ec_point *c);
 +
 +/**
 + * crypto_bignum_mul - res = b * p
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point
 + * @b: Bignum
 + * @res: EC point; used to store the result of b * p
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
 +                      const struct crypto_bignum *b,
 +                      struct crypto_ec_point *res);
 +
 +/**
 + * crypto_ec_point_invert - Compute inverse of an EC point
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point to invert (and result of the operation)
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p);
 +
 +/**
 + * crypto_ec_point_solve_y_coord - Solve y coordinate for an x coordinate
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point to use for the returning the result
 + * @x: x coordinate
 + * @y_bit: y-bit (0 or 1) for selecting the y value to use
 + * Returns: 0 on success, -1 on failure
 + */
 +int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
 +                                struct crypto_ec_point *p,
 +                                const struct crypto_bignum *x, int y_bit);
 +
 +/**
 + * crypto_ec_point_compute_y_sqr - Compute y^2 = x^3 + ax + b
 + * @e: EC context from crypto_ec_init()
 + * @x: x coordinate
 + * Returns: y^2 on success, %NULL failure
 + */
 +struct crypto_bignum *
 +crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
 +                            const struct crypto_bignum *x);
 +
 +/**
 + * crypto_ec_point_is_at_infinity - Check whether EC point is neutral element
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point
 + * Returns: 1 if the specified EC point is the neutral element of the group or
 + *    0 if not
 + */
 +int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
 +                                 const struct crypto_ec_point *p);
 +
 +/**
 + * crypto_ec_point_is_on_curve - Check whether EC point is on curve
 + * @e: EC context from crypto_ec_init()
 + * @p: EC point
 + * Returns: 1 if the specified EC point is on the curve or 0 if not
 + */
 +int crypto_ec_point_is_on_curve(struct crypto_ec *e,
 +                              const struct crypto_ec_point *p);
 +
 +/**
 + * crypto_ec_point_cmp - Compare two EC points
 + * @e: EC context from crypto_ec_init()
 + * @a: EC point
 + * @b: EC point
 + * Returns: 0 on equal, non-zero otherwise
 + */
 +int crypto_ec_point_cmp(const struct crypto_ec *e,
 +                      const struct crypto_ec_point *a,
 +                      const struct crypto_ec_point *b);
 +
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* CRYPTO_H */
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,646f729..646f729
mode 000000,100644..100644
--- /dev/null
index 0000000,a00253f..a00253f
mode 000000,100644..100644
--- /dev/null
index 0000000,76c4fe7..76c4fe7
mode 000000,100644..100644
--- /dev/null
index 0000000,1089589..1089589
mode 000000,100644..100644
--- /dev/null
index d02158e,0000000..33262da
mode 100644,000000..100644
--- /dev/null
@@@ -1,602 -1,0 +1,612 @@@
-     /**
-      * If non-null, specifies a callback method that can be used to
-      * confirm the validity of a peer certificate.
-      */
 +/*
 + * SSL/TLS interface definition
 + * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + */
 +
 +#ifndef TLS_H
 +#define TLS_H
 +
 +#include <openssl/x509.h>
 +
 +struct tls_connection;
 +
 +struct tls_random {
 +      const u8 *client_random;
 +      size_t client_random_len;
 +      const u8 *server_random;
 +      size_t server_random_len;
 +};
 +
 +enum tls_event {
 +      TLS_CERT_CHAIN_SUCCESS,
 +      TLS_CERT_CHAIN_FAILURE,
 +      TLS_PEER_CERTIFICATE,
 +      TLS_ALERT
 +};
 +
 +/*
 + * Note: These are used as identifier with external programs and as such, the
 + * values must not be changed.
 + */
 +enum tls_fail_reason {
 +      TLS_FAIL_UNSPECIFIED = 0,
 +      TLS_FAIL_UNTRUSTED = 1,
 +      TLS_FAIL_REVOKED = 2,
 +      TLS_FAIL_NOT_YET_VALID = 3,
 +      TLS_FAIL_EXPIRED = 4,
 +      TLS_FAIL_SUBJECT_MISMATCH = 5,
 +      TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
 +      TLS_FAIL_BAD_CERTIFICATE = 7,
 +      TLS_FAIL_SERVER_CHAIN_PROBE = 8,
 +      TLS_FAIL_DOMAIN_SUFFIX_MISMATCH = 9,
 +      TLS_FAIL_DOMAIN_MISMATCH = 10,
 +};
 +
 +
 +#define TLS_MAX_ALT_SUBJECT 10
 +
 +union tls_event_data {
 +      struct {
 +              int depth;
 +              const char *subject;
 +              enum tls_fail_reason reason;
 +              const char *reason_txt;
 +              const struct wpabuf *cert;
 +      } cert_fail;
 +
 +      struct {
 +              int depth;
 +              const char *subject;
 +              const struct wpabuf *cert;
 +              const u8 *hash;
 +              size_t hash_len;
 +              const char *altsubject[TLS_MAX_ALT_SUBJECT];
 +              int num_altsubject;
 +      } peer_cert;
 +
 +      struct {
 +              int is_local;
 +              const char *type;
 +              const char *description;
 +      } alert;
 +};
 +
 +struct tls_config {
 +      const char *opensc_engine_path;
 +      const char *pkcs11_engine_path;
 +      const char *pkcs11_module_path;
 +      int fips_mode;
 +      int cert_in_cb;
 +      const char *openssl_ciphers;
 +      unsigned int tls_session_lifetime;
 +
 +      void (*event_cb)(void *ctx, enum tls_event ev,
 +                       union tls_event_data *data);
 +      void *cb_ctx;
 +};
 +
 +#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
 +#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
 +#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
 +#define TLS_CONN_REQUEST_OCSP BIT(3)
 +#define TLS_CONN_REQUIRE_OCSP BIT(4)
 +#define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
 +#define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
 +#define TLS_CONN_EAP_FAST BIT(7)
 +#define TLS_CONN_DISABLE_TLSv1_0 BIT(8)
++#define TLS_CONN_EXT_CERT_CHECK BIT(9)
++#define TLS_CONN_REQUIRE_OCSP_ALL BIT(10)
 +
 +struct X509; /* from OpenSSL */
 +
 +/**
 + * struct tls_connection_params - Parameters for TLS connection
 + * @ca_cert: File or reference name for CA X.509 certificate in PEM or DER
 + * format
 + * @ca_cert_blob: ca_cert as inlined data or %NULL if not used
 + * @ca_cert_blob_len: ca_cert_blob length
 + * @ca_path: Path to CA certificates (OpenSSL specific)
 + * @subject_match: String to match in the subject of the peer certificate or
 + * %NULL to allow all subjects
 + * @altsubject_match: String to match in the alternative subject of the peer
 + * certificate or %NULL to allow all alternative subjects
 + * @suffix_match: String to suffix match in the dNSName or CN of the peer
 + * certificate or %NULL to allow all domain names. This may allow subdomains an
 + * wildcard certificates. Each domain name label must have a full match.
 + * @domain_match: String to match in the dNSName or CN of the peer
 + * certificate or %NULL to allow all domain names. This requires a full,
 + * case-insensitive match.
 + * @client_cert: File or reference name for client X.509 certificate in PEM or
 + * DER format
 + * @client_cert_blob: client_cert as inlined data or %NULL if not used
 + * @client_cert_blob_len: client_cert_blob length
 + * @private_key: File or reference name for client private key in PEM or DER
 + * format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY)
 + * @private_key_blob: private_key as inlined data or %NULL if not used
 + * @private_key_blob_len: private_key_blob length
 + * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
 + * passphrase is used.
 + * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
 + * @dh_blob: dh_file as inlined data or %NULL if not used
 + * @dh_blob_len: dh_blob length
 + * @engine: 1 = use engine (e.g., a smartcard) for private key operations
 + * (this is OpenSSL specific for now)
 + * @engine_id: engine id string (this is OpenSSL specific for now)
 + * @ppin: pointer to the pin variable in the configuration
 + * (this is OpenSSL specific for now)
 + * @key_id: the private key's id when using engine (this is OpenSSL
 + * specific for now)
 + * @cert_id: the certificate's id when using engine
 + * @ca_cert_id: the CA certificate's id when using engine
 + * @openssl_ciphers: OpenSSL cipher configuration
 + * @flags: Parameter options (TLS_CONN_*)
 + * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
 + *    or %NULL if OCSP is not enabled
++ * @ocsp_stapling_response_multi: DER encoded file with cached OCSP stapling
++ *    response list (OCSPResponseList for ocsp_multi in RFC 6961) or %NULL if
++ *    ocsp_multi is not enabled
 + * @server_cert_cb: Optional callback to be used to validate server certificate
 + *  when no CA or path was specified. 
 + * @server_cert_ctx: Optional context arg for server_cert_cb.
 + *
 + * TLS connection parameters to be configured with tls_connection_set_params()
 + * and tls_global_set_params().
 + *
 + * Certificates and private key can be configured either as a reference name
 + * (file path or reference to certificate store) or by providing the same data
 + * as a pointer to the data in memory. Only one option will be used for each
 + * field.
 + */
 +struct tls_connection_params {
 +      const char *ca_cert;
 +      const u8 *ca_cert_blob;
 +      size_t ca_cert_blob_len;
 +      const char *ca_path;
 +      const char *subject_match;
 +      const char *altsubject_match;
 +      const char *suffix_match;
 +      const char *domain_match;
 +      const char *client_cert;
 +      const u8 *client_cert_blob;
 +      size_t client_cert_blob_len;
 +      const char *private_key;
 +      const u8 *private_key_blob;
 +      size_t private_key_blob_len;
 +      const char *private_key_passwd;
 +      const char *dh_file;
 +      const u8 *dh_blob;
 +      size_t dh_blob_len;
 +
 +      /* OpenSSL specific variables */
 +      int engine;
 +      const char *engine_id;
 +      const char *pin;
 +      const char *key_id;
 +      const char *cert_id;
 +      const char *ca_cert_id;
 +      const char *openssl_ciphers;
 +
 +      unsigned int flags;
 +      const char *ocsp_stapling_response;
-  * tls_connection_prf - Use TLS-PRF to derive keying material
++      const char *ocsp_stapling_response_multi;
 +    int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx);
 +    void *server_cert_ctx;
 +};
 +
 +
 +/**
 + * tls_init - Initialize TLS library
 + * @conf: Configuration data for TLS library
 + * Returns: Context data to be used as tls_ctx in calls to other functions,
 + * or %NULL on failure.
 + *
 + * Called once during program startup and once for each RSN pre-authentication
 + * session. In other words, there can be two concurrent TLS contexts. If global
 + * library initialization is needed (i.e., one that is shared between both
 + * authentication types), the TLS library wrapper should maintain a reference
 + * counter and do global initialization only when moving from 0 to 1 reference.
 + */
 +void * tls_init(const struct tls_config *conf);
 +
 +/**
 + * tls_deinit - Deinitialize TLS library
 + * @tls_ctx: TLS context data from tls_init()
 + *
 + * Called once during program shutdown and once for each RSN pre-authentication
 + * session. If global library deinitialization is needed (i.e., one that is
 + * shared between both authentication types), the TLS library wrapper should
 + * maintain a reference counter and do global deinitialization only when moving
 + * from 1 to 0 references.
 + */
 +void tls_deinit(void *tls_ctx);
 +
 +/**
 + * tls_get_errors - Process pending errors
 + * @tls_ctx: TLS context data from tls_init()
 + * Returns: Number of found error, 0 if no errors detected.
 + *
 + * Process all pending TLS errors.
 + */
 +int tls_get_errors(void *tls_ctx);
 +
 +/**
 + * tls_connection_init - Initialize a new TLS connection
 + * @tls_ctx: TLS context data from tls_init()
 + * Returns: Connection context data, conn for other function calls
 + */
 +struct tls_connection * tls_connection_init(void *tls_ctx);
 +
 +/**
 + * tls_connection_deinit - Free TLS connection data
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + *
 + * Release all resources allocated for TLS connection.
 + */
 +void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
 +
 +/**
 + * tls_connection_established - Has the TLS connection been completed?
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: 1 if TLS connection has been completed, 0 if not.
 + */
 +int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
 +
 +/**
 + * tls_connection_shutdown - Shutdown TLS connection
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: 0 on success, -1 on failure
 + *
 + * Shutdown current TLS connection without releasing all resources. New
 + * connection can be started by using the same conn without having to call
 + * tls_connection_init() or setting certificates etc. again. The new
 + * connection should try to use session resumption.
 + */
 +int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
 +
 +enum {
 +      TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN = -4,
 +      TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
 +      TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
 +};
 +
 +/**
 + * tls_connection_set_params - Set TLS connection parameters
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @params: Connection parameters
 + * Returns: 0 on success, -1 on failure,
 + * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
 + * failure, or
 + * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
 + * PKCS#11 engine private key, or
 + * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
 + * failure.
 + */
 +int __must_check
 +tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
 +                        const struct tls_connection_params *params);
 +
 +/**
 + * tls_global_set_params - Set TLS parameters for all TLS connection
 + * @tls_ctx: TLS context data from tls_init()
 + * @params: Global TLS parameters
 + * Returns: 0 on success, -1 on failure,
 + * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on error causing PKCS#11 engine
 + * failure, or
 + * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
 + * PKCS#11 engine private key, or
 + * TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN (-4) on PIN error causing PKCS#11 engine
 + * failure.
 + */
 +int __must_check tls_global_set_params(
 +      void *tls_ctx, const struct tls_connection_params *params);
 +
 +/**
 + * tls_global_set_verify - Set global certificate verification options
 + * @tls_ctx: TLS context data from tls_init()
 + * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
 + * 2 = verify CRL for all certificates
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
 +
 +/**
 + * tls_connection_set_verify - Set certificate verification options
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @verify_peer: 1 = verify peer certificate
 + * @flags: Connection flags (TLS_CONN_*)
 + * @session_ctx: Session caching context or %NULL to use default
 + * @session_ctx_len: Length of @session_ctx in bytes.
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_connection_set_verify(void *tls_ctx,
 +                                         struct tls_connection *conn,
 +                                         int verify_peer,
 +                                         unsigned int flags,
 +                                         const u8 *session_ctx,
 +                                         size_t session_ctx_len);
 +
 +/**
 + * tls_connection_get_random - Get random data from TLS connection
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @data: Structure of client/server random data (filled on success)
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_connection_get_random(void *tls_ctx,
 +                                       struct tls_connection *conn,
 +                                       struct tls_random *data);
 +
 +/**
-  * @server_random_first: seed is 0 = client_random|server_random,
-  * 1 = server_random|client_random
-  * @skip_keyblock: Skip TLS key block from the beginning of PRF output
++ * tls_connection_export_key - Derive keying material from a TLS connection
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @label: Label (e.g., description of the key) for PRF
-  * tls_connection_prf() is required so that further keying material can be
-  * derived from the master secret. Example implementation of this function is in
-  * tls_prf_sha1_md5() when it is called with seed set to
-  * client_random|server_random (or server_random|client_random). For TLSv1.2 and
-  * newer, a different PRF is needed, though.
 + * @out: Buffer for output data from TLS-PRF
 + * @out_len: Length of the output buffer
 + * Returns: 0 on success, -1 on failure
 + *
- int __must_check  tls_connection_prf(void *tls_ctx,
-                                    struct tls_connection *conn,
-                                    const char *label,
-                                    int server_random_first,
-                                    int skip_keyblock,
-                                    u8 *out, size_t out_len);
++ * Exports keying material using the mechanism described in RFC 5705.
++ */
++int __must_check tls_connection_export_key(void *tls_ctx,
++                                         struct tls_connection *conn,
++                                         const char *label,
++                                         u8 *out, size_t out_len);
++
++/**
++ * tls_connection_get_eap_fast_key - Derive key material for EAP-FAST
++ * @tls_ctx: TLS context data from tls_init()
++ * @conn: Connection context data from tls_connection_init()
++ * @out: Buffer for output data from TLS-PRF
++ * @out_len: Length of the output buffer
++ * Returns: 0 on success, -1 on failure
++ *
++ * Exports key material after the normal TLS key block for use with
++ * EAP-FAST. Most callers will want tls_connection_export_key(), but EAP-FAST
++ * uses a different legacy mechanism.
 + */
-       TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
++int __must_check tls_connection_get_eap_fast_key(void *tls_ctx,
++                                               struct tls_connection *conn,
++                                               u8 *out, size_t out_len);
 +
 +/**
 + * tls_connection_handshake - Process TLS handshake (client side)
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @in_data: Input data from TLS server
 + * @appl_data: Pointer to application data pointer, or %NULL if dropped
 + * Returns: Output data, %NULL on failure
 + *
 + * The caller is responsible for freeing the returned output data. If the final
 + * handshake message includes application data, this is decrypted and
 + * appl_data (if not %NULL) is set to point this data. The caller is
 + * responsible for freeing appl_data.
 + *
 + * This function is used during TLS handshake. The first call is done with
 + * in_data == %NULL and the library is expected to return ClientHello packet.
 + * This packet is then send to the server and a response from server is given
 + * to TLS library by calling this function again with in_data pointing to the
 + * TLS message from the server.
 + *
 + * If the TLS handshake fails, this function may return %NULL. However, if the
 + * TLS library has a TLS alert to send out, that should be returned as the
 + * output data. In this case, tls_connection_get_failed() must return failure
 + * (> 0).
 + *
 + * tls_connection_established() should return 1 once the TLS handshake has been
 + * completed successfully.
 + */
 +struct wpabuf * tls_connection_handshake(void *tls_ctx,
 +                                       struct tls_connection *conn,
 +                                       const struct wpabuf *in_data,
 +                                       struct wpabuf **appl_data);
 +
 +struct wpabuf * tls_connection_handshake2(void *tls_ctx,
 +                                        struct tls_connection *conn,
 +                                        const struct wpabuf *in_data,
 +                                        struct wpabuf **appl_data,
 +                                        int *more_data_needed);
 +
 +/**
 + * tls_connection_server_handshake - Process TLS handshake (server side)
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @in_data: Input data from TLS peer
 + * @appl_data: Pointer to application data pointer, or %NULL if dropped
 + * Returns: Output data, %NULL on failure
 + *
 + * The caller is responsible for freeing the returned output data.
 + */
 +struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
 +                                              struct tls_connection *conn,
 +                                              const struct wpabuf *in_data,
 +                                              struct wpabuf **appl_data);
 +
 +/**
 + * tls_connection_encrypt - Encrypt data into TLS tunnel
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @in_data: Plaintext data to be encrypted
 + * Returns: Encrypted TLS data or %NULL on failure
 + *
 + * This function is used after TLS handshake has been completed successfully to
 + * send data in the encrypted tunnel. The caller is responsible for freeing the
 + * returned output data.
 + */
 +struct wpabuf * tls_connection_encrypt(void *tls_ctx,
 +                                     struct tls_connection *conn,
 +                                     const struct wpabuf *in_data);
 +
 +/**
 + * tls_connection_decrypt - Decrypt data from TLS tunnel
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @in_data: Encrypted TLS data
 + * Returns: Decrypted TLS data or %NULL on failure
 + *
 + * This function is used after TLS handshake has been completed successfully to
 + * receive data from the encrypted tunnel. The caller is responsible for
 + * freeing the returned output data.
 + */
 +struct wpabuf * tls_connection_decrypt(void *tls_ctx,
 +                                     struct tls_connection *conn,
 +                                     const struct wpabuf *in_data);
 +
 +struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
 +                                      struct tls_connection *conn,
 +                                      const struct wpabuf *in_data,
 +                                      int *more_data_needed);
 +
 +/**
 + * tls_connection_resumed - Was session resumption used
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: 1 if current session used session resumption, 0 if not
 + */
 +int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
 +
 +enum {
 +      TLS_CIPHER_NONE,
 +      TLS_CIPHER_RC4_SHA /* 0x0005 */,
 +      TLS_CIPHER_AES128_SHA /* 0x002f */,
 +      TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
++      TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */,
++      TLS_CIPHER_RSA_DHE_AES256_SHA /* 0x0039 */,
++      TLS_CIPHER_AES256_SHA /* 0x0035 */,
 +};
 +
 +/**
 + * tls_connection_set_cipher_list - Configure acceptable cipher suites
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
 + * (TLS_CIPHER_*).
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_connection_set_cipher_list(void *tls_ctx,
 +                                              struct tls_connection *conn,
 +                                              u8 *ciphers);
 +
 +/**
 + * tls_get_version - Get the current TLS version number
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @buf: Buffer for returning the TLS version number
 + * @buflen: buf size
 + * Returns: 0 on success, -1 on failure
 + *
 + * Get the currently used TLS version number.
 + */
 +int __must_check tls_get_version(void *tls_ctx, struct tls_connection *conn,
 +                               char *buf, size_t buflen);
 +
 +/**
 + * tls_get_cipher - Get current cipher name
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @buf: Buffer for the cipher name
 + * @buflen: buf size
 + * Returns: 0 on success, -1 on failure
 + *
 + * Get the name of the currently used cipher.
 + */
 +int __must_check tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
 +                              char *buf, size_t buflen);
 +
 +/**
 + * tls_connection_enable_workaround - Enable TLS workaround options
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function is used to enable connection-specific workaround options for
 + * buffer SSL/TLS implementations.
 + */
 +int __must_check tls_connection_enable_workaround(void *tls_ctx,
 +                                                struct tls_connection *conn);
 +
 +/**
 + * tls_connection_client_hello_ext - Set TLS extension for ClientHello
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * @ext_type: Extension type
 + * @data: Extension payload (%NULL to remove extension)
 + * @data_len: Extension payload length
 + * Returns: 0 on success, -1 on failure
 + */
 +int __must_check tls_connection_client_hello_ext(void *tls_ctx,
 +                                               struct tls_connection *conn,
 +                                               int ext_type, const u8 *data,
 +                                               size_t data_len);
 +
 +/**
 + * tls_connection_get_failed - Get connection failure status
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + *
 + * Returns >0 if connection has failed, 0 if not.
 + */
 +int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn);
 +
 +/**
 + * tls_connection_get_read_alerts - Get connection read alert status
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: Number of times a fatal read (remote end reported error) has
 + * happened during this connection.
 + */
 +int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
 +
 +/**
 + * tls_connection_get_write_alerts - Get connection write alert status
 + * @tls_ctx: TLS context data from tls_init()
 + * @conn: Connection context data from tls_connection_init()
 + * Returns: Number of times a fatal write (locally detected error) has happened
 + * during this connection.
 + */
 +int tls_connection_get_write_alerts(void *tls_ctx,
 +                                  struct tls_connection *conn);
 +
 +typedef int (*tls_session_ticket_cb)
 +(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
 + const u8 *server_random, u8 *master_secret);
 +
 +int __must_check  tls_connection_set_session_ticket_cb(
 +      void *tls_ctx, struct tls_connection *conn,
 +      tls_session_ticket_cb cb, void *ctx);
 +
 +void tls_connection_set_log_cb(struct tls_connection *conn,
 +                             void (*log_cb)(void *ctx, const char *msg),
 +                             void *ctx);
 +
 +#define TLS_BREAK_VERIFY_DATA BIT(0)
 +#define TLS_BREAK_SRV_KEY_X_HASH BIT(1)
 +#define TLS_BREAK_SRV_KEY_X_SIGNATURE BIT(2)
 +#define TLS_DHE_PRIME_511B BIT(3)
 +#define TLS_DHE_PRIME_767B BIT(4)
 +#define TLS_DHE_PRIME_15 BIT(5)
 +#define TLS_DHE_PRIME_58B BIT(6)
 +#define TLS_DHE_NON_PRIME BIT(7)
 +
 +void tls_connection_set_test_flags(struct tls_connection *conn, u32 flags);
 +
 +int tls_get_library_version(char *buf, size_t buf_len);
 +
 +void tls_connection_set_success_data(struct tls_connection *conn,
 +                                   struct wpabuf *data);
 +
 +void tls_connection_set_success_data_resumed(struct tls_connection *conn);
 +
 +const struct wpabuf *
 +tls_connection_get_success_data(struct tls_connection *conn);
 +
 +void tls_connection_remove_session(struct tls_connection *conn);
 +
 +#endif /* TLS_H */
Simple merge
Simple merge
Simple merge
index fab1865,0000000..9db8095
mode 100644,000000..100644
--- /dev/null
@@@ -1,4178 -1,0 +1,4366 @@@
- #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)
 +/*
 + * SSL/TLS interface functions for OpenSSL
 + * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
 + *
 + * 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/opensslv.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"
++#include "tls_openssl.h"
 +
- #ifndef OPENSSL_NO_ENGINE
++#if !defined(CONFIG_FIPS) &&                             \
++    (defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) ||   \
++     defined(EAP_SERVER_FAST))
++#define OPENSSL_NEED_EAP_FAST_PRF
 +#endif
 +
 +#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 */
 +
++#if (OPENSSL_VERSION_NUMBER < 0x10100000L || \
++     defined(LIBRESSL_VERSION_NUMBER)) &&    \
++    !defined(BORINGSSL_API_VERSION)
++/*
++ * SSL_get_client_random() and SSL_get_server_random() were added in OpenSSL
++ * 1.1.0 and newer BoringSSL revisions. Provide compatibility wrappers for
++ * older versions.
++ */
++
++static size_t SSL_get_client_random(const SSL *ssl, unsigned char *out,
++                                  size_t outlen)
++{
++      if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
++              return 0;
++      os_memcpy(out, ssl->s3->client_random, SSL3_RANDOM_SIZE);
++      return SSL3_RANDOM_SIZE;
++}
++
++
++static size_t SSL_get_server_random(const SSL *ssl, unsigned char *out,
++                                  size_t outlen)
++{
++      if (!ssl->s3 || outlen < SSL3_RANDOM_SIZE)
++              return 0;
++      os_memcpy(out, ssl->s3->server_random, SSL3_RANDOM_SIZE);
++      return SSL3_RANDOM_SIZE;
++}
++
++
++#ifdef OPENSSL_NEED_EAP_FAST_PRF
++static size_t SSL_SESSION_get_master_key(const SSL_SESSION *session,
++                                       unsigned char *out, size_t outlen)
++{
++      if (!session || session->master_key_length < 0 ||
++          (size_t) session->master_key_length > outlen)
++              return 0;
++      if ((size_t) session->master_key_length < outlen)
++              outlen = session->master_key_length;
++      os_memcpy(out, session->master_key, outlen);
++      return outlen;
++}
++#endif /* OPENSSL_NEED_EAP_FAST_PRF */
++
++#endif
++
 +#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;
 +}
++
++
++static int tls_add_ca_from_keystore(X509_STORE *ctx, const char *key_alias)
++{
++      BIO *bio = BIO_from_keystore(key_alias);
++      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) {
++              wpa_printf(MSG_WARNING, "TLS: Failed to parse certificate: %s",
++                         key_alias);
++              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(ctx, info->x509);
++              if (info->crl)
++                      X509_STORE_add_crl(ctx, info->crl);
++      }
++
++      sk_X509_INFO_pop_free(stack, X509_INFO_free);
++
++      return 0;
++}
++
++
++static int tls_add_ca_from_keystore_encoded(X509_STORE *ctx,
++                                          const char *encoded_key_alias)
++{
++      int rc = -1;
++      int len = os_strlen(encoded_key_alias);
++      unsigned char *decoded_alias;
++
++      if (len & 1) {
++              wpa_printf(MSG_WARNING, "Invalid hex-encoded alias: %s",
++                         encoded_key_alias);
++              return rc;
++      }
++
++      decoded_alias = os_malloc(len / 2 + 1);
++      if (decoded_alias) {
++              if (!hexstr2bin(encoded_key_alias, decoded_alias, len / 2)) {
++                      decoded_alias[len / 2] = '\0';
++                      rc = tls_add_ca_from_keystore(
++                              ctx, (const char *) decoded_alias);
++              }
++              os_free(decoded_alias);
++      }
++
++      return rc;
++}
++
 +#endif /* ANDROID */
 +
 +static int tls_openssl_ref_count = 0;
 +static int tls_ex_idx_session = -1;
 +
 +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;
 +};
 +
 +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;
- #if OPENSSL_VERSION_NUMBER >= 0x10100000L
++#if defined(ANDROID) || !defined(OPENSSL_NO_ENGINE)
 +      ENGINE *engine;        /* functional reference to the engine */
 +      EVP_PKEY *private_key; /* the private key if using engine */
 +#endif /* OPENSSL_NO_ENGINE */
 +      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;
 +
- #endif
 +      unsigned char client_random[SSL3_RANDOM_SIZE];
 +      unsigned char server_random[SSL3_RANDOM_SIZE];
-               if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
 +
 +    int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx);
 +    void *server_cert_ctx;
 +};
 +
 +
 +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,
 +                      (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))) {
 +              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);
 +
-               ENGINE_free(engine);
++              if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx),
++                                       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 (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) {
-               return 0;
 +              wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
 +                         "available", id);
++              /*
++               * If it was auto-loaded by ENGINE_by_id() we might still
++               * need to tell it which PKCS#11 module to use in legacy
++               * (non-p11-kit) environments. Do so now; even if it was
++               * properly initialised before, setting it again will be
++               * harmless.
++               */
++              goto found;
 +      }
 +      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;
 +      }
- #ifndef OPENSSL_NO_ENGINE
++ found:
 +      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
 +      };
 +
 +      if (!pkcs11_so_path)
 +              return 0;
 +
 +      pre_cmd[1] = pkcs11_so_path;
 +      pre_cmd[3] = engine_id;
 +      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) {
 +              tls_global = context = tls_context_new(conf);
 +              if (context == NULL)
 +                      return NULL;
 +#ifdef CONFIG_FIPS
 +#ifdef OPENSSL_FIPS
 +              if (conf && conf->fips_mode) {
 +                      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;
 +                      } 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 */
++#if OPENSSL_VERSION_NUMBER < 0x10100000L
 +              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 */
++#endif /* < 1.1.0 */
 +      } else {
 +              context = tls_context_new(conf);
 +              if (context == NULL)
 +                      return NULL;
 +      }
 +      tls_openssl_ref_count++;
 +
 +      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;
 +              }
++              os_free(data);
 +              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)) {
 +              if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
 +                  tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
 +                                                 conf->pkcs11_module_path)) {
 +                      tls_deinit(data);
 +                      return NULL;
 +              }
 +      }
 +#endif /* OPENSSL_NO_ENGINE */
 +
 +      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)
 +{
 +      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 OPENSSL_VERSION_NUMBER < 0x10100000L
 +// 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();
++#endif /* < 1.1.0 */
 +              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 */
 +
 +
++#ifdef ANDROID
++/* EVP_PKEY_from_keystore comes from system/security/keystore-engine. */
++EVP_PKEY * EVP_PKEY_from_keystore(const char *key_id);
++#endif /* ANDROID */
++
 +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)
 +{
++#if defined(ANDROID) && defined(OPENSSL_IS_BORINGSSL)
++#if !defined(OPENSSL_NO_ENGINE)
++#error "This code depends on OPENSSL_NO_ENGINE being defined by BoringSSL."
++#endif
++      if (!key_id)
++              return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
++      conn->engine = NULL;
++      conn->private_key = EVP_PKEY_from_keystore(key_id);
++      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));
++              return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
++      }
++#endif /* ANDROID && OPENSSL_IS_BORINGSSL */
++
 +#ifndef OPENSSL_NO_ENGINE
 +      int ret = -1;
 +      if (engine_id == NULL) {
 +              wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
 +              return -1;
 +      }
 +
 +      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");
 +
 +#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;
 +      }
 +#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)
 +{
- #endif /* OPENSSL_NO_ENGINE */
++#if defined(ANDROID) || !defined(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) {
++#if !defined(OPENSSL_IS_BORINGSSL)
 +              ENGINE_finish(conn->engine);
++#endif /* !OPENSSL_IS_BORINGSSL */
 +              conn->engine = NULL;
 +      }
-       wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d",
-                  write_p ? "TX" : "RX", version, content_type);
++#endif /* ANDROID || !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 const char * openssl_content_type(int content_type)
++{
++      switch (content_type) {
++      case 20:
++              return "change cipher spec";
++      case 21:
++              return "alert";
++      case 22:
++              return "handshake";
++      case 23:
++              return "application data";
++      case 24:
++              return "heartbeat";
++      case 256:
++              return "TLS header info"; /* pseudo content type */
++      default:
++              return "?";
++      }
++}
++
++
++static const char * openssl_handshake_type(int content_type, const u8 *buf,
++                                         size_t len)
++{
++      if (content_type != 22 || !buf || len == 0)
++              return "";
++      switch (buf[0]) {
++      case 0:
++              return "hello request";
++      case 1:
++              return "client hello";
++      case 2:
++              return "server hello";
++      case 4:
++              return "new session ticket";
++      case 11:
++              return "certificate";
++      case 12:
++              return "server key exchange";
++      case 13:
++              return "certificate request";
++      case 14:
++              return "server hello done";
++      case 15:
++              return "certificate verify";
++      case 16:
++              return "client key exchange";
++      case 20:
++              return "finished";
++      case 21:
++              return "certificate url";
++      case 22:
++              return "certificate status";
++      default:
++              return "?";
++      }
++}
++
++
 +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;
 +
-       if (conn->cert_probe || context->cert_in_cb) {
++      if (write_p == 2) {
++              wpa_printf(MSG_DEBUG,
++                         "OpenSSL: session ver=0x%x content_type=%d",
++                         version, content_type);
++              wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Data", buf, len);
++              return;
++      }
++
++      wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d (%s/%s)",
++                 write_p ? "TX" : "RX", version, content_type,
++                 openssl_content_type(content_type),
++                 openssl_handshake_type(content_type, buf, len));
 +      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)
 +{
 +      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);
 +      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;
 +      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++;
 +      }
 +
++      sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
++
 +      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");
++                      sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
 +                      return 1;
 +              }
 +      }
++      sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
 +
 +      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;
 +
 +      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;
 +      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 (context->event_cb == NULL)
 +              return;
 +
 +      os_memset(&ev, 0, sizeof(ev));
-       if (preverify_ok && context->event_cb != NULL)
++      if (conn->cert_probe || (conn->flags & TLS_CONN_EXT_CERT_CHECK) ||
++          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;
 +
 +      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';
 +      }
++      sk_GENERAL_NAME_pop_free(ext, GENERAL_NAME_free);
 +
 +      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 void debug_print_cert(X509 *cert, const char *title);
 +
 +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;
 +      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;
 +
 +    // debug_print_cert(err_cert, "\n\n***** tls_verify_cb:\n");
 +
 +      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 (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;
 +
 +      wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb(enter) - preverify_ok=%d "
 +                 "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s' server_cert_cb=%p server_cert_only=%d",
 +                 preverify_ok, err, X509_verify_cert_error_string(err),
 +               conn->ca_cert_verify, depth, buf, conn->server_cert_cb, conn->server_cert_only);
 +
 +
 +      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) {
 +        wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: allowing cert because depth > 0 && conn->server_cert_only\n");
 +              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, "tls_verify_cb: OpenSSL: Ignore certificate validity "
 +                         "time mismatch");
 +              preverify_ok = 1;
 +      }
 +
 +      err_str = X509_verify_cert_error_string(err);
 +
 +#ifdef CONFIG_SHA256
 +      if (depth == 0) {
 +        if (conn->server_cert_cb) {
 +            preverify_ok = conn->server_cert_cb(preverify_ok, err_cert, conn->server_cert_ctx);
 +            wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb: server_cert_cb returned %d", preverify_ok);
 +        }
 +        if (conn->server_cert_only) {
 +            /*
 +             * Do not require preverify_ok so we can explicity allow otherwise
 +             * invalid pinned server certificates.
 +             */
 +            struct wpabuf *cert;
 +            cert = get_x509_cert(err_cert);
 +            if (!cert) {
 +                wpa_printf(MSG_DEBUG, "tls_verify_cb: 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,
 +                               "tls_verify_cb: 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_verify_cb: 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(exit) - 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_verify_cb: 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_verify_cb: 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_verify_cb: 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_verify_cb: 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, "tls_verify_cb: 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);
 +      }
 +
-               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)
++#ifdef OPENSSL_IS_BORINGSSL
++      if (depth == 0 && (conn->flags & TLS_CONN_REQUEST_OCSP) &&
++          preverify_ok) {
++              enum ocsp_result res;
++
++              res = check_ocsp_resp(conn->ssl_ctx, conn->ssl, err_cert,
++                                    conn->peer_issuer,
++                                    conn->peer_issuer_issuer);
++              if (res == OCSP_REVOKED) {
++                      preverify_ok = 0;
++                      openssl_tls_fail_event(conn, err_cert, err, depth, buf,
++                                             "certificate revoked",
++                                             TLS_FAIL_REVOKED);
++                      if (err == X509_V_OK)
++                              X509_STORE_CTX_set_error(
++                                      x509_ctx, X509_V_ERR_CERT_REVOKED);
++              } else if (res != OCSP_GOOD &&
++                         (conn->flags & TLS_CONN_REQUIRE_OCSP)) {
++                      preverify_ok = 0;
++                      openssl_tls_fail_event(conn, err_cert, err, depth, buf,
++                                             "bad certificate status response",
++                                             TLS_FAIL_UNSPECIFIED);
++              }
++      }
++#endif /* OPENSSL_IS_BORINGSSL */
++
++      if (depth == 0 && preverify_ok && context->event_cb != NULL)
 +              context->event_cb(context->cb_ctx,
 +                                TLS_CERT_CHAIN_SUCCESS, NULL);
 +
 +      return preverify_ok;
 +}
 +
 +
 +#ifndef OPENSSL_NO_STDIO
 +static int tls_load_ca_der(struct tls_data *data, const char *ca_cert)
 +{
 +      SSL_CTX *ssl_ctx = data->ssl;
 +      X509_LOOKUP *lookup;
 +      int ret = 0;
 +
 +      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 */
 +
 +
 +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,
 +                                  int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx),
 +                                  void *server_cert_ctx)
 +{
 +      SSL_CTX *ssl_ctx = data->ssl;
 +      X509_STORE *store;
 +
 +      /*
 +       * Remove previously configured trusted CA certificates before adding
 +       * new ones.
 +       */
 +      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;
 +    conn->server_cert_cb = server_cert_cb;
 +    conn->server_cert_ctx = server_cert_ctx;
 +
 +      if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
 +                         "chain; setting conn->ca_cert_verify=0");
 +              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) {
 +              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;
 +              }
 +
 +              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
++      /* Single alias */
 +      if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
-               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);
++              if (tls_add_ca_from_keystore(SSL_CTX_get_cert_store(ssl_ctx),
++                                           &ca_cert[11]) < 0)
 +                      return -1;
++              SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
++              return 0;
++      }
 +
-               sk_X509_INFO_pop_free(stack, X509_INFO_free);
++      /* Multiple aliases separated by space */
++      if (ca_cert && os_strncmp("keystores://", ca_cert, 12) == 0) {
++              char *aliases = os_strdup(&ca_cert[12]);
++              const char *delim = " ";
++              int rc = 0;
++              char *savedptr;
++              char *alias;
++
++              if (!aliases)
++                      return -1;
++              alias = strtok_r(aliases, delim, &savedptr);
++              for (; alias; alias = strtok_r(NULL, delim, &savedptr)) {
++                      if (tls_add_ca_from_keystore_encoded(
++                                  SSL_CTX_get_cert_store(ssl_ctx), alias)) {
++                              wpa_printf(MSG_WARNING,
++                                         "OpenSSL: %s - Failed to add ca_cert %s from keystore",
++                                         __func__, alias);
++                              rc = -1;
++                              break;
 +                      }
 +              }
- #if OPENSSL_VERSION_NUMBER >= 0x10002000L
-               SSL_clear_chain_certs(ssl);
++              os_free(aliases);
++              if (rc)
++                      return rc;
++
 +              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_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");
 +                      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 */
 +              wpa_printf(MSG_DEBUG, "OpenSSL: tls_connection_ca_cert: No ca_cert; setting conn->ca_cert_verify=0");
 +              conn->ca_cert_verify = 0;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +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) {
 +              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,
 +                                          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,
 +                            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 {
 +              wpa_printf(MSG_DEBUG, "OpenSSL: tls_connection_set_verify: !verify_peer; setting conn->ca_cert_verify=0");
 +              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);
 +
 +      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;
 +
++#ifdef PKCS12_FUNCS
++#if OPENSSL_VERSION_NUMBER < 0x10002000L
++      /*
++       * Clear previously set extra chain certificates, if any, from PKCS#12
++       * processing in tls_parse_pkcs12() to allow OpenSSL to build a new
++       * chain properly.
++       */
++      SSL_CTX_clear_extra_chain_certs(conn->ssl_ctx);
++#endif /* OPENSSL_VERSION_NUMBER < 0x10002000L */
++#endif /* PKCS12_FUNCS */
++
 +      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;
 +      }
 +
 +      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;
 +      }
 +
 +      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_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
 +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_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_use_PrivateKey(data->ssl, pkey) != 1)
 +                              res = -1;
 +              }
 +              EVP_PKEY_free(pkey);
 +      }
 +
 +      if (certs) {
-                       if (SSL_add1_chain_cert(ssl, cert) != 1) {
++#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
++              if (ssl)
++                      SSL_clear_chain_certs(ssl);
++              else
++                      SSL_CTX_clear_chain_certs(data->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);
-               sk_X509_free(certs);
++                      if ((ssl && SSL_add1_chain_cert(ssl, cert) != 1) ||
++                          (!ssl && SSL_CTX_add1_chain_cert(data->ssl,
++                                                           cert) != 1)) {
 +                              tls_show_errors(MSG_DEBUG, __func__,
 +                                              "Failed to add additional certificate");
 +                              res = -1;
++                              X509_free(cert);
 +                              break;
 +                      }
++                      X509_free(cert);
 +              }
 +              if (!res) {
 +                      /* Try to continue anyway */
 +              }
-               res = SSL_build_cert_chain(ssl,
-                                          SSL_BUILD_CHAIN_FLAG_CHECK |
-                                          SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
++              sk_X509_pop_free(certs, X509_free);
 +#ifndef OPENSSL_IS_BORINGSSL
- #if OPENSSL_VERSION_NUMBER >= 0x10001000L
++              if (ssl)
++                      res = SSL_build_cert_chain(
++                              ssl,
++                              SSL_BUILD_CHAIN_FLAG_CHECK |
++                              SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR);
++              else
++                      res = SSL_CTX_build_cert_chain(
++                              data->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 */
- #endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */
 +              SSL_CTX_clear_extra_chain_certs(data->ssl);
-               sk_X509_free(certs);
 +              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...
 +                       */
 +                      if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1)
 +                      {
++                              X509_free(cert);
 +                              res = -1;
 +                              break;
 +                      }
 +              }
- #ifndef OPENSSL_NO_ENGINE
++              sk_X509_pop_free(certs, X509_free);
 +#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */
 +      }
 +
 +      PKCS12_free(p12);
 +
 +      if (res < 0)
 +              tls_get_errors(data);
 +
 +      return res;
 +}
 +#endif  /* PKCS12_FUNCS */
 +
 +
 +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;
 +      }
 +
 +      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 */
 +}
 +
 +
 +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;
 +
 +      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;
 +      }
 +
 +      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,
 +                         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 */
 +}
 +
 +
 +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;
 +      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 */
 +      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;
 +      }
 +      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)
 +{
- #if OPENSSL_VERSION_NUMBER < 0x10100000L
-       if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
-               return -1;
-       os_memset(keys, 0, sizeof(*keys));
-       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 defined(ANDROID) || !defined(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 */
 +}
 +
 +
 +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)
 +{
 +      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;
 +              }
 +
 +              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;
 +              }
 +
 +              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(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;
 +              }
 +
 +              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;
 +              }
 +#else /* OPENSSL_NO_STDIO */
 +              wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
 +                         __func__);
 +#endif /* OPENSSL_NO_STDIO */
 +
 +              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) {
 +              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);
 +
 +      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;
 +}
 +
 +
 +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);
 +
 +      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 */
 +}
 +
 +
 +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 */
 +}
 +
 +
 +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;
- #endif
 +      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));
- #ifndef CONFIG_FIPS
 +
 +      return 0;
 +}
 +
 +
- #if OPENSSL_VERSION_NUMBER < 0x10100000L
++#ifdef OPENSSL_NEED_EAP_FAST_PRF
 +static int openssl_get_keyblock_size(SSL *ssl)
 +{
- #if OPENSSL_VERSION_NUMBER >= 0x00909000L
++#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 +      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;
- #else
-       h = ssl->read_hash;
- #endif
 +      h = EVP_MD_CTX_md(ssl->read_hash);
- #if OPENSSL_VERSION_NUMBER >= 0x10000000L
 +      if (h)
 +              md_size = EVP_MD_size(h);
- #endif
 +      else if (ssl->s3)
 +              md_size = ssl->s3->tmp.new_mac_secret_size;
- #endif /* CONFIG_FIPS */
 +      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
 +}
- 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)
++#endif /* OPENSSL_NEED_EAP_FAST_PRF */
 +
 +
- #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);
++int tls_connection_export_key(void *tls_ctx, struct tls_connection *conn,
++                            const char *label, u8 *out, size_t out_len)
 +{
-       }
++      if (!conn ||
++          SSL_export_keying_material(conn->ssl, out, out_len, label,
++                                     os_strlen(label), NULL, 0, 0) != 1)
 +              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);
-       }
++      return 0;
++}
 +
-       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
 +
-        * 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.
++int tls_connection_get_eap_fast_key(void *tls_ctx, struct tls_connection *conn,
++                                  u8 *out, size_t out_len)
++{
++#ifdef OPENSSL_NEED_EAP_FAST_PRF
 +      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;
 +
 +      /*
-       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;
-       }
++       * TLS library did not support EAP-FAST 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 (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);
-       }
++      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));
 +
-                              label, rnd, 2 * SSL3_RANDOM_SIZE,
++      os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE);
++      os_memcpy(rnd + SSL3_RANDOM_SIZE, client_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,
++                             "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
 +                             _out, skip + out_len);
 +              ret = 0;
 +      } else if (tls_prf_sha1_md5(master_key, master_key_len,
-       if (ret == 0 && skip_keyblock)
++                                  "key expansion", rnd, 2 * SSL3_RANDOM_SIZE,
 +                                  _out, skip + out_len) == 0) {
 +              ret = 0;
 +      }
 +      os_memset(master_key, 0, sizeof(master_key));
 +      os_free(rnd);
- #endif
- #endif /* CONFIG_FIPS */
- }
- int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
-                      const char *label, int server_random_first,
-                      int skip_keyblock, u8 *out, size_t out_len)
- {
- #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);
++      if (ret == 0)
 +              os_memcpy(out, _out + skip, out_len);
 +      bin_clear_free(tmp_out, skip);
 +
 +      return ret;
- #if OPENSSL_VERSION_NUMBER >= 0x10001000L
++#else /* OPENSSL_NEED_EAP_FAST_PRF */
++      wpa_printf(MSG_ERROR,
++                 "OpenSSL: EAP-FAST keys cannot be exported in FIPS mode");
++      return -1;
++#endif /* OPENSSL_NEED_EAP_FAST_PRF */
 +}
 +
 +
 +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 (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 (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)
 +{
- #else
-       return conn ? conn->ssl->hit : 0;
- #endif
 +      return conn ? SSL_cache_hit(conn->ssl) : 0;
-       char buf[100], *pos, *end;
 +}
 +
 +
 +int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
 +                                 u8 *ciphers)
 +{
- #if OPENSSL_VERSION_NUMBER >= 0x10100000L
++      char buf[500], *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;
++              case TLS_CIPHER_RSA_DHE_AES256_SHA:
++                      suite = "DHE-RSA-AES256-SHA";
++                      break;
++              case TLS_CIPHER_AES256_SHA:
++                      suite = "AES256-SHA";
++                      break;
 +              default:
 +                      wpa_printf(MSG_DEBUG, "TLS: Unsupported "
 +                                 "cipher selection: %d", *c);
 +                      return -1;
 +              }
 +              ret = os_snprintf(pos, end - pos, ":%s", suite);
 +              if (os_snprintf_error(end - pos, ret))
 +                      break;
 +              pos += ret;
 +
 +              c++;
 +      }
 +
 +      wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
 +
- #ifdef OPENSSL_IS_BORINGSSL
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
 +#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;
 +
 +      if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
 +                                     data_len) != 1)
 +              return -1;
 +
 +      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_CERTID_free(id);
 +              OCSP_BASICRESP_free(basic);
 +              OCSP_RESPONSE_free(rsp);
 +              return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1;
 +      }
++      OCSP_CERTID_free(id);
 +
 +      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 (params->flags & TLS_CONN_REQUIRE_OCSP_ALL) {
++              wpa_printf(MSG_INFO,
++                         "OpenSSL: ocsp=3 not supported");
++              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));
 +      }
 +
 +      if (engine_id) {
 +              wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
 +              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,
 +                                           params->altsubject_match,
 +                                           params->suffix_match,
 +                                           params->domain_match))
 +              return -1;
 +
 +      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;
 +      } else {
 +        if (tls_connection_ca_cert(data, conn, params->ca_cert,
 +                                   params->ca_cert_blob,
 +                                   params->ca_cert_blob_len,
 +                                   params->ca_path, params->server_cert_cb, 
 +                                   params->server_cert_ctx))
 +            return -1;
 +    }
 +
 +      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;
 +
 +      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;
 +      } 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;
 +      }
 +
 +      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 OPENSSL_IS_BORINGSSL
++      if (params->flags & TLS_CONN_REQUEST_OCSP) {
++              SSL_enable_ocsp_stapling(conn->ssl);
++      }
++#else /* OPENSSL_IS_BORINGSSL */
 +#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 */
++#endif /* OPENSSL_IS_BORINGSSL */
 +
 +      conn->flags = params->flags;
 +
 +      tls_get_errors(data);
 +
 +      return 0;
 +}
 +
 +
 +int tls_global_set_params(void *tls_ctx,
 +                        const struct tls_connection_params *params)
 +{
 +      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));
 +      }
 +
 +      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;
 +      }
 +
 +      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;
 +      }
 +
 +#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 */
 +
 +      return 0;
 +}
 +
 +
 +#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. */
 +
- #if OPENSSL_VERSION_NUMBER < 0x10100000L
++#if (defined(OPENSSL_IS_BORINGSSL) || OPENSSL_VERSION_NUMBER >= 0x10100000L) && !defined(LIBRESSL_VERSION_NUMBER)
 +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 || defined(LIBRESSL_VERSION_NUMBER)
 +      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;
 +}
 +
 +
 +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;
 +}
 +#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;
 +              SSL_set_session_ticket_ext_cb(conn->ssl,
 +                                            tls_session_ticket_ext_cb, conn);
 +      } else {
 +              if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
 +                      return -1;
 +              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)
 +{
++#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
++      return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
++                         OPENSSL_VERSION_TEXT,
++                         OpenSSL_version(OPENSSL_VERSION));
++#else
 +      return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s",
 +                         OPENSSL_VERSION_TEXT,
 +                         SSLeay_version(SSLEAY_VERSION));
++#endif
 +}
 +
 +
 +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");
 +}
index 0000000,2a62d5c..2a62d5c
mode 000000,100644..100644
--- /dev/null
index 0000000,8b37b34..8b37b34
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
index 6d547fb,0000000..40d8a42
mode 100644,000000..100644
--- /dev/null
@@@ -1,115 -1,0 +1,115 @@@
-                        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);
 +/*
 + * EAP-FAST definitions (RFC 4851)
 + * 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_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,
++                       size_t len);
++int eap_fast_derive_eap_msk(const u8 *simck, u8 *msk);
++int 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 */
Simple merge
Simple merge
Simple merge
index 0dc8ea8,0000000..fca972f
mode 100644,000000..100644
--- /dev/null
@@@ -1,826 -1,0 +1,840 @@@
-        * server certificate. If this string is set, the server sertificate is
 +/*
 + * EAP peer configuration data
 + * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
 + *
 + * 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
 +
 +#include <openssl/x509.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.
 +       */
 +      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
-        * Note: Since this is a substring match, this cannot be used securily
++       * server certificate. If this string is set, the server certificate 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
 +       *
-        * If this string is set, the server sertificate is only accepted if it
++       * Note: Since this is a substring match, this cannot be used securely
 +       * 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 non-null, specifies a callback method that can be used to
-      * override the validity of a peer certificate.
++       * If this string is set, the server certificate 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.
 +       */
 +      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;
 +
++      /**
++       * pending_ext_cert_check - External server certificate check status
++       *
++       * This field should not be set in configuration step. It is only used
++       * internally when control interface is used to request external
++       * validation of server certificate chain.
++       */
++      enum {
++              NO_CHECK = 0,
++              PENDING_CHECK,
++              EXT_CERT_CHECK_GOOD,
++              EXT_CERT_CHECK_BAD,
++      } pending_ext_cert_check;
++
 +    /**
++     * server_cert_cb -- if non-null, specifies a callback method that can
++     * be used to override the validity of a peer (server/acceptor) certificate.
 +     */
 +    int (*server_cert_cb)(int ok_so_far, X509* cert, void *ca_ctx);
 +    void *server_cert_ctx;
 +};
 +
 +
 +/**
 + * 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 */
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 5d915fa,0000000..f1f5d55
mode 100644,000000..100644
--- /dev/null
@@@ -1,397 -1,0 +1,399 @@@
 +/*
 + * EAP peer state machines internal structures (RFC 4137)
 + * 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_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;
 +      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;
++      unsigned int ext_cert_check:1;
++      unsigned int waiting_ext_cert_check: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 11c3278,0000000..ee4a1f5
mode 100644,000000..100644
--- /dev/null
@@@ -1,119 -1,0 +1,118 @@@
- void eap_peer_method_free(struct eap_method *method);
 +/*
 + * 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);
 +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
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index bc4482a,0000000..0d17122
mode 100644,000000..100644
--- /dev/null
@@@ -1,1115 -1,0 +1,1124 @@@
-       if (config->ocsp == 2)
 +/*
 + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
 + * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
 + *
 + * 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;
++      if (os_strstr(txt, "tls_ext_cert_check=1"))
++              params->flags |= TLS_CONN_EXT_CERT_CHECK;
++      if (os_strstr(txt, "tls_ext_cert_check=0"))
++              params->flags &= ~TLS_CONN_EXT_CERT_CHECK;
 +}
 +
 +
 +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);
 +    params->server_cert_cb = config->server_cert_cb;
 +    params->server_cert_ctx = config->server_cert_ctx;
 +}
 +
 +
 +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);
 +    params->server_cert_cb = config->server_cert_cb;
 +    params->server_cert_ctx = config->server_cert_ctx;
 +}
 +
 +
 +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;
 +      }
 +
 +      /*
 +       * 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;
 +
++      sm->ext_cert_check = !!(params->flags & TLS_CONN_EXT_CERT_CHECK);
++
 +      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;
 +
 +      if (config->ocsp)
 +              params->flags |= TLS_CONN_REQUEST_OCSP;
-       if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0,
-                              out, len)) {
++      if (config->ocsp >= 2)
 +              params->flags |= TLS_CONN_REQUIRE_OCSP;
++      if (config->ocsp == 3)
++              params->flags |= TLS_CONN_REQUIRE_OCSP_ALL;
 +      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;
 +      }
 +
 +      res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
 +      if (res == TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN) {
 +              /*
 +               * 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");
 +              sm->ignore = TRUE;
 +      }
 +      if (res) {
 +              wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
 +                         "parameters");
 +              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,
 +                        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)
 +{
 +      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)
 +{
 +      u8 *out;
 +
 +      out = os_malloc(len);
 +      if (out == NULL)
 +              return NULL;
 +
-       if (tls_connection_get_random(sm->ssl_ctx, data->conn, &keys))
-               return NULL;
-       if (keys.client_random == NULL || keys.server_random == NULL)
++      if (tls_connection_export_key(data->ssl_ctx, data->conn, label, out,
++                                    len)) {
 +              os_free(out);
 +              return NULL;
 +      }
 +
 +      return out;
 +}
 +
 +
 +/**
 + * 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) ||
++          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);
 +
 +      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;
 +      }
 +      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
 + * @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,
 +                               const struct wpabuf *in_data,
 +                               struct wpabuf **out_data)
 +{
 +      const struct wpabuf *msg;
 +      int need_more_input;
 +      struct wpabuf *appl_data;
 +
 +      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;
 +      data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
 +                                               msg, &appl_data);
 +
 +      eap_peer_tls_reset_input(data);
 +
 +      if (appl_data &&
 +          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;
 +      }
 +
 +      *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
 + * @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,
 +                              u8 id, const struct wpabuf *in_data,
 +                              struct wpabuf **out_data)
 +{
 +      int ret = 0;
 +
 +      *out_data = NULL;
 +
 +      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.
 +               */
 +              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;
 +      }
 +
 +      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 "
 +                         "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;
 +              }
 +      }
 +
 +      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;
 +
 +      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);
 +      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)
 +{
 +      char version[20], name[128];
 +      int len = 0, ret;
 +
 +      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);
 +
 +      //// 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;
 +
 +      *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);
 +              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;
 +      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);
++                      os_free(methods);
++                      os_free(buf);
++                      return -1;
 +              } 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;
 +}
Simple merge
index c174fe5,0000000..12ea169
mode 100644,000000..100644
--- /dev/null
@@@ -1,1956 -1,0 +1,2048 @@@
-  * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
 +/*
 + * EAP peer method: EAP-TTLS (RFC 5281)
-   EapDecision cbDecision;
++ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
 + *
 + * 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"
 +
 +
 +#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;
 +
 +      const struct eap_method *phase2_method;
 +      void *phase2_priv;
 +      int phase2_success;
 +      int phase2_start;
++      EapDecision decision_succ;
 +
 +      enum phase2_types {
 +              EAP_TTLS_PHASE2_EAP,
 +              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;
++      struct wpabuf *pending_resp;
 +      int chbind_req_sent; /* channel binding request was sent */
 +      int done_butfor_cb; /*we turned METHOD_DONE into METHOD_MAY_CONT to receive cb*/
-               } 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;
++      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);
++      int selected_non_eap;
 +      char *selected;
 +
 +      data = os_zalloc(sizeof(*data));
 +      if (data == NULL)
 +              return NULL;
 +      data->ttls_version = EAP_TTLS_VERSION;
 +      selected = "EAP";
++      selected_non_eap = 0;
 +      data->phase2_type = EAP_TTLS_PHASE2_EAP;
 +
++      /*
++       * Either one auth= type or one or more autheap= methods can be
++       * specified.
++       */
 +      if (config && config->phase2) {
++              const char *token, *last = NULL;
++
++              while ((token = cstr_token(config->phase2, " \t", &last))) {
++                      if (os_strncmp(token, "auth=", 5) != 0)
++                              continue;
++                      token += 5;
++
++                      if (last - token == 8 &&
++                          os_strncmp(token, "MSCHAPV2", 8) == 0) {
++                              selected = "MSCHAPV2";
++                              data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
++                      } else if (last - token == 6 &&
++                                 os_strncmp(token, "MSCHAP", 6) == 0) {
++                              selected = "MSCHAP";
++                              data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
++                      } else if (last - token == 3 &&
++                                 os_strncmp(token, "PAP", 3) == 0) {
++                              selected = "PAP";
++                              data->phase2_type = EAP_TTLS_PHASE2_PAP;
++                      } else if (last - token == 4 &&
++                                 os_strncmp(token, "CHAP", 4) == 0) {
++                              selected = "CHAP";
++                              data->phase2_type = EAP_TTLS_PHASE2_CHAP;
++                      } else {
++                              wpa_printf(MSG_ERROR,
++                                         "EAP-TTLS: Unsupported Phase2 type '%s'",
++                                         token);
++                              eap_ttls_deinit(sm, data);
++                              return NULL;
++                      }
++
++                      if (selected_non_eap) {
++                              wpa_printf(MSG_ERROR,
++                                         "EAP-TTLS: Only one Phase2 type can be specified");
++                              eap_ttls_deinit(sm, data);
++                              return NULL;
++                      }
++
++                      selected_non_eap = 1;
++              }
++
 +              if (os_strstr(config->phase2, "autheap=")) {
++                      if (selected_non_eap) {
++                              wpa_printf(MSG_ERROR,
++                                         "EAP-TTLS: Both auth= and autheap= params cannot be specified");
++                              eap_ttls_deinit(sm, data);
++                              return NULL;
++                      }
 +                      selected = "EAP";
 +                      data->phase2_type = EAP_TTLS_PHASE2_EAP;
-       int ret;
 +              }
 +      }
++
 +      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;
 +      }
 +
 +      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;
 +      }
 +
 +      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);
 +      eap_peer_tls_ssl_deinit(sm, &data->ssl);
 +      eap_ttls_free_key(data);
 +      os_free(data->session_id);
 +      wpabuf_free(data->pending_phase2_req);
++      wpabuf_free(data->pending_resp);
 +      os_free(data);
 +}
 +
 +
 +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);
 +      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;
 +}
 +
 +static int eap_ttls_v0_derive_key(struct eap_sm *sm,
 +                                struct eap_ttls_data *data)
 +{
 +      eap_ttls_free_key(data);
 +      data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
 +                                               "ttls keying material",
 +                                               EAP_TLS_KEY_LEN +
 +                                               EAP_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_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");
 +      }
 +
 +      return 0;
 +}
 +
 +
 +#ifndef CONFIG_FIPS
 +static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
 +                                      struct eap_ttls_data *data, size_t len)
 +{
 +      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;
 +      }
 +
 +      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);
 +}
 +
 +
 +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;
 +      }
 +
 +      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 */
 +      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;
 +
 +      pos += 24;
 +      os_free(challenge);
 +      AVP_PAD(buf, pos);
 +
 +      wpabuf_put(msg, pos - buf);
 +      *resp = msg;
 +
 +      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;
 +
 +      /* 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;
 +
 +      /* 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;
 +
 +      /* 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;
 +}
 +
 +
 +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");
 +      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;
 +}
 +
 +
 +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;
 +
 +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;
 +}
 +
 +
 +static int eap_ttls_process_handshake(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)
 +{
 +      int res;
 +
++      if (sm->waiting_ext_cert_check && data->pending_resp) {
++              struct eap_peer_config *config = eap_get_config(sm);
++
++              if (config->pending_ext_cert_check == EXT_CERT_CHECK_GOOD) {
++                      wpa_printf(MSG_DEBUG,
++                                 "EAP-TTLS: External certificate check succeeded - continue handshake");
++                      *out_data = data->pending_resp;
++                      data->pending_resp = NULL;
++                      sm->waiting_ext_cert_check = 0;
++                      return 0;
++              }
++
++              if (config->pending_ext_cert_check == EXT_CERT_CHECK_BAD) {
++                      wpa_printf(MSG_DEBUG,
++                                 "EAP-TTLS: External certificate check failed - force authentication failure");
++                      ret->methodState = METHOD_DONE;
++                      ret->decision = DECISION_FAIL;
++                      sm->waiting_ext_cert_check = 0;
++                      return 0;
++              }
++
++              wpa_printf(MSG_DEBUG,
++                         "EAP-TTLS: Continuing to wait external server certificate validation");
++              return 0;
++      }
++
 +      res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
 +                                        data->ttls_version, identifier,
 +                                        in_data, out_data);
 +      if (res < 0) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed");
 +              ret->methodState = METHOD_DONE;
 +              ret->decision = DECISION_FAIL;
 +              return -1;
 +      }
 +
++      if (sm->waiting_ext_cert_check) {
++              wpa_printf(MSG_DEBUG,
++                         "EAP-TTLS: Waiting external server certificate validation");
++              wpabuf_free(data->pending_resp);
++              data->pending_resp = *out_data;
++              *out_data = NULL;
++              return 0;
++      }
++
 +      if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
 +              wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
 +                         "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;
 +              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) {
 +              /*
 +               * Application data included in the handshake message.
 +               */
 +              wpabuf_free(data->pending_phase2_req);
 +              data->pending_phase2_req = *out_data;
 +              *out_data = NULL;
 +              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)
 +{
 +      if (ret->methodState == METHOD_DONE) {
 +              ret->allowNotifications = FALSE;
 +              if (ret->decision == DECISION_UNCOND_SUCC ||
 +                  ret->decision == DECISION_COND_SUCC) {
 +                      wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
 +                                 "completed successfully");
 +                      data->phase2_success = 1;
++                      data->decision_succ = ret->decision;
 +#ifdef EAP_TNC
 +                      if (!data->ready_for_tnc && !data->tnc_started) {
 +                              /*
 +                               * 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 */
 +              }
 +      } else if (ret->methodState == METHOD_MAY_CONT &&
 +                 (ret->decision == DECISION_UNCOND_SUCC ||
 +                  ret->decision == DECISION_COND_SUCC)) {
 +                      wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
 +                                 "completed successfully (MAY_CONT)");
 +                      data->phase2_success = 1;
++                      data->decision_succ = ret->decision;
++      } else if (data->decision_succ != DECISION_FAIL &&
++                 data->phase2_success &&
++                 !data->ssl.tls_out) {
++              /*
++               * This is needed to cover the case where the final Phase 2
++               * message gets fragmented since fragmentation clears
++               * decision back to FAIL.
++               */
++              wpa_printf(MSG_DEBUG,
++                         "EAP-TTLS: Restore success decision after fragmented frame sent completely");
++              ret->decision = data->decision_succ;
 +      }
 +}
 +
 +
 +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) {
 +              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;
 +      }
 +
 +      wpabuf_set(&msg, pos, left);
 +
 +      resp = NULL;
 +      if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
 +          !data->resuming) {
 +              res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp);
 +      } else {
 +              res = eap_ttls_process_handshake(sm, data, ret, id,
 +                                               &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;
++      wpabuf_free(data->pending_resp);
++      data->pending_resp = NULL;
++      data->decision_succ = DECISION_FAIL;
 +#ifdef EAP_TNC
 +      data->ready_for_tnc = 0;
 +      data->tnc_started = 0;
 +#endif /* EAP_TNC */
 +}
 +
 +
 +static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
 +{
 +      struct eap_ttls_data *data = priv;
 +      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 (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;
-       ret = eap_peer_method_register(eap);
-       if (ret)
-               eap_peer_method_free(eap);
-       return 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;
 +
++      return eap_peer_method_register(eap);
 +}
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
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,1d7b68c..1d7b68c
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
index 13aa941,0000000..2a185fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,568 -1,0 +1,584 @@@
 +/*
 + * wpa_supplicant/hostapd / common helper functions, etc.
 + * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
 + *
 + * 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_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 */
 +
 +#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 */
 +
 +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_IP
++#define ETH_P_IP 0x0800
++#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))
++#undef __bitwise
 +#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 */
 +
++#define SSID_MAX_LEN 32
++
++struct wpa_ssid_value {
++      u8 ssid[SSID_MAX_LEN];
++      size_t ssid_len;
++};
++
 +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);
++int ssid_parse(const char *buf, struct wpa_ssid_value *ssid);
 +
 +#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);
++int has_ctrl_char(const u8 *data, size_t len);
++int has_newline(const char *str);
 +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);
 +
++int str_starts(const char *str, const char *start);
++
 +
 +/*
 + * 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 */
Simple merge
Simple merge
index 00233a0,0000000..ef5fd0a
mode 100644,000000..100644
--- /dev/null
@@@ -1,368 -1,0 +1,376 @@@
 +/*
 + * Event loop
 + * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + *
 + * This file defines an event loop interface that supports processing events
 + * from registered timeouts (i.e., do something after N seconds), sockets
 + * (e.g., a new packet available for reading), and signals. eloop.c is an
 + * implementation of this interface using select() and sockets. This is
 + * suitable for most UNIX/POSIX systems. When porting to other operating
 + * systems, it may be necessary to replace that implementation with OS specific
 + * mechanisms.
 + */
 +
 +#ifndef ELOOP_H
 +#define ELOOP_H
 +
 +#ifdef __cplusplus
 +extern "C" {
 +#endif
 +
 +
 +/**
 + * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts
 + */
 +#define ELOOP_ALL_CTX (void *) -1
 +
 +/**
 + * eloop_event_type - eloop socket event type for eloop_register_sock()
 + * @EVENT_TYPE_READ: Socket has data available for reading
 + * @EVENT_TYPE_WRITE: Socket has room for new data to be written
 + * @EVENT_TYPE_EXCEPTION: An exception has been reported
 + */
 +typedef enum {
 +      EVENT_TYPE_READ = 0,
 +      EVENT_TYPE_WRITE,
 +      EVENT_TYPE_EXCEPTION
 +} eloop_event_type;
 +
 +/**
 + * eloop_sock_handler - eloop socket event callback type
 + * @sock: File descriptor number for the socket
 + * @eloop_ctx: Registered callback context data (eloop_data)
 + * @sock_ctx: Registered callback context data (user_data)
 + */
 +typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx);
 +
 +/**
 + * eloop_event_handler - eloop generic event callback type
 + * @eloop_ctx: Registered callback context data (eloop_data)
 + * @sock_ctx: Registered callback context data (user_data)
 + */
 +typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
 +
 +/**
 + * eloop_timeout_handler - eloop timeout event callback type
 + * @eloop_ctx: Registered callback context data (eloop_data)
 + * @sock_ctx: Registered callback context data (user_data)
 + */
 +typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
 +
 +/**
 + * eloop_signal_handler - eloop signal event callback type
 + * @sig: Signal number
 + * @signal_ctx: Registered callback context data (user_data from
 + * eloop_register_signal(), eloop_register_signal_terminate(), or
 + * eloop_register_signal_reconfig() call)
 + */
 +typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
 +
 +/**
 + * eloop_init() - Initialize global event loop data
 + * Returns: 0 on success, -1 on failure
 + *
 + * This function must be called before any other eloop_* function.
 + */
 +int eloop_init(void);
 +
 +/**
 + * eloop_register_read_sock - Register handler for read events
 + * @sock: File descriptor number for the socket
 + * @handler: Callback function to be called when data is available for reading
 + * @eloop_data: Callback context data (eloop_ctx)
 + * @user_data: Callback context data (sock_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a read socket notifier for the given file descriptor. The handler
 + * function will be called whenever data is available for reading from the
 + * socket. The handler function is responsible for clearing the event after
 + * having processed it in order to avoid eloop from calling the handler again
 + * for the same event.
 + */
 +int eloop_register_read_sock(int sock, eloop_sock_handler handler,
 +                           void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_unregister_read_sock - Unregister handler for read events
 + * @sock: File descriptor number for the socket
 + *
 + * Unregister a read socket notifier that was previously registered with
 + * eloop_register_read_sock().
 + */
 +void eloop_unregister_read_sock(int sock);
 +
 +/**
 + * eloop_register_sock - Register handler for socket events
 + * @sock: File descriptor number for the socket
 + * @type: Type of event to wait for
 + * @handler: Callback function to be called when the event is triggered
 + * @eloop_data: Callback context data (eloop_ctx)
 + * @user_data: Callback context data (sock_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register an event notifier for the given socket's file descriptor. The
 + * handler function will be called whenever the that event is triggered for the
 + * socket. The handler function is responsible for clearing the event after
 + * having processed it in order to avoid eloop from calling the handler again
 + * for the same event.
 + */
 +int eloop_register_sock(int sock, eloop_event_type type,
 +                      eloop_sock_handler handler,
 +                      void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_unregister_sock - Unregister handler for socket events
 + * @sock: File descriptor number for the socket
 + * @type: Type of event for which sock was registered
 + *
 + * Unregister a socket event notifier that was previously registered with
 + * eloop_register_sock().
 + */
 +void eloop_unregister_sock(int sock, eloop_event_type type);
 +
 +/**
 + * eloop_register_event - Register handler for generic events
 + * @event: Event to wait (eloop implementation specific)
 + * @event_size: Size of event data
 + * @handler: Callback function to be called when event is triggered
 + * @eloop_data: Callback context data (eloop_data)
 + * @user_data: Callback context data (user_data)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register an event handler for the given event. This function is used to
 + * register eloop implementation specific events which are mainly targeted for
 + * operating system specific code (driver interface and l2_packet) since the
 + * portable code will not be able to use such an OS-specific call. The handler
 + * function will be called whenever the event is triggered. The handler
 + * function is responsible for clearing the event after having processed it in
 + * order to avoid eloop from calling the handler again for the same event.
 + *
 + * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE
 + * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable,
 + * and they would call this function with eloop_register_event(h, sizeof(h),
 + * ...).
 + */
 +int eloop_register_event(void *event, size_t event_size,
 +                       eloop_event_handler handler,
 +                       void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_unregister_event - Unregister handler for a generic event
 + * @event: Event to cancel (eloop implementation specific)
 + * @event_size: Size of event data
 + *
 + * Unregister a generic event notifier that was previously registered with
 + * eloop_register_event().
 + */
 +void eloop_unregister_event(void *event, size_t event_size);
 +
 +/**
 + * eloop_register_timeout - Register timeout
 + * @secs: Number of seconds to the timeout
 + * @usecs: Number of microseconds to the timeout
 + * @handler: Callback function to be called when timeout occurs
 + * @eloop_data: Callback context data (eloop_ctx)
 + * @user_data: Callback context data (sock_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a timeout that will cause the handler function to be called after
 + * given time.
 + */
 +int eloop_register_timeout(unsigned int secs, unsigned int usecs,
 +                         eloop_timeout_handler handler,
 +                         void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_cancel_timeout - Cancel timeouts
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all
 + * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all
 + * Returns: Number of cancelled timeouts
 + *
 + * Cancel matching <handler,eloop_data,user_data> timeouts registered with
 + * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
 + * cancelling all timeouts regardless of eloop_data/user_data.
 + */
 +int eloop_cancel_timeout(eloop_timeout_handler handler,
 +                       void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_cancel_timeout_one - Cancel a single timeout
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data
 + * @user_data: Matching user_data
 + * @remaining: Time left on the cancelled timer
 + * Returns: Number of cancelled timeouts
 + *
 + * Cancel matching <handler,eloop_data,user_data> timeout registered with
 + * eloop_register_timeout() and return the remaining time left.
 + */
 +int eloop_cancel_timeout_one(eloop_timeout_handler handler,
 +                           void *eloop_data, void *user_data,
 +                           struct os_reltime *remaining);
 +
 +/**
 + * eloop_is_timeout_registered - Check if a timeout is already registered
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data
 + * @user_data: Matching user_data
 + * Returns: 1 if the timeout is registered, 0 if the timeout is not registered
 + *
 + * Determine if a matching <handler,eloop_data,user_data> timeout is registered
 + * with eloop_register_timeout().
 + */
 +int eloop_is_timeout_registered(eloop_timeout_handler handler,
 +                              void *eloop_data, void *user_data);
 +
 +/**
 + * eloop_deplete_timeout - Deplete a timeout that is already registered
 + * @req_secs: Requested number of seconds to the timeout
 + * @req_usecs: Requested number of microseconds to the timeout
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data
 + * @user_data: Matching user_data
 + * Returns: 1 if the timeout is depleted, 0 if no change is made, -1 if no
 + * timeout matched
 + *
 + * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
 + * deplete the timeout if remaining time is more than the requested time.
 + */
 +int eloop_deplete_timeout(unsigned int req_secs, unsigned int req_usecs,
 +                        eloop_timeout_handler handler, void *eloop_data,
 +                        void *user_data);
 +
 +/**
 + * eloop_replenish_timeout - Replenish a timeout that is already registered
 + * @req_secs: Requested number of seconds to the timeout
 + * @req_usecs: Requested number of microseconds to the timeout
 + * @handler: Matching callback function
 + * @eloop_data: Matching eloop_data
 + * @user_data: Matching user_data
 + * Returns: 1 if the timeout is replenished, 0 if no change is made, -1 if no
 + * timeout matched
 + *
 + * Find a registered matching <handler,eloop_data,user_data> timeout. If found,
 + * replenish the timeout if remaining time is less than the requested time.
 + */
 +int eloop_replenish_timeout(unsigned int req_secs, unsigned int req_usecs,
 +                          eloop_timeout_handler handler, void *eloop_data,
 +                          void *user_data);
 +
 +/**
 + * eloop_register_signal - Register handler for signals
 + * @sig: Signal number (e.g., SIGHUP)
 + * @handler: Callback function to be called when the signal is received
 + * @user_data: Callback context data (signal_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a callback function that will be called when a signal is received.
 + * The callback function is actually called only after the system signal
 + * handler has returned. This means that the normal limits for sighandlers
 + * (i.e., only "safe functions" allowed) do not apply for the registered
 + * callback.
 + */
 +int eloop_register_signal(int sig, eloop_signal_handler handler,
 +                        void *user_data);
 +
 +/**
 + * eloop_register_signal_terminate - Register handler for terminate signals
 + * @handler: Callback function to be called when the signal is received
 + * @user_data: Callback context data (signal_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a callback function that will be called when a process termination
 + * signal is received. The callback function is actually called only after the
 + * system signal handler has returned. This means that the normal limits for
 + * sighandlers (i.e., only "safe functions" allowed) do not apply for the
 + * registered callback.
 + *
 + * This function is a more portable version of eloop_register_signal() since
 + * the knowledge of exact details of the signals is hidden in eloop
 + * implementation. In case of operating systems using signal(), this function
 + * registers handlers for SIGINT and SIGTERM.
 + */
 +int eloop_register_signal_terminate(eloop_signal_handler handler,
 +                                  void *user_data);
 +
 +/**
 + * eloop_register_signal_reconfig - Register handler for reconfig signals
 + * @handler: Callback function to be called when the signal is received
 + * @user_data: Callback context data (signal_ctx)
 + * Returns: 0 on success, -1 on failure
 + *
 + * Register a callback function that will be called when a reconfiguration /
 + * hangup signal is received. The callback function is actually called only
 + * after the system signal handler has returned. This means that the normal
 + * limits for sighandlers (i.e., only "safe functions" allowed) do not apply
 + * for the registered callback.
 + *
 + * This function is a more portable version of eloop_register_signal() since
 + * the knowledge of exact details of the signals is hidden in eloop
 + * implementation. In case of operating systems using signal(), this function
 + * registers a handler for SIGHUP.
 + */
 +int eloop_register_signal_reconfig(eloop_signal_handler handler,
 +                                 void *user_data);
 +
 +/**
++ * eloop_sock_requeue - Requeue sockets
++ *
++ * Requeue sockets after forking because some implementations require this,
++ * such as epoll and kqueue.
++ */
++int eloop_sock_requeue(void);
++
++/**
 + * eloop_run - Start the event loop
 + *
 + * Start the event loop and continue running as long as there are any
 + * registered event handlers. This function is run after event loop has been
 + * initialized with event_init() and one or more events have been registered.
 + */
 +void eloop_run(void);
 +
 +/**
 + * eloop_terminate - Terminate event loop
 + *
 + * Terminate event loop even if there are registered events. This can be used
 + * to request the program to be terminated cleanly.
 + */
 +void eloop_terminate(void);
 +
 +/**
 + * eloop_destroy - Free any resources allocated for the event loop
 + *
 + * After calling eloop_destroy(), other eloop_* functions must not be called
 + * before re-running eloop_init().
 + */
 +void eloop_destroy(void);
 +
 +/**
 + * eloop_terminated - Check whether event loop has been terminated
 + * Returns: 1 = event loop terminate, 0 = event loop still running
 + *
 + * This function can be used to check whether eloop_terminate() has been called
 + * to request termination of the event loop. This is normally used to abort
 + * operations that may still be queued to be run when eloop_terminate() was
 + * called.
 + */
 +int eloop_terminated(void);
 +
 +/**
 + * eloop_wait_for_read_sock - Wait for a single reader
 + * @sock: File descriptor number for the socket
 + *
 + * Do a blocking wait for a single read socket.
 + */
 +void eloop_wait_for_read_sock(int sock);
 +
 +#ifdef __cplusplus
 +}
 +#endif
 +
 +#endif /* ELOOP_H */
Simple merge
Simple merge
Simple merge
Simple merge
index 0000000,3bfe4ad..3bfe4ad
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 7c72ea4,0000000..2983ad3
mode 100644,000000..100644
--- /dev/null
@@@ -1,860 -1,0 +1,862 @@@
-               if (strcmp(fstype, "debugfs") == 0) {
 +/*
 + * wpa_supplicant/hostapd / Debug prints
 + * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
 + *
 + * This software may be distributed under the terms of the BSD license.
 + * See README for more details.
 + */
 +
 +#include "includes.h"
 +
 +#include "common.h"
 +
 +#ifdef CONFIG_DEBUG_SYSLOG
 +#include <syslog.h>
 +
 +static int wpa_debug_syslog = 0;
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +#include <sys/types.h>
 +#include <sys/stat.h>
 +#include <fcntl.h>
 +#include <string.h>
 +#include <stdio.h>
 +
 +static FILE *wpa_debug_tracing_file = NULL;
 +
 +#define WPAS_TRACE_PFX "wpas <%d>: "
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +
 +
 +int wpa_debug_level = MSG_INFO;
 +int wpa_debug_show_keys = 0;
 +int wpa_debug_timestamp = 0;
 +
 +
 +#ifdef CONFIG_ANDROID_LOG
 +
 +#include <android/log.h>
 +
 +#ifndef ANDROID_LOG_NAME
 +#define ANDROID_LOG_NAME      "wpa_supplicant"
 +#endif /* ANDROID_LOG_NAME */
 +
 +static int wpa_to_android_level(int level)
 +{
 +      if (level == MSG_ERROR)
 +              return ANDROID_LOG_ERROR;
 +      if (level == MSG_WARNING)
 +              return ANDROID_LOG_WARN;
 +      if (level == MSG_INFO)
 +              return ANDROID_LOG_INFO;
 +      return ANDROID_LOG_DEBUG;
 +}
 +
 +#endif /* CONFIG_ANDROID_LOG */
 +
 +#ifndef CONFIG_NO_STDOUT_DEBUG
 +
 +#ifdef CONFIG_DEBUG_FILE
 +static FILE *out_file = NULL;
 +#endif /* CONFIG_DEBUG_FILE */
 +
 +
 +void wpa_debug_print_timestamp(void)
 +{
 +#ifndef CONFIG_ANDROID_LOG
 +      struct os_time tv;
 +
 +      if (!wpa_debug_timestamp)
 +              return;
 +
 +      os_get_time(&tv);
 +#ifdef CONFIG_DEBUG_FILE
 +      if (out_file) {
 +              fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
 +                      (unsigned int) tv.usec);
 +      } else
 +#endif /* CONFIG_DEBUG_FILE */
 +      printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
 +#endif /* CONFIG_ANDROID_LOG */
 +}
 +
 +
 +#ifdef CONFIG_DEBUG_SYSLOG
 +#ifndef LOG_HOSTAPD
 +#define LOG_HOSTAPD LOG_DAEMON
 +#endif /* LOG_HOSTAPD */
 +
 +void wpa_debug_open_syslog(void)
 +{
 +      openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD);
 +      wpa_debug_syslog++;
 +}
 +
 +
 +void wpa_debug_close_syslog(void)
 +{
 +      if (wpa_debug_syslog)
 +              closelog();
 +}
 +
 +
 +static int syslog_priority(int level)
 +{
 +      switch (level) {
 +      case MSG_MSGDUMP:
 +      case MSG_DEBUG:
 +              return LOG_DEBUG;
 +      case MSG_INFO:
 +              return LOG_NOTICE;
 +      case MSG_WARNING:
 +              return LOG_WARNING;
 +      case MSG_ERROR:
 +              return LOG_ERR;
 +      }
 +      return LOG_INFO;
 +}
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +
 +int wpa_debug_open_linux_tracing(void)
 +{
 +      int mounts, trace_fd;
 +      char buf[4096] = {};
 +      ssize_t buflen;
 +      char *line, *tmp1, *path = NULL;
 +
 +      mounts = open("/proc/mounts", O_RDONLY);
 +      if (mounts < 0) {
 +              printf("no /proc/mounts\n");
 +              return -1;
 +      }
 +
 +      buflen = read(mounts, buf, sizeof(buf) - 1);
 +      close(mounts);
 +      if (buflen < 0) {
 +              printf("failed to read /proc/mounts\n");
 +              return -1;
 +      }
 +
 +      line = strtok_r(buf, "\n", &tmp1);
 +      while (line) {
 +              char *tmp2, *tmp_path, *fstype;
 +              /* "<dev> <mountpoint> <fs type> ..." */
 +              strtok_r(line, " ", &tmp2);
 +              tmp_path = strtok_r(NULL, " ", &tmp2);
 +              fstype = strtok_r(NULL, " ", &tmp2);
-       if (last_path) {
-               char *tmp = os_strdup(last_path);
-               wpa_debug_close_file();
-               rv = wpa_debug_open_file(tmp);
-               os_free(tmp);
-       } else {
-               wpa_printf(MSG_ERROR, "Last-path was not set, cannot "
-                          "re-open log file.");
-               rv = -1;
-       }
++              if (fstype && strcmp(fstype, "debugfs") == 0) {
 +                      path = tmp_path;
 +                      break;
 +              }
 +
 +              line = strtok_r(NULL, "\n", &tmp1);
 +      }
 +
 +      if (path == NULL) {
 +              printf("debugfs mountpoint not found\n");
 +              return -1;
 +      }
 +
 +      snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path);
 +
 +      trace_fd = open(buf, O_WRONLY);
 +      if (trace_fd < 0) {
 +              printf("failed to open trace_marker file\n");
 +              return -1;
 +      }
 +      wpa_debug_tracing_file = fdopen(trace_fd, "w");
 +      if (wpa_debug_tracing_file == NULL) {
 +              close(trace_fd);
 +              printf("failed to fdopen()\n");
 +              return -1;
 +      }
 +
 +      return 0;
 +}
 +
 +
 +void wpa_debug_close_linux_tracing(void)
 +{
 +      if (wpa_debug_tracing_file == NULL)
 +              return;
 +      fclose(wpa_debug_tracing_file);
 +      wpa_debug_tracing_file = NULL;
 +}
 +
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +
 +
 +/**
 + * 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, ...)
 +{
 +      va_list ap;
 +
 +      va_start(ap, fmt);
 +      if (level >= wpa_debug_level) {
 +#ifdef CONFIG_ANDROID_LOG
 +              __android_log_vprint(wpa_to_android_level(level),
 +                                   ANDROID_LOG_NAME, fmt, ap);
 +#else /* CONFIG_ANDROID_LOG */
 +#ifdef CONFIG_DEBUG_SYSLOG
 +              if (wpa_debug_syslog) {
 +                      vsyslog(syslog_priority(level), fmt, ap);
 +              } else {
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +              wpa_debug_print_timestamp();
 +#ifdef CONFIG_DEBUG_FILE
 +              if (out_file) {
 +                      vfprintf(out_file, fmt, ap);
 +                      fprintf(out_file, "\n");
 +              } else {
 +#endif /* CONFIG_DEBUG_FILE */
 +              vprintf(fmt, ap);
 +              printf("\n");
 +#ifdef CONFIG_DEBUG_FILE
 +              }
 +#endif /* CONFIG_DEBUG_FILE */
 +#ifdef CONFIG_DEBUG_SYSLOG
 +              }
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +#endif /* CONFIG_ANDROID_LOG */
 +      }
 +      va_end(ap);
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +      if (wpa_debug_tracing_file != NULL) {
 +              va_start(ap, fmt);
 +              fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level);
 +              vfprintf(wpa_debug_tracing_file, fmt, ap);
 +              fprintf(wpa_debug_tracing_file, "\n");
 +              fflush(wpa_debug_tracing_file);
 +              va_end(ap);
 +      }
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +}
 +
 +
 +static void _wpa_hexdump(int level, const char *title, const u8 *buf,
 +                       size_t len, int show)
 +{
 +      size_t i;
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +      if (wpa_debug_tracing_file != NULL) {
 +              fprintf(wpa_debug_tracing_file,
 +                      WPAS_TRACE_PFX "%s - hexdump(len=%lu):",
 +                      level, title, (unsigned long) len);
 +              if (buf == NULL) {
 +                      fprintf(wpa_debug_tracing_file, " [NULL]\n");
 +              } else if (!show) {
 +                      fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
 +              } else {
 +                      for (i = 0; i < len; i++)
 +                              fprintf(wpa_debug_tracing_file,
 +                                      " %02x", buf[i]);
 +              }
 +              fflush(wpa_debug_tracing_file);
 +      }
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +
 +      if (level < wpa_debug_level)
 +              return;
 +#ifdef CONFIG_ANDROID_LOG
 +      {
 +              const char *display;
 +              char *strbuf = NULL;
 +              size_t slen = len;
 +              if (buf == NULL) {
 +                      display = " [NULL]";
 +              } else if (len == 0) {
 +                      display = "";
 +              } else if (show && len) {
 +                      /* Limit debug message length for Android log */
 +                      if (slen > 32)
 +                              slen = 32;
 +                      strbuf = os_malloc(1 + 3 * slen);
 +                      if (strbuf == NULL) {
 +                              wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
 +                                         "allocate message buffer");
 +                              return;
 +                      }
 +
 +                      for (i = 0; i < slen; i++)
 +                              os_snprintf(&strbuf[i * 3], 4, " %02x",
 +                                          buf[i]);
 +
 +                      display = strbuf;
 +              } else {
 +                      display = " [REMOVED]";
 +              }
 +
 +              __android_log_print(wpa_to_android_level(level),
 +                                  ANDROID_LOG_NAME,
 +                                  "%s - hexdump(len=%lu):%s%s",
 +                                  title, (long unsigned int) len, display,
 +                                  len > slen ? " ..." : "");
 +              bin_clear_free(strbuf, 1 + 3 * slen);
 +              return;
 +      }
 +#else /* CONFIG_ANDROID_LOG */
 +#ifdef CONFIG_DEBUG_SYSLOG
 +      if (wpa_debug_syslog) {
 +              const char *display;
 +              char *strbuf = NULL;
 +
 +              if (buf == NULL) {
 +                      display = " [NULL]";
 +              } else if (len == 0) {
 +                      display = "";
 +              } else if (show && len) {
 +                      strbuf = os_malloc(1 + 3 * len);
 +                      if (strbuf == NULL) {
 +                              wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
 +                                         "allocate message buffer");
 +                              return;
 +                      }
 +
 +                      for (i = 0; i < len; i++)
 +                              os_snprintf(&strbuf[i * 3], 4, " %02x",
 +                                          buf[i]);
 +
 +                      display = strbuf;
 +              } else {
 +                      display = " [REMOVED]";
 +              }
 +
 +              syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
 +                     title, (unsigned long) len, display);
 +              bin_clear_free(strbuf, 1 + 3 * len);
 +              return;
 +      }
 +#endif /* CONFIG_DEBUG_SYSLOG */
 +      wpa_debug_print_timestamp();
 +#ifdef CONFIG_DEBUG_FILE
 +      if (out_file) {
 +              fprintf(out_file, "%s - hexdump(len=%lu):",
 +                      title, (unsigned long) len);
 +              if (buf == NULL) {
 +                      fprintf(out_file, " [NULL]");
 +              } else if (show) {
 +                      for (i = 0; i < len; i++)
 +                              fprintf(out_file, " %02x", buf[i]);
 +              } else {
 +                      fprintf(out_file, " [REMOVED]");
 +              }
 +              fprintf(out_file, "\n");
 +      } else {
 +#endif /* CONFIG_DEBUG_FILE */
 +      printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
 +      if (buf == NULL) {
 +              printf(" [NULL]");
 +      } else if (show) {
 +              for (i = 0; i < len; i++)
 +                      printf(" %02x", buf[i]);
 +      } else {
 +              printf(" [REMOVED]");
 +      }
 +      printf("\n");
 +#ifdef CONFIG_DEBUG_FILE
 +      }
 +#endif /* CONFIG_DEBUG_FILE */
 +#endif /* CONFIG_ANDROID_LOG */
 +}
 +
 +void wpa_hexdump(int level, const char *title, const void *buf, size_t len)
 +{
 +      _wpa_hexdump(level, title, buf, len, 1);
 +}
 +
 +
 +void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len)
 +{
 +      _wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
 +}
 +
 +
 +static void _wpa_hexdump_ascii(int level, const char *title, const void *buf,
 +                             size_t len, int show)
 +{
 +      size_t i, llen;
 +      const u8 *pos = buf;
 +      const size_t line_len = 16;
 +
 +#ifdef CONFIG_DEBUG_LINUX_TRACING
 +      if (wpa_debug_tracing_file != NULL) {
 +              fprintf(wpa_debug_tracing_file,
 +                      WPAS_TRACE_PFX "%s - hexdump_ascii(len=%lu):",
 +                      level, title, (unsigned long) len);
 +              if (buf == NULL) {
 +                      fprintf(wpa_debug_tracing_file, " [NULL]\n");
 +              } else if (!show) {
 +                      fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
 +              } else {
 +                      /* can do ascii processing in userspace */
 +                      for (i = 0; i < len; i++)
 +                              fprintf(wpa_debug_tracing_file,
 +                                      " %02x", pos[i]);
 +              }
 +              fflush(wpa_debug_tracing_file);
 +      }
 +#endif /* CONFIG_DEBUG_LINUX_TRACING */
 +
 +      if (level < wpa_debug_level)
 +              return;
 +#ifdef CONFIG_ANDROID_LOG
 +      _wpa_hexdump(level, title, buf, len, show);
 +#else /* CONFIG_ANDROID_LOG */
 +      wpa_debug_print_timestamp();
 +#ifdef CONFIG_DEBUG_FILE
 +      if (out_file) {
 +              if (!show) {
 +                      fprintf(out_file,
 +                              "%s - hexdump_ascii(len=%lu): [REMOVED]\n",
 +                              title, (unsigned long) len);
 +                      return;
 +              }
 +              if (buf == NULL) {
 +                      fprintf(out_file,
 +                              "%s - hexdump_ascii(len=%lu): [NULL]\n",
 +                              title, (unsigned long) len);
 +                      return;
 +              }
 +              fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
 +                      title, (unsigned long) len);
 +              while (len) {
 +                      llen = len > line_len ? line_len : len;
 +                      fprintf(out_file, "    ");
 +                      for (i = 0; i < llen; i++)
 +                              fprintf(out_file, " %02x", pos[i]);
 +                      for (i = llen; i < line_len; i++)
 +                              fprintf(out_file, "   ");
 +                      fprintf(out_file, "   ");
 +                      for (i = 0; i < llen; i++) {
 +                              if (isprint(pos[i]))
 +                                      fprintf(out_file, "%c", pos[i]);
 +                              else
 +                                      fprintf(out_file, "_");
 +                      }
 +                      for (i = llen; i < line_len; i++)
 +                              fprintf(out_file, " ");
 +                      fprintf(out_file, "\n");
 +                      pos += llen;
 +                      len -= llen;
 +              }
 +      } else {
 +#endif /* CONFIG_DEBUG_FILE */
 +      if (!show) {
 +              printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
 +                     title, (unsigned long) len);
 +              return;
 +      }
 +      if (buf == NULL) {
 +              printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
 +                     title, (unsigned long) len);
 +              return;
 +      }
 +      printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
 +      while (len) {
 +              llen = len > line_len ? line_len : len;
 +              printf("    ");
 +              for (i = 0; i < llen; i++)
 +                      printf(" %02x", pos[i]);
 +              for (i = llen; i < line_len; i++)
 +                      printf("   ");
 +              printf("   ");
 +              for (i = 0; i < llen; i++) {
 +                      if (isprint(pos[i]))
 +                              printf("%c", pos[i]);
 +                      else
 +                              printf("_");
 +              }
 +              for (i = llen; i < line_len; i++)
 +                      printf(" ");
 +              printf("\n");
 +              pos += llen;
 +              len -= llen;
 +      }
 +#ifdef CONFIG_DEBUG_FILE
 +      }
 +#endif /* CONFIG_DEBUG_FILE */
 +#endif /* CONFIG_ANDROID_LOG */
 +}
 +
 +
 +void wpa_hexdump_ascii(int level, const char *title, const void *buf,
 +                     size_t len)
 +{
 +      _wpa_hexdump_ascii(level, title, buf, len, 1);
 +}
 +
 +
 +void wpa_hexdump_ascii_key(int level, const char *title, const void *buf,
 +                         size_t len)
 +{
 +      _wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
 +}
 +
 +
 +#ifdef CONFIG_DEBUG_FILE
 +static char *last_path = NULL;
 +#endif /* CONFIG_DEBUG_FILE */
 +
 +int wpa_debug_reopen_file(void)
 +{
 +#ifdef CONFIG_DEBUG_FILE
 +      int rv;
++      char *tmp;
++
++      if (!last_path)
++              return 0; /* logfile not used */
++
++      tmp = os_strdup(last_path);
++      if (!tmp)
++              return -1;
++
++      wpa_debug_close_file();
++      rv = wpa_debug_open_file(tmp);
++      os_free(tmp);
 +      return rv;
 +#else /* CONFIG_DEBUG_FILE */
 +      return 0;
 +#endif /* CONFIG_DEBUG_FILE */
 +}
 +
 +
 +int wpa_debug_open_file(const char *path)
 +{
 +#ifdef CONFIG_DEBUG_FILE
 +      if (!path)
 +              return 0;
 +
 +      if (last_path == NULL || os_strcmp(last_path, path) != 0) {
 +              /* Save our path to enable re-open */
 +              os_free(last_path);
 +              last_path = os_strdup(path);
 +      }
 +
 +      out_file = fopen(path, "a");
 +      if (out_file == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
 +                   "output file %s, using standard output", path);
 +              return -1;
 +      }
 +#ifndef _WIN32
 +      setvbuf(out_file, NULL, _IOLBF, 0);
 +#endif /* _WIN32 */
 +#else /* CONFIG_DEBUG_FILE */
 +      (void)path;
 +#endif /* CONFIG_DEBUG_FILE */
 +      return 0;
 +}
 +
 +
 +void wpa_debug_close_file(void)
 +{
 +#ifdef CONFIG_DEBUG_FILE
 +      if (!out_file)
 +              return;
 +      fclose(out_file);
 +      out_file = NULL;
 +      os_free(last_path);
 +      last_path = NULL;
 +#endif /* CONFIG_DEBUG_FILE */
 +}
 +
 +
 +void wpa_debug_setup_stdout(void)
 +{
 +#ifndef _WIN32
 +      setvbuf(stdout, NULL, _IOLBF, 0);
 +#endif /* _WIN32 */
 +}
 +
 +#endif /* CONFIG_NO_STDOUT_DEBUG */
 +
 +
 +#ifndef CONFIG_NO_WPA_MSG
 +static wpa_msg_cb_func wpa_msg_cb = NULL;
 +
 +void wpa_msg_register_cb(wpa_msg_cb_func func)
 +{
 +      wpa_msg_cb = func;
 +}
 +
 +
 +static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;
 +
 +void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func)
 +{
 +      wpa_msg_ifname_cb = func;
 +}
 +
 +
 +void wpa_msg(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +      char prefix[130];
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
 +                         "buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      prefix[0] = '\0';
 +      if (wpa_msg_ifname_cb) {
 +              const char *ifname = wpa_msg_ifname_cb(ctx);
 +              if (ifname) {
 +                      int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
 +                                            ifname);
 +                      if (os_snprintf_error(sizeof(prefix), res))
 +                              prefix[0] = '\0';
 +              }
 +      }
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_printf(level, "%s%s", prefix, buf);
 +      if (wpa_msg_cb)
 +              wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      if (!wpa_msg_cb)
 +              return;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate "
 +                         "message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_msg_cb(ctx, level, WPA_MSG_PER_INTERFACE, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_global(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_msg_global: Failed to allocate "
 +                         "message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_printf(level, "%s", buf);
 +      if (wpa_msg_cb)
 +              wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      if (!wpa_msg_cb)
 +              return;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR,
 +                         "wpa_msg_global_ctrl: Failed to allocate message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_msg_cb(ctx, level, WPA_MSG_GLOBAL, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "wpa_msg_no_global: Failed to allocate "
 +                         "message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_printf(level, "%s", buf);
 +      if (wpa_msg_cb)
 +              wpa_msg_cb(ctx, level, WPA_MSG_NO_GLOBAL, buf, len);
 +      bin_clear_free(buf, buflen);
 +}
 +
 +
 +void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "%s: Failed to allocate message buffer",
 +                         __func__);
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      wpa_printf(level, "%s", buf);
 +      if (wpa_msg_cb)
 +              wpa_msg_cb(ctx, level, WPA_MSG_ONLY_GLOBAL, buf, len);
 +      os_free(buf);
 +}
 +
 +#endif /* CONFIG_NO_WPA_MSG */
 +
 +
 +#ifndef CONFIG_NO_HOSTAPD_LOGGER
 +static hostapd_logger_cb_func hostapd_logger_cb = NULL;
 +
 +void hostapd_logger_register_cb(hostapd_logger_cb_func func)
 +{
 +      hostapd_logger_cb = func;
 +}
 +
 +
 +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
 +                  const char *fmt, ...)
 +{
 +      va_list ap;
 +      char *buf;
 +      int buflen;
 +      int len;
 +
 +      va_start(ap, fmt);
 +      buflen = vsnprintf(NULL, 0, fmt, ap) + 1;
 +      va_end(ap);
 +
 +      buf = os_malloc(buflen);
 +      if (buf == NULL) {
 +              wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
 +                         "message buffer");
 +              return;
 +      }
 +      va_start(ap, fmt);
 +      len = vsnprintf(buf, buflen, fmt, ap);
 +      va_end(ap);
 +      if (hostapd_logger_cb)
 +              hostapd_logger_cb(ctx, addr, module, level, buf, len);
 +      else if (addr)
 +              wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s",
 +                         MAC2STR(addr), buf);
 +      else
 +              wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
 +      bin_clear_free(buf, buflen);
 +}
 +#endif /* CONFIG_NO_HOSTAPD_LOGGER */
 +
 +
 +const char * debug_level_str(int level)
 +{
 +      switch (level) {
 +      case MSG_EXCESSIVE:
 +              return "EXCESSIVE";
 +      case MSG_MSGDUMP:
 +              return "MSGDUMP";
 +      case MSG_DEBUG:
 +              return "DEBUG";
 +      case MSG_INFO:
 +              return "INFO";
 +      case MSG_WARNING:
 +              return "WARNING";
 +      case MSG_ERROR:
 +              return "ERROR";
 +      default:
 +              return "?";
 +      }
 +}
 +
 +
 +int str_to_debug_level(const char *s)
 +{
 +      if (os_strcasecmp(s, "EXCESSIVE") == 0)
 +              return MSG_EXCESSIVE;
 +      if (os_strcasecmp(s, "MSGDUMP") == 0)
 +              return MSG_MSGDUMP;
 +      if (os_strcasecmp(s, "DEBUG") == 0)
 +              return MSG_DEBUG;
 +      if (os_strcasecmp(s, "INFO") == 0)
 +              return MSG_INFO;
 +      if (os_strcasecmp(s, "WARNING") == 0)
 +              return MSG_WARNING;
 +      if (os_strcasecmp(s, "ERROR") == 0)
 +              return MSG_ERROR;
 +      return -1;
 +}
Simple merge
index 64b3d8d,0000000..0458e3f
mode 100644,000000..100644
--- /dev/null
@@@ -1,171 -1,0 +1,172 @@@
-       return (const u8 *)wpabuf_head(buf);
 +/*
 + * Dynamic data buffer
 + * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
 + *
 + * 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 */
 +      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);
++struct wpabuf * wpabuf_parse_bin(const char *buf);
 +
 +
 +/**
 + * 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)
 +{
 +      return buf->buf;
 +}
 +
 +static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
 +{
-       return (u8 *)wpabuf_mhead(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)
 +{
 +      return buf->buf;
 +}
 +
 +static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
 +{
-       u8 *pos = (u8 *)wpabuf_put(buf, 1);
++      return (u8 *) wpabuf_mhead(buf);
 +}
 +
 +static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
 +{
-       u8 *pos = (u8 *)wpabuf_put(buf, 2);
++      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, 4);
++      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, 2);
++      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, 3);
++      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, 4);
++      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 */
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 20999b9,974ed1e..974ed1e
Binary files differ
index 7061fd7,a2f360a..a2f360a
Binary files differ
Simple merge
index 0d50201,a1d6366..a1d6366
Binary files differ
index eb17d9c,67ef81c..67ef81c
Binary files differ
index 953d7cb,c9ed0b4..c9ed0b4
Binary files differ
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
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
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
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