From: Dan Breslau Date: Fri, 2 Sep 2016 17:02:24 +0000 (-0400) Subject: Updated through tag hostap_2_5 from git://w1.fi/hostap.git X-Git-Tag: v0.9.6~2^2~11 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=mech_eap.git;a=commitdiff_plain;h=4f319dde67a76fe0aaf33f6d2788968012584ada Updated through tag hostap_2_5 from git://w1.fi/hostap.git --- 4f319dde67a76fe0aaf33f6d2788968012584ada diff --cc .gitignore index 3674727,ae624c9..2089b08 --- a/.gitignore +++ b/.gitignore @@@ -1,16 -1,30 +1,46 @@@ +Makefile.in +aclocal.m4 +autom4te.cache +configure +config.* +ltmain.sh +libtool +depcomp +m4 +!m4/minuso.m4 +build-aux +!build-aux/compile +mech_eap.spec +mech_eap*tar* +*.lo + *.o + *.d + *.gcno + *.gcda + *.gcov + *.pyc +*# + *~ + .config + tests/hwsim/logs + wpaspy/build + wpa_supplicant/eapol_test + wpa_supplicant/nfc_pw_token + wpa_supplicant/preauth_test + wpa_supplicant/wpa_cli + wpa_supplicant/wpa_passphrase + wpa_supplicant/wpa_supplicant + wpa_supplicant/wpa_priv + wpa_supplicant/wpa_gui/Makefile + wpa_supplicant/wpa_gui/wpa_gui + wpa_supplicant/wpa_gui-qt4/Makefile + wpa_supplicant/wpa_gui-qt4/wpa_gui + hostapd/hostapd + hostapd/hostapd_cli + hostapd/hlr_auc_gw + hostapd/nt_password_hash + mac80211_hwsim/tools/hwsim_test + wlantest/libwlantest.a + wlantest/test_vectors + wlantest/wlantest + wlantest/wlantest_cli diff --cc libeap/Android.mk index 0000000,bd7a409..bd7a409 mode 000000,100644..100644 --- a/libeap/Android.mk +++ b/libeap/Android.mk diff --cc libeap/Makefile.am index 77ee4c0,0000000..890a9ea mode 100644,000000..100644 --- a/libeap/Makefile.am +++ b/libeap/Makefile.am @@@ -1,199 -1,0 +1,212 @@@ +AUTOMAKE_OPTIONS = foreign + +AM_CPPFLAGS = -I$(srcdir)/src -I$(srcdir)/eap_example -I$(srcdir)/src/utils @OPENSSL_CFLAGS@ +noinst_HEADERS = \ + src/common/defs.h \ + src/common/eapol_common.h \ + src/common/ieee802_11_common.h \ + src/common/ieee802_11_defs.h \ + src/common/privsep_commands.h \ + src/common/version.h \ + src/common/wpa_common.h \ + src/common/wpa_ctrl.h + +EXTRA_DIST = src/tls/libtommath.c \ + wpa_supplicant/README + +SOURCES_BOTH = src/eap_common/eap_peap_common.c +SOURCES_BOTH += src/eap_common/eap_psk_common.c +SOURCES_BOTH += src/eap_common/eap_pax_common.c +SOURCES_BOTH += src/eap_common/eap_sake_common.c +SOURCES_BOTH += src/eap_common/eap_gpsk_common.c +SOURCES_BOTH += src/eap_common/chap.c \ + src/eap_common/chap.h \ + src/eap_common/eap_common.h \ + src/eap_common/eap_defs.h \ + src/eap_common/eap_fast_common.h \ + src/eap_common/eap_gpsk_common.h \ + src/eap_common/eap_ikev2_common.h \ + src/eap_common/eap_pax_common.h \ + src/eap_common/eap_peap_common.h \ + src/eap_common/eap_psk_common.h \ + src/eap_common/eap_pwd_common.h \ + src/eap_common/eap_sake_common.h \ + src/eap_common/eap_sim_common.h \ + src/eap_common/eap_tlv_common.h \ + src/eap_common/eap_ttls.h \ + src/eap_common/eap_wsc_common.h \ + src/eap_common/ikev2_common.h + + +SOURCES_peer = src/eap_peer/eap_tls.c +SOURCES_peer += src/eap_peer/eap_peap.c +SOURCES_peer += src/eap_peer/eap_ttls.c +SOURCES_peer += src/eap_peer/eap_md5.c +SOURCES_peer += src/eap_peer/eap_mschapv2.c +SOURCES_peer += src/eap_peer/mschapv2.c +SOURCES_peer += src/eap_peer/eap_otp.c +SOURCES_peer += src/eap_peer/eap_gtc.c +SOURCES_peer += src/eap_peer/eap_leap.c +SOURCES_peer += src/eap_peer/eap_psk.c +SOURCES_peer += src/eap_peer/eap_pax.c +SOURCES_peer += src/eap_peer/eap_sake.c +SOURCES_peer += src/eap_peer/eap_gpsk.c +SOURCES_peer += src/eap_peer/eap.c +SOURCES_peer += src/eap_common/eap_common.c +SOURCES_peer += src/eap_peer/eap_methods.c +SOURCES_peer += src/eap_peer/eap_tls_common.c \ + src/eap_peer/eap_config.h \ + src/eap_peer/eap_fast_pac.h \ + src/eap_peer/eap.h \ + src/eap_peer/eap_i.h \ + src/eap_peer/eap_methods.h \ + src/eap_peer/eap_tls_common.h \ + src/eap_peer/ikev2.h \ + src/eap_peer/mschapv2.h \ + src/eap_peer/tncc.h \ + src/radius/radius.h + + +AM_CFLAGS = -DEAP_TLS +AM_CFLAGS += -DEAP_PEAP +AM_CFLAGS += -DEAP_TTLS +AM_CFLAGS += -DEAP_MD5 +AM_CFLAGS += -DEAP_MSCHAPv2 +AM_CFLAGS += -DEAP_GTC +AM_CFLAGS += -DEAP_OTP +AM_CFLAGS += -DEAP_LEAP +AM_CFLAGS += -DEAP_PSK +AM_CFLAGS += -DEAP_PAX +AM_CFLAGS += -DEAP_SAKE +AM_CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256 + +AM_CFLAGS += -DEAP_SERVER_IDENTITY +AM_CFLAGS += -DEAP_SERVER_TLS +AM_CFLAGS += -DEAP_SERVER_PEAP +AM_CFLAGS += -DEAP_SERVER_TTLS +AM_CFLAGS += -DEAP_SERVER_MD5 +AM_CFLAGS += -DEAP_SERVER_MSCHAPV2 +AM_CFLAGS += -DEAP_SERVER_GTC +AM_CFLAGS += -DEAP_SERVER_PSK +AM_CFLAGS += -DEAP_SERVER_PAX +AM_CFLAGS += -DEAP_SERVER_SAKE +AM_CFLAGS += -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256 + +AM_CFLAGS += -DIEEE8021X_EAPOL +AM_CFLAGS += -DCONFIG_IPV6 +AM_CFLAGS += -DCONFIG_DEBUG_FILE +AM_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH +AM_CFLAGS += -DCONFIG_INTERNAL_SHA1 +AM_CFLAGS += -DEAP_TLS_OPENSSL +AM_CFLAGS += -DPKCS12_FUNCS +AM_CFLAGS += -DCONFIG_SHA256 + +UTILS_SRCS = src/utils/base64.c \ + src/utils/common.c \ + src/utils/ip_addr.c \ + src/utils/radiotap.c \ + src/utils/trace.c \ + src/utils/uuid.c \ + src/utils/wpa_debug.c \ + src/utils/wpabuf.c \ + src/utils/os_unix.c \ + src/utils/radius_utils.c \ +src/utils/radius_utils.h \ + src/utils/base64.h \ + src/utils/build_config.h \ + src/utils/common.h \ + src/utils/eloop.h \ + src/utils/includes.h \ + src/utils/ip_addr.h \ + src/utils/list.h \ + src/utils/os.h \ + src/utils/pcsc_funcs.h \ + src/utils/radiotap.h \ + src/utils/radiotap_iter.h \ + src/utils/state_machine.h \ + src/utils/trace.h \ + src/utils/uuid.h \ + src/utils/wpabuf.h \ + src/utils/wpa_debug.h + + +CRYPTO_SRCS = \ + src/crypto/aes-cbc.c \ ++ src/crypto/aes-ccm.c \ + src/crypto/aes-ctr.c \ + src/crypto/aes-eax.c \ + src/crypto/aes-encblock.c \ ++ src/crypto/aes-gcm.c \ ++ src/crypto/aes-internal.c \ ++ src/crypto/aes-internal-dec.c \ ++ src/crypto/aes-internal-enc.c \ + src/crypto/aes-omac1.c \ ++ src/crypto/aes-siv.c \ ++ src/crypto/aes-siv.h \ + src/crypto/aes-unwrap.c \ + src/crypto/aes-wrap.c \ ++ src/crypto/aes.h \ ++ src/crypto/aes_i.h \ ++ src/crypto/aes_wrap.h \ ++ src/crypto/crypto.h \ ++ src/crypto/des-internal.c \ ++ src/crypto/dh_group5.h \ ++ src/crypto/dh_groups.h \ ++ src/crypto/md4-internal.c \ + src/crypto/md5.c \ - src/crypto/md5-non-fips.c \ ++ src/crypto/md5-internal.c \ ++ src/crypto/md5.h \ + src/crypto/milenage.c \ ++ src/crypto/milenage.h \ + src/crypto/ms_funcs.c \ ++ src/crypto/ms_funcs.h \ ++ src/crypto/rc4.c \ + src/crypto/sha1.c \ ++ src/crypto/sha1-internal.c \ + src/crypto/sha1-pbkdf2.c \ ++ src/crypto/sha1-prf.c \ + src/crypto/sha1-tlsprf.c \ + src/crypto/sha1-tprf.c \ ++ src/crypto/sha256-prf.c \ ++ src/crypto/sha256-tlsprf.c \ + src/crypto/sha256.c \ - src/crypto/crypto_openssl.c \ - src/crypto/tls_openssl.c \ - src/crypto/aes.h \ - src/crypto/aes_i.h \ - src/crypto/aes_wrap.h \ - src/crypto/crypto.h \ - src/crypto/dh_group5.h \ - src/crypto/dh_groups.h \ - src/crypto/md5.h \ - src/crypto/milenage.h \ - src/crypto/ms_funcs.h \ - src/crypto/sha1.h \ + src/crypto/sha256.h \ ++ src/crypto/sha256_i.h \ + src/crypto/tls.h + ++ +TLS_SRCS = \ + src/tls/asn1.c \ + src/tls/bignum.c \ + src/tls/pkcs1.c \ + src/tls/pkcs5.c \ + src/tls/pkcs8.c \ + src/tls/rsa.c \ + src/tls/tlsv1_client.c \ + src/tls/tlsv1_client_read.c \ + src/tls/tlsv1_client_write.c \ + src/tls/tlsv1_common.c \ + src/tls/tlsv1_cred.c \ + src/tls/tlsv1_record.c \ + src/tls/tlsv1_server.c \ + src/tls/tlsv1_server_read.c \ + src/tls/tlsv1_server_write.c \ + src/tls/x509v3.c \ + src/tls/asn1.h \ + src/tls/bignum.h \ + src/tls/pkcs1.h \ + src/tls/pkcs5.h \ + src/tls/pkcs8.h \ + src/tls/rsa.h \ + src/tls/tlsv1_client.h \ + src/tls/tlsv1_client_i.h \ + src/tls/tlsv1_common.h \ + src/tls/tlsv1_cred.h \ + src/tls/tlsv1_record.h \ + src/tls/tlsv1_server.h \ + src/tls/tlsv1_server_i.h \ + src/tls/x509v3.h + +libeap_la_SOURCES = $(SOURCES_BOTH) $(SOURCES_peer) $(UTILS_SRCS) $(CRYPTO_SRCS) + +noinst_LTLIBRARIES = libeap.la diff --cc libeap/doc/p2p.doxygen index 0000000,c1a81db..c1a81db mode 000000,100644..100644 --- a/libeap/doc/p2p.doxygen +++ b/libeap/doc/p2p.doxygen diff --cc libeap/doc/p2p_arch.dot index 0000000,27ae0e2..27ae0e2 mode 000000,100644..100644 --- a/libeap/doc/p2p_arch.dot +++ b/libeap/doc/p2p_arch.dot diff --cc libeap/doc/p2p_arch2.dot index 0000000,9c7b4b5..9c7b4b5 mode 000000,100644..100644 --- a/libeap/doc/p2p_arch2.dot +++ b/libeap/doc/p2p_arch2.dot diff --cc libeap/doc/p2p_sm.dot index 0000000,640caef..640caef mode 000000,100644..100644 --- a/libeap/doc/p2p_sm.dot +++ b/libeap/doc/p2p_sm.dot diff --cc libeap/eap_example/dh.conf index 0000000,7bc8325..7bc8325 mode 000000,100644..100644 --- a/libeap/eap_example/dh.conf +++ b/libeap/eap_example/dh.conf diff --cc libeap/hostapd/Android.mk index 0000000,5885f2b..5885f2b mode 000000,100644..100644 --- a/libeap/hostapd/Android.mk +++ b/libeap/hostapd/Android.mk diff --cc libeap/hostapd/android.config index 0000000,0b1d7c7..0b1d7c7 mode 000000,100644..100644 --- a/libeap/hostapd/android.config +++ b/libeap/hostapd/android.config diff --cc libeap/hostapd/hapd_module_tests.c index 0000000,f7887eb..f7887eb mode 000000,100644..100644 --- a/libeap/hostapd/hapd_module_tests.c +++ b/libeap/hostapd/hapd_module_tests.c diff --cc libeap/hostapd/hlr_auc_gw.txt index 0000000,097bbce..097bbce mode 000000,100644..100644 --- a/libeap/hostapd/hlr_auc_gw.txt +++ b/libeap/hostapd/hlr_auc_gw.txt diff --cc libeap/hostapd/hostapd.eap_user_sqlite index 0000000,826db34..826db34 mode 000000,100644..100644 --- a/libeap/hostapd/hostapd.eap_user_sqlite +++ b/libeap/hostapd/hostapd.eap_user_sqlite diff --cc libeap/hostapd/wps-ap-nfc.py index 0000000,2fc3012..2fc3012 mode 000000,100755..100755 --- a/libeap/hostapd/wps-ap-nfc.py +++ b/libeap/hostapd/wps-ap-nfc.py diff --cc libeap/hs20/client/Android.mk index 0000000,b23ac17..b23ac17 mode 000000,100644..100644 --- a/libeap/hs20/client/Android.mk +++ b/libeap/hs20/client/Android.mk diff --cc libeap/hs20/client/Makefile index 0000000,94cd5f1..94cd5f1 mode 000000,100644..100644 --- a/libeap/hs20/client/Makefile +++ b/libeap/hs20/client/Makefile diff --cc libeap/hs20/client/devdetail.xml index 0000000,6d0389e..6d0389e mode 000000,100644..100644 --- a/libeap/hs20/client/devdetail.xml +++ b/libeap/hs20/client/devdetail.xml diff --cc libeap/hs20/client/devinfo.xml index 0000000,d48a520..d48a520 mode 000000,100644..100644 --- a/libeap/hs20/client/devinfo.xml +++ b/libeap/hs20/client/devinfo.xml diff --cc libeap/hs20/client/est.c index 0000000,ec05bc4..ec05bc4 mode 000000,100644..100644 --- a/libeap/hs20/client/est.c +++ b/libeap/hs20/client/est.c diff --cc libeap/hs20/client/oma_dm_client.c index 0000000,5854b72..5854b72 mode 000000,100644..100644 --- a/libeap/hs20/client/oma_dm_client.c +++ b/libeap/hs20/client/oma_dm_client.c diff --cc libeap/hs20/client/osu_client.c index 0000000,0315f7b..0315f7b mode 000000,100644..100644 --- a/libeap/hs20/client/osu_client.c +++ b/libeap/hs20/client/osu_client.c diff --cc libeap/hs20/client/osu_client.h index 0000000,9a7059e..9a7059e mode 000000,100644..100644 --- a/libeap/hs20/client/osu_client.h +++ b/libeap/hs20/client/osu_client.h diff --cc libeap/hs20/client/spp_client.c index 0000000,c619541..c619541 mode 000000,100644..100644 --- a/libeap/hs20/client/spp_client.c +++ b/libeap/hs20/client/spp_client.c diff --cc libeap/hs20/server/Makefile index 0000000,248ed5c..248ed5c mode 000000,100644..100644 --- a/libeap/hs20/server/Makefile +++ b/libeap/hs20/server/Makefile diff --cc libeap/hs20/server/ca/clean.sh index 0000000,c72dcbd..c72dcbd mode 000000,100755..100755 --- a/libeap/hs20/server/ca/clean.sh +++ b/libeap/hs20/server/ca/clean.sh diff --cc libeap/hs20/server/ca/est-csrattrs.cnf index 0000000,b50ea00..b50ea00 mode 000000,100644..100644 --- a/libeap/hs20/server/ca/est-csrattrs.cnf +++ b/libeap/hs20/server/ca/est-csrattrs.cnf diff --cc libeap/hs20/server/ca/est-csrattrs.sh index 0000000,0b73a04..0b73a04 mode 000000,100755..100755 --- a/libeap/hs20/server/ca/est-csrattrs.sh +++ b/libeap/hs20/server/ca/est-csrattrs.sh diff --cc libeap/hs20/server/ca/hs20.oid index 0000000,a829ff2..a829ff2 mode 000000,100644..100644 --- a/libeap/hs20/server/ca/hs20.oid +++ b/libeap/hs20/server/ca/hs20.oid diff --cc libeap/hs20/server/ca/ocsp-req.sh index 0000000,931a206..931a206 mode 000000,100755..100755 --- a/libeap/hs20/server/ca/ocsp-req.sh +++ b/libeap/hs20/server/ca/ocsp-req.sh diff --cc libeap/hs20/server/ca/ocsp-responder-ica.sh index 0000000,116c6e1..116c6e1 mode 000000,100755..100755 --- a/libeap/hs20/server/ca/ocsp-responder-ica.sh +++ b/libeap/hs20/server/ca/ocsp-responder-ica.sh diff --cc libeap/hs20/server/ca/ocsp-responder.sh index 0000000,8cebd74..8cebd74 mode 000000,100755..100755 --- a/libeap/hs20/server/ca/ocsp-responder.sh +++ b/libeap/hs20/server/ca/ocsp-responder.sh diff --cc libeap/hs20/server/ca/ocsp-update-cache.sh index 0000000,8ddef9b..8ddef9b mode 000000,100755..100755 --- a/libeap/hs20/server/ca/ocsp-update-cache.sh +++ b/libeap/hs20/server/ca/ocsp-update-cache.sh diff --cc libeap/hs20/server/ca/openssl-root.cnf index 0000000,5bc50be..5bc50be mode 000000,100644..100644 --- a/libeap/hs20/server/ca/openssl-root.cnf +++ b/libeap/hs20/server/ca/openssl-root.cnf diff --cc libeap/hs20/server/ca/openssl.cnf index 0000000,6141013..6141013 mode 000000,100644..100644 --- a/libeap/hs20/server/ca/openssl.cnf +++ b/libeap/hs20/server/ca/openssl.cnf diff --cc libeap/hs20/server/ca/setup.sh index 0000000,78abccc..78abccc mode 000000,100755..100755 --- a/libeap/hs20/server/ca/setup.sh +++ b/libeap/hs20/server/ca/setup.sh diff --cc libeap/hs20/server/ca/w1fi_logo.png index 0000000,ac7c259..ac7c259 mode 000000,100644..100644 Binary files differ diff --cc libeap/hs20/server/hs20-osu-server.txt index 0000000,001d6f2..001d6f2 mode 000000,100644..100644 --- a/libeap/hs20/server/hs20-osu-server.txt +++ b/libeap/hs20/server/hs20-osu-server.txt diff --cc libeap/hs20/server/hs20_spp_server.c index 0000000,591f66b..591f66b mode 000000,100644..100644 --- a/libeap/hs20/server/hs20_spp_server.c +++ b/libeap/hs20/server/hs20_spp_server.c diff --cc libeap/hs20/server/spp_server.c index 0000000,33e3fa1..33e3fa1 mode 000000,100644..100644 --- a/libeap/hs20/server/spp_server.c +++ b/libeap/hs20/server/spp_server.c diff --cc libeap/hs20/server/spp_server.h index 0000000,7b27be3..7b27be3 mode 000000,100644..100644 --- a/libeap/hs20/server/spp_server.h +++ b/libeap/hs20/server/spp_server.h diff --cc libeap/hs20/server/sql-example.txt index 0000000,20dcf2f..20dcf2f mode 000000,100644..100644 --- a/libeap/hs20/server/sql-example.txt +++ b/libeap/hs20/server/sql-example.txt diff --cc libeap/hs20/server/sql.txt index 0000000,6609538..6609538 mode 000000,100644..100644 --- a/libeap/hs20/server/sql.txt +++ b/libeap/hs20/server/sql.txt diff --cc libeap/hs20/server/www/add-free.php index 0000000,1efc655..1efc655 mode 000000,100644..100644 --- a/libeap/hs20/server/www/add-free.php +++ b/libeap/hs20/server/www/add-free.php diff --cc libeap/hs20/server/www/add-mo.php index 0000000,a3b4513..a3b4513 mode 000000,100644..100644 --- a/libeap/hs20/server/www/add-mo.php +++ b/libeap/hs20/server/www/add-mo.php diff --cc libeap/hs20/server/www/cert-enroll.php index 0000000,f023ca5..f023ca5 mode 000000,100644..100644 --- a/libeap/hs20/server/www/cert-enroll.php +++ b/libeap/hs20/server/www/cert-enroll.php diff --cc libeap/hs20/server/www/config.php index 0000000,e3af435..e3af435 mode 000000,100644..100644 --- a/libeap/hs20/server/www/config.php +++ b/libeap/hs20/server/www/config.php diff --cc libeap/hs20/server/www/est.php index 0000000,a45648b..a45648b mode 000000,100644..100644 --- a/libeap/hs20/server/www/est.php +++ b/libeap/hs20/server/www/est.php diff --cc libeap/hs20/server/www/free-remediation.php index 0000000,5648b30..5648b30 mode 000000,100644..100644 --- a/libeap/hs20/server/www/free-remediation.php +++ b/libeap/hs20/server/www/free-remediation.php diff --cc libeap/hs20/server/www/free.php index 0000000,8195069..8195069 mode 000000,100644..100644 --- a/libeap/hs20/server/www/free.php +++ b/libeap/hs20/server/www/free.php diff --cc libeap/hs20/server/www/redirect.php index 0000000,8fc9cd6..8fc9cd6 mode 000000,100644..100644 --- a/libeap/hs20/server/www/redirect.php +++ b/libeap/hs20/server/www/redirect.php diff --cc libeap/hs20/server/www/remediation.php index 0000000,392a7bd..392a7bd mode 000000,100644..100644 --- a/libeap/hs20/server/www/remediation.php +++ b/libeap/hs20/server/www/remediation.php diff --cc libeap/hs20/server/www/signup.php index 0000000,aeb2f68..aeb2f68 mode 000000,100644..100644 --- a/libeap/hs20/server/www/signup.php +++ b/libeap/hs20/server/www/signup.php diff --cc libeap/hs20/server/www/spp.php index 0000000,dde4434..dde4434 mode 000000,100644..100644 --- a/libeap/hs20/server/www/spp.php +++ b/libeap/hs20/server/www/spp.php diff --cc libeap/hs20/server/www/users.php index 0000000,c340a33..c340a33 mode 000000,100644..100644 --- a/libeap/hs20/server/www/users.php +++ b/libeap/hs20/server/www/users.php diff --cc libeap/patches/openssl-0.9.8zf-tls-extensions.patch index 0000000,3a8f90e..3a8f90e mode 000000,100644..100644 --- a/libeap/patches/openssl-0.9.8zf-tls-extensions.patch +++ b/libeap/patches/openssl-0.9.8zf-tls-extensions.patch diff --cc libeap/src/ap/acs.c index 0000000,03d797f..03d797f mode 000000,100644..100644 --- a/libeap/src/ap/acs.c +++ b/libeap/src/ap/acs.c diff --cc libeap/src/ap/acs.h index 0000000,fc85259..fc85259 mode 000000,100644..100644 --- a/libeap/src/ap/acs.h +++ b/libeap/src/ap/acs.h diff --cc libeap/src/ap/bss_load.c index 0000000,fb63942..fb63942 mode 000000,100644..100644 --- a/libeap/src/ap/bss_load.c +++ b/libeap/src/ap/bss_load.c diff --cc libeap/src/ap/bss_load.h index 0000000,ac3c793..ac3c793 mode 000000,100644..100644 --- a/libeap/src/ap/bss_load.h +++ b/libeap/src/ap/bss_load.h diff --cc libeap/src/ap/dfs.c index 0000000,715f19b..715f19b mode 000000,100644..100644 --- a/libeap/src/ap/dfs.c +++ b/libeap/src/ap/dfs.c diff --cc libeap/src/ap/dfs.h index 0000000,be8c0e6..be8c0e6 mode 000000,100644..100644 --- a/libeap/src/ap/dfs.h +++ b/libeap/src/ap/dfs.h diff --cc libeap/src/ap/dhcp_snoop.c index 0000000,3a77225..3a77225 mode 000000,100644..100644 --- a/libeap/src/ap/dhcp_snoop.c +++ b/libeap/src/ap/dhcp_snoop.c diff --cc libeap/src/ap/dhcp_snoop.h index 0000000,93d0050..93d0050 mode 000000,100644..100644 --- a/libeap/src/ap/dhcp_snoop.h +++ b/libeap/src/ap/dhcp_snoop.h diff --cc libeap/src/ap/eap_user_db.c index 0000000,082d0f5..082d0f5 mode 000000,100644..100644 --- a/libeap/src/ap/eap_user_db.c +++ b/libeap/src/ap/eap_user_db.c diff --cc libeap/src/ap/gas_serv.c index 0000000,9d19f98..9d19f98 mode 000000,100644..100644 --- a/libeap/src/ap/gas_serv.c +++ b/libeap/src/ap/gas_serv.c diff --cc libeap/src/ap/gas_serv.h index 0000000,4ec3201..4ec3201 mode 000000,100644..100644 --- a/libeap/src/ap/gas_serv.h +++ b/libeap/src/ap/gas_serv.h diff --cc libeap/src/ap/hs20.c index 0000000,d7909fa..d7909fa mode 000000,100644..100644 --- a/libeap/src/ap/hs20.c +++ b/libeap/src/ap/hs20.c diff --cc libeap/src/ap/hs20.h index 0000000,152439f..152439f mode 000000,100644..100644 --- a/libeap/src/ap/hs20.h +++ b/libeap/src/ap/hs20.h diff --cc libeap/src/ap/ieee802_11_shared.c index 0000000,d462ac8..d462ac8 mode 000000,100644..100644 --- a/libeap/src/ap/ieee802_11_shared.c +++ b/libeap/src/ap/ieee802_11_shared.c diff --cc libeap/src/ap/ieee802_11_vht.c index 0000000,5bf1b5d..5bf1b5d mode 000000,100644..100644 --- a/libeap/src/ap/ieee802_11_vht.c +++ b/libeap/src/ap/ieee802_11_vht.c diff --cc libeap/src/ap/ndisc_snoop.c index 0000000,4a87721..4a87721 mode 000000,100644..100644 --- a/libeap/src/ap/ndisc_snoop.c +++ b/libeap/src/ap/ndisc_snoop.c diff --cc libeap/src/ap/ndisc_snoop.h index 0000000,3cc9a55..3cc9a55 mode 000000,100644..100644 --- a/libeap/src/ap/ndisc_snoop.h +++ b/libeap/src/ap/ndisc_snoop.h diff --cc libeap/src/ap/vlan_util.c index 0000000,d4e0efb..d4e0efb mode 000000,100644..100644 --- a/libeap/src/ap/vlan_util.c +++ b/libeap/src/ap/vlan_util.c diff --cc libeap/src/ap/vlan_util.h index 0000000,bef5a16..bef5a16 mode 000000,100644..100644 --- a/libeap/src/ap/vlan_util.h +++ b/libeap/src/ap/vlan_util.h diff --cc libeap/src/ap/wnm_ap.c index 0000000,4c8bc10..4c8bc10 mode 000000,100644..100644 --- a/libeap/src/ap/wnm_ap.c +++ b/libeap/src/ap/wnm_ap.c diff --cc libeap/src/ap/wnm_ap.h index 0000000,7789307..7789307 mode 000000,100644..100644 --- a/libeap/src/ap/wnm_ap.h +++ b/libeap/src/ap/wnm_ap.h diff --cc libeap/src/ap/x_snoop.c index 0000000,aef9a53..aef9a53 mode 000000,100644..100644 --- a/libeap/src/ap/x_snoop.c +++ b/libeap/src/ap/x_snoop.c diff --cc libeap/src/ap/x_snoop.h index 0000000,e43a78d..e43a78d mode 000000,100644..100644 --- a/libeap/src/ap/x_snoop.h +++ b/libeap/src/ap/x_snoop.h diff --cc libeap/src/common/common_module_tests.c index 0000000,d69448b..d69448b mode 000000,100644..100644 --- a/libeap/src/common/common_module_tests.c +++ b/libeap/src/common/common_module_tests.c diff --cc libeap/src/common/gas.c index 0000000,cff9254..cff9254 mode 000000,100644..100644 --- a/libeap/src/common/gas.c +++ b/libeap/src/common/gas.c diff --cc libeap/src/common/gas.h index 0000000,306adc5..306adc5 mode 000000,100644..100644 --- a/libeap/src/common/gas.h +++ b/libeap/src/common/gas.h diff --cc libeap/src/common/hw_features_common.c index 0000000,9c37ea6..9c37ea6 mode 000000,100644..100644 --- a/libeap/src/common/hw_features_common.c +++ b/libeap/src/common/hw_features_common.c diff --cc libeap/src/common/hw_features_common.h index 0000000,7360b4e..7360b4e mode 000000,100644..100644 --- a/libeap/src/common/hw_features_common.h +++ b/libeap/src/common/hw_features_common.h diff --cc libeap/src/common/ieee802_1x_defs.h index 0000000,cc88caa..cc88caa mode 000000,100644..100644 --- a/libeap/src/common/ieee802_1x_defs.h +++ b/libeap/src/common/ieee802_1x_defs.h diff --cc libeap/src/common/qca-vendor-attr.h index 0000000,6f51803..6f51803 mode 000000,100644..100644 --- a/libeap/src/common/qca-vendor-attr.h +++ b/libeap/src/common/qca-vendor-attr.h diff --cc libeap/src/common/qca-vendor.h index 0000000,28985f5..28985f5 mode 000000,100644..100644 --- a/libeap/src/common/qca-vendor.h +++ b/libeap/src/common/qca-vendor.h diff --cc libeap/src/common/sae.c index 0000000,503fa1d..503fa1d mode 000000,100644..100644 --- a/libeap/src/common/sae.c +++ b/libeap/src/common/sae.c diff --cc libeap/src/common/sae.h index 0000000,c07026c..c07026c mode 000000,100644..100644 --- a/libeap/src/common/sae.h +++ b/libeap/src/common/sae.h diff --cc libeap/src/common/tnc.h index 0000000,108acf9..108acf9 mode 000000,100644..100644 --- a/libeap/src/common/tnc.h +++ b/libeap/src/common/tnc.h diff --cc libeap/src/common/wpa_helpers.c index 0000000,28913b9..28913b9 mode 000000,100644..100644 --- a/libeap/src/common/wpa_helpers.c +++ b/libeap/src/common/wpa_helpers.c diff --cc libeap/src/common/wpa_helpers.h index 0000000,54c2872..54c2872 mode 000000,100644..100644 --- a/libeap/src/common/wpa_helpers.h +++ b/libeap/src/common/wpa_helpers.h diff --cc libeap/src/crypto/aes-ccm.c index 0000000,cf22778..cf22778 mode 000000,100644..100644 --- a/libeap/src/crypto/aes-ccm.c +++ b/libeap/src/crypto/aes-ccm.c diff --cc libeap/src/crypto/aes-gcm.c index 0000000,84294d2..84294d2 mode 000000,100644..100644 --- a/libeap/src/crypto/aes-gcm.c +++ b/libeap/src/crypto/aes-gcm.c diff --cc libeap/src/crypto/aes-siv.c index 0000000,5ac82c2..5ac82c2 mode 000000,100644..100644 --- a/libeap/src/crypto/aes-siv.c +++ b/libeap/src/crypto/aes-siv.c diff --cc libeap/src/crypto/aes_siv.h index 0000000,463cf65..463cf65 mode 000000,100644..100644 --- a/libeap/src/crypto/aes_siv.h +++ b/libeap/src/crypto/aes_siv.h diff --cc libeap/src/crypto/crypto_module_tests.c index 0000000,581005d..581005d mode 000000,100644..100644 --- a/libeap/src/crypto/crypto_module_tests.c +++ b/libeap/src/crypto/crypto_module_tests.c diff --cc libeap/src/crypto/random.c index 0000000,3a86a93..3a86a93 mode 000000,100644..100644 --- a/libeap/src/crypto/random.c +++ b/libeap/src/crypto/random.c diff --cc libeap/src/crypto/random.h index 0000000,d13e1c4..d13e1c4 mode 000000,100644..100644 --- a/libeap/src/crypto/random.h +++ b/libeap/src/crypto/random.h diff --cc libeap/src/crypto/sha1-prf.c index 0000000,4b2d137..4b2d137 mode 000000,100644..100644 --- a/libeap/src/crypto/sha1-prf.c +++ b/libeap/src/crypto/sha1-prf.c diff --cc libeap/src/crypto/sha256-kdf.c index 0000000,e7509ce..e7509ce mode 000000,100644..100644 --- a/libeap/src/crypto/sha256-kdf.c +++ b/libeap/src/crypto/sha256-kdf.c diff --cc libeap/src/crypto/sha256-prf.c index 0000000,79791c0..79791c0 mode 000000,100644..100644 --- a/libeap/src/crypto/sha256-prf.c +++ b/libeap/src/crypto/sha256-prf.c diff --cc libeap/src/crypto/sha256-tlsprf.c index 0000000,0528dad..0528dad mode 000000,100644..100644 --- a/libeap/src/crypto/sha256-tlsprf.c +++ b/libeap/src/crypto/sha256-tlsprf.c diff --cc libeap/src/crypto/sha256_i.h index 0000000,a502d2b..a502d2b mode 000000,100644..100644 --- a/libeap/src/crypto/sha256_i.h +++ b/libeap/src/crypto/sha256_i.h diff --cc libeap/src/crypto/sha384-prf.c index 0000000,653920b..653920b mode 000000,100644..100644 --- a/libeap/src/crypto/sha384-prf.c +++ b/libeap/src/crypto/sha384-prf.c diff --cc libeap/src/crypto/sha384.h index 0000000,3deafa5..3deafa5 mode 000000,100644..100644 --- a/libeap/src/crypto/sha384.h +++ b/libeap/src/crypto/sha384.h diff --cc libeap/src/crypto/tls_openssl.c index d155c09,0000000..0a8ae57 mode 100644,000000..100644 --- a/libeap/src/crypto/tls_openssl.c +++ b/libeap/src/crypto/tls_openssl.c @@@ -1,2919 -1,0 +1,4148 @@@ +/* + * SSL/TLS interface functions for OpenSSL - * Copyright (c) 2004-2010, Jouni Malinen ++ * Copyright (c) 2004-2015, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#include "includes.h" + +#ifndef CONFIG_SMARTCARD +#ifndef OPENSSL_NO_ENGINE ++#ifndef ANDROID +#define OPENSSL_NO_ENGINE +#endif +#endif ++#endif + +#include +#include +#include +#include +#ifndef OPENSSL_NO_ENGINE +#include +#endif /* OPENSSL_NO_ENGINE */ ++#ifndef OPENSSL_NO_DSA ++#include ++#endif ++#ifndef OPENSSL_NO_DH ++#include ++#endif + +#include "common.h" +#include "crypto.h" ++#include "sha1.h" ++#include "sha256.h" +#include "tls.h" + - #if OPENSSL_VERSION_NUMBER >= 0x0090800fL - #define OPENSSL_d2i_TYPE const unsigned char ** - #else - #define OPENSSL_d2i_TYPE unsigned char ** ++#if OPENSSL_VERSION_NUMBER < 0x10000000L ++/* ERR_remove_thread_state replaces ERR_remove_state and the latter is ++ * deprecated. However, OpenSSL 0.9.8 doesn't include ++ * ERR_remove_thread_state. */ ++#define ERR_remove_thread_state(tid) ERR_remove_state(0) +#endif + - #ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT - #ifdef SSL_OP_NO_TICKET - /* - * Session ticket override patch was merged into OpenSSL 0.9.9 tree on - * 2008-11-15. This version uses a bit different API compared to the old patch. - */ - #define CONFIG_OPENSSL_TICKET_OVERRIDE - #endif ++#if 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 ++#endif /* OPENSSL_NO_TLSEXT */ ++#endif /* SSL_set_tlsext_status_type */ ++ ++#ifdef ANDROID ++#include ++#include ++ ++static BIO * BIO_from_keystore(const char *key) ++{ ++ BIO *bio = NULL; ++ uint8_t *value = NULL; ++ int length = keystore_get(key, strlen(key), &value); ++ if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL) ++ BIO_write(bio, value, length); ++ free(value); ++ return bio; ++} ++#endif /* ANDROID */ ++ +static int tls_openssl_ref_count = 0; ++static int tls_ex_idx_session = -1; + - struct tls_global { ++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_global *tls_global = NULL; ++static struct tls_context *tls_global = NULL; ++ + ++struct tls_data { ++ SSL_CTX *ssl; ++ unsigned int tls_session_lifetime; ++}; + +struct tls_connection { ++ struct tls_context *context; ++ SSL_CTX *ssl_ctx; + SSL *ssl; + BIO *ssl_in, *ssl_out; +#ifndef OPENSSL_NO_ENGINE + ENGINE *engine; /* functional reference to the engine */ + EVP_PKEY *private_key; /* the private key if using engine */ +#endif /* OPENSSL_NO_ENGINE */ - char *subject_match, *altsubject_match; ++ char *subject_match, *altsubject_match, *suffix_match, *domain_match; + int read_alerts, write_alerts, failed; + + tls_session_ticket_cb session_ticket_cb; + void *session_ticket_cb_ctx; + + /* SessionTicket received from OpenSSL hello_extension_cb (server) */ + u8 *session_ticket; + size_t session_ticket_len; + + unsigned int ca_cert_verify:1; + unsigned int cert_probe:1; + unsigned int server_cert_only:1; ++ unsigned int invalid_hb_used:1; ++ unsigned int success_data:1; + + u8 srv_cert_hash[32]; ++ ++ unsigned int flags; ++ ++ X509 *peer_cert; ++ X509 *peer_issuer; ++ X509 *peer_issuer_issuer; ++ ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L ++ unsigned char client_random[SSL3_RANDOM_SIZE]; ++ unsigned char server_random[SSL3_RANDOM_SIZE]; ++#endif +}; + + ++static struct tls_context * tls_context_new(const struct tls_config *conf) ++{ ++ struct tls_context *context = os_zalloc(sizeof(*context)); ++ if (context == NULL) ++ return NULL; ++ if (conf) { ++ context->event_cb = conf->event_cb; ++ context->cb_ctx = conf->cb_ctx; ++ context->cert_in_cb = conf->cert_in_cb; ++ } ++ return context; ++} ++ ++ +#ifdef CONFIG_NO_STDOUT_DEBUG + +static void _tls_show_errors(void) +{ + unsigned long err; + + while ((err = ERR_get_error())) { + /* Just ignore the errors, since stdout is disabled */ + } +} +#define tls_show_errors(l, f, t) _tls_show_errors() + +#else /* CONFIG_NO_STDOUT_DEBUG */ + +static void tls_show_errors(int level, const char *func, const char *txt) +{ + unsigned long err; + + wpa_printf(level, "OpenSSL: %s - %s %s", + func, txt, ERR_error_string(ERR_get_error(), NULL)); + + while ((err = ERR_get_error())) { + wpa_printf(MSG_INFO, "OpenSSL: pending error: %s", + ERR_error_string(err, NULL)); + } +} + +#endif /* CONFIG_NO_STDOUT_DEBUG */ + + +#ifdef CONFIG_NATIVE_WINDOWS + +/* Windows CryptoAPI and access to certificate stores */ +#include + +#ifdef __MINGW32_VERSION +/* + * MinGW does not yet include all the needed definitions for CryptoAPI, so + * define here whatever extra is needed. + */ +#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16) +#define CERT_STORE_READONLY_FLAG 0x00008000 +#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 + +#endif /* __MINGW32_VERSION */ + + +struct cryptoapi_rsa_data { + const CERT_CONTEXT *cert; + HCRYPTPROV crypt_prov; + DWORD key_spec; + BOOL free_crypt_prov; +}; + + +static void cryptoapi_error(const char *msg) +{ + wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u", + msg, (unsigned int) GetLastError()); +} + + +static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); + return 0; +} + + +static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); + return 0; +} + + +static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + struct cryptoapi_rsa_data *priv = + (struct cryptoapi_rsa_data *) rsa->meth->app_data; + HCRYPTHASH hash; + DWORD hash_size, len, i; + unsigned char *buf = NULL; + int ret = 0; + + if (priv == NULL) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, + ERR_R_PASSED_NULL_PARAMETER); + return 0; + } + + if (padding != RSA_PKCS1_PADDING) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, + RSA_R_UNKNOWN_PADDING_TYPE); + return 0; + } + + if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) { + wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported", + __func__); + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, + RSA_R_INVALID_MESSAGE_LENGTH); + return 0; + } + + if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash)) + { + cryptoapi_error("CryptCreateHash failed"); + return 0; + } + + len = sizeof(hash_size); + if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len, + 0)) { + cryptoapi_error("CryptGetHashParam failed"); + goto err; + } + + if ((int) hash_size != flen) { + wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)", + (unsigned) hash_size, flen); + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, + RSA_R_INVALID_MESSAGE_LENGTH); + goto err; + } + if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) { + cryptoapi_error("CryptSetHashParam failed"); + goto err; + } + + len = RSA_size(rsa); + buf = os_malloc(len); + if (buf == NULL) { + RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) { + cryptoapi_error("CryptSignHash failed"); + goto err; + } + + for (i = 0; i < len; i++) + to[i] = buf[len - i - 1]; + ret = len; + +err: + os_free(buf); + CryptDestroyHash(hash); + + return ret; +} + + +static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from, + unsigned char *to, RSA *rsa, int padding) +{ + wpa_printf(MSG_DEBUG, "%s - not implemented", __func__); + return 0; +} + + +static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv) +{ + if (priv == NULL) + return; + if (priv->crypt_prov && priv->free_crypt_prov) + CryptReleaseContext(priv->crypt_prov, 0); + if (priv->cert) + CertFreeCertificateContext(priv->cert); + os_free(priv); +} + + +static int cryptoapi_finish(RSA *rsa) +{ + cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data); + os_free((void *) rsa->meth); + rsa->meth = NULL; + return 1; +} + + +static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store) +{ + HCERTSTORE cs; + const CERT_CONTEXT *ret = NULL; + + cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0, + store | CERT_STORE_OPEN_EXISTING_FLAG | + CERT_STORE_READONLY_FLAG, L"MY"); + if (cs == NULL) { + cryptoapi_error("Failed to open 'My system store'"); + return NULL; + } + + if (strncmp(name, "cert://", 7) == 0) { + unsigned short wbuf[255]; + MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255); + ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING | + PKCS_7_ASN_ENCODING, + 0, CERT_FIND_SUBJECT_STR, + wbuf, NULL); + } else if (strncmp(name, "hash://", 7) == 0) { + CRYPT_HASH_BLOB blob; + int len; + const char *hash = name + 7; + unsigned char *buf; + + len = os_strlen(hash) / 2; + buf = os_malloc(len); + if (buf && hexstr2bin(hash, buf, len) == 0) { + blob.cbData = len; + blob.pbData = buf; + ret = CertFindCertificateInStore(cs, + X509_ASN_ENCODING | + PKCS_7_ASN_ENCODING, + 0, CERT_FIND_HASH, + &blob, NULL); + } + os_free(buf); + } + + CertCloseStore(cs, 0); + + return ret; +} + + +static int tls_cryptoapi_cert(SSL *ssl, const char *name) +{ + X509 *cert = NULL; + RSA *rsa = NULL, *pub_rsa; + struct cryptoapi_rsa_data *priv; + RSA_METHOD *rsa_meth; + + if (name == NULL || + (strncmp(name, "cert://", 7) != 0 && + strncmp(name, "hash://", 7) != 0)) + return -1; + + priv = os_zalloc(sizeof(*priv)); + rsa_meth = os_zalloc(sizeof(*rsa_meth)); + if (priv == NULL || rsa_meth == NULL) { + wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory " + "for CryptoAPI RSA method"); + os_free(priv); + os_free(rsa_meth); + return -1; + } + + priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER); + if (priv->cert == NULL) { + priv->cert = cryptoapi_find_cert( + name, CERT_SYSTEM_STORE_LOCAL_MACHINE); + } + if (priv->cert == NULL) { + wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate " + "'%s'", name); + goto err; + } + - cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded, ++ cert = d2i_X509(NULL, ++ (const unsigned char **) &priv->cert->pbCertEncoded, + priv->cert->cbCertEncoded); + if (cert == NULL) { + wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER " + "encoding"); + goto err; + } + + if (!CryptAcquireCertificatePrivateKey(priv->cert, + CRYPT_ACQUIRE_COMPARE_KEY_FLAG, + NULL, &priv->crypt_prov, + &priv->key_spec, + &priv->free_crypt_prov)) { + cryptoapi_error("Failed to acquire a private key for the " + "certificate"); + goto err; + } + + rsa_meth->name = "Microsoft CryptoAPI RSA Method"; + rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc; + rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec; + rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc; + rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec; + rsa_meth->finish = cryptoapi_finish; + rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK; + rsa_meth->app_data = (char *) priv; + + rsa = RSA_new(); + if (rsa == NULL) { + SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, + ERR_R_MALLOC_FAILURE); + goto err; + } + + if (!SSL_use_certificate(ssl, cert)) { + RSA_free(rsa); + rsa = NULL; + goto err; + } + pub_rsa = cert->cert_info->key->pkey->pkey.rsa; + X509_free(cert); + cert = NULL; + + rsa->n = BN_dup(pub_rsa->n); + rsa->e = BN_dup(pub_rsa->e); + if (!RSA_set_method(rsa, rsa_meth)) + goto err; + + if (!SSL_use_RSAPrivateKey(ssl, rsa)) + goto err; + RSA_free(rsa); + + return 0; + +err: + if (cert) + X509_free(cert); + if (rsa) + RSA_free(rsa); + else { + os_free(rsa_meth); + cryptoapi_free_data(priv); + } + return -1; +} + + +static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name) +{ + HCERTSTORE cs; + PCCERT_CONTEXT ctx = NULL; + X509 *cert; + char buf[128]; + const char *store; +#ifdef UNICODE + WCHAR *wstore; +#endif /* UNICODE */ + + if (name == NULL || strncmp(name, "cert_store://", 13) != 0) + return -1; + + store = name + 13; +#ifdef UNICODE + wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR)); + if (wstore == NULL) + return -1; + wsprintf(wstore, L"%S", store); + cs = CertOpenSystemStore(0, wstore); + os_free(wstore); +#else /* UNICODE */ + cs = CertOpenSystemStore(0, store); +#endif /* UNICODE */ + if (cs == NULL) { + wpa_printf(MSG_DEBUG, "%s: failed to open system cert store " + "'%s': error=%d", __func__, store, + (int) GetLastError()); + return -1; + } + + while ((ctx = CertEnumCertificatesInStore(cs, ctx))) { - cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded, ++ cert = d2i_X509(NULL, ++ (const unsigned char **) &ctx->pbCertEncoded, + ctx->cbCertEncoded); + if (cert == NULL) { + wpa_printf(MSG_INFO, "CryptoAPI: Could not process " + "X509 DER encoding for CA cert"); + continue; + } + + X509_NAME_oneline(X509_get_subject_name(cert), buf, + sizeof(buf)); + wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for " + "system certificate store: subject='%s'", buf); + + if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { + tls_show_errors(MSG_WARNING, __func__, + "Failed to add ca_cert to OpenSSL " + "certificate store"); + } + + X509_free(cert); + } + + if (!CertCloseStore(cs, 0)) { + wpa_printf(MSG_DEBUG, "%s: failed to close system cert store " + "'%s': error=%d", __func__, name + 13, + (int) GetLastError()); + } + + return 0; +} + + +#else /* CONFIG_NATIVE_WINDOWS */ + +static int tls_cryptoapi_cert(SSL *ssl, const char *name) +{ + return -1; +} + +#endif /* CONFIG_NATIVE_WINDOWS */ + + +static void ssl_info_cb(const SSL *ssl, int where, int ret) +{ + const char *str; + int w; + + wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret); + w = where & ~SSL_ST_MASK; + if (w & SSL_ST_CONNECT) + str = "SSL_connect"; + else if (w & SSL_ST_ACCEPT) + str = "SSL_accept"; + else + str = "undefined"; + + if (where & SSL_CB_LOOP) { + wpa_printf(MSG_DEBUG, "SSL: %s:%s", + str, SSL_state_string_long(ssl)); + } else if (where & SSL_CB_ALERT) { ++ struct tls_connection *conn = SSL_get_app_data((SSL *) ssl); + wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s", + where & SSL_CB_READ ? + "read (remote end reported an error)" : + "write (local SSL3 detected an error)", + SSL_alert_type_string_long(ret), + SSL_alert_desc_string_long(ret)); + if ((ret >> 8) == SSL3_AL_FATAL) { - struct tls_connection *conn = - SSL_get_app_data((SSL *) ssl); + if (where & SSL_CB_READ) + conn->read_alerts++; + else + conn->write_alerts++; + } ++ if (conn->context->event_cb != NULL) { ++ union tls_event_data ev; ++ struct tls_context *context = conn->context; ++ os_memset(&ev, 0, sizeof(ev)); ++ ev.alert.is_local = !(where & SSL_CB_READ); ++ ev.alert.type = SSL_alert_type_string_long(ret); ++ ev.alert.description = SSL_alert_desc_string_long(ret); ++ context->event_cb(context->cb_ctx, TLS_ALERT, &ev); ++ } + } else if (where & SSL_CB_EXIT && ret <= 0) { + wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s", + str, ret == 0 ? "failed" : "error", + SSL_state_string_long(ssl)); + } +} + + +#ifndef OPENSSL_NO_ENGINE +/** + * tls_engine_load_dynamic_generic - load any openssl engine + * @pre: an array of commands and values that load an engine initialized + * in the engine specific function + * @post: an array of commands and values that initialize an already loaded + * engine (or %NULL if not required) + * @id: the engine id of the engine to load (only required if post is not %NULL + * + * This function is a generic function that loads any openssl engine. + * + * Returns: 0 on success, -1 on failure + */ +static int tls_engine_load_dynamic_generic(const char *pre[], + const char *post[], const char *id) +{ + ENGINE *engine; + const char *dynamic_id = "dynamic"; + + engine = ENGINE_by_id(id); + if (engine) { + ENGINE_free(engine); + wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already " + "available", id); + return 0; + } + ERR_clear_error(); + + engine = ENGINE_by_id(dynamic_id); + if (engine == NULL) { + wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", + dynamic_id, + ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + + /* Perform the pre commands. This will load the engine. */ + while (pre && pre[0]) { + wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]); + if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) { + wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: " + "%s %s [%s]", pre[0], pre[1], + ERR_error_string(ERR_get_error(), NULL)); + ENGINE_free(engine); + return -1; + } + pre += 2; + } + + /* + * Free the reference to the "dynamic" engine. The loaded engine can + * now be looked up using ENGINE_by_id(). + */ + ENGINE_free(engine); + + engine = ENGINE_by_id(id); + if (engine == NULL) { + wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]", + id, ERR_error_string(ERR_get_error(), NULL)); + return -1; + } + + while (post && post[0]) { + wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]); + if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) { + wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:" + " %s %s [%s]", post[0], post[1], + ERR_error_string(ERR_get_error(), NULL)); + ENGINE_remove(engine); + ENGINE_free(engine); + return -1; + } + post += 2; + } + ENGINE_free(engine); + + return 0; +} + + +/** + * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc + * @pkcs11_so_path: pksc11_so_path from the configuration + * @pcks11_module_path: pkcs11_module_path from the configuration + */ +static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path, + const char *pkcs11_module_path) +{ + char *engine_id = "pkcs11"; + const char *pre_cmd[] = { + "SO_PATH", NULL /* pkcs11_so_path */, + "ID", NULL /* engine_id */, + "LIST_ADD", "1", + /* "NO_VCHECK", "1", */ + "LOAD", NULL, + NULL, NULL + }; + const char *post_cmd[] = { + "MODULE_PATH", NULL /* pkcs11_module_path */, + NULL, NULL + }; + - if (!pkcs11_so_path || !pkcs11_module_path) ++ if (!pkcs11_so_path) + return 0; + + pre_cmd[1] = pkcs11_so_path; + pre_cmd[3] = engine_id; - post_cmd[1] = pkcs11_module_path; ++ 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 = os_zalloc(sizeof(*tls_global)); - if (tls_global == NULL) ++ tls_global = context = tls_context_new(conf); ++ if (context == NULL) + return NULL; - if (conf) { - tls_global->event_cb = conf->event_cb; - tls_global->cb_ctx = conf->cb_ctx; - } - +#ifdef CONFIG_FIPS +#ifdef OPENSSL_FIPS + if (conf && conf->fips_mode) { - if (!FIPS_mode_set(1)) { ++ 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 ++ } else { + wpa_printf(MSG_INFO, "Running in FIPS mode"); ++ fips_enabled = 1; ++ } + } +#else /* OPENSSL_FIPS */ + if (conf && conf->fips_mode) { + wpa_printf(MSG_ERROR, "FIPS mode requested, but not " + "supported"); ++ os_free(tls_global); ++ tls_global = NULL; + return NULL; + } +#endif /* OPENSSL_FIPS */ +#endif /* CONFIG_FIPS */ + SSL_load_error_strings(); + SSL_library_init(); +#ifndef OPENSSL_NO_SHA256 + EVP_add_digest(EVP_sha256()); +#endif /* OPENSSL_NO_SHA256 */ + /* TODO: if /dev/urandom is available, PRNG is seeded + * automatically. If this is not the case, random data should + * be added here. */ + +#ifdef PKCS12_FUNCS +#ifndef OPENSSL_NO_RC2 + /* + * 40-bit RC2 is commonly used in PKCS#12 files, so enable it. + * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8 + * versions, but it looks like OpenSSL 1.0.0 does not do that + * anymore. + */ + EVP_add_cipher(EVP_rc2_40_cbc()); +#endif /* OPENSSL_NO_RC2 */ + PKCS12_PBE_add(); +#endif /* PKCS12_FUNCS */ ++ } else { ++ context = tls_context_new(conf); ++ if (context == NULL) ++ return NULL; + } + tls_openssl_ref_count++; + - ssl = SSL_CTX_new(TLSv1_method()); - if (ssl == NULL) ++ data = os_zalloc(sizeof(*data)); ++ if (data) ++ ssl = SSL_CTX_new(SSLv23_method()); ++ else ++ ssl = NULL; ++ if (ssl == NULL) { ++ tls_openssl_ref_count--; ++ if (context != tls_global) ++ os_free(context); ++ if (tls_openssl_ref_count == 0) { ++ os_free(tls_global); ++ tls_global = NULL; ++ } + return NULL; ++ } ++ data->ssl = ssl; ++ if (conf) ++ data->tls_session_lifetime = conf->tls_session_lifetime; ++ ++ SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2); ++ SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3); + + SSL_CTX_set_info_callback(ssl, ssl_info_cb); ++ SSL_CTX_set_app_data(ssl, context); ++ if (data->tls_session_lifetime > 0) { ++ SSL_CTX_set_quiet_shutdown(ssl, 1); ++ /* ++ * Set default context here. In practice, this will be replaced ++ * by the per-EAP method context in tls_connection_set_verify(). ++ */ ++ SSL_CTX_set_session_id_context(ssl, (u8 *) "hostapd", 7); ++ SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_SERVER); ++ SSL_CTX_set_timeout(ssl, data->tls_session_lifetime); ++ SSL_CTX_sess_set_remove_cb(ssl, remove_session_cb); ++ } else { ++ SSL_CTX_set_session_cache_mode(ssl, SSL_SESS_CACHE_OFF); ++ } ++ ++ if (tls_ex_idx_session < 0) { ++ tls_ex_idx_session = SSL_SESSION_get_ex_new_index( ++ 0, NULL, NULL, NULL, NULL); ++ if (tls_ex_idx_session < 0) { ++ tls_deinit(data); ++ return NULL; ++ } ++ } + +#ifndef OPENSSL_NO_ENGINE ++ wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); ++ ERR_load_ENGINE_strings(); ++ ENGINE_load_dynamic(); ++ + if (conf && + (conf->opensc_engine_path || conf->pkcs11_engine_path || + conf->pkcs11_module_path)) { - wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine"); - ERR_load_ENGINE_strings(); - ENGINE_load_dynamic(); - + 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(ssl); ++ tls_deinit(data); + return NULL; + } + } +#endif /* OPENSSL_NO_ENGINE */ + - return ssl; ++ 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) +{ - SSL_CTX *ssl = 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) { - ERR_remove_state(0); ++// The next four lines, and two more just below, deal with de-initializing ++// global state in the OpenSSL engine. We (Moonshot) don't want that, since ++// we use OpenSSL elsewhere in our apps (i.e., not only via hostap / libeap.) ++//// #ifndef OPENSSL_NO_ENGINE ++//// ENGINE_cleanup(); ++//// #endif /* OPENSSL_NO_ENGINE */ ++//// CRYPTO_cleanup_all_ex_data(); ++ ERR_remove_thread_state(NULL); ++//// ERR_free_strings(); ++//// EVP_cleanup(); ++ os_free(tls_global->ocsp_stapling_response); ++ tls_global->ocsp_stapling_response = NULL; + os_free(tls_global); + tls_global = NULL; + } ++ ++ os_free(data); ++} ++ ++ ++#ifndef OPENSSL_NO_ENGINE ++ ++/* Cryptoki return values */ ++#define CKR_PIN_INCORRECT 0x000000a0 ++#define CKR_PIN_INVALID 0x000000a1 ++#define CKR_PIN_LEN_RANGE 0x000000a2 ++ ++/* libp11 */ ++#define ERR_LIB_PKCS11 ERR_LIB_USER ++ ++static int tls_is_pin_error(unsigned int err) ++{ ++ return ERR_GET_LIB(err) == ERR_LIB_PKCS11 && ++ (ERR_GET_REASON(err) == CKR_PIN_INCORRECT || ++ ERR_GET_REASON(err) == CKR_PIN_INVALID || ++ ERR_GET_REASON(err) == CKR_PIN_LEN_RANGE); +} + ++#endif /* OPENSSL_NO_ENGINE */ ++ + +static int tls_engine_init(struct tls_connection *conn, const char *engine_id, + const char *pin, const char *key_id, + const char *cert_id, const char *ca_cert_id) +{ +#ifndef OPENSSL_NO_ENGINE + int ret = -1; + if (engine_id == NULL) { + wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set"); + return -1; + } - if (pin == NULL) { - wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set"); - return -1; - } - if (key_id == NULL) { - wpa_printf(MSG_ERROR, "ENGINE: Key Id not set"); - return -1; - } + + 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"); + - if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) { ++#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; + } - /* load private key first in-case PIN is required for cert */ - conn->private_key = ENGINE_load_private_key(conn->engine, - key_id, NULL, NULL); - if (!conn->private_key) { - wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id" - " '%s' [%s]", key_id, - ERR_error_string(ERR_get_error(), NULL)); - ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; - goto err; ++#endif ++ if (key_id) { ++ /* ++ * Ensure that the ENGINE does not attempt to use the OpenSSL ++ * UI system to obtain a PIN, if we didn't provide one. ++ */ ++ struct { ++ const void *password; ++ const char *prompt_info; ++ } key_cb = { "", NULL }; ++ ++ /* load private key first in-case PIN is required for cert */ ++ conn->private_key = ENGINE_load_private_key(conn->engine, ++ key_id, NULL, ++ &key_cb); ++ if (!conn->private_key) { ++ unsigned long err = ERR_get_error(); ++ ++ wpa_printf(MSG_ERROR, ++ "ENGINE: cannot load private key with id '%s' [%s]", ++ key_id, ++ ERR_error_string(err, NULL)); ++ if (tls_is_pin_error(err)) ++ ret = TLS_SET_PARAMS_ENGINE_PRV_BAD_PIN; ++ else ++ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; ++ goto err; ++ } + } + + /* handle a certificate and/or CA certificate */ + if (cert_id || ca_cert_id) { + const char *cmd_name = "LOAD_CERT_CTRL"; + + /* test if the engine supports a LOAD_CERT_CTRL */ + if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME, + 0, (void *)cmd_name, NULL)) { + wpa_printf(MSG_ERROR, "ENGINE: engine does not support" + " loading certificates"); + ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED; + goto err; + } + } + + return 0; + +err: + if (conn->engine) { + ENGINE_free(conn->engine); + conn->engine = NULL; + } + + if (conn->private_key) { + EVP_PKEY_free(conn->private_key); + conn->private_key = NULL; + } + + return ret; +#else /* OPENSSL_NO_ENGINE */ + return 0; +#endif /* OPENSSL_NO_ENGINE */ +} + + +static void tls_engine_deinit(struct tls_connection *conn) +{ +#ifndef OPENSSL_NO_ENGINE + wpa_printf(MSG_DEBUG, "ENGINE: engine deinit"); + if (conn->private_key) { + EVP_PKEY_free(conn->private_key); + conn->private_key = NULL; + } + if (conn->engine) { + ENGINE_finish(conn->engine); + conn->engine = NULL; + } +#endif /* OPENSSL_NO_ENGINE */ +} + + +int tls_get_errors(void *ssl_ctx) +{ + int count = 0; + unsigned long err; + + while ((err = ERR_get_error())) { + wpa_printf(MSG_INFO, "TLS - SSL error: %s", + ERR_error_string(err, NULL)); + count++; + } + + return count; +} + ++ ++static void tls_msg_cb(int write_p, int version, int content_type, ++ const void *buf, size_t len, SSL *ssl, void *arg) ++{ ++ struct tls_connection *conn = arg; ++ const u8 *pos = buf; ++ ++ wpa_printf(MSG_DEBUG, "OpenSSL: %s ver=0x%x content_type=%d", ++ write_p ? "TX" : "RX", version, content_type); ++ wpa_hexdump_key(MSG_MSGDUMP, "OpenSSL: Message", buf, len); ++ if (content_type == 24 && len >= 3 && pos[0] == 1) { ++ size_t payload_len = WPA_GET_BE16(pos + 1); ++ if (payload_len + 3 > len) { ++ wpa_printf(MSG_ERROR, "OpenSSL: Heartbeat attack detected"); ++ conn->invalid_hb_used = 1; ++ } ++ } ++} ++ ++ +struct tls_connection * tls_connection_init(void *ssl_ctx) +{ - SSL_CTX *ssl = 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 0; ++ return SSL_clear(conn->ssl) == 1 ? 0 : -1; +} + + +static int tls_match_altsubject_component(X509 *cert, int type, + const char *value, size_t len) +{ + GENERAL_NAME *gen; + void *ext; - int i, found = 0; ++ int found = 0; ++ stack_index_t i; + + ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); + + for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { + gen = sk_GENERAL_NAME_value(ext, i); + if (gen->type != type) + continue; + if (os_strlen((char *) gen->d.ia5->data) == len && + os_memcmp(value, gen->d.ia5->data, len) == 0) + found++; + } + + return found; +} + + +static int tls_match_altsubject(X509 *cert, const char *match) +{ + int type; + const char *pos, *end; + size_t len; + + pos = match; + do { + if (os_strncmp(pos, "EMAIL:", 6) == 0) { + type = GEN_EMAIL; + pos += 6; + } else if (os_strncmp(pos, "DNS:", 4) == 0) { + type = GEN_DNS; + pos += 4; + } else if (os_strncmp(pos, "URI:", 4) == 0) { + type = GEN_URI; + pos += 4; + } else { + wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName " + "match '%s'", pos); + return 0; + } + end = os_strchr(pos, ';'); + while (end) { + if (os_strncmp(end + 1, "EMAIL:", 6) == 0 || + os_strncmp(end + 1, "DNS:", 4) == 0 || + os_strncmp(end + 1, "URI:", 4) == 0) + break; + end = os_strchr(end + 1, ';'); + } + if (end) + len = end - pos; + else + len = os_strlen(pos); + if (tls_match_altsubject_component(cert, type, pos, len) > 0) + return 1; + pos = end + 1; + } while (end); + + return 0; +} + + ++#ifndef CONFIG_NATIVE_WINDOWS ++static int domain_suffix_match(const u8 *val, size_t len, const char *match, ++ int full) ++{ ++ size_t i, match_len; ++ ++ /* Check for embedded nuls that could mess up suffix matching */ ++ for (i = 0; i < len; i++) { ++ if (val[i] == '\0') { ++ wpa_printf(MSG_DEBUG, "TLS: Embedded null in a string - reject"); ++ return 0; ++ } ++ } ++ ++ match_len = os_strlen(match); ++ if (match_len > len || (full && match_len != len)) ++ return 0; ++ ++ if (os_strncasecmp((const char *) val + len - match_len, match, ++ match_len) != 0) ++ return 0; /* no match */ ++ ++ if (match_len == len) ++ return 1; /* exact match */ ++ ++ if (val[len - match_len - 1] == '.') ++ return 1; /* full label match completes suffix match */ ++ ++ wpa_printf(MSG_DEBUG, "TLS: Reject due to incomplete label match"); ++ return 0; ++} ++#endif /* CONFIG_NATIVE_WINDOWS */ ++ ++ ++static int tls_match_suffix(X509 *cert, const char *match, int full) ++{ ++#ifdef CONFIG_NATIVE_WINDOWS ++ /* wincrypt.h has conflicting X509_NAME definition */ ++ return -1; ++#else /* CONFIG_NATIVE_WINDOWS */ ++ GENERAL_NAME *gen; ++ void *ext; ++ int i; ++ stack_index_t j; ++ int dns_name = 0; ++ X509_NAME *name; ++ ++ wpa_printf(MSG_DEBUG, "TLS: Match domain against %s%s", ++ full ? "": "suffix ", match); ++ ++ ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); ++ ++ for (j = 0; ext && j < sk_GENERAL_NAME_num(ext); j++) { ++ gen = sk_GENERAL_NAME_value(ext, j); ++ if (gen->type != GEN_DNS) ++ continue; ++ dns_name++; ++ wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate dNSName", ++ gen->d.dNSName->data, ++ gen->d.dNSName->length); ++ if (domain_suffix_match(gen->d.dNSName->data, ++ gen->d.dNSName->length, match, full) == ++ 1) { ++ wpa_printf(MSG_DEBUG, "TLS: %s in dNSName found", ++ full ? "Match" : "Suffix match"); ++ return 1; ++ } ++ } ++ ++ if (dns_name) { ++ wpa_printf(MSG_DEBUG, "TLS: None of the dNSName(s) matched"); ++ return 0; ++ } ++ ++ name = X509_get_subject_name(cert); ++ i = -1; ++ for (;;) { ++ X509_NAME_ENTRY *e; ++ ASN1_STRING *cn; ++ ++ i = X509_NAME_get_index_by_NID(name, NID_commonName, i); ++ if (i == -1) ++ break; ++ e = X509_NAME_get_entry(name, i); ++ if (e == NULL) ++ continue; ++ cn = X509_NAME_ENTRY_get_data(e); ++ if (cn == NULL) ++ continue; ++ wpa_hexdump_ascii(MSG_DEBUG, "TLS: Certificate commonName", ++ cn->data, cn->length); ++ if (domain_suffix_match(cn->data, cn->length, match, full) == 1) ++ { ++ wpa_printf(MSG_DEBUG, "TLS: %s in commonName found", ++ full ? "Match" : "Suffix match"); ++ return 1; ++ } ++ } ++ ++ wpa_printf(MSG_DEBUG, "TLS: No CommonName %smatch found", ++ full ? "": "suffix "); ++ return 0; ++#endif /* CONFIG_NATIVE_WINDOWS */ ++} ++ ++ +static enum tls_fail_reason openssl_tls_fail_reason(int err) +{ + switch (err) { + case X509_V_ERR_CERT_REVOKED: + return TLS_FAIL_REVOKED; + case X509_V_ERR_CERT_NOT_YET_VALID: + case X509_V_ERR_CRL_NOT_YET_VALID: + return TLS_FAIL_NOT_YET_VALID; + case X509_V_ERR_CERT_HAS_EXPIRED: + case X509_V_ERR_CRL_HAS_EXPIRED: + return TLS_FAIL_EXPIRED; + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: + case X509_V_ERR_UNABLE_TO_GET_CRL: + case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER: + case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN: + case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY: + case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT: + case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE: + case X509_V_ERR_CERT_CHAIN_TOO_LONG: + case X509_V_ERR_PATH_LENGTH_EXCEEDED: + case X509_V_ERR_INVALID_CA: + return TLS_FAIL_UNTRUSTED; + case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE: + case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY: + case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: + case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: + case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD: + case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD: + case X509_V_ERR_CERT_UNTRUSTED: + case X509_V_ERR_CERT_REJECTED: + return TLS_FAIL_BAD_CERTIFICATE; + default: + return TLS_FAIL_UNSPECIFIED; + } +} + + +static struct wpabuf * get_x509_cert(X509 *cert) +{ + struct wpabuf *buf; + u8 *tmp; + + int cert_len = i2d_X509(cert, NULL); + if (cert_len <= 0) + return NULL; + + buf = wpabuf_alloc(cert_len); + if (buf == NULL) + return NULL; + + tmp = wpabuf_put(buf, cert_len); + i2d_X509(cert, &tmp); + return buf; +} + + +static void openssl_tls_fail_event(struct tls_connection *conn, + X509 *err_cert, int err, int depth, + const char *subject, const char *err_str, + enum tls_fail_reason reason) +{ + union tls_event_data ev; + struct wpabuf *cert = NULL; ++ struct tls_context *context = conn->context; + - if (tls_global->event_cb == NULL) ++ 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; - tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev); ++ 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 (tls_global->event_cb == NULL) ++ if (context->event_cb == NULL) + return; + + os_memset(&ev, 0, sizeof(ev)); - if (conn->cert_probe) { ++ if (conn->cert_probe || context->cert_in_cb) { + cert = get_x509_cert(err_cert); + ev.peer_cert.cert = cert; + } +#ifdef CONFIG_SHA256 + if (cert) { + const u8 *addr[1]; + size_t len[1]; + addr[0] = wpabuf_head(cert); + len[0] = wpabuf_len(cert); + if (sha256_vector(1, addr, len, hash) == 0) { + ev.peer_cert.hash = hash; + ev.peer_cert.hash_len = sizeof(hash); + } + } +#endif /* CONFIG_SHA256 */ + ev.peer_cert.depth = depth; + ev.peer_cert.subject = subject; - tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev); ++ ++ ext = X509_get_ext_d2i(err_cert, NID_subject_alt_name, NULL, NULL); ++ for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) { ++ char *pos; ++ ++ if (num_altsubject == TLS_MAX_ALT_SUBJECT) ++ break; ++ gen = sk_GENERAL_NAME_value(ext, i); ++ if (gen->type != GEN_EMAIL && ++ gen->type != GEN_DNS && ++ gen->type != GEN_URI) ++ continue; ++ ++ pos = os_malloc(10 + gen->d.ia5->length + 1); ++ if (pos == NULL) ++ break; ++ altsubject[num_altsubject++] = pos; ++ ++ switch (gen->type) { ++ case GEN_EMAIL: ++ os_memcpy(pos, "EMAIL:", 6); ++ pos += 6; ++ break; ++ case GEN_DNS: ++ os_memcpy(pos, "DNS:", 4); ++ pos += 4; ++ break; ++ case GEN_URI: ++ os_memcpy(pos, "URI:", 4); ++ pos += 4; ++ break; ++ } ++ ++ os_memcpy(pos, gen->d.ia5->data, gen->d.ia5->length); ++ pos += gen->d.ia5->length; ++ *pos = '\0'; ++ } ++ ++ for (alt = 0; alt < num_altsubject; alt++) ++ ev.peer_cert.altsubject[alt] = altsubject[alt]; ++ ev.peer_cert.num_altsubject = num_altsubject; ++ ++ context->event_cb(context->cb_ctx, TLS_PEER_CERTIFICATE, &ev); + wpabuf_free(cert); ++ for (alt = 0; alt < num_altsubject; alt++) ++ os_free(altsubject[alt]); +} + + +static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx) +{ + char buf[256]; + X509 *err_cert; + int err, depth; + SSL *ssl; + struct tls_connection *conn; - char *match, *altmatch; ++ struct tls_context *context; ++ char *match, *altmatch, *suffix_match, *domain_match; + const char *err_str; + + err_cert = X509_STORE_CTX_get_current_cert(x509_ctx); ++ if (!err_cert) ++ return 0; ++ + err = X509_STORE_CTX_get_error(x509_ctx); + depth = X509_STORE_CTX_get_error_depth(x509_ctx); + ssl = X509_STORE_CTX_get_ex_data(x509_ctx, + SSL_get_ex_data_X509_STORE_CTX_idx()); + X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); + + conn = SSL_get_app_data(ssl); - match = conn ? conn->subject_match : NULL; - altmatch = conn ? conn->altsubject_match : NULL; ++ if (conn == NULL) ++ return 0; ++ ++ if (depth == 0) ++ conn->peer_cert = err_cert; ++ else if (depth == 1) ++ conn->peer_issuer = err_cert; ++ else if (depth == 2) ++ conn->peer_issuer_issuer = err_cert; ++ ++ context = conn->context; ++ match = conn->subject_match; ++ altmatch = conn->altsubject_match; ++ suffix_match = conn->suffix_match; ++ domain_match = conn->domain_match; + + if (!preverify_ok && !conn->ca_cert_verify) + preverify_ok = 1; + if (!preverify_ok && depth > 0 && conn->server_cert_only) + preverify_ok = 1; ++ if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) && ++ (err == X509_V_ERR_CERT_HAS_EXPIRED || ++ err == X509_V_ERR_CERT_NOT_YET_VALID)) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity " ++ "time mismatch"); ++ preverify_ok = 1; ++ } + + err_str = X509_verify_cert_error_string(err); + +#ifdef CONFIG_SHA256 - if (preverify_ok && depth == 0 && conn->server_cert_only) { ++ /* ++ * Do not require preverify_ok so we can explicity allow otherwise ++ * invalid pinned server certificates. ++ */ ++ if (depth == 0 && conn->server_cert_only) { + struct wpabuf *cert; + cert = get_x509_cert(err_cert); + if (!cert) { + wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch " + "server certificate data"); + preverify_ok = 0; + } else { + u8 hash[32]; + const u8 *addr[1]; + size_t len[1]; + addr[0] = wpabuf_head(cert); + len[0] = wpabuf_len(cert); + if (sha256_vector(1, addr, len, hash) < 0 || + os_memcmp(conn->srv_cert_hash, hash, 32) != 0) { + err_str = "Server certificate mismatch"; + err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN; + preverify_ok = 0; ++ } else if (!preverify_ok) { ++ /* ++ * Certificate matches pinned certificate, allow ++ * regardless of other problems. ++ */ ++ wpa_printf(MSG_DEBUG, ++ "OpenSSL: Ignore validation issues for a pinned server certificate"); ++ preverify_ok = 1; + } + wpabuf_free(cert); + } + } +#endif /* CONFIG_SHA256 */ + + if (!preverify_ok) { + wpa_printf(MSG_WARNING, "TLS: Certificate verification failed," + " error %d (%s) depth %d for '%s'", err, err_str, + depth, buf); + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + err_str, TLS_FAIL_UNSPECIFIED); + return preverify_ok; + } + + wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d " + "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'", + preverify_ok, err, err_str, + conn->ca_cert_verify, depth, buf); + if (depth == 0 && match && os_strstr(buf, match) == NULL) { + wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not " + "match with '%s'", buf, match); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Subject mismatch", + TLS_FAIL_SUBJECT_MISMATCH); + } else if (depth == 0 && altmatch && + !tls_match_altsubject(err_cert, altmatch)) { + wpa_printf(MSG_WARNING, "TLS: altSubjectName match " + "'%s' not found", altmatch); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "AltSubject mismatch", + TLS_FAIL_ALTSUBJECT_MISMATCH); ++ } else if (depth == 0 && suffix_match && ++ !tls_match_suffix(err_cert, suffix_match, 0)) { ++ wpa_printf(MSG_WARNING, "TLS: Domain suffix match '%s' not found", ++ suffix_match); ++ preverify_ok = 0; ++ openssl_tls_fail_event(conn, err_cert, err, depth, buf, ++ "Domain suffix mismatch", ++ TLS_FAIL_DOMAIN_SUFFIX_MISMATCH); ++ } else if (depth == 0 && domain_match && ++ !tls_match_suffix(err_cert, domain_match, 1)) { ++ wpa_printf(MSG_WARNING, "TLS: Domain match '%s' not found", ++ domain_match); ++ preverify_ok = 0; ++ openssl_tls_fail_event(conn, err_cert, err, depth, buf, ++ "Domain mismatch", ++ TLS_FAIL_DOMAIN_MISMATCH); + } else + openssl_tls_cert_event(conn, err_cert, depth, buf); + + if (conn->cert_probe && preverify_ok && depth == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate " + "on probe-only run"); + preverify_ok = 0; + openssl_tls_fail_event(conn, err_cert, err, depth, buf, + "Server certificate chain probe", + TLS_FAIL_SERVER_CHAIN_PROBE); + } + ++ if (preverify_ok && context->event_cb != NULL) ++ context->event_cb(context->cb_ctx, ++ TLS_CERT_CHAIN_SUCCESS, NULL); ++ + return preverify_ok; +} + + +#ifndef OPENSSL_NO_STDIO - static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert) ++static int tls_load_ca_der(struct tls_data *data, const char *ca_cert) +{ - SSL_CTX *ssl_ctx = _ssl_ctx; ++ SSL_CTX *ssl_ctx = data->ssl; + X509_LOOKUP *lookup; + int ret = 0; + - lookup = X509_STORE_add_lookup(ssl_ctx->cert_store, ++ 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(void *_ssl_ctx, struct tls_connection *conn, ++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) +{ - SSL_CTX *ssl_ctx = _ssl_ctx; ++ SSL_CTX *ssl_ctx = data->ssl; ++ X509_STORE *store; + + /* + * Remove previously configured trusted CA certificates before adding + * new ones. + */ - X509_STORE_free(ssl_ctx->cert_store); - ssl_ctx->cert_store = X509_STORE_new(); - if (ssl_ctx->cert_store == NULL) { ++ store = X509_STORE_new(); ++ if (store == NULL) { + wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new " + "certificate store", __func__); + return -1; + } ++ SSL_CTX_set_cert_store(ssl_ctx, store); + + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); + conn->ca_cert_verify = 1; + + if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate " + "chain"); + conn->cert_probe = 1; + conn->ca_cert_verify = 0; + return 0; + } + + if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) { +#ifdef CONFIG_SHA256 + const char *pos = ca_cert + 7; + if (os_strncmp(pos, "server/sha256/", 14) != 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert " + "hash value '%s'", ca_cert); + return -1; + } + pos += 14; + if (os_strlen(pos) != 32 * 2) { + wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 " + "hash length in ca_cert '%s'", ca_cert); + return -1; + } + if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash " + "value in ca_cert '%s'", ca_cert); + return -1; + } + conn->server_cert_only = 1; + wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server " + "certificate match"); + return 0; +#else /* CONFIG_SHA256 */ + wpa_printf(MSG_INFO, "No SHA256 included in the build - " + "cannot validate server certificate hash"); + return -1; +#endif /* CONFIG_SHA256 */ + } + + if (ca_cert_blob) { - X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &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->cert_store, cert)) { ++ if (!X509_STORE_add_cert(SSL_CTX_get_cert_store(ssl_ctx), ++ cert)) { + unsigned long err = ERR_peek_error(); + tls_show_errors(MSG_WARNING, __func__, + "Failed to add ca_cert_blob to " + "certificate store"); + if (ERR_GET_LIB(err) == ERR_LIB_X509 && + ERR_GET_REASON(err) == + X509_R_CERT_ALREADY_IN_HASH_TABLE) { + wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring " + "cert already in hash table error", + __func__); + } else { + X509_free(cert); + return -1; + } + } + X509_free(cert); + wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob " + "to certificate store", __func__); + return 0; + } + ++#ifdef ANDROID ++ if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) { ++ BIO *bio = BIO_from_keystore(&ca_cert[11]); ++ STACK_OF(X509_INFO) *stack = NULL; ++ stack_index_t i; ++ ++ if (bio) { ++ stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL); ++ BIO_free(bio); ++ } ++ if (!stack) ++ return -1; ++ ++ for (i = 0; i < sk_X509_INFO_num(stack); ++i) { ++ X509_INFO *info = sk_X509_INFO_value(stack, i); ++ if (info->x509) { ++ X509_STORE_add_cert(ssl_ctx->cert_store, ++ info->x509); ++ } ++ if (info->crl) { ++ X509_STORE_add_crl(ssl_ctx->cert_store, ++ info->crl); ++ } ++ } ++ sk_X509_INFO_pop_free(stack, X509_INFO_free); ++ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); ++ return 0; ++ } ++#endif /* ANDROID */ ++ +#ifdef CONFIG_NATIVE_WINDOWS + if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) == + 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from " + "system certificate store"); + return 0; + } +#endif /* CONFIG_NATIVE_WINDOWS */ + + if (ca_cert || ca_path) { +#ifndef OPENSSL_NO_STDIO + if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) != + 1) { + tls_show_errors(MSG_WARNING, __func__, + "Failed to load root certificates"); + if (ca_cert && - tls_load_ca_der(ssl_ctx, ca_cert) == 0) { ++ 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(ssl_ctx); ++ tls_get_errors(data); + } +#else /* OPENSSL_NO_STDIO */ + wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", + __func__); + return -1; +#endif /* OPENSSL_NO_STDIO */ + } else { + /* No ca_cert configured - do not try to verify server + * certificate */ + conn->ca_cert_verify = 0; + } + + return 0; +} + + - static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert) ++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) { - X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx); ++ 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 *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) ++ int verify_peer, unsigned int flags, ++ const u8 *session_ctx, size_t session_ctx_len) +{ + static int counter = 0; ++ struct tls_data *data = ssl_ctx; + + if (conn == NULL) + return -1; + + if (verify_peer) { + conn->ca_cert_verify = 1; + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER | + SSL_VERIFY_FAIL_IF_NO_PEER_CERT | + SSL_VERIFY_CLIENT_ONCE, tls_verify_cb); + } else { + conn->ca_cert_verify = 0; + SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL); + } + ++ tls_set_conn_flags(conn->ssl, flags); ++ conn->flags = flags; ++ + SSL_set_accept_state(conn->ssl); + - /* - * Set session id context in order to avoid fatal errors when client - * tries to resume a session. However, set the context to a unique - * value in order to effectively disable session resumption for now - * since not all areas of the server code are ready for it (e.g., - * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS - * handshake). - */ - counter++; - SSL_set_session_id_context(conn->ssl, - (const unsigned char *) &counter, - sizeof(counter)); ++ if (data->tls_session_lifetime == 0) { ++ /* ++ * Set session id context to a unique value to make sure ++ * session resumption cannot be used either through session ++ * caching or TLS ticket extension. ++ */ ++ counter++; ++ SSL_set_session_id_context(conn->ssl, ++ (const unsigned char *) &counter, ++ sizeof(counter)); ++ } else if (session_ctx) { ++ SSL_set_session_id_context(conn->ssl, session_ctx, ++ session_ctx_len); ++ } + + return 0; +} + + +static int tls_connection_client_cert(struct tls_connection *conn, + const char *client_cert, + const u8 *client_cert_blob, + size_t client_cert_blob_len) +{ + if (client_cert == NULL && client_cert_blob == NULL) + return 0; + + if (client_cert_blob && + SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob, + client_cert_blob_len) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> " + "OK"); + return 0; + } else if (client_cert_blob) { + tls_show_errors(MSG_DEBUG, __func__, + "SSL_use_certificate_ASN1 failed"); + } + + if (client_cert == NULL) + return -1; + ++#ifdef ANDROID ++ if (os_strncmp("keystore://", client_cert, 11) == 0) { ++ BIO *bio = BIO_from_keystore(&client_cert[11]); ++ X509 *x509 = NULL; ++ int ret = -1; ++ if (bio) { ++ x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL); ++ BIO_free(bio); ++ } ++ if (x509) { ++ if (SSL_use_certificate(conn->ssl, x509) == 1) ++ ret = 0; ++ X509_free(x509); ++ } ++ return ret; ++ } ++#endif /* ANDROID */ ++ +#ifndef OPENSSL_NO_STDIO + if (SSL_use_certificate_file(conn->ssl, client_cert, + SSL_FILETYPE_ASN1) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)" + " --> OK"); + return 0; - } else { - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_certificate_file (DER) failed"); + } + + if (SSL_use_certificate_file(conn->ssl, client_cert, + SSL_FILETYPE_PEM) == 1) { ++ ERR_clear_error(); + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)" + " --> OK"); + return 0; - } else { - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_certificate_file (PEM) failed"); + } ++ ++ 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(SSL_CTX *ssl_ctx, const char *client_cert) ++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(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12, ++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(ssl_ctx, cert) != 1) ++ if (SSL_CTX_use_certificate(data->ssl, cert) != 1) + res = -1; + } + X509_free(cert); + } + + if (pkey) { + wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12"); + if (ssl) { + if (SSL_use_PrivateKey(ssl, pkey) != 1) + res = -1; + } else { - if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1) ++ if (SSL_CTX_use_PrivateKey(data->ssl, pkey) != 1) + res = -1; + } + EVP_PKEY_free(pkey); + } + + if (certs) { ++#if OPENSSL_VERSION_NUMBER >= 0x10002000L ++ SSL_clear_chain_certs(ssl); ++ while ((cert = sk_X509_pop(certs)) != NULL) { ++ X509_NAME_oneline(X509_get_subject_name(cert), buf, ++ sizeof(buf)); ++ wpa_printf(MSG_DEBUG, "TLS: additional certificate" ++ " from PKCS12: subject='%s'", buf); ++ if (SSL_add1_chain_cert(ssl, cert) != 1) { ++ tls_show_errors(MSG_DEBUG, __func__, ++ "Failed to add additional certificate"); ++ res = -1; ++ break; ++ } ++ } ++ if (!res) { ++ /* Try to continue anyway */ ++ } ++ sk_X509_free(certs); ++#ifndef OPENSSL_IS_BORINGSSL ++ res = SSL_build_cert_chain(ssl, ++ SSL_BUILD_CHAIN_FLAG_CHECK | ++ SSL_BUILD_CHAIN_FLAG_IGNORE_ERROR); ++ if (!res) { ++ tls_show_errors(MSG_DEBUG, __func__, ++ "Failed to build certificate chain"); ++ } else if (res == 2) { ++ wpa_printf(MSG_DEBUG, ++ "TLS: Ignore certificate chain verification error when building chain with PKCS#12 extra certificates"); ++ } ++#endif /* OPENSSL_IS_BORINGSSL */ ++ /* ++ * Try to continue regardless of result since it is possible for ++ * the extra certificates not to be required. ++ */ ++ res = 0; ++#else /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ ++#if OPENSSL_VERSION_NUMBER >= 0x10001000L ++ SSL_CTX_clear_extra_chain_certs(data->ssl); ++#endif /* OPENSSL_VERSION_NUMBER >= 0x10001000L */ + while ((cert = sk_X509_pop(certs)) != NULL) { + X509_NAME_oneline(X509_get_subject_name(cert), buf, + sizeof(buf)); + wpa_printf(MSG_DEBUG, "TLS: additional certificate" + " from PKCS12: subject='%s'", buf); + /* + * There is no SSL equivalent for the chain cert - so + * always add it to the context... + */ - if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) { ++ if (SSL_CTX_add_extra_chain_cert(data->ssl, cert) != 1) ++ { + res = -1; + break; + } + } + sk_X509_free(certs); ++#endif /* OPENSSL_VERSION_NUMBER >= 0x10002000L */ + } + + PKCS12_free(p12); + + if (res < 0) - tls_get_errors(ssl_ctx); ++ tls_get_errors(data); + + return res; +} +#endif /* PKCS12_FUNCS */ + + - static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key, - const char *passwd) ++static int tls_read_pkcs12(struct tls_data *data, SSL *ssl, ++ const char *private_key, const char *passwd) +{ +#ifdef PKCS12_FUNCS + FILE *f; + PKCS12 *p12; + + f = fopen(private_key, "rb"); + if (f == NULL) + return -1; + + p12 = d2i_PKCS12_fp(f, NULL); + fclose(f); + + if (p12 == NULL) { + tls_show_errors(MSG_INFO, __func__, + "Failed to use PKCS#12 file"); + return -1; + } + - return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd); ++ 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(SSL_CTX *ssl_ctx, SSL *ssl, ++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, (OPENSSL_d2i_TYPE) &blob, len); ++ 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(ssl_ctx, ssl, p12, passwd); ++ 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, ¶ms, 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_get_error(), NULL)); ++ 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(void *_ssl_ctx, ++static int tls_connection_engine_ca_cert(struct tls_data *data, + struct tls_connection *conn, + const char *ca_cert_id) +{ +#ifndef OPENSSL_NO_ENGINE + X509 *cert; - SSL_CTX *ssl_ctx = _ssl_ctx; ++ 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 */ - X509_STORE_free(ssl_ctx->cert_store); - ssl_ctx->cert_store = X509_STORE_new(); - if (ssl_ctx->cert_store == NULL) { ++ 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; + } - if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) { ++ SSL_CTX_set_cert_store(ssl_ctx, store); ++ if (!X509_STORE_add_cert(store, cert)) { + unsigned long err = ERR_peek_error(); + tls_show_errors(MSG_WARNING, __func__, + "Failed to add CA certificate from engine " + "to certificate store"); + if (ERR_GET_LIB(err) == ERR_LIB_X509 && + ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) { + wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert" + " already in hash table error", + __func__); + } else { + X509_free(cert); + return -1; + } + } + X509_free(cert); + wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine " + "to certificate store", __func__); + SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb); ++ conn->ca_cert_verify = 1; ++ + return 0; + +#else /* OPENSSL_NO_ENGINE */ + return -1; +#endif /* OPENSSL_NO_ENGINE */ +} + + +static int tls_connection_engine_private_key(struct tls_connection *conn) +{ +#ifndef OPENSSL_NO_ENGINE + if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) { + tls_show_errors(MSG_ERROR, __func__, + "ENGINE: cannot use private key for TLS"); + return -1; + } + if (!SSL_check_private_key(conn->ssl)) { + tls_show_errors(MSG_INFO, __func__, + "Private key failed verification"); + return -1; + } + return 0; +#else /* OPENSSL_NO_ENGINE */ + wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but " + "engine support was not compiled in"); + return -1; +#endif /* OPENSSL_NO_ENGINE */ +} + + - static int tls_connection_private_key(void *_ssl_ctx, ++static int tls_connection_private_key(struct tls_data *data, + struct tls_connection *conn, + const char *private_key, + const char *private_key_passwd, + const u8 *private_key_blob, + size_t private_key_blob_len) +{ - SSL_CTX *ssl_ctx = _ssl_ctx; ++ SSL_CTX *ssl_ctx = data->ssl; + char *passwd; + int ok; + + if (private_key == NULL && private_key_blob == NULL) + return 0; + + if (private_key_passwd) { + passwd = os_strdup(private_key_passwd); + if (passwd == NULL) + return -1; + } else + passwd = NULL; + + SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb); + SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd); + + ok = 0; + while (private_key_blob) { + if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl, + (u8 *) private_key_blob, + private_key_blob_len) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" + "ASN1(EVP_PKEY_RSA) --> OK"); + ok = 1; + break; - } else { - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)" - " failed"); + } + + if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl, + (u8 *) private_key_blob, + private_key_blob_len) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_" + "ASN1(EVP_PKEY_DSA) --> OK"); + ok = 1; + break; - } else { - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)" - " failed"); + } + + if (SSL_use_RSAPrivateKey_ASN1(conn->ssl, + (u8 *) private_key_blob, + private_key_blob_len) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: " + "SSL_use_RSAPrivateKey_ASN1 --> OK"); + ok = 1; + break; - } else { - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_RSAPrivateKey_ASN1 failed"); + } + - if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob, ++ if (tls_read_pkcs12_blob(data, conn->ssl, private_key_blob, + private_key_blob_len, passwd) == 0) { + wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> " + "OK"); + ok = 1; + break; + } + + break; + } + + while (!ok && private_key) { +#ifndef OPENSSL_NO_STDIO + if (SSL_use_PrivateKey_file(conn->ssl, private_key, + SSL_FILETYPE_ASN1) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: " + "SSL_use_PrivateKey_File (DER) --> OK"); + ok = 1; + break; - } else { - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_PrivateKey_File (DER) " - "failed"); + } + + if (SSL_use_PrivateKey_file(conn->ssl, private_key, + SSL_FILETYPE_PEM) == 1) { + wpa_printf(MSG_DEBUG, "OpenSSL: " + "SSL_use_PrivateKey_File (PEM) --> OK"); + ok = 1; + break; - } else { - tls_show_errors(MSG_DEBUG, __func__, - "SSL_use_PrivateKey_File (PEM) " - "failed"); + } +#else /* OPENSSL_NO_STDIO */ + wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", + __func__); +#endif /* OPENSSL_NO_STDIO */ + - if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd) ++ 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) { - wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key"); ++ tls_show_errors(MSG_INFO, __func__, ++ "Failed to load private key"); + os_free(passwd); - ERR_clear_error(); + 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(SSL_CTX *ssl_ctx, const char *private_key, ++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(ssl_ctx, NULL, private_key, passwd)) { ++ 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(SSL_CTX *ssl_ctx, const char *dh_file) ++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_keys(void *ssl_ctx, struct tls_connection *conn, - struct tls_keys *keys) ++int tls_connection_get_random(void *ssl_ctx, struct tls_connection *conn, ++ struct tls_random *keys) +{ + SSL *ssl; + + if (conn == NULL || keys == NULL) + return -1; + ssl = conn->ssl; ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL) + return -1; + + os_memset(keys, 0, sizeof(*keys)); - keys->master_key = ssl->session->master_key; - keys->master_key_len = ssl->session->master_key_length; + keys->client_random = ssl->s3->client_random; + keys->client_random_len = SSL3_RANDOM_SIZE; + keys->server_random = ssl->s3->server_random; + keys->server_random_len = SSL3_RANDOM_SIZE; ++#else ++ if (ssl == NULL) ++ return -1; ++ ++ os_memset(keys, 0, sizeof(*keys)); ++ keys->client_random = conn->client_random; ++ keys->client_random_len = SSL_get_client_random( ++ ssl, conn->client_random, sizeof(conn->client_random)); ++ keys->server_random = conn->server_random; ++ keys->server_random_len = SSL_get_server_random( ++ ssl, conn->server_random, sizeof(conn->server_random)); ++#endif + + return 0; +} + + ++#ifndef CONFIG_FIPS ++static int openssl_get_keyblock_size(SSL *ssl) ++{ ++#if OPENSSL_VERSION_NUMBER < 0x10100000L ++ const EVP_CIPHER *c; ++ const EVP_MD *h; ++ int md_size; ++ ++ if (ssl->enc_read_ctx == NULL || ssl->enc_read_ctx->cipher == NULL || ++ ssl->read_hash == NULL) ++ return -1; ++ ++ c = ssl->enc_read_ctx->cipher; ++#if OPENSSL_VERSION_NUMBER >= 0x00909000L ++ h = EVP_MD_CTX_md(ssl->read_hash); ++#else ++ h = ssl->read_hash; ++#endif ++ if (h) ++ md_size = EVP_MD_size(h); ++#if OPENSSL_VERSION_NUMBER >= 0x10000000L ++ else if (ssl->s3) ++ md_size = ssl->s3->tmp.new_mac_secret_size; ++#endif ++ else ++ return -1; ++ ++ wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d " ++ "IV_len=%d", EVP_CIPHER_key_length(c), md_size, ++ EVP_CIPHER_iv_length(c)); ++ return 2 * (EVP_CIPHER_key_length(c) + ++ md_size + ++ EVP_CIPHER_iv_length(c)); ++#else ++ const SSL_CIPHER *ssl_cipher; ++ int cipher, digest; ++ const EVP_CIPHER *c; ++ const EVP_MD *h; ++ ++ ssl_cipher = SSL_get_current_cipher(ssl); ++ if (!ssl_cipher) ++ return -1; ++ cipher = SSL_CIPHER_get_cipher_nid(ssl_cipher); ++ digest = SSL_CIPHER_get_digest_nid(ssl_cipher); ++ wpa_printf(MSG_DEBUG, "OpenSSL: cipher nid %d digest nid %d", ++ cipher, digest); ++ if (cipher < 0 || digest < 0) ++ return -1; ++ c = EVP_get_cipherbynid(cipher); ++ h = EVP_get_digestbynid(digest); ++ if (!c || !h) ++ return -1; ++ ++ wpa_printf(MSG_DEBUG, ++ "OpenSSL: keyblock size: key_len=%d MD_size=%d IV_len=%d", ++ EVP_CIPHER_key_length(c), EVP_MD_size(h), ++ EVP_CIPHER_iv_length(c)); ++ return 2 * (EVP_CIPHER_key_length(c) + EVP_MD_size(h) + ++ EVP_CIPHER_iv_length(c)); ++#endif ++} ++#endif /* CONFIG_FIPS */ ++ ++ ++static int openssl_tls_prf(struct tls_connection *conn, ++ const char *label, int server_random_first, ++ int skip_keyblock, u8 *out, size_t out_len) ++{ ++#ifdef CONFIG_FIPS ++ wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS " ++ "mode"); ++ return -1; ++#else /* CONFIG_FIPS */ ++#if OPENSSL_VERSION_NUMBER < 0x10100000L ++ SSL *ssl; ++ u8 *rnd; ++ int ret = -1; ++ int skip = 0; ++ u8 *tmp_out = NULL; ++ u8 *_out = out; ++ const char *ver; ++ ++ /* ++ * TLS library did not support key generation, so get the needed TLS ++ * session parameters and use an internal implementation of TLS PRF to ++ * derive the key. ++ */ ++ ++ if (conn == NULL) ++ return -1; ++ ssl = conn->ssl; ++ if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL || ++ ssl->session->master_key_length <= 0) ++ return -1; ++ ver = SSL_get_version(ssl); ++ ++ if (skip_keyblock) { ++ skip = openssl_get_keyblock_size(ssl); ++ if (skip < 0) ++ return -1; ++ tmp_out = os_malloc(skip + out_len); ++ if (!tmp_out) ++ return -1; ++ _out = tmp_out; ++ } ++ ++ rnd = os_malloc(2 * SSL3_RANDOM_SIZE); ++ if (!rnd) { ++ os_free(tmp_out); ++ return -1; ++ } ++ ++ if (server_random_first) { ++ os_memcpy(rnd, ssl->s3->server_random, SSL3_RANDOM_SIZE); ++ os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->client_random, ++ SSL3_RANDOM_SIZE); ++ } else { ++ os_memcpy(rnd, ssl->s3->client_random, SSL3_RANDOM_SIZE); ++ os_memcpy(rnd + SSL3_RANDOM_SIZE, ssl->s3->server_random, ++ SSL3_RANDOM_SIZE); ++ } ++ ++ if (os_strcmp(ver, "TLSv1.2") == 0) { ++ tls_prf_sha256(ssl->session->master_key, ++ ssl->session->master_key_length, ++ label, rnd, 2 * SSL3_RANDOM_SIZE, ++ _out, skip + out_len); ++ ret = 0; ++ } else if (tls_prf_sha1_md5(ssl->session->master_key, ++ ssl->session->master_key_length, ++ label, rnd, 2 * SSL3_RANDOM_SIZE, ++ _out, skip + out_len) == 0) { ++ ret = 0; ++ } ++ os_free(rnd); ++ if (ret == 0 && skip_keyblock) ++ os_memcpy(out, _out + skip, out_len); ++ bin_clear_free(tmp_out, skip); ++ ++ return ret; ++#else ++ SSL *ssl; ++ SSL_SESSION *sess; ++ u8 *rnd; ++ int ret = -1; ++ int skip = 0; ++ u8 *tmp_out = NULL; ++ u8 *_out = out; ++ unsigned char client_random[SSL3_RANDOM_SIZE]; ++ unsigned char server_random[SSL3_RANDOM_SIZE]; ++ unsigned char master_key[64]; ++ size_t master_key_len; ++ const char *ver; ++ ++ /* ++ * TLS library did not support key generation, so get the needed TLS ++ * session parameters and use an internal implementation of TLS PRF to ++ * derive the key. ++ */ ++ ++ if (conn == NULL) ++ return -1; ++ ssl = conn->ssl; ++ if (ssl == NULL) ++ return -1; ++ ver = SSL_get_version(ssl); ++ sess = SSL_get_session(ssl); ++ if (!ver || !sess) ++ return -1; ++ ++ if (skip_keyblock) { ++ skip = openssl_get_keyblock_size(ssl); ++ if (skip < 0) ++ return -1; ++ tmp_out = os_malloc(skip + out_len); ++ if (!tmp_out) ++ return -1; ++ _out = tmp_out; ++ } ++ ++ rnd = os_malloc(2 * SSL3_RANDOM_SIZE); ++ if (!rnd) { ++ os_free(tmp_out); ++ return -1; ++ } ++ ++ SSL_get_client_random(ssl, client_random, sizeof(client_random)); ++ SSL_get_server_random(ssl, server_random, sizeof(server_random)); ++ master_key_len = SSL_SESSION_get_master_key(sess, master_key, ++ sizeof(master_key)); ++ ++ if (server_random_first) { ++ os_memcpy(rnd, server_random, SSL3_RANDOM_SIZE); ++ os_memcpy(rnd + SSL3_RANDOM_SIZE, client_random, ++ SSL3_RANDOM_SIZE); ++ } else { ++ os_memcpy(rnd, client_random, SSL3_RANDOM_SIZE); ++ os_memcpy(rnd + SSL3_RANDOM_SIZE, server_random, ++ SSL3_RANDOM_SIZE); ++ } ++ ++ if (os_strcmp(ver, "TLSv1.2") == 0) { ++ tls_prf_sha256(master_key, master_key_len, ++ label, rnd, 2 * SSL3_RANDOM_SIZE, ++ _out, skip + out_len); ++ ret = 0; ++ } else if (tls_prf_sha1_md5(master_key, master_key_len, ++ label, rnd, 2 * SSL3_RANDOM_SIZE, ++ _out, skip + out_len) == 0) { ++ ret = 0; ++ } ++ os_memset(master_key, 0, sizeof(master_key)); ++ os_free(rnd); ++ if (ret == 0 && skip_keyblock) ++ os_memcpy(out, _out + skip, out_len); ++ bin_clear_free(tmp_out, skip); ++ ++ return ret; ++#endif ++#endif /* CONFIG_FIPS */ ++} ++ ++ +int tls_connection_prf(void *tls_ctx, struct tls_connection *conn, + const char *label, int server_random_first, - u8 *out, size_t out_len) ++ int skip_keyblock, u8 *out, size_t out_len) +{ - return -1; ++#if OPENSSL_VERSION_NUMBER >= 0x10001000L ++ SSL *ssl; ++ if (conn == NULL) ++ return -1; ++ if (server_random_first || skip_keyblock) ++ return openssl_tls_prf(conn, label, ++ server_random_first, skip_keyblock, ++ out, out_len); ++ ssl = conn->ssl; ++ if (SSL_export_keying_material(ssl, out, out_len, label, ++ os_strlen(label), NULL, 0, 0) == 1) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF"); ++ return 0; ++ } ++#endif ++ return openssl_tls_prf(conn, label, server_random_first, ++ skip_keyblock, out, out_len); +} + + +static struct wpabuf * +openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data, + int server) +{ + int res; + struct wpabuf *out_data; + + /* + * Give TLS handshake data from the server (if available) to OpenSSL + * for processing. + */ - if (in_data && ++ if (in_data && wpabuf_len(in_data) > 0 && + BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data)) + < 0) { + tls_show_errors(MSG_INFO, __func__, + "Handshake failed - BIO_write"); + return NULL; + } + + /* Initiate TLS handshake or continue the existing handshake */ + if (server) + res = SSL_accept(conn->ssl); + else + res = SSL_connect(conn->ssl); + if (res != 1) { + int err = SSL_get_error(conn->ssl, res); + if (err == SSL_ERROR_WANT_READ) + wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want " + "more data"); + else if (err == SSL_ERROR_WANT_WRITE) + wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to " + "write"); + else { + tls_show_errors(MSG_INFO, __func__, "SSL_connect"); + conn->failed++; + } + } + + /* Get the TLS handshake data to be sent to the server */ + res = BIO_ctrl_pending(conn->ssl_out); + wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res); + out_data = wpabuf_alloc(res); + if (out_data == NULL) { + wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for " + "handshake output (%d bytes)", res); + if (BIO_reset(conn->ssl_out) < 0) { + tls_show_errors(MSG_INFO, __func__, + "BIO_reset failed"); + } + return NULL; + } + res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data), + res); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Handshake failed - BIO_read"); + if (BIO_reset(conn->ssl_out) < 0) { + tls_show_errors(MSG_INFO, __func__, + "BIO_reset failed"); + } + wpabuf_free(out_data); + return NULL; + } + wpabuf_put(out_data, res); + + return out_data; +} + + +static struct wpabuf * +openssl_get_appl_data(struct tls_connection *conn, size_t max_len) +{ + struct wpabuf *appl_data; + int res; + + appl_data = wpabuf_alloc(max_len + 100); + if (appl_data == NULL) + return NULL; + + res = SSL_read(conn->ssl, wpabuf_mhead(appl_data), + wpabuf_size(appl_data)); + if (res < 0) { + int err = SSL_get_error(conn->ssl, res); + if (err == SSL_ERROR_WANT_READ || + err == SSL_ERROR_WANT_WRITE) { + wpa_printf(MSG_DEBUG, "SSL: No Application Data " + "included"); + } else { + tls_show_errors(MSG_INFO, __func__, + "Failed to read possible " + "Application Data"); + } + wpabuf_free(appl_data); + return NULL; + } + + wpabuf_put(appl_data, res); + wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished " + "message", appl_data); + + return appl_data; +} + + +static struct wpabuf * +openssl_connection_handshake(struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data, int server) +{ + struct wpabuf *out_data; + + if (appl_data) + *appl_data = NULL; + + out_data = openssl_handshake(conn, in_data, server); + if (out_data == NULL) + return NULL; ++ if (conn->invalid_hb_used) { ++ wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response"); ++ wpabuf_free(out_data); ++ return NULL; ++ } + - if (SSL_is_init_finished(conn->ssl) && appl_data && in_data) - *appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data)); ++ if (SSL_is_init_finished(conn->ssl)) { ++ wpa_printf(MSG_DEBUG, ++ "OpenSSL: Handshake finished - resumed=%d", ++ tls_connection_resumed(conn->ssl_ctx, conn)); ++ if (appl_data && in_data) ++ *appl_data = openssl_get_appl_data(conn, ++ wpabuf_len(in_data)); ++ } ++ ++ if (conn->invalid_hb_used) { ++ wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response"); ++ if (appl_data) { ++ wpabuf_free(*appl_data); ++ *appl_data = NULL; ++ } ++ wpabuf_free(out_data); ++ return NULL; ++ } + + return out_data; +} + + +struct wpabuf * +tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return openssl_connection_handshake(conn, in_data, appl_data, 0); +} + + +struct wpabuf * tls_connection_server_handshake(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data, + struct wpabuf **appl_data) +{ + return openssl_connection_handshake(conn, in_data, appl_data, 1); +} + + +struct wpabuf * tls_connection_encrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) +{ + int res; + struct wpabuf *buf; + + if (conn == NULL) + return NULL; + + /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */ + if ((res = BIO_reset(conn->ssl_in)) < 0 || + (res = BIO_reset(conn->ssl_out)) < 0) { + tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); + return NULL; + } + res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data)); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Encryption failed - SSL_write"); + return NULL; + } + + /* Read encrypted data to be sent to the server */ + buf = wpabuf_alloc(wpabuf_len(in_data) + 300); + if (buf == NULL) + return NULL; + res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf)); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Encryption failed - BIO_read"); + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + + return buf; +} + + +struct wpabuf * tls_connection_decrypt(void *tls_ctx, + struct tls_connection *conn, + const struct wpabuf *in_data) +{ + int res; + struct wpabuf *buf; + + /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */ + res = BIO_write(conn->ssl_in, wpabuf_head(in_data), + wpabuf_len(in_data)); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Decryption failed - BIO_write"); + return NULL; + } + if (BIO_reset(conn->ssl_out) < 0) { + tls_show_errors(MSG_INFO, __func__, "BIO_reset failed"); + return NULL; + } + + /* Read decrypted data for further processing */ + /* + * Even though we try to disable TLS compression, it is possible that + * this cannot be done with all TLS libraries. Add extra buffer space + * to handle the possibility of the decrypted data being longer than + * input data. + */ + buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3); + if (buf == NULL) + return NULL; + res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf)); + if (res < 0) { + tls_show_errors(MSG_INFO, __func__, + "Decryption failed - SSL_read"); + wpabuf_free(buf); + return NULL; + } + wpabuf_put(buf, res); + ++ if (conn->invalid_hb_used) { ++ wpa_printf(MSG_INFO, "TLS: Heartbeat attack detected - do not send response"); ++ wpabuf_free(buf); ++ return NULL; ++ } ++ + return buf; +} + + +int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn) +{ ++#if OPENSSL_VERSION_NUMBER >= 0x10001000L ++ return conn ? SSL_cache_hit(conn->ssl) : 0; ++#else + return conn ? conn->ssl->hit : 0; ++#endif +} + + +int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn, + u8 *ciphers) +{ + char buf[100], *pos, *end; + u8 *c; + int ret; + + if (conn == NULL || conn->ssl == NULL || ciphers == NULL) + return -1; + + buf[0] = '\0'; + pos = buf; + end = pos + sizeof(buf); + + c = ciphers; + while (*c != TLS_CIPHER_NONE) { + const char *suite; + + switch (*c) { + case TLS_CIPHER_RC4_SHA: + suite = "RC4-SHA"; + break; + case TLS_CIPHER_AES128_SHA: + suite = "AES128-SHA"; + break; + case TLS_CIPHER_RSA_DHE_AES128_SHA: + suite = "DHE-RSA-AES128-SHA"; + break; + case TLS_CIPHER_ANON_DH_AES128_SHA: + suite = "ADH-AES128-SHA"; + break; + default: + wpa_printf(MSG_DEBUG, "TLS: Unsupported " + "cipher selection: %d", *c); + return -1; + } + ret = os_snprintf(pos, end - pos, ":%s", suite); - if (ret < 0 || ret >= end - pos) ++ if (os_snprintf_error(end - pos, ret)) + break; + pos += ret; + + c++; + } + + wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1); + ++#if OPENSSL_VERSION_NUMBER >= 0x10100000L ++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) ++ if (os_strstr(buf, ":ADH-")) { ++ /* ++ * Need to drop to security level 0 to allow anonymous ++ * cipher suites for EAP-FAST. ++ */ ++ SSL_set_security_level(conn->ssl, 0); ++ } else if (SSL_get_security_level(conn->ssl) == 0) { ++ /* Force at least security level 1 */ ++ SSL_set_security_level(conn->ssl, 1); ++ } ++#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ ++#endif ++ + if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) { + tls_show_errors(MSG_INFO, __func__, + "Cipher suite configuration failed"); + return -1; + } + + return 0; +} + + ++int tls_get_version(void *ssl_ctx, struct tls_connection *conn, ++ char *buf, size_t buflen) ++{ ++ const char *name; ++ if (conn == NULL || conn->ssl == NULL) ++ return -1; ++ ++ name = SSL_get_version(conn->ssl); ++ if (name == NULL) ++ return -1; ++ ++ os_strlcpy(buf, name, buflen); ++ return 0; ++} ++ ++ +int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn, + char *buf, size_t buflen) +{ + const char *name; + if (conn == NULL || conn->ssl == NULL) + return -1; + + name = SSL_get_cipher(conn->ssl); + if (name == NULL) + return -1; + + os_strlcpy(buf, name, buflen); + return 0; +} + + +int tls_connection_enable_workaround(void *ssl_ctx, + struct tls_connection *conn) +{ + SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS); + + return 0; +} + + +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) +/* ClientHello TLS extensions require a patch to openssl, so this function is + * commented out unless explicitly needed for EAP-FAST in order to be able to + * build this file with unmodified openssl. */ +int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn, + int ext_type, const u8 *data, + size_t data_len) +{ + if (conn == NULL || conn->ssl == NULL || ext_type != 35) + return -1; + - #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE + if (SSL_set_session_ticket_ext(conn->ssl, (void *) data, + data_len) != 1) + return -1; - #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ - if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data, - data_len) != 1) - return -1; - #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ + + return 0; +} +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ + + +int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + return conn->failed; +} + + +int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + return conn->read_alerts; +} + + +int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn) +{ + if (conn == NULL) + return -1; + return conn->write_alerts; +} + + ++#ifdef HAVE_OCSP ++ ++static void ocsp_debug_print_resp(OCSP_RESPONSE *rsp) ++{ ++#ifndef CONFIG_NO_STDOUT_DEBUG ++ BIO *out; ++ size_t rlen; ++ char *txt; ++ int res; ++ ++ if (wpa_debug_level > MSG_DEBUG) ++ return; ++ ++ out = BIO_new(BIO_s_mem()); ++ if (!out) ++ return; ++ ++ OCSP_RESPONSE_print(out, rsp, 0); ++ rlen = BIO_ctrl_pending(out); ++ txt = os_malloc(rlen + 1); ++ if (!txt) { ++ BIO_free(out); ++ return; ++ } ++ ++ res = BIO_read(out, txt, rlen); ++ if (res > 0) { ++ txt[res] = '\0'; ++ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP Response\n%s", txt); ++ } ++ os_free(txt); ++ BIO_free(out); ++#endif /* CONFIG_NO_STDOUT_DEBUG */ ++} ++ ++ ++static void debug_print_cert(X509 *cert, const char *title) ++{ ++#ifndef CONFIG_NO_STDOUT_DEBUG ++ BIO *out; ++ size_t rlen; ++ char *txt; ++ int res; ++ ++ if (wpa_debug_level > MSG_DEBUG) ++ return; ++ ++ out = BIO_new(BIO_s_mem()); ++ if (!out) ++ return; ++ ++ X509_print(out, cert); ++ rlen = BIO_ctrl_pending(out); ++ txt = os_malloc(rlen + 1); ++ if (!txt) { ++ BIO_free(out); ++ return; ++ } ++ ++ res = BIO_read(out, txt, rlen); ++ if (res > 0) { ++ txt[res] = '\0'; ++ wpa_printf(MSG_DEBUG, "OpenSSL: %s\n%s", title, txt); ++ } ++ os_free(txt); ++ ++ BIO_free(out); ++#endif /* CONFIG_NO_STDOUT_DEBUG */ ++} ++ ++ ++static int ocsp_resp_cb(SSL *s, void *arg) ++{ ++ struct tls_connection *conn = arg; ++ const unsigned char *p; ++ int len, status, reason; ++ OCSP_RESPONSE *rsp; ++ OCSP_BASICRESP *basic; ++ OCSP_CERTID *id; ++ ASN1_GENERALIZEDTIME *produced_at, *this_update, *next_update; ++ X509_STORE *store; ++ STACK_OF(X509) *certs = NULL; ++ ++ len = SSL_get_tlsext_status_ocsp_resp(s, &p); ++ if (!p) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: No OCSP response received"); ++ return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; ++ } ++ ++ wpa_hexdump(MSG_DEBUG, "OpenSSL: OCSP response", p, len); ++ ++ rsp = d2i_OCSP_RESPONSE(NULL, &p, len); ++ if (!rsp) { ++ wpa_printf(MSG_INFO, "OpenSSL: Failed to parse OCSP response"); ++ return 0; ++ } ++ ++ ocsp_debug_print_resp(rsp); ++ ++ status = OCSP_response_status(rsp); ++ if (status != OCSP_RESPONSE_STATUS_SUCCESSFUL) { ++ wpa_printf(MSG_INFO, "OpenSSL: OCSP responder error %d (%s)", ++ status, OCSP_response_status_str(status)); ++ return 0; ++ } ++ ++ basic = OCSP_response_get1_basic(rsp); ++ if (!basic) { ++ wpa_printf(MSG_INFO, "OpenSSL: Could not find BasicOCSPResponse"); ++ return 0; ++ } ++ ++ store = SSL_CTX_get_cert_store(conn->ssl_ctx); ++ if (conn->peer_issuer) { ++ debug_print_cert(conn->peer_issuer, "Add OCSP issuer"); ++ ++ if (X509_STORE_add_cert(store, conn->peer_issuer) != 1) { ++ tls_show_errors(MSG_INFO, __func__, ++ "OpenSSL: Could not add issuer to certificate store"); ++ } ++ certs = sk_X509_new_null(); ++ if (certs) { ++ X509 *cert; ++ cert = X509_dup(conn->peer_issuer); ++ if (cert && !sk_X509_push(certs, cert)) { ++ tls_show_errors( ++ MSG_INFO, __func__, ++ "OpenSSL: Could not add issuer to OCSP responder trust store"); ++ X509_free(cert); ++ sk_X509_free(certs); ++ certs = NULL; ++ } ++ if (certs && conn->peer_issuer_issuer) { ++ cert = X509_dup(conn->peer_issuer_issuer); ++ if (cert && !sk_X509_push(certs, cert)) { ++ tls_show_errors( ++ MSG_INFO, __func__, ++ "OpenSSL: Could not add issuer's issuer to OCSP responder trust store"); ++ X509_free(cert); ++ } ++ } ++ } ++ } ++ ++ status = OCSP_basic_verify(basic, certs, store, OCSP_TRUSTOTHER); ++ sk_X509_pop_free(certs, X509_free); ++ if (status <= 0) { ++ tls_show_errors(MSG_INFO, __func__, ++ "OpenSSL: OCSP response failed verification"); ++ OCSP_BASICRESP_free(basic); ++ OCSP_RESPONSE_free(rsp); ++ return 0; ++ } ++ ++ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP response verification succeeded"); ++ ++ if (!conn->peer_cert) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: Peer certificate not available for OCSP status check"); ++ OCSP_BASICRESP_free(basic); ++ OCSP_RESPONSE_free(rsp); ++ return 0; ++ } ++ ++ if (!conn->peer_issuer) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: Peer issuer certificate not available for OCSP status check"); ++ OCSP_BASICRESP_free(basic); ++ OCSP_RESPONSE_free(rsp); ++ return 0; ++ } ++ ++ id = OCSP_cert_to_id(NULL, conn->peer_cert, conn->peer_issuer); ++ if (!id) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: Could not create OCSP certificate identifier"); ++ OCSP_BASICRESP_free(basic); ++ OCSP_RESPONSE_free(rsp); ++ return 0; ++ } ++ ++ if (!OCSP_resp_find_status(basic, id, &status, &reason, &produced_at, ++ &this_update, &next_update)) { ++ wpa_printf(MSG_INFO, "OpenSSL: Could not find current server certificate from OCSP response%s", ++ (conn->flags & TLS_CONN_REQUIRE_OCSP) ? "" : ++ " (OCSP not required)"); ++ OCSP_BASICRESP_free(basic); ++ OCSP_RESPONSE_free(rsp); ++ return (conn->flags & TLS_CONN_REQUIRE_OCSP) ? 0 : 1; ++ } ++ ++ if (!OCSP_check_validity(this_update, next_update, 5 * 60, -1)) { ++ tls_show_errors(MSG_INFO, __func__, ++ "OpenSSL: OCSP status times invalid"); ++ OCSP_BASICRESP_free(basic); ++ OCSP_RESPONSE_free(rsp); ++ return 0; ++ } ++ ++ OCSP_BASICRESP_free(basic); ++ OCSP_RESPONSE_free(rsp); ++ ++ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status for server certificate: %s", ++ OCSP_cert_status_str(status)); ++ ++ if (status == V_OCSP_CERTSTATUS_GOOD) ++ return 1; ++ if (status == V_OCSP_CERTSTATUS_REVOKED) ++ return 0; ++ if (conn->flags & TLS_CONN_REQUIRE_OCSP) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP required"); ++ return 0; ++ } ++ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status unknown, but OCSP was not required, so allow connection to continue"); ++ return 1; ++} ++ ++ ++static int ocsp_status_cb(SSL *s, void *arg) ++{ ++ char *tmp; ++ char *resp; ++ size_t len; ++ ++ if (tls_global->ocsp_stapling_response == NULL) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - no response configured"); ++ return SSL_TLSEXT_ERR_OK; ++ } ++ ++ resp = os_readfile(tls_global->ocsp_stapling_response, &len); ++ if (resp == NULL) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - could not read response file"); ++ /* TODO: Build OCSPResponse with responseStatus = internalError ++ */ ++ return SSL_TLSEXT_ERR_OK; ++ } ++ wpa_printf(MSG_DEBUG, "OpenSSL: OCSP status callback - send cached response"); ++ tmp = OPENSSL_malloc(len); ++ if (tmp == NULL) { ++ os_free(resp); ++ return SSL_TLSEXT_ERR_ALERT_FATAL; ++ } ++ ++ os_memcpy(tmp, resp, len); ++ os_free(resp); ++ SSL_set_tlsext_status_ocsp_resp(s, tmp, len); ++ ++ return SSL_TLSEXT_ERR_OK; ++} ++ ++#endif /* HAVE_OCSP */ ++ ++ +int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn, + const struct tls_connection_params *params) +{ ++ struct tls_data *data = tls_ctx; + int ret; + unsigned long err; ++ int can_pkcs11 = 0; ++ const char *key_id = params->key_id; ++ const char *cert_id = params->cert_id; ++ const char *ca_cert_id = params->ca_cert_id; ++ const char *engine_id = params->engine ? params->engine_id : NULL; + + if (conn == NULL) + return -1; + ++ /* ++ * If the engine isn't explicitly configured, and any of the ++ * cert/key fields are actually PKCS#11 URIs, then automatically ++ * use the PKCS#11 ENGINE. ++ */ ++ if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0) ++ can_pkcs11 = 1; ++ ++ if (!key_id && params->private_key && can_pkcs11 && ++ os_strncmp(params->private_key, "pkcs11:", 7) == 0) { ++ can_pkcs11 = 2; ++ key_id = params->private_key; ++ } ++ ++ if (!cert_id && params->client_cert && can_pkcs11 && ++ os_strncmp(params->client_cert, "pkcs11:", 7) == 0) { ++ can_pkcs11 = 2; ++ cert_id = params->client_cert; ++ } ++ ++ if (!ca_cert_id && params->ca_cert && can_pkcs11 && ++ os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) { ++ can_pkcs11 = 2; ++ ca_cert_id = params->ca_cert; ++ } ++ ++ /* If we need to automatically enable the PKCS#11 ENGINE, do so. */ ++ if (can_pkcs11 == 2 && !engine_id) ++ engine_id = "pkcs11"; ++ ++#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) ++#if OPENSSL_VERSION_NUMBER < 0x10100000L ++ if (params->flags & TLS_CONN_EAP_FAST) { ++ wpa_printf(MSG_DEBUG, ++ "OpenSSL: Use TLSv1_method() for EAP-FAST"); ++ if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) { ++ tls_show_errors(MSG_INFO, __func__, ++ "Failed to set TLSv1_method() for EAP-FAST"); ++ return -1; ++ } ++ } ++#endif ++#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ ++ + while ((err = ERR_get_error())) { + wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s", + __func__, ERR_error_string(err, NULL)); + } + - if (params->engine) { ++ if (engine_id) { + wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine"); - ret = tls_engine_init(conn, params->engine_id, params->pin, - params->key_id, params->cert_id, - params->ca_cert_id); ++ 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->altsubject_match, ++ params->suffix_match, ++ params->domain_match)) + return -1; + - if (params->engine && params->ca_cert_id) { - if (tls_connection_engine_ca_cert(tls_ctx, conn, - params->ca_cert_id)) ++ 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(tls_ctx, conn, params->ca_cert, ++ } else if (tls_connection_ca_cert(data, conn, params->ca_cert, + params->ca_cert_blob, + params->ca_cert_blob_len, + params->ca_path)) + return -1; + - if (params->engine && params->cert_id) { - if (tls_connection_engine_client_cert(conn, params->cert_id)) ++ if (engine_id && cert_id) { ++ if (tls_connection_engine_client_cert(conn, cert_id)) + return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED; + } else if (tls_connection_client_cert(conn, params->client_cert, + params->client_cert_blob, + params->client_cert_blob_len)) + return -1; + - if (params->engine && params->key_id) { ++ 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(tls_ctx, conn, ++ } 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; + } + - tls_get_errors(tls_ctx); ++ if (params->openssl_ciphers && ++ SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) { ++ wpa_printf(MSG_INFO, ++ "OpenSSL: Failed to set cipher string '%s'", ++ params->openssl_ciphers); ++ return -1; ++ } ++ ++ tls_set_conn_flags(conn->ssl, params->flags); ++ ++#ifdef HAVE_OCSP ++ if (params->flags & TLS_CONN_REQUEST_OCSP) { ++ SSL_CTX *ssl_ctx = data->ssl; ++ SSL_set_tlsext_status_type(conn->ssl, TLSEXT_STATUSTYPE_ocsp); ++ SSL_CTX_set_tlsext_status_cb(ssl_ctx, ocsp_resp_cb); ++ SSL_CTX_set_tlsext_status_arg(ssl_ctx, conn); ++ } ++#else /* HAVE_OCSP */ ++ if (params->flags & TLS_CONN_REQUIRE_OCSP) { ++ wpa_printf(MSG_INFO, ++ "OpenSSL: No OCSP support included - reject configuration"); ++ return -1; ++ } ++ if (params->flags & TLS_CONN_REQUEST_OCSP) { ++ wpa_printf(MSG_DEBUG, ++ "OpenSSL: No OCSP support included - allow optional OCSP case to continue"); ++ } ++#endif /* HAVE_OCSP */ ++ ++ conn->flags = params->flags; ++ ++ tls_get_errors(data); + + return 0; +} + + +int tls_global_set_params(void *tls_ctx, + const struct tls_connection_params *params) +{ - SSL_CTX *ssl_ctx = tls_ctx; ++ 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(ssl_ctx, params->ca_cert)) - return -1; - - if (tls_global_client_cert(ssl_ctx, params->client_cert)) - return -1; - - if (tls_global_private_key(ssl_ctx, params->private_key, - params->private_key_passwd)) - return -1; - - if (tls_global_dh(ssl_ctx, params->dh_file)) { - wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'", - params->dh_file); ++ 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; + } + - return 0; - } - - - int tls_connection_get_keyblock_size(void *tls_ctx, - struct tls_connection *conn) - { - const EVP_CIPHER *c; - const EVP_MD *h; - - if (conn == NULL || conn->ssl == NULL || - conn->ssl->enc_read_ctx == NULL || - conn->ssl->enc_read_ctx->cipher == NULL || - conn->ssl->read_hash == NULL) ++ if (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; ++ } + - c = conn->ssl->enc_read_ctx->cipher; - #if OPENSSL_VERSION_NUMBER >= 0x00909000L - h = EVP_MD_CTX_md(conn->ssl->read_hash); - #else - h = conn->ssl->read_hash; - #endif - - return 2 * (EVP_CIPHER_key_length(c) + - EVP_MD_size(h) + - EVP_CIPHER_iv_length(c)); - } - ++#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 */ + - unsigned int tls_capabilities(void *tls_ctx) - { + return 0; +} + + - int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn, - int tls_ia) - { - return -1; - } - - - struct wpabuf * tls_connection_ia_send_phase_finished( - void *tls_ctx, struct tls_connection *conn, int final) - { - return NULL; - } - - - int tls_connection_ia_final_phase_finished(void *tls_ctx, - struct tls_connection *conn) - { - return -1; - } - - - int tls_connection_ia_permute_inner_secret(void *tls_ctx, - struct tls_connection *conn, - const u8 *key, size_t key_len) - { - return -1; - } - - +#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST) +/* Pre-shared secred requires a patch to openssl, so this function is + * commented out unless explicitly needed for EAP-FAST in order to be able to + * build this file with unmodified openssl. */ + ++#ifdef OPENSSL_IS_BORINGSSL ++static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, ++ STACK_OF(SSL_CIPHER) *peer_ciphers, ++ const SSL_CIPHER **cipher, void *arg) ++#else /* OPENSSL_IS_BORINGSSL */ +static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len, + STACK_OF(SSL_CIPHER) *peer_ciphers, + SSL_CIPHER **cipher, void *arg) ++#endif /* OPENSSL_IS_BORINGSSL */ +{ + struct tls_connection *conn = arg; + int ret; + ++#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (conn == NULL || conn->session_ticket_cb == NULL) + return 0; + + ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, + conn->session_ticket, + conn->session_ticket_len, + s->s3->client_random, + s->s3->server_random, secret); ++#else ++ unsigned char client_random[SSL3_RANDOM_SIZE]; ++ unsigned char server_random[SSL3_RANDOM_SIZE]; ++ ++ if (conn == NULL || conn->session_ticket_cb == NULL) ++ return 0; ++ ++ SSL_get_client_random(s, client_random, sizeof(client_random)); ++ SSL_get_server_random(s, server_random, sizeof(server_random)); ++ ++ ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx, ++ conn->session_ticket, ++ conn->session_ticket_len, ++ client_random, ++ server_random, secret); ++#endif ++ + os_free(conn->session_ticket); + conn->session_ticket = NULL; + + if (ret <= 0) + return 0; + + *secret_len = SSL_MAX_MASTER_KEY_LENGTH; + return 1; +} + + - #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE +static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data, + int len, void *arg) +{ + struct tls_connection *conn = arg; + + if (conn == NULL || conn->session_ticket_cb == NULL) + return 0; + + wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len); + + os_free(conn->session_ticket); + conn->session_ticket = NULL; + + wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " + "extension", data, len); + + conn->session_ticket = os_malloc(len); + if (conn->session_ticket == NULL) + return 0; + + os_memcpy(conn->session_ticket, data, len); + conn->session_ticket_len = len; + + return 1; +} - #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ - #ifdef SSL_OP_NO_TICKET - static void tls_hello_ext_cb(SSL *s, int client_server, int type, - unsigned char *data, int len, void *arg) - { - struct tls_connection *conn = arg; - - if (conn == NULL || conn->session_ticket_cb == NULL) - return; - - wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, - type, len); - - if (type == TLSEXT_TYPE_session_ticket && !client_server) { - os_free(conn->session_ticket); - conn->session_ticket = NULL; - - wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " - "extension", data, len); - conn->session_ticket = os_malloc(len); - if (conn->session_ticket == NULL) - return; - - os_memcpy(conn->session_ticket, data, len); - conn->session_ticket_len = len; - } - } - #else /* SSL_OP_NO_TICKET */ - static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg) - { - struct tls_connection *conn = arg; - - if (conn == NULL || conn->session_ticket_cb == NULL) - return 0; - - wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__, - ext->type, ext->length); - - os_free(conn->session_ticket); - conn->session_ticket = NULL; - - if (ext->type == 35) { - wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket " - "extension", ext->data, ext->length); - conn->session_ticket = os_malloc(ext->length); - if (conn->session_ticket == NULL) - return SSL_AD_INTERNAL_ERROR; - - os_memcpy(conn->session_ticket, ext->data, ext->length); - conn->session_ticket_len = ext->length; - } - - return 0; - } - #endif /* SSL_OP_NO_TICKET */ - #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ +#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; - #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE + SSL_set_session_ticket_ext_cb(conn->ssl, + tls_session_ticket_ext_cb, conn); - #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ - #ifdef SSL_OP_NO_TICKET - SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb); - SSL_set_tlsext_debug_arg(conn->ssl, conn); - #else /* SSL_OP_NO_TICKET */ - if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb, - conn) != 1) - return -1; - #endif /* SSL_OP_NO_TICKET */ - #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ + } else { + if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1) + return -1; - #ifdef CONFIG_OPENSSL_TICKET_OVERRIDE + SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL); - #else /* CONFIG_OPENSSL_TICKET_OVERRIDE */ - #ifdef SSL_OP_NO_TICKET - SSL_set_tlsext_debug_callback(conn->ssl, NULL); - SSL_set_tlsext_debug_arg(conn->ssl, conn); - #else /* SSL_OP_NO_TICKET */ - if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1) - return -1; - #endif /* SSL_OP_NO_TICKET */ - #endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */ + } + + return 0; +#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ + return -1; +#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */ +} ++ ++ ++int tls_get_library_version(char *buf, size_t buf_len) ++{ ++ return os_snprintf(buf, buf_len, "OpenSSL build=%s run=%s", ++ OPENSSL_VERSION_TEXT, ++ SSLeay_version(SSLEAY_VERSION)); ++} ++ ++ ++void tls_connection_set_success_data(struct tls_connection *conn, ++ struct wpabuf *data) ++{ ++ SSL_SESSION *sess; ++ struct wpabuf *old; ++ ++ if (tls_ex_idx_session < 0) ++ goto fail; ++ sess = SSL_get_session(conn->ssl); ++ if (!sess) ++ goto fail; ++ old = SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); ++ if (old) { ++ wpa_printf(MSG_DEBUG, "OpenSSL: Replacing old success data %p", ++ old); ++ wpabuf_free(old); ++ } ++ if (SSL_SESSION_set_ex_data(sess, tls_ex_idx_session, data) != 1) ++ goto fail; ++ ++ wpa_printf(MSG_DEBUG, "OpenSSL: Stored success data %p", data); ++ conn->success_data = 1; ++ return; ++ ++fail: ++ wpa_printf(MSG_INFO, "OpenSSL: Failed to store success data"); ++ wpabuf_free(data); ++} ++ ++ ++void tls_connection_set_success_data_resumed(struct tls_connection *conn) ++{ ++ wpa_printf(MSG_DEBUG, ++ "OpenSSL: Success data accepted for resumed session"); ++ conn->success_data = 1; ++} ++ ++ ++const struct wpabuf * ++tls_connection_get_success_data(struct tls_connection *conn) ++{ ++ SSL_SESSION *sess; ++ ++ if (tls_ex_idx_session < 0 || ++ !(sess = SSL_get_session(conn->ssl))) ++ return NULL; ++ return SSL_SESSION_get_ex_data(sess, tls_ex_idx_session); ++} ++ ++ ++void tls_connection_remove_session(struct tls_connection *conn) ++{ ++ SSL_SESSION *sess; ++ ++ sess = SSL_get_session(conn->ssl); ++ if (!sess) ++ return; ++ ++ if (SSL_CTX_remove_session(conn->ssl_ctx, sess) != 1) ++ wpa_printf(MSG_DEBUG, ++ "OpenSSL: Session was not cached"); ++ else ++ wpa_printf(MSG_DEBUG, ++ "OpenSSL: Removed cached session to disable session resumption"); ++} diff --cc libeap/src/drivers/android_drv.h index 0000000,31d9440..31d9440 mode 000000,100644..100644 --- a/libeap/src/drivers/android_drv.h +++ b/libeap/src/drivers/android_drv.h diff --cc libeap/src/drivers/driver_common.c index 0000000,aebea8c..aebea8c mode 000000,100644..100644 --- a/libeap/src/drivers/driver_common.c +++ b/libeap/src/drivers/driver_common.c diff --cc libeap/src/drivers/driver_macsec_qca.c index 0000000,3eae2f8..3eae2f8 mode 000000,100644..100644 --- a/libeap/src/drivers/driver_macsec_qca.c +++ b/libeap/src/drivers/driver_macsec_qca.c diff --cc libeap/src/drivers/driver_nl80211.h index 0000000,5c21e0f..5c21e0f mode 000000,100644..100644 --- a/libeap/src/drivers/driver_nl80211.h +++ b/libeap/src/drivers/driver_nl80211.h diff --cc libeap/src/drivers/driver_nl80211_android.c index 0000000,ba47888..ba47888 mode 000000,100644..100644 --- a/libeap/src/drivers/driver_nl80211_android.c +++ b/libeap/src/drivers/driver_nl80211_android.c diff --cc libeap/src/drivers/driver_nl80211_capa.c index 0000000,4cf3123..4cf3123 mode 000000,100644..100644 --- a/libeap/src/drivers/driver_nl80211_capa.c +++ b/libeap/src/drivers/driver_nl80211_capa.c diff --cc libeap/src/drivers/driver_nl80211_event.c index 0000000,7b0f721..7b0f721 mode 000000,100644..100644 --- a/libeap/src/drivers/driver_nl80211_event.c +++ b/libeap/src/drivers/driver_nl80211_event.c diff --cc libeap/src/drivers/driver_nl80211_monitor.c index 0000000,45385da..45385da mode 000000,100644..100644 --- a/libeap/src/drivers/driver_nl80211_monitor.c +++ b/libeap/src/drivers/driver_nl80211_monitor.c diff --cc libeap/src/drivers/driver_nl80211_scan.c index 0000000,4b762ea..4b762ea mode 000000,100644..100644 --- a/libeap/src/drivers/driver_nl80211_scan.c +++ b/libeap/src/drivers/driver_nl80211_scan.c diff --cc libeap/src/drivers/driver_openbsd.c index 0000000,e94eda0..e94eda0 mode 000000,100644..100644 --- a/libeap/src/drivers/driver_openbsd.c +++ b/libeap/src/drivers/driver_openbsd.c diff --cc libeap/src/drivers/drivers.mk index 0000000,8da4c53..8da4c53 mode 000000,100644..100644 --- a/libeap/src/drivers/drivers.mk +++ b/libeap/src/drivers/drivers.mk diff --cc libeap/src/drivers/linux_defines.h index 0000000,a107479..a107479 mode 000000,100644..100644 --- a/libeap/src/drivers/linux_defines.h +++ b/libeap/src/drivers/linux_defines.h diff --cc libeap/src/drivers/linux_wext.h index 0000000,e7c7001..e7c7001 mode 000000,100644..100644 --- a/libeap/src/drivers/linux_wext.h +++ b/libeap/src/drivers/linux_wext.h diff --cc libeap/src/eap_common/eap_common.h index 9db77ed,0000000..91cf7d5 mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_common.h +++ b/libeap/src/eap_common/eap_common.h @@@ -1,36 -1,0 +1,41 @@@ +/* + * EAP common peer/server definitions - * Copyright (c) 2004-2007, Jouni Malinen ++ * Copyright (c) 2004-2014, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_COMMON_H +#define EAP_COMMON_H + +#include "wpabuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + ++ ++struct erp_tlvs { ++ const u8 *keyname; ++ const u8 *domain; ++ u8 keyname_len; ++ u8 domain_len; ++}; ++ ++int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload); +const u8 * eap_hdr_validate(int vendor, EapType eap_type, + const struct wpabuf *msg, size_t *plen); +struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len, + u8 code, u8 identifier); +void eap_update_len(struct wpabuf *msg); +u8 eap_get_id(const struct wpabuf *msg); +EapType eap_get_type(const struct wpabuf *msg); ++int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs, ++ int stop_at_keyname); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_COMMON_H */ diff --cc libeap/src/eap_common/eap_defs.h index 482f9d2,0000000..708e50d mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_defs.h +++ b/libeap/src/eap_common/eap_defs.h @@@ -1,94 -1,0 +1,126 @@@ +/* + * EAP server/peer: Shared EAP definitions - * Copyright (c) 2004-2007, Jouni Malinen ++ * Copyright (c) 2004-2014, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_DEFS_H +#define EAP_DEFS_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* RFC 3748 - Extensible Authentication Protocol (EAP) */ + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_hdr { + u8 code; + u8 identifier; + be16 length; /* including code and identifier; network byte order */ + /* followed by length-4 octets of data */ +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3, - EAP_CODE_FAILURE = 4 }; ++ EAP_CODE_FAILURE = 4, EAP_CODE_INITIATE = 5, EAP_CODE_FINISH = 6 }; + +/* EAP Request and Response data begins with one octet Type. Success and + * Failure do not have additional data. */ + ++/* Type field in EAP-Initiate and EAP-Finish messages */ ++enum eap_erp_type { ++ EAP_ERP_TYPE_REAUTH_START = 1, ++ EAP_ERP_TYPE_REAUTH = 2, ++}; ++ ++/* ERP TV/TLV types */ ++enum eap_erp_tlv_type { ++ EAP_ERP_TLV_KEYNAME_NAI = 1, ++ EAP_ERP_TV_RRK_LIFETIME = 2, ++ EAP_ERP_TV_RMSK_LIFETIME = 3, ++ EAP_ERP_TLV_DOMAIN_NAME = 4, ++ EAP_ERP_TLV_CRYPTOSUITES = 5, ++ EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6, ++ EAP_ERP_TLV_CALLED_STATION_ID = 128, ++ EAP_ERP_TLV_CALLING_STATION_ID = 129, ++ EAP_ERP_TLV_NAS_IDENTIFIER = 130, ++ EAP_ERP_TLV_NAS_IP_ADDRESS = 131, ++ EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132, ++}; ++ ++/* ERP Cryptosuite */ ++enum eap_erp_cryptosuite { ++ EAP_ERP_CS_HMAC_SHA256_64 = 1, ++ EAP_ERP_CS_HMAC_SHA256_128 = 2, ++ EAP_ERP_CS_HMAC_SHA256_256 = 3, ++}; ++ +/* + * EAP Method Types as allocated by IANA: + * http://www.iana.org/assignments/eap-numbers + */ +typedef enum { + EAP_TYPE_NONE = 0, + EAP_TYPE_IDENTITY = 1 /* RFC 3748 */, + EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */, + EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */, + EAP_TYPE_MD5 = 4, /* RFC 3748 */ + EAP_TYPE_OTP = 5 /* RFC 3748 */, + EAP_TYPE_GTC = 6, /* RFC 3748 */ + EAP_TYPE_TLS = 13 /* RFC 2716 */, + EAP_TYPE_LEAP = 17 /* Cisco proprietary */, + EAP_TYPE_SIM = 18 /* RFC 4186 */, + EAP_TYPE_TTLS = 21 /* RFC 5281 */, + EAP_TYPE_AKA = 23 /* RFC 4187 */, + EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */, + EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */, + EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */, + EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment; + * type 38 has previously been allocated for + * EAP-HTTP Digest, (funk.com) */, + EAP_TYPE_FAST = 43 /* RFC 4851 */, + EAP_TYPE_PAX = 46 /* RFC 4746 */, + EAP_TYPE_PSK = 47 /* RFC 4764 */, + EAP_TYPE_SAKE = 48 /* RFC 4763 */, + EAP_TYPE_IKEV2 = 49 /* RFC 5106 */, - EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */, ++ EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */, + EAP_TYPE_GPSK = 51 /* RFC 5433 */, + EAP_TYPE_PWD = 52 /* RFC 5931 */, ++ EAP_TYPE_EKE = 53 /* RFC 6124 */, + EAP_TYPE_EXPANDED = 254 /* RFC 3748 */ +} EapType; + + +/* SMI Network Management Private Enterprise Code for vendor specific types */ +enum { + EAP_VENDOR_IETF = 0, + EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */, - EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */ ++ EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance (moved to WBA) */, ++ EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */, ++ EAP_VENDOR_WFA_NEW = 40808 /* Wi-Fi Alliance */ +}; + ++#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP ++#define EAP_VENDOR_TYPE_UNAUTH_TLS 1 ++ ++#define EAP_VENDOR_WFA_UNAUTH_TLS 13 ++ +#define EAP_MSK_LEN 64 +#define EAP_EMSK_LEN 64 ++#define EAP_EMSK_NAME_LEN 8 ++#define ERP_MAX_KEY_LEN 64 + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_DEFS_H */ diff --cc libeap/src/eap_common/eap_eke_common.c index 0000000,4dfdb3f..4dfdb3f mode 000000,100644..100644 --- a/libeap/src/eap_common/eap_eke_common.c +++ b/libeap/src/eap_common/eap_eke_common.c diff --cc libeap/src/eap_common/eap_eke_common.h index 0000000,a4c0422..a4c0422 mode 000000,100644..100644 --- a/libeap/src/eap_common/eap_eke_common.h +++ b/libeap/src/eap_common/eap_eke_common.h diff --cc libeap/src/eap_common/eap_fast_common.h index c4f54ca,0000000..6d547fb mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_fast_common.h +++ b/libeap/src/eap_common/eap_fast_common.h @@@ -1,121 -1,0 +1,115 @@@ +/* + * EAP-FAST definitions (RFC 4851) + * Copyright (c) 2004-2008, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_FAST_H +#define EAP_FAST_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_FAST_VERSION 1 +#define EAP_FAST_KEY_LEN 64 +#define EAP_FAST_SIMCK_LEN 40 +#define EAP_FAST_SKS_LEN 40 +#define EAP_FAST_CMK_LEN 20 + +#define TLS_EXT_PAC_OPAQUE 35 + +/* + * RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field + * Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined + * in the general PAC TLV format (Section 4.2). + */ +#define PAC_TYPE_PAC_KEY 1 +#define PAC_TYPE_PAC_OPAQUE 2 +#define PAC_TYPE_CRED_LIFETIME 3 +#define PAC_TYPE_A_ID 4 +#define PAC_TYPE_I_ID 5 +/* + * 6 was previous assigned for SERVER_PROTECTED_DATA, but + * draft-cam-winget-eap-fast-provisioning-02.txt changed this to Reserved. + */ +#define PAC_TYPE_A_ID_INFO 7 +#define PAC_TYPE_PAC_ACKNOWLEDGEMENT 8 +#define PAC_TYPE_PAC_INFO 9 +#define PAC_TYPE_PAC_TYPE 10 + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct pac_tlv_hdr { + be16 type; + be16 len; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +#define EAP_FAST_PAC_KEY_LEN 32 + +/* RFC 5422: 4.2.6 PAC-Type TLV */ +#define PAC_TYPE_TUNNEL_PAC 1 +/* Application Specific Short Lived PACs (only in volatile storage) */ +/* User Authorization PAC */ +#define PAC_TYPE_USER_AUTHORIZATION 3 +/* Application Specific Long Lived PACs */ +/* Machine Authentication PAC */ +#define PAC_TYPE_MACHINE_AUTHENTICATION 2 + + +/* + * RFC 5422: + * Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange + */ +struct eap_fast_key_block_provisioning { + /* Extra key material after TLS key_block */ + u8 session_key_seed[EAP_FAST_SKS_LEN]; + u8 server_challenge[16]; /* MSCHAPv2 ServerChallenge */ + u8 client_challenge[16]; /* MSCHAPv2 ClientChallenge */ +}; + + +struct wpabuf; +struct tls_connection; + +struct eap_fast_tlv_parse { + u8 *eap_payload_tlv; + size_t eap_payload_tlv_len; + struct eap_tlv_crypto_binding_tlv *crypto_binding; + size_t crypto_binding_len; + int iresult; + int result; + int request_action; + u8 *pac; + size_t pac_len; +}; + +void eap_fast_put_tlv_hdr(struct wpabuf *buf, u16 type, u16 len); +void eap_fast_put_tlv(struct wpabuf *buf, u16 type, const void *data, + u16 len); +void eap_fast_put_tlv_buf(struct wpabuf *buf, u16 type, + const struct wpabuf *data); +struct wpabuf * eap_fast_tlv_eap_payload(struct wpabuf *buf); +void eap_fast_derive_master_secret(const u8 *pac_key, const u8 *server_random, + const u8 *client_random, u8 *master_secret); +u8 * eap_fast_derive_key(void *ssl_ctx, struct tls_connection *conn, + const char *label, size_t len); +void eap_fast_derive_eap_msk(const u8 *simck, u8 *msk); +void eap_fast_derive_eap_emsk(const u8 *simck, u8 *emsk); +int eap_fast_parse_tlv(struct eap_fast_tlv_parse *tlv, - int tlv_type, u8 *pos, int len); ++ int tlv_type, u8 *pos, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_FAST_H */ diff --cc libeap/src/eap_common/eap_gpsk_common.h index 6766603,0000000..0e18ec2 mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_gpsk_common.h +++ b/libeap/src/eap_common/eap_gpsk_common.h @@@ -1,74 -1,0 +1,74 @@@ +/* + * EAP server/peer: EAP-GPSK shared routines + * Copyright (c) 2006-2007, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_GPSK_COMMON_H +#define EAP_GPSK_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_GPSK_OPCODE_GPSK_1 1 +#define EAP_GPSK_OPCODE_GPSK_2 2 +#define EAP_GPSK_OPCODE_GPSK_3 3 +#define EAP_GPSK_OPCODE_GPSK_4 4 +#define EAP_GPSK_OPCODE_FAIL 5 +#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6 + +/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */ +#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001 +#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002 +#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003 + +#define EAP_GPSK_RAND_LEN 32 +#define EAP_GPSK_MAX_SK_LEN 32 +#define EAP_GPSK_MAX_PK_LEN 32 +#define EAP_GPSK_MAX_MIC_LEN 32 + +#define EAP_GPSK_VENDOR_IETF 0x00000000 +#define EAP_GPSK_CIPHER_RESERVED 0x000000 +#define EAP_GPSK_CIPHER_AES 0x000001 +#define EAP_GPSK_CIPHER_SHA256 0x000002 + + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_gpsk_csuite { + u8 vendor[4]; + u8 specifier[2]; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +int eap_gpsk_supported_ciphersuite(int vendor, int specifier); +int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor, + int specifier, + const u8 *rand_client, const u8 *rand_server, + const u8 *id_client, size_t id_client_len, + const u8 *id_server, size_t id_server_len, + u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len, + u8 *pk, size_t *pk_len); ++int eap_gpsk_derive_session_id(const u8 *psk, size_t psk_len, int vendor, ++ int specifier, ++ const u8 *rand_peer, const u8 *rand_server, ++ const u8 *id_peer, size_t id_peer_len, ++ const u8 *id_server, size_t id_server_len, ++ u8 method_type, u8 *sid, size_t *sid_len); +size_t eap_gpsk_mic_len(int vendor, int specifier); +int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor, + int specifier, const u8 *data, size_t len, u8 *mic); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_GPSK_COMMON_H */ diff --cc libeap/src/eap_common/eap_ikev2_common.h index a054b6a,0000000..e3bade5 mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_ikev2_common.h +++ b/libeap/src/eap_common/eap_ikev2_common.h @@@ -1,50 -1,0 +1,37 @@@ +/* + * EAP-IKEv2 definitions + * Copyright (c) 2007, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_IKEV2_COMMON_H +#define EAP_IKEV2_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + - #ifdef CCNS_PL - /* incorrect bit order */ - #define IKEV2_FLAGS_LENGTH_INCLUDED 0x01 - #define IKEV2_FLAGS_MORE_FRAGMENTS 0x02 - #define IKEV2_FLAGS_ICV_INCLUDED 0x04 - #else /* CCNS_PL */ +#define IKEV2_FLAGS_LENGTH_INCLUDED 0x80 +#define IKEV2_FLAGS_MORE_FRAGMENTS 0x40 +#define IKEV2_FLAGS_ICV_INCLUDED 0x20 - #endif /* CCNS_PL */ + +#define IKEV2_FRAGMENT_SIZE 1400 + +struct ikev2_keys; + +int eap_ikev2_derive_keymat(int prf, struct ikev2_keys *keys, + const u8 *i_nonce, size_t i_nonce_len, + const u8 *r_nonce, size_t r_nonce_len, + u8 *keymat); +struct wpabuf * eap_ikev2_build_frag_ack(u8 id, u8 code); +int eap_ikev2_validate_icv(int integ_alg, struct ikev2_keys *keys, + int initiator, const struct wpabuf *msg, + const u8 *pos, const u8 *end); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_IKEV2_COMMON_H */ diff --cc libeap/src/eap_common/eap_pax_common.h index ff9b903,0000000..cc38b17 mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_pax_common.h +++ b/libeap/src/eap_common/eap_pax_common.h @@@ -1,105 -1,0 +1,100 @@@ +/* + * EAP server/peer: EAP-PAX shared routines + * Copyright (c) 2005-2007, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_PAX_COMMON_H +#define EAP_PAX_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_pax_hdr { + u8 op_code; + u8 flags; + u8 mac_id; + u8 dh_group_id; + u8 public_key_id; + /* Followed by variable length payload and ICV */ +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +/* op_code: */ +enum { + EAP_PAX_OP_STD_1 = 0x01, + EAP_PAX_OP_STD_2 = 0x02, + EAP_PAX_OP_STD_3 = 0x03, + EAP_PAX_OP_SEC_1 = 0x11, + EAP_PAX_OP_SEC_2 = 0x12, + EAP_PAX_OP_SEC_3 = 0x13, + EAP_PAX_OP_SEC_4 = 0x14, + EAP_PAX_OP_SEC_5 = 0x15, + EAP_PAX_OP_ACK = 0x21 +}; + +/* flags: */ +#define EAP_PAX_FLAGS_MF 0x01 +#define EAP_PAX_FLAGS_CE 0x02 +#define EAP_PAX_FLAGS_AI 0x04 + +/* mac_id: */ +#define EAP_PAX_MAC_HMAC_SHA1_128 0x01 +#define EAP_PAX_HMAC_SHA256_128 0x02 + +/* dh_group_id: */ +#define EAP_PAX_DH_GROUP_NONE 0x00 +#define EAP_PAX_DH_GROUP_2048_MODP 0x01 +#define EAP_PAX_DH_GROUP_3072_MODP 0x02 +#define EAP_PAX_DH_GROUP_NIST_ECC_P_256 0x03 + +/* public_key_id: */ +#define EAP_PAX_PUBLIC_KEY_NONE 0x00 +#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP 0x01 +#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 0x02 +#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC 0x03 + +/* ADE type: */ +#define EAP_PAX_ADE_VENDOR_SPECIFIC 0x01 +#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING 0x02 +#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING 0x03 + + +#define EAP_PAX_RAND_LEN 32 +#define EAP_PAX_MAC_LEN 16 +#define EAP_PAX_ICV_LEN 16 +#define EAP_PAX_AK_LEN 16 +#define EAP_PAX_MK_LEN 16 +#define EAP_PAX_CK_LEN 16 +#define EAP_PAX_ICK_LEN 16 ++#define EAP_PAX_MID_LEN 16 + + +int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len, + const char *identifier, + const u8 *entropy, size_t entropy_len, + size_t output_len, u8 *output); +int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len, + const u8 *data1, size_t data1_len, + const u8 *data2, size_t data2_len, + const u8 *data3, size_t data3_len, + u8 *mac); +int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e, - u8 *mk, u8 *ck, u8 *ick); ++ u8 *mk, u8 *ck, u8 *ick, u8 *mid); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_PAX_COMMON_H */ diff --cc libeap/src/eap_common/eap_peap_common.h index b67de7e,0000000..069450e mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_peap_common.h +++ b/libeap/src/eap_common/eap_peap_common.h @@@ -1,30 -1,0 +1,24 @@@ +/* + * EAP-PEAP common routines - * Copyright (c) 2008, Jouni Malinen ++ * Copyright (c) 2008-2011, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_PEAP_COMMON_H +#define EAP_PEAP_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + - void peap_prfplus(int version, const u8 *key, size_t key_len, - const char *label, const u8 *seed, size_t seed_len, - u8 *buf, size_t buf_len); ++int peap_prfplus(int version, const u8 *key, size_t key_len, ++ const char *label, const u8 *seed, size_t seed_len, ++ u8 *buf, size_t buf_len); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_PEAP_COMMON_H */ diff --cc libeap/src/eap_common/eap_psk_common.h index 0de2c75,0000000..e7c50b9 mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_psk_common.h +++ b/libeap/src/eap_common/eap_psk_common.h @@@ -1,85 -1,0 +1,79 @@@ +/* + * EAP server/peer: EAP-PSK shared routines + * Copyright (c) 2004-2007, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_PSK_COMMON_H +#define EAP_PSK_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_PSK_RAND_LEN 16 +#define EAP_PSK_MAC_LEN 16 +#define EAP_PSK_TEK_LEN 16 +#define EAP_PSK_PSK_LEN 16 +#define EAP_PSK_AK_LEN 16 +#define EAP_PSK_KDK_LEN 16 + +#define EAP_PSK_R_FLAG_CONT 1 +#define EAP_PSK_R_FLAG_DONE_SUCCESS 2 +#define EAP_PSK_R_FLAG_DONE_FAILURE 3 +#define EAP_PSK_E_FLAG 0x20 + +#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6) +#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6) + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +/* EAP-PSK First Message (AS -> Supplicant) */ +struct eap_psk_hdr_1 { + u8 flags; + u8 rand_s[EAP_PSK_RAND_LEN]; + /* Followed by variable length ID_S */ +} STRUCT_PACKED; + +/* EAP-PSK Second Message (Supplicant -> AS) */ +struct eap_psk_hdr_2 { + u8 flags; + u8 rand_s[EAP_PSK_RAND_LEN]; + u8 rand_p[EAP_PSK_RAND_LEN]; + u8 mac_p[EAP_PSK_MAC_LEN]; + /* Followed by variable length ID_P */ +} STRUCT_PACKED; + +/* EAP-PSK Third Message (AS -> Supplicant) */ +struct eap_psk_hdr_3 { + u8 flags; + u8 rand_s[EAP_PSK_RAND_LEN]; + u8 mac_s[EAP_PSK_MAC_LEN]; + /* Followed by variable length PCHANNEL */ +} STRUCT_PACKED; + +/* EAP-PSK Fourth Message (Supplicant -> AS) */ +struct eap_psk_hdr_4 { + u8 flags; + u8 rand_s[EAP_PSK_RAND_LEN]; + /* Followed by variable length PCHANNEL */ +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +int __must_check eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk); +int __must_check eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, + u8 *msk, u8 *emsk); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_PSK_COMMON_H */ diff --cc libeap/src/eap_common/eap_pwd_common.h index 03454ac,0000000..6562ea4 mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_pwd_common.h +++ b/libeap/src/eap_common/eap_pwd_common.h @@@ -1,87 -1,0 +1,80 @@@ +/* + * EAP server/peer: EAP-pwd shared definitions + * Copyright (c) 2009, Dan Harkins + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the BSD license. - * - * Alternatively, this software may be distributed under the terms of the - * GNU General Public License version 2 as published by the Free Software - * Foundation. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_PWD_COMMON_H +#define EAP_PWD_COMMON_H + +#include - #include +#include +#include - #include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * definition of a finite cyclic group + * TODO: support one based on a prime field + */ +typedef struct group_definition_ { + u16 group_num; + EC_GROUP *group; + EC_POINT *pwe; + BIGNUM *order; + BIGNUM *prime; +} EAP_PWD_group; + +/* + * EAP-pwd header, included on all payloads ++ * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set) + */ - struct eap_pwd_hdr { - u8 l_bit:1; - u8 m_bit:1; - u8 exch:6; - u8 total_length[0]; /* included when l_bit is set */ - } STRUCT_PACKED; ++#define EAP_PWD_HDR_SIZE 1 + +#define EAP_PWD_OPCODE_ID_EXCH 1 +#define EAP_PWD_OPCODE_COMMIT_EXCH 2 +#define EAP_PWD_OPCODE_CONFIRM_EXCH 3 - #define EAP_PWD_GET_LENGTH_BIT(x) ((x)->lm_exch & 0x80) - #define EAP_PWD_SET_LENGTH_BIT(x) ((x)->lm_exch |= 0x80) - #define EAP_PWD_GET_MORE_BIT(x) ((x)->lm_exch & 0x40) - #define EAP_PWD_SET_MORE_BIT(x) ((x)->lm_exch |= 0x40) - #define EAP_PWD_GET_EXCHANGE(x) ((x)->lm_exch & 0x3f) - #define EAP_PWD_SET_EXCHANGE(x,y) ((x)->lm_exch |= (y)) ++#define EAP_PWD_GET_LENGTH_BIT(x) ((x) & 0x80) ++#define EAP_PWD_SET_LENGTH_BIT(x) ((x) |= 0x80) ++#define EAP_PWD_GET_MORE_BIT(x) ((x) & 0x40) ++#define EAP_PWD_SET_MORE_BIT(x) ((x) |= 0x40) ++#define EAP_PWD_GET_EXCHANGE(x) ((x) & 0x3f) ++#define EAP_PWD_SET_EXCHANGE(x,y) ((x) |= (y)) + +/* EAP-pwd-ID payload */ +struct eap_pwd_id { + be16 group_num; + u8 random_function; +#define EAP_PWD_DEFAULT_RAND_FUNC 1 + u8 prf; +#define EAP_PWD_DEFAULT_PRF 1 + u8 token[4]; + u8 prep; +#define EAP_PWD_PREP_NONE 0 +#define EAP_PWD_PREP_MS 1 + u8 identity[0]; /* length inferred from payload */ +} STRUCT_PACKED; + +/* common routines */ - int compute_password_element(EAP_PWD_group *, u16, u8 *, int, u8 *, int, u8 *, - int, u8 *); - int compute_keys(EAP_PWD_group *, BN_CTX *, BIGNUM *, EC_POINT *, EC_POINT *, - BIGNUM *, BIGNUM *, u32 *, u8 *, u8 *); - void H_Init(HMAC_CTX *); - void H_Update(HMAC_CTX *, const u8 *, int); - void H_Final(HMAC_CTX *, u8 *); ++int compute_password_element(EAP_PWD_group *grp, u16 num, ++ const u8 *password, size_t password_len, ++ const u8 *id_server, size_t id_server_len, ++ const u8 *id_peer, size_t id_peer_len, ++ const u8 *token); ++int compute_keys(EAP_PWD_group *grp, BN_CTX *bnctx, const BIGNUM *k, ++ const BIGNUM *peer_scalar, const BIGNUM *server_scalar, ++ const u8 *confirm_peer, const u8 *confirm_server, ++ const u32 *ciphersuite, u8 *msk, u8 *emsk, u8 *session_id); ++struct crypto_hash * eap_pwd_h_init(void); ++void eap_pwd_h_update(struct crypto_hash *hash, const u8 *data, size_t len); ++void eap_pwd_h_final(struct crypto_hash *hash, u8 *digest); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_PWD_COMMON_H */ diff --cc libeap/src/eap_common/eap_sake_common.h index 8a5b170,0000000..440badc mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_sake_common.h +++ b/libeap/src/eap_common/eap_sake_common.h @@@ -1,110 -1,0 +1,104 @@@ +/* + * EAP server/peer: EAP-SAKE shared routines + * Copyright (c) 2006-2007, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_SAKE_COMMON_H +#define EAP_SAKE_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_SAKE_VERSION 2 + +#define EAP_SAKE_SUBTYPE_CHALLENGE 1 +#define EAP_SAKE_SUBTYPE_CONFIRM 2 +#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3 +#define EAP_SAKE_SUBTYPE_IDENTITY 4 + +#define EAP_SAKE_AT_RAND_S 1 +#define EAP_SAKE_AT_RAND_P 2 +#define EAP_SAKE_AT_MIC_S 3 +#define EAP_SAKE_AT_MIC_P 4 +#define EAP_SAKE_AT_SERVERID 5 +#define EAP_SAKE_AT_PEERID 6 +#define EAP_SAKE_AT_SPI_S 7 +#define EAP_SAKE_AT_SPI_P 8 +#define EAP_SAKE_AT_ANY_ID_REQ 9 +#define EAP_SAKE_AT_PERM_ID_REQ 10 +#define EAP_SAKE_AT_ENCR_DATA 128 +#define EAP_SAKE_AT_IV 129 +#define EAP_SAKE_AT_PADDING 130 +#define EAP_SAKE_AT_NEXT_TMPID 131 +#define EAP_SAKE_AT_MSK_LIFE 132 + +#define EAP_SAKE_RAND_LEN 16 +#define EAP_SAKE_MIC_LEN 16 +#define EAP_SAKE_ROOT_SECRET_LEN 16 +#define EAP_SAKE_SMS_LEN 16 +#define EAP_SAKE_TEK_AUTH_LEN 16 +#define EAP_SAKE_TEK_CIPHER_LEN 16 +#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN) + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_sake_hdr { + u8 version; /* EAP_SAKE_VERSION */ + u8 session_id; + u8 subtype; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + +struct eap_sake_parse_attr { + const u8 *rand_s; + const u8 *rand_p; + const u8 *mic_s; + const u8 *mic_p; + const u8 *serverid; + size_t serverid_len; + const u8 *peerid; + size_t peerid_len; + const u8 *spi_s; + size_t spi_s_len; + const u8 *spi_p; + size_t spi_p_len; + const u8 *any_id_req; + const u8 *perm_id_req; + const u8 *encr_data; + size_t encr_data_len; + const u8 *iv; + size_t iv_len; + const u8 *next_tmpid; + size_t next_tmpid_len; + const u8 *msk_life; +}; + +int eap_sake_parse_attributes(const u8 *buf, size_t len, + struct eap_sake_parse_attr *attr); +void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b, + const u8 *rand_s, const u8 *rand_p, + u8 *tek, u8 *msk, u8 *emsk); +int eap_sake_compute_mic(const u8 *tek_auth, + const u8 *rand_s, const u8 *rand_p, + const u8 *serverid, size_t serverid_len, + const u8 *peerid, size_t peerid_len, + int peer, const u8 *eap, size_t eap_len, + const u8 *mic_pos, u8 *mic); +void eap_sake_add_attr(struct wpabuf *buf, u8 type, const u8 *data, + size_t len); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_SAKE_COMMON_H */ diff --cc libeap/src/eap_common/eap_sim_common.h index b6359a9,0000000..7c2cff1 mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_sim_common.h +++ b/libeap/src/eap_common/eap_sim_common.h @@@ -1,243 -1,0 +1,238 @@@ +/* + * EAP peer/server: EAP-SIM/AKA/AKA' shared routines + * Copyright (c) 2004-2008, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_SIM_COMMON_H +#define EAP_SIM_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_SIM_NONCE_S_LEN 16 +#define EAP_SIM_NONCE_MT_LEN 16 +#define EAP_SIM_MAC_LEN 16 +#define EAP_SIM_MK_LEN 20 +#define EAP_SIM_K_AUT_LEN 16 +#define EAP_SIM_K_ENCR_LEN 16 +#define EAP_SIM_KEYING_DATA_LEN 64 +#define EAP_SIM_IV_LEN 16 +#define EAP_SIM_KC_LEN 8 +#define EAP_SIM_SRES_LEN 4 + +#define GSM_RAND_LEN 16 + +#define EAP_SIM_VERSION 1 + +/* EAP-SIM Subtypes */ +#define EAP_SIM_SUBTYPE_START 10 +#define EAP_SIM_SUBTYPE_CHALLENGE 11 +#define EAP_SIM_SUBTYPE_NOTIFICATION 12 +#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13 +#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14 + +/* AT_CLIENT_ERROR_CODE error codes */ +#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0 +#define EAP_SIM_UNSUPPORTED_VERSION 1 +#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2 +#define EAP_SIM_RAND_NOT_FRESH 3 + +#define EAP_SIM_MAX_FAST_REAUTHS 1000 + +#define EAP_SIM_MAX_CHAL 3 + + +/* EAP-AKA Subtypes */ +#define EAP_AKA_SUBTYPE_CHALLENGE 1 +#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2 +#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4 +#define EAP_AKA_SUBTYPE_IDENTITY 5 +#define EAP_AKA_SUBTYPE_NOTIFICATION 12 +#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13 +#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14 + +/* AT_CLIENT_ERROR_CODE error codes */ +#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0 + +#define EAP_AKA_RAND_LEN 16 +#define EAP_AKA_AUTN_LEN 16 +#define EAP_AKA_AUTS_LEN 14 +#define EAP_AKA_RES_MAX_LEN 16 +#define EAP_AKA_IK_LEN 16 +#define EAP_AKA_CK_LEN 16 +#define EAP_AKA_MAX_FAST_REAUTHS 1000 +#define EAP_AKA_MIN_RES_LEN 4 +#define EAP_AKA_MAX_RES_LEN 16 +#define EAP_AKA_CHECKCODE_LEN 20 + +#define EAP_AKA_PRIME_K_AUT_LEN 32 +#define EAP_AKA_PRIME_CHECKCODE_LEN 32 +#define EAP_AKA_PRIME_K_RE_LEN 32 + +struct wpabuf; + +void eap_sim_derive_mk(const u8 *identity, size_t identity_len, + const u8 *nonce_mt, u16 selected_version, + const u8 *ver_list, size_t ver_list_len, + int num_chal, const u8 *kc, u8 *mk); +void eap_aka_derive_mk(const u8 *identity, size_t identity_len, + const u8 *ik, const u8 *ck, u8 *mk); +int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, + u8 *emsk); +int eap_sim_derive_keys_reauth(u16 _counter, + const u8 *identity, size_t identity_len, + const u8 *nonce_s, const u8 *mk, u8 *msk, + u8 *emsk); +int eap_sim_verify_mac(const u8 *k_aut, const struct wpabuf *req, + const u8 *mac, const u8 *extra, size_t extra_len); +void eap_sim_add_mac(const u8 *k_aut, const u8 *msg, size_t msg_len, u8 *mac, + const u8 *extra, size_t extra_len); + +#if defined(EAP_AKA_PRIME) || defined(EAP_SERVER_AKA_PRIME) +void eap_aka_prime_derive_keys(const u8 *identity, size_t identity_len, + const u8 *ik, const u8 *ck, u8 *k_encr, + u8 *k_aut, u8 *k_re, u8 *msk, u8 *emsk); +int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, + const u8 *identity, size_t identity_len, + const u8 *nonce_s, u8 *msk, u8 *emsk); +int eap_sim_verify_mac_sha256(const u8 *k_aut, const struct wpabuf *req, + const u8 *mac, const u8 *extra, + size_t extra_len); +void eap_sim_add_mac_sha256(const u8 *k_aut, const u8 *msg, size_t msg_len, + u8 *mac, const u8 *extra, size_t extra_len); + +void eap_aka_prime_derive_ck_ik_prime(u8 *ck, u8 *ik, const u8 *sqn_ak, + const u8 *network_name, + size_t network_name_len); +#else /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ +static inline void eap_aka_prime_derive_keys(const u8 *identity, + size_t identity_len, + const u8 *ik, const u8 *ck, + u8 *k_encr, u8 *k_aut, u8 *k_re, + u8 *msk, u8 *emsk) +{ +} + +static inline int eap_aka_prime_derive_keys_reauth(const u8 *k_re, u16 counter, + const u8 *identity, + size_t identity_len, + const u8 *nonce_s, u8 *msk, + u8 *emsk) +{ + return -1; +} + +static inline int eap_sim_verify_mac_sha256(const u8 *k_aut, + const struct wpabuf *req, + const u8 *mac, const u8 *extra, + size_t extra_len) +{ + return -1; +} +#endif /* EAP_AKA_PRIME || EAP_SERVER_AKA_PRIME */ + + +/* EAP-SIM/AKA Attributes (0..127 non-skippable) */ +#define EAP_SIM_AT_RAND 1 +#define EAP_SIM_AT_AUTN 2 /* only AKA */ +#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */ +#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */ +#define EAP_SIM_AT_PADDING 6 /* only encrypted */ +#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */ +#define EAP_SIM_AT_PERMANENT_ID_REQ 10 +#define EAP_SIM_AT_MAC 11 +#define EAP_SIM_AT_NOTIFICATION 12 +#define EAP_SIM_AT_ANY_ID_REQ 13 +#define EAP_SIM_AT_IDENTITY 14 /* only send */ +#define EAP_SIM_AT_VERSION_LIST 15 /* only SIM */ +#define EAP_SIM_AT_SELECTED_VERSION 16 /* only SIM */ +#define EAP_SIM_AT_FULLAUTH_ID_REQ 17 +#define EAP_SIM_AT_COUNTER 19 /* only encrypted */ +#define EAP_SIM_AT_COUNTER_TOO_SMALL 20 /* only encrypted */ +#define EAP_SIM_AT_NONCE_S 21 /* only encrypted */ +#define EAP_SIM_AT_CLIENT_ERROR_CODE 22 /* only send */ +#define EAP_SIM_AT_KDF_INPUT 23 /* only AKA' */ +#define EAP_SIM_AT_KDF 24 /* only AKA' */ +#define EAP_SIM_AT_IV 129 +#define EAP_SIM_AT_ENCR_DATA 130 +#define EAP_SIM_AT_NEXT_PSEUDONYM 132 /* only encrypted */ +#define EAP_SIM_AT_NEXT_REAUTH_ID 133 /* only encrypted */ +#define EAP_SIM_AT_CHECKCODE 134 /* only AKA */ +#define EAP_SIM_AT_RESULT_IND 135 +#define EAP_SIM_AT_BIDDING 136 + +/* AT_NOTIFICATION notification code values */ +#define EAP_SIM_GENERAL_FAILURE_AFTER_AUTH 0 +#define EAP_SIM_TEMPORARILY_DENIED 1026 +#define EAP_SIM_NOT_SUBSCRIBED 1031 +#define EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH 16384 +#define EAP_SIM_SUCCESS 32768 + +/* EAP-AKA' AT_KDF Key Derivation Function values */ +#define EAP_AKA_PRIME_KDF 1 + +/* AT_BIDDING flags */ +#define EAP_AKA_BIDDING_FLAG_D 0x8000 + + +enum eap_sim_id_req { + NO_ID_REQ, ANY_ID, FULLAUTH_ID, PERMANENT_ID +}; + + +struct eap_sim_attrs { + const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s; + const u8 *next_pseudonym, *next_reauth_id; + const u8 *nonce_mt, *identity, *res, *auts; + const u8 *checkcode; + const u8 *kdf_input; + const u8 *bidding; + size_t num_chal, version_list_len, encr_data_len; + size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len; + size_t res_len_bits; + size_t checkcode_len; + size_t kdf_input_len; + enum eap_sim_id_req id_req; + int notification, counter, selected_version, client_error_code; + int counter_too_small; + int result_ind; +#define EAP_AKA_PRIME_KDF_MAX 10 + u16 kdf[EAP_AKA_PRIME_KDF_MAX]; + size_t kdf_count; +}; + +int eap_sim_parse_attr(const u8 *start, const u8 *end, + struct eap_sim_attrs *attr, int aka, int encr); +u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data, + size_t encr_data_len, const u8 *iv, + struct eap_sim_attrs *attr, int aka); + + +struct eap_sim_msg; + +struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype); - struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, const u8 *k_aut, ++struct wpabuf * eap_sim_msg_finish(struct eap_sim_msg *msg, int type, ++ const u8 *k_aut, + const u8 *extra, size_t extra_len); +void eap_sim_msg_free(struct eap_sim_msg *msg); +u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr, + const u8 *data, size_t len); +u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, + u16 value, const u8 *data, size_t len); +u8 * eap_sim_msg_add_mac(struct eap_sim_msg *msg, u8 attr); +int eap_sim_msg_add_encr_start(struct eap_sim_msg *msg, u8 attr_iv, + u8 attr_encr); +int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, + int attr_pad); + +void eap_sim_report_notification(void *msg_ctx, int notification, int aka); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_SIM_COMMON_H */ diff --cc libeap/src/eap_common/eap_tlv_common.h index 25522ae,0000000..fcec4ce mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_tlv_common.h +++ b/libeap/src/eap_common/eap_tlv_common.h @@@ -1,126 -1,0 +1,120 @@@ +/* + * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt) + * Copyright (c) 2004-2008, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_TLV_COMMON_H +#define EAP_TLV_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */ +#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */ +#define EAP_TLV_NAK_TLV 4 +#define EAP_TLV_ERROR_CODE_TLV 5 +#define EAP_TLV_CONNECTION_BINDING_TLV 6 +#define EAP_TLV_VENDOR_SPECIFIC_TLV 7 +#define EAP_TLV_URI_TLV 8 +#define EAP_TLV_EAP_PAYLOAD_TLV 9 +#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10 +#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */ +#define EAP_TLV_CRYPTO_BINDING_TLV 12 +#define EAP_TLV_CALLING_STATION_ID_TLV 13 +#define EAP_TLV_CALLED_STATION_ID_TLV 14 +#define EAP_TLV_NAS_PORT_TYPE_TLV 15 +#define EAP_TLV_SERVER_IDENTIFIER_TLV 16 +#define EAP_TLV_IDENTITY_TYPE_TLV 17 +#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18 +#define EAP_TLV_REQUEST_ACTION_TLV 19 +#define EAP_TLV_PKCS7_TLV 20 + +#define EAP_TLV_RESULT_SUCCESS 1 +#define EAP_TLV_RESULT_FAILURE 2 + +#define EAP_TLV_TYPE_MANDATORY 0x8000 +#define EAP_TLV_TYPE_MASK 0x3fff + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct eap_tlv_hdr { + be16 tlv_type; + be16 length; +} STRUCT_PACKED; + +struct eap_tlv_nak_tlv { + be16 tlv_type; + be16 length; + be32 vendor_id; + be16 nak_type; +} STRUCT_PACKED; + +struct eap_tlv_result_tlv { + be16 tlv_type; + be16 length; + be16 status; +} STRUCT_PACKED; + +/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */ +struct eap_tlv_intermediate_result_tlv { + be16 tlv_type; + be16 length; + be16 status; + /* Followed by optional TLVs */ +} STRUCT_PACKED; + +/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */ +struct eap_tlv_crypto_binding_tlv { + be16 tlv_type; + be16 length; + u8 reserved; + u8 version; + u8 received_version; + u8 subtype; + u8 nonce[32]; + u8 compound_mac[20]; +} STRUCT_PACKED; + +struct eap_tlv_pac_ack_tlv { + be16 tlv_type; + be16 length; + be16 pac_type; + be16 pac_len; + be16 result; +} STRUCT_PACKED; + +/* RFC 4851, Section 4.2.9 - Request-Action TLV */ +struct eap_tlv_request_action_tlv { + be16 tlv_type; + be16 length; + be16 action; +} STRUCT_PACKED; + +/* RFC 5422, Section 4.2.6 - PAC-Type TLV */ +struct eap_tlv_pac_type_tlv { + be16 tlv_type; /* PAC_TYPE_PAC_TYPE */ + be16 length; + be16 pac_type; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + +#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0 +#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1 + +#define EAP_TLV_ACTION_PROCESS_TLV 1 +#define EAP_TLV_ACTION_NEGOTIATE_EAP 2 + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_TLV_COMMON_H */ diff --cc libeap/src/eap_common/eap_ttls.h index 08f371c,0000000..f439da2 mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_ttls.h +++ b/libeap/src/eap_common/eap_ttls.h @@@ -1,84 -1,0 +1,78 @@@ +/* + * EAP server/peer: EAP-TTLS (RFC 5281) + * Copyright (c) 2004-2007, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_TTLS_H +#define EAP_TTLS_H + +#ifdef __cplusplus +extern "C" { +#endif + +struct ttls_avp { + be32 avp_code; + be32 avp_length; /* 8-bit flags, 24-bit length; + * length includes AVP header */ + /* optional 32-bit Vendor-ID */ + /* Data */ +}; + +struct ttls_avp_vendor { + be32 avp_code; + be32 avp_length; /* 8-bit flags, 24-bit length; + * length includes AVP header */ + be32 vendor_id; + /* Data */ +}; + + +#define AVP_FLAGS_VENDOR 0x80 +#define AVP_FLAGS_MANDATORY 0x40 + +#define AVP_PAD(start, pos) \ +do { \ + int __pad; \ + __pad = (4 - (((pos) - (start)) & 3)) & 3; \ + os_memset((pos), 0, __pad); \ + pos += __pad; \ +} while (0) + + +/* RFC 2865 */ +#define RADIUS_ATTR_USER_NAME 1 +#define RADIUS_ATTR_USER_PASSWORD 2 +#define RADIUS_ATTR_CHAP_PASSWORD 3 +#define RADIUS_ATTR_REPLY_MESSAGE 18 +#define RADIUS_ATTR_VENDOR_SPECIFIC 26 +#define RADIUS_ATTR_CHAP_CHALLENGE 60 +#define RADIUS_ATTR_EAP_MESSAGE 79 + +/* RFC 2548 */ +#define RADIUS_VENDOR_ID_MICROSOFT 311 +#define RADIUS_ATTR_MS_CHAP_RESPONSE 1 +#define RADIUS_ATTR_MS_CHAP_ERROR 2 +#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6 +#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11 +#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25 +#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26 +#define RADIUS_ATTR_MS_CHAP2_CPW 27 + +#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16 +#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50 +#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8 +#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50 +#define EAP_TTLS_CHAP_CHALLENGE_LEN 16 +#define EAP_TTLS_CHAP_PASSWORD_LEN 16 + +#define RADIUS_VENDOR_ID_UKERNA 25622 +#define RADIUS_ATTR_UKERNA_CHBIND 135 + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_TTLS_H */ diff --cc libeap/src/eap_common/eap_wsc_common.h index 2d88b5a,0000000..6914216 mode 100644,000000..100644 --- a/libeap/src/eap_common/eap_wsc_common.h +++ b/libeap/src/eap_common/eap_wsc_common.h @@@ -1,41 -1,0 +1,35 @@@ +/* + * EAP-WSC definitions for Wi-Fi Protected Setup + * Copyright (c) 2007, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_WSC_COMMON_H +#define EAP_WSC_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define EAP_VENDOR_TYPE_WSC 1 + +#define WSC_FLAGS_MF 0x01 +#define WSC_FLAGS_LF 0x02 + +#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0" +#define WSC_ID_REGISTRAR_LEN 30 +#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0" +#define WSC_ID_ENROLLEE_LEN 29 + +#define WSC_FRAGMENT_SIZE 1400 + + +struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_WSC_COMMON_H */ diff --cc libeap/src/eap_peer/eap.h index 6a1b511,0000000..831db76 mode 100644,000000..100644 --- a/libeap/src/eap_peer/eap.h +++ b/libeap/src/eap_peer/eap.h @@@ -1,299 -1,0 +1,362 @@@ +/* + * EAP peer state machine functions (RFC 4137) - * Copyright (c) 2004-2007, Jouni Malinen ++ * Copyright (c) 2004-2012, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_H +#define EAP_H + +#include "common/defs.h" +#include "eap_common/eap_defs.h" +#include "eap_peer/eap_methods.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct eap_sm; +struct wpa_config_blob; +struct wpabuf; + +struct eap_method_type { + int vendor; + u32 method; +}; + +#ifdef IEEE8021X_EAPOL + +/** + * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine + * + * These variables are used in the interface between EAP peer state machine and + * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is + * expected to maintain these variables and register a callback functions for + * EAP state machine to get and set the variables. + */ +enum eapol_bool_var { + /** + * EAPOL_eapSuccess - EAP SUCCESS state reached + * + * EAP state machine reads and writes this value. + */ + EAPOL_eapSuccess, + + /** + * EAPOL_eapRestart - Lower layer request to restart authentication + * + * Set to TRUE in lower layer, FALSE in EAP state machine. + */ + EAPOL_eapRestart, + + /** + * EAPOL_eapFail - EAP FAILURE state reached + * + * EAP state machine writes this value. + */ + EAPOL_eapFail, + + /** + * EAPOL_eapResp - Response to send + * + * Set to TRUE in EAP state machine, FALSE in lower layer. + */ + EAPOL_eapResp, + + /** + * EAPOL_eapNoResp - Request has been process; no response to send + * + * Set to TRUE in EAP state machine, FALSE in lower layer. + */ + EAPOL_eapNoResp, + + /** + * EAPOL_eapReq - EAP request available from lower layer + * + * Set to TRUE in lower layer, FALSE in EAP state machine. + */ + EAPOL_eapReq, + + /** + * EAPOL_portEnabled - Lower layer is ready for communication + * + * EAP state machines reads this value. + */ + EAPOL_portEnabled, + + /** + * EAPOL_altAccept - Alternate indication of success (RFC3748) + * + * EAP state machines reads this value. + */ + EAPOL_altAccept, + + /** + * EAPOL_altReject - Alternate indication of failure (RFC3748) + * + * EAP state machines reads this value. + */ - EAPOL_altReject ++ EAPOL_altReject, ++ ++ /** ++ * EAPOL_eapTriggerStart - EAP-based trigger to send EAPOL-Start ++ * ++ * EAP state machine writes this value. ++ */ ++ EAPOL_eapTriggerStart +}; + +/** + * enum eapol_int_var - EAPOL integer state variables for EAP state machine + * + * These variables are used in the interface between EAP peer state machine and + * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is + * expected to maintain these variables and register a callback functions for + * EAP state machine to get and set the variables. + */ +enum eapol_int_var { + /** + * EAPOL_idleWhile - Outside time for EAP peer timeout + * + * This integer variable is used to provide an outside timer that the + * external (to EAP state machine) code must decrement by one every + * second until the value reaches zero. This is used in the same way as + * EAPOL state machine timers. EAP state machine reads and writes this + * value. + */ + EAPOL_idleWhile +}; + +/** + * struct eapol_callbacks - Callback functions from EAP to lower layer + * + * This structure defines the callback functions that EAP state machine + * requires from the lower layer (usually EAPOL state machine) for updating + * state variables and requesting information. eapol_ctx from + * eap_peer_sm_init() call will be used as the ctx parameter for these + * callback functions. + */ +struct eapol_callbacks { + /** + * get_config - Get pointer to the current network configuration + * @ctx: eapol_ctx from eap_peer_sm_init() call + */ + struct eap_peer_config * (*get_config)(void *ctx); + + /** + * get_bool - Get a boolean EAPOL state variable + * @variable: EAPOL boolean variable to get + * Returns: Value of the EAPOL variable + */ + Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable); + + /** + * set_bool - Set a boolean EAPOL state variable + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @variable: EAPOL boolean variable to set + * @value: Value for the EAPOL variable + */ + void (*set_bool)(void *ctx, enum eapol_bool_var variable, + Boolean value); + + /** + * get_int - Get an integer EAPOL state variable + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @variable: EAPOL integer variable to get + * Returns: Value of the EAPOL variable + */ + unsigned int (*get_int)(void *ctx, enum eapol_int_var variable); + + /** + * set_int - Set an integer EAPOL state variable + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @variable: EAPOL integer variable to set + * @value: Value for the EAPOL variable + */ + void (*set_int)(void *ctx, enum eapol_int_var variable, + unsigned int value); + + /** + * get_eapReqData - Get EAP-Request data + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @len: Pointer to variable that will be set to eapReqDataLen + * Returns: Reference to eapReqData (EAP state machine will not free + * this) or %NULL if eapReqData not available. + */ + struct wpabuf * (*get_eapReqData)(void *ctx); + + /** + * set_config_blob - Set named configuration blob + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @blob: New value for the blob + * + * Adds a new configuration blob or replaces the current value of an + * existing blob. + */ + void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob); + + /** + * get_config_blob - Get a named configuration blob + * @ctx: eapol_ctx from eap_peer_sm_init() call + * @name: Name of the blob + * Returns: Pointer to blob data or %NULL if not found + */ + const struct wpa_config_blob * (*get_config_blob)(void *ctx, + const char *name); + + /** + * notify_pending - Notify that a pending request can be retried + * @ctx: eapol_ctx from eap_peer_sm_init() call + * + * An EAP method can perform a pending operation (e.g., to get a + * response from an external process). Once the response is available, + * this callback function can be used to request EAPOL state machine to + * retry delivering the previously received (and still unanswered) EAP + * request to EAP state machine. + */ + void (*notify_pending)(void *ctx); + + /** + * eap_param_needed - Notify that EAP parameter is needed + * @ctx: eapol_ctx from eap_peer_sm_init() call - * @field: Field name (e.g., "IDENTITY") ++ * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY) + * @txt: User readable text describing the required parameter + */ - void (*eap_param_needed)(void *ctx, const char *field, ++ void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field, + const char *txt); ++ ++ /** ++ * notify_cert - Notification of a peer certificate ++ * @ctx: eapol_ctx from eap_peer_sm_init() call ++ * @depth: Depth in certificate chain (0 = server) ++ * @subject: Subject of the peer certificate ++ * @altsubject: Select fields from AltSubject of the peer certificate ++ * @num_altsubject: Number of altsubject values ++ * @cert_hash: SHA-256 hash of the certificate ++ * @cert: Peer certificate ++ */ ++ void (*notify_cert)(void *ctx, int depth, const char *subject, ++ const char *altsubject[], int num_altsubject, ++ const char *cert_hash, const struct wpabuf *cert); ++ ++ /** ++ * notify_status - Notification of the current EAP state ++ * @ctx: eapol_ctx from eap_peer_sm_init() call ++ * @status: Step in the process of EAP authentication ++ * @parameter: Step-specific parameter, e.g., EAP method name ++ */ ++ void (*notify_status)(void *ctx, const char *status, ++ const char *parameter); ++ ++#ifdef CONFIG_EAP_PROXY ++ /** ++ * eap_proxy_cb - Callback signifying any updates from eap_proxy ++ * @ctx: eapol_ctx from eap_peer_sm_init() call ++ */ ++ void (*eap_proxy_cb)(void *ctx); ++#endif /* CONFIG_EAP_PROXY */ ++ ++ /** ++ * set_anon_id - Set or add anonymous identity ++ * @ctx: eapol_ctx from eap_peer_sm_init() call ++ * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear ++ * @len: Length of anonymous identity in octets ++ */ ++ void (*set_anon_id)(void *ctx, const u8 *id, size_t len); +}; + +/** + * struct eap_config - Configuration for EAP state machine + */ +struct eap_config { + /** + * opensc_engine_path - OpenSC engine for OpenSSL engine support + * + * Usually, path to engine_opensc.so. + */ + const char *opensc_engine_path; + /** + * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support + * + * Usually, path to engine_pkcs11.so. + */ + const char *pkcs11_engine_path; + /** + * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine + * + * Usually, path to opensc-pkcs11.so. + */ + const char *pkcs11_module_path; + /** ++ * openssl_ciphers - OpenSSL cipher string ++ * ++ * This is an OpenSSL specific configuration option for configuring the ++ * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the ++ * default. ++ */ ++ const char *openssl_ciphers; ++ /** + * wps - WPS context data + * + * This is only used by EAP-WSC and can be left %NULL if not available. + */ + struct wps_context *wps; ++ ++ /** ++ * cert_in_cb - Include server certificates in callback ++ */ ++ int cert_in_cb; +}; + +struct eap_sm * eap_peer_sm_init(void *eapol_ctx, - struct eapol_callbacks *eapol_cb, ++ const struct eapol_callbacks *eapol_cb, + void *msg_ctx, struct eap_config *conf); +void eap_peer_sm_deinit(struct eap_sm *sm); +int eap_peer_sm_step(struct eap_sm *sm); +void eap_sm_abort(struct eap_sm *sm); +int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, + int verbose); ++const char * eap_sm_get_method_name(struct eap_sm *sm); +struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted); +void eap_sm_request_identity(struct eap_sm *sm); +void eap_sm_request_password(struct eap_sm *sm); +void eap_sm_request_new_password(struct eap_sm *sm); +void eap_sm_request_pin(struct eap_sm *sm); +void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len); +void eap_sm_request_passphrase(struct eap_sm *sm); ++void eap_sm_request_sim(struct eap_sm *sm, const char *req); +void eap_sm_notify_ctrl_attached(struct eap_sm *sm); +u32 eap_get_phase2_type(const char *name, int *vendor); +struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config, + size_t *count); +void eap_set_fast_reauth(struct eap_sm *sm, int enabled); +void eap_set_workaround(struct eap_sm *sm, unsigned int workaround); +void eap_set_force_disabled(struct eap_sm *sm, int disabled); ++void eap_set_external_sim(struct eap_sm *sm, int external_sim); +int eap_key_available(struct eap_sm *sm); +void eap_notify_success(struct eap_sm *sm); +void eap_notify_lower_layer_success(struct eap_sm *sm); ++const u8 * eap_get_eapSessionId(struct eap_sm *sm, size_t *len); +const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len); +struct wpabuf * eap_get_eapRespData(struct eap_sm *sm); +void eap_register_scard_ctx(struct eap_sm *sm, void *ctx); +void eap_invalidate_cached_session(struct eap_sm *sm); + +int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf); +int eap_is_wps_pin_enrollee(struct eap_peer_config *conf); + ++struct ext_password_data; ++void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext); ++void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len); ++int eap_peer_was_failure_expected(struct eap_sm *sm); ++void eap_peer_erp_free_keys(struct eap_sm *sm); ++ +#endif /* IEEE8021X_EAPOL */ + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_H */ diff --cc libeap/src/eap_peer/eap_config.h index c78fba1,0000000..0b0824b mode 100644,000000..100644 --- a/libeap/src/eap_peer/eap_config.h +++ b/libeap/src/eap_peer/eap_config.h @@@ -1,711 -1,0 +1,816 @@@ +/* + * EAP peer configuration data - * Copyright (c) 2003-2008, Jouni Malinen ++ * Copyright (c) 2003-2013, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_CONFIG_H +#define EAP_CONFIG_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3.1 */ +#define CHBIND_CODE_REQUEST 1 +#define CHBIND_CODE_SUCCESS 2 +#define CHBIND_CODE_FAILURE 3 +/* http://tools.ietf.org/html/draft-ietf-emu-chbind-13#section-5.3. */ +#define CHBIND_NSID_RADIUS 1 + +struct eap_peer_chbind_config +{ + /* namespace id for this channel binding info */ + int nsid; + + /* data to be sent in channel binding request */ + u8 *req_data; + + size_t req_data_len; + + /* lower level callback invoked when response is received */ + void (*response_cb)(void *ctx, int code, int nsid, u8 *resp_data, size_t resp_data_len); + + /* context for response callback */ + void *ctx; +}; + +/** + * struct eap_peer_config - EAP peer configuration/credentials + */ +struct eap_peer_config { + /** + * identity - EAP Identity + * + * This field is used to set the real user identity or NAI (for + * EAP-PSK/PAX/SAKE/GPSK). + */ + u8 *identity; + + /** + * identity_len - EAP Identity length + */ + size_t identity_len; + + /** + * anonymous_identity - Anonymous EAP Identity + * + * This field is used for unencrypted use with EAP types that support + * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the + * real identity (identity field) only to the authentication server. + * + * If not set, the identity field will be used for both unencrypted and + * protected fields. ++ * ++ * This field can also be used with EAP-SIM/AKA/AKA' to store the ++ * pseudonym identity. + */ + u8 *anonymous_identity; + + /** + * anonymous_identity_len - Length of anonymous_identity + */ + size_t anonymous_identity_len; + + /** + * password - Password string for EAP + * + * This field can include either the plaintext password (default + * option) or a NtPasswordHash (16-byte MD4 hash of the unicode + * presentation of the password) if flags field has + * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can + * only be used with authentication mechanism that use this hash as the + * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2, + * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP). + * + * In addition, this field is used to configure a pre-shared key for + * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK + * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length + * PSK. + */ + u8 *password; + + /** + * password_len - Length of password field + */ + size_t password_len; + + /** + * ca_cert - File path to CA certificate file (PEM/DER) + * + * This file can have one or more trusted CA certificates. If ca_cert + * and ca_path are not included, server certificate will not be + * verified. This is insecure and a trusted CA certificate should + * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + * + * Alternatively, this can be used to only perform matching of the + * server certificate (SHA-256 hash of the DER encoded X.509 + * certificate). In this case, the possible CA certificates in the + * server certificate chain are ignored and only the server certificate + * is verified. This is configured with the following format: + * hash:://server/sha256/cert_hash_in_hex + * For example: "hash://server/sha256/ + * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a" + * + * On Windows, trusted CA certificates can be loaded from the system + * certificate store by setting this to cert_store://name, e.g., + * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT". + * Note that when running wpa_supplicant as an application, the user + * certificate store (My user account) is used, whereas computer store + * (Computer account) is used when running wpasvc as a service. + */ + u8 *ca_cert; + + /** + * ca_path - Directory path for CA certificate files (PEM) + * + * This path may contain multiple CA certificates in OpenSSL format. + * Common use for this is to point to system trusted CA list which is + * often installed into directory like /etc/ssl/certs. If configured, + * these certificates are added to the list of trusted CAs. ca_cert + * may also be included in that case, but it is not required. + */ + u8 *ca_path; + + /** + * client_cert - File path to client certificate file (PEM/DER) + * + * This field is used with EAP method that use TLS authentication. + * Usually, this is only configured for EAP-TLS, even though this could + * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *client_cert; + + /** + * private_key - File path to client private key file (PEM/DER/PFX) + * + * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be + * commented out. Both the private key and certificate will be read + * from the PKCS#12 file in this case. Full path to the file should be + * used since working directory may change when wpa_supplicant is run + * in the background. + * + * Windows certificate store can be used by leaving client_cert out and + * configuring private_key in one of the following formats: + * + * cert://substring_to_match + * + * hash://certificate_thumbprint_in_hex + * + * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4" + * + * Note that when running wpa_supplicant as an application, the user + * certificate store (My user account) is used, whereas computer store + * (Computer account) is used when running wpasvc as a service. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *private_key; + + /** + * private_key_passwd - Password for private key file + * + * If left out, this will be asked through control interface. + */ - u8 *private_key_passwd; ++ char *private_key_passwd; + + /** + * dh_file - File path to DH/DSA parameters file (in PEM format) + * + * This is an optional configuration file for setting parameters for an + * ephemeral DH key exchange. In most cases, the default RSA + * authentication does not use this configuration. However, it is + * possible setup RSA to use ephemeral DH key exchange. In addition, + * ciphers with DSA keys always use ephemeral DH keys. This can be used + * to achieve forward secrecy. If the file is in DSA parameters format, + * it will be automatically converted into DH params. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *dh_file; + + /** + * subject_match - Constraint for server certificate subject + * + * This substring is matched against the subject of the authentication + * server certificate. If this string is set, the server sertificate is + * only accepted if it contains this string in the subject. The subject + * string is in following format: + * + * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com ++ * ++ * Note: Since this is a substring match, this cannot be used securily ++ * to do a suffix match against a possible domain name in the CN entry. ++ * For such a use case, domain_suffix_match should be used instead. + */ + u8 *subject_match; + + /** + * altsubject_match - Constraint for server certificate alt. subject + * + * Semicolon separated string of entries to be matched against the + * alternative subject name of the authentication server certificate. + * If this string is set, the server sertificate is only accepted if it + * contains one of the entries in an alternative subject name + * extension. + * + * altSubjectName string is in following format: TYPE:VALUE + * + * Example: EMAIL:server@example.com + * Example: DNS:server.example.com;DNS:server2.example.com + * + * Following types are supported: EMAIL, DNS, URI + */ + u8 *altsubject_match; + + /** ++ * domain_suffix_match - Constraint for server domain name ++ * ++ * If set, this FQDN is used as a suffix match requirement for the ++ * server certificate in SubjectAltName dNSName element(s). If a ++ * matching dNSName is found, this constraint is met. If no dNSName ++ * values are present, this constraint is matched against SubjectName CN ++ * using same suffix match comparison. Suffix match here means that the ++ * host/domain name is compared one label at a time starting from the ++ * top-level domain and all the labels in domain_suffix_match shall be ++ * included in the certificate. The certificate may include additional ++ * sub-level labels in addition to the required labels. ++ * ++ * For example, domain_suffix_match=example.com would match ++ * test.example.com but would not match test-example.com. ++ */ ++ char *domain_suffix_match; ++ ++ /** ++ * domain_match - Constraint for server domain name ++ * ++ * If set, this FQDN is used as a full match requirement for the ++ * server certificate in SubjectAltName dNSName element(s). If a ++ * matching dNSName is found, this constraint is met. If no dNSName ++ * values are present, this constraint is matched against SubjectName CN ++ * using same full match comparison. This behavior is similar to ++ * domain_suffix_match, but has the requirement of a full match, i.e., ++ * no subdomains or wildcard matches are allowed. Case-insensitive ++ * comparison is used, so "Example.com" matches "example.com", but would ++ * not match "test.Example.com". ++ */ ++ char *domain_match; ++ ++ /** + * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2) + * + * This file can have one or more trusted CA certificates. If ca_cert2 + * and ca_path2 are not included, server certificate will not be + * verified. This is insecure and a trusted CA certificate should + * always be configured. Full path to the file should be used since + * working directory may change when wpa_supplicant is run in the + * background. + * + * This field is like ca_cert, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *ca_cert2; + + /** + * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2) + * + * This path may contain multiple CA certificates in OpenSSL format. + * Common use for this is to point to system trusted CA list which is + * often installed into directory like /etc/ssl/certs. If configured, + * these certificates are added to the list of trusted CAs. ca_cert + * may also be included in that case, but it is not required. + * + * This field is like ca_path, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + u8 *ca_path2; + + /** + * client_cert2 - File path to client certificate file + * + * This field is like client_cert, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *client_cert2; + + /** + * private_key2 - File path to client private key file + * + * This field is like private_key, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the + * file should be used since working directory may change when + * wpa_supplicant is run in the background. + * + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + u8 *private_key2; + + /** + * private_key2_passwd - Password for private key file + * + * This field is like private_key_passwd, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ - u8 *private_key2_passwd; ++ 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. ++ * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS. "mschapv2_retry=0" can ++ * be used to disable MSCHAPv2 password retry in authentication failure ++ * cases. + */ + char *phase2; + + /** + * pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM + * + * This field is used to configure PC/SC smartcard interface. + * Currently, the only configuration is whether this field is %NULL (do + * not use PC/SC) or non-NULL (e.g., "") to enable PC/SC. + * + * This field is used for EAP-SIM and EAP-AKA. + */ + char *pcsc; + + /** + * pin - PIN for USIM, GSM SIM, and smartcards + * + * This field is used to configure PIN for SIM and smartcards for + * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a + * smartcard is used for private key operations. + * + * If left out, this will be asked through control interface. + */ + char *pin; + + /** + * engine - Enable OpenSSL engine (e.g., for smartcard access) + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + */ + int engine; + + /** + * engine_id - Engine ID for OpenSSL engine + * + * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 + * engine. + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + */ + char *engine_id; + + /** + * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2) + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + * + * This field is like engine, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + int engine2; + + + /** + * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2) + * + * This field is used to configure PIN for SIM and smartcards for + * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a + * smartcard is used for private key operations. + * + * This field is like pin2, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + * + * If left out, this will be asked through control interface. + */ + char *pin2; + + /** + * engine2_id - Engine ID for OpenSSL engine (Phase 2) + * + * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11 + * engine. + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + * + * This field is like engine_id, but used for phase 2 (inside + * EAP-TTLS/PEAP/FAST tunnel) authentication. + */ + char *engine2_id; + + + /** + * key_id - Key ID for OpenSSL engine + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + */ + char *key_id; + + /** + * cert_id - Cert ID for OpenSSL engine + * + * This is used if the certificate operations for EAP-TLS are performed + * using a smartcard. + */ + char *cert_id; + + /** + * ca_cert_id - CA Cert ID for OpenSSL engine + * + * This is used if the CA certificate for EAP-TLS is on a smartcard. + */ + char *ca_cert_id; + + /** + * key2_id - Key ID for OpenSSL engine (phase2) + * + * This is used if private key operations for EAP-TLS are performed + * using a smartcard. + */ + char *key2_id; + + /** + * cert2_id - Cert ID for OpenSSL engine (phase2) + * + * This is used if the certificate operations for EAP-TLS are performed + * using a smartcard. + */ + char *cert2_id; + + /** + * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2) + * + * This is used if the CA certificate for EAP-TLS is on a smartcard. + */ + char *ca_cert2_id; + + /** + * otp - One-time-password + * + * This field should not be set in configuration step. It is only used + * internally when OTP is entered through the control interface. + */ + u8 *otp; + + /** + * otp_len - Length of the otp field + */ + size_t otp_len; + + /** + * pending_req_identity - Whether there is a pending identity request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_identity; + + /** + * pending_req_password - Whether there is a pending password request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_password; + + /** + * pending_req_pin - Whether there is a pending PIN request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_pin; + + /** + * pending_req_new_password - Pending password update request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_new_password; + + /** + * pending_req_passphrase - Pending passphrase request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + int pending_req_passphrase; + + /** + * pending_req_otp - Whether there is a pending OTP request + * + * This field should not be set in configuration step. It is only used + * internally when control interface is used to request needed + * information. + */ + char *pending_req_otp; + + /** + * pending_req_otp_len - Length of the pending OTP request + */ + size_t pending_req_otp_len; + + /** + * pac_file - File path or blob name for the PAC entries (EAP-FAST) + * + * wpa_supplicant will need to be able to create this file and write + * updates to it when PAC is being provisioned or refreshed. Full path + * to the file should be used since working directory may change when + * wpa_supplicant is run in the background. + * Alternatively, a named configuration blob can be used by setting + * this to blob://blob_name. + */ + char *pac_file; + + /** + * mschapv2_retry - MSCHAPv2 retry in progress + * + * This field is used internally by EAP-MSCHAPv2 and should not be set + * as part of configuration. + */ + int mschapv2_retry; + + /** + * new_password - New password for password update + * + * This field is used during MSCHAPv2 password update. This is normally + * requested from the user through the control interface and not set + * from configuration. + */ + u8 *new_password; + + /** + * new_password_len - Length of new_password field + */ + size_t new_password_len; + + /** + * fragment_size - Maximum EAP fragment size in bytes (default 1398) + * + * This value limits the fragment size for EAP methods that support + * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set + * small enough to make the EAP messages fit in MTU of the network + * interface used for EAPOL. The default value is suitable for most + * cases. + */ + int fragment_size; + + /** + * chbind_config - eap channel binding config data + */ + struct eap_peer_chbind_config *chbind_config; + + /** + * chbind_config_len - channel binding config data count + */ + size_t chbind_config_len; + +#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0) ++#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1) + /** + * flags - Network configuration flags (bitfield) + * + * This variable is used for internal flags to describe further details + * for the network parameters. + * bit 0 = password is represented as a 16-byte NtPasswordHash value + * instead of plaintext password ++ * bit 1 = password is stored in external storage; the value in the ++ * password field is the name of that external entry + */ + u32 flags; ++ ++ /** ++ * ocsp - Whether to use/require OCSP to check server certificate ++ * ++ * 0 = do not use OCSP stapling (TLS certificate status extension) ++ * 1 = try to use OCSP stapling, but not require response ++ * 2 = require valid OCSP stapling response ++ */ ++ int ocsp; ++ ++ /** ++ * external_sim_resp - Response from external SIM processing ++ * ++ * This field should not be set in configuration step. It is only used ++ * internally when control interface is used to request external ++ * SIM/USIM processing. ++ */ ++ char *external_sim_resp; ++ ++ /** ++ * sim_num - User selected SIM identifier ++ * ++ * This variable is used for identifying which SIM is used if the system ++ * has more than one. ++ */ ++ int sim_num; ++ ++ /** ++ * openssl_ciphers - OpenSSL cipher string ++ * ++ * This is an OpenSSL specific configuration option for configuring the ++ * ciphers for this connection. If not set, the default cipher suite ++ * list is used. ++ */ ++ char *openssl_ciphers; ++ ++ /** ++ * erp - Whether EAP Re-authentication Protocol (ERP) is enabled ++ */ ++ int erp; +}; + + +/** + * struct wpa_config_blob - Named configuration blob + * + * This data structure is used to provide storage for binary objects to store + * abstract information like certificates and private keys inlined with the + * configuration data. + */ +struct wpa_config_blob { + /** + * name - Blob name + */ + char *name; + + /** + * data - Pointer to binary data + */ + u8 *data; + + /** + * len - Length of binary data + */ + size_t len; + + /** + * next - Pointer to next blob in the configuration + */ + struct wpa_config_blob *next; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_CONFIG_H */ diff --cc libeap/src/eap_peer/eap_eke.c index 0000000,dfbda56..dfbda56 mode 000000,100644..100644 --- a/libeap/src/eap_peer/eap_eke.c +++ b/libeap/src/eap_peer/eap_eke.c diff --cc libeap/src/eap_peer/eap_i.h index d6c391c,0000000..5d915fa mode 100644,000000..100644 --- a/libeap/src/eap_peer/eap_i.h +++ b/libeap/src/eap_peer/eap_i.h @@@ -1,364 -1,0 +1,397 @@@ +/* + * EAP peer state machines internal structures (RFC 4137) - * Copyright (c) 2004-2007, Jouni Malinen ++ * Copyright (c) 2004-2014, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#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; - struct eapol_callbacks *eapol_cb; ++ 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_md5[16]; /* MD5() of the current EAP packet */ - u8 last_md5[16]; /* MD5() of the previously received EAP packet; used - * in duplicate request detection. */ ++ u8 req_sha1[20]; /* SHA1() of the current EAP packet */ ++ u8 last_sha1[20]; /* SHA1() of the previously received EAP packet; used ++ * in duplicate request detection. */ + + void *msg_ctx; + void *scard_ctx; + void *ssl_ctx; ++ void *ssl_ctx2; + + unsigned int workaround; + + /* Optional challenges generated in Phase 1 (EAP-FAST) */ + u8 *peer_challenge, *auth_challenge; + + int num_rounds; + int force_disabled; + + struct wps_context *wps; + + int prev_failure; ++ struct eap_peer_config *last_config; ++ ++ struct ext_password_data *ext_pw; ++ struct wpabuf *ext_pw_buf; ++ ++ int external_sim; ++ ++ unsigned int expected_failure:1; ++ ++ struct dl_list erp_keys; /* struct eap_erp_key */ +}; + +const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len); +const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len); +const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash); +const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len); +const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len); +void eap_clear_config_otp(struct eap_sm *sm); +const char * eap_get_config_phase1(struct eap_sm *sm); +const char * eap_get_config_phase2(struct eap_sm *sm); +int eap_get_config_fragment_size(struct eap_sm *sm); +struct eap_peer_config * eap_get_config(struct eap_sm *sm); +void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob); +const struct wpa_config_blob * +eap_get_config_blob(struct eap_sm *sm, const char *name); +void eap_notify_pending(struct eap_sm *sm); +int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_I_H */ diff --cc libeap/src/eap_peer/eap_methods.h index 8045a4d,0000000..11c3278 mode 100644,000000..100644 --- a/libeap/src/eap_peer/eap_methods.h +++ b/libeap/src/eap_peer/eap_methods.h @@@ -1,122 -1,0 +1,119 @@@ +/* + * EAP peer: Method registration + * Copyright (c) 2004-2007, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_METHODS_H +#define EAP_METHODS_H + +#include "eap_common/eap_defs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method); +const struct eap_method * eap_peer_get_methods(size_t *count); + +struct eap_method * eap_peer_method_alloc(int version, int vendor, + EapType method, const char *name); +void eap_peer_method_free(struct eap_method *method); +int eap_peer_method_register(struct eap_method *method); + + +#ifdef IEEE8021X_EAPOL + +EapType eap_peer_get_type(const char *name, int *vendor); +const char * eap_get_name(int vendor, EapType type); +size_t eap_get_names(char *buf, size_t buflen); +char ** eap_get_names_as_string_array(size_t *num); +void eap_peer_unregister_methods(void); + +#else /* IEEE8021X_EAPOL */ + +static inline EapType eap_peer_get_type(const char *name, int *vendor) +{ + *vendor = EAP_VENDOR_IETF; + return EAP_TYPE_NONE; +} + +static inline const char * eap_get_name(int vendor, EapType type) +{ + return NULL; +} + +static inline size_t eap_get_names(char *buf, size_t buflen) +{ + return 0; +} + +static inline int eap_peer_register_methods(void) +{ + return 0; +} + +static inline void eap_peer_unregister_methods(void) +{ +} + +static inline char ** eap_get_names_as_string_array(size_t *num) +{ + return NULL; +} + +#endif /* IEEE8021X_EAPOL */ + + +#ifdef CONFIG_DYNAMIC_EAP_METHODS + +int eap_peer_method_load(const char *so); +int eap_peer_method_unload(struct eap_method *method); + +#else /* CONFIG_DYNAMIC_EAP_METHODS */ + +static inline int eap_peer_method_load(const char *so UNUSED) +{ + return 0; +} + +static inline int eap_peer_method_unload(struct eap_method *method UNUSED) +{ + return 0; +} + +#endif /* CONFIG_DYNAMIC_EAP_METHODS */ + +/* EAP peer method registration calls for statically linked in methods */ +int eap_peer_md5_register(void); +int eap_peer_tls_register(void); ++int eap_peer_unauth_tls_register(void); ++int eap_peer_wfa_unauth_tls_register(void); +int eap_peer_mschapv2_register(void); +int eap_peer_peap_register(void); +int eap_peer_ttls_register(void); +int eap_peer_gtc_register(void); +int eap_peer_otp_register(void); +int eap_peer_sim_register(void); +int eap_peer_leap_register(void); +int eap_peer_psk_register(void); +int eap_peer_aka_register(void); +int eap_peer_aka_prime_register(void); +int eap_peer_fast_register(void); +int eap_peer_pax_register(void); +int eap_peer_sake_register(void); +int eap_peer_gpsk_register(void); +int eap_peer_wsc_register(void); +int eap_peer_ikev2_register(void); +int eap_peer_vendor_test_register(void); +int eap_peer_tnc_register(void); +int eap_peer_pwd_register(void); ++int eap_peer_eke_register(void); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_METHODS_H */ diff --cc libeap/src/eap_peer/eap_proxy.h index 0000000,23cdbe6..23cdbe6 mode 000000,100644..100644 --- a/libeap/src/eap_peer/eap_proxy.h +++ b/libeap/src/eap_peer/eap_proxy.h diff --cc libeap/src/eap_peer/eap_proxy_dummy.c index 0000000,d84f012..d84f012 mode 000000,100644..100644 --- a/libeap/src/eap_peer/eap_proxy_dummy.c +++ b/libeap/src/eap_peer/eap_proxy_dummy.c diff --cc libeap/src/eap_peer/eap_tls_common.c index 8559c4d,0000000..b1f9300 mode 100644,000000..100644 --- a/libeap/src/eap_peer/eap_tls_common.c +++ b/libeap/src/eap_peer/eap_tls_common.c @@@ -1,1016 -1,0 +1,1111 @@@ +/* + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2009, Jouni Malinen ++ * Copyright (c) 2004-2013, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#include "includes.h" + +#include "common.h" +#include "crypto/sha1.h" +#include "crypto/tls.h" +#include "eap_i.h" +#include "eap_tls_common.h" +#include "eap_config.h" + + ++static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len, ++ u8 code, u8 identifier) ++{ ++ if (type == EAP_UNAUTH_TLS_TYPE) ++ return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS, ++ EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len, ++ code, identifier); ++ if (type == EAP_WFA_UNAUTH_TLS_TYPE) ++ return eap_msg_alloc(EAP_VENDOR_WFA_NEW, ++ EAP_VENDOR_WFA_UNAUTH_TLS, payload_len, ++ code, identifier); ++ return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code, ++ identifier); ++} ++ ++ +static int eap_tls_check_blob(struct eap_sm *sm, const char **name, + const u8 **data, size_t *data_len) +{ + const struct wpa_config_blob *blob; + + if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0) + return 0; + + blob = eap_get_config_blob(sm, *name + 7); + if (blob == NULL) { + wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not " + "found", __func__, *name + 7); + return -1; + } + + *name = NULL; + *data = blob->data; + *data_len = blob->len; + + return 0; +} + + +static void eap_tls_params_flags(struct tls_connection_params *params, + const char *txt) +{ + if (txt == NULL) + return; + if (os_strstr(txt, "tls_allow_md5=1")) + params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5; + if (os_strstr(txt, "tls_disable_time_checks=1")) + params->flags |= TLS_CONN_DISABLE_TIME_CHECKS; ++ if (os_strstr(txt, "tls_disable_session_ticket=1")) ++ params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; ++ if (os_strstr(txt, "tls_disable_session_ticket=0")) ++ params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET; ++ if (os_strstr(txt, "tls_disable_tlsv1_0=1")) ++ params->flags |= TLS_CONN_DISABLE_TLSv1_0; ++ if (os_strstr(txt, "tls_disable_tlsv1_0=0")) ++ params->flags &= ~TLS_CONN_DISABLE_TLSv1_0; ++ if (os_strstr(txt, "tls_disable_tlsv1_1=1")) ++ params->flags |= TLS_CONN_DISABLE_TLSv1_1; ++ if (os_strstr(txt, "tls_disable_tlsv1_1=0")) ++ params->flags &= ~TLS_CONN_DISABLE_TLSv1_1; ++ if (os_strstr(txt, "tls_disable_tlsv1_2=1")) ++ params->flags |= TLS_CONN_DISABLE_TLSv1_2; ++ if (os_strstr(txt, "tls_disable_tlsv1_2=0")) ++ params->flags &= ~TLS_CONN_DISABLE_TLSv1_2; +} + + +static void eap_tls_params_from_conf1(struct tls_connection_params *params, + struct eap_peer_config *config) +{ + params->ca_cert = (char *) config->ca_cert; + params->ca_path = (char *) config->ca_path; + params->client_cert = (char *) config->client_cert; + params->private_key = (char *) config->private_key; + params->private_key_passwd = (char *) config->private_key_passwd; + params->dh_file = (char *) config->dh_file; + params->subject_match = (char *) config->subject_match; + params->altsubject_match = (char *) config->altsubject_match; ++ params->suffix_match = config->domain_suffix_match; ++ params->domain_match = config->domain_match; + params->engine = config->engine; + params->engine_id = config->engine_id; + params->pin = config->pin; + params->key_id = config->key_id; + params->cert_id = config->cert_id; + params->ca_cert_id = config->ca_cert_id; + eap_tls_params_flags(params, config->phase1); +} + + +static void eap_tls_params_from_conf2(struct tls_connection_params *params, + struct eap_peer_config *config) +{ + params->ca_cert = (char *) config->ca_cert2; + params->ca_path = (char *) config->ca_path2; + params->client_cert = (char *) config->client_cert2; + params->private_key = (char *) config->private_key2; + params->private_key_passwd = (char *) config->private_key2_passwd; + params->dh_file = (char *) config->dh_file2; + params->subject_match = (char *) config->subject_match2; + params->altsubject_match = (char *) config->altsubject_match2; ++ params->suffix_match = config->domain_suffix_match2; ++ params->domain_match = config->domain_match2; + params->engine = config->engine2; + params->engine_id = config->engine2_id; + params->pin = config->pin2; + params->key_id = config->key2_id; + params->cert_id = config->cert2_id; + params->ca_cert_id = config->ca_cert2_id; + eap_tls_params_flags(params, config->phase2); +} + + +static int eap_tls_params_from_conf(struct eap_sm *sm, + struct eap_ssl_data *data, + struct tls_connection_params *params, + struct eap_peer_config *config, int phase2) +{ + os_memset(params, 0, sizeof(*params)); ++ if (sm->workaround && data->eap_type != EAP_TYPE_FAST) { ++ /* ++ * Some deployed authentication servers seem to be unable to ++ * handle the TLS Session Ticket extension (they are supposed ++ * to ignore unrecognized TLS extensions, but end up rejecting ++ * the ClientHello instead). As a workaround, disable use of ++ * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and ++ * EAP-TTLS (EAP-FAST uses session ticket, so any server that ++ * supports EAP-FAST does not need this workaround). ++ */ ++ params->flags |= TLS_CONN_DISABLE_SESSION_TICKET; ++ } + if (phase2) { + wpa_printf(MSG_DEBUG, "TLS: using phase2 config options"); + eap_tls_params_from_conf2(params, config); + } else { + wpa_printf(MSG_DEBUG, "TLS: using phase1 config options"); + eap_tls_params_from_conf1(params, config); ++ if (data->eap_type == EAP_TYPE_FAST) ++ params->flags |= TLS_CONN_EAP_FAST; + } - params->tls_ia = data->tls_ia; + + /* + * Use blob data, if available. Otherwise, leave reference to external + * file as-is. + */ + if (eap_tls_check_blob(sm, ¶ms->ca_cert, ¶ms->ca_cert_blob, + ¶ms->ca_cert_blob_len) || + eap_tls_check_blob(sm, ¶ms->client_cert, + ¶ms->client_cert_blob, + ¶ms->client_cert_blob_len) || + eap_tls_check_blob(sm, ¶ms->private_key, + ¶ms->private_key_blob, + ¶ms->private_key_blob_len) || + eap_tls_check_blob(sm, ¶ms->dh_file, ¶ms->dh_blob, + ¶ms->dh_blob_len)) { + wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs"); + return -1; + } + ++ params->openssl_ciphers = config->openssl_ciphers; ++ + return 0; +} + + +static int eap_tls_init_connection(struct eap_sm *sm, + struct eap_ssl_data *data, + struct eap_peer_config *config, + struct tls_connection_params *params) +{ + int res; + - data->conn = tls_connection_init(sm->ssl_ctx); ++ if (config->ocsp) ++ params->flags |= TLS_CONN_REQUEST_OCSP; ++ if (config->ocsp == 2) ++ params->flags |= TLS_CONN_REQUIRE_OCSP; ++ data->conn = tls_connection_init(data->ssl_ctx); + if (data->conn == NULL) { + wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS " + "connection"); + return -1; + } + - res = tls_connection_set_params(sm->ssl_ctx, data->conn, params); - if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) { ++ 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 might be wrong. - * We reset the PIN in the configuration to be sure to not use - * it again and the calling function must request a new one. ++ * 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"); - /* - * We do not know exactly but maybe the PIN was wrong, - * so ask for a new one. - */ - os_free(config->pin); - config->pin = NULL; - eap_sm_request_pin(sm); + sm->ignore = TRUE; - tls_connection_deinit(sm->ssl_ctx, data->conn); - data->conn = NULL; - return -1; - } else if (res) { ++ } ++ if (res) { + wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection " + "parameters"); - tls_connection_deinit(sm->ssl_ctx, data->conn); ++ 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) ++ 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, ¶ms, config, data->phase2) < + 0) + return -1; + + if (eap_tls_init_connection(sm, data, config, ¶ms) < 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(sm->ssl_ctx, data->conn); ++ 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) +{ - struct tls_keys keys; - u8 *rnd = NULL, *out; ++ u8 *out; + + out = os_malloc(len); + if (out == NULL) + return NULL; + - /* First, try to use TLS library function for PRF, if available. */ - if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) == - 0) - return out; ++ if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, 0, ++ out, len)) { ++ os_free(out); ++ return NULL; ++ } + - /* - * TLS library did not support key generation, so get the needed TLS - * session parameters and use an internal implementation of TLS PRF to - * derive the key. - */ - if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys)) - goto fail; - - if (keys.client_random == NULL || keys.server_random == NULL || - keys.master_key == NULL) - goto fail; - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - if (rnd == NULL) - goto fail; - os_memcpy(rnd, keys.client_random, keys.client_random_len); - os_memcpy(rnd + keys.client_random_len, keys.server_random, - keys.server_random_len); ++ return out; ++} + - if (tls_prf(keys.master_key, keys.master_key_len, - label, rnd, keys.client_random_len + - keys.server_random_len, out, len)) - goto fail; + - os_free(rnd); - 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)) ++ return NULL; ++ ++ if (keys.client_random == NULL || keys.server_random == NULL) ++ return NULL; ++ ++ *len = 1 + keys.client_random_len + keys.server_random_len; ++ out = os_malloc(*len); ++ if (out == NULL) ++ return NULL; ++ ++ /* Session-Id = EAP type || client.random || server.random */ ++ out[0] = eap_type; ++ os_memcpy(out + 1, keys.client_random, keys.client_random_len); ++ os_memcpy(out + 1 + keys.client_random_len, keys.server_random, ++ keys.server_random_len); + - fail: - os_free(out); - os_free(rnd); - return NULL; ++ 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; + } - wpabuf_put_buf(data->tls_in, in_data); ++ if (in_data) ++ wpabuf_put_buf(data->tls_in, in_data); + data->tls_in_left -= in_len; + + if (data->tls_in_left > 0) { + wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input " + "data", (unsigned long) data->tls_in_left); + return 1; + } + + return 0; +} + + +/** + * eap_peer_tls_data_reassemble - Reassemble TLS data + * @data: Data for TLS processing + * @in_data: Next incoming TLS segment + * @need_more_input: Variable for returning whether more input data is needed + * to reassemble this TLS packet + * Returns: Pointer to output data, %NULL on error or when more data is needed + * for the full message (in which case, *need_more_input is also set to 1). + * + * This function reassembles TLS fragments. Caller must not free the returned + * data buffer since an internal pointer to it is maintained. + */ +static const struct wpabuf * eap_peer_tls_data_reassemble( + struct eap_ssl_data *data, const struct wpabuf *in_data, + int *need_more_input) +{ + *need_more_input = 0; + + if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) { + /* Message has fragments */ + int res = eap_peer_tls_reassemble_fragment(data, in_data); + if (res) { + if (res == 1) + *need_more_input = 1; + return NULL; + } + + /* Message is now fully reassembled. */ + } else { + /* No fragments in this message, so just make a copy of it. */ + data->tls_in_left = 0; + data->tls_in = wpabuf_dup(in_data); + if (data->tls_in == NULL) + return NULL; + } + + return data->tls_in; +} + + +/** + * eap_tls_process_input - Process incoming TLS message + * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init() + * @data: Data for TLS processing + * @in_data: Message received from the server - * @in_len: Length of in_data + * @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 u8 *in_data, size_t in_len, ++ const struct wpabuf *in_data, + struct wpabuf **out_data) +{ + const struct wpabuf *msg; + int need_more_input; + struct wpabuf *appl_data; - struct wpabuf buf; + - wpabuf_set(&buf, in_data, in_len); - msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input); ++ 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(sm->ssl_ctx, data->conn, ++ data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn, + msg, &appl_data); + + eap_peer_tls_reset_input(data); + + if (appl_data && - tls_connection_established(sm->ssl_ctx, data->conn) && - !tls_connection_get_failed(sm->ssl_ctx, data->conn)) { ++ 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_msg_alloc(EAP_VENDOR_IETF, eap_type, - 1 + length_included * 4 + len, - EAP_CODE_RESPONSE, id); ++ *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 - * @in_len: Length of in_data + * @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 u8 *in_data, size_t in_len, ++ 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 && in_len > 0) { ++ 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, in_len, - out_data); ++ 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(sm->ssl_ctx, data->conn)) { ++ 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"); ++ "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 (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) { ++ 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_msg_alloc(EAP_VENDOR_IETF, eap_type, 1, EAP_CODE_RESPONSE, - id); ++ 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(sm->ssl_ctx, data->conn); ++ 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 name[128]; ++ char version[20], name[128]; + int len = 0, ret; + - if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) { - ret = os_snprintf(buf + len, buflen - len, - "EAP TLS cipher=%s\n", name); - if (ret < 0 || (size_t) ret >= buflen - len) - return len; - len += ret; - } ++ 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); - pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, &left); ++ ++ //// 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(sm->ssl_ctx, data->conn, msg); ++ *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(sm->ssl_ctx, data->conn, - in_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; - u8 method; ++ u32 method; + size_t num_methods = 0, prefix_len; + + if (config == NULL || config->phase2 == NULL) + goto get_defaults; + + start = buf = os_strdup(config->phase2); + if (buf == NULL) + return -1; + + prefix_len = os_strlen(prefix); + + while (start && *start != '\0') { + int vendor; + pos = os_strstr(start, prefix); + if (pos == NULL) + break; + if (start != pos && *(pos - 1) != ' ') { + start = pos + prefix_len; + continue; + } + + start = pos + prefix_len; + pos = os_strchr(start, ' '); + if (pos) + *pos++ = '\0'; + method = eap_get_phase2_type(start, &vendor); + if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) { + wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP " + "method '%s'", start); + } else { + num_methods++; - _methods = os_realloc(methods, - num_methods * sizeof(*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; +} diff --cc libeap/src/eap_peer/eap_tls_common.h index 53ed1a9,0000000..3f7f003 mode 100644,000000..100644 --- a/libeap/src/eap_peer/eap_tls_common.h +++ b/libeap/src/eap_peer/eap_tls_common.h @@@ -1,134 -1,0 +1,140 @@@ +/* + * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions - * Copyright (c) 2004-2009, Jouni Malinen ++ * Copyright (c) 2004-2009, 2012, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef EAP_TLS_COMMON_H +#define EAP_TLS_COMMON_H + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * struct eap_ssl_data - TLS data for EAP methods + */ +struct eap_ssl_data { + /** + * conn - TLS connection context data from tls_connection_init() + */ + struct tls_connection *conn; + + /** + * tls_out - TLS message to be sent out in fragments + */ + struct wpabuf *tls_out; + + /** + * tls_out_pos - The current position in the outgoing TLS message + */ + size_t tls_out_pos; + + /** + * tls_out_limit - Maximum fragment size for outgoing TLS messages + */ + size_t tls_out_limit; + + /** + * tls_in - Received TLS message buffer for re-assembly + */ + struct wpabuf *tls_in; + + /** + * tls_in_left - Number of remaining bytes in the incoming TLS message + */ + size_t tls_in_left; + + /** + * tls_in_total - Total number of bytes in the incoming TLS message + */ + size_t tls_in_total; + + /** + * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel) + */ + int phase2; + + /** + * include_tls_length - Whether the TLS length field is included even + * if the TLS data is not fragmented + */ + int include_tls_length; + + /** - * tls_ia - Whether TLS/IA is enabled for this TLS connection ++ * eap - EAP state machine allocated with eap_peer_sm_init() + */ - int tls_ia; ++ struct eap_sm *eap; + + /** - * eap - EAP state machine allocated with eap_peer_sm_init() ++ * ssl_ctx - TLS library context to use for the connection + */ - struct eap_sm *eap; ++ void *ssl_ctx; ++ ++ /** ++ * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST) ++ */ ++ u8 eap_type; +}; + + +/* EAP TLS Flags */ +#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80 +#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40 +#define EAP_TLS_FLAGS_START 0x20 +#define EAP_TLS_VERSION_MASK 0x07 + + /* could be up to 128 bytes, but only the first 64 bytes are used */ +#define EAP_TLS_KEY_LEN 64 + ++/* dummy type used as a flag for UNAUTH-TLS */ ++#define EAP_UNAUTH_TLS_TYPE 255 ++#define EAP_WFA_UNAUTH_TLS_TYPE 254 ++ + +int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data, - struct eap_peer_config *config); ++ struct eap_peer_config *config, u8 eap_type); +void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data); +u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data, + const char *label, size_t len); ++u8 * eap_peer_tls_derive_session_id(struct eap_sm *sm, ++ struct eap_ssl_data *data, u8 eap_type, ++ size_t *len); +int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data, + EapType eap_type, int peap_version, - u8 id, const u8 *in_data, size_t in_len, ++ u8 id, const struct wpabuf *in_data, + struct wpabuf **out_data); +struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type, + int peap_version); +int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data); +int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, + char *buf, size_t buflen, int verbose); +const u8 * eap_peer_tls_process_init(struct eap_sm *sm, + struct eap_ssl_data *data, + EapType eap_type, + struct eap_method_ret *ret, + const struct wpabuf *reqData, + size_t *len, u8 *flags); +void eap_peer_tls_reset_input(struct eap_ssl_data *data); +void eap_peer_tls_reset_output(struct eap_ssl_data *data); +int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data, + const struct wpabuf *in_data, + struct wpabuf **in_decrypted); +int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data, + EapType eap_type, int peap_version, u8 id, + const struct wpabuf *in_data, + struct wpabuf **out_data); +int eap_peer_select_phase2_methods(struct eap_peer_config *config, + const char *prefix, + struct eap_method_type **types, + size_t *num_types); +int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types, + struct eap_hdr *hdr, struct wpabuf **resp); + +#ifdef __cplusplus +} +#endif + +#endif /* EAP_TLS_COMMON_H */ diff --cc libeap/src/eap_peer/eap_ttls.c index 37e6bf3,0000000..c174fe5 mode 100644,000000..100644 --- a/libeap/src/eap_peer/eap_ttls.c +++ b/libeap/src/eap_peer/eap_ttls.c @@@ -1,2221 -1,0 +1,1956 @@@ +/* + * EAP peer method: EAP-TTLS (RFC 5281) - * Copyright (c) 2004-2008, Jouni Malinen ++ * Copyright (c) 2004-2011, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#include "includes.h" + +#include "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" + + - /* Maximum supported TTLS version - * 0 = RFC 5281 - * 1 = draft-funk-eap-ttls-v1-00.txt - */ - #ifndef EAP_TTLS_VERSION - #define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */ - #endif /* EAP_TTLS_VERSION */ - - - #define MSCHAPV2_KEY_LEN 16 - #define MSCHAPV2_NT_RESPONSE_LEN 24 ++#define EAP_TTLS_VERSION 0 + + +static void eap_ttls_deinit(struct eap_sm *sm, void *priv); + + +struct eap_ttls_data { + struct eap_ssl_data ssl; - int ssl_initialized; + - int ttls_version, force_ttls_version; ++ int ttls_version; + + const struct eap_method *phase2_method; + void *phase2_priv; + int phase2_success; + int phase2_start; + + enum phase2_types { + EAP_TTLS_PHASE2_EAP, + EAP_TTLS_PHASE2_MSCHAPV2, + EAP_TTLS_PHASE2_MSCHAP, + EAP_TTLS_PHASE2_PAP, + EAP_TTLS_PHASE2_CHAP + } phase2_type; + struct eap_method_type phase2_eap_type; + struct eap_method_type *phase2_eap_types; + size_t num_phase2_eap_types; + + u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN]; + int auth_response_valid; + u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */ + u8 ident; + int resuming; /* starting a resumed session */ + int reauth; /* reauthentication */ + u8 *key_data; ++ u8 *session_id; ++ size_t id_len; + + struct wpabuf *pending_phase2_req; + int chbind_req_sent; /* channel binding request was sent */ + int done_butfor_cb; /*we turned METHOD_DONE into METHOD_MAY_CONT to receive cb*/ + EapDecision cbDecision; +#ifdef EAP_TNC + int ready_for_tnc; + int tnc_started; +#endif /* EAP_TNC */ +}; + + +/* draft-ietf-emu-chbind-13 section 5.3 */ + +#ifdef _MSC_VER +#pragma pack(push, 1) +#endif /* _MSC_VER */ + +struct chbind_hdr { + u16 len; + u8 nsid; +} STRUCT_PACKED; + +#ifdef _MSC_VER +#pragma pack(pop) +#endif /* _MSC_VER */ + + + +static void * eap_ttls_init(struct eap_sm *sm) +{ + struct eap_ttls_data *data; + struct eap_peer_config *config = eap_get_config(sm); + char *selected; + + data = os_zalloc(sizeof(*data)); + if (data == NULL) + return NULL; + data->ttls_version = EAP_TTLS_VERSION; - data->force_ttls_version = -1; + selected = "EAP"; + data->phase2_type = EAP_TTLS_PHASE2_EAP; + - #if EAP_TTLS_VERSION > 0 - if (config && config->phase1) { - const char *pos = os_strstr(config->phase1, "ttlsver="); - if (pos) { - data->force_ttls_version = atoi(pos + 8); - data->ttls_version = data->force_ttls_version; - wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version " - "%d", data->force_ttls_version); - } - } - #endif /* EAP_TTLS_VERSION */ - + if (config && config->phase2) { + if (os_strstr(config->phase2, "autheap=")) { + selected = "EAP"; + data->phase2_type = EAP_TTLS_PHASE2_EAP; + } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) { + selected = "MSCHAPV2"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2; + } else if (os_strstr(config->phase2, "auth=MSCHAP")) { + selected = "MSCHAP"; + data->phase2_type = EAP_TTLS_PHASE2_MSCHAP; + } else if (os_strstr(config->phase2, "auth=PAP")) { + selected = "PAP"; + data->phase2_type = EAP_TTLS_PHASE2_PAP; + } else if (os_strstr(config->phase2, "auth=CHAP")) { + selected = "CHAP"; + data->phase2_type = EAP_TTLS_PHASE2_CHAP; + } + } + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected); + + if (data->phase2_type == EAP_TTLS_PHASE2_EAP) { + if (eap_peer_select_phase2_methods(config, "autheap=", + &data->phase2_eap_types, + &data->num_phase2_eap_types) + < 0) { + eap_ttls_deinit(sm, data); + return NULL; + } + + data->phase2_eap_type.vendor = EAP_VENDOR_IETF; + data->phase2_eap_type.method = EAP_TYPE_NONE; + } + - #if EAP_TTLS_VERSION > 0 - if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) && - data->ttls_version > 0) { - if (data->force_ttls_version > 0) { - wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and " - "TLS library does not support TLS/IA.", - data->force_ttls_version); - eap_ttls_deinit(sm, data); - return NULL; - } - data->ttls_version = 0; ++ if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) { ++ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); ++ eap_ttls_deinit(sm, data); ++ return NULL; + } - #endif /* EAP_TTLS_VERSION */ + + return data; +} + + +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); - if (data->ssl_initialized) - eap_peer_tls_ssl_deinit(sm, &data->ssl); - os_free(data->key_data); ++ eap_peer_tls_ssl_deinit(sm, &data->ssl); ++ eap_ttls_free_key(data); ++ os_free(data->session_id); + wpabuf_free(data->pending_phase2_req); + 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((flags << 24) | (hdrlen + len)); ++ 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; +} + - #if EAP_TTLS_VERSION > 0 - static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm, - struct eap_ttls_data *data, - const u8 *key, size_t key_len) - { - u8 *buf; - size_t buf_len; - int ret; - - if (key) { - buf_len = 2 + key_len; - buf = os_malloc(buf_len); - if (buf == NULL) - return -1; - WPA_PUT_BE16(buf, key_len); - os_memcpy(buf + 2, key, key_len); - } else { - buf = NULL; - buf_len = 0; - } - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner " - "secret permutation", buf, buf_len); - ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx, - data->ssl.conn, - buf, buf_len); - os_free(buf); - - return ret; - } - #endif /* EAP_TTLS_VERSION */ - - +static int eap_ttls_v0_derive_key(struct eap_sm *sm, + struct eap_ttls_data *data) +{ - os_free(data->key_data); ++ eap_ttls_free_key(data); + data->key_data = eap_peer_tls_derive_key(sm, &data->ssl, + "ttls keying material", - EAP_TLS_KEY_LEN); ++ EAP_TLS_KEY_LEN + ++ EAP_EMSK_LEN); + if (!data->key_data) { + wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key"); + return -1; + } + + wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", + data->key_data, EAP_TLS_KEY_LEN); - - return 0; - } - - - #if EAP_TTLS_VERSION > 0 - static int eap_ttls_v1_derive_key(struct eap_sm *sm, - struct eap_ttls_data *data) - { - struct tls_keys keys; - u8 *rnd; - - os_free(data->key_data); - data->key_data = NULL; - - os_memset(&keys, 0, sizeof(keys)); - if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || - keys.client_random == NULL || keys.server_random == NULL || - keys.inner_secret == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " - "client random, or server random to derive keying " - "material"); - return -1; - } - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - data->key_data = os_malloc(EAP_TLS_KEY_LEN); - if (rnd == NULL || data->key_data == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation"); - os_free(rnd); - os_free(data->key_data); - data->key_data = NULL; - return -1; - } - os_memcpy(rnd, keys.client_random, keys.client_random_len); - os_memcpy(rnd + keys.client_random_len, keys.server_random, - keys.server_random_len); - - if (tls_prf(keys.inner_secret, keys.inner_secret_len, - "ttls v1 keying material", rnd, keys.client_random_len + - keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key"); - os_free(rnd); - os_free(data->key_data); - data->key_data = NULL; - return -1; ++ wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK", ++ data->key_data + EAP_TLS_KEY_LEN, ++ EAP_EMSK_LEN); ++ ++ os_free(data->session_id); ++ data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl, ++ EAP_TYPE_TTLS, ++ &data->id_len); ++ if (data->session_id) { ++ wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived Session-Id", ++ data->session_id, data->id_len); ++ } else { ++ wpa_printf(MSG_ERROR, "EAP-TTLS: Failed to derive Session-Id"); + } + - wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random", - rnd, keys.client_random_len + keys.server_random_len); - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret", - keys.inner_secret, keys.inner_secret_len); - - os_free(rnd); - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key", - data->key_data, EAP_TLS_KEY_LEN); - + return 0; +} - #endif /* EAP_TTLS_VERSION */ + + ++#ifndef CONFIG_FIPS +static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm, + struct eap_ttls_data *data, size_t len) +{ - #if EAP_TTLS_VERSION > 0 - struct tls_keys keys; - u8 *challenge, *rnd; - #endif /* EAP_TTLS_VERSION */ - - if (data->ttls_version == 0) { - return eap_peer_tls_derive_key(sm, &data->ssl, - "ttls challenge", len); - } - - #if EAP_TTLS_VERSION > 0 - - os_memset(&keys, 0, sizeof(keys)); - if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) || - keys.client_random == NULL || keys.server_random == NULL || - keys.inner_secret == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, " - "client random, or server random to derive " - "implicit challenge"); - return NULL; - } - - rnd = os_malloc(keys.client_random_len + keys.server_random_len); - challenge = os_malloc(len); - if (rnd == NULL || challenge == NULL) { - wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit " - "challenge derivation"); - os_free(rnd); - os_free(challenge); - return NULL; - } - os_memcpy(rnd, keys.server_random, keys.server_random_len); - os_memcpy(rnd + keys.server_random_len, keys.client_random, - keys.client_random_len); - - if (tls_prf(keys.inner_secret, keys.inner_secret_len, - "inner application challenge", rnd, - keys.client_random_len + keys.server_random_len, - challenge, len)) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit " - "challenge"); - os_free(rnd); - os_free(challenge); - return NULL; - } - - os_free(rnd); - - wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge", - challenge, len); - - return challenge; - - #else /* EAP_TTLS_VERSION */ - - return NULL; - - #endif /* EAP_TTLS_VERSION */ - } - - - static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret) - { - #if EAP_TTLS_VERSION > 0 - if (data->ttls_version > 0) { - const struct eap_method *m = data->phase2_method; - void *priv = data->phase2_priv; - - /* TTLSv1 requires TLS/IA FinalPhaseFinished */ - if (ret->decision == DECISION_UNCOND_SUCC) - ret->decision = DECISION_COND_SUCC; - ret->methodState = METHOD_CONT; - - if (ret->decision == DECISION_COND_SUCC && - m->isKeyAvailable && m->getKey && - m->isKeyAvailable(sm, priv)) { - u8 *key; - size_t key_len; - key = m->getKey(sm, priv, &key_len); - if (key) { - eap_ttls_ia_permute_inner_secret( - sm, data, key, key_len); - os_free(key); - } - } - } - #endif /* EAP_TTLS_VERSION */ ++ return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len); +} ++#endif /* CONFIG_FIPS */ + + +static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data, + 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; + } - eap_ttlsv1_phase2_eap_finish(sm, data, ret); + + 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 void eap_ttlsv1_permute_inner(struct eap_sm *sm, - struct eap_ttls_data *data) - { - #if EAP_TTLS_VERSION > 0 - u8 session_key[2 * MSCHAPV2_KEY_LEN]; - - if (data->ttls_version == 0) - return; - - get_asymetric_start_key(data->master_key, session_key, - MSCHAPV2_KEY_LEN, 0, 0); - get_asymetric_start_key(data->master_key, - session_key + MSCHAPV2_KEY_LEN, - MSCHAPV2_KEY_LEN, 1, 0); - eap_ttls_ia_permute_inner_secret(sm, data, session_key, - sizeof(session_key)); - #endif /* EAP_TTLS_VERSION */ - } - - +static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct wpabuf **resp) +{ ++#ifdef CONFIG_FIPS ++ wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPV2 not supported in FIPS build"); ++ return -1; ++#else /* CONFIG_FIPS */ ++#ifdef EAP_MSCHAPv2 + struct wpabuf *msg; + u8 *buf, *pos, *challenge, *peer_challenge; + const u8 *identity, *password; + 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; + } - peer_challenge = challenge + 1 + EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; + + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, + RADIUS_VENDOR_ID_MICROSOFT, 1, + 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 */ - os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN); ++ if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) { ++ os_free(challenge); ++ wpabuf_free(msg); ++ wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get " ++ "random data for peer challenge"); ++ return -1; ++ } ++ peer_challenge = pos; + pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN; + os_memset(pos, 0, 8); /* Reserved, must be zero */ + pos += 8; + 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; + - eap_ttlsv1_permute_inner(sm, data); - + pos += 24; + os_free(challenge); + AVP_PAD(buf, pos); + + wpabuf_put(msg, pos - buf); + *resp = msg; + - if (sm->workaround && data->ttls_version == 0) { - /* At least FreeRADIUS seems to be terminating - * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success - * packet. */ - wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - " - "allow success without tunneled response"); - ret->methodState = METHOD_MAY_CONT; - ret->decision = DECISION_COND_SUCC; - } - + return 0; ++#else /* EAP_MSCHAPv2 */ ++ wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); ++ return -1; ++#endif /* EAP_MSCHAPv2 */ ++#endif /* CONFIG_FIPS */ +} + + +static int eap_ttls_phase2_request_mschap(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct wpabuf **resp) +{ ++#ifdef CONFIG_FIPS ++ wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAP not supported in FIPS build"); ++ return -1; ++#else /* CONFIG_FIPS */ + struct wpabuf *msg; + u8 *buf, *pos, *challenge; + const u8 *identity, *password; + size_t identity_len, password_len; + int pwhash; + + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request"); + + identity = eap_get_config_identity(sm, &identity_len); + password = eap_get_config_password2(sm, &password_len, &pwhash); + if (identity == NULL || password == NULL) + return -1; + + msg = wpabuf_alloc(identity_len + 1000); + if (msg == NULL) { + wpa_printf(MSG_ERROR, + "EAP-TTLS/MSCHAP: Failed to allocate memory"); + return -1; + } + pos = buf = wpabuf_mhead(msg); + + /* User-Name */ + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, + identity, identity_len); + + /* MS-CHAP-Challenge */ + challenge = eap_ttls_implicit_challenge( + sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1); + if (challenge == NULL) { + wpabuf_free(msg); + wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive " + "implicit challenge"); + return -1; + } + + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE, + RADIUS_VENDOR_ID_MICROSOFT, 1, + challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); + + /* MS-CHAP-Response */ + pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE, + RADIUS_VENDOR_ID_MICROSOFT, 1, + EAP_TTLS_MSCHAP_RESPONSE_LEN); + data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN]; + *pos++ = data->ident; + *pos++ = 1; /* Flags: Use NT style passwords */ + os_memset(pos, 0, 24); /* LM-Response */ + pos += 24; + if (pwhash) { + challenge_response(challenge, password, pos); /* NT-Response */ + wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash", + password, 16); + } else { + nt_challenge_response(challenge, password, password_len, + pos); /* NT-Response */ + wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password", + password, password_len); + } + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge", + challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24); + pos += 24; + os_free(challenge); + AVP_PAD(buf, pos); + + wpabuf_put(msg, pos - buf); + *resp = msg; + - if (data->ttls_version > 0) { - /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, - * so do not allow connection to be terminated yet. */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - /* EAP-TTLS/MSCHAP does not provide tunneled success - * notification, so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - } ++ /* EAP-TTLS/MSCHAP does not provide tunneled success ++ * notification, so assume that Phase2 succeeds. */ ++ ret->methodState = METHOD_DONE; ++ ret->decision = DECISION_COND_SUCC; + + return 0; ++#endif /* CONFIG_FIPS */ +} + + +static int eap_ttls_phase2_request_pap(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct wpabuf **resp) +{ + struct wpabuf *msg; + u8 *buf, *pos; + size_t pad; + const u8 *identity, *password; + size_t identity_len, password_len; + + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request"); + + identity = eap_get_config_identity(sm, &identity_len); + password = eap_get_config_password(sm, &password_len); + if (identity == NULL || password == NULL) + return -1; + + msg = wpabuf_alloc(identity_len + password_len + 100); + if (msg == NULL) { + wpa_printf(MSG_ERROR, + "EAP-TTLS/PAP: Failed to allocate memory"); + return -1; + } + pos = buf = wpabuf_mhead(msg); + + /* User-Name */ + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, + identity, identity_len); + + /* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts + * the data, so no separate encryption is used in the AVP itself. + * However, the password is padded to obfuscate its length. */ + pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15; + pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1, + password_len + pad); + os_memcpy(pos, password, password_len); + pos += password_len; + os_memset(pos, 0, pad); + pos += pad; + AVP_PAD(buf, pos); + + wpabuf_put(msg, pos - buf); + *resp = msg; + - if (data->ttls_version > 0) { - /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, - * so do not allow connection to be terminated yet. */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - /* EAP-TTLS/PAP does not provide tunneled success notification, - * so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - } ++ /* EAP-TTLS/PAP does not provide tunneled success notification, ++ * so assume that Phase2 succeeds. */ ++ ret->methodState = METHOD_DONE; ++ ret->decision = DECISION_COND_SUCC; + + return 0; +} + + +static int eap_ttls_phase2_request_chap(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct wpabuf **resp) +{ ++#ifdef CONFIG_FIPS ++ wpa_printf(MSG_ERROR, "EAP-TTLS: CHAP not supported in FIPS build"); ++ return -1; ++#else /* CONFIG_FIPS */ + struct wpabuf *msg; + u8 *buf, *pos, *challenge; + const u8 *identity, *password; + size_t identity_len, password_len; + + wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request"); + + identity = eap_get_config_identity(sm, &identity_len); + password = eap_get_config_password(sm, &password_len); + if (identity == NULL || password == NULL) + return -1; + + msg = wpabuf_alloc(identity_len + 1000); + if (msg == NULL) { + wpa_printf(MSG_ERROR, + "EAP-TTLS/CHAP: Failed to allocate memory"); + return -1; + } + pos = buf = wpabuf_mhead(msg); + + /* User-Name */ + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1, + identity, identity_len); + + /* CHAP-Challenge */ + challenge = eap_ttls_implicit_challenge( + sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1); + if (challenge == NULL) { + wpabuf_free(msg); + wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive " + "implicit challenge"); + return -1; + } + + pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1, + challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); + + /* CHAP-Password */ + pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1, + 1 + EAP_TTLS_CHAP_PASSWORD_LEN); + data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN]; + *pos++ = data->ident; + + /* MD5(Ident + Password + Challenge) */ + chap_md5(data->ident, password, password_len, challenge, + EAP_TTLS_CHAP_CHALLENGE_LEN, pos); + + wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username", + identity, identity_len); + wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password", + password, password_len); + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge", + challenge, EAP_TTLS_CHAP_CHALLENGE_LEN); + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password", + pos, EAP_TTLS_CHAP_PASSWORD_LEN); + pos += EAP_TTLS_CHAP_PASSWORD_LEN; + os_free(challenge); + AVP_PAD(buf, pos); + + wpabuf_put(msg, pos - buf); + *resp = msg; + - if (data->ttls_version > 0) { - /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success, - * so do not allow connection to be terminated yet. */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - /* EAP-TTLS/CHAP does not provide tunneled success - * notification, so assume that Phase2 succeeds. */ - ret->methodState = METHOD_DONE; - ret->decision = DECISION_COND_SUCC; - } ++ /* EAP-TTLS/CHAP does not provide tunneled success ++ * notification, so assume that Phase2 succeeds. */ ++ ret->methodState = METHOD_DONE; ++ ret->decision = DECISION_COND_SUCC; + + return 0; ++#endif /* CONFIG_FIPS */ +} + + +static int eap_ttls_phase2_request(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct eap_hdr *hdr, + struct wpabuf **resp) +{ + int res = 0; + size_t len; + enum phase2_types phase2_type = data->phase2_type; + +#ifdef EAP_TNC + if (data->tnc_started) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC"); + phase2_type = EAP_TTLS_PHASE2_EAP; + } +#endif /* EAP_TNC */ + + if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 || + phase2_type == EAP_TTLS_PHASE2_MSCHAP || + phase2_type == EAP_TTLS_PHASE2_PAP || + phase2_type == EAP_TTLS_PHASE2_CHAP) { + if (eap_get_config_identity(sm, &len) == NULL) { + wpa_printf(MSG_INFO, + "EAP-TTLS: Identity not configured"); + eap_sm_request_identity(sm); + if (eap_get_config_password(sm, &len) == NULL) + eap_sm_request_password(sm); + return 0; + } + + if (eap_get_config_password(sm, &len) == NULL) { + wpa_printf(MSG_INFO, + "EAP-TTLS: Password not configured"); + eap_sm_request_password(sm); + return 0; + } + } + + switch (phase2_type) { + case EAP_TTLS_PHASE2_EAP: + res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp); + break; + case EAP_TTLS_PHASE2_MSCHAPV2: + res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp); + break; + case EAP_TTLS_PHASE2_MSCHAP: + res = eap_ttls_phase2_request_mschap(sm, data, ret, resp); + break; + case EAP_TTLS_PHASE2_PAP: + res = eap_ttls_phase2_request_pap(sm, data, ret, resp); + break; + case EAP_TTLS_PHASE2_CHAP: + res = eap_ttls_phase2_request_chap(sm, data, ret, resp); + break; + default: + wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown"); + res = -1; + break; + } + + if (res < 0) { + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + } + + return res; +} + + - #if EAP_TTLS_VERSION > 0 - static struct wpabuf * eap_ttls_build_phase_finished( - struct eap_sm *sm, struct eap_ttls_data *data, int id, int final) - { - struct wpabuf *req, *buf; - - buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx, - data->ssl.conn, - final); - if (buf == NULL) - return NULL; - - req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS, - 1 + wpabuf_len(buf), - EAP_CODE_RESPONSE, id); - if (req == NULL) { - wpabuf_free(buf); - return NULL; - } - - wpabuf_put_u8(req, data->ttls_version); - wpabuf_put_buf(req, buf); - wpabuf_free(buf); - eap_update_len(req); - - return req; - } - #endif /* EAP_TTLS_VERSION */ - - +struct ttls_parse_avp { + u8 *mschapv2; + u8 *eapdata; + 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; ichbind_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; ichbind_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; ichbind_config_len; i++) { + struct eap_peer_chbind_config *chbind_config = + &config->chbind_config[i]; + pos = 1; + found = 0; + while (pos+sizeof(*hdr) < parse->chbind_len) { + hdr = (struct chbind_hdr *)(&parse->chbind_data[pos]); + pos += sizeof(*hdr); + len = be_to_host16(hdr->len); + if (pos + len <= parse->chbind_len) { + if (chbind_config->nsid == hdr->nsid) + chbind_config->response_cb( + chbind_config->ctx, + code, hdr->nsid, + &parse->chbind_data[pos], len); + found = 1; + } + pos += len; + } + if (pos != parse->chbind_len) { + wpa_printf(MSG_WARNING, "EAP-TTLS: bad channel binding response " + "frame (parsed len=%lu, expected %lu) - dropped", + (unsigned long) pos, + (unsigned long) parse->chbind_len); + return -1; + } + if (!found) { + chbind_config->response_cb( + chbind_config->ctx, + code, chbind_config->nsid, + NULL, 0); + } + + } + return 0; +} + +static int eap_ttls_process_phase2_eap(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct ttls_parse_avp *parse, + struct wpabuf **resp) +{ + struct eap_hdr *hdr; + size_t len; + + if (parse->eapdata == NULL) { + wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the " + "packet - dropped"); + return -1; + } + + wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP", + parse->eapdata, parse->eap_len); + hdr = (struct eap_hdr *) parse->eapdata; + + if (parse->eap_len < sizeof(*hdr)) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP " + "frame (len=%lu, expected %lu or more) - dropped", + (unsigned long) parse->eap_len, + (unsigned long) sizeof(*hdr)); + return -1; + } + len = be_to_host16(hdr->length); + if (len > parse->eap_len) { + wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 " + "EAP frame (EAP hdr len=%lu, EAP data len in " + "AVP=%lu)", + (unsigned long) len, + (unsigned long) parse->eap_len); + return -1; + } + wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d " + "identifier=%d length=%lu", + hdr->code, hdr->identifier, (unsigned long) len); + switch (hdr->code) { + case EAP_CODE_REQUEST: + if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) { + wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request " + "processing failed"); + return -1; + } + break; + default: + wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in " + "Phase 2 EAP header", hdr->code); + return -1; + } + + return 0; +} + + +static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct ttls_parse_avp *parse) +{ ++#ifdef EAP_MSCHAPv2 + if (parse->mschapv2_error) { + wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received " + "MS-CHAP-Error - failed"); + ret->methodState = METHOD_DONE; + ret->decision = DECISION_FAIL; + /* Reply with empty data to ACK error */ + return 1; + } + + if (parse->mschapv2 == NULL) { +#ifdef EAP_TNC + if (data->phase2_success && parse->eapdata) { + /* + * Allow EAP-TNC to be started after successfully + * completed MSCHAPV2. + */ + return 1; + } +#endif /* EAP_TNC */ + wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP " + "received for Phase2 MSCHAPV2"); + return -1; + } + if (parse->mschapv2[0] != data->ident) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 " + "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)", + parse->mschapv2[0], data->ident); + return -1; + } + if (!data->auth_response_valid || + mschapv2_verify_auth_response(data->auth_response, + parse->mschapv2 + 1, 42)) { + wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator " + "response in Phase 2 MSCHAPV2 success request"); + return -1; + } + + wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 " + "authentication succeeded"); - if (data->ttls_version > 0) { - /* - * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report - * success, so do not allow connection to be terminated - * yet. - */ - ret->methodState = METHOD_CONT; - ret->decision = DECISION_COND_SUCC; - } else { - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - } ++ ret->methodState = METHOD_DONE; ++ ret->decision = DECISION_UNCOND_SUCC; ++ data->phase2_success = 1; + + /* + * Reply with empty data; authentication server will reply + * with EAP-Success after this. + */ + return 1; ++#else /* EAP_MSCHAPv2 */ ++ wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build"); ++ return -1; ++#endif /* EAP_MSCHAPv2 */ +} + + +#ifdef EAP_TNC +static int eap_ttls_process_tnc_start(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + struct ttls_parse_avp *parse, + struct wpabuf **resp) +{ + /* TNC uses inner EAP method after non-EAP TTLS phase 2. */ + if (parse->eapdata == NULL) { + wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " + "unexpected tunneled data (no EAP)"); + return -1; + } + + if (!data->ready_for_tnc) { + wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received " + "EAP after non-EAP, but not ready for TNC"); + return -1; + } + + wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed " + "non-EAP method"); + data->tnc_started = 1; + + if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0) + return -1; + + return 0; +} +#endif /* EAP_TNC */ + + +static int eap_ttls_process_decrypted(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + u8 identifier, + struct ttls_parse_avp *parse, + struct wpabuf *in_decrypted, + struct wpabuf **out_data) +{ + struct wpabuf *resp = NULL; + struct eap_peer_config *config = eap_get_config(sm); + int res; + enum phase2_types phase2_type = data->phase2_type; + +#ifdef EAP_TNC + if (data->tnc_started) + phase2_type = EAP_TTLS_PHASE2_EAP; +#endif /* EAP_TNC */ + + /* handle channel binding response here */ + if (parse->chbind_data) { + /* received channel binding repsonse */ + if (eap_ttls_process_chbind(sm, data, ret, parse, &resp) < 0) + return -1; + if (data->done_butfor_cb) { + ret->methodState = METHOD_DONE; + ret->decision = data->cbDecision; + data->phase2_success = 1; + return 1; /*request ack*/ + } + } + + switch (phase2_type) { + case EAP_TTLS_PHASE2_EAP: + if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) < + 0) + return -1; + break; + case EAP_TTLS_PHASE2_MSCHAPV2: + res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse); +#ifdef EAP_TNC + if (res == 1 && parse->eapdata && data->phase2_success) { + /* + * TNC may be required as the next + * authentication method within the tunnel. + */ + ret->methodState = METHOD_MAY_CONT; + data->ready_for_tnc = 1; + if (eap_ttls_process_tnc_start(sm, data, ret, parse, + &resp) == 0) + break; + } +#endif /* EAP_TNC */ + return res; + case EAP_TTLS_PHASE2_MSCHAP: + case EAP_TTLS_PHASE2_PAP: + case EAP_TTLS_PHASE2_CHAP: +#ifdef EAP_TNC + if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) < + 0) + return -1; + break; +#else /* EAP_TNC */ + /* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled + * requests to the supplicant */ + wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected " + "tunneled data"); + return -1; +#endif /* EAP_TNC */ + } + + if (!resp && (config->pending_req_identity || + config->pending_req_password || + config->pending_req_otp || + config->pending_req_new_password)) { + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = wpabuf_dup(in_decrypted); + return 0; + } + + /* issue channel binding request when appropriate */ + if (config->chbind_config && config->chbind_config_len > 0 && + !data->chbind_req_sent) { + if (eap_ttls_add_chbind_request(sm, data, &resp) < 0) + return -1; + data->chbind_req_sent = 1; + if (ret->methodState == METHOD_DONE) { + data->done_butfor_cb = 1; + data->cbDecision = ret->decision; + ret->methodState = METHOD_MAY_CONT; + } + } + + if (resp) { + if (eap_ttls_encrypt_response(sm, data, resp, identifier, + out_data) < 0) + return -1; + } + + return 0; +} + + - #if EAP_TTLS_VERSION > 0 - static void eap_ttls_final_phase_finished(struct eap_sm *sm, - struct eap_ttls_data *data, - struct eap_method_ret *ret, - u8 identifier, - struct wpabuf **out_data) - { - wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received"); - wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_UNCOND_SUCC; - data->phase2_success = 1; - *out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1); - eap_ttls_v1_derive_key(sm, data); - } - #endif /* EAP_TTLS_VERSION */ - - +static int eap_ttls_implicit_identity_request(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + 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; + - #if EAP_TTLS_VERSION > 0 - if (data->ttls_version > 0 && - (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) && - tls_connection_ia_final_phase_finished(sm->ssl_ctx, - data->ssl.conn)) { - eap_ttls_final_phase_finished(sm, data, ret, identifier, - out_data); - goto done; - } - #endif /* EAP_TTLS_VERSION */ - +continue_req: + data->phase2_start = 0; + + 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_start(struct eap_sm *sm, - struct eap_ttls_data *data, u8 flags, - struct eap_method_ret *ret) - { - struct eap_peer_config *config = eap_get_config(sm); - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)", - flags & EAP_TLS_VERSION_MASK, data->ttls_version); - #if EAP_TTLS_VERSION > 0 - if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version) - data->ttls_version = flags & EAP_TLS_VERSION_MASK; - if (data->force_ttls_version >= 0 && - data->force_ttls_version != data->ttls_version) { - wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select " - "forced TTLS version %d", - data->force_ttls_version); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - return -1; - } - wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d", - data->ttls_version); - - if (data->ttls_version > 0) - data->ssl.tls_ia = 1; - #endif /* EAP_TTLS_VERSION */ - if (!data->ssl_initialized && - eap_peer_tls_ssl_init(sm, &data->ssl, config)) { - wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL."); - return -1; - } - data->ssl_initialized = 1; - - wpa_printf(MSG_DEBUG, "EAP-TTLS: Start"); - - return 0; - } - - +static int eap_ttls_process_handshake(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret, + u8 identifier, - const u8 *in_data, size_t in_len, ++ const struct wpabuf *in_data, + struct wpabuf **out_data) +{ + int res; + + res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, + data->ttls_version, identifier, - in_data, in_len, out_data); ++ in_data, out_data); ++ if (res < 0) { ++ wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS processing failed"); ++ ret->methodState = METHOD_DONE; ++ ret->decision = DECISION_FAIL; ++ return -1; ++ } + + if (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; - if (data->ttls_version == 0) - eap_ttls_v0_derive_key(sm, data); ++ eap_ttls_v0_derive_key(sm, data); + + if (*out_data == NULL || wpabuf_len(*out_data) == 0) { + if (eap_ttls_decrypt(sm, data, ret, identifier, + 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) { - struct wpabuf msg; + /* + * Application data included in the handshake message. + */ + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = *out_data; + *out_data = NULL; - wpabuf_set(&msg, in_data, in_len); - res = eap_ttls_decrypt(sm, data, ret, identifier, &msg, ++ res = eap_ttls_decrypt(sm, data, ret, identifier, in_data, + out_data); + } + + return res; +} + + +static void eap_ttls_check_auth_status(struct eap_sm *sm, + struct eap_ttls_data *data, + struct eap_method_ret *ret) +{ - if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) { ++ if (ret->methodState == METHOD_DONE) { + ret->allowNotifications = FALSE; + if (ret->decision == DECISION_UNCOND_SUCC || + ret->decision == DECISION_COND_SUCC) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " + "completed successfully"); + data->phase2_success = 1; +#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 (data->ttls_version == 0 && - ret->methodState == METHOD_MAY_CONT && ++ } else if (ret->methodState == METHOD_MAY_CONT && + (ret->decision == DECISION_UNCOND_SUCC || + ret->decision == DECISION_COND_SUCC)) { + wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication " + "completed successfully (MAY_CONT)"); + data->phase2_success = 1; + } +} + + +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) { - if (eap_ttls_process_start(sm, data, flags, ret) < 0) - return NULL; ++ wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own " ++ "ver=%d)", flags & EAP_TLS_VERSION_MASK, ++ data->ttls_version); + + /* RFC 5281, Ch. 9.2: + * "This packet MAY contain additional information in the form + * of AVPs, which may provide useful hints to the client" + * For now, ignore any potential extra data. + */ + left = 0; - } else if (!data->ssl_initialized) { - wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not " - "include Start flag"); - ret->methodState = METHOD_DONE; - ret->decision = DECISION_FAIL; - ret->allowNotifications = FALSE; - return NULL; + } + ++ wpabuf_set(&msg, pos, left); ++ + resp = NULL; + if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) && + !data->resuming) { - struct wpabuf msg; - wpabuf_set(&msg, pos, left); + res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp); + } else { + res = eap_ttls_process_handshake(sm, data, ret, id, - pos, left, &resp); ++ &msg, &resp); + } + + eap_ttls_check_auth_status(sm, data, ret); + + /* FIX: what about res == -1? Could just move all error processing into + * the other functions and get rid of this res==1 case here. */ + if (res == 1) { + wpabuf_free(resp); + return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS, + data->ttls_version); + } + return resp; +} + + +static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv) +{ + struct eap_ttls_data *data = priv; + return tls_connection_established(sm->ssl_ctx, data->ssl.conn) && + data->phase2_success; +} + + +static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv) +{ + struct eap_ttls_data *data = priv; + wpabuf_free(data->pending_phase2_req); + data->pending_phase2_req = NULL; +#ifdef EAP_TNC + data->ready_for_tnc = 0; + data->tnc_started = 0; +#endif /* EAP_TNC */ +} + + +static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv) +{ + struct eap_ttls_data *data = priv; - os_free(data->key_data); - data->key_data = NULL; ++ eap_ttls_free_key(data); ++ os_free(data->session_id); ++ data->session_id = NULL; + if (eap_peer_tls_reauth_init(sm, &data->ssl)) { + os_free(data); + return NULL; + } + if (data->phase2_priv && data->phase2_method && + data->phase2_method->init_for_reauth) + data->phase2_method->init_for_reauth(sm, data->phase2_priv); + data->phase2_start = 0; + data->phase2_success = 0; + data->resuming = 1; + data->reauth = 1; + return priv; +} + + +static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf, + size_t buflen, int verbose) +{ + struct eap_ttls_data *data = priv; + int len, ret; + + len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose); + ret = os_snprintf(buf + len, buflen - len, + "EAP-TTLSv%d Phase2 method=", + data->ttls_version); - if (ret < 0 || (size_t) ret >= buflen - len) ++ if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + switch (data->phase2_type) { + case EAP_TTLS_PHASE2_EAP: + ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n", + data->phase2_method ? + data->phase2_method->name : "?"); + break; + case EAP_TTLS_PHASE2_MSCHAPV2: + ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n"); + break; + case EAP_TTLS_PHASE2_MSCHAP: + ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n"); + break; + case EAP_TTLS_PHASE2_PAP: + ret = os_snprintf(buf + len, buflen - len, "PAP\n"); + break; + case EAP_TTLS_PHASE2_CHAP: + ret = os_snprintf(buf + len, buflen - len, "CHAP\n"); + break; + default: + ret = 0; + break; + } - if (ret < 0 || (size_t) ret >= buflen - len) ++ if (os_snprintf_error(buflen - len, ret)) + return len; + len += ret; + + return len; +} + + +static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv) +{ + struct eap_ttls_data *data = priv; + return data->key_data != NULL && data->phase2_success; +} + + +static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len) +{ + struct eap_ttls_data *data = priv; + u8 *key; + + if (data->key_data == NULL || !data->phase2_success) + return NULL; + + key = os_malloc(EAP_TLS_KEY_LEN); + if (key == NULL) + return NULL; + + *len = EAP_TLS_KEY_LEN; + os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN); + + return key; +} + + ++static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len) ++{ ++ struct eap_ttls_data *data = priv; ++ u8 *id; ++ ++ if (data->session_id == NULL || !data->phase2_success) ++ return NULL; ++ ++ id = os_malloc(data->id_len); ++ if (id == NULL) ++ return NULL; ++ ++ *len = data->id_len; ++ os_memcpy(id, data->session_id, data->id_len); ++ ++ return id; ++} ++ ++ ++static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len) ++{ ++ struct eap_ttls_data *data = priv; ++ u8 *key; ++ ++ if (data->key_data == NULL) ++ return NULL; ++ ++ key = os_malloc(EAP_EMSK_LEN); ++ if (key == NULL) ++ return NULL; ++ ++ *len = EAP_EMSK_LEN; ++ os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN); ++ ++ return key; ++} ++ ++ +int eap_peer_ttls_register(void) +{ + struct eap_method *eap; + int ret; + + eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION, + EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS"); + if (eap == NULL) + return -1; + + eap->init = eap_ttls_init; + eap->deinit = eap_ttls_deinit; + eap->process = eap_ttls_process; + eap->isKeyAvailable = eap_ttls_isKeyAvailable; + eap->getKey = eap_ttls_getKey; ++ eap->getSessionId = eap_ttls_get_session_id; + eap->get_status = eap_ttls_get_status; + eap->has_reauth_data = eap_ttls_has_reauth_data; + eap->deinit_for_reauth = eap_ttls_deinit_for_reauth; + eap->init_for_reauth = eap_ttls_init_for_reauth; ++ eap->get_emsk = eap_ttls_get_emsk; + + ret = eap_peer_method_register(eap); + if (ret) + eap_peer_method_free(eap); + return ret; +} diff --cc libeap/src/eap_server/eap_server_eke.c index 0000000,ba82be9..ba82be9 mode 000000,100644..100644 --- a/libeap/src/eap_server/eap_server_eke.c +++ b/libeap/src/eap_server/eap_server_eke.c diff --cc libeap/src/fst/Makefile index 0000000,9c41962..9c41962 mode 000000,100644..100644 --- a/libeap/src/fst/Makefile +++ b/libeap/src/fst/Makefile diff --cc libeap/src/fst/fst.c index 0000000,2880870..2880870 mode 000000,100644..100644 --- a/libeap/src/fst/fst.c +++ b/libeap/src/fst/fst.c diff --cc libeap/src/fst/fst.h index 0000000,0c0e435..0c0e435 mode 000000,100644..100644 --- a/libeap/src/fst/fst.h +++ b/libeap/src/fst/fst.h diff --cc libeap/src/fst/fst_ctrl_aux.c index 0000000,dc7b2a7..dc7b2a7 mode 000000,100644..100644 --- a/libeap/src/fst/fst_ctrl_aux.c +++ b/libeap/src/fst/fst_ctrl_aux.c diff --cc libeap/src/fst/fst_ctrl_aux.h index 0000000,e2133f5..e2133f5 mode 000000,100644..100644 --- a/libeap/src/fst/fst_ctrl_aux.h +++ b/libeap/src/fst/fst_ctrl_aux.h diff --cc libeap/src/fst/fst_ctrl_defs.h index 0000000,6735389..6735389 mode 000000,100644..100644 --- a/libeap/src/fst/fst_ctrl_defs.h +++ b/libeap/src/fst/fst_ctrl_defs.h diff --cc libeap/src/fst/fst_ctrl_iface.c index 0000000,d090718..d090718 mode 000000,100644..100644 --- a/libeap/src/fst/fst_ctrl_iface.c +++ b/libeap/src/fst/fst_ctrl_iface.c diff --cc libeap/src/fst/fst_ctrl_iface.h index 0000000,4d0cd9f..4d0cd9f mode 000000,100644..100644 --- a/libeap/src/fst/fst_ctrl_iface.h +++ b/libeap/src/fst/fst_ctrl_iface.h diff --cc libeap/src/fst/fst_defs.h index 0000000,8ddcc61..8ddcc61 mode 000000,100644..100644 --- a/libeap/src/fst/fst_defs.h +++ b/libeap/src/fst/fst_defs.h diff --cc libeap/src/fst/fst_group.c index 0000000,f6c7be9..f6c7be9 mode 000000,100644..100644 --- a/libeap/src/fst/fst_group.c +++ b/libeap/src/fst/fst_group.c diff --cc libeap/src/fst/fst_group.h index 0000000,3a87c0b..3a87c0b mode 000000,100644..100644 --- a/libeap/src/fst/fst_group.h +++ b/libeap/src/fst/fst_group.h diff --cc libeap/src/fst/fst_iface.c index 0000000,5a92d2c..5a92d2c mode 000000,100644..100644 --- a/libeap/src/fst/fst_iface.c +++ b/libeap/src/fst/fst_iface.c diff --cc libeap/src/fst/fst_iface.h index 0000000,4670d89..4670d89 mode 000000,100644..100644 --- a/libeap/src/fst/fst_iface.h +++ b/libeap/src/fst/fst_iface.h diff --cc libeap/src/fst/fst_internal.h index 0000000,9fe32b8..9fe32b8 mode 000000,100644..100644 --- a/libeap/src/fst/fst_internal.h +++ b/libeap/src/fst/fst_internal.h diff --cc libeap/src/fst/fst_session.c index 0000000,55fa694..55fa694 mode 000000,100644..100644 --- a/libeap/src/fst/fst_session.c +++ b/libeap/src/fst/fst_session.c diff --cc libeap/src/fst/fst_session.h index 0000000,1162de4..1162de4 mode 000000,100644..100644 --- a/libeap/src/fst/fst_session.h +++ b/libeap/src/fst/fst_session.h diff --cc libeap/src/pae/Makefile index 0000000,9c41962..9c41962 mode 000000,100644..100644 --- a/libeap/src/pae/Makefile +++ b/libeap/src/pae/Makefile diff --cc libeap/src/pae/ieee802_1x_cp.c index 0000000,cf43c59..cf43c59 mode 000000,100644..100644 --- a/libeap/src/pae/ieee802_1x_cp.c +++ b/libeap/src/pae/ieee802_1x_cp.c diff --cc libeap/src/pae/ieee802_1x_cp.h index 0000000,773c930..773c930 mode 000000,100644..100644 --- a/libeap/src/pae/ieee802_1x_cp.h +++ b/libeap/src/pae/ieee802_1x_cp.h diff --cc libeap/src/pae/ieee802_1x_kay.c index 0000000,ef74430..ef74430 mode 000000,100644..100644 --- a/libeap/src/pae/ieee802_1x_kay.c +++ b/libeap/src/pae/ieee802_1x_kay.c diff --cc libeap/src/pae/ieee802_1x_kay.h index 0000000,064417e..064417e mode 000000,100644..100644 --- a/libeap/src/pae/ieee802_1x_kay.h +++ b/libeap/src/pae/ieee802_1x_kay.h diff --cc libeap/src/pae/ieee802_1x_kay_i.h index 0000000,bdad3a5..bdad3a5 mode 000000,100644..100644 --- a/libeap/src/pae/ieee802_1x_kay_i.h +++ b/libeap/src/pae/ieee802_1x_kay_i.h diff --cc libeap/src/pae/ieee802_1x_key.c index 0000000,9a8d923..9a8d923 mode 000000,100644..100644 --- a/libeap/src/pae/ieee802_1x_key.c +++ b/libeap/src/pae/ieee802_1x_key.c diff --cc libeap/src/pae/ieee802_1x_key.h index 0000000,ea318ea..ea318ea mode 000000,100644..100644 --- a/libeap/src/pae/ieee802_1x_key.h +++ b/libeap/src/pae/ieee802_1x_key.h diff --cc libeap/src/pae/ieee802_1x_secy_ops.c index 0000000,fbe05dc..fbe05dc mode 000000,100644..100644 --- a/libeap/src/pae/ieee802_1x_secy_ops.c +++ b/libeap/src/pae/ieee802_1x_secy_ops.c diff --cc libeap/src/pae/ieee802_1x_secy_ops.h index 0000000,295b823..295b823 mode 000000,100644..100644 --- a/libeap/src/pae/ieee802_1x_secy_ops.h +++ b/libeap/src/pae/ieee802_1x_secy_ops.h diff --cc libeap/src/radius/radius_das.c index 0000000,b7d991b..b7d991b mode 000000,100644..100644 --- a/libeap/src/radius/radius_das.c +++ b/libeap/src/radius/radius_das.c diff --cc libeap/src/radius/radius_das.h index 0000000,ce731d4..ce731d4 mode 000000,100644..100644 --- a/libeap/src/radius/radius_das.h +++ b/libeap/src/radius/radius_das.h diff --cc libeap/src/rsn_supp/tdls.c index 0000000,722c20a..722c20a mode 000000,100644..100644 --- a/libeap/src/rsn_supp/tdls.c +++ b/libeap/src/rsn_supp/tdls.c diff --cc libeap/src/utils/bitfield.c index 0000000,8dcec39..8dcec39 mode 000000,100644..100644 --- a/libeap/src/utils/bitfield.c +++ b/libeap/src/utils/bitfield.c diff --cc libeap/src/utils/bitfield.h index 0000000,7050a20..7050a20 mode 000000,100644..100644 --- a/libeap/src/utils/bitfield.h +++ b/libeap/src/utils/bitfield.h diff --cc libeap/src/utils/browser-android.c index 0000000,9ce1a5c..9ce1a5c mode 000000,100644..100644 --- a/libeap/src/utils/browser-android.c +++ b/libeap/src/utils/browser-android.c diff --cc libeap/src/utils/browser-system.c index 0000000,aed3970..aed3970 mode 000000,100644..100644 --- a/libeap/src/utils/browser-system.c +++ b/libeap/src/utils/browser-system.c diff --cc libeap/src/utils/browser-wpadebug.c index 0000000,59ba4d1..59ba4d1 mode 000000,100644..100644 --- a/libeap/src/utils/browser-wpadebug.c +++ b/libeap/src/utils/browser-wpadebug.c diff --cc libeap/src/utils/browser.c index 0000000,9cf6152..9cf6152 mode 000000,100644..100644 --- a/libeap/src/utils/browser.c +++ b/libeap/src/utils/browser.c diff --cc libeap/src/utils/browser.h index 0000000,aaa0eed..aaa0eed mode 000000,100644..100644 --- a/libeap/src/utils/browser.h +++ b/libeap/src/utils/browser.h diff --cc libeap/src/utils/common.h index 2868df7,0000000..13aa941 mode 100644,000000..100644 --- a/libeap/src/utils/common.h +++ b/libeap/src/utils/common.h @@@ -1,486 -1,0 +1,568 @@@ +/* + * wpa_supplicant/hostapd / common helper functions, etc. + * Copyright (c) 2002-2007, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef COMMON_H +#define COMMON_H + +#include "os.h" + +#if defined(__linux__) || defined(__GLIBC__) +#include +#include +#endif /* __linux__ */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \ + defined(__OpenBSD__) +#include +#include +#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 +#include +#define __BYTE_ORDER _BYTE_ORDER +#define __LITTLE_ENDIAN _LITTLE_ENDIAN +#define __BIG_ENDIAN _BIG_ENDIAN +static inline unsigned short bswap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int bswap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} +#endif /* __APPLE__ */ + - #ifdef CONFIG_TI_COMPILER - #define __BIG_ENDIAN 4321 - #define __LITTLE_ENDIAN 1234 - #ifdef __big_endian__ - #define __BYTE_ORDER __BIG_ENDIAN - #else - #define __BYTE_ORDER __LITTLE_ENDIAN - #endif - #endif /* CONFIG_TI_COMPILER */ - - #ifdef __SYMBIAN32__ - #define __BIG_ENDIAN 4321 - #define __LITTLE_ENDIAN 1234 - #define __BYTE_ORDER __LITTLE_ENDIAN - #endif /* __SYMBIAN32__ */ - +#ifdef CONFIG_NATIVE_WINDOWS +#ifdef CONFIG_IPV6 +#include +#include +#else +#include +#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 */ + - #ifdef CONFIG_TI_COMPILER - #ifdef _LLONG_AVAILABLE - typedef unsigned long long u64; - #else - /* - * TODO: 64-bit variable not available. Using long as a workaround to test the - * build, but this will likely not work for all operations. - */ - typedef unsigned long u64; - #endif - typedef unsigned int u32; - typedef unsigned short u16; - typedef unsigned char u8; - #define WPA_TYPES_DEFINED - #endif /* CONFIG_TI_COMPILER */ - - #ifdef __SYMBIAN32__ - #define __REMOVE_PLATSEC_DIAGNOSTICS__ - #include - typedef TUint64 u64; - typedef TUint32 u32; - typedef TUint16 u16; - typedef TUint8 u8; - #define WPA_TYPES_DEFINED - #endif /* __SYMBIAN32__ */ - +#ifndef WPA_TYPES_DEFINED +#ifdef CONFIG_USE_INTTYPES_H +#include +#else +#include +#endif +typedef uint64_t u64; +typedef uint32_t u32; +typedef uint16_t u16; +typedef uint8_t u8; +typedef int64_t s64; +typedef int32_t s32; +typedef int16_t s16; +typedef int8_t s8; +#define WPA_TYPES_DEFINED +#endif /* !WPA_TYPES_DEFINED */ + + +/* Define platform specific byte swapping macros */ + +#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS) + +static inline unsigned short wpa_swap_16(unsigned short v) +{ + return ((v & 0xff) << 8) | (v >> 8); +} + +static inline unsigned int wpa_swap_32(unsigned int v) +{ + return ((v & 0xff) << 24) | ((v & 0xff00) << 8) | + ((v & 0xff0000) >> 8) | (v >> 24); +} + +#define le_to_host16(n) (n) +#define host_to_le16(n) (n) +#define be_to_host16(n) wpa_swap_16(n) +#define host_to_be16(n) wpa_swap_16(n) +#define le_to_host32(n) (n) ++#define host_to_le32(n) (n) +#define be_to_host32(n) wpa_swap_32(n) +#define host_to_be32(n) wpa_swap_32(n) + +#define WPA_BYTE_SWAP_DEFINED + +#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */ + + +#ifndef WPA_BYTE_SWAP_DEFINED + +#ifndef __BYTE_ORDER +#ifndef __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __LITTLE_ENDIAN 1234 +#define __BIG_ENDIAN 4321 +#if defined(sparc) +#define __BYTE_ORDER __BIG_ENDIAN +#endif +#endif /* __BIG_ENDIAN */ +#endif /* __LITTLE_ENDIAN */ +#endif /* __BYTE_ORDER */ + +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define le_to_host16(n) ((__force u16) (le16) (n)) +#define host_to_le16(n) ((__force le16) (u16) (n)) +#define be_to_host16(n) bswap_16((__force u16) (be16) (n)) +#define host_to_be16(n) ((__force be16) bswap_16((n))) +#define le_to_host32(n) ((__force u32) (le32) (n)) +#define host_to_le32(n) ((__force le32) (u32) (n)) +#define be_to_host32(n) bswap_32((__force u32) (be32) (n)) +#define host_to_be32(n) ((__force be32) bswap_32((n))) +#define le_to_host64(n) ((__force u64) (le64) (n)) +#define host_to_le64(n) ((__force le64) (u64) (n)) +#define be_to_host64(n) bswap_64((__force u64) (be64) (n)) +#define host_to_be64(n) ((__force be64) bswap_64((n))) +#elif __BYTE_ORDER == __BIG_ENDIAN +#define le_to_host16(n) bswap_16(n) +#define host_to_le16(n) bswap_16(n) +#define be_to_host16(n) (n) +#define host_to_be16(n) (n) +#define le_to_host32(n) bswap_32(n) ++#define host_to_le32(n) bswap_32(n) +#define be_to_host32(n) (n) +#define host_to_be32(n) (n) +#define le_to_host64(n) bswap_64(n) +#define host_to_le64(n) bswap_64(n) +#define be_to_host64(n) (n) +#define host_to_be64(n) (n) +#ifndef WORDS_BIGENDIAN +#define WORDS_BIGENDIAN +#endif +#else +#error Could not determine CPU byte order +#endif + +#define WPA_BYTE_SWAP_DEFINED +#endif /* !WPA_BYTE_SWAP_DEFINED */ + + +/* Macros for handling unaligned memory accesses */ + - #define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1])) - #define WPA_PUT_BE16(a, val) \ - do { \ - (a)[0] = ((u16) (val)) >> 8; \ - (a)[1] = ((u16) (val)) & 0xff; \ - } while (0) - - #define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0])) - #define WPA_PUT_LE16(a, val) \ - do { \ - (a)[1] = ((u16) (val)) >> 8; \ - (a)[0] = ((u16) (val)) & 0xff; \ - } while (0) - - #define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \ - ((u32) (a)[2])) - #define WPA_PUT_BE24(a, val) \ - do { \ - (a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[2] = (u8) (((u32) (val)) & 0xff); \ - } while (0) - - #define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \ - (((u32) (a)[2]) << 8) | ((u32) (a)[3])) - #define WPA_PUT_BE32(a, val) \ - do { \ - (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[3] = (u8) (((u32) (val)) & 0xff); \ - } while (0) - - #define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \ - (((u32) (a)[1]) << 8) | ((u32) (a)[0])) - #define WPA_PUT_LE32(a, val) \ - do { \ - (a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \ - (a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \ - (a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \ - (a)[0] = (u8) (((u32) (val)) & 0xff); \ - } while (0) - - #define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \ - (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \ - (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \ - (((u64) (a)[6]) << 8) | ((u64) (a)[7])) - #define WPA_PUT_BE64(a, val) \ - do { \ - (a)[0] = (u8) (((u64) (val)) >> 56); \ - (a)[1] = (u8) (((u64) (val)) >> 48); \ - (a)[2] = (u8) (((u64) (val)) >> 40); \ - (a)[3] = (u8) (((u64) (val)) >> 32); \ - (a)[4] = (u8) (((u64) (val)) >> 24); \ - (a)[5] = (u8) (((u64) (val)) >> 16); \ - (a)[6] = (u8) (((u64) (val)) >> 8); \ - (a)[7] = (u8) (((u64) (val)) & 0xff); \ - } while (0) - - #define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \ - (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \ - (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \ - (((u64) (a)[1]) << 8) | ((u64) (a)[0])) ++static inline u16 WPA_GET_BE16(const u8 *a) ++{ ++ return (a[0] << 8) | a[1]; ++} ++ ++static inline void WPA_PUT_BE16(u8 *a, u16 val) ++{ ++ a[0] = val >> 8; ++ a[1] = val & 0xff; ++} ++ ++static inline u16 WPA_GET_LE16(const u8 *a) ++{ ++ return (a[1] << 8) | a[0]; ++} ++ ++static inline void WPA_PUT_LE16(u8 *a, u16 val) ++{ ++ a[1] = val >> 8; ++ a[0] = val & 0xff; ++} ++ ++static inline u32 WPA_GET_BE24(const u8 *a) ++{ ++ return (a[0] << 16) | (a[1] << 8) | a[2]; ++} ++ ++static inline void WPA_PUT_BE24(u8 *a, u32 val) ++{ ++ a[0] = (val >> 16) & 0xff; ++ a[1] = (val >> 8) & 0xff; ++ a[2] = val & 0xff; ++} ++ ++static inline u32 WPA_GET_BE32(const u8 *a) ++{ ++ return ((u32) a[0] << 24) | (a[1] << 16) | (a[2] << 8) | a[3]; ++} ++ ++static inline void WPA_PUT_BE32(u8 *a, u32 val) ++{ ++ a[0] = (val >> 24) & 0xff; ++ a[1] = (val >> 16) & 0xff; ++ a[2] = (val >> 8) & 0xff; ++ a[3] = val & 0xff; ++} ++ ++static inline u32 WPA_GET_LE32(const u8 *a) ++{ ++ return ((u32) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0]; ++} ++ ++static inline void WPA_PUT_LE32(u8 *a, u32 val) ++{ ++ a[3] = (val >> 24) & 0xff; ++ a[2] = (val >> 16) & 0xff; ++ a[1] = (val >> 8) & 0xff; ++ a[0] = val & 0xff; ++} ++ ++static inline u64 WPA_GET_BE64(const u8 *a) ++{ ++ return (((u64) a[0]) << 56) | (((u64) a[1]) << 48) | ++ (((u64) a[2]) << 40) | (((u64) a[3]) << 32) | ++ (((u64) a[4]) << 24) | (((u64) a[5]) << 16) | ++ (((u64) a[6]) << 8) | ((u64) a[7]); ++} ++ ++static inline void WPA_PUT_BE64(u8 *a, u64 val) ++{ ++ a[0] = val >> 56; ++ a[1] = val >> 48; ++ a[2] = val >> 40; ++ a[3] = val >> 32; ++ a[4] = val >> 24; ++ a[5] = val >> 16; ++ a[6] = val >> 8; ++ a[7] = val & 0xff; ++} ++ ++static inline u64 WPA_GET_LE64(const u8 *a) ++{ ++ return (((u64) a[7]) << 56) | (((u64) a[6]) << 48) | ++ (((u64) a[5]) << 40) | (((u64) a[4]) << 32) | ++ (((u64) a[3]) << 24) | (((u64) a[2]) << 16) | ++ (((u64) a[1]) << 8) | ((u64) a[0]); ++} ++ ++static inline void WPA_PUT_LE64(u8 *a, u64 val) ++{ ++ a[7] = val >> 56; ++ a[6] = val >> 48; ++ a[5] = val >> 40; ++ a[4] = val >> 32; ++ a[3] = val >> 24; ++ a[2] = val >> 16; ++ a[1] = val >> 8; ++ a[0] = val & 0xff; ++} + + +#ifndef ETH_ALEN +#define ETH_ALEN 6 +#endif ++#ifndef ETH_HLEN ++#define ETH_HLEN 14 ++#endif +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif +#ifndef ETH_P_ALL +#define ETH_P_ALL 0x0003 +#endif ++#ifndef ETH_P_80211_ENCAP ++#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */ ++#endif +#ifndef ETH_P_PAE +#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ +#endif /* ETH_P_PAE */ +#ifndef ETH_P_EAPOL +#define ETH_P_EAPOL ETH_P_PAE +#endif /* ETH_P_EAPOL */ +#ifndef ETH_P_RSN_PREAUTH +#define ETH_P_RSN_PREAUTH 0x88c7 +#endif /* ETH_P_RSN_PREAUTH */ +#ifndef ETH_P_RRB +#define ETH_P_RRB 0x890D +#endif /* ETH_P_RRB */ + + +#ifdef __GNUC__ +#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b)))) +#define STRUCT_PACKED __attribute__ ((packed)) +#define UNUSED __attribute__ ((unused)) +#else +#define PRINTF_FORMAT(a,b) +#define STRUCT_PACKED +#define UNUSED +#endif + + +#ifdef CONFIG_ANSI_C_EXTRA + +#if !defined(_MSC_VER) || _MSC_VER < 1400 +/* snprintf - used in number of places; sprintf() is _not_ a good replacement + * due to possible buffer overflow; see, e.g., + * http://www.ijs.si/software/snprintf/ for portable implementation of + * snprintf. */ +int snprintf(char *str, size_t size, const char *format, ...); + +/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */ +int vsnprintf(char *str, size_t size, const char *format, va_list ap); +#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */ + +/* getopt - only used in main.c */ +int getopt(int argc, char *const argv[], const char *optstring); +extern char *optarg; +extern int optind; + +#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF +#ifndef __socklen_t_defined +typedef int socklen_t; +#endif +#endif + +/* inline - define as __inline or just define it to be empty, if needed */ +#ifdef CONFIG_NO_INLINE +#define inline +#else +#define inline __inline +#endif + +#ifndef __func__ +#define __func__ "__func__ not defined" +#endif + +#ifndef bswap_16 +#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff)) +#endif + +#ifndef bswap_32 +#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \ + (((u32) (a) << 8) & 0xff0000) | \ + (((u32) (a) >> 8) & 0xff00) | \ + (((u32) (a) >> 24) & 0xff)) +#endif + +#ifndef MSG_DONTWAIT +#define MSG_DONTWAIT 0 +#endif + +#ifdef _WIN32_WCE +void perror(const char *s); +#endif /* _WIN32_WCE */ + +#endif /* CONFIG_ANSI_C_EXTRA */ + +#ifndef MAC2STR +#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5] +#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x" ++ ++/* ++ * Compact form for string representation of MAC address ++ * To be used, e.g., for constructing dbus paths for P2P Devices ++ */ ++#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x" +#endif + +#ifndef BIT - #define BIT(x) (1 << (x)) ++#define BIT(x) (1U << (x)) +#endif + +/* + * Definitions for sparse validation + * (http://kernel.org/pub/linux/kernel/people/josh/sparse/) + */ +#ifdef __CHECKER__ +#define __force __attribute__((force)) +#define __bitwise __attribute__((bitwise)) +#else +#define __force +#define __bitwise +#endif + +typedef u16 __bitwise be16; +typedef u16 __bitwise le16; +typedef u32 __bitwise be32; +typedef u32 __bitwise le32; +typedef u64 __bitwise be64; +typedef u64 __bitwise le64; + +#ifndef __must_check +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define __must_check __attribute__((__warn_unused_result__)) +#else +#define __must_check +#endif /* __GNUC__ */ +#endif /* __must_check */ + ++#ifndef __maybe_unused ++#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) ++#define __maybe_unused __attribute__((unused)) ++#else ++#define __maybe_unused ++#endif /* __GNUC__ */ ++#endif /* __must_check */ ++ +int hwaddr_aton(const char *txt, u8 *addr); ++int hwaddr_masked_aton(const char *txt, u8 *addr, u8 *mask, u8 maskable); ++int hwaddr_compact_aton(const char *txt, u8 *addr); +int hwaddr_aton2(const char *txt, u8 *addr); ++int hex2byte(const char *hex); +int hexstr2bin(const char *hex, u8 *buf, size_t len); +void inc_byte_array(u8 *counter, size_t len); +void wpa_get_ntp_timestamp(u8 *buf); ++int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...); ++int wpa_snprintf_hex_sep(char *buf, size_t buf_size, const u8 *data, size_t len, ++ char sep); +int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len); +int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data, + size_t len); + ++int hwaddr_mask_txt(char *buf, size_t len, const u8 *addr, const u8 *mask); ++ +#ifdef CONFIG_NATIVE_WINDOWS +void wpa_unicode2ascii_inplace(TCHAR *str); +TCHAR * wpa_strdup_tchar(const char *str); +#else /* CONFIG_NATIVE_WINDOWS */ +#define wpa_unicode2ascii_inplace(s) do { } while (0) +#define wpa_strdup_tchar(s) strdup((s)) +#endif /* CONFIG_NATIVE_WINDOWS */ + ++void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len); ++size_t printf_decode(u8 *buf, size_t maxlen, const char *str); ++ +const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len); + ++char * wpa_config_parse_string(const char *value, size_t *len); ++int is_hex(const u8 *data, size_t len); ++size_t merge_byte_arrays(u8 *res, size_t res_len, ++ const u8 *src1, size_t src1_len, ++ const u8 *src2, size_t src2_len); ++char * dup_binstr(const void *src, size_t len); ++ +static inline int is_zero_ether_addr(const u8 *a) +{ + return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]); +} + ++static inline int is_broadcast_ether_addr(const u8 *a) ++{ ++ return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff; ++} ++ ++static inline int is_multicast_ether_addr(const u8 *a) ++{ ++ return a[0] & 0x01; ++} ++ ++#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff" ++ +#include "wpa_debug.h" + + ++struct wpa_freq_range_list { ++ struct wpa_freq_range { ++ unsigned int min; ++ unsigned int max; ++ } *range; ++ unsigned int num; ++}; ++ ++int freq_range_list_parse(struct wpa_freq_range_list *res, const char *value); ++int freq_range_list_includes(const struct wpa_freq_range_list *list, ++ unsigned int freq); ++char * freq_range_list_str(const struct wpa_freq_range_list *list); ++ ++int int_array_len(const int *a); ++void int_array_concat(int **res, const int *a); ++void int_array_sort_unique(int *a); ++void int_array_add_unique(int **res, int a); ++ ++#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) ++ ++void str_clear_free(char *str); ++void bin_clear_free(void *bin, size_t len); ++ ++int random_mac_addr(u8 *addr); ++int random_mac_addr_keep_oui(u8 *addr); ++ ++const char * cstr_token(const char *str, const char *delim, const char **last); ++char * str_token(char *str, const char *delim, char **context); ++size_t utf8_escape(const char *inp, size_t in_size, ++ char *outp, size_t out_size); ++size_t utf8_unescape(const char *inp, size_t in_size, ++ char *outp, size_t out_size); ++int is_ctrl_char(char c); ++ ++ +/* + * gcc 4.4 ends up generating strict-aliasing warnings about some very common + * networking socket uses that do not really result in a real problem and + * cannot be easily avoided with union-based type-punning due to struct + * definitions including another struct in system header files. To avoid having + * to fully disable strict-aliasing warnings, provide a mechanism to hide the + * typecast from aliasing for now. A cleaner solution will hopefully be found + * in the future to handle these cases. + */ +void * __hide_aliasing_typecast(void *foo); +#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a)) + ++#ifdef CONFIG_VALGRIND ++#include ++#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 */ diff --cc libeap/src/utils/edit.c index 0000000,d340bfa..d340bfa mode 000000,100644..100644 --- a/libeap/src/utils/edit.c +++ b/libeap/src/utils/edit.c diff --cc libeap/src/utils/edit.h index 0000000,ad27f1c..ad27f1c mode 000000,100644..100644 --- a/libeap/src/utils/edit.h +++ b/libeap/src/utils/edit.h diff --cc libeap/src/utils/edit_readline.c index 0000000,c2a5bca..c2a5bca mode 000000,100644..100644 --- a/libeap/src/utils/edit_readline.c +++ b/libeap/src/utils/edit_readline.c diff --cc libeap/src/utils/edit_simple.c index 0000000,13173cb..13173cb mode 000000,100644..100644 --- a/libeap/src/utils/edit_simple.c +++ b/libeap/src/utils/edit_simple.c diff --cc libeap/src/utils/ext_password.c index 0000000,0613119..0613119 mode 000000,100644..100644 --- a/libeap/src/utils/ext_password.c +++ b/libeap/src/utils/ext_password.c diff --cc libeap/src/utils/ext_password.h index 0000000,e3e46ea..e3e46ea mode 000000,100644..100644 --- a/libeap/src/utils/ext_password.h +++ b/libeap/src/utils/ext_password.h diff --cc libeap/src/utils/ext_password_i.h index 0000000,043e731..043e731 mode 000000,100644..100644 --- a/libeap/src/utils/ext_password_i.h +++ b/libeap/src/utils/ext_password_i.h diff --cc libeap/src/utils/ext_password_test.c index 0000000,b3a4552..b3a4552 mode 000000,100644..100644 --- a/libeap/src/utils/ext_password_test.c +++ b/libeap/src/utils/ext_password_test.c diff --cc libeap/src/utils/http-utils.h index 0000000,8d4399a..8d4399a mode 000000,100644..100644 --- a/libeap/src/utils/http-utils.h +++ b/libeap/src/utils/http-utils.h diff --cc libeap/src/utils/http_curl.c index 0000000,653eb54..653eb54 mode 000000,100644..100644 --- a/libeap/src/utils/http_curl.c +++ b/libeap/src/utils/http_curl.c diff --cc libeap/src/utils/platform.h index 0000000,46cfe78..46cfe78 mode 000000,100644..100644 --- a/libeap/src/utils/platform.h +++ b/libeap/src/utils/platform.h diff --cc libeap/src/utils/utils_module_tests.c index 0000000,41511b9..41511b9 mode 000000,100644..100644 --- a/libeap/src/utils/utils_module_tests.c +++ b/libeap/src/utils/utils_module_tests.c diff --cc libeap/src/utils/wpa_debug.h index 0f7bf28,0000000..2dfc388 mode 100644,000000..100644 --- a/libeap/src/utils/wpa_debug.h +++ b/libeap/src/utils/wpa_debug.h @@@ -1,266 -1,0 +1,383 @@@ +/* + * wpa_supplicant/hostapd / Debug prints - * Copyright (c) 2002-2007, Jouni Malinen ++ * Copyright (c) 2002-2013, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#ifndef WPA_DEBUG_H +#define WPA_DEBUG_H + +#include "wpabuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + ++extern int wpa_debug_level; ++extern int wpa_debug_show_keys; ++extern int wpa_debug_timestamp; ++ ++ +/* Debugging function - conditional printf and hex dump. Driver wrappers can + * use these for debugging purposes. */ + +enum { + MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR +}; + +#ifdef CONFIG_NO_STDOUT_DEBUG + +#define wpa_debug_print_timestamp() do { } while (0) +#define wpa_printf(args...) do { } while (0) +#define wpa_hexdump(l,t,b,le) do { } while (0) +#define wpa_hexdump_buf(l,t,b) do { } while (0) +#define wpa_hexdump_key(l,t,b,le) do { } while (0) +#define wpa_hexdump_buf_key(l,t,b) do { } while (0) +#define wpa_hexdump_ascii(l,t,b,le) do { } while (0) +#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0) +#define wpa_debug_open_file(p) do { } while (0) +#define wpa_debug_close_file() do { } while (0) ++#define wpa_debug_setup_stdout() do { } while (0) ++#define wpa_dbg(args...) do { } while (0) ++ ++static inline int wpa_debug_reopen_file(void) ++{ ++ return 0; ++} + +#else /* CONFIG_NO_STDOUT_DEBUG */ + +int wpa_debug_open_file(const char *path); ++int wpa_debug_reopen_file(void); +void wpa_debug_close_file(void); ++void wpa_debug_setup_stdout(void); + +/** + * wpa_debug_printf_timestamp - Print timestamp for debug output + * + * This function prints a timestamp in seconds_from_1970.microsoconds + * format if debug output has been configured to include timestamps in debug + * messages. + */ +void wpa_debug_print_timestamp(void); + +/** + * wpa_printf - conditional printf + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_printf(int level, const char *fmt, ...) +PRINTF_FORMAT(2, 3); + +/** + * wpa_hexdump - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. + */ - void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len); ++void wpa_hexdump(int level, const char *title, const void *buf, size_t len); + +static inline void wpa_hexdump_buf(int level, const char *title, + const struct wpabuf *buf) +{ - wpa_hexdump(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf)); ++//!!LOCAL wpa_hexdump(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf)); ++ ++ wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL, ++ buf ? wpabuf_len(buf) : 0); +} + +/** + * wpa_hexdump_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump. This works + * like wpa_hexdump(), but by default, does not include secret keys (passwords, + * etc.) in debug output. + */ - void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len); ++void wpa_hexdump_key(int level, const char *title, const void *buf, size_t len); + +static inline void wpa_hexdump_buf_key(int level, const char *title, + const struct wpabuf *buf) +{ - wpa_hexdump_key(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf)); ++//!! LOCAL wpa_hexdump_key(level, title, (const u8 *)wpabuf_head(buf), wpabuf_len(buf)); ++ ++ wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL, ++ buf ? wpabuf_len(buf) : 0); +} + +/** + * wpa_hexdump_ascii - conditional hex dump + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. + */ - void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, ++void wpa_hexdump_ascii(int level, const char *title, const void *buf, + size_t len); + +/** + * wpa_hexdump_ascii_key - conditional hex dump, hide keys + * @level: priority level (MSG_*) of the message + * @title: title of for the message + * @buf: data buffer to be dumped + * @len: length of the buf + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. The contents of buf is printed out has hex dump with both + * the hex numbers and ASCII characters (for printable range) are shown. 16 + * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by + * default, does not include secret keys (passwords, etc.) in debug output. + */ - void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, ++void wpa_hexdump_ascii_key(int level, const char *title, const void *buf, + size_t len); + ++/* ++ * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce ++ * binary size. As such, it should be used with debugging messages that are not ++ * needed in the control interface while wpa_msg() has to be used for anything ++ * that needs to shown to control interface monitors. ++ */ ++#define wpa_dbg(args...) wpa_msg(args) ++ +#endif /* CONFIG_NO_STDOUT_DEBUG */ + + +#ifdef CONFIG_NO_WPA_MSG +#define wpa_msg(args...) do { } while (0) +#define wpa_msg_ctrl(args...) do { } while (0) ++#define wpa_msg_global(args...) do { } while (0) ++#define wpa_msg_global_ctrl(args...) do { } while (0) ++#define wpa_msg_no_global(args...) do { } while (0) ++#define wpa_msg_global_only(args...) do { } while (0) +#define wpa_msg_register_cb(f) do { } while (0) ++#define wpa_msg_register_ifname_cb(f) do { } while (0) +#else /* CONFIG_NO_WPA_MSG */ +/** + * wpa_msg - Conditional printf for default target and ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. The + * output may be directed to stdout, stderr, and/or syslog based on + * configuration. This function is like wpa_printf(), but it also sends the + * same message to all attached ctrl_iface monitors. + * + * Note: New line '\n' is added to the end of the text when printing to stdout. + */ +void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4); + +/** + * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors + * @ctx: Pointer to context data; this is the ctx variable registered + * with struct wpa_driver_ops::init() + * @level: priority level (MSG_*) of the message + * @fmt: printf format string, followed by optional arguments + * + * This function is used to print conditional debugging and error messages. + * This function is like wpa_msg(), but it sends the output only to the + * attached ctrl_iface monitors. In other words, it can be used for frequent + * events that do not need to be sent to syslog. + */ +void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...) +PRINTF_FORMAT(3, 4); + - typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt, - size_t len); ++/** ++ * wpa_msg_global - Global printf for ctrl_iface monitors ++ * @ctx: Pointer to context data; this is the ctx variable registered ++ * with struct wpa_driver_ops::init() ++ * @level: priority level (MSG_*) of the message ++ * @fmt: printf format string, followed by optional arguments ++ * ++ * This function is used to print conditional debugging and error messages. ++ * This function is like wpa_msg(), but it sends the output as a global event, ++ * i.e., without being specific to an interface. For backwards compatibility, ++ * an old style event is also delivered on one of the interfaces (the one ++ * specified by the context data). ++ */ ++void wpa_msg_global(void *ctx, int level, const char *fmt, ...) ++PRINTF_FORMAT(3, 4); ++ ++/** ++ * wpa_msg_global_ctrl - Conditional global printf for ctrl_iface monitors ++ * @ctx: Pointer to context data; this is the ctx variable registered ++ * with struct wpa_driver_ops::init() ++ * @level: priority level (MSG_*) of the message ++ * @fmt: printf format string, followed by optional arguments ++ * ++ * This function is used to print conditional debugging and error messages. ++ * This function is like wpa_msg_global(), but it sends the output only to the ++ * attached global ctrl_iface monitors. In other words, it can be used for ++ * frequent events that do not need to be sent to syslog. ++ */ ++void wpa_msg_global_ctrl(void *ctx, int level, const char *fmt, ...) ++PRINTF_FORMAT(3, 4); ++ ++/** ++ * wpa_msg_no_global - Conditional printf for ctrl_iface monitors ++ * @ctx: Pointer to context data; this is the ctx variable registered ++ * with struct wpa_driver_ops::init() ++ * @level: priority level (MSG_*) of the message ++ * @fmt: printf format string, followed by optional arguments ++ * ++ * This function is used to print conditional debugging and error messages. ++ * This function is like wpa_msg(), but it does not send the output as a global ++ * event. ++ */ ++void wpa_msg_no_global(void *ctx, int level, const char *fmt, ...) ++PRINTF_FORMAT(3, 4); ++ ++/** ++ * wpa_msg_global_only - Conditional printf for ctrl_iface monitors ++ * @ctx: Pointer to context data; this is the ctx variable registered ++ * with struct wpa_driver_ops::init() ++ * @level: priority level (MSG_*) of the message ++ * @fmt: printf format string, followed by optional arguments ++ * ++ * This function is used to print conditional debugging and error messages. ++ * This function is like wpa_msg_global(), but it sends the output only as a ++ * global event. ++ */ ++void wpa_msg_global_only(void *ctx, int level, const char *fmt, ...) ++PRINTF_FORMAT(3, 4); ++ ++enum wpa_msg_type { ++ WPA_MSG_PER_INTERFACE, ++ WPA_MSG_GLOBAL, ++ WPA_MSG_NO_GLOBAL, ++ WPA_MSG_ONLY_GLOBAL, ++}; ++ ++typedef void (*wpa_msg_cb_func)(void *ctx, int level, enum wpa_msg_type type, ++ const char *txt, size_t len); + +/** + * wpa_msg_register_cb - Register callback function for wpa_msg() messages + * @func: Callback function (%NULL to unregister) + */ +void wpa_msg_register_cb(wpa_msg_cb_func func); - #endif /* CONFIG_NO_WPA_MSG */ + ++typedef const char * (*wpa_msg_get_ifname_func)(void *ctx); ++void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func); ++ ++#endif /* CONFIG_NO_WPA_MSG */ + +#ifdef CONFIG_NO_HOSTAPD_LOGGER +#define hostapd_logger(args...) do { } while (0) +#define hostapd_logger_register_cb(f) do { } while (0) +#else /* CONFIG_NO_HOSTAPD_LOGGER */ +void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level, + const char *fmt, ...) PRINTF_FORMAT(5, 6); + +typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr, + unsigned int module, int level, + const char *txt, size_t len); + +/** + * hostapd_logger_register_cb - Register callback function for hostapd_logger() + * @func: Callback function (%NULL to unregister) + */ +void hostapd_logger_register_cb(hostapd_logger_cb_func func); +#endif /* CONFIG_NO_HOSTAPD_LOGGER */ + +#define HOSTAPD_MODULE_IEEE80211 0x00000001 +#define HOSTAPD_MODULE_IEEE8021X 0x00000002 +#define HOSTAPD_MODULE_RADIUS 0x00000004 +#define HOSTAPD_MODULE_WPA 0x00000008 +#define HOSTAPD_MODULE_DRIVER 0x00000010 +#define HOSTAPD_MODULE_IAPP 0x00000020 +#define HOSTAPD_MODULE_MLME 0x00000040 + +enum hostapd_logger_level { + HOSTAPD_LEVEL_DEBUG_VERBOSE = 0, + HOSTAPD_LEVEL_DEBUG = 1, + HOSTAPD_LEVEL_INFO = 2, + HOSTAPD_LEVEL_NOTICE = 3, + HOSTAPD_LEVEL_WARNING = 4 +}; + + +#ifdef CONFIG_DEBUG_SYSLOG + +void wpa_debug_open_syslog(void); +void wpa_debug_close_syslog(void); + +#else /* CONFIG_DEBUG_SYSLOG */ + +static inline void wpa_debug_open_syslog(void) +{ +} + +static inline void wpa_debug_close_syslog(void) +{ +} + +#endif /* CONFIG_DEBUG_SYSLOG */ + ++#ifdef CONFIG_DEBUG_LINUX_TRACING ++ ++int wpa_debug_open_linux_tracing(void); ++void wpa_debug_close_linux_tracing(void); ++ ++#else /* CONFIG_DEBUG_LINUX_TRACING */ ++ ++static inline int wpa_debug_open_linux_tracing(void) ++{ ++ return 0; ++} ++ ++static inline void wpa_debug_close_linux_tracing(void) ++{ ++} ++ ++#endif /* CONFIG_DEBUG_LINUX_TRACING */ ++ + +#ifdef EAPOL_TEST +#define WPA_ASSERT(a) \ + do { \ + if (!(a)) { \ + printf("WPA_ASSERT FAILED '" #a "' " \ + "%s %s:%d\n", \ + __FUNCTION__, __FILE__, __LINE__); \ + exit(1); \ + } \ + } while (0) +#else +#define WPA_ASSERT(a) do { } while (0) +#endif + ++const char * debug_level_str(int level); ++int str_to_debug_level(const char *s); ++ +#ifdef __cplusplus +} +#endif + +#endif /* WPA_DEBUG_H */ diff --cc libeap/src/utils/wpabuf.h index 44c0510,0000000..64b3d8d mode 100644,000000..100644 --- a/libeap/src/utils/wpabuf.h +++ b/libeap/src/utils/wpabuf.h @@@ -1,176 -1,0 +1,171 @@@ +/* + * Dynamic data buffer - * Copyright (c) 2007-2009, Jouni Malinen ++ * Copyright (c) 2007-2012, Jouni Malinen + * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Alternatively, this software may be distributed under the terms of BSD - * license. - * - * See README and COPYING for more details. ++ * This software may be distributed under the terms of the BSD license. ++ * See README for more details. + */ + +#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 *ext_data; /* pointer to external data; NULL if data follows - * struct wpabuf */ ++ u8 *buf; /* pointer to the head of the buffer */ ++ unsigned int flags; + /* optionally followed by the allocated buffer */ +}; + + +int wpabuf_resize(struct wpabuf **buf, size_t add_len); +struct wpabuf * wpabuf_alloc(size_t len); +struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len); +struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len); +struct wpabuf * wpabuf_dup(const struct wpabuf *src); +void wpabuf_free(struct wpabuf *buf); ++void wpabuf_clear_free(struct wpabuf *buf); +void * wpabuf_put(struct wpabuf *buf, size_t len); +struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); +void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3); + + +/** + * wpabuf_size - Get the currently allocated size of a wpabuf buffer + * @buf: wpabuf buffer + * Returns: Currently allocated size of the buffer + */ +static inline size_t wpabuf_size(const struct wpabuf *buf) +{ + return buf->size; +} + +/** + * wpabuf_len - Get the current length of a wpabuf buffer data + * @buf: wpabuf buffer + * Returns: Currently used length of the buffer + */ +static inline size_t wpabuf_len(const struct wpabuf *buf) +{ + return buf->used; +} + +/** + * wpabuf_tailroom - Get size of available tail room in the end of the buffer + * @buf: wpabuf buffer + * Returns: Tail room (in bytes) of available space in the end of the buffer + */ +static inline size_t wpabuf_tailroom(const struct wpabuf *buf) +{ + return buf->size - buf->used; +} + +/** + * wpabuf_head - Get pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline const void * wpabuf_head(const struct wpabuf *buf) +{ - if (buf->ext_data) - return buf->ext_data; - return buf + 1; ++ return buf->buf; +} + +static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf) +{ + return (const u8 *)wpabuf_head(buf); +} + +/** + * wpabuf_mhead - Get modifiable pointer to the head of the buffer data + * @buf: wpabuf buffer + * Returns: Pointer to the head of the buffer data + */ +static inline void * wpabuf_mhead(struct wpabuf *buf) +{ - if (buf->ext_data) - return buf->ext_data; - return buf + 1; ++ return buf->buf; +} + +static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf) +{ + return (u8 *)wpabuf_mhead(buf); +} + +static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 1); + *pos = data; +} + +static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 2); + WPA_PUT_LE16(pos, data); +} + +static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 4); + WPA_PUT_LE32(pos, data); +} + +static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 2); + WPA_PUT_BE16(pos, data); +} + +static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 3); + WPA_PUT_BE24(pos, data); +} + +static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data) +{ + u8 *pos = (u8 *)wpabuf_put(buf, 4); + WPA_PUT_BE32(pos, data); +} + +static inline void wpabuf_put_data(struct wpabuf *buf, const void *data, + size_t len) +{ + if (data) + os_memcpy(wpabuf_put(buf, len), data, len); +} + +static inline void wpabuf_put_buf(struct wpabuf *dst, + const struct wpabuf *src) +{ + wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src)); +} + +static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len) +{ - buf->ext_data = (u8 *) data; ++ 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 */ diff --cc libeap/src/utils/xml-utils.c index 0000000,4916d29..4916d29 mode 000000,100644..100644 --- a/libeap/src/utils/xml-utils.c +++ b/libeap/src/utils/xml-utils.c diff --cc libeap/src/utils/xml-utils.h index 0000000,fb6208c..fb6208c mode 000000,100644..100644 --- a/libeap/src/utils/xml-utils.h +++ b/libeap/src/utils/xml-utils.h diff --cc libeap/src/utils/xml_libxml2.c index 0000000,c928394..c928394 mode 000000,100644..100644 --- a/libeap/src/utils/xml_libxml2.c +++ b/libeap/src/utils/xml_libxml2.c diff --cc libeap/src/wps/wps_attr_parse.h index 0000000,8188fe9..8188fe9 mode 000000,100644..100644 --- a/libeap/src/wps/wps_attr_parse.h +++ b/libeap/src/wps/wps_attr_parse.h diff --cc libeap/src/wps/wps_module_tests.c index 0000000,3506307..3506307 mode 000000,100644..100644 --- a/libeap/src/wps/wps_module_tests.c +++ b/libeap/src/wps/wps_module_tests.c diff --cc libeap/tests/ap-mgmt-fuzzer/Makefile index 0000000,141a6f6..141a6f6 mode 000000,100644..100644 --- a/libeap/tests/ap-mgmt-fuzzer/Makefile +++ b/libeap/tests/ap-mgmt-fuzzer/Makefile diff --cc libeap/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c index 0000000,dd06144..dd06144 mode 000000,100644..100644 --- a/libeap/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c +++ b/libeap/tests/ap-mgmt-fuzzer/ap-mgmt-fuzzer.c diff --cc libeap/tests/ap-mgmt-fuzzer/auth.dat index 0000000,0eb36e5..0eb36e5 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/ap-mgmt-fuzzer/probe-req.dat index 0000000,a5fba77..a5fba77 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/eapol-fuzzer/Makefile index 0000000,f5a9a57..f5a9a57 mode 000000,100644..100644 --- a/libeap/tests/eapol-fuzzer/Makefile +++ b/libeap/tests/eapol-fuzzer/Makefile diff --cc libeap/tests/eapol-fuzzer/eap-req-identity.dat index 0000000,768b277..768b277 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/eapol-fuzzer/eap-req-sim.dat index 0000000,eb854aa..eb854aa mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/eapol-fuzzer/eapol-fuzzer.c index 0000000,7429ee3..7429ee3 mode 000000,100644..100644 --- a/libeap/tests/eapol-fuzzer/eapol-fuzzer.c +++ b/libeap/tests/eapol-fuzzer/eapol-fuzzer.c diff --cc libeap/tests/eapol-fuzzer/eapol-key-m1.dat index 0000000,937721c..937721c mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/README index 0000000,e68b0dc..e68b0dc mode 000000,100644..100644 --- a/libeap/tests/hwsim/README +++ b/libeap/tests/hwsim/README diff --cc libeap/tests/hwsim/auth_serv/as.conf index 0000000,0d89b92..0d89b92 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/as.conf +++ b/libeap/tests/hwsim/auth_serv/as.conf diff --cc libeap/tests/hwsim/auth_serv/as2.conf index 0000000,d9ee031..d9ee031 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/as2.conf +++ b/libeap/tests/hwsim/auth_serv/as2.conf diff --cc libeap/tests/hwsim/auth_serv/ca-and-crl.pem index 0000000,ba79339..ba79339 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ca-and-crl.pem +++ b/libeap/tests/hwsim/auth_serv/ca-and-crl.pem diff --cc libeap/tests/hwsim/auth_serv/ca-incorrect.pem index 0000000,2e9a492..2e9a492 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ca-incorrect.pem +++ b/libeap/tests/hwsim/auth_serv/ca-incorrect.pem diff --cc libeap/tests/hwsim/auth_serv/ca.der index 0000000,09d5fa0..09d5fa0 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/auth_serv/ca.pem index 0000000,b128893..b128893 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ca.pem +++ b/libeap/tests/hwsim/auth_serv/ca.pem diff --cc libeap/tests/hwsim/auth_serv/dh.conf index 0000000,7bc8325..7bc8325 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/dh.conf +++ b/libeap/tests/hwsim/auth_serv/dh.conf diff --cc libeap/tests/hwsim/auth_serv/dh2.conf index 0000000,5532efe..5532efe mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/dh2.conf +++ b/libeap/tests/hwsim/auth_serv/dh2.conf diff --cc libeap/tests/hwsim/auth_serv/dsaparam.pem index 0000000,54ba66a..54ba66a mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/dsaparam.pem +++ b/libeap/tests/hwsim/auth_serv/dsaparam.pem diff --cc libeap/tests/hwsim/auth_serv/eap_user.conf index 0000000,3738e6c..3738e6c mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/eap_user.conf +++ b/libeap/tests/hwsim/auth_serv/eap_user.conf diff --cc libeap/tests/hwsim/auth_serv/eap_user_vlan.conf index 0000000,e5ad0d7..e5ad0d7 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/eap_user_vlan.conf +++ b/libeap/tests/hwsim/auth_serv/eap_user_vlan.conf diff --cc libeap/tests/hwsim/auth_serv/ec-ca-openssl.cnf index 0000000,c803dd3..c803dd3 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec-ca-openssl.cnf +++ b/libeap/tests/hwsim/auth_serv/ec-ca-openssl.cnf diff --cc libeap/tests/hwsim/auth_serv/ec-ca.pem index 0000000,a04b886..a04b886 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec-ca.pem +++ b/libeap/tests/hwsim/auth_serv/ec-ca.pem diff --cc libeap/tests/hwsim/auth_serv/ec-generate.sh index 0000000,c9fdabc..c9fdabc mode 000000,100755..100755 --- a/libeap/tests/hwsim/auth_serv/ec-generate.sh +++ b/libeap/tests/hwsim/auth_serv/ec-generate.sh diff --cc libeap/tests/hwsim/auth_serv/ec-server.key index 0000000,391e9ed..391e9ed mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec-server.key +++ b/libeap/tests/hwsim/auth_serv/ec-server.key diff --cc libeap/tests/hwsim/auth_serv/ec-server.pem index 0000000,4222b1e..4222b1e mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec-server.pem +++ b/libeap/tests/hwsim/auth_serv/ec-server.pem diff --cc libeap/tests/hwsim/auth_serv/ec-user.key index 0000000,e390c06..e390c06 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec-user.key +++ b/libeap/tests/hwsim/auth_serv/ec-user.key diff --cc libeap/tests/hwsim/auth_serv/ec-user.pem index 0000000,9a6aba8..9a6aba8 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec-user.pem +++ b/libeap/tests/hwsim/auth_serv/ec-user.pem diff --cc libeap/tests/hwsim/auth_serv/ec2-ca.pem index 0000000,0054ba8..0054ba8 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec2-ca.pem +++ b/libeap/tests/hwsim/auth_serv/ec2-ca.pem diff --cc libeap/tests/hwsim/auth_serv/ec2-generate.sh index 0000000,5a8d2d2..5a8d2d2 mode 000000,100755..100755 --- a/libeap/tests/hwsim/auth_serv/ec2-generate.sh +++ b/libeap/tests/hwsim/auth_serv/ec2-generate.sh diff --cc libeap/tests/hwsim/auth_serv/ec2-server.key index 0000000,9cd76ee..9cd76ee mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec2-server.key +++ b/libeap/tests/hwsim/auth_serv/ec2-server.key diff --cc libeap/tests/hwsim/auth_serv/ec2-server.pem index 0000000,a7cc37e..a7cc37e mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec2-server.pem +++ b/libeap/tests/hwsim/auth_serv/ec2-server.pem diff --cc libeap/tests/hwsim/auth_serv/ec2-user.key index 0000000,adfa937..adfa937 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec2-user.key +++ b/libeap/tests/hwsim/auth_serv/ec2-user.key diff --cc libeap/tests/hwsim/auth_serv/ec2-user.pem index 0000000,ef86cd1..ef86cd1 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ec2-user.pem +++ b/libeap/tests/hwsim/auth_serv/ec2-user.pem diff --cc libeap/tests/hwsim/auth_serv/hlr_auc_gw.gsm index 0000000,b67aeca..b67aeca mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/hlr_auc_gw.gsm +++ b/libeap/tests/hwsim/auth_serv/hlr_auc_gw.gsm diff --cc libeap/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db index 0000000,ecd06d7..ecd06d7 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db +++ b/libeap/tests/hwsim/auth_serv/hlr_auc_gw.milenage_db diff --cc libeap/tests/hwsim/auth_serv/index-revoked.txt index 0000000,95b052e..95b052e mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/index-revoked.txt +++ b/libeap/tests/hwsim/auth_serv/index-revoked.txt diff --cc libeap/tests/hwsim/auth_serv/index-unknown.txt index 0000000,97dfbba..97dfbba mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/index-unknown.txt +++ b/libeap/tests/hwsim/auth_serv/index-unknown.txt diff --cc libeap/tests/hwsim/auth_serv/index.txt index 0000000,52c8e0c..52c8e0c mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/index.txt +++ b/libeap/tests/hwsim/auth_serv/index.txt diff --cc libeap/tests/hwsim/auth_serv/ocsp-req.der index 0000000,20999b9..20999b9 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/auth_serv/ocsp-responder.key index 0000000,fb866fb..fb866fb mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ocsp-responder.key +++ b/libeap/tests/hwsim/auth_serv/ocsp-responder.key diff --cc libeap/tests/hwsim/auth_serv/ocsp-responder.pem index 0000000,bbde1e8..bbde1e8 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/ocsp-responder.pem +++ b/libeap/tests/hwsim/auth_serv/ocsp-responder.pem diff --cc libeap/tests/hwsim/auth_serv/ocsp-server-cache.der index 0000000,33e6753..33e6753 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/auth_serv/ocsp-server-cache.der-invalid index 0000000,218bd03..218bd03 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/auth_serv/radius_clients.conf index 0000000,7e34015..7e34015 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/radius_clients.conf +++ b/libeap/tests/hwsim/auth_serv/radius_clients.conf diff --cc libeap/tests/hwsim/auth_serv/radius_clients_ipv6.conf index 0000000,8723efc..8723efc mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/radius_clients_ipv6.conf +++ b/libeap/tests/hwsim/auth_serv/radius_clients_ipv6.conf diff --cc libeap/tests/hwsim/auth_serv/server-eku-client-server.key index 0000000,ce2e5f2..ce2e5f2 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-eku-client-server.key +++ b/libeap/tests/hwsim/auth_serv/server-eku-client-server.key diff --cc libeap/tests/hwsim/auth_serv/server-eku-client-server.pem index 0000000,7ed4014..7ed4014 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-eku-client-server.pem +++ b/libeap/tests/hwsim/auth_serv/server-eku-client-server.pem diff --cc libeap/tests/hwsim/auth_serv/server-eku-client.key index 0000000,f2a99cd..f2a99cd mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-eku-client.key +++ b/libeap/tests/hwsim/auth_serv/server-eku-client.key diff --cc libeap/tests/hwsim/auth_serv/server-eku-client.pem index 0000000,cbb8437..cbb8437 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-eku-client.pem +++ b/libeap/tests/hwsim/auth_serv/server-eku-client.pem diff --cc libeap/tests/hwsim/auth_serv/server-expired.key index 0000000,882d645..882d645 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-expired.key +++ b/libeap/tests/hwsim/auth_serv/server-expired.key diff --cc libeap/tests/hwsim/auth_serv/server-expired.pem index 0000000,f279aae..f279aae mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-expired.pem +++ b/libeap/tests/hwsim/auth_serv/server-expired.pem diff --cc libeap/tests/hwsim/auth_serv/server-long-duration.key index 0000000,8578515..8578515 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-long-duration.key +++ b/libeap/tests/hwsim/auth_serv/server-long-duration.key diff --cc libeap/tests/hwsim/auth_serv/server-long-duration.pem index 0000000,442a054..442a054 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-long-duration.pem +++ b/libeap/tests/hwsim/auth_serv/server-long-duration.pem diff --cc libeap/tests/hwsim/auth_serv/server-no-dnsname.key index 0000000,fd0ad39..fd0ad39 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-no-dnsname.key +++ b/libeap/tests/hwsim/auth_serv/server-no-dnsname.key diff --cc libeap/tests/hwsim/auth_serv/server-no-dnsname.pem index 0000000,93d0ec2..93d0ec2 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server-no-dnsname.pem +++ b/libeap/tests/hwsim/auth_serv/server-no-dnsname.pem diff --cc libeap/tests/hwsim/auth_serv/server.key index 0000000,1416327..1416327 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server.key +++ b/libeap/tests/hwsim/auth_serv/server.key diff --cc libeap/tests/hwsim/auth_serv/server.pem index 0000000,fa3e0ae..fa3e0ae mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/server.pem +++ b/libeap/tests/hwsim/auth_serv/server.pem diff --cc libeap/tests/hwsim/auth_serv/server.pkcs12 index 0000000,7061fd7..7061fd7 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/auth_serv/user.key index 0000000,b9fd702..b9fd702 mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/user.key +++ b/libeap/tests/hwsim/auth_serv/user.key diff --cc libeap/tests/hwsim/auth_serv/user.pem index 0000000,4bc2e1a..4bc2e1a mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/user.pem +++ b/libeap/tests/hwsim/auth_serv/user.pem diff --cc libeap/tests/hwsim/auth_serv/user.pkcs12 index 0000000,0d50201..0d50201 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/auth_serv/user.rsa-key index 0000000,4c3cfbf..4c3cfbf mode 000000,100644..100644 --- a/libeap/tests/hwsim/auth_serv/user.rsa-key +++ b/libeap/tests/hwsim/auth_serv/user.rsa-key diff --cc libeap/tests/hwsim/auth_serv/user2.pkcs12 index 0000000,eb17d9c..eb17d9c mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/auth_serv/user3.pkcs12 index 0000000,953d7cb..953d7cb mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/bss-1.conf index 0000000,b465dcb..b465dcb mode 000000,100644..100644 --- a/libeap/tests/hwsim/bss-1.conf +++ b/libeap/tests/hwsim/bss-1.conf diff --cc libeap/tests/hwsim/bss-2.conf index 0000000,7a8c64c..7a8c64c mode 000000,100644..100644 --- a/libeap/tests/hwsim/bss-2.conf +++ b/libeap/tests/hwsim/bss-2.conf diff --cc libeap/tests/hwsim/bss-3.conf index 0000000,fe671de..fe671de mode 000000,100644..100644 --- a/libeap/tests/hwsim/bss-3.conf +++ b/libeap/tests/hwsim/bss-3.conf diff --cc libeap/tests/hwsim/bss-ht40-1.conf index 0000000,a338c6b..a338c6b mode 000000,100644..100644 --- a/libeap/tests/hwsim/bss-ht40-1.conf +++ b/libeap/tests/hwsim/bss-ht40-1.conf diff --cc libeap/tests/hwsim/bss-ht40-2.conf index 0000000,c7e27ce..c7e27ce mode 000000,100644..100644 --- a/libeap/tests/hwsim/bss-ht40-2.conf +++ b/libeap/tests/hwsim/bss-ht40-2.conf diff --cc libeap/tests/hwsim/build.sh index 0000000,b35e0f1..b35e0f1 mode 000000,100755..100755 --- a/libeap/tests/hwsim/build.sh +++ b/libeap/tests/hwsim/build.sh diff --cc libeap/tests/hwsim/check_kernel.py index 0000000,15e5856..15e5856 mode 000000,100644..100644 --- a/libeap/tests/hwsim/check_kernel.py +++ b/libeap/tests/hwsim/check_kernel.py diff --cc libeap/tests/hwsim/dictionary.radius index 0000000,295ccd3..295ccd3 mode 000000,100644..100644 --- a/libeap/tests/hwsim/dictionary.radius +++ b/libeap/tests/hwsim/dictionary.radius diff --cc libeap/tests/hwsim/example-hostapd.config index 0000000,085092a..085092a mode 000000,100644..100644 --- a/libeap/tests/hwsim/example-hostapd.config +++ b/libeap/tests/hwsim/example-hostapd.config diff --cc libeap/tests/hwsim/example-setup.txt index 0000000,2396b97..2396b97 mode 000000,100644..100644 --- a/libeap/tests/hwsim/example-setup.txt +++ b/libeap/tests/hwsim/example-setup.txt diff --cc libeap/tests/hwsim/example-wpa_supplicant.config index 0000000,67b767c..67b767c mode 000000,100644..100644 --- a/libeap/tests/hwsim/example-wpa_supplicant.config +++ b/libeap/tests/hwsim/example-wpa_supplicant.config diff --cc libeap/tests/hwsim/fst_module_aux.py index 0000000,286fa85..286fa85 mode 000000,100644..100644 --- a/libeap/tests/hwsim/fst_module_aux.py +++ b/libeap/tests/hwsim/fst_module_aux.py diff --cc libeap/tests/hwsim/fst_test_common.py index 0000000,22d0ff6..22d0ff6 mode 000000,100644..100644 --- a/libeap/tests/hwsim/fst_test_common.py +++ b/libeap/tests/hwsim/fst_test_common.py diff --cc libeap/tests/hwsim/hostapd.accept index 0000000,ce455b1..ce455b1 mode 000000,100644..100644 --- a/libeap/tests/hwsim/hostapd.accept +++ b/libeap/tests/hwsim/hostapd.accept diff --cc libeap/tests/hwsim/hostapd.macaddr index 0000000,b39390d..b39390d mode 000000,100644..100644 --- a/libeap/tests/hwsim/hostapd.macaddr +++ b/libeap/tests/hwsim/hostapd.macaddr diff --cc libeap/tests/hwsim/hostapd.py index 0000000,33cfa62..33cfa62 mode 000000,100644..100644 --- a/libeap/tests/hwsim/hostapd.py +++ b/libeap/tests/hwsim/hostapd.py diff --cc libeap/tests/hwsim/hostapd.vlan index 0000000,b0e905b..b0e905b mode 000000,100644..100644 --- a/libeap/tests/hwsim/hostapd.vlan +++ b/libeap/tests/hwsim/hostapd.vlan diff --cc libeap/tests/hwsim/hostapd.wlan3.vlan index 0000000,3155e26..3155e26 mode 000000,100644..100644 --- a/libeap/tests/hwsim/hostapd.wlan3.vlan +++ b/libeap/tests/hwsim/hostapd.wlan3.vlan diff --cc libeap/tests/hwsim/hostapd.wlan4.vlan index 0000000,75ac704..75ac704 mode 000000,100644..100644 --- a/libeap/tests/hwsim/hostapd.wlan4.vlan +++ b/libeap/tests/hwsim/hostapd.wlan4.vlan diff --cc libeap/tests/hwsim/hostapd.wpa_psk index 0000000,7644f89..7644f89 mode 000000,100644..100644 --- a/libeap/tests/hwsim/hostapd.wpa_psk +++ b/libeap/tests/hwsim/hostapd.wpa_psk diff --cc libeap/tests/hwsim/hwsim.py index 0000000,e21c814..e21c814 mode 000000,100644..100644 --- a/libeap/tests/hwsim/hwsim.py +++ b/libeap/tests/hwsim/hwsim.py diff --cc libeap/tests/hwsim/hwsim_utils.py index 0000000,85f54a2..85f54a2 mode 000000,100644..100644 --- a/libeap/tests/hwsim/hwsim_utils.py +++ b/libeap/tests/hwsim/hwsim_utils.py diff --cc libeap/tests/hwsim/multi-bss-acs.conf index 0000000,4e1db46..4e1db46 mode 000000,100644..100644 --- a/libeap/tests/hwsim/multi-bss-acs.conf +++ b/libeap/tests/hwsim/multi-bss-acs.conf diff --cc libeap/tests/hwsim/multi-bss-iface.conf index 0000000,6b6167f..6b6167f mode 000000,100644..100644 --- a/libeap/tests/hwsim/multi-bss-iface.conf +++ b/libeap/tests/hwsim/multi-bss-iface.conf diff --cc libeap/tests/hwsim/multi-bss.conf index 0000000,64584b6..64584b6 mode 000000,100644..100644 --- a/libeap/tests/hwsim/multi-bss.conf +++ b/libeap/tests/hwsim/multi-bss.conf diff --cc libeap/tests/hwsim/netlink.py index 0000000,82b6fa2..82b6fa2 mode 000000,100644..100644 --- a/libeap/tests/hwsim/netlink.py +++ b/libeap/tests/hwsim/netlink.py diff --cc libeap/tests/hwsim/nl80211.py index 0000000,440c820..440c820 mode 000000,100644..100644 --- a/libeap/tests/hwsim/nl80211.py +++ b/libeap/tests/hwsim/nl80211.py diff --cc libeap/tests/hwsim/p2p0.conf index 0000000,9482bdc..9482bdc mode 000000,100644..100644 --- a/libeap/tests/hwsim/p2p0.conf +++ b/libeap/tests/hwsim/p2p0.conf diff --cc libeap/tests/hwsim/p2p1.conf index 0000000,3622b15..3622b15 mode 000000,100644..100644 --- a/libeap/tests/hwsim/p2p1.conf +++ b/libeap/tests/hwsim/p2p1.conf diff --cc libeap/tests/hwsim/p2p2.conf index 0000000,eda52e1..eda52e1 mode 000000,100644..100644 --- a/libeap/tests/hwsim/p2p2.conf +++ b/libeap/tests/hwsim/p2p2.conf diff --cc libeap/tests/hwsim/radius_das.py index 0000000,300681a..300681a mode 000000,100644..100644 --- a/libeap/tests/hwsim/radius_das.py +++ b/libeap/tests/hwsim/radius_das.py diff --cc libeap/tests/hwsim/rfkill.py index 0000000,cf73f4f..cf73f4f mode 000000,100755..100755 --- a/libeap/tests/hwsim/rfkill.py +++ b/libeap/tests/hwsim/rfkill.py diff --cc libeap/tests/hwsim/run-all.sh index 0000000,5cf56a9..5cf56a9 mode 000000,100755..100755 --- a/libeap/tests/hwsim/run-all.sh +++ b/libeap/tests/hwsim/run-all.sh diff --cc libeap/tests/hwsim/run-tests.py index 0000000,13e360b..13e360b mode 000000,100755..100755 --- a/libeap/tests/hwsim/run-tests.py +++ b/libeap/tests/hwsim/run-tests.py diff --cc libeap/tests/hwsim/start.sh index 0000000,f71f64f..f71f64f mode 000000,100755..100755 --- a/libeap/tests/hwsim/start.sh +++ b/libeap/tests/hwsim/start.sh diff --cc libeap/tests/hwsim/stop.sh index 0000000,5d23b5b..5d23b5b mode 000000,100755..100755 --- a/libeap/tests/hwsim/stop.sh +++ b/libeap/tests/hwsim/stop.sh diff --cc libeap/tests/hwsim/test_ap_acs.py index 0000000,a4a4e30..a4a4e30 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_acs.py +++ b/libeap/tests/hwsim/test_ap_acs.py diff --cc libeap/tests/hwsim/test_ap_ciphers.py index 0000000,9d4e868..9d4e868 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_ciphers.py +++ b/libeap/tests/hwsim/test_ap_ciphers.py diff --cc libeap/tests/hwsim/test_ap_config.py index 0000000,aec70f7..aec70f7 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_config.py +++ b/libeap/tests/hwsim/test_ap_config.py diff --cc libeap/tests/hwsim/test_ap_csa.py index 0000000,c88e517..c88e517 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_csa.py +++ b/libeap/tests/hwsim/test_ap_csa.py diff --cc libeap/tests/hwsim/test_ap_dynamic.py index 0000000,19eb9c4..19eb9c4 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_dynamic.py +++ b/libeap/tests/hwsim/test_ap_dynamic.py diff --cc libeap/tests/hwsim/test_ap_eap.py index 0000000,f7d910e..f7d910e mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_eap.py +++ b/libeap/tests/hwsim/test_ap_eap.py diff --cc libeap/tests/hwsim/test_ap_ft.py index 0000000,f95966c..f95966c mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_ft.py +++ b/libeap/tests/hwsim/test_ap_ft.py diff --cc libeap/tests/hwsim/test_ap_hs20.py index 0000000,27f9e87..27f9e87 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_hs20.py +++ b/libeap/tests/hwsim/test_ap_hs20.py diff --cc libeap/tests/hwsim/test_ap_ht.py index 0000000,8a8aa9f..8a8aa9f mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_ht.py +++ b/libeap/tests/hwsim/test_ap_ht.py diff --cc libeap/tests/hwsim/test_ap_mixed.py index 0000000,c342d39..c342d39 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_mixed.py +++ b/libeap/tests/hwsim/test_ap_mixed.py diff --cc libeap/tests/hwsim/test_ap_open.py index 0000000,139756e..139756e mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_open.py +++ b/libeap/tests/hwsim/test_ap_open.py diff --cc libeap/tests/hwsim/test_ap_params.py index 0000000,517f2a7..517f2a7 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_params.py +++ b/libeap/tests/hwsim/test_ap_params.py diff --cc libeap/tests/hwsim/test_ap_pmf.py index 0000000,62306b5..62306b5 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_pmf.py +++ b/libeap/tests/hwsim/test_ap_pmf.py diff --cc libeap/tests/hwsim/test_ap_psk.py index 0000000,281d54b..281d54b mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_psk.py +++ b/libeap/tests/hwsim/test_ap_psk.py diff --cc libeap/tests/hwsim/test_ap_qosmap.py index 0000000,67604b2..67604b2 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_qosmap.py +++ b/libeap/tests/hwsim/test_ap_qosmap.py diff --cc libeap/tests/hwsim/test_ap_roam.py index 0000000,f41e272..f41e272 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_roam.py +++ b/libeap/tests/hwsim/test_ap_roam.py diff --cc libeap/tests/hwsim/test_ap_tdls.py index 0000000,bcfa3cc..bcfa3cc mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_tdls.py +++ b/libeap/tests/hwsim/test_ap_tdls.py diff --cc libeap/tests/hwsim/test_ap_track.py index 0000000,5ca2b60..5ca2b60 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_track.py +++ b/libeap/tests/hwsim/test_ap_track.py diff --cc libeap/tests/hwsim/test_ap_vht.py index 0000000,d883114..d883114 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_vht.py +++ b/libeap/tests/hwsim/test_ap_vht.py diff --cc libeap/tests/hwsim/test_ap_vlan.py index 0000000,822bf99..822bf99 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_vlan.py +++ b/libeap/tests/hwsim/test_ap_vlan.py diff --cc libeap/tests/hwsim/test_ap_wps.py index 0000000,1561792..1561792 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ap_wps.py +++ b/libeap/tests/hwsim/test_ap_wps.py diff --cc libeap/tests/hwsim/test_autoscan.py index 0000000,97d29e9..97d29e9 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_autoscan.py +++ b/libeap/tests/hwsim/test_autoscan.py diff --cc libeap/tests/hwsim/test_bgscan.py index 0000000,c73fdeb..c73fdeb mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_bgscan.py +++ b/libeap/tests/hwsim/test_bgscan.py diff --cc libeap/tests/hwsim/test_cfg80211.py index 0000000,e67ad98..e67ad98 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_cfg80211.py +++ b/libeap/tests/hwsim/test_cfg80211.py diff --cc libeap/tests/hwsim/test_connect_cmd.py index 0000000,3f4c42b..3f4c42b mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_connect_cmd.py +++ b/libeap/tests/hwsim/test_connect_cmd.py diff --cc libeap/tests/hwsim/test_dbus.py index 0000000,dba899e..dba899e mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_dbus.py +++ b/libeap/tests/hwsim/test_dbus.py diff --cc libeap/tests/hwsim/test_dbus_old.py index 0000000,c7c7e19..c7c7e19 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_dbus_old.py +++ b/libeap/tests/hwsim/test_dbus_old.py diff --cc libeap/tests/hwsim/test_dfs.py index 0000000,592736e..592736e mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_dfs.py +++ b/libeap/tests/hwsim/test_dfs.py diff --cc libeap/tests/hwsim/test_eap_proto.py index 0000000,f0c8a52..f0c8a52 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_eap_proto.py +++ b/libeap/tests/hwsim/test_eap_proto.py diff --cc libeap/tests/hwsim/test_erp.py index 0000000,c4f2fa5..c4f2fa5 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_erp.py +++ b/libeap/tests/hwsim/test_erp.py diff --cc libeap/tests/hwsim/test_ext_password.py index 0000000,c70895c..c70895c mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ext_password.py +++ b/libeap/tests/hwsim/test_ext_password.py diff --cc libeap/tests/hwsim/test_fst_config.py index 0000000,938cf9a..938cf9a mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_fst_config.py +++ b/libeap/tests/hwsim/test_fst_config.py diff --cc libeap/tests/hwsim/test_fst_module.py index 0000000,1f62db1..1f62db1 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_fst_module.py +++ b/libeap/tests/hwsim/test_fst_module.py diff --cc libeap/tests/hwsim/test_gas.py index 0000000,416d616..416d616 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_gas.py +++ b/libeap/tests/hwsim/test_gas.py diff --cc libeap/tests/hwsim/test_hapd_ctrl.py index 0000000,e45eca0..e45eca0 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_hapd_ctrl.py +++ b/libeap/tests/hwsim/test_hapd_ctrl.py diff --cc libeap/tests/hwsim/test_hostapd_oom.py index 0000000,cb91225..cb91225 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_hostapd_oom.py +++ b/libeap/tests/hwsim/test_hostapd_oom.py diff --cc libeap/tests/hwsim/test_ibss.py index 0000000,59faa8c..59faa8c mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ibss.py +++ b/libeap/tests/hwsim/test_ibss.py diff --cc libeap/tests/hwsim/test_ieee8021x.py index 0000000,d35a4d4..d35a4d4 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ieee8021x.py +++ b/libeap/tests/hwsim/test_ieee8021x.py diff --cc libeap/tests/hwsim/test_module_tests.py index 0000000,2e96c45..2e96c45 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_module_tests.py +++ b/libeap/tests/hwsim/test_module_tests.py diff --cc libeap/tests/hwsim/test_monitor_interface.py index 0000000,7af8724..7af8724 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_monitor_interface.py +++ b/libeap/tests/hwsim/test_monitor_interface.py diff --cc libeap/tests/hwsim/test_nfc_p2p.py index 0000000,7b5ddae..7b5ddae mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_nfc_p2p.py +++ b/libeap/tests/hwsim/test_nfc_p2p.py diff --cc libeap/tests/hwsim/test_nfc_wps.py index 0000000,22d599b..22d599b mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_nfc_wps.py +++ b/libeap/tests/hwsim/test_nfc_wps.py diff --cc libeap/tests/hwsim/test_offchannel_tx.py index 0000000,6d49392..6d49392 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_offchannel_tx.py +++ b/libeap/tests/hwsim/test_offchannel_tx.py diff --cc libeap/tests/hwsim/test_p2p_autogo.py index 0000000,c92119b..c92119b mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_autogo.py +++ b/libeap/tests/hwsim/test_p2p_autogo.py diff --cc libeap/tests/hwsim/test_p2p_channel.py index 0000000,8fa80a4..8fa80a4 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_channel.py +++ b/libeap/tests/hwsim/test_p2p_channel.py diff --cc libeap/tests/hwsim/test_p2p_concurrency.py index 0000000,16be8c6..16be8c6 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_concurrency.py +++ b/libeap/tests/hwsim/test_p2p_concurrency.py diff --cc libeap/tests/hwsim/test_p2p_device.py index 0000000,c7e6299..c7e6299 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_device.py +++ b/libeap/tests/hwsim/test_p2p_device.py diff --cc libeap/tests/hwsim/test_p2p_discovery.py index 0000000,fbd3f83..fbd3f83 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_discovery.py +++ b/libeap/tests/hwsim/test_p2p_discovery.py diff --cc libeap/tests/hwsim/test_p2p_ext.py index 0000000,7385e97..7385e97 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_ext.py +++ b/libeap/tests/hwsim/test_p2p_ext.py diff --cc libeap/tests/hwsim/test_p2p_grpform.py index 0000000,f86637d..f86637d mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_grpform.py +++ b/libeap/tests/hwsim/test_p2p_grpform.py diff --cc libeap/tests/hwsim/test_p2p_invitation.py index 0000000,ffe8437..ffe8437 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_invitation.py +++ b/libeap/tests/hwsim/test_p2p_invitation.py diff --cc libeap/tests/hwsim/test_p2p_messages.py index 0000000,19d551b..19d551b mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_messages.py +++ b/libeap/tests/hwsim/test_p2p_messages.py diff --cc libeap/tests/hwsim/test_p2p_persistent.py index 0000000,2752a88..2752a88 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_persistent.py +++ b/libeap/tests/hwsim/test_p2p_persistent.py diff --cc libeap/tests/hwsim/test_p2p_service.py index 0000000,ea7a8f4..ea7a8f4 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_service.py +++ b/libeap/tests/hwsim/test_p2p_service.py diff --cc libeap/tests/hwsim/test_p2p_set.py index 0000000,ba1e7ce..ba1e7ce mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_set.py +++ b/libeap/tests/hwsim/test_p2p_set.py diff --cc libeap/tests/hwsim/test_p2p_wifi_display.py index 0000000,e820639..e820639 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2p_wifi_display.py +++ b/libeap/tests/hwsim/test_p2p_wifi_display.py diff --cc libeap/tests/hwsim/test_p2ps.py index 0000000,5f0b13b..5f0b13b mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_p2ps.py +++ b/libeap/tests/hwsim/test_p2ps.py diff --cc libeap/tests/hwsim/test_peerkey.py index 0000000,aac4473..aac4473 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_peerkey.py +++ b/libeap/tests/hwsim/test_peerkey.py diff --cc libeap/tests/hwsim/test_pmksa_cache.py index 0000000,0899c84..0899c84 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_pmksa_cache.py +++ b/libeap/tests/hwsim/test_pmksa_cache.py diff --cc libeap/tests/hwsim/test_radio_work.py index 0000000,83eb8f4..83eb8f4 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_radio_work.py +++ b/libeap/tests/hwsim/test_radio_work.py diff --cc libeap/tests/hwsim/test_radius.py index 0000000,662285c..662285c mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_radius.py +++ b/libeap/tests/hwsim/test_radius.py diff --cc libeap/tests/hwsim/test_rfkill.py index 0000000,425b40f..425b40f mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_rfkill.py +++ b/libeap/tests/hwsim/test_rfkill.py diff --cc libeap/tests/hwsim/test_sae.py index 0000000,ba70f75..ba70f75 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_sae.py +++ b/libeap/tests/hwsim/test_sae.py diff --cc libeap/tests/hwsim/test_scan.py index 0000000,fa1bcc9..fa1bcc9 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_scan.py +++ b/libeap/tests/hwsim/test_scan.py diff --cc libeap/tests/hwsim/test_ssid.py index 0000000,ca0479e..ca0479e mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_ssid.py +++ b/libeap/tests/hwsim/test_ssid.py diff --cc libeap/tests/hwsim/test_sta_dynamic.py index 0000000,49c1ae4..49c1ae4 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_sta_dynamic.py +++ b/libeap/tests/hwsim/test_sta_dynamic.py diff --cc libeap/tests/hwsim/test_suite_b.py index 0000000,1a32c69..1a32c69 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_suite_b.py +++ b/libeap/tests/hwsim/test_suite_b.py diff --cc libeap/tests/hwsim/test_tnc.py index 0000000,ba9e8e9..ba9e8e9 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_tnc.py +++ b/libeap/tests/hwsim/test_tnc.py diff --cc libeap/tests/hwsim/test_wep.py index 0000000,bd8fec0..bd8fec0 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_wep.py +++ b/libeap/tests/hwsim/test_wep.py diff --cc libeap/tests/hwsim/test_wext.py index 0000000,83bd8dd..83bd8dd mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_wext.py +++ b/libeap/tests/hwsim/test_wext.py diff --cc libeap/tests/hwsim/test_wnm.py index 0000000,c30436e..c30436e mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_wnm.py +++ b/libeap/tests/hwsim/test_wnm.py diff --cc libeap/tests/hwsim/test_wpas_ap.py index 0000000,53de399..53de399 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_wpas_ap.py +++ b/libeap/tests/hwsim/test_wpas_ap.py diff --cc libeap/tests/hwsim/test_wpas_config.py index 0000000,0af31da..0af31da mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_wpas_config.py +++ b/libeap/tests/hwsim/test_wpas_config.py diff --cc libeap/tests/hwsim/test_wpas_ctrl.py index 0000000,de7cde4..de7cde4 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_wpas_ctrl.py +++ b/libeap/tests/hwsim/test_wpas_ctrl.py diff --cc libeap/tests/hwsim/test_wpas_mesh.py index 0000000,b6188d1..b6188d1 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_wpas_mesh.py +++ b/libeap/tests/hwsim/test_wpas_mesh.py diff --cc libeap/tests/hwsim/test_wpas_wmm_ac.py index 0000000,d2d5596..d2d5596 mode 000000,100644..100644 --- a/libeap/tests/hwsim/test_wpas_wmm_ac.py +++ b/libeap/tests/hwsim/test_wpas_wmm_ac.py diff --cc libeap/tests/hwsim/tnc/.gitignore index 0000000,2f88962..2f88962 mode 000000,100644..100644 --- a/libeap/tests/hwsim/tnc/.gitignore +++ b/libeap/tests/hwsim/tnc/.gitignore diff --cc libeap/tests/hwsim/tnc/Makefile index 0000000,64ba0ca..64ba0ca mode 000000,100644..100644 --- a/libeap/tests/hwsim/tnc/Makefile +++ b/libeap/tests/hwsim/tnc/Makefile diff --cc libeap/tests/hwsim/tnc/hostap2_imc.c index 0000000,3818c17..3818c17 mode 000000,100644..100644 --- a/libeap/tests/hwsim/tnc/hostap2_imc.c +++ b/libeap/tests/hwsim/tnc/hostap2_imc.c diff --cc libeap/tests/hwsim/tnc/hostap2_imv.c index 0000000,652888a..652888a mode 000000,100644..100644 --- a/libeap/tests/hwsim/tnc/hostap2_imv.c +++ b/libeap/tests/hwsim/tnc/hostap2_imv.c diff --cc libeap/tests/hwsim/tnc/hostap_imc.c index 0000000,d28183a..d28183a mode 000000,100644..100644 --- a/libeap/tests/hwsim/tnc/hostap_imc.c +++ b/libeap/tests/hwsim/tnc/hostap_imc.c diff --cc libeap/tests/hwsim/tnc/hostap_imv.c index 0000000,0f4f9c8..0f4f9c8 mode 000000,100644..100644 --- a/libeap/tests/hwsim/tnc/hostap_imv.c +++ b/libeap/tests/hwsim/tnc/hostap_imv.c diff --cc libeap/tests/hwsim/tnc/tnc_config index 0000000,613783a..613783a mode 000000,100644..100644 --- a/libeap/tests/hwsim/tnc/tnc_config +++ b/libeap/tests/hwsim/tnc/tnc_config diff --cc libeap/tests/hwsim/tshark.py index 0000000,ee70cfd..ee70cfd mode 000000,100644..100644 --- a/libeap/tests/hwsim/tshark.py +++ b/libeap/tests/hwsim/tshark.py diff --cc libeap/tests/hwsim/utils.py index 0000000,daed84f..daed84f mode 000000,100644..100644 --- a/libeap/tests/hwsim/utils.py +++ b/libeap/tests/hwsim/utils.py diff --cc libeap/tests/hwsim/vm/.gitignore index 0000000,b1ce1b1..b1ce1b1 mode 000000,100644..100644 --- a/libeap/tests/hwsim/vm/.gitignore +++ b/libeap/tests/hwsim/vm/.gitignore diff --cc libeap/tests/hwsim/vm/README index 0000000,8fef72c..8fef72c mode 000000,100644..100644 --- a/libeap/tests/hwsim/vm/README +++ b/libeap/tests/hwsim/vm/README diff --cc libeap/tests/hwsim/vm/build-codecov.sh index 0000000,e67ef2e..e67ef2e mode 000000,100755..100755 --- a/libeap/tests/hwsim/vm/build-codecov.sh +++ b/libeap/tests/hwsim/vm/build-codecov.sh diff --cc libeap/tests/hwsim/vm/combine-codecov.sh index 0000000,3fe8443..3fe8443 mode 000000,100755..100755 --- a/libeap/tests/hwsim/vm/combine-codecov.sh +++ b/libeap/tests/hwsim/vm/combine-codecov.sh diff --cc libeap/tests/hwsim/vm/dbus.conf index 0000000,e64e44f..e64e44f mode 000000,100644..100644 --- a/libeap/tests/hwsim/vm/dbus.conf +++ b/libeap/tests/hwsim/vm/dbus.conf diff --cc libeap/tests/hwsim/vm/inside.sh index 0000000,ffab4ee..ffab4ee mode 000000,100755..100755 --- a/libeap/tests/hwsim/vm/inside.sh +++ b/libeap/tests/hwsim/vm/inside.sh diff --cc libeap/tests/hwsim/vm/kernel-config index 0000000,08fc7a9..08fc7a9 mode 000000,100644..100644 --- a/libeap/tests/hwsim/vm/kernel-config +++ b/libeap/tests/hwsim/vm/kernel-config diff --cc libeap/tests/hwsim/vm/parallel-vm.py index 0000000,40ab5e3..40ab5e3 mode 000000,100755..100755 --- a/libeap/tests/hwsim/vm/parallel-vm.py +++ b/libeap/tests/hwsim/vm/parallel-vm.py diff --cc libeap/tests/hwsim/vm/parallel-vm.sh index 0000000,b2fd078..b2fd078 mode 000000,100755..100755 --- a/libeap/tests/hwsim/vm/parallel-vm.sh +++ b/libeap/tests/hwsim/vm/parallel-vm.sh diff --cc libeap/tests/hwsim/vm/process-codecov.sh index 0000000,d932aa2..d932aa2 mode 000000,100755..100755 --- a/libeap/tests/hwsim/vm/process-codecov.sh +++ b/libeap/tests/hwsim/vm/process-codecov.sh diff --cc libeap/tests/hwsim/vm/uevent.sh index 0000000,d52f7fc..d52f7fc mode 000000,100755..100755 --- a/libeap/tests/hwsim/vm/uevent.sh +++ b/libeap/tests/hwsim/vm/uevent.sh diff --cc libeap/tests/hwsim/vm/vm-run.sh index 0000000,9993043..9993043 mode 000000,100755..100755 --- a/libeap/tests/hwsim/vm/vm-run.sh +++ b/libeap/tests/hwsim/vm/vm-run.sh diff --cc libeap/tests/hwsim/w1fi_logo.png index 0000000,ac7c259..ac7c259 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/wlantest.py index 0000000,5f6b4ac..5f6b4ac mode 000000,100644..100644 --- a/libeap/tests/hwsim/wlantest.py +++ b/libeap/tests/hwsim/wlantest.py diff --cc libeap/tests/hwsim/wpasupplicant.py index 0000000,8e79c8b..8e79c8b mode 000000,100644..100644 --- a/libeap/tests/hwsim/wpasupplicant.py +++ b/libeap/tests/hwsim/wpasupplicant.py diff --cc libeap/tests/hwsim/wps-mixed-cred index 0000000,fca2871..fca2871 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/hwsim/wps-wep-cred index 0000000,407cf41..407cf41 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/p2p-fuzzer/Makefile index 0000000,4f81ef1..4f81ef1 mode 000000,100644..100644 --- a/libeap/tests/p2p-fuzzer/Makefile +++ b/libeap/tests/p2p-fuzzer/Makefile diff --cc libeap/tests/p2p-fuzzer/go-neg-req.dat index 0000000,ed06834..ed06834 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/p2p-fuzzer/invitation-req.dat index 0000000,5991f3e..5991f3e mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/p2p-fuzzer/p2p-fuzzer.c index 0000000,dcc1d72..dcc1d72 mode 000000,100644..100644 --- a/libeap/tests/p2p-fuzzer/p2p-fuzzer.c +++ b/libeap/tests/p2p-fuzzer/p2p-fuzzer.c diff --cc libeap/tests/p2p-fuzzer/p2ps-pd-req.dat index 0000000,7e1b6d9..7e1b6d9 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/p2p-fuzzer/proberesp-go.dat index 0000000,8541652..8541652 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/p2p-fuzzer/proberesp.dat index 0000000,8d997d1..8d997d1 mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/test-https.c index 0000000,a72e56f..a72e56f mode 000000,100644..100644 --- a/libeap/tests/test-https.c +++ b/libeap/tests/test-https.c diff --cc libeap/tests/test-rc4.c index 0000000,99f5592..99f5592 mode 000000,100644..100644 --- a/libeap/tests/test-rc4.c +++ b/libeap/tests/test-rc4.c diff --cc libeap/tests/test-rsa-sig-ver.c index 0000000,6fad5b1..6fad5b1 mode 000000,100644..100644 --- a/libeap/tests/test-rsa-sig-ver.c +++ b/libeap/tests/test-rsa-sig-ver.c diff --cc libeap/tests/wnm-fuzzer/Makefile index 0000000,dede75b..dede75b mode 000000,100644..100644 --- a/libeap/tests/wnm-fuzzer/Makefile +++ b/libeap/tests/wnm-fuzzer/Makefile diff --cc libeap/tests/wnm-fuzzer/bss-tm-req.dat index 0000000,14510bb..14510bb mode 000000,100644..100644 Binary files differ diff --cc libeap/tests/wnm-fuzzer/wnm-fuzzer.c index 0000000,8efa311..8efa311 mode 000000,100644..100644 --- a/libeap/tests/wnm-fuzzer/wnm-fuzzer.c +++ b/libeap/tests/wnm-fuzzer/wnm-fuzzer.c diff --cc libeap/tests/wnm-fuzzer/wnm-notif.dat index 0000000,c234d3a..c234d3a mode 000000,100644..100644 Binary files differ diff --cc libeap/wlantest/Makefile index 0000000,320fdbb..320fdbb mode 000000,100644..100644 --- a/libeap/wlantest/Makefile +++ b/libeap/wlantest/Makefile diff --cc libeap/wlantest/bip.c index 0000000,bda8036..bda8036 mode 000000,100644..100644 --- a/libeap/wlantest/bip.c +++ b/libeap/wlantest/bip.c diff --cc libeap/wlantest/bss.c index 0000000,f021956..f021956 mode 000000,100644..100644 --- a/libeap/wlantest/bss.c +++ b/libeap/wlantest/bss.c diff --cc libeap/wlantest/ccmp.c index 0000000,ee1f1a6..ee1f1a6 mode 000000,100644..100644 --- a/libeap/wlantest/ccmp.c +++ b/libeap/wlantest/ccmp.c diff --cc libeap/wlantest/crc32.c index 0000000,adbbda5..adbbda5 mode 000000,100644..100644 --- a/libeap/wlantest/crc32.c +++ b/libeap/wlantest/crc32.c diff --cc libeap/wlantest/ctrl.c index 0000000,7de0a8a..7de0a8a mode 000000,100644..100644 --- a/libeap/wlantest/ctrl.c +++ b/libeap/wlantest/ctrl.c diff --cc libeap/wlantest/gcmp.c index 0000000,d92f4ed..d92f4ed mode 000000,100644..100644 --- a/libeap/wlantest/gcmp.c +++ b/libeap/wlantest/gcmp.c diff --cc libeap/wlantest/inject.c index 0000000,ed25033..ed25033 mode 000000,100644..100644 --- a/libeap/wlantest/inject.c +++ b/libeap/wlantest/inject.c diff --cc libeap/wlantest/monitor.c index 0000000,afcc380..afcc380 mode 000000,100644..100644 --- a/libeap/wlantest/monitor.c +++ b/libeap/wlantest/monitor.c diff --cc libeap/wlantest/process.c index 0000000,802d0af..802d0af mode 000000,100644..100644 --- a/libeap/wlantest/process.c +++ b/libeap/wlantest/process.c diff --cc libeap/wlantest/readpcap.c index 0000000,7c3ce18..7c3ce18 mode 000000,100644..100644 --- a/libeap/wlantest/readpcap.c +++ b/libeap/wlantest/readpcap.c diff --cc libeap/wlantest/rx_data.c index 0000000,4c55e7d..4c55e7d mode 000000,100644..100644 --- a/libeap/wlantest/rx_data.c +++ b/libeap/wlantest/rx_data.c diff --cc libeap/wlantest/rx_eapol.c index 0000000,75bfa7d..75bfa7d mode 000000,100644..100644 --- a/libeap/wlantest/rx_eapol.c +++ b/libeap/wlantest/rx_eapol.c diff --cc libeap/wlantest/rx_ip.c index 0000000,19b338b..19b338b mode 000000,100644..100644 --- a/libeap/wlantest/rx_ip.c +++ b/libeap/wlantest/rx_ip.c diff --cc libeap/wlantest/rx_mgmt.c index 0000000,6242bc6..6242bc6 mode 000000,100644..100644 --- a/libeap/wlantest/rx_mgmt.c +++ b/libeap/wlantest/rx_mgmt.c diff --cc libeap/wlantest/rx_tdls.c index 0000000,0c012a9..0c012a9 mode 000000,100644..100644 --- a/libeap/wlantest/rx_tdls.c +++ b/libeap/wlantest/rx_tdls.c diff --cc libeap/wlantest/sta.c index 0000000,1268b8a..1268b8a mode 000000,100644..100644 --- a/libeap/wlantest/sta.c +++ b/libeap/wlantest/sta.c diff --cc libeap/wlantest/test_vectors.c index 0000000,36f2f5d..36f2f5d mode 000000,100644..100644 --- a/libeap/wlantest/test_vectors.c +++ b/libeap/wlantest/test_vectors.c diff --cc libeap/wlantest/tkip.c index 0000000,ed3d601..ed3d601 mode 000000,100644..100644 --- a/libeap/wlantest/tkip.c +++ b/libeap/wlantest/tkip.c diff --cc libeap/wlantest/wep.c index 0000000,c4137f3..c4137f3 mode 000000,100644..100644 --- a/libeap/wlantest/wep.c +++ b/libeap/wlantest/wep.c diff --cc libeap/wlantest/wired.c index 0000000,77a395f..77a395f mode 000000,100644..100644 --- a/libeap/wlantest/wired.c +++ b/libeap/wlantest/wired.c diff --cc libeap/wlantest/wlantest.c index 0000000,ab3b2fc..ab3b2fc mode 000000,100644..100644 --- a/libeap/wlantest/wlantest.c +++ b/libeap/wlantest/wlantest.c diff --cc libeap/wlantest/wlantest.h index 0000000,ced9baa..ced9baa mode 000000,100644..100644 --- a/libeap/wlantest/wlantest.h +++ b/libeap/wlantest/wlantest.h diff --cc libeap/wlantest/wlantest_cli.c index 0000000,ad5a48d..ad5a48d mode 000000,100644..100644 --- a/libeap/wlantest/wlantest_cli.c +++ b/libeap/wlantest/wlantest_cli.c diff --cc libeap/wlantest/wlantest_ctrl.h index 0000000,1af6838..1af6838 mode 000000,100644..100644 --- a/libeap/wlantest/wlantest_ctrl.h +++ b/libeap/wlantest/wlantest_ctrl.h diff --cc libeap/wlantest/writepcap.c index 0000000,28b306b..28b306b mode 000000,100644..100644 --- a/libeap/wlantest/writepcap.c +++ b/libeap/wlantest/writepcap.c diff --cc libeap/wpa_supplicant/Android.mk index 0000000,0d818ed..0d818ed mode 000000,100644..100644 --- a/libeap/wpa_supplicant/Android.mk +++ b/libeap/wpa_supplicant/Android.mk diff --cc libeap/wpa_supplicant/README-HS20 index 0000000,161dc06..161dc06 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/README-HS20 +++ b/libeap/wpa_supplicant/README-HS20 diff --cc libeap/wpa_supplicant/README-P2P index 0000000,6a5b032..6a5b032 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/README-P2P +++ b/libeap/wpa_supplicant/README-P2P diff --cc libeap/wpa_supplicant/android.config index 0000000,6c3ee6d..6c3ee6d mode 000000,100644..100644 --- a/libeap/wpa_supplicant/android.config +++ b/libeap/wpa_supplicant/android.config diff --cc libeap/wpa_supplicant/autoscan.c index 0000000,a2cf7a5..a2cf7a5 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/autoscan.c +++ b/libeap/wpa_supplicant/autoscan.c diff --cc libeap/wpa_supplicant/autoscan.h index 0000000,e2a7652..e2a7652 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/autoscan.h +++ b/libeap/wpa_supplicant/autoscan.h diff --cc libeap/wpa_supplicant/autoscan_exponential.c index 0000000,424477b..424477b mode 000000,100644..100644 --- a/libeap/wpa_supplicant/autoscan_exponential.c +++ b/libeap/wpa_supplicant/autoscan_exponential.c diff --cc libeap/wpa_supplicant/autoscan_periodic.c index 0000000,102d723..102d723 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/autoscan_periodic.c +++ b/libeap/wpa_supplicant/autoscan_periodic.c diff --cc libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.c index 0000000,67c079e..67c079e mode 000000,100644..100644 --- a/libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.c +++ b/libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.c diff --cc libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.h index 0000000,2aecbbe..2aecbbe mode 000000,100644..100644 --- a/libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.h +++ b/libeap/wpa_supplicant/dbus/dbus_new_handlers_p2p.h diff --cc libeap/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in index 0000000,a75918f..a75918f mode 000000,100644..100644 --- a/libeap/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in +++ b/libeap/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service.in diff --cc libeap/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in index 0000000,d97ff39..d97ff39 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in +++ b/libeap/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service.in diff --cc libeap/wpa_supplicant/doc/docbook/eapol_test.sgml index 0000000,e9af6d9..e9af6d9 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/doc/docbook/eapol_test.sgml +++ b/libeap/wpa_supplicant/doc/docbook/eapol_test.sgml diff --cc libeap/wpa_supplicant/eap_proxy_dummy.mak index 0000000,e69de29..e69de29 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/eap_proxy_dummy.mak +++ b/libeap/wpa_supplicant/eap_proxy_dummy.mak diff --cc libeap/wpa_supplicant/eap_proxy_dummy.mk index 0000000,e69de29..e69de29 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/eap_proxy_dummy.mk +++ b/libeap/wpa_supplicant/eap_proxy_dummy.mk diff --cc libeap/wpa_supplicant/eapol_test.py index 0000000,80e7dfc..80e7dfc mode 000000,100755..100755 --- a/libeap/wpa_supplicant/eapol_test.py +++ b/libeap/wpa_supplicant/eapol_test.py diff --cc libeap/wpa_supplicant/examples/dbus-listen-preq.py index 0000000,5ac9859..5ac9859 mode 000000,100755..100755 --- a/libeap/wpa_supplicant/examples/dbus-listen-preq.py +++ b/libeap/wpa_supplicant/examples/dbus-listen-preq.py diff --cc libeap/wpa_supplicant/examples/p2p-nfc.py index 0000000,91eba28..91eba28 mode 000000,100755..100755 --- a/libeap/wpa_supplicant/examples/p2p-nfc.py +++ b/libeap/wpa_supplicant/examples/p2p-nfc.py diff --cc libeap/wpa_supplicant/examples/p2p/p2p_connect.py index 0000000,59b0a9d..59b0a9d mode 000000,100644..100644 --- a/libeap/wpa_supplicant/examples/p2p/p2p_connect.py +++ b/libeap/wpa_supplicant/examples/p2p/p2p_connect.py diff --cc libeap/wpa_supplicant/examples/p2p/p2p_disconnect.py index 0000000,c3e39b3..c3e39b3 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/examples/p2p/p2p_disconnect.py +++ b/libeap/wpa_supplicant/examples/p2p/p2p_disconnect.py diff --cc libeap/wpa_supplicant/examples/p2p/p2p_find.py index 0000000,973d46a..973d46a mode 000000,100644..100644 --- a/libeap/wpa_supplicant/examples/p2p/p2p_find.py +++ b/libeap/wpa_supplicant/examples/p2p/p2p_find.py diff --cc libeap/wpa_supplicant/examples/p2p/p2p_flush.py index 0000000,ff8509d..ff8509d mode 000000,100644..100644 --- a/libeap/wpa_supplicant/examples/p2p/p2p_flush.py +++ b/libeap/wpa_supplicant/examples/p2p/p2p_flush.py diff --cc libeap/wpa_supplicant/examples/p2p/p2p_group_add.py index 0000000,5c8fdaf..5c8fdaf mode 000000,100644..100644 --- a/libeap/wpa_supplicant/examples/p2p/p2p_group_add.py +++ b/libeap/wpa_supplicant/examples/p2p/p2p_group_add.py diff --cc libeap/wpa_supplicant/examples/p2p/p2p_invite.py index 0000000,6deb397..6deb397 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/examples/p2p/p2p_invite.py +++ b/libeap/wpa_supplicant/examples/p2p/p2p_invite.py diff --cc libeap/wpa_supplicant/examples/p2p/p2p_listen.py index 0000000,bb3c1e4..bb3c1e4 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/examples/p2p/p2p_listen.py +++ b/libeap/wpa_supplicant/examples/p2p/p2p_listen.py diff --cc libeap/wpa_supplicant/examples/p2p/p2p_stop_find.py index 0000000,f6c03b0..f6c03b0 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/examples/p2p/p2p_stop_find.py +++ b/libeap/wpa_supplicant/examples/p2p/p2p_stop_find.py diff --cc libeap/wpa_supplicant/examples/wps-ap-cli index 0000000,cc2cff2..cc2cff2 mode 000000,100755..100755 --- a/libeap/wpa_supplicant/examples/wps-ap-cli +++ b/libeap/wpa_supplicant/examples/wps-ap-cli diff --cc libeap/wpa_supplicant/examples/wps-nfc.py index 0000000,7459eb9..7459eb9 mode 000000,100755..100755 --- a/libeap/wpa_supplicant/examples/wps-nfc.py +++ b/libeap/wpa_supplicant/examples/wps-nfc.py diff --cc libeap/wpa_supplicant/gas_query.c index 0000000,10ecce7..10ecce7 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/gas_query.c +++ b/libeap/wpa_supplicant/gas_query.c diff --cc libeap/wpa_supplicant/gas_query.h index 0000000,ad13490..ad13490 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/gas_query.h +++ b/libeap/wpa_supplicant/gas_query.h diff --cc libeap/wpa_supplicant/hs20_supplicant.c index 0000000,a1afc85..a1afc85 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/hs20_supplicant.c +++ b/libeap/wpa_supplicant/hs20_supplicant.c diff --cc libeap/wpa_supplicant/hs20_supplicant.h index 0000000,85b5120..85b5120 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/hs20_supplicant.h +++ b/libeap/wpa_supplicant/hs20_supplicant.h diff --cc libeap/wpa_supplicant/interworking.c index 0000000,fd47c17..fd47c17 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/interworking.c +++ b/libeap/wpa_supplicant/interworking.c diff --cc libeap/wpa_supplicant/interworking.h index 0000000,3743dc0..3743dc0 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/interworking.h +++ b/libeap/wpa_supplicant/interworking.h diff --cc libeap/wpa_supplicant/mesh.c index 0000000,77f708b..77f708b mode 000000,100644..100644 --- a/libeap/wpa_supplicant/mesh.c +++ b/libeap/wpa_supplicant/mesh.c diff --cc libeap/wpa_supplicant/mesh.h index 0000000,3cb7f1b..3cb7f1b mode 000000,100644..100644 --- a/libeap/wpa_supplicant/mesh.h +++ b/libeap/wpa_supplicant/mesh.h diff --cc libeap/wpa_supplicant/mesh_mpm.c index 0000000,f81b88c..f81b88c mode 000000,100644..100644 --- a/libeap/wpa_supplicant/mesh_mpm.c +++ b/libeap/wpa_supplicant/mesh_mpm.c diff --cc libeap/wpa_supplicant/mesh_mpm.h index 0000000,7ebaef0..7ebaef0 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/mesh_mpm.h +++ b/libeap/wpa_supplicant/mesh_mpm.h diff --cc libeap/wpa_supplicant/mesh_rsn.c index 0000000,747f1ae..747f1ae mode 000000,100644..100644 --- a/libeap/wpa_supplicant/mesh_rsn.c +++ b/libeap/wpa_supplicant/mesh_rsn.c diff --cc libeap/wpa_supplicant/mesh_rsn.h index 0000000,b1471b2..b1471b2 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/mesh_rsn.h +++ b/libeap/wpa_supplicant/mesh_rsn.h diff --cc libeap/wpa_supplicant/nfc_pw_token.c index 0000000,11afb5b..11afb5b mode 000000,100644..100644 --- a/libeap/wpa_supplicant/nfc_pw_token.c +++ b/libeap/wpa_supplicant/nfc_pw_token.c diff --cc libeap/wpa_supplicant/offchannel.c index 0000000,63af83a..63af83a mode 000000,100644..100644 --- a/libeap/wpa_supplicant/offchannel.c +++ b/libeap/wpa_supplicant/offchannel.c diff --cc libeap/wpa_supplicant/offchannel.h index 0000000,0ad7e18..0ad7e18 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/offchannel.h +++ b/libeap/wpa_supplicant/offchannel.h diff --cc libeap/wpa_supplicant/p2p_supplicant_sd.c index 0000000,fc07b07..fc07b07 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/p2p_supplicant_sd.c +++ b/libeap/wpa_supplicant/p2p_supplicant_sd.c diff --cc libeap/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in index 0000000,03ac507..03ac507 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in +++ b/libeap/wpa_supplicant/systemd/wpa_supplicant-nl80211.service.arg.in diff --cc libeap/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in index 0000000,c8a744d..c8a744d mode 000000,100644..100644 --- a/libeap/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in +++ b/libeap/wpa_supplicant/systemd/wpa_supplicant-wired.service.arg.in diff --cc libeap/wpa_supplicant/systemd/wpa_supplicant.service.arg.in index 0000000,7788b38..7788b38 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/systemd/wpa_supplicant.service.arg.in +++ b/libeap/wpa_supplicant/systemd/wpa_supplicant.service.arg.in diff --cc libeap/wpa_supplicant/systemd/wpa_supplicant.service.in index 0000000,ea964ce..ea964ce mode 000000,100644..100644 --- a/libeap/wpa_supplicant/systemd/wpa_supplicant.service.in +++ b/libeap/wpa_supplicant/systemd/wpa_supplicant.service.in diff --cc libeap/wpa_supplicant/utils/log2pcap.py index 0000000,65e2fa1..65e2fa1 mode 000000,100755..100755 --- a/libeap/wpa_supplicant/utils/log2pcap.py +++ b/libeap/wpa_supplicant/utils/log2pcap.py diff --cc libeap/wpa_supplicant/wifi_display.c index 0000000,c363b21..c363b21 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wifi_display.c +++ b/libeap/wpa_supplicant/wifi_display.c diff --cc libeap/wpa_supplicant/wifi_display.h index 0000000,0966bdb..0966bdb mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wifi_display.h +++ b/libeap/wpa_supplicant/wifi_display.h diff --cc libeap/wpa_supplicant/wmm_ac.c index 0000000,5625d36..5625d36 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wmm_ac.c +++ b/libeap/wpa_supplicant/wmm_ac.c diff --cc libeap/wpa_supplicant/wmm_ac.h index 0000000,5171b16..5171b16 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wmm_ac.h +++ b/libeap/wpa_supplicant/wmm_ac.h diff --cc libeap/wpa_supplicant/wnm_sta.c index 0000000,954de67..954de67 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wnm_sta.c +++ b/libeap/wpa_supplicant/wnm_sta.c diff --cc libeap/wpa_supplicant/wnm_sta.h index 0000000,8de4348..8de4348 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wnm_sta.h +++ b/libeap/wpa_supplicant/wnm_sta.h diff --cc libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp index 0000000,9cd937c..9cd937c mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp +++ b/libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.cpp diff --cc libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h index 0000000,74887ee..74887ee mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h +++ b/libeap/wpa_supplicant/wpa_gui-qt4/scanresultsitem.h diff --cc libeap/wpa_supplicant/wpa_gui-qt4/signalbar.cpp index 0000000,2bba582..2bba582 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wpa_gui-qt4/signalbar.cpp +++ b/libeap/wpa_supplicant/wpa_gui-qt4/signalbar.cpp diff --cc libeap/wpa_supplicant/wpa_gui-qt4/signalbar.h index 0000000,37da5dd..37da5dd mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wpa_gui-qt4/signalbar.h +++ b/libeap/wpa_supplicant/wpa_gui-qt4/signalbar.h diff --cc libeap/wpa_supplicant/wpa_supplicant_conf.mk index 0000000,74986ea..74986ea mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wpa_supplicant_conf.mk +++ b/libeap/wpa_supplicant/wpa_supplicant_conf.mk diff --cc libeap/wpa_supplicant/wpa_supplicant_conf.sh index 0000000,f36eef1..f36eef1 mode 000000,100755..100755 --- a/libeap/wpa_supplicant/wpa_supplicant_conf.sh +++ b/libeap/wpa_supplicant/wpa_supplicant_conf.sh diff --cc libeap/wpa_supplicant/wpa_supplicant_template.conf index 0000000,f3f2a64..f3f2a64 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wpa_supplicant_template.conf +++ b/libeap/wpa_supplicant/wpa_supplicant_template.conf diff --cc libeap/wpa_supplicant/wpas_kay.c index 0000000,354decf..354decf mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wpas_kay.c +++ b/libeap/wpa_supplicant/wpas_kay.c diff --cc libeap/wpa_supplicant/wpas_kay.h index 0000000,b7236d0..b7236d0 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wpas_kay.h +++ b/libeap/wpa_supplicant/wpas_kay.h diff --cc libeap/wpa_supplicant/wpas_module_tests.c index 0000000,6af1678..6af1678 mode 000000,100644..100644 --- a/libeap/wpa_supplicant/wpas_module_tests.c +++ b/libeap/wpa_supplicant/wpas_module_tests.c diff --cc libeap/wpadebug/AndroidManifest.xml index 0000000,9f3ca68..9f3ca68 mode 000000,100644..100644 --- a/libeap/wpadebug/AndroidManifest.xml +++ b/libeap/wpadebug/AndroidManifest.xml diff --cc libeap/wpadebug/README index 0000000,843b99b..843b99b mode 000000,100644..100644 --- a/libeap/wpadebug/README +++ b/libeap/wpadebug/README diff --cc libeap/wpadebug/build.xml index 0000000,5301e69..5301e69 mode 000000,100644..100644 --- a/libeap/wpadebug/build.xml +++ b/libeap/wpadebug/build.xml diff --cc libeap/wpadebug/project.properties index 0000000,7c6ac05..7c6ac05 mode 000000,100644..100644 --- a/libeap/wpadebug/project.properties +++ b/libeap/wpadebug/project.properties diff --cc libeap/wpadebug/res/layout/cred_edit.xml index 0000000,292b30a..292b30a mode 000000,100644..100644 --- a/libeap/wpadebug/res/layout/cred_edit.xml +++ b/libeap/wpadebug/res/layout/cred_edit.xml diff --cc libeap/wpadebug/res/layout/main.xml index 0000000,6fdd565..6fdd565 mode 000000,100644..100644 --- a/libeap/wpadebug/res/layout/main.xml +++ b/libeap/wpadebug/res/layout/main.xml diff --cc libeap/wpadebug/res/raw/shell_commands.txt index 0000000,9b45d65..9b45d65 mode 000000,100644..100644 --- a/libeap/wpadebug/res/raw/shell_commands.txt +++ b/libeap/wpadebug/res/raw/shell_commands.txt diff --cc libeap/wpadebug/res/raw/wpa_commands.txt index 0000000,3baa01c..3baa01c mode 000000,100644..100644 --- a/libeap/wpadebug/res/raw/wpa_commands.txt +++ b/libeap/wpadebug/res/raw/wpa_commands.txt diff --cc libeap/wpadebug/src/w1/fi/wpadebug/CommandListActivity.java index 0000000,6d7ad4d..6d7ad4d mode 000000,100644..100644 --- a/libeap/wpadebug/src/w1/fi/wpadebug/CommandListActivity.java +++ b/libeap/wpadebug/src/w1/fi/wpadebug/CommandListActivity.java diff --cc libeap/wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java index 0000000,28ef85f..28ef85f mode 000000,100644..100644 --- a/libeap/wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java +++ b/libeap/wpadebug/src/w1/fi/wpadebug/DisplayMessageActivity.java diff --cc libeap/wpadebug/src/w1/fi/wpadebug/MainActivity.java index 0000000,c5d123e..c5d123e mode 000000,100644..100644 --- a/libeap/wpadebug/src/w1/fi/wpadebug/MainActivity.java +++ b/libeap/wpadebug/src/w1/fi/wpadebug/MainActivity.java diff --cc libeap/wpadebug/src/w1/fi/wpadebug/WifiReceiver.java index 0000000,d69e05d..d69e05d mode 000000,100644..100644 --- a/libeap/wpadebug/src/w1/fi/wpadebug/WifiReceiver.java +++ b/libeap/wpadebug/src/w1/fi/wpadebug/WifiReceiver.java diff --cc libeap/wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java index 0000000,e089179..e089179 mode 000000,100644..100644 --- a/libeap/wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java +++ b/libeap/wpadebug/src/w1/fi/wpadebug/WpaCommandListActivity.java diff --cc libeap/wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java index 0000000,3902f09..3902f09 mode 000000,100644..100644 --- a/libeap/wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java +++ b/libeap/wpadebug/src/w1/fi/wpadebug/WpaCredActivity.java diff --cc libeap/wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java index 0000000,3f846c7..3f846c7 mode 000000,100644..100644 --- a/libeap/wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java +++ b/libeap/wpadebug/src/w1/fi/wpadebug/WpaCredEditActivity.java diff --cc libeap/wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java index 0000000,6a16017..6a16017 mode 000000,100644..100644 --- a/libeap/wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java +++ b/libeap/wpadebug/src/w1/fi/wpadebug/WpaNfcActivity.java diff --cc libeap/wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java index 0000000,a7c54fc..a7c54fc mode 000000,100644..100644 --- a/libeap/wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java +++ b/libeap/wpadebug/src/w1/fi/wpadebug/WpaWebViewActivity.java diff --cc libeap/wpaspy/Makefile index 0000000,bc920e0..bc920e0 mode 000000,100644..100644 --- a/libeap/wpaspy/Makefile +++ b/libeap/wpaspy/Makefile diff --cc libeap/wpaspy/setup.py index 0000000,4dbf765..4dbf765 mode 000000,100644..100644 --- a/libeap/wpaspy/setup.py +++ b/libeap/wpaspy/setup.py diff --cc libeap/wpaspy/test.py index 0000000,493af7a..493af7a mode 000000,100755..100755 --- a/libeap/wpaspy/test.py +++ b/libeap/wpaspy/test.py diff --cc libeap/wpaspy/wpaspy.c index 0000000,278089b..278089b mode 000000,100644..100644 --- a/libeap/wpaspy/wpaspy.c +++ b/libeap/wpaspy/wpaspy.c diff --cc libeap/wpaspy/wpaspy.py index 0000000,2f57d74..2f57d74 mode 000000,100644..100644 --- a/libeap/wpaspy/wpaspy.py +++ b/libeap/wpaspy/wpaspy.py diff --cc mech_eap/gssapiP_eap.h index 40d937b,0000000..1e8a360 mode 100644,000000..100644 --- a/mech_eap/gssapiP_eap.h +++ b/mech_eap/gssapiP_eap.h @@@ -1,449 -1,0 +1,450 @@@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GSSAPIP_EAP_H_ +#define _GSSAPIP_EAP_H_ 1 + +#include "config.h" + +#ifdef HAVE_HEIMDAL_VERSION +#define KRB5_DEPRECATED /* so we can use krb5_free_unparsed_name() */ +#endif + +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STDARG_H +#include +#endif +#include +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef WIN32 +#ifndef MAXHOSTNAMELEN +# include +# define MAXHOSTNAMELEN NI_MAXHOST +#endif +#endif + +/* GSS headers */ +#include +#include +#ifdef HAVE_HEIMDAL_VERSION +typedef struct gss_any *gss_any_t; +#else +#include +#endif +#include "gssapi_eap.h" + +#ifndef HAVE_GSS_INQUIRE_ATTRS_FOR_MECH +typedef const gss_OID_desc *gss_const_OID; +#endif + +/* Kerberos headers */ +#include + +/* EAP headers */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef GSSEAP_ENABLE_ACCEPTOR +/* libradsec headers */ +#include +#include +#include +#endif + +#include "gsseap_err.h" +#include "radsec_err.h" +#include "util.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* These name flags are informative and not actually used by anything yet */ +#define NAME_FLAG_NAI 0x00000001 +#define NAME_FLAG_SERVICE 0x00000002 +#define NAME_FLAG_COMPOSITE 0x00000004 + +struct gss_eap_saml_attr_ctx; +struct gss_eap_attr_ctx; + +#ifdef HAVE_HEIMDAL_VERSION +struct gss_name_t_desc_struct +#else +struct gss_name_struct +#endif +{ + GSSEAP_MUTEX mutex; /* mutex protects attrCtx */ + OM_uint32 flags; + gss_OID mechanismUsed; /* this is immutable */ + krb5_principal krbPrincipal; /* this is immutable */ +#ifdef GSSEAP_ENABLE_ACCEPTOR + struct gss_eap_attr_ctx *attrCtx; +#endif +}; + +#define CRED_FLAG_INITIATE 0x00010000 +#define CRED_FLAG_ACCEPT 0x00020000 +#define CRED_FLAG_PASSWORD 0x00040000 +#define CRED_FLAG_DEFAULT_CCACHE 0x00080000 +#define CRED_FLAG_RESOLVED 0x00100000 +#define CRED_FLAG_TARGET 0x00200000 +#define CRED_FLAG_CERTIFICATE 0x00400000 +#define CRED_FLAG_CONFIG_BLOB 0x00800000 +#define CRED_FLAG_PUBLIC_MASK 0x0000FFFF + +#ifdef HAVE_HEIMDAL_VERSION +struct gss_cred_id_t_desc_struct +#else +struct gss_cred_id_struct +#endif +{ + GSSEAP_MUTEX mutex; + OM_uint32 flags; + gss_name_t name; + gss_name_t target; /* for initiator */ + gss_buffer_desc password; + gss_OID_set mechanisms; + time_t expiryTime; + gss_buffer_desc radiusConfigFile; + gss_buffer_desc radiusConfigStanza; + gss_buffer_desc caCertificate; + gss_buffer_desc subjectNameConstraint; + gss_buffer_desc subjectAltNameConstraint; + gss_buffer_desc clientCertificate; + gss_buffer_desc privateKey; + gss_buffer_desc caCertificateBlob; +#ifdef GSSEAP_ENABLE_REAUTH + krb5_ccache krbCredCache; + gss_cred_id_t reauthCred; +#endif +}; + +#define CTX_FLAG_INITIATOR 0x00000001 +#define CTX_FLAG_KRB_REAUTH 0x00000002 +#define CTX_FLAG_CHANNEL_BINDINGS_VERIFIED 0x00000004 + +#define CTX_IS_INITIATOR(ctx) (((ctx)->flags & CTX_FLAG_INITIATOR) != 0) + +#define CTX_IS_ESTABLISHED(ctx) ((ctx)->state == GSSEAP_STATE_ESTABLISHED) + +/* Initiator context flags */ +#define CTX_FLAG_EAP_SUCCESS 0x00010000 +#define CTX_FLAG_EAP_RESTART 0x00020000 +#define CTX_FLAG_EAP_FAIL 0x00040000 +#define CTX_FLAG_EAP_RESP 0x00080000 +#define CTX_FLAG_EAP_NO_RESP 0x00100000 +#define CTX_FLAG_EAP_REQ 0x00200000 +#define CTX_FLAG_EAP_PORT_ENABLED 0x00400000 +#define CTX_FLAG_EAP_ALT_ACCEPT 0x00800000 +#define CTX_FLAG_EAP_ALT_REJECT 0x01000000 +#define CTX_FLAG_EAP_CHBIND_ACCEPT 0x02000000 ++#define CTX_FLAG_EAP_TRIGGER_START 0x04000000 +#define CTX_FLAG_EAP_MASK 0xFFFF0000 + +#define CONFIG_BLOB_CLIENT_CERT 0 +#define CONFIG_BLOB_PRIVATE_KEY 1 +#define CONFIG_BLOB_CA_CERT 2 +#define CONFIG_BLOB_MAX 3 + +struct gss_eap_initiator_ctx { + unsigned int idleWhile; + struct eap_peer_config eapPeerConfig; + struct eap_sm *eap; + struct wpabuf reqData; + struct wpabuf *chbindData; + unsigned int chbindReqFlags; + struct wpa_config_blob configBlobs[CONFIG_BLOB_MAX]; +}; + +#ifdef GSSEAP_ENABLE_ACCEPTOR +struct gss_eap_acceptor_ctx { + struct rs_context *radContext; + struct rs_connection *radConn; + char *radServer; + gss_buffer_desc state; + rs_avp *vps; +}; +#endif + +#ifdef HAVE_HEIMDAL_VERSION +struct gss_ctx_id_t_desc_struct +#else +struct gss_ctx_id_struct +#endif +{ + GSSEAP_MUTEX mutex; + enum gss_eap_state state; + OM_uint32 flags; + OM_uint32 gssFlags; + gss_OID mechanismUsed; + krb5_cksumtype checksumType; + krb5_enctype encryptionType; + krb5_keyblock rfc3961Key; + gss_name_t initiatorName; + gss_name_t acceptorName; + time_t expiryTime; + uint64_t sendSeq, recvSeq; + void *seqState; + gss_cred_id_t cred; + union { + struct gss_eap_initiator_ctx initiator; + #define initiatorCtx ctxU.initiator +#ifdef GSSEAP_ENABLE_ACCEPTOR + struct gss_eap_acceptor_ctx acceptor; + #define acceptorCtx ctxU.acceptor +#endif +#ifdef GSSEAP_ENABLE_REAUTH + gss_ctx_id_t reauth; + #define reauthCtx ctxU.reauth +#endif + } ctxU; + const struct gss_eap_token_buffer_set *inputTokens; + const struct gss_eap_token_buffer_set *outputTokens; +}; + +#define TOK_FLAG_SENDER_IS_ACCEPTOR 0x01 +#define TOK_FLAG_WRAP_CONFIDENTIAL 0x02 +#define TOK_FLAG_ACCEPTOR_SUBKEY 0x04 + +#define KEY_USAGE_ACCEPTOR_SEAL 22 +#define KEY_USAGE_ACCEPTOR_SIGN 23 +#define KEY_USAGE_INITIATOR_SEAL 24 +#define KEY_USAGE_INITIATOR_SIGN 25 + +#define KEY_USAGE_GSSEAP_CHBIND_MIC 60 +#define KEY_USAGE_GSSEAP_ACCTOKEN_MIC 61 +#define KEY_USAGE_GSSEAP_INITOKEN_MIC 62 + +/* accept_sec_context.c */ +OM_uint32 +gssEapAcceptSecContext(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_cred_id_t cred, + gss_buffer_t input_token, + gss_channel_bindings_t input_chan_bindings, + gss_name_t *src_name, + gss_OID *mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec, + gss_cred_id_t *delegated_cred_handle); + +/* init_sec_context.c */ +OM_uint32 +gssEapInitSecContext(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec); + +/* wrap_iov.c */ +OM_uint32 +gssEapWrapOrGetMIC(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count, + enum gss_eap_token_type toktype); + +OM_uint32 +gssEapUnwrapOrVerifyMIC(OM_uint32 *minor_status, + gss_ctx_id_t ctx, + int *conf_state, + gss_qop_t *qop_state, + gss_iov_buffer_desc *iov, + int iov_count, + enum gss_eap_token_type toktype); + +OM_uint32 +gssEapWrapIovLength(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + int *conf_state, + gss_iov_buffer_desc *iov, + int iov_count); +OM_uint32 +gssEapWrap(OM_uint32 *minor, + gss_ctx_id_t ctx, + int conf_req_flag, + gss_qop_t qop_req, + gss_buffer_t input_message_buffer, + int *conf_state, + gss_buffer_t output_message_buffer); + +unsigned char +rfc4121Flags(gss_ctx_id_t ctx, int receiving); + +/* display_status.c */ +void +gssEapSaveStatusInfo(OM_uint32 minor, const char *format, ...); + +OM_uint32 +gssEapDisplayStatus(OM_uint32 *minor, + OM_uint32 status_value, + gss_buffer_t status_string); + +#define IS_WIRE_ERROR(err) ((err) >= GSSEAP_RESERVED && \ + (err) <= GSSEAP_RADIUS_PROT_FAILURE) + +#ifdef GSSEAP_ENABLE_ACCEPTOR +#define IS_RADIUS_ERROR(err) ((err) >= ERROR_TABLE_BASE_rse && \ + (err) <= ERROR_TABLE_BASE_rse + RSE_MAX) +#else +#define IS_RADIUS_ERROR(err) (0) +#endif + +/* exchange_meta_data.c */ +OM_uint32 GSSAPI_CALLCONV +gssEapExchangeMetaData(OM_uint32 *minor, + gss_const_OID mech, + gss_cred_id_t cred, + gss_ctx_id_t *ctx, + const gss_name_t name, + OM_uint32 req_flags, + gss_const_buffer_t meta_data); + +/* export_sec_context.c */ +OM_uint32 +gssEapExportSecContext(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_buffer_t token); + +/* import_sec_context.c */ +OM_uint32 +gssEapImportContext(OM_uint32 *minor, + gss_buffer_t token, + gss_ctx_id_t ctx); + +/* inquire_sec_context_by_oid.c */ +#define NEGOEX_INITIATOR_SALT "gss-eap-negoex-initiator" +#define NEGOEX_INITIATOR_SALT_LEN (sizeof(NEGOEX_INITIATOR_SALT) - 1) + +#define NEGOEX_ACCEPTOR_SALT "gss-eap-negoex-acceptor" +#define NEGOEX_ACCEPTOR_SALT_LEN (sizeof(NEGOEX_ACCEPTOR_SALT) - 1) + +/* pseudo_random.c */ +OM_uint32 +gssEapPseudoRandom(OM_uint32 *minor, + gss_ctx_id_t ctx, + int prf_key, + const gss_buffer_t prf_in, + gss_buffer_t prf_out); + +/* query_mechanism_info.c */ +OM_uint32 +gssQueryMechanismInfo(OM_uint32 *minor, + gss_const_OID mech_oid, + unsigned char auth_scheme[16]); + +/* query_meta_data.c */ +OM_uint32 +gssEapQueryMetaData(OM_uint32 *minor, + gss_const_OID mech GSSEAP_UNUSED, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + const gss_name_t name, + OM_uint32 req_flags GSSEAP_UNUSED, + gss_buffer_t meta_data); + +/* eap_mech.c */ +OM_uint32 +gssEapInitiatorInit(OM_uint32 *minor); + +void +gssEapFinalize(void); + + /* Debugging and tracing*/ + #define gssEapTrace(_fmt, ...) wpa_printf(MSG_INFO, _fmt, __VA_ARGS__); + +static inline void +gssEapTraceStatus(const char *function, + OM_uint32 major, OM_uint32 minor) +{ + gss_buffer_desc gss_code_buf, mech_buf; + OM_uint32 tmpmaj, tmpmin, ctx = 0; + gss_code_buf.value = NULL; + mech_buf.value = NULL; + tmpmaj = gss_display_status(&tmpmin, major, + GSS_C_GSS_CODE, GSS_C_NO_OID, &ctx, + &gss_code_buf); + if (!GSS_ERROR(tmpmaj)) { +if (minor == 0) + tmpmaj = makeStringBuffer(&tmpmin, "no minor", &mech_buf); +else tmpmaj = gssEapDisplayStatus(&tmpmin, minor, &mech_buf); +} + if (!GSS_ERROR(tmpmaj)) + wpa_printf(MSG_INFO, "%s: %.*s/%.*s", + function, (int) gss_code_buf.length, (char *) gss_code_buf.value, + (int) mech_buf.length, (char *) mech_buf.value); + else wpa_printf(MSG_INFO, "%s: %u/%u", + function, major, minor); + tmpmaj = gss_release_buffer(&tmpmin, &gss_code_buf); + tmpmaj = gss_release_buffer(&tmpmin, &mech_buf); + } + + + /*If built as a library on Linux, don't respect environment when set*uid*/ +#ifdef HAVE_SECURE_GETENV +#define getenv secure_getenv +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _GSSAPIP_EAP_H_ */ diff --cc mech_eap/init_sec_context.c index f6d7269,0000000..a9d8891 mode 100644,000000..100644 --- a/mech_eap/init_sec_context.c +++ b/mech_eap/init_sec_context.c @@@ -1,1367 -1,0 +1,1370 @@@ +/* + * Copyright (c) 2011, JANET(UK) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of JANET(UK) nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Establish a security context on the initiator (client). These functions + * wrap around libeap. + */ + +#include "gssapiP_eap.h" +#include "radius/radius.h" +#include "util_radius.h" +#include "utils/radius_utils.h" + +/* methods allowed for phase1 authentication*/ +static const struct eap_method_type allowed_eap_method_types[] = { + {EAP_VENDOR_IETF, EAP_TYPE_TTLS}, + {EAP_VENDOR_IETF, EAP_TYPE_NONE}}; + +static OM_uint32 +policyVariableToFlag(enum eapol_bool_var variable) +{ + OM_uint32 flag = 0; + + switch (variable) { + case EAPOL_eapSuccess: + flag = CTX_FLAG_EAP_SUCCESS; + break; + case EAPOL_eapRestart: + flag = CTX_FLAG_EAP_RESTART; + break; + case EAPOL_eapFail: + flag = CTX_FLAG_EAP_FAIL; + break; + case EAPOL_eapResp: + flag = CTX_FLAG_EAP_RESP; + break; + case EAPOL_eapNoResp: + flag = CTX_FLAG_EAP_NO_RESP; + break; + case EAPOL_eapReq: + flag = CTX_FLAG_EAP_REQ; + break; + case EAPOL_portEnabled: + flag = CTX_FLAG_EAP_PORT_ENABLED; + break; + case EAPOL_altAccept: + flag = CTX_FLAG_EAP_ALT_ACCEPT; + break; + case EAPOL_altReject: + flag = CTX_FLAG_EAP_ALT_REJECT; + break; ++ case EAPOL_eapTriggerStart: ++ flag = CTX_FLAG_EAP_TRIGGER_START; ++ break; + } + + return flag; +} + +static struct eap_peer_config * +peerGetConfig(void *ctx) +{ + gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx; + + return &gssCtx->initiatorCtx.eapPeerConfig; +} + +static Boolean +peerGetBool(void *data, enum eapol_bool_var variable) +{ + gss_ctx_id_t ctx = data; + OM_uint32 flag; + + if (ctx == GSS_C_NO_CONTEXT) + return FALSE; + + flag = policyVariableToFlag(variable); + + return ((ctx->flags & flag) != 0); +} + +static void +peerSetBool(void *data, enum eapol_bool_var variable, + Boolean value) +{ + gss_ctx_id_t ctx = data; + OM_uint32 flag; + + if (ctx == GSS_C_NO_CONTEXT) + return; + + flag = policyVariableToFlag(variable); + + if (value) + ctx->flags |= flag; + else + ctx->flags &= ~(flag); +} + +static unsigned int +peerGetInt(void *data, enum eapol_int_var variable) +{ + gss_ctx_id_t ctx = data; + + if (ctx == GSS_C_NO_CONTEXT) + return FALSE; + + GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx)); + + switch (variable) { + case EAPOL_idleWhile: + return ctx->initiatorCtx.idleWhile; + break; + } + + return 0; +} + +static void +peerSetInt(void *data, enum eapol_int_var variable, + unsigned int value) +{ + gss_ctx_id_t ctx = data; + + if (ctx == GSS_C_NO_CONTEXT) + return; + + GSSEAP_ASSERT(CTX_IS_INITIATOR(ctx)); + + switch (variable) { + case EAPOL_idleWhile: + ctx->initiatorCtx.idleWhile = value; + break; + } +} + +static struct wpabuf * +peerGetEapReqData(void *ctx) +{ + gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx; + + return &gssCtx->initiatorCtx.reqData; +} + +static void +peerSetConfigBlob(void *ctx GSSEAP_UNUSED, + struct wpa_config_blob *blob GSSEAP_UNUSED) +{ +} + +static const struct wpa_config_blob * +peerGetConfigBlob(void *ctx, + const char *name) +{ + gss_ctx_id_t gssCtx = (gss_ctx_id_t)ctx; + size_t index; + + if (strcmp(name, "client-cert") == 0) + index = CONFIG_BLOB_CLIENT_CERT; + else if (strcmp(name, "private-key") == 0) + index = CONFIG_BLOB_PRIVATE_KEY; + else if (strcmp(name, "ca-cert") == 0) + index = CONFIG_BLOB_CA_CERT; + else + return NULL; + + return &gssCtx->initiatorCtx.configBlobs[index]; +} + +static void +peerNotifyPending(void *ctx GSSEAP_UNUSED) +{ +} + +static struct eapol_callbacks gssEapPolicyCallbacks = { + peerGetConfig, + peerGetBool, + peerSetBool, + peerGetInt, + peerSetInt, + peerGetEapReqData, + peerSetConfigBlob, + peerGetConfigBlob, + peerNotifyPending, +}; + + +#define CHBIND_SERVICE_NAME_FLAG 0x01 +#define CHBIND_HOST_NAME_FLAG 0x02 +#define CHBIND_SERVICE_SPECIFIC_FLAG 0x04 +#define CHBIND_REALM_NAME_FLAG 0x08 + +static OM_uint32 +peerInitEapChannelBinding(OM_uint32 *minor, gss_ctx_id_t ctx) +{ + struct wpabuf *buf = NULL; + unsigned int chbindReqFlags = 0; + krb5_principal princ = NULL; + gss_buffer_desc nameBuf = GSS_C_EMPTY_BUFFER; + OM_uint32 major = GSS_S_COMPLETE; + krb5_context krbContext = NULL; + + /* XXX is this check redundant? */ + if (ctx->acceptorName == GSS_C_NO_NAME) { + major = GSS_S_BAD_NAME; + *minor = GSSEAP_NO_ACCEPTOR_NAME; + goto cleanup; + } + + princ = ctx->acceptorName->krbPrincipal; + + krbPrincComponentToGssBuffer(princ, 0, &nameBuf); + if (nameBuf.length > 0) { + major = gssEapRadiusAddAttr(minor, &buf, PW_GSS_ACCEPTOR_SERVICE_NAME, + 0, &nameBuf); + if (GSS_ERROR(major)) + goto cleanup; + + chbindReqFlags |= CHBIND_SERVICE_NAME_FLAG; + } + + krbPrincComponentToGssBuffer(princ, 1, &nameBuf); + if (nameBuf.length > 0) { + major = gssEapRadiusAddAttr(minor, &buf, PW_GSS_ACCEPTOR_HOST_NAME, + 0, &nameBuf); + if (GSS_ERROR(major)) + goto cleanup; + + chbindReqFlags |= CHBIND_HOST_NAME_FLAG; + } + + GSSEAP_KRB_INIT(&krbContext); + + *minor = krbPrincUnparseServiceSpecifics(krbContext, princ, &nameBuf); + if (*minor != 0) + goto cleanup; + + if (nameBuf.length > 0) { + major = gssEapRadiusAddAttr(minor, &buf, + PW_GSS_ACCEPTOR_SERVICE_SPECIFICS, + 0, &nameBuf); + if (GSS_ERROR(major)) + goto cleanup; + + chbindReqFlags |= CHBIND_SERVICE_SPECIFIC_FLAG; + } + + krbFreeUnparsedName(krbContext, &nameBuf); + krbPrincRealmToGssBuffer(princ, &nameBuf); + + if (nameBuf.length > 0) { + major = gssEapRadiusAddAttr(minor, &buf, + PW_GSS_ACCEPTOR_REALM_NAME, + 0, &nameBuf); + if (GSS_ERROR(major)) + goto cleanup; + + chbindReqFlags |= CHBIND_REALM_NAME_FLAG; + } + + if (chbindReqFlags == 0) { + major = GSS_S_BAD_NAME; + *minor = GSSEAP_BAD_ACCEPTOR_NAME; + goto cleanup; + } + + ctx->initiatorCtx.chbindData = buf; + ctx->initiatorCtx.chbindReqFlags = chbindReqFlags; + + buf = NULL; + + major = GSS_S_COMPLETE; + *minor = 0; + +cleanup: + /*namebuf is freed when used and may be left with a unowned pointer*/ + wpabuf_free(buf); + + return major; +} + +static void +peerProcessChbindResponse(void *context, int code, int nsid, + u8 *data, size_t len) +{ + radius_parser msg; + gss_ctx_id_t ctx = (gss_ctx_id_t )context; + void *vsadata; + u8 type; + u32 vendor_id; + u32 chbindRetFlags = 0; + size_t vsadata_len; + + if (nsid != CHBIND_NSID_RADIUS) + return; + + if (data == NULL) + return; + msg = radius_parser_start(data, len); + if (msg == NULL) + return; + + while (radius_parser_parse_tlv(msg, &type, &vendor_id, &vsadata, + &vsadata_len) == 0) { + switch (type) { + case PW_GSS_ACCEPTOR_SERVICE_NAME: + chbindRetFlags |= CHBIND_SERVICE_NAME_FLAG; + break; + case PW_GSS_ACCEPTOR_HOST_NAME: + chbindRetFlags |= CHBIND_HOST_NAME_FLAG; + break; + case PW_GSS_ACCEPTOR_SERVICE_SPECIFICS: + chbindRetFlags |= CHBIND_SERVICE_SPECIFIC_FLAG; + break; + case PW_GSS_ACCEPTOR_REALM_NAME: + chbindRetFlags |= CHBIND_REALM_NAME_FLAG; + break; + } + } + + radius_parser_finish(msg); + + if (code == CHBIND_CODE_SUCCESS && + ((chbindRetFlags & ctx->initiatorCtx.chbindReqFlags) == ctx->initiatorCtx.chbindReqFlags)) { + ctx->flags |= CTX_FLAG_EAP_CHBIND_ACCEPT; + ctx->gssFlags |= GSS_C_MUTUAL_FLAG; + } /* else log failures? */ +} + +static OM_uint32 +peerConfigInit(OM_uint32 *minor, gss_ctx_id_t ctx) +{ + OM_uint32 major; + krb5_context krbContext; + struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig; + struct wpa_config_blob *configBlobs = ctx->initiatorCtx.configBlobs; + gss_buffer_desc identity = GSS_C_EMPTY_BUFFER; + gss_buffer_desc realm = GSS_C_EMPTY_BUFFER; + gss_cred_id_t cred = ctx->cred; + + eapPeerConfig->identity = NULL; + eapPeerConfig->identity_len = 0; + eapPeerConfig->anonymous_identity = NULL; + eapPeerConfig->anonymous_identity_len = 0; + eapPeerConfig->password = NULL; + eapPeerConfig->password_len = 0; + eapPeerConfig->eap_methods = (struct eap_method_type *) allowed_eap_method_types; + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + GSSEAP_KRB_INIT(&krbContext); + + eapPeerConfig->fragment_size = 1024; + + GSSEAP_ASSERT(cred->name != GSS_C_NO_NAME); + + if ((cred->name->flags & (NAME_FLAG_NAI | NAME_FLAG_SERVICE)) == 0) { + *minor = GSSEAP_BAD_INITIATOR_NAME; + return GSS_S_BAD_NAME; + } + + /* identity */ + major = gssEapDisplayName(minor, cred->name, &identity, NULL); + if (GSS_ERROR(major)) + return major; + + eapPeerConfig->identity = (unsigned char *)identity.value; + eapPeerConfig->identity_len = identity.length; + + krbPrincRealmToGssBuffer(cred->name->krbPrincipal, &realm); + + /* anonymous_identity */ + eapPeerConfig->anonymous_identity = GSSEAP_MALLOC(realm.length + 2); + if (eapPeerConfig->anonymous_identity == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + eapPeerConfig->anonymous_identity[0] = '@'; + memcpy(eapPeerConfig->anonymous_identity + 1, realm.value, realm.length); + eapPeerConfig->anonymous_identity[1 + realm.length] = '\0'; + eapPeerConfig->anonymous_identity_len = 1 + realm.length; + + /* password */ + if ((cred->flags & CRED_FLAG_CERTIFICATE) == 0) { + eapPeerConfig->password = (unsigned char *)cred->password.value; + eapPeerConfig->password_len = cred->password.length; + } + + /* certs */ + eapPeerConfig->ca_cert = (unsigned char *)cred->caCertificate.value; + eapPeerConfig->subject_match = (unsigned char *)cred->subjectNameConstraint.value; + eapPeerConfig->altsubject_match = (unsigned char *)cred->subjectAltNameConstraint.value; + configBlobs[CONFIG_BLOB_CA_CERT].data = cred->caCertificateBlob.value; + configBlobs[CONFIG_BLOB_CA_CERT].len = cred->caCertificateBlob.length; + + /* eap channel binding */ + if (ctx->initiatorCtx.chbindData != NULL) { + struct eap_peer_chbind_config *chbind_config = + (struct eap_peer_chbind_config *)GSSEAP_MALLOC(sizeof(struct eap_peer_chbind_config)); + if (chbind_config == NULL) { + *minor = ENOMEM; + return GSS_S_FAILURE; + } + + chbind_config->req_data = wpabuf_mhead_u8(ctx->initiatorCtx.chbindData); + chbind_config->req_data_len = wpabuf_len(ctx->initiatorCtx.chbindData); + chbind_config->nsid = CHBIND_NSID_RADIUS; + chbind_config->response_cb = &peerProcessChbindResponse; + chbind_config->ctx = ctx; + eapPeerConfig->chbind_config = chbind_config; + eapPeerConfig->chbind_config_len = 1; + } else { + eapPeerConfig->chbind_config = NULL; + eapPeerConfig->chbind_config_len = 0; + } + if (cred->flags & CRED_FLAG_CERTIFICATE) { + /* + * CRED_FLAG_CONFIG_BLOB is an internal flag which will be used in the + * future to directly pass certificate and private key data to the + * EAP implementation, rather than an indirected string pointer. + */ + if (cred->flags & CRED_FLAG_CONFIG_BLOB) { + eapPeerConfig->client_cert = (unsigned char *)"blob://client-cert"; + configBlobs[CONFIG_BLOB_CLIENT_CERT].data = cred->clientCertificate.value; + configBlobs[CONFIG_BLOB_CLIENT_CERT].len = cred->clientCertificate.length; + + eapPeerConfig->client_cert = (unsigned char *)"blob://private-key"; + configBlobs[CONFIG_BLOB_PRIVATE_KEY].data = cred->clientCertificate.value; + configBlobs[CONFIG_BLOB_PRIVATE_KEY].len = cred->privateKey.length; + } else { + eapPeerConfig->client_cert = (unsigned char *)cred->clientCertificate.value; + eapPeerConfig->private_key = (unsigned char *)cred->privateKey.value; + } - eapPeerConfig->private_key_passwd = (unsigned char *)cred->password.value; ++ eapPeerConfig->private_key_passwd = (char *)cred->password.value; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +peerConfigFree(OM_uint32 *minor, + gss_ctx_id_t ctx) +{ + struct eap_peer_config *eapPeerConfig = &ctx->initiatorCtx.eapPeerConfig; + + if (eapPeerConfig->identity != NULL) { + GSSEAP_FREE(eapPeerConfig->identity); + eapPeerConfig->identity = NULL; + eapPeerConfig->identity_len = 0; + } + + if (eapPeerConfig->anonymous_identity != NULL) { + GSSEAP_FREE(eapPeerConfig->anonymous_identity); + eapPeerConfig->anonymous_identity = NULL; + eapPeerConfig->anonymous_identity_len = 0; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +/* + * Mark an initiator context as ready for cryptographic operations + */ +static OM_uint32 +initReady(OM_uint32 *minor, gss_ctx_id_t ctx) +{ + OM_uint32 major; + const unsigned char *key; + size_t keyLength; + + /* Cache encryption type derived from selected mechanism OID */ + major = gssEapOidToEnctype(minor, ctx->mechanismUsed, &ctx->encryptionType); + if (GSS_ERROR(major)) + return major; + + if (!eap_key_available(ctx->initiatorCtx.eap)) { + *minor = GSSEAP_KEY_UNAVAILABLE; + return GSS_S_UNAVAILABLE; + } + + key = eap_get_eapKeyData(ctx->initiatorCtx.eap, &keyLength); + + if (keyLength < EAP_EMSK_LEN) { + *minor = GSSEAP_KEY_TOO_SHORT; + return GSS_S_UNAVAILABLE; + } + + major = gssEapDeriveRfc3961Key(minor, + &key[EAP_EMSK_LEN / 2], + EAP_EMSK_LEN / 2, + ctx->encryptionType, + &ctx->rfc3961Key); + if (GSS_ERROR(major)) + return major; + + major = rfc3961ChecksumTypeForKey(minor, &ctx->rfc3961Key, + &ctx->checksumType); + if (GSS_ERROR(major)) + return major; + + major = sequenceInit(minor, + &ctx->seqState, + ctx->recvSeq, + ((ctx->gssFlags & GSS_C_REPLAY_FLAG) != 0), + ((ctx->gssFlags & GSS_C_SEQUENCE_FLAG) != 0), + TRUE); + if (GSS_ERROR(major)) + return major; + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +initBegin(OM_uint32 *minor, + gss_ctx_id_t ctx, + gss_name_t target, + gss_OID mech, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED) +{ + OM_uint32 major; + gss_cred_id_t cred = ctx->cred; + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + if (cred->expiryTime) + ctx->expiryTime = cred->expiryTime; + else if (timeReq == 0 || timeReq == GSS_C_INDEFINITE) + ctx->expiryTime = 0; + else + ctx->expiryTime = time(NULL) + timeReq; + + /* + * The credential mutex protects its name, however we need to + * explicitly lock the acceptor name (unlikely as it may be + * that it has attributes set on it). + */ + major = gssEapDuplicateName(minor, cred->name, &ctx->initiatorName); + if (GSS_ERROR(major)) + return major; + + if (target != GSS_C_NO_NAME) { + GSSEAP_MUTEX_LOCK(&target->mutex); + + major = gssEapDuplicateName(minor, target, &ctx->acceptorName); + if (GSS_ERROR(major)) { + GSSEAP_MUTEX_UNLOCK(&target->mutex); + return major; + } + + GSSEAP_MUTEX_UNLOCK(&target->mutex); + } + + major = gssEapCanonicalizeOid(minor, + mech, + OID_FLAG_NULL_VALID | OID_FLAG_MAP_NULL_TO_DEFAULT_MECH, + &ctx->mechanismUsed); + if (GSS_ERROR(major)) + return major; + + /* If credentials were provided, check they're usable with this mech */ + if (!gssEapCredAvailable(cred, ctx->mechanismUsed)) { + *minor = GSSEAP_CRED_MECH_MISMATCH; + return GSS_S_BAD_MECH; + } + + *minor = 0; + return GSS_S_COMPLETE; +} + +static OM_uint32 +eapGssSmInitError(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx GSSEAP_UNUSED, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + unsigned char *p; + + if (inputToken->length < 8) { + *minor = GSSEAP_TOK_TRUNC; + return GSS_S_DEFECTIVE_TOKEN; + } + + p = (unsigned char *)inputToken->value; + + major = load_uint32_be(&p[0]); + *minor = load_uint32_be(&p[4]); + if ((*minor >0) && (*minor < 128)) + * minor += ERROR_TABLE_BASE_eapg; + else *minor = 0; + + if (!GSS_ERROR(major) || !IS_WIRE_ERROR(*minor)) { + major = GSS_S_FAILURE; + *minor = GSSEAP_BAD_ERROR_TOKEN; + } + + GSSEAP_ASSERT(GSS_ERROR(major)); + + return major; +} + +#ifdef GSSEAP_ENABLE_REAUTH +static OM_uint32 +eapGssSmInitGssReauth(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags, + OM_uint32 timeReq, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major, tmpMinor; + gss_name_t mechTarget = GSS_C_NO_NAME; + gss_OID actualMech = GSS_C_NO_OID; + OM_uint32 gssFlags, timeRec; + + /* + * Here we use the passed in credential handle because the resolved + * context credential does not currently have the reauth creds. + */ + if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL) { + if (!gssEapCanReauthP(cred, target, timeReq)) + return GSS_S_CONTINUE_NEEDED; + + ctx->flags |= CTX_FLAG_KRB_REAUTH; + } else if ((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0) { + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_WRONG_ITOK; + goto cleanup; + } + + GSSEAP_ASSERT(cred != GSS_C_NO_CREDENTIAL); + + major = gssEapMechToGlueName(minor, target, &mechTarget); + if (GSS_ERROR(major)) + goto cleanup; + + major = gssInitSecContext(minor, + cred->reauthCred, + &ctx->reauthCtx, + mechTarget, + (gss_OID)gss_mech_krb5, + reqFlags | GSS_C_MUTUAL_FLAG, + timeReq, + chanBindings, + inputToken, + &actualMech, + outputToken, + &gssFlags, + &timeRec); + if (GSS_ERROR(major)) + goto cleanup; + + ctx->gssFlags = gssFlags; + + if (major == GSS_S_COMPLETE) { + GSSEAP_ASSERT(GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE); + + major = gssEapReauthComplete(minor, ctx, cred, actualMech, timeRec); + if (GSS_ERROR(major)) + goto cleanup; + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED); + } else { + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_REAUTHENTICATE); + } + +cleanup: + gssReleaseName(&tmpMinor, &mechTarget); + + return major; +} +#endif /* GSSEAP_ENABLE_REAUTH */ + +#ifdef GSSEAP_DEBUG +static OM_uint32 +eapGssSmInitVendorInfo(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx GSSEAP_UNUSED, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + major = makeStringBuffer(minor, "JANET(UK)", outputToken); + if (GSS_ERROR(major)) + return major; + + return GSS_S_CONTINUE_NEEDED; +} +#endif + +static OM_uint32 +eapGssSmInitAcceptorName(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_INITIAL && + ctx->acceptorName != GSS_C_NO_NAME) { + + /* Send desired target name to acceptor */ + major = gssEapDisplayName(minor, ctx->acceptorName, + outputToken, NULL); + if (GSS_ERROR(major)) + return major; + } else if (inputToken != GSS_C_NO_BUFFER) { + OM_uint32 tmpMinor; + gss_name_t nameHint; + int equal; + + /* Accept target name hint from acceptor or verify acceptor */ + major = gssEapImportName(minor, inputToken, + GSS_C_NT_USER_NAME, + ctx->mechanismUsed, + &nameHint); + if (GSS_ERROR(major)) + return major; + + if (ctx->acceptorName != GSS_C_NO_NAME) { + /* verify name hint matched asserted acceptor name */ + major = gssEapCompareName(minor, + nameHint, + ctx->acceptorName, + COMPARE_NAME_FLAG_IGNORE_EMPTY_REALMS, + &equal); + if (GSS_ERROR(major)) { + gssEapReleaseName(&tmpMinor, &nameHint); + return major; + } + + gssEapReleaseName(&tmpMinor, &nameHint); + + if (!equal) { + *minor = GSSEAP_WRONG_ACCEPTOR_NAME; + return GSS_S_DEFECTIVE_TOKEN; + } + } else { /* acceptor name is no_name */ + /* accept acceptor name hint */ + ctx->acceptorName = nameHint; + nameHint = GSS_C_NO_NAME; + } + } + + + /* + * Currently, other parts of the code assume that the acceptor name + * is available, hence this check. + */ + if (ctx->acceptorName == GSS_C_NO_NAME) { + *minor = GSSEAP_NO_ACCEPTOR_NAME; + return GSS_S_FAILURE; + } + + /* + * Generate channel binding data + */ + if (ctx->initiatorCtx.chbindData == NULL) { + major = peerInitEapChannelBinding(minor, ctx); + if (GSS_ERROR(major)) + return major; + } + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmInitIdentity(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags) +{ + struct eap_config eapConfig; + +#ifdef GSSEAP_ENABLE_REAUTH + if (GSSEAP_SM_STATE(ctx) == GSSEAP_STATE_REAUTHENTICATE) { + OM_uint32 tmpMinor; + + /* server didn't support reauthentication, sent EAP request */ + gssDeleteSecContext(&tmpMinor, &ctx->reauthCtx, GSS_C_NO_BUFFER); + ctx->flags &= ~(CTX_FLAG_KRB_REAUTH); + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_INITIAL); + } else +#endif + *smFlags |= SM_FLAG_FORCE_SEND_TOKEN; + + GSSEAP_ASSERT((ctx->flags & CTX_FLAG_KRB_REAUTH) == 0); + GSSEAP_ASSERT(inputToken == GSS_C_NO_BUFFER); + + memset(&eapConfig, 0, sizeof(eapConfig)); + + ctx->initiatorCtx.eap = eap_peer_sm_init(ctx, + &gssEapPolicyCallbacks, + ctx, + &eapConfig); + if (ctx->initiatorCtx.eap == NULL) { + *minor = GSSEAP_PEER_SM_INIT_FAILURE; + return GSS_S_FAILURE; + } + + ctx->flags |= CTX_FLAG_EAP_RESTART | CTX_FLAG_EAP_PORT_ENABLED; + + /* poke EAP state machine */ + if (eap_peer_sm_step(ctx->initiatorCtx.eap) != 0) { + *minor = GSSEAP_PEER_SM_STEP_FAILURE; + return GSS_S_FAILURE; + } + + GSSEAP_SM_TRANSITION_NEXT(ctx); + + *minor = 0; + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmInitAuthenticate(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major; + OM_uint32 tmpMinor; + struct wpabuf *resp = NULL; + + *minor = 0; + + GSSEAP_ASSERT(inputToken != GSS_C_NO_BUFFER); + + major = peerConfigInit(minor, ctx); + if (GSS_ERROR(major)) + goto cleanup; + + GSSEAP_ASSERT(ctx->initiatorCtx.eap != NULL); + GSSEAP_ASSERT(ctx->flags & CTX_FLAG_EAP_PORT_ENABLED); + + ctx->flags |= CTX_FLAG_EAP_REQ; /* we have a Request from the acceptor */ + + wpabuf_set(&ctx->initiatorCtx.reqData, + inputToken->value, inputToken->length); + + major = GSS_S_CONTINUE_NEEDED; + + eap_peer_sm_step(ctx->initiatorCtx.eap); + if (ctx->flags & CTX_FLAG_EAP_RESP) { + ctx->flags &= ~(CTX_FLAG_EAP_RESP); + + resp = eap_get_eapRespData(ctx->initiatorCtx.eap); + } else if (ctx->flags & CTX_FLAG_EAP_SUCCESS) { + major = initReady(minor, ctx); + if (GSS_ERROR(major)) + goto cleanup; + + ctx->flags &= ~(CTX_FLAG_EAP_SUCCESS); + major = GSS_S_CONTINUE_NEEDED; + GSSEAP_SM_TRANSITION_NEXT(ctx); + } else if (ctx->flags & CTX_FLAG_EAP_FAIL) { + major = GSS_S_DEFECTIVE_CREDENTIAL; + *minor = GSSEAP_PEER_AUTH_FAILURE; + } else { + major = GSS_S_DEFECTIVE_TOKEN; + *minor = GSSEAP_PEER_BAD_MESSAGE; + } + +cleanup: + if (resp != NULL) { + OM_uint32 tmpMajor; + gss_buffer_desc respBuf; + + GSSEAP_ASSERT(major == GSS_S_CONTINUE_NEEDED); + + respBuf.length = wpabuf_len(resp); + respBuf.value = (void *)wpabuf_head(resp); + + tmpMajor = duplicateBuffer(&tmpMinor, &respBuf, outputToken); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; + } + + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + } + + wpabuf_set(&ctx->initiatorCtx.reqData, NULL, 0); + peerConfigFree(&tmpMinor, ctx); + + return major; +} + +static OM_uint32 +eapGssSmInitGssFlags(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + unsigned char wireFlags[4]; + gss_buffer_desc flagsBuf; + + /* + * As a temporary measure, force mutual authentication until channel binding is + * more widely deployed. + */ + ctx->gssFlags |= GSS_C_MUTUAL_FLAG; + store_uint32_be(ctx->gssFlags & GSSEAP_WIRE_FLAGS_MASK, wireFlags); + + flagsBuf.length = sizeof(wireFlags); + flagsBuf.value = wireFlags; + + return duplicateBuffer(minor, &flagsBuf, outputToken); +} + +static OM_uint32 +eapGssSmInitGssChannelBindings(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major; + krb5_error_code code; + krb5_context krbContext; + krb5_data data; + krb5_checksum cksum; + gss_buffer_desc cksumBuffer; + + if (chanBindings == GSS_C_NO_CHANNEL_BINDINGS || + chanBindings->application_data.length == 0) + return GSS_S_CONTINUE_NEEDED; + + GSSEAP_KRB_INIT(&krbContext); + + KRB_DATA_INIT(&data); + + gssBufferToKrbData(&chanBindings->application_data, &data); + + code = krb5_c_make_checksum(krbContext, ctx->checksumType, + &ctx->rfc3961Key, + KEY_USAGE_GSSEAP_CHBIND_MIC, + &data, &cksum); + if (code != 0) { + *minor = code; + return GSS_S_FAILURE; + } + + cksumBuffer.length = KRB_CHECKSUM_LENGTH(&cksum); + cksumBuffer.value = KRB_CHECKSUM_DATA(&cksum); + + major = duplicateBuffer(minor, &cksumBuffer, outputToken); + if (GSS_ERROR(major)) { + krb5_free_checksum_contents(krbContext, &cksum); + return major; + } + + *minor = 0; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + + krb5_free_checksum_contents(krbContext, &cksum); + + return GSS_S_CONTINUE_NEEDED; +} + +static OM_uint32 +eapGssSmInitInitiatorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken GSSEAP_UNUSED, + gss_buffer_t outputToken, + OM_uint32 *smFlags) +{ + OM_uint32 major; + + major = gssEapMakeTokenMIC(minor, ctx, outputToken); + if (GSS_ERROR(major)) + return major; + + GSSEAP_SM_TRANSITION_NEXT(ctx); + + *minor = 0; + *smFlags |= SM_FLAG_OUTPUT_TOKEN_CRITICAL; + + return GSS_S_CONTINUE_NEEDED; +} + +#ifdef GSSEAP_ENABLE_REAUTH +static OM_uint32 +eapGssSmInitReauthCreds(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + if (ctx->gssFlags & GSS_C_MUTUAL_FLAG) { + major = gssEapStoreReauthCreds(minor, ctx, cred, inputToken); + if (GSS_ERROR(major)) + return major; + } + + *minor = 0; + return GSS_S_CONTINUE_NEEDED; +} +#endif /* GSSEAP_ENABLE_REAUTH */ + +static OM_uint32 +eapGssSmInitAcceptorMIC(OM_uint32 *minor, + gss_cred_id_t cred GSSEAP_UNUSED, + gss_ctx_id_t ctx, + gss_name_t target GSSEAP_UNUSED, + gss_OID mech GSSEAP_UNUSED, + OM_uint32 reqFlags GSSEAP_UNUSED, + OM_uint32 timeReq GSSEAP_UNUSED, + gss_channel_bindings_t chanBindings GSSEAP_UNUSED, + gss_buffer_t inputToken, + gss_buffer_t outputToken GSSEAP_UNUSED, + OM_uint32 *smFlags GSSEAP_UNUSED) +{ + OM_uint32 major; + + major = gssEapVerifyTokenMIC(minor, ctx, inputToken); + if (GSS_ERROR(major)) + return major; + + GSSEAP_SM_TRANSITION(ctx, GSSEAP_STATE_ESTABLISHED); + + *minor = 0; + + return GSS_S_COMPLETE; +} + +static struct gss_eap_sm eapGssInitiatorSm[] = { + { + ITOK_TYPE_CONTEXT_ERR, + ITOK_TYPE_NONE, + GSSEAP_STATE_ALL & ~(GSSEAP_STATE_INITIAL), + 0, + eapGssSmInitError + }, + { + ITOK_TYPE_ACCEPTOR_NAME_RESP, + ITOK_TYPE_ACCEPTOR_NAME_REQ, + GSSEAP_STATE_INITIAL | GSSEAP_STATE_AUTHENTICATE | + GSSEAP_STATE_ACCEPTOR_EXTS, + 0, + eapGssSmInitAcceptorName + }, +#ifdef GSSEAP_DEBUG + { + ITOK_TYPE_NONE, + ITOK_TYPE_VENDOR_INFO, + GSSEAP_STATE_INITIAL, + 0, + eapGssSmInitVendorInfo + }, +#endif +#ifdef GSSEAP_ENABLE_REAUTH + { + ITOK_TYPE_REAUTH_RESP, + ITOK_TYPE_REAUTH_REQ, + GSSEAP_STATE_INITIAL | GSSEAP_STATE_REAUTHENTICATE, + 0, + eapGssSmInitGssReauth + }, +#endif + { + ITOK_TYPE_NONE, + ITOK_TYPE_NONE, +#ifdef GSSEAP_ENABLE_REAUTH + GSSEAP_STATE_REAUTHENTICATE | +#endif + GSSEAP_STATE_INITIAL, + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitIdentity + }, + { + ITOK_TYPE_EAP_REQ, + ITOK_TYPE_EAP_RESP, + GSSEAP_STATE_AUTHENTICATE, + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitAuthenticate + }, + { + ITOK_TYPE_NONE, + ITOK_TYPE_GSS_FLAGS, + GSSEAP_STATE_INITIATOR_EXTS, + 0, + eapGssSmInitGssFlags + }, + { + ITOK_TYPE_NONE, + ITOK_TYPE_GSS_CHANNEL_BINDINGS, + GSSEAP_STATE_INITIATOR_EXTS, + 0, + eapGssSmInitGssChannelBindings + }, + { + ITOK_TYPE_NONE, + ITOK_TYPE_INITIATOR_MIC, + GSSEAP_STATE_INITIATOR_EXTS, + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitInitiatorMIC + }, +#ifdef GSSEAP_ENABLE_REAUTH + { + ITOK_TYPE_REAUTH_CREDS, + ITOK_TYPE_NONE, + GSSEAP_STATE_ACCEPTOR_EXTS, + 0, + eapGssSmInitReauthCreds + }, +#endif + /* other extensions go here */ + { + ITOK_TYPE_ACCEPTOR_MIC, + ITOK_TYPE_NONE, + GSSEAP_STATE_ACCEPTOR_EXTS, + SM_ITOK_FLAG_REQUIRED, + eapGssSmInitAcceptorMIC + } +}; + +OM_uint32 +gssEapInitSecContext(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t ctx, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + OM_uint32 major, tmpMinor; + int initialContextToken = (ctx->mechanismUsed == GSS_C_NO_OID); + + /* + * XXX is acquiring the credential lock here necessary? The password is + * mutable but the contract could specify that this is not updated whilst + * a context is being initialized. + */ + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_LOCK(&cred->mutex); + + if (ctx->cred == GSS_C_NO_CREDENTIAL) { + major = gssEapResolveInitiatorCred(minor, cred, target_name, &ctx->cred); + if (GSS_ERROR(major)) + goto cleanup; + + GSSEAP_ASSERT(ctx->cred != GSS_C_NO_CREDENTIAL); + } + + GSSEAP_MUTEX_LOCK(&ctx->cred->mutex); + + GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_RESOLVED); + GSSEAP_ASSERT(ctx->cred->flags & CRED_FLAG_INITIATE); + + if (initialContextToken) { + major = initBegin(minor, ctx, target_name, mech_type, + req_flags, time_req, input_chan_bindings); + if (GSS_ERROR(major)) + goto cleanup; + } + + major = gssEapSmStep(minor, + cred, + ctx, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + output_token, + eapGssInitiatorSm, + sizeof(eapGssInitiatorSm) / sizeof(eapGssInitiatorSm[0])); + if (GSS_ERROR(major)) + goto cleanup; + + if (actual_mech_type != NULL) { + OM_uint32 tmpMajor; + + tmpMajor = gssEapCanonicalizeOid(&tmpMinor, ctx->mechanismUsed, 0, actual_mech_type); + if (GSS_ERROR(tmpMajor)) { + major = tmpMajor; + *minor = tmpMinor; + goto cleanup; + } + } + + if (ret_flags != NULL) + *ret_flags = ctx->gssFlags; + + if (time_rec != NULL) + gssEapContextTime(&tmpMinor, ctx, time_rec); + + GSSEAP_ASSERT(CTX_IS_ESTABLISHED(ctx) || major == GSS_S_CONTINUE_NEEDED); + +cleanup: + if (cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&cred->mutex); + if (ctx->cred != GSS_C_NO_CREDENTIAL) + GSSEAP_MUTEX_UNLOCK(&ctx->cred->mutex); + + return major; +} + +OM_uint32 GSSAPI_CALLCONV +gss_init_sec_context(OM_uint32 *minor, + gss_cred_id_t cred, + gss_ctx_id_t *context_handle, + gss_name_t target_name, + gss_OID mech_type, + OM_uint32 req_flags, + OM_uint32 time_req, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_OID *actual_mech_type, + gss_buffer_t output_token, + OM_uint32 *ret_flags, + OM_uint32 *time_rec) +{ + OM_uint32 major, tmpMinor; + gss_ctx_id_t ctx = *context_handle; + + *minor = 0; + + output_token->length = 0; + output_token->value = NULL; + + if (ctx == GSS_C_NO_CONTEXT) { + if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) { + *minor = GSSEAP_WRONG_SIZE; + return GSS_S_DEFECTIVE_TOKEN; + } + + major = gssEapAllocContext(minor, &ctx); + if (GSS_ERROR(major)) + return major; + + ctx->flags |= CTX_FLAG_INITIATOR; + + *context_handle = ctx; + } + + GSSEAP_MUTEX_LOCK(&ctx->mutex); + + major = gssEapInitSecContext(minor, + cred, + ctx, + target_name, + mech_type, + req_flags, + time_req, + input_chan_bindings, + input_token, + actual_mech_type, + output_token, + ret_flags, + time_rec); + + GSSEAP_MUTEX_UNLOCK(&ctx->mutex); + + if (GSS_ERROR(major)) + gssEapReleaseContext(&tmpMinor, context_handle); + + gssEapTraceStatus( "gss_init_sec_context", major, *minor); + return major; +}