aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2007-07-11 15:48:36 +0000
committerSam Leffler <sam@FreeBSD.org>2007-07-11 15:48:36 +0000
commit7700b89cce864f82dbd9cf54979c59dd06ca9356 (patch)
treec3da7f33886a852f7dceb74373fbdeec49a48f77
parent4e0922e888407f6dd91546a040e26125317fcfd8 (diff)
downloadsrc-7700b89cce864f82dbd9cf54979c59dd06ca9356.tar.gz
src-7700b89cce864f82dbd9cf54979c59dd06ca9356.zip
Import of WPA supplicant 0.5.8
Notes
Notes: svn path=/vendor/wpa_supplicant/dist/; revision=171366
-rw-r--r--contrib/wpa_supplicant/COPYING4
-rw-r--r--contrib/wpa_supplicant/ChangeLog328
-rw-r--r--contrib/wpa_supplicant/FREEBSD-Xlist19
-rw-r--r--contrib/wpa_supplicant/FREEBSD-upgrade8
-rw-r--r--contrib/wpa_supplicant/Makefile530
-rw-r--r--contrib/wpa_supplicant/README102
-rw-r--r--contrib/wpa_supplicant/aes.c12
-rw-r--r--contrib/wpa_supplicant/aes.h25
-rw-r--r--contrib/wpa_supplicant/aes_wrap.c377
-rw-r--r--contrib/wpa_supplicant/aes_wrap.h2
-rw-r--r--contrib/wpa_supplicant/asn1.c205
-rw-r--r--contrib/wpa_supplicant/asn1.h71
-rw-r--r--contrib/wpa_supplicant/asn1_test.c210
-rw-r--r--contrib/wpa_supplicant/base64.c32
-rw-r--r--contrib/wpa_supplicant/base64.h2
-rw-r--r--contrib/wpa_supplicant/bignum.c230
-rw-r--r--contrib/wpa_supplicant/bignum.h38
-rw-r--r--contrib/wpa_supplicant/build_config.h50
-rw-r--r--contrib/wpa_supplicant/common.c479
-rw-r--r--contrib/wpa_supplicant/common.h312
-rw-r--r--contrib/wpa_supplicant/config.c713
-rw-r--r--contrib/wpa_supplicant/config.h82
-rw-r--r--contrib/wpa_supplicant/config_file.c365
-rw-r--r--contrib/wpa_supplicant/config_none.c57
-rw-r--r--contrib/wpa_supplicant/config_ssid.h121
-rw-r--r--contrib/wpa_supplicant/config_types.h14
-rw-r--r--contrib/wpa_supplicant/config_winreg.c882
-rw-r--r--contrib/wpa_supplicant/crypto.c87
-rw-r--r--contrib/wpa_supplicant/crypto.h308
-rw-r--r--contrib/wpa_supplicant/crypto_cryptoapi.c801
-rw-r--r--contrib/wpa_supplicant/crypto_gnutls.c14
-rw-r--r--contrib/wpa_supplicant/crypto_internal.c670
-rw-r--r--contrib/wpa_supplicant/crypto_libtomcrypt.c736
-rw-r--r--contrib/wpa_supplicant/crypto_none.c28
-rw-r--r--contrib/wpa_supplicant/ctrl_iface.c1401
-rw-r--r--contrib/wpa_supplicant/ctrl_iface.h127
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_dbus.c1043
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_dbus.h146
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_dbus_handlers.c1205
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_dbus_handlers.h77
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_named_pipe.c834
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_udp.c561
-rw-r--r--contrib/wpa_supplicant/ctrl_iface_unix.c656
-rw-r--r--contrib/wpa_supplicant/dbus-wpa_supplicant.conf20
-rw-r--r--contrib/wpa_supplicant/dbus_dict_helpers.c957
-rw-r--r--contrib/wpa_supplicant/dbus_dict_helpers.h135
-rw-r--r--contrib/wpa_supplicant/defconfig162
-rw-r--r--contrib/wpa_supplicant/defs.h13
-rw-r--r--contrib/wpa_supplicant/des.c476
-rw-r--r--contrib/wpa_supplicant/doc/code_structure.doxygen6
-rw-r--r--contrib/wpa_supplicant/doc/ctrl_iface.doxygen30
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_background.84
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_background.sgml2
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_cli.815
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml14
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_passphrase.89
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml7
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.817
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.58
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml6
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml26
-rw-r--r--contrib/wpa_supplicant/doc/doxygen.fast2
-rw-r--r--contrib/wpa_supplicant/doc/doxygen.full4
-rw-r--r--contrib/wpa_supplicant/doc/eap.doxygen28
-rwxr-xr-xcontrib/wpa_supplicant/doc/kerneldoc2doxygen.pl4
-rw-r--r--contrib/wpa_supplicant/doc/mainpage.doxygen2
-rw-r--r--contrib/wpa_supplicant/doc/porting.doxygen91
-rw-r--r--contrib/wpa_supplicant/doc/testing_tools.doxygen9
-rw-r--r--contrib/wpa_supplicant/driver.h208
-rw-r--r--contrib/wpa_supplicant/driver_hostap.h2
-rw-r--r--contrib/wpa_supplicant/driver_ndis.c1500
-rw-r--r--contrib/wpa_supplicant/driver_ndis.h29
-rw-r--r--contrib/wpa_supplicant/driver_wired.c73
-rw-r--r--contrib/wpa_supplicant/drivers.c16
-rw-r--r--contrib/wpa_supplicant/eap.c1170
-rw-r--r--contrib/wpa_supplicant/eap.h62
-rw-r--r--contrib/wpa_supplicant/eap_aka.c342
-rw-r--r--contrib/wpa_supplicant/eap_defs.h39
-rw-r--r--contrib/wpa_supplicant/eap_fast.c736
-rw-r--r--contrib/wpa_supplicant/eap_gpsk.c583
-rw-r--r--contrib/wpa_supplicant/eap_gpsk_common.c441
-rw-r--r--contrib/wpa_supplicant/eap_gpsk_common.h66
-rw-r--r--contrib/wpa_supplicant/eap_gtc.c120
-rw-r--r--contrib/wpa_supplicant/eap_i.h84
-rw-r--r--contrib/wpa_supplicant/eap_leap.c148
-rw-r--r--contrib/wpa_supplicant/eap_md5.c89
-rw-r--r--contrib/wpa_supplicant/eap_methods.c500
-rw-r--r--contrib/wpa_supplicant/eap_methods.h87
-rw-r--r--contrib/wpa_supplicant/eap_mschapv2.c796
-rw-r--r--contrib/wpa_supplicant/eap_otp.c81
-rw-r--r--contrib/wpa_supplicant/eap_pax.c117
-rw-r--r--contrib/wpa_supplicant/eap_pax_common.c20
-rw-r--r--contrib/wpa_supplicant/eap_pax_common.h31
-rw-r--r--contrib/wpa_supplicant/eap_peap.c291
-rw-r--r--contrib/wpa_supplicant/eap_psk.c169
-rw-r--r--contrib/wpa_supplicant/eap_psk_common.c25
-rw-r--r--contrib/wpa_supplicant/eap_psk_common.h29
-rw-r--r--contrib/wpa_supplicant/eap_sake.c515
-rw-r--r--contrib/wpa_supplicant/eap_sake_common.c380
-rw-r--r--contrib/wpa_supplicant/eap_sake_common.h104
-rw-r--r--contrib/wpa_supplicant/eap_sim.c371
-rw-r--r--contrib/wpa_supplicant/eap_sim_common.c316
-rw-r--r--contrib/wpa_supplicant/eap_sim_common.h76
-rw-r--r--contrib/wpa_supplicant/eap_testing.txt14
-rw-r--r--contrib/wpa_supplicant/eap_tls.c183
-rw-r--r--contrib/wpa_supplicant/eap_tls_common.c579
-rw-r--r--contrib/wpa_supplicant/eap_tls_common.h11
-rw-r--r--contrib/wpa_supplicant/eap_tlv.c68
-rw-r--r--contrib/wpa_supplicant/eap_tlv.h24
-rw-r--r--contrib/wpa_supplicant/eap_ttls.c817
-rw-r--r--contrib/wpa_supplicant/eap_ttls.h14
-rw-r--r--contrib/wpa_supplicant/eap_vendor_test.c198
-rw-r--r--contrib/wpa_supplicant/eapol_sm.c328
-rw-r--r--contrib/wpa_supplicant/eapol_sm.h12
-rw-r--r--contrib/wpa_supplicant/eapol_test.c293
-rw-r--r--contrib/wpa_supplicant/eloop.c332
-rw-r--r--contrib/wpa_supplicant/eloop.h207
-rw-r--r--contrib/wpa_supplicant/eloop_none.c390
-rw-r--r--contrib/wpa_supplicant/eloop_win.c604
-rw-r--r--contrib/wpa_supplicant/events.c253
-rw-r--r--contrib/wpa_supplicant/hostapd.h9
-rw-r--r--contrib/wpa_supplicant/includes.h57
-rw-r--r--contrib/wpa_supplicant/l2_packet.h12
-rw-r--r--contrib/wpa_supplicant/libtommath.c2370
-rw-r--r--contrib/wpa_supplicant/main.c110
-rw-r--r--contrib/wpa_supplicant/md4.c282
-rw-r--r--contrib/wpa_supplicant/md5.c53
-rw-r--r--contrib/wpa_supplicant/md5.h11
-rw-r--r--contrib/wpa_supplicant/mlme.c2897
-rw-r--r--contrib/wpa_supplicant/mlme.h104
-rw-r--r--contrib/wpa_supplicant/ms_funcs.c245
-rw-r--r--contrib/wpa_supplicant/ms_funcs.h13
-rw-r--r--contrib/wpa_supplicant/nmake.mak188
-rw-r--r--contrib/wpa_supplicant/openssl-0.9.8d-tls-extensions.patch429
-rw-r--r--contrib/wpa_supplicant/openssl-0.9.8e-tls-extensions.patch353
-rw-r--r--contrib/wpa_supplicant/os.h485
-rw-r--r--contrib/wpa_supplicant/os_internal.c441
-rw-r--r--contrib/wpa_supplicant/os_none.c220
-rw-r--r--contrib/wpa_supplicant/os_unix.c212
-rw-r--r--contrib/wpa_supplicant/pcsc_funcs.c599
-rw-r--r--contrib/wpa_supplicant/pcsc_funcs.h10
-rw-r--r--contrib/wpa_supplicant/pmksa_cache.c502
-rw-r--r--contrib/wpa_supplicant/pmksa_cache.h116
-rw-r--r--contrib/wpa_supplicant/preauth.c530
-rw-r--r--contrib/wpa_supplicant/preauth.h53
-rw-r--r--contrib/wpa_supplicant/preauth_test.c77
-rw-r--r--contrib/wpa_supplicant/radius.c295
-rw-r--r--contrib/wpa_supplicant/radius.h48
-rw-r--r--contrib/wpa_supplicant/radius_client.c427
-rw-r--r--contrib/wpa_supplicant/radius_client.h22
-rw-r--r--contrib/wpa_supplicant/rc4.c7
-rw-r--r--contrib/wpa_supplicant/rc4.h2
-rw-r--r--contrib/wpa_supplicant/rsa.c359
-rw-r--r--contrib/wpa_supplicant/rsa.h29
-rw-r--r--contrib/wpa_supplicant/sha1.c470
-rw-r--r--contrib/wpa_supplicant/sha1.h10
-rw-r--r--contrib/wpa_supplicant/sha256.c379
-rw-r--r--contrib/wpa_supplicant/sha256.h27
-rw-r--r--contrib/wpa_supplicant/state_machine.h144
-rw-r--r--contrib/wpa_supplicant/tls.h182
-rw-r--r--contrib/wpa_supplicant/tls_gnutls.c772
-rw-r--r--contrib/wpa_supplicant/tls_internal.c326
-rw-r--r--contrib/wpa_supplicant/tls_none.c219
-rw-r--r--contrib/wpa_supplicant/tls_openssl.c418
-rw-r--r--contrib/wpa_supplicant/tls_schannel.c172
-rw-r--r--contrib/wpa_supplicant/tlsv1_client.c2609
-rw-r--r--contrib/wpa_supplicant/tlsv1_client.h58
-rw-r--r--contrib/wpa_supplicant/tlsv1_common.c552
-rw-r--r--contrib/wpa_supplicant/tlsv1_common.h233
-rw-r--r--contrib/wpa_supplicant/todo.txt93
-rw-r--r--contrib/wpa_supplicant/version.h2
-rw-r--r--contrib/wpa_supplicant/wpa.c2289
-rw-r--r--contrib/wpa_supplicant/wpa.h51
-rw-r--r--contrib/wpa_supplicant/wpa_cli.c604
-rw-r--r--contrib/wpa_supplicant/wpa_common.h58
-rw-r--r--contrib/wpa_supplicant/wpa_ctrl.c296
-rw-r--r--contrib/wpa_supplicant/wpa_ctrl.h4
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp122
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.h63
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui200
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/main.cpp44
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp582
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.h58
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui747
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/scanresults.cpp124
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/scanresults.h47
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui290
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp100
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.h46
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui264
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro31
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpagui.cpp779
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpagui.h76
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui712
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h42
-rw-r--r--contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h4
-rw-r--r--contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h92
-rw-r--r--contrib/wpa_supplicant/wpa_gui/scanresults.ui.h6
-rwxr-xr-xcontrib/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling11
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpa_gui.pro28
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpagui.ui7
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpagui.ui.h88
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpamsg.h11
-rw-r--r--contrib/wpa_supplicant/wpa_i.h77
-rw-r--r--contrib/wpa_supplicant/wpa_passphrase.c9
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.c939
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.conf118
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.h43
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant_i.h226
-rw-r--r--contrib/wpa_supplicant/x509v3.c1596
-rw-r--r--contrib/wpa_supplicant/x509v3.h154
211 files changed, 49687 insertions, 9538 deletions
diff --git a/contrib/wpa_supplicant/COPYING b/contrib/wpa_supplicant/COPYING
index 60549be514af..14f5453722a8 100644
--- a/contrib/wpa_supplicant/COPYING
+++ b/contrib/wpa_supplicant/COPYING
@@ -2,7 +2,7 @@
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
diff --git a/contrib/wpa_supplicant/ChangeLog b/contrib/wpa_supplicant/ChangeLog
index 4ed9e261dfb6..5bf3660a05c9 100644
--- a/contrib/wpa_supplicant/ChangeLog
+++ b/contrib/wpa_supplicant/ChangeLog
@@ -1,32 +1,334 @@
ChangeLog for wpa_supplicant
-2006-02-08 - v0.4.8
+2007-05-28 - v0.5.8
+ * updated driver_wext.c to build with the current wireless-dev.git tree
+ and net/d80211 changes
+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+ draft (draft-ietf-emu-eap-gpsk-03.txt)
+ * fixed 'make install'
+ * fixed EAP-TTLS implementation not to crash on use of freed memory
+ if TLS library initialization fails
+ * fixed EAP-AKA Notification processing to allow Notification to be
+ processed after AKA Challenge response has been sent
+
+2006-12-31 - v0.5.7
+ * updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
+ * updated EAP-PSK to use the IANA-allocated EAP type 47
+ * fixed EAP-PAX key derivation
+ * fixed EAP-PSK bit ordering of the Flags field
+ * fixed EAP-PEAP/TTLS/FAST to use the correct EAP identifier in
+ tunnelled identity request (previously, the identifier from the outer
+ method was used, not the tunnelled identifier which could be
+ different)
+ * fixed EAP-TTLS AVP parser processing for too short AVP lengths
+ * added support for EAP-FAST authentication with inner methods that
+ generate MSK (e.g., EAP-MSCHAPv2 that was previously only supported
+ for PAC provisioning)
+ * fixed dbus ctrl_iface to validate message interface before
+ dispatching to avoid a possible segfault [Bug 190]
+ * fixed PeerKey key derivation to use the correct PRF label
+ * updated Windows binary build to link against OpenSSL 0.9.8d and
+ added support for EAP-FAST
+
+2006-11-24 - v0.5.6
+ * added experimental, integrated TLSv1 client implementation with the
+ needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
+ setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
+ .config); this can be useful, e.g., if the target system does not
+ have a suitable TLS library and a minimal code size is required
+ (total size of this internal TLS/crypto code is bit under 50 kB on
+ x86 and the crypto code is shared by rest of the supplicant so some
+ of it was already required; TLSv1/X.509/ASN.1/RSA added about 25 kB)
+ * removed STAKey handshake since PeerKey handshake has replaced it in
+ IEEE 802.11ma and there are no known deployments of STAKey
+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+ draft (draft-ietf-emu-eap-gpsk-01.txt)
+ * added preliminary implementation of IEEE 802.11w/D1.0 (management
+ frame protection)
+ (Note: this requires driver support to work properly.)
+ (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
+ * fixed Windows named pipes ctrl_iface to not stop listening for
+ commands if client program opens a named pipe and closes it
+ immediately without sending a command
+ * fixed USIM PIN status determination for the case that PIN is not
+ needed (this allows EAP-AKA to be used with USIM cards that do not
+ use PIN)
+ * added support for reading 3G USIM AID from EF_DIR to allow EAP-AKA to
+ be used with cards that do not support file selection based on
+ partial AID
+ * added support for matching the subjectAltName of the authentication
+ server certificate against multiple name components (e.g.,
+ altsubject_match="DNS:server.example.com;DNS:server2.example.com")
+ * fixed EAP-SIM/AKA key derivation for re-authentication case (only
+ affects IEEE 802.1X with dynamic WEP keys)
+ * changed ctrl_iface network configuration 'get' operations to not
+ return password/key material; if these fields are requested, "*"
+ will be returned if the password/key is set, but the value of the
+ parameter is not exposed
+
+2006-08-27 - v0.5.5
+ * added support for building Windows version with UNICODE defined
+ (wide-char functions)
+ * driver_ndis: fixed static WEP configuration to avoid race condition
+ issues with some NDIS drivers between association and setting WEP
+ keys
+ * driver_ndis: added validation for IELength value in scan results to
+ avoid crashes when using buggy NDIS drivers [Bug 165]
+ * fixed Release|Win32 target in the Visual Studio project files
+ (previously, only Debug|Win32 target was set properly)
+ * changed control interface API call wpa_ctrl_pending() to allow it to
+ return -1 on error (e.g., connection lost); control interface clients
+ will need to make sure that they verify that the value is indeed >0
+ when determining whether there are pending messages
+ * added an alternative control interface backend for Windows targets:
+ Named Pipe (CONFIG_CTRL_IFACE=named_pipe); this is now the default
+ control interface mechanism for Windows builds (previously, UDP to
+ localhost was used)
+ * changed ctrl_interface configuration for UNIX domain sockets:
+ - deprecated ctrl_interface_group variable (it may be removed in
+ future versions)
+ - allow both directory and group be configured with ctrl_interface
+ in following format: DIR=/var/run/wpa_supplicant GROUP=wheel
+ - ctrl_interface=/var/run/wpa_supplicant is still supported for the
+ case when group is not changed
+ * added support for controlling more than one interface per process in
+ Windows version
+ * added a workaround for a case where the AP is using unknown address
+ (e.g., MAC address of the wired interface) as the source address for
+ EAPOL-Key frames; previously, that source address was used as the
+ destination for EAPOL-Key frames and in key derivation; now, BSSID is
+ used even if the source address does not match with it
+ (this resolves an interoperability issue with Thomson SpeedTouch 580)
+ * added a workaround for UDP-based control interface (which was used in
+ Windows builds before this release) to prevent packets with forged
+ addresses from being accepted as local control requests
+ * removed ndis_events.cpp and possibility of using external
+ ndis_events.exe; C version (ndis_events.c) is fully functional and
+ there is no desire to maintain two separate versions of this
+ implementation
+ * ndis_events: Changed NDIS event notification design to use WMI to
+ learn the adapter description through Win32_PnPEntity class; this
+ should fix some cases where the adapter name was not recognized
+ correctly (e.g., with some USB WLAN adapters, e.g., Ralink RT2500
+ USB) [Bug 113]
+ * fixed selection of the first network in ap_scan=2 mode; previously,
+ wpa_supplicant could get stuck in SCANNING state when only the first
+ network for enabled (e.g., after 'wpa_cli select_network 0')
+ * winsvc: added support for configuring ctrl_interface parameters in
+ registry (ctrl_interface string value in
+ HKLM\SOFTWARE\wpa_supplicant\interfaces\0000 key); this new value is
+ required to enable control interface (previously, this was hardcoded
+ to be enabled)
+ * allow wpa_gui subdirectory to be built with both Qt3 and Qt4
+ * converted wpa_gui-qt4 subdirectory to use Qt4 specific project format
+
+2006-06-20 - v0.5.4
+ * fixed build with CONFIG_STAKEY=y [Bug 143]
+ * added support for doing MLME (IEEE 802.11 management frame
+ processing) in wpa_supplicant when using Devicescape IEEE 802.11
+ stack (wireless-dev.git tree)
+ * added a new network block configuration option, fragment_size, to
+ configure the maximum EAP fragment size
+ * driver_ndis: Disable WZC automatically for the selected interface to
+ avoid conflicts with two programs trying to control the radio; WZC
+ will be re-enabled (if it was enabled originally) when wpa_supplicant
+ is terminated
+ * added an experimental TLSv1 client implementation
+ (CONFIG_TLS=internal) that can be used instead of an external TLS
+ library, e.g., to reduce total size requirement on systems that do
+ not include any TLS library by default (this is not yet complete;
+ basic functionality is there, but certificate validation is not yet
+ included)
+ * added PeerKey handshake implementation for IEEE 802.11e
+ direct link setup (DLS) to replace STAKey handshake
+ * fixed WPA PSK update through ctrl_iface for the case where the old
+ PSK was derived from an ASCII passphrase and the new PSK is set as
+ a raw PSK (hex string)
+ * added new configuration option for identifying which network block
+ was used (id_str in wpa_supplicant.conf; included on
+ WPA_EVENT_CONNECT monitor event and as WPA_ID_STR environmental
+ variable in wpa_cli action scripts; in addition WPA_ID variable is
+ set to the current unique identifier that wpa_supplicant assigned
+ automatically for the network and that can be used with
+ GET_NETWORK/SET_NETWORK ctrl_iface commands)
+ * wpa_cli action script is now called only when the connect/disconnect
+ status changes or when associating with a different network
+ * fixed configuration parser not to remove CCMP from group cipher list
+ if WPA-None (adhoc) is used (pairwise=NONE in that case)
+ * fixed integrated NDIS events processing not to hang the process due
+ to a missed change in eloop_win.c API in v0.5.3 [Bug 155]
+ * added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
+ draft-clancy-emu-eap-shared-secret-00.txt)
+ * added Microsoft Visual Studio 2005 solution and project files for
+ build wpa_supplicant for Windows (see vs2005 subdirectory)
+ * eloop_win: fixed unregistration of Windows events
+ * l2_packet_winpcap: fixed a deadlock in deinitializing l2_packet
+ at the end of RSN pre-authentication and added unregistration of
+ a Windows event to avoid getting eloop_win stuck with an invalid
+ handle
+ * driver_ndis: added support for selecting AP based on BSSID
+ * added new environmental variable for wpa_cli action scripts:
+ WPA_CTRL_DIR is the current control interface directory
+ * driver_ndis: added support for using NDISUIO instead of WinPcap for
+ OID set/query operations (CONFIG_USE_NDISUIO=y in .config); with new
+ l2_packet_ndis (CONFIG_L2_PACKET=ndis), this can be used to build
+ wpa_supplicant without requiring WinPcap; note that using NDISUIO
+ requires that WZC is disabled (net stop wzcsvc) since NDISUIO allows
+ only one application to open the device
+ * changed NDIS driver naming to only include device GUID, e.g.,
+ {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D}, instead of including WinPcap
+ specific \Device\NPF_ prefix before the GUID; the prefix is still
+ allowed for backwards compatibility, but it is not required anymore
+ when specifying the interface
+ * driver_ndis: re-initialize driver interface is the adapter is removed
+ and re-inserted [Bug 159]
+ * driver_madwifi: fixed TKIP and CCMP sequence number configuration on
+ big endian hosts [Bug 146]
+
+2006-04-27 - v0.5.3
+ * fixed EAP-GTC response to include correct user identity when run as
+ phase 2 method of EAP-FAST (i.e., EAP-FAST did not work in v0.5.2)
+ * driver_ndis: Fixed encryption mode configuration for unencrypted
+ networks (some NDIS drivers ignored this, but others, e.g., Broadcom,
+ refused to associate with open networks) [Bug 106]
+ * driver_ndis: use BSSID OID polling to detect when IBSS network is
+ formed even when ndis_events code is included since some NDIS drivers
+ do not generate media connect events in IBSS mode
+ * config_winreg: allow global ctrl_interface parameter to be configured
+ in Windows registry
+ * config_winreg: added support for saving configuration data into
+ Windows registry
+ * added support for controlling network device operational state
+ (dormant/up) for Linux 2.6.17 to improve DHCP processing (see
+ http://www.flamewarmaster.de/software/dhcpclient/ for a DHCP client
+ that can use this information)
+ * driver_wext: added support for WE-21 change to SSID configuration
+ * driver_wext: fixed privacy configuration for static WEP keys mode
+ [Bug 140]
+ * added an optional driver_ops callback for MLME-SETPROTECTION.request
+ primitive
+ * added support for EAP-SAKE (no EAP method number allocated yet, so
+ this is using the same experimental type 255 as EAP-PSK)
+ * added support for dynamically loading EAP methods (.so files) instead
+ of requiring them to be statically linked in; this is disabled by
+ default (see CONFIG_DYNAMIC_EAP_METHODS in defconfig for information
+ on how to use this)
+
+2006-03-19 - v0.5.2
+ * do not try to use USIM APDUs when initializing PC/SC for SIM card
+ access for a network that has not enabled EAP-AKA
+ * fixed EAP phase 2 Nak for EAP-{PEAP,TTLS,FAST} (this was broken in
+ v0.5.1 due to the new support for expanded EAP types)
+ * added support for generating EAP Expanded Nak
+ * try to fetch scan results once before requesting new scan when
+ starting up in ap_scan=1 mode (this can speed up initial association
+ a lot with, e.g., madwifi-ng driver)
+ * added support for receiving EAPOL frames from a Linux bridge
+ interface (-bbr0 on command line)
+ * fixed EAPOL re-authentication for sessions that used PMKSA caching
+ * changed EAP method registration to use a dynamic list of methods
+ instead of a static list generated at build time
+ * fixed PMKSA cache deinitialization not to use freed memory when
+ removing PMKSA entries
+ * fixed a memory leak in EAP-TTLS re-authentication
+ * reject WPA/WPA2 message 3/4 if it does not include any valid
+ WPA/RSN IE
+ * driver_wext: added fallback to use SIOCSIWENCODE for setting auth_alg
+ if the driver does not support SIOCSIWAUTH
+
+2006-01-29 - v0.5.1
+ * driver_test: added better support for multiple APs and STAs by using
+ a directory with sockets that include MAC address for each device in
+ the name (driver_param=test_dir=/tmp/test)
+ * added support for EAP expanded type (vendor specific EAP methods)
+ * added AP_SCAN command into ctrl_iface so that ap_scan configuration
+ option can be changed if needed
+ * wpa_cli/wpa_gui: skip non-socket files in control directory when
+ using UNIX domain sockets; this avoids selecting an incorrect
+ interface (e.g., a PID file could be in this directory, even though
+ use of this directory for something else than socket files is not
+ recommended)
+ * fixed TLS library deinitialization after RSN pre-authentication not
+ to disable TLS library for normal authentication
+ * driver_wext: Remove null-termination from SSID length if the driver
+ used it; some Linux drivers do this and they were causing problems in
+ wpa_supplicant not finding matching configuration block. This change
+ would break a case where the SSID actually ends in '\0', but that is
+ not likely to happen in real use.
+ * fixed PMKSA cache processing not to trigger deauthentication if the
+ current PMKSA cache entry is replaced with a valid new entry
+ * fixed PC/SC initialization for ap_scan != 1 modes (this fixes
+ EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or
+ ap_scan=2)
+
+2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
+ * added experimental STAKey handshake implementation for IEEE 802.11e
+ direct link setup (DLS); note: this is disabled by default in both
+ build and runtime configuration (can be enabled with CONFIG_STAKEY=y
+ and stakey=1)
+ * fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to
+ decrypt AT_ENCR_DATA attributes correctly
+ * fixed EAP-AKA to allow resynchronization within the same session
+ * made code closer to ANSI C89 standard to make it easier to port to
+ other C libraries and compilers
+ * started moving operating system or C library specific functions into
+ wrapper functions defined in os.h and implemented in os_*.c to make
+ code more portable
+ * wpa_supplicant can now be built with Microsoft Visual C++
+ (e.g., with the freely available Toolkit 2003 version or Visual
+ C++ 2005 Express Edition and Platform SDK); see nmake.mak for an
+ example makefile for nmake
+ * added support for using Windows registry for command line parameters
+ (CONFIG_MAIN=main_winsvc) and configuration data
+ (CONFIG_BACKEND=winreg); see win_example.reg for an example registry
+ contents; this version can be run both as a Windows service and as a
+ normal application; 'wpasvc.exe app' to start as applicant,
+ 'wpasvc.exe reg <full path to wpasvc.exe>' to register a service,
+ 'net start wpasvc' to start the service, 'wpasvc.exe unreg' to
+ unregister a service
+ * made it possible to link ndis_events.exe functionality into
+ wpa_supplicant.exe by defining CONFIG_NDIS_EVENTS_INTEGRATED
+ * added better support for multiple control interface backends
+ (CONFIG_CTRL_IFACE option); currently, 'unix' and 'udp' are supported
* fixed PC/SC code to use correct length for GSM AUTH command buffer
and to not use pioRecvPci with SCardTransmit() calls; these were not
causing visible problems with pcsc-lite, but Windows Winscard.dll
refused the previously used parameters; this fixes EAP-SIM and
EAP-AKA authentication using SIM/USIM card under Windows
+ * added new event loop implementation for Windows using
+ WaitForMultipleObject() instead of select() in order to allow waiting
+ for non-socket objects; this can be selected with
+ CONFIG_ELOOP=eloop_win in .config
+ * added support for selecting l2_packet implementation in .config
+ (CONFIG_L2_PACKET; following options are available now: linux, pcap,
+ winpcap, freebsd, none)
+ * added new l2_packet implementation for WinPcap
+ (CONFIG_L2_PACKET=winpcap) that uses a separate receive thread to
+ reduce latency in EAPOL receive processing from about 100 ms to about
+ 3 ms
* added support for EAP-FAST key derivation using other ciphers than
RC4-128-SHA for authentication and AES128-SHA for provisioning
- * fixed EAP-SIM and EAP-AKA pseudonym and fast re-authentication to
- decrypt AT_ENCR_DATA attributes correctly
* added support for configuring CA certificate as DER file and as a
configuration blob
* fixed private key configuration as configuration blob and added
support for using PKCS#12 as a blob
- * fixed cygwin build
+ * tls_gnutls: added support for using PKCS#12 files; added support for
+ session resumption
* added support for loading trusted CA certificates from Windows
certificate store: ca_cert="cert_store://<name>", where <name> is
likely CA (Intermediate CA certificates) or ROOT (root certificates)
- * fixed TLS library deinitialization after RSN pre-authentication not
- to disable TLS library for normal authentication
- * fixed PMKSA cache processing not to trigger deauthentication if the
- current PMKSA cache entry is replaced with a valid new entry
- * fixed PC/SC initialization for ap_scan != 1 modes (this fixes
- EAP-SIM and EAP-AKA with real SIM/USIM card when using ap_scan=0 or
- ap_scan=2)
- * do not try to use USIM APDUs when initializing PC/SC for SIM card
- access for a network that has not enabled EAP-AKA
+ * added C version of ndis_events.cpp and made it possible to build this
+ with MinGW so that CONFIG_NDIS_EVENTS_INTEGRATED can be used more
+ easily on cross-compilation builds
+ * added wpasvc.exe into Windows binary release; this is an alternative
+ version of wpa_supplicant.exe with configuration backend using
+ Windows registry and with the entry point designed to run as a
+ Windows service
+ * integrated ndis_events.exe functionality into wpa_supplicant.exe and
+ wpasvc.exe and removed this additional tool from the Windows binary
+ release since it is not needed anymore
+ * load winscard.dll functions dynamically when building with MinGW
+ since MinGW does not yet include winscard library
2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
* l2_packet_pcap: fixed wired IEEE 802.1X authentication with libpcap
diff --git a/contrib/wpa_supplicant/FREEBSD-Xlist b/contrib/wpa_supplicant/FREEBSD-Xlist
index d2f169790480..d9522be08a91 100644
--- a/contrib/wpa_supplicant/FREEBSD-Xlist
+++ b/contrib/wpa_supplicant/FREEBSD-Xlist
@@ -7,16 +7,27 @@ driver_bsd.c
driver_hostap.c
driver_ipw.c
driver_madwifi.c
-driver_ndis.c
-driver_ndis.h
-driver_ndis_.c
driver_ndiswrapper.c
+driver_ndis_.c
driver_prism54.c
driver_test.c
driver_wext.c
driver_wext.h
-l2_packet.c
+l2_packet_freebsd.c
+l2_packet_linux.c
+l2_packet_ndis.c
+l2_packet_none.c
+l2_packet_pcap.c
+l2_packet_winpcap.c
+main_none.c
+main_winmain.c
+main_winsvc.c
+ndis_events.c
ndis_events.cpp
+nmake.mk
+os_win32.c
priv_netlink.h
+vs2005
+win_example.reg
win_if_list.c
wireless_copy.h
diff --git a/contrib/wpa_supplicant/FREEBSD-upgrade b/contrib/wpa_supplicant/FREEBSD-upgrade
index f8ef0f001379..88a4b1848017 100644
--- a/contrib/wpa_supplicant/FREEBSD-upgrade
+++ b/contrib/wpa_supplicant/FREEBSD-upgrade
@@ -6,12 +6,12 @@ WPA Supplicant
For the import files and directories were pruned by:
- tar -X FREEBSD-Xlist -zxf wpa_supplicant-0.3.8.tar.gz
+ tar -X FREEBSD-Xlist -zxf wpa_supplicant-0.5.8.tar.gz
then imported by:
- cvs import -m 'Import of WPA supplicant 0.3.8' \
- src/contrib/wpa_supplicant MALINEN v0_3_8
+ cvs import -m 'Import of WPA supplicant 0.5.8' \
+ src/contrib/wpa_supplicant MALINEN v0_5_8
To make local changes to wpa_supplcaint, simply patch and commit
to the main branch (aka HEAD). Never make local changes on the
@@ -21,4 +21,4 @@ All local changes should be submitted to Jouni Malinen for inclusion in
the next vendor release.
sam@FreeBSD.org
-4-June-2005
+11-July-2007
diff --git a/contrib/wpa_supplicant/Makefile b/contrib/wpa_supplicant/Makefile
index d8fd3edda01c..f29eb693a7e3 100644
--- a/contrib/wpa_supplicant/Makefile
+++ b/contrib/wpa_supplicant/Makefile
@@ -11,7 +11,7 @@ CFLAGS += -I. -I../utils -I../hostapd
ALL=wpa_supplicant wpa_passphrase wpa_cli
-all: verify_config $(ALL)
+all: verify_config $(ALL) dynamic_eap_methods
verify_config:
@if [ ! -r .config ]; then \
@@ -36,13 +36,36 @@ install: all
for i in $(ALL); do cp $$i $(DESTDIR)/usr/local/sbin/$$i; done
OBJS = config.o \
- eloop.o common.o md5.o \
- rc4.o sha1.o
-OBJS_p = wpa_passphrase.o sha1.o md5.o
+ common.o md5.o md4.o \
+ rc4.o sha1.o des.o
+OBJS_p = wpa_passphrase.o sha1.o md5.o md4.o \
+ common.o des.o
OBJS_c = wpa_cli.o wpa_ctrl.o
-include .config
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+OBJS += os_$(CONFIG_OS).o
+OBJS_p += os_$(CONFIG_OS).o
+OBJS_c += os_$(CONFIG_OS).o
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += $(CONFIG_ELOOP).o
+
+
ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
@@ -56,6 +79,14 @@ OBJS += config_file.o base64.o
CFLAGS += -DCONFIG_BACKEND_FILE
endif
+ifeq ($(CONFIG_BACKEND), winreg)
+OBJS += config_winreg.o
+endif
+
+ifeq ($(CONFIG_BACKEND), none)
+OBJS += config_none.o
+endif
+
ifdef CONFIG_DRIVER_HOSTAP
CFLAGS += -DCONFIG_DRIVER_HOSTAP
OBJS_d += driver_hostap.o
@@ -111,15 +142,21 @@ endif
ifdef CONFIG_DRIVER_BSD
CFLAGS += -DCONFIG_DRIVER_BSD
OBJS_d += driver_bsd.o
-CONFIG_DNET_PCAP=y
-CONFIG_L2_FREEBSD=y
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
endif
ifdef CONFIG_DRIVER_NDIS
CFLAGS += -DCONFIG_DRIVER_NDIS
OBJS_d += driver_ndis.o driver_ndis_.o
-CONFIG_DNET_PCAP=y
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=pcap
+endif
CONFIG_WINPCAP=y
+ifdef CONFIG_USE_NDISUIO
+CFLAGS += -DCONFIG_USE_NDISUIO
+endif
endif
ifdef CONFIG_DRIVER_WIRED
@@ -132,116 +169,176 @@ CFLAGS += -DCONFIG_DRIVER_TEST
OBJS_d += driver_test.o
endif
-ifdef CONFIG_DNET_PCAP
-CFLAGS += -DUSE_DNET_PCAP
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=linux
+endif
+
+OBJS += l2_packet_$(CONFIG_L2_PACKET).o
+
+ifeq ($(CONFIG_L2_PACKET), pcap)
ifdef CONFIG_WINPCAP
-OBJS += l2_packet_pcap.o
CFLAGS += -DCONFIG_WINPCAP
LIBS += -lwpcap -lpacket
LIBS_w += -lwpcap
else
-ifdef CONFIG_L2_FREEBSD
-OBJS += l2_packet_freebsd.o
-LIBS += -lpcap
-else
-OBJS += l2_packet_pcap.o
LIBS += -ldnet -lpcap
endif
endif
-else
-OBJS += l2_packet_linux.o
+
+ifeq ($(CONFIG_L2_PACKET), winpcap)
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+endif
+
+ifeq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -lpcap
endif
ifdef CONFIG_EAP_TLS
# EAP-TLS
+ifeq ($(CONFIG_EAP_TLS), dyn)
+CFLAGS += -DEAP_TLS_DYNAMIC
+EAPDYN += eap_tls.so
+else
CFLAGS += -DEAP_TLS
OBJS += eap_tls.o
+endif
TLS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
endif
ifdef CONFIG_EAP_PEAP
# EAP-PEAP
+ifeq ($(CONFIG_EAP_PEAP), dyn)
+CFLAGS += -DEAP_PEAP_DYNAMIC
+EAPDYN += eap_peap.so
+else
CFLAGS += -DEAP_PEAP
OBJS += eap_peap.o
+endif
TLS_FUNCS=y
-CONFIG_EAP_MSCHAPV2=y
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_TLV=y
endif
ifdef CONFIG_EAP_TTLS
# EAP-TTLS
+ifeq ($(CONFIG_EAP_TTLS), dyn)
+CFLAGS += -DEAP_TTLS_DYNAMIC
+EAPDYN += eap_ttls.so
+else
CFLAGS += -DEAP_TTLS
OBJS += eap_ttls.o
+endif
MS_FUNCS=y
TLS_FUNCS=y
-CONFIG_EAP_MD5=y
CONFIG_IEEE8021X_EAPOL=y
endif
ifdef CONFIG_EAP_MD5
-# EAP-MD5 (also used by EAP-TTLS)
+# EAP-MD5
+ifeq ($(CONFIG_EAP_MD5), dyn)
+CFLAGS += -DEAP_MD5_DYNAMIC
+EAPDYN += eap_md5.so
+else
CFLAGS += -DEAP_MD5
OBJS += eap_md5.o
+endif
CONFIG_IEEE8021X_EAPOL=y
endif
# backwards compatibility for old spelling
ifdef CONFIG_MSCHAPV2
+ifndef CONFIG_EAP_MSCHAPV2
CONFIG_EAP_MSCHAPV2=y
endif
+endif
ifdef CONFIG_EAP_MSCHAPV2
-# EAP-MSCHAPv2 (also used by EAP-PEAP)
+# EAP-MSCHAPv2
+ifeq ($(CONFIG_EAP_MSCHAPV2), dyn)
+CFLAGS += -DEAP_MSCHAPv2_DYNAMIC
+EAPDYN += eap_mschapv2.so
+else
CFLAGS += -DEAP_MSCHAPv2
OBJS += eap_mschapv2.o
+endif
MS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
endif
ifdef CONFIG_EAP_GTC
-# EAP-GTC (also used by EAP-PEAP)
+# EAP-GTC
+ifeq ($(CONFIG_EAP_GTC), dyn)
+CFLAGS += -DEAP_GTC_DYNAMIC
+EAPDYN += eap_gtc.so
+else
CFLAGS += -DEAP_GTC
OBJS += eap_gtc.o
+endif
CONFIG_IEEE8021X_EAPOL=y
endif
ifdef CONFIG_EAP_OTP
# EAP-OTP
+ifeq ($(CONFIG_EAP_OTP), dyn)
+CFLAGS += -DEAP_OTP_DYNAMIC
+EAPDYN += eap_otp.so
+else
CFLAGS += -DEAP_OTP
OBJS += eap_otp.o
+endif
CONFIG_IEEE8021X_EAPOL=y
endif
ifdef CONFIG_EAP_SIM
# EAP-SIM
+ifeq ($(CONFIG_EAP_SIM), dyn)
+CFLAGS += -DEAP_SIM_DYNAMIC
+EAPDYN += eap_sim.so
+else
CFLAGS += -DEAP_SIM
OBJS += eap_sim.o
+endif
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_SIM_COMMON=y
endif
ifdef CONFIG_EAP_LEAP
# EAP-LEAP
+ifeq ($(CONFIG_EAP_LEAP), dyn)
+CFLAGS += -DEAP_LEAP_DYNAMIC
+EAPDYN += eap_leap.so
+else
CFLAGS += -DEAP_LEAP
OBJS += eap_leap.o
+endif
MS_FUNCS=y
CONFIG_IEEE8021X_EAPOL=y
endif
ifdef CONFIG_EAP_PSK
# EAP-PSK
+ifeq ($(CONFIG_EAP_PSK), dyn)
+CFLAGS += -DEAP_PSK_DYNAMIC
+EAPDYN += eap_psk.so
+else
CFLAGS += -DEAP_PSK
OBJS += eap_psk.o eap_psk_common.o
+endif
CONFIG_IEEE8021X_EAPOL=y
NEED_AES=y
endif
ifdef CONFIG_EAP_AKA
# EAP-AKA
+ifeq ($(CONFIG_EAP_AKA), dyn)
+CFLAGS += -DEAP_AKA_DYNAMIC
+EAPDYN += eap_aka.so
+else
CFLAGS += -DEAP_AKA
OBJS += eap_aka.o
+endif
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_SIM_COMMON=y
endif
@@ -259,22 +356,75 @@ endif
ifdef CONFIG_EAP_FAST
# EAP-FAST
+ifeq ($(CONFIG_EAP_FAST), dyn)
+CFLAGS += -DEAP_FAST_DYNAMIC
+EAPDYN += eap_fast.so
+else
CFLAGS += -DEAP_FAST
OBJS += eap_fast.o
+endif
TLS_FUNCS=y
endif
ifdef CONFIG_EAP_PAX
# EAP-PAX
+ifeq ($(CONFIG_EAP_PAX), dyn)
+CFLAGS += -DEAP_PAX_DYNAMIC
+EAPDYN += eap_pax.so
+else
CFLAGS += -DEAP_PAX
OBJS += eap_pax.o eap_pax_common.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+# EAP-SAKE
+ifeq ($(CONFIG_EAP_SAKE), dyn)
+CFLAGS += -DEAP_SAKE_DYNAMIC
+EAPDYN += eap_sake.so
+else
+CFLAGS += -DEAP_SAKE
+OBJS += eap_sake.o eap_sake_common.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GPSK
+# EAP-GPSK
+ifeq ($(CONFIG_EAP_GPSK), dyn)
+CFLAGS += -DEAP_GPSK_DYNAMIC
+EAPDYN += eap_gpsk.so
+else
+CFLAGS += -DEAP_GPSK
+OBJS += eap_gpsk.o eap_gpsk_common.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
+NEED_SHA256=y
+endif
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn)
+CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC
+EAPDYN += eap_vendor_test.so
+else
+CFLAGS += -DEAP_VENDOR_TEST
+OBJS += eap_vendor_test.o
+endif
CONFIG_IEEE8021X_EAPOL=y
endif
ifdef CONFIG_IEEE8021X_EAPOL
# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication)
CFLAGS += -DIEEE8021X_EAPOL
-OBJS += eapol_sm.o eap.o
+OBJS += eapol_sm.o eap.o eap_methods.o
+ifdef CONFIG_DYNAMIC_EAP_METHODS
+CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS
+LIBS += -ldl -rdynamic
+endif
endif
ifdef CONFIG_PCSC
@@ -282,18 +432,38 @@ ifdef CONFIG_PCSC
CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
OBJS += pcsc_funcs.o
# -lpthread may not be needed depending on how pcsc-lite was configured
+ifdef CONFIG_NATIVE_WINDOWS
+#Once MinGW gets support for WinScard, -lwinscard could be used instead of the
+#dynamic symbol loading that is now used in pcsc_funcs.c
+#LIBS += -lwinscard
+else
LIBS += -lpcsclite -lpthread
endif
+endif
ifndef CONFIG_TLS
CONFIG_TLS=openssl
endif
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+CFLAGS += -DCONFIG_INTERNAL_X509
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+CFLAGS += -DCONFIG_INTERNAL_X509
+endif
+
+
ifdef TLS_FUNCS
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
CFLAGS += -DEAP_TLS_FUNCS
OBJS += eap_tls_common.o
ifeq ($(CONFIG_TLS), openssl)
+CFLAGS += -DEAP_TLS_OPENSSL
OBJS += tls_openssl.o
LIBS += -lssl -lcrypto
LIBS_p += -lcrypto
@@ -302,16 +472,45 @@ ifeq ($(CONFIG_TLS), gnutls)
OBJS += tls_gnutls.o
LIBS += -lgnutls -lgcrypt -lgpg-error
LIBS_p += -lgcrypt
+ifdef CONFIG_GNUTLS_EXTRA
+CFLAGS += -DCONFIG_GNUTLS_EXTRA
+LIBS += -lgnutls-extra
+endif
endif
ifeq ($(CONFIG_TLS), schannel)
OBJS += tls_schannel.o
-# Using OpenSSL for crypto at the moment; to be replaced
-LIBS += -lcrypto
-LIBS_p += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), internal)
+OBJS += tls_internal.o tlsv1_common.o tlsv1_client.o asn1.o x509v3.o
+OBJS_p += asn1.o rc4.o aes_wrap.o
+ifneq ($(CONFIG_BACKEND), file)
+OBJS += base64.o
+endif
+CFLAGS += -DCONFIG_TLS_INTERNAL
+ifeq ($(CONFIG_CRYPTO), internal)
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+else
+LIBS += -ltommath
+LIBS_p += -ltommath
+endif
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+endif
+endif
+ifeq ($(CONFIG_TLS), none)
+OBJS += tls_none.o
+CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
endif
ifdef CONFIG_SMARTCARD
ifndef CONFIG_NATIVE_WINDOWS
-ifndef CONFIG_L2_FREEBSD
+ifneq ($(CONFIG_L2_PACKET), freebsd)
LIBS += -ldl
endif
endif
@@ -345,24 +544,85 @@ LIBS += -lgcrypt
LIBS_p += -lgcrypt
endif
ifeq ($(CONFIG_TLS), schannel)
-# Using OpenSSL for crypto at the moment; to be replaced
-LIBS += -lcrypto
-LIBS_p += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+endif
endif
endif
ifeq ($(CONFIG_TLS), openssl)
OBJS += crypto.o
OBJS_p += crypto.o
+CONFIG_INTERNAL_SHA256=y
endif
ifeq ($(CONFIG_TLS), gnutls)
OBJS += crypto_gnutls.o
OBJS_p += crypto_gnutls.o
+CONFIG_INTERNAL_SHA256=y
endif
ifeq ($(CONFIG_TLS), schannel)
-# Using OpenSSL for crypto at the moment; to be replaced
-OBJS += crypto.o
-OBJS_p += crypto.o
+OBJS += crypto_cryptoapi.o
+OBJS_p += crypto_cryptoapi.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += crypto_libtomcrypt.o
+OBJS_p += crypto_libtomcrypt.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += crypto_internal.o rsa.o bignum.o
+OBJS_p += crypto_internal.o rsa.o bignum.o
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += crypto_cryptoapi.o
+OBJS_p += crypto_cryptoapi.o
+CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+endif
+endif
+ifeq ($(CONFIG_TLS), none)
+OBJS += crypto_none.o
+OBJS_p += crypto_none.o
+CONFIG_INTERNAL_SHA256=y
+endif
+else
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+
+ifdef CONFIG_INTERNAL_AES
+CFLAGS += -DINTERNAL_AES
+endif
+ifdef CONFIG_INTERNAL_SHA1
+CFLAGS += -DINTERNAL_SHA1
+endif
+ifdef CONFIG_INTERNAL_SHA256
+CFLAGS += -DINTERNAL_SHA256
endif
+ifdef CONFIG_INTERNAL_MD5
+CFLAGS += -DINTERNAL_MD5
+endif
+ifdef CONFIG_INTERNAL_MD4
+CFLAGS += -DINTERNAL_MD4
+endif
+ifdef CONFIG_INTERNAL_DES
+CFLAGS += -DINTERNAL_DES
+endif
+
+ifdef NEED_SHA256
+OBJS += sha256.o
endif
ifdef CONFIG_WIRELESS_EXTENSION
@@ -371,8 +631,31 @@ OBJS_d += driver_wext.o
endif
ifdef CONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), y)
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_CTRL_IFACE=named_pipe
+else
+CONFIG_CTRL_IFACE=unix
+endif
+endif
CFLAGS += -DCONFIG_CTRL_IFACE
-OBJS += ctrl_iface.o
+ifeq ($(CONFIG_CTRL_IFACE), unix)
+CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+endif
+ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
+CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
+endif
+OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
+endif
+
+ifdef CONFIG_CTRL_IFACE_DBUS
+CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE
+OBJS += ctrl_iface_dbus.o ctrl_iface_dbus_handlers.o dbus_dict_helpers.o
+LIBS += `pkg-config --libs dbus-1`
+CFLAGS += `pkg-config --cflags dbus-1`
endif
ifdef CONFIG_READLINE
@@ -381,13 +664,20 @@ LIBS_c += -lncurses -lreadline
endif
ifdef CONFIG_NATIVE_WINDOWS
-CFLAGS += -DCONFIG_NATIVE_WINDOWS -DCONFIG_CTRL_IFACE_UDP
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
LIBS += -lws2_32 -lgdi32 -lcrypt32
LIBS_c += -lws2_32
+LIBS_p += -lws2_32
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+LIBS_p += -lcrypt32
+endif
endif
ifdef CONFIG_NO_STDOUT_DEBUG
CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+ifndef CONFIG_CTRL_IFACE
+CFLAGS += -DCONFIG_NO_WPA_MSG
+endif
endif
ifdef CONFIG_IPV6
@@ -395,53 +685,117 @@ ifdef CONFIG_IPV6
CFLAGS += -DCONFIG_IPV6
endif
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+endif
+
ifndef CONFIG_NO_WPA
-OBJS += wpa.o preauth.o
+OBJS += wpa.o preauth.o pmksa_cache.o
NEED_AES=y
else
-CFLAGS += -DCONFIG_NO_WPA
+CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+endif
+
+ifdef CONFIG_NO_WPA2
+CFLAGS += -DCONFIG_NO_WPA2
+endif
+
+ifdef CONFIG_NO_AES_EXTRAS
+CFLAGS += -DCONFIG_NO_AES_WRAP
+CFLAGS += -DCONFIG_NO_AES_CTR -DCONFIG_NO_AES_OMAC1
+CFLAGS += -DCONFIG_NO_AES_EAX -DCONFIG_NO_AES_CBC
endif
ifdef NEED_AES
OBJS += aes_wrap.o
endif
+ifdef CONFIG_CLIENT_MLME
+OBJS += mlme.o
+CFLAGS += -DCONFIG_CLIENT_MLME
+endif
+
+ifndef CONFIG_MAIN
+CONFIG_MAIN=main
+endif
+
OBJS += wpa_supplicant.o events.o
OBJS_t := $(OBJS) eapol_test.o radius.o radius_client.o
OBJS_t2 := $(OBJS) preauth_test.o
-OBJS += main.o drivers.o $(OBJS_d)
+OBJS += $(CONFIG_MAIN).o drivers.o $(OBJS_d)
+
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED
+OBJS += ndis_events.o
+EXTRALIBS += -loleaut32 -lole32 -luuid
+ifdef PLATFORMSDKLIB
+EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib
+else
+EXTRALIBS += WbemUuid.Lib
+endif
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+dynamic_eap_methods: $(EAPDYN)
wpa_supplicant: .config $(OBJS)
- $(CC) -o wpa_supplicant $(OBJS) $(LIBS)
+ $(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
eapol_test: .config $(OBJS_t)
- $(CC) -o eapol_test $(OBJS_t) $(LIBS)
+ $(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
preauth_test: .config $(OBJS_t2)
- $(CC) -o preauth_test $(OBJS_t2) $(LIBS)
+ $(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
wpa_passphrase: $(OBJS_p)
- $(CC) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+ $(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
wpa_cli: $(OBJS_c)
- $(CC) -o wpa_cli $(OBJS_c) $(LIBS_c)
+ $(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
+
+OBJSa=asn1_test.o asn1.o x509v3.o common.o os_unix.o \
+ crypto_$(CONFIG_CRYPTO).o md5.o sha1.o \
+ rc4.o des.o aes_wrap.o \
+ bignum.o rsa.o
+asn1_test: $(OBJSa)
+ $(LDO) $(LDFLAGS) -o asn1_test $(OBJSa)
+
+OBJSx=tests/test_x509v3.o asn1.o x509v3.o \
+ common.o os_unix.o \
+ crypto_$(CONFIG_CRYPTO).o \
+ md5.o sha1.o \
+ rc4.o des.o aes_wrap.o \
+ bignum.o rsa.o
+test_x509v3: $(OBJSx)
+ $(LDO) $(LDFLAGS) -o test_x509v3 $(OBJSx)
win_if_list: win_if_list.c
- $(CC) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
-
-# parameters for Microsoft Visual C++ Toolkit 2003 compiler
-CL=cl
-CLDIR=C:\Program Files\Microsoft Visual C++ Toolkit 2003
-PSDKDIR=C:\Program Files\Microsoft Platform SDK for Windows XP SP2
-CLFLAGS=-O
-CLLIBS=wbemuuid.lib libcmt.lib kernel32.lib uuid.lib ole32.lib oleaut32.lib \
- ws2_32.lib
-
-ndis_events: ndis_events.cpp
- INCLUDE="$(CLDIR)\include;$(PSDKDIR)\Include" \
- LIB="$(CLDIR)\lib;$(PSDKDIR)\Lib" \
- $(CL) $(CLFLAGS) -o ndis_events.exe ndis_events.cpp \
- /link -nodefaultlib $(CLLIBS)
+ $(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
+
+eap_psk.so: eap_psk.c eap_psk_common.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_psk_register=eap_peer_method_dynamic_init
+
+eap_pax.so: eap_pax.c eap_pax_common.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_pax_register=eap_peer_method_dynamic_init
+
+eap_sake.so: eap_sake.c eap_sake_common.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_sake_register=eap_peer_method_dynamic_init
+
+%.so: %.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
+ -D$(*:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
+
wpa_supplicant.exe: wpa_supplicant
mv -f $< $@
@@ -465,39 +819,55 @@ wpa_gui/Makefile:
wpa_gui: wpa_gui/Makefile
$(MAKE) -C wpa_gui
-TEST_SRC_MS_FUNCS = ms_funcs.c crypto.c sha1.c md5.c
-test-ms_funcs: $(TEST_SRC_MS_FUNCS)
- $(CC) -o test-ms_funcs -Wall -Werror $(TEST_SRC_MS_FUNCS) \
- -DTEST_MAIN_MS_FUNCS -lcrypto -I../hostapd -I.
+TEST_MS_FUNCS_OBJS = crypto.o sha1.o md5.o \
+ os_unix.o rc4.o tests/test_ms_funcs.o
+test-ms_funcs: $(TEST_MS_FUNCS_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_MS_FUNCS_OBJS) $(LIBS) -lcrypto
./test-ms_funcs
rm test-ms_funcs
-TEST_SRC_SHA1 = sha1.c
-test-sha1: $(TEST_SRC_SHA1)
- $(CC) -o test-sha1 -Wall -Werror $(TEST_SRC_SHA1) \
- -DTEST_MAIN -I../hostad -I.
+TEST_SHA1_OBJS = sha1.o md5.o tests/test_sha1.o #crypto.o
+test-sha1: $(TEST_SHA1_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_SHA1_OBJS) $(LIBS)
./test-sha1
rm test-sha1
-TEST_SRC_AES_WRAP = aes_wrap.c
-test-aes_wrap: $(TEST_SRC_AES_WRAP)
- $(CC) -o test-aes_wrap -Wall -Werror $(TEST_SRC_AES_WRAP) \
- -DTEST_MAIN -I../hostad -I.
- ./test-aes_wrap
- rm test-aes_wrap
-
-TEST_SRC_EAP_SIM_COMMON = eap_sim_common.c sha1.c md5.c \
- aes_wrap.c common.c
-test-eap_sim_common: $(TEST_SRC_EAP_SIM_COMMON)
- $(CC) -o test-eap_sim_common -Wall -Werror $(TEST_SRC_EAP_SIM_COMMON) \
- -DTEST_MAIN_EAP_SIM_COMMON -I../hostapd -I.
+TEST_SHA256_OBJS = sha256.o md5.o tests/test_sha256.o crypto.o
+test-sha256: $(TEST_SHA256_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_SHA256_OBJS) $(LIBS)
+ ./test-sha256
+ rm test-sha256
+
+TEST_AES_OBJS = aes_wrap.o tests/test_aes.o # crypto.o
+test-aes: $(TEST_AES_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_AES_OBJS) $(LIBS)
+ ./test-aes
+ rm test-aes
+
+TEST_EAP_SIM_COMMON_OBJS = sha1.o md5.o \
+ aes_wrap.o common.o os_unix.o \
+ tests/test_eap_sim_common.o
+test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_AES_OBJS) $(LIBS)
./test-eap_sim_common
rm test-eap_sim_common
-tests: test-ms_funcs test-sha1 test-aes_wrap test-eap_sim_common
+TEST_MD4_OBJS = md4.o tests/test_md4.o #crypto.o
+test-md4: $(TEST_MD4_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_MD4_OBJS) $(LIBS)
+ ./test-md4
+ rm test-md4
+
+TEST_MD5_OBJS = md5.o tests/test_md5.o #crypto.o
+test-md5: $(TEST_MD5_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_MD5_OBJS) $(LIBS)
+ ./test-md5
+ rm test-md5
+
+tests: test-ms_funcs test-sha1 test-aes test-eap_sim_common test-md4 test-md5
clean:
- rm -f core *~ *.o *.d $(ALL) $(WINALL)
+ rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL)
%.eps: %.fig
fig2dev -L eps $*.fig $*.eps
diff --git a/contrib/wpa_supplicant/README b/contrib/wpa_supplicant/README
index 831756b12c25..be0757420efd 100644
--- a/contrib/wpa_supplicant/README
+++ b/contrib/wpa_supplicant/README
@@ -1,8 +1,7 @@
WPA Supplicant
==============
-Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi> and
-contributors
+Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is dual-licensed under both the GPL version 2 and BSD
@@ -26,13 +25,13 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(this copy of the license is in COPYING file)
-Alternatively, this software may be distributed under the terms of BSD
-license:
+Alternatively, this software may be distributed, used, and modified
+under the terms of BSD license:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -90,6 +89,8 @@ Supported WPA/IEEE 802.11i features:
* EAP-AKA
* EAP-PSK
* EAP-PAX
+ * EAP-SAKE
+ * EAP-GPSK
* LEAP (note: requires special support from the driver for IEEE 802.11
authentication)
(following methods are supported, but since they do not generate keying
@@ -103,6 +104,20 @@ Supported WPA/IEEE 802.11i features:
* pre-authentication
* PMKSA caching
+Supported TLS/crypto libraries:
+- OpenSSL (default)
+- GnuTLS
+
+Internal TLS/crypto implementation (optional):
+- can be used in place of an external TLS/crypto library
+- TLSv1
+- X.509 certificate processing
+- PKCS #1
+- ASN.1
+- RSA
+- bignum
+- minimal size (ca. 50 kB binary, parts of which are already needed for WPA;
+ TLSv1/X.509/ASN.1/RSA/bignum parts are about 25 kB on x86)
Requirements
@@ -114,6 +129,14 @@ Current hardware/software requirements:
- NetBSD-current
- Microsoft Windows with WinPcap (at least WinXP, may work with other versions)
- drivers:
+ Linux drivers that support WPA/WPA2 configuration with the generic
+ Linux wireless extensions (WE-18 or newer). Even though there are
+ number of driver specific interface included in wpa_supplicant, please
+ note that Linux drivers are moving to use generic wireless extensions
+ and driver_wext (-Dwext on wpa_supplicant command line) should be the
+ default option to start with before falling back to driver specific
+ interface.
+
Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)
(http://hostap.epitest.fi/)
Driver need to be set in Managed mode ('iwconfig wlan0 mode managed').
@@ -191,18 +214,27 @@ Optional libraries for layer2 packet processing:
These libraries are _not_ used in the default Linux build. Instead,
internal Linux specific implementation is used. libpcap/libdnet are
-more portable and they can be used by adding CONFIG_DNET_PCAP=y into
+more portable and they can be used by adding CONFIG_L2_PACKET=pcap into
.config. They may also be selected automatically for other operating
-systems.
+systems. In case of Windows builds, WinPcap is used by default
+(CONFIG_L2_PACKET=winpcap).
Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS:
-- openssl (tested with 0.9.7c and 0.9.7d, assumed to work with most
- relatively recent versions; this is likely to be available with most
- distributions, http://www.openssl.org/)
-
-This library is only needed when EAP-TLS, EAP-PEAP, or EAP-TTLS
-support is enabled. WPA-PSK mode does not require this or EAPOL/EAP
+- OpenSSL (tested with 0.9.7c and 0.9.7d, and 0.9.8 versions; assumed to
+ work with most relatively recent versions; this is likely to be
+ available with most distributions, http://www.openssl.org/)
+- GnuTLS
+- internal TLSv1 implementation
+
+TLS options for EAP-FAST:
+- OpenSSL 0.9.8d _with_ openssl-0.9.8d-tls-extensions.patch applied
+ (i.e., the default OpenSSL package does not include support for
+ extensions needed for EAP-FAST)
+- internal TLSv1 implementation
+
+One of these libraries is needed when EAP-TLS, EAP-PEAP, EAP-TTLS, or
+EAP-FAST support is enabled. WPA-PSK mode does not require this or EAPOL/EAP
implementation. A configuration file, .config, for compilation is
needed to enable IEEE 802.1X/EAPOL and EAP methods. Note that EAP-MD5,
EAP-GTC, EAP-OTP, and EAP-MSCHAPV2 cannot be used alone with WPA, so
@@ -321,8 +353,8 @@ select which parts of it will be included. This is done by creating a
build time configuration file, .config, in the wpa_supplicant root
directory. Configuration options are text lines using following
format: CONFIG_<option>=y. Lines starting with # are considered
-comments and are ignored. See defconfig file for example configuration
-and list of available option.
+comments and are ignored. See defconfig file for an example configuration
+and a list of available options and additional notes.
The build time configuration can be used to select only the needed
features and limit the binary size and requirements for external
@@ -332,8 +364,9 @@ methods (e.g., EAP-TLS, EAP-PEAP, ..) are included.
Following build time configuration options are used to control IEEE
802.1X/EAPOL and EAP state machines and all EAP methods. Including
-TLS, PEAP, or TTLS will require linking wpa_supplicant with openssl
-library for TLS implementation.
+TLS, PEAP, or TTLS will require linking wpa_supplicant with OpenSSL
+library for TLS implementation. Alternatively, GnuTLS or the internal
+TLSv1 implementation can be used for TLS functionaly.
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_MD5=y
@@ -346,6 +379,8 @@ CONFIG_EAP_OTP=y
CONFIG_EAP_SIM=y
CONFIG_EAP_AKA=y
CONFIG_EAP_PSK=y
+CONFIG_EAP_SAKE=y
+CONFIG_EAP_GPSK=y
CONFIG_EAP_PAX=y
CONFIG_EAP_LEAP=y
@@ -355,11 +390,6 @@ authentication algorithm (for EAP-SIM/EAP-AKA). This requires pcsc-lite
CONFIG_PCSC=y
-Following option can be used to replace the native Linux packet socket
-interface with libpcap/libdnet.
-
-CONFIG_DNET_PCAP=y
-
Following options can be added to .config to select which driver
interfaces are included. Hermes driver interface needs to be downloaded
from Agere (see above). CONFIG_WIRELESS_EXTENSION will be used
@@ -402,6 +432,8 @@ CONFIG_EAP_OTP=y
CONFIG_EAP_SIM=y
CONFIG_EAP_AKA=y
CONFIG_EAP_PSK=y
+CONFIG_EAP_SAKE=y
+CONFIG_EAP_GPSK=y
CONFIG_EAP_PAX=y
CONFIG_EAP_LEAP=y
CONFIG_PCSC=y
@@ -449,19 +481,30 @@ Command line options
--------------------
usage:
- wpa_supplicant [-BddehLqqvw] -i<ifname> -c<config file> [-D<driver>] \
- [-N -i<ifname> -c<conf> [-D<driver>] ...]
+ wpa_supplicant [-BddehLqqvwW] [-P<pid file>] [-g<global ctrl>] \
+ -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] [-p<driver_param>] \
+ [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] \
+ [-p<driver_param>] [-b<br_ifname>] ...]
options:
+ -b = optional bridge interface name
-B = run daemon in the background
+ -c = Configuration file
+ -C = ctrl_interface parameter (only used if -c is not)
+ -i = interface name
-d = increase debugging verbosity (-dd even more)
+ -D = driver name
+ -g = global ctrl_interface
-K = include keys (passwords, etc.) in debug output
-t = include timestamp in debug messages
-h = show this help text
-L = show license (GPL and BSD)
+ -p = driver parameters
+ -P = PID file
-q = decrease debugging verbosity (-qq even less)
-v = show version
-w = wait for interface to be added, if needed
+ -W = wait for a control interface monitor before starting
-N = start describing new interface
drivers:
@@ -473,7 +516,7 @@ drivers:
wext = Linux wireless extensions (generic)
ndiswrapper = Linux ndiswrapper
broadcom = Broadcom wl.o driver
- ipw = Intel ipw2100/2200 driver
+ ipw = Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 or newer)
wired = wpa_supplicant wired Ethernet driver
bsd = BSD 802.11 support (Atheros, etc.)
ndis = Windows NDIS driver
@@ -503,6 +546,13 @@ wpa_supplicant \
-c wpa2.conf -i ath0 -D madwifi
+If the interface is added in a Linux bridge (e.g., br0), the bridge
+interface needs to be configured to wpa_supplicant in addition to the
+main interface:
+
+wpa_supplicant -cw.conf -Dmadwifi -iath0 -bbr0
+
+
Configuration file
------------------
@@ -518,7 +568,7 @@ reloading can be triggered with 'wpa_cli reconfigure' command.
Configuration file can include one or more network blocks, e.g., one
for each used SSID. wpa_supplicant will automatically select the best
betwork based on the order of network blocks in the configuration
-file, network security level (WPA/WPA2 is prefered), and signal
+file, network security level (WPA/WPA2 is preferred), and signal
strength.
Example configuration files for some common configurations:
diff --git a/contrib/wpa_supplicant/aes.c b/contrib/wpa_supplicant/aes.c
index ce94778dd62e..1a2459b3e013 100644
--- a/contrib/wpa_supplicant/aes.c
+++ b/contrib/wpa_supplicant/aes.c
@@ -9,7 +9,7 @@
* cost of reduced throughput (quite small difference on Pentium 4,
* 10-25% when using -O1 or -O2 optimization)
*
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -21,6 +21,8 @@
* See README and COPYING for more details.
*/
+#include "includes.h"
+
/*
* rijndael-alg-fst.c
*
@@ -1060,7 +1062,7 @@ void * aes_encrypt_init(const u8 *key, size_t len)
u32 *rk;
if (len != 16)
return NULL;
- rk = malloc(4 * 44);
+ rk = os_malloc(4 * 44);
if (rk == NULL)
return NULL;
rijndaelKeySetupEnc(rk, key);
@@ -1076,7 +1078,7 @@ void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
void aes_encrypt_deinit(void *ctx)
{
- free(ctx);
+ os_free(ctx);
}
@@ -1085,7 +1087,7 @@ void * aes_decrypt_init(const u8 *key, size_t len)
u32 *rk;
if (len != 16)
return NULL;
- rk = malloc(4 * 44);
+ rk = os_malloc(4 * 44);
if (rk == NULL)
return NULL;
rijndaelKeySetupDec(rk, key);
@@ -1101,5 +1103,5 @@ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
void aes_decrypt_deinit(void *ctx)
{
- free(ctx);
+ os_free(ctx);
}
diff --git a/contrib/wpa_supplicant/aes.h b/contrib/wpa_supplicant/aes.h
new file mode 100644
index 000000000000..6b9f4147afb1
--- /dev/null
+++ b/contrib/wpa_supplicant/aes.h
@@ -0,0 +1,25 @@
+/*
+ * AES functions
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+void * aes_encrypt_init(const u8 *key, size_t len);
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+void aes_encrypt_deinit(void *ctx);
+void * aes_decrypt_init(const u8 *key, size_t len);
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+void aes_decrypt_deinit(void *ctx);
+
+#endif /* AES_H */
diff --git a/contrib/wpa_supplicant/aes_wrap.c b/contrib/wpa_supplicant/aes_wrap.c
index a5925ca2ec47..c52e45af27c5 100644
--- a/contrib/wpa_supplicant/aes_wrap.c
+++ b/contrib/wpa_supplicant/aes_wrap.c
@@ -7,7 +7,7 @@
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,17 +19,18 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
+
#include "common.h"
#include "aes_wrap.h"
#include "crypto.h"
-#ifndef EAP_TLS_FUNCS
+#ifdef INTERNAL_AES
#include "aes.c"
-#endif /* EAP_TLS_FUNCS */
+#endif /* INTERNAL_AES */
+
+#ifndef CONFIG_NO_AES_WRAP
/**
* aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
@@ -49,8 +50,8 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
r = cipher + 8;
/* 1) Initialize variables. */
- memset(a, 0xa6, 8);
- memcpy(r, plain, 8 * n);
+ os_memset(a, 0xa6, 8);
+ os_memcpy(r, plain, 8 * n);
ctx = aes_encrypt_init(kek, 16);
if (ctx == NULL)
@@ -66,12 +67,12 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
for (j = 0; j <= 5; j++) {
r = cipher + 8;
for (i = 1; i <= n; i++) {
- memcpy(b, a, 8);
- memcpy(b + 8, r, 8);
+ os_memcpy(b, a, 8);
+ os_memcpy(b + 8, r, 8);
aes_encrypt(ctx, b, b);
- memcpy(a, b, 8);
+ os_memcpy(a, b, 8);
a[7] ^= n * j + i;
- memcpy(r, b + 8, 8);
+ os_memcpy(r, b + 8, 8);
r += 8;
}
}
@@ -86,6 +87,8 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
return 0;
}
+#endif /* CONFIG_NO_AES_WRAP */
+
/**
* aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
@@ -102,9 +105,9 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
void *ctx;
/* 1) Initialize variables. */
- memcpy(a, cipher, 8);
+ os_memcpy(a, cipher, 8);
r = plain;
- memcpy(r, cipher + 8, 8 * n);
+ os_memcpy(r, cipher + 8, 8 * n);
ctx = aes_decrypt_init(kek, 16);
if (ctx == NULL)
@@ -120,13 +123,13 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
for (j = 5; j >= 0; j--) {
r = plain + (n - 1) * 8;
for (i = n; i >= 1; i--) {
- memcpy(b, a, 8);
+ os_memcpy(b, a, 8);
b[7] ^= n * j + i;
- memcpy(b + 8, r, 8);
+ os_memcpy(b + 8, r, 8);
aes_decrypt(ctx, b, b);
- memcpy(a, b, 8);
- memcpy(r, b + 8, 8);
+ os_memcpy(a, b, 8);
+ os_memcpy(r, b + 8, 8);
r -= 8;
}
}
@@ -148,6 +151,8 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
#define BLOCK_SIZE 16
+#ifndef CONFIG_NO_AES_OMAC1
+
static void gf_mulx(u8 *pad)
{
int i, carry;
@@ -162,8 +167,8 @@ static void gf_mulx(u8 *pad)
/**
- * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128
- * @key: Key for the hash operation
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * @key: 128-bit key for the hash operation
* @data: Data buffer for which a MAC is determined
* @data: Length of data buffer in bytes
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
@@ -174,13 +179,12 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
void *ctx;
u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
const u8 *pos = data;
- int i;
- size_t left = data_len;
+ size_t i, left = data_len;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
- memset(cbc, 0, BLOCK_SIZE);
+ os_memset(cbc, 0, BLOCK_SIZE);
while (left >= BLOCK_SIZE) {
for (i = 0; i < BLOCK_SIZE; i++)
@@ -190,7 +194,7 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
left -= BLOCK_SIZE;
}
- memset(pad, 0, BLOCK_SIZE);
+ os_memset(pad, 0, BLOCK_SIZE);
aes_encrypt(ctx, pad, pad);
gf_mulx(pad);
@@ -208,6 +212,8 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
return 0;
}
+#endif /* CONFIG_NO_AES_OMAC1 */
+
/**
* aes_128_encrypt_block - Perform one AES 128-bit block operation
@@ -228,6 +234,8 @@ int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
}
+#ifndef CONFIG_NO_AES_CTR
+
/**
* aes_128_ctr_encrypt - AES-128 CTR mode encryption
* @key: Key for encryption (16 bytes)
@@ -240,7 +248,7 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len)
{
void *ctx;
- size_t len, left = data_len;
+ size_t j, len, left = data_len;
int i;
u8 *pos = data;
u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE];
@@ -248,14 +256,14 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
- memcpy(counter, nonce, BLOCK_SIZE);
+ os_memcpy(counter, nonce, BLOCK_SIZE);
while (left > 0) {
aes_encrypt(ctx, counter, buf);
len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE;
- for (i = 0; i < len; i++)
- pos[i] ^= buf[i];
+ for (j = 0; j < len; j++)
+ pos[j] ^= buf[j];
pos += len;
left -= len;
@@ -269,6 +277,10 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
return 0;
}
+#endif /* CONFIG_NO_AES_CTR */
+
+
+#ifndef CONFIG_NO_AES_EAX
/**
* aes_128_eax_encrypt - AES-128 EAX mode encryption
@@ -299,26 +311,26 @@ int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
buf_len = hdr_len;
buf_len += 16;
- buf = malloc(buf_len);
+ buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
- memset(buf, 0, 15);
+ os_memset(buf, 0, 15);
buf[15] = 0;
- memcpy(buf + 16, nonce, nonce_len);
+ os_memcpy(buf + 16, nonce, nonce_len);
omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
buf[15] = 1;
- memcpy(buf + 16, hdr, hdr_len);
+ os_memcpy(buf + 16, hdr, hdr_len);
omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
buf[15] = 2;
- memcpy(buf + 16, data, data_len);
+ os_memcpy(buf + 16, data, data_len);
omac1_aes_128(key, buf, 16 + data_len, data_mac);
- free(buf);
+ os_free(buf);
for (i = 0; i < BLOCK_SIZE; i++)
tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
@@ -356,25 +368,25 @@ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
buf_len = hdr_len;
buf_len += 16;
- buf = malloc(buf_len);
+ buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
- memset(buf, 0, 15);
+ os_memset(buf, 0, 15);
buf[15] = 0;
- memcpy(buf + 16, nonce, nonce_len);
+ os_memcpy(buf + 16, nonce, nonce_len);
omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
buf[15] = 1;
- memcpy(buf + 16, hdr, hdr_len);
+ os_memcpy(buf + 16, hdr, hdr_len);
omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
buf[15] = 2;
- memcpy(buf + 16, data, data_len);
+ os_memcpy(buf + 16, data, data_len);
omac1_aes_128(key, buf, 16 + data_len, data_mac);
- free(buf);
+ os_free(buf);
for (i = 0; i < BLOCK_SIZE; i++) {
if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
@@ -386,6 +398,10 @@ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
return 0;
}
+#endif /* CONFIG_NO_AES_EAX */
+
+
+#ifndef CONFIG_NO_AES_CBC
/**
* aes_128_cbc_encrypt - AES-128 CBC encryption
@@ -405,14 +421,14 @@ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
- memcpy(cbc, iv, BLOCK_SIZE);
+ os_memcpy(cbc, iv, BLOCK_SIZE);
blocks = data_len / BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
for (j = 0; j < BLOCK_SIZE; j++)
cbc[j] ^= pos[j];
aes_encrypt(ctx, cbc, cbc);
- memcpy(pos, cbc, BLOCK_SIZE);
+ os_memcpy(pos, cbc, BLOCK_SIZE);
pos += BLOCK_SIZE;
}
aes_encrypt_deinit(ctx);
@@ -438,288 +454,19 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
ctx = aes_decrypt_init(key, 16);
if (ctx == NULL)
return -1;
- memcpy(cbc, iv, BLOCK_SIZE);
+ os_memcpy(cbc, iv, BLOCK_SIZE);
blocks = data_len / BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
- memcpy(tmp, pos, BLOCK_SIZE);
+ os_memcpy(tmp, pos, BLOCK_SIZE);
aes_decrypt(ctx, pos, pos);
for (j = 0; j < BLOCK_SIZE; j++)
pos[j] ^= cbc[j];
- memcpy(cbc, tmp, BLOCK_SIZE);
+ os_memcpy(cbc, tmp, BLOCK_SIZE);
pos += BLOCK_SIZE;
}
aes_decrypt_deinit(ctx);
return 0;
}
-
-#ifdef TEST_MAIN
-
-#ifdef __i386__
-#define rdtscll(val) \
- __asm__ __volatile__("rdtsc" : "=A" (val))
-
-static void test_aes_perf(void)
-{
- const int num_iters = 10;
- int i;
- unsigned int start, end;
- u8 key[16], pt[16], ct[16];
- void *ctx;
-
- printf("keySetupEnc:");
- for (i = 0; i < num_iters; i++) {
- rdtscll(start);
- ctx = aes_encrypt_init(key, 16);
- rdtscll(end);
- aes_encrypt_deinit(ctx);
- printf(" %d", end - start);
- }
- printf("\n");
-
- printf("Encrypt:");
- ctx = aes_encrypt_init(key, 16);
- for (i = 0; i < num_iters; i++) {
- rdtscll(start);
- aes_encrypt(ctx, pt, ct);
- rdtscll(end);
- printf(" %d", end - start);
- }
- aes_encrypt_deinit(ctx);
- printf("\n");
-}
-#endif /* __i386__ */
-
-
-static int test_eax(void)
-{
- u8 msg[] = { 0xF7, 0xFB };
- u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
- 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
- u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
- 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
- u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
- u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
- 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
- 0x67, 0xE5 };
- u8 data[sizeof(msg)], tag[BLOCK_SIZE];
-
- memcpy(data, msg, sizeof(msg));
- if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
- data, sizeof(data), tag)) {
- printf("AES-128 EAX mode encryption failed\n");
- return 1;
- }
- if (memcmp(data, cipher, sizeof(data)) != 0) {
- printf("AES-128 EAX mode encryption returned invalid cipher "
- "text\n");
- return 1;
- }
- if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) {
- printf("AES-128 EAX mode encryption returned invalid tag\n");
- return 1;
- }
-
- if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
- data, sizeof(data), tag)) {
- printf("AES-128 EAX mode decryption failed\n");
- return 1;
- }
- if (memcmp(data, msg, sizeof(data)) != 0) {
- printf("AES-128 EAX mode decryption returned invalid plain "
- "text\n");
- return 1;
- }
-
- return 0;
-}
-
-
-static int test_cbc(void)
-{
- struct cbc_test_vector {
- u8 key[16];
- u8 iv[16];
- u8 plain[32];
- u8 cipher[32];
- size_t len;
- } vectors[] = {
- {
- { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
- 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
- { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
- 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
- "Single block msg",
- { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
- 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
- 16
- },
- {
- { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
- 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
- { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
- 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
- { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
- { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
- 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
- 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
- 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
- 32
- }
- };
- int i, ret = 0;
- u8 *buf;
-
- for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) {
- struct cbc_test_vector *tv = &vectors[i];
- buf = malloc(tv->len);
- if (buf == NULL) {
- ret++;
- break;
- }
- memcpy(buf, tv->plain, tv->len);
- aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len);
- if (memcmp(buf, tv->cipher, tv->len) != 0) {
- printf("AES-CBC encrypt %d failed\n", i);
- ret++;
- }
- memcpy(buf, tv->cipher, tv->len);
- aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len);
- if (memcmp(buf, tv->plain, tv->len) != 0) {
- printf("AES-CBC decrypt %d failed\n", i);
- ret++;
- }
- free(buf);
- }
-
- return ret;
-}
-
-
-/* OMAC1 AES-128 test vectors from
- * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
- */
-
-struct omac1_test_vector {
- u8 k[16];
- u8 msg[64];
- int msg_len;
- u8 tag[16];
-};
-
-static struct omac1_test_vector test_vectors[] =
-{
- {
- { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
- 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
- { },
- 0,
- { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
- 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
- },
- {
- { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
- 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
- { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
- 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
- 16,
- { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
- 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
- },
- {
- { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
- 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
- { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
- 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
- 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
- 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
- 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
- 40,
- { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
- 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
- },
- {
- { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
- 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
- { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
- 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
- 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
- 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
- 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
- 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
- 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
- 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
- 64,
- { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
- 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
- },
-};
-
-
-int main(int argc, char *argv[])
-{
- u8 kek[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
- };
- u8 plain[] = {
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
- };
- u8 crypt[] = {
- 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
- 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
- 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
- };
- u8 result[24];
- int ret = 0, i;
- struct omac1_test_vector *tv;
-
- if (aes_wrap(kek, 2, plain, result)) {
- printf("AES-WRAP-128-128 reported failure\n");
- ret++;
- }
- if (memcmp(result, crypt, 24) != 0) {
- printf("AES-WRAP-128-128 failed\n");
- ret++;
- }
- if (aes_unwrap(kek, 2, crypt, result)) {
- printf("AES-UNWRAP-128-128 reported failure\n");
- ret++;
- }
- if (memcmp(result, plain, 16) != 0) {
- int i;
- printf("AES-UNWRAP-128-128 failed\n");
- ret++;
- for (i = 0; i < 16; i++)
- printf(" %02x", result[i]);
- printf("\n");
- }
-
-#ifdef __i386__
- test_aes_perf();
-#endif /* __i386__ */
-
- for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {
- tv = &test_vectors[i];
- omac1_aes_128(tv->k, tv->msg, tv->msg_len, result);
- if (memcmp(result, tv->tag, 16) != 0) {
- printf("OMAC1-AES-128 test vector %d failed\n", i);
- ret++;
- }
- }
-
- ret += test_eax();
-
- ret += test_cbc();
-
- if (ret)
- printf("FAILED!\n");
-
- return ret;
-}
-#endif /* TEST_MAIN */
+#endif /* CONFIG_NO_AES_CBC */
diff --git a/contrib/wpa_supplicant/aes_wrap.h b/contrib/wpa_supplicant/aes_wrap.h
index cb1a53967761..1bc6971eff8e 100644
--- a/contrib/wpa_supplicant/aes_wrap.h
+++ b/contrib/wpa_supplicant/aes_wrap.h
@@ -7,7 +7,7 @@
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/contrib/wpa_supplicant/asn1.c b/contrib/wpa_supplicant/asn1.c
new file mode 100644
index 000000000000..ff3db7dc73c0
--- /dev/null
+++ b/contrib/wpa_supplicant/asn1.c
@@ -0,0 +1,205 @@
+/*
+ * ASN.1 DER parsing
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+
+#ifdef CONFIG_INTERNAL_X509
+
+#include "asn1.h"
+
+int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
+{
+ const u8 *pos, *end;
+ u8 tmp;
+
+ os_memset(hdr, 0, sizeof(*hdr));
+ pos = buf;
+ end = buf + len;
+
+ hdr->identifier = *pos++;
+ hdr->class = hdr->identifier >> 6;
+ hdr->constructed = !!(hdr->identifier & (1 << 5));
+
+ if ((hdr->identifier & 0x1f) == 0x1f) {
+ hdr->tag = 0;
+ do {
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
+ "underflow");
+ return -1;
+ }
+ tmp = *pos++;
+ wpa_printf(MSG_MSGDUMP, "ASN.1: Extended tag data: "
+ "0x%02x", tmp);
+ hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
+ } while (tmp & 0x80);
+ } else
+ hdr->tag = hdr->identifier & 0x1f;
+
+ tmp = *pos++;
+ if (tmp & 0x80) {
+ if (tmp == 0xff) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
+ "value 0xff used");
+ return -1;
+ }
+ tmp &= 0x7f; /* number of subsequent octets */
+ hdr->length = 0;
+ while (tmp--) {
+ if (pos >= end) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Length "
+ "underflow");
+ return -1;
+ }
+ hdr->length = (hdr->length << 8) | *pos++;
+ }
+ } else {
+ /* Short form - length 0..127 in one octet */
+ hdr->length = tmp;
+ }
+
+ if (pos + hdr->length > end) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
+ return -1;
+ }
+
+ hdr->payload = pos;
+ return 0;
+}
+
+
+int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
+ const u8 **next)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ unsigned long val;
+ u8 tmp;
+
+ os_memset(oid, 0, sizeof(*oid));
+
+ if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
+ return -1;
+
+ if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
+ "tag 0x%x", hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = hdr.payload + hdr.length;
+ *next = end;
+
+ while (pos < end) {
+ val = 0;
+
+ do {
+ if (pos >= end)
+ return -1;
+ tmp = *pos++;
+ val = (val << 7) | (tmp & 0x7f);
+ } while (tmp & 0x80);
+
+ if (oid->len >= ASN1_MAX_OID_LEN) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
+ return -1;
+ }
+ if (oid->len == 0) {
+ /*
+ * The first octet encodes the first two object
+ * identifier components in (X*40) + Y formula.
+ * X = 0..2.
+ */
+ oid->oid[0] = val / 40;
+ if (oid->oid[0] > 2)
+ oid->oid[0] = 2;
+ oid->oid[1] = val - oid->oid[0] * 40;
+ oid->len = 2;
+ } else
+ oid->oid[oid->len++] = val;
+ }
+
+ return 0;
+}
+
+
+void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
+{
+ char *pos = buf;
+ size_t i;
+ int ret;
+
+ if (len == 0)
+ return;
+
+ buf[0] = '\0';
+
+ for (i = 0; i < oid->len; i++) {
+ ret = os_snprintf(pos, buf + len - pos,
+ "%s%lu",
+ i == 0 ? "" : ".", oid->oid[i]);
+ if (ret < 0 || ret >= buf + len - pos)
+ break;
+ pos += ret;
+ }
+ buf[len - 1] = '\0';
+}
+
+
+static u8 rotate_bits(u8 octet)
+{
+ int i;
+ u8 res;
+
+ res = 0;
+ for (i = 0; i < 8; i++) {
+ res <<= 1;
+ if (octet & 1)
+ res |= 1;
+ octet >>= 1;
+ }
+
+ return res;
+}
+
+
+unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
+{
+ unsigned long val = 0;
+ const u8 *pos = buf;
+
+ /* BER requires that unused bits are zero, so we can ignore the number
+ * of unused bits */
+ pos++;
+
+ if (len >= 2)
+ val |= rotate_bits(*pos++);
+ if (len >= 3)
+ val |= ((unsigned long) rotate_bits(*pos++)) << 8;
+ if (len >= 4)
+ val |= ((unsigned long) rotate_bits(*pos++)) << 16;
+ if (len >= 5)
+ val |= ((unsigned long) rotate_bits(*pos++)) << 24;
+ if (len >= 6)
+ wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
+ "(BIT STRING length %lu)",
+ __func__, (unsigned long) len);
+
+ return val;
+}
+
+#endif /* CONFIG_INTERNAL_X509 */
diff --git a/contrib/wpa_supplicant/asn1.h b/contrib/wpa_supplicant/asn1.h
new file mode 100644
index 000000000000..c02ada8278a2
--- /dev/null
+++ b/contrib/wpa_supplicant/asn1.h
@@ -0,0 +1,71 @@
+/*
+ * ASN.1 DER parsing
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef ASN1_H
+#define ASN1_H
+
+#define ASN1_TAG_EOC 0x00 /* not used with DER */
+#define ASN1_TAG_BOOLEAN 0x01
+#define ASN1_TAG_INTEGER 0x02
+#define ASN1_TAG_BITSTRING 0x03
+#define ASN1_TAG_OCTETSTRING 0x04
+#define ASN1_TAG_NULL 0x05
+#define ASN1_TAG_OID 0x06
+#define ASN1_TAG_OBJECT_DESCRIPTOR 0x07 /* not yet parsed */
+#define ASN1_TAG_EXTERNAL 0x08 /* not yet parsed */
+#define ASN1_TAG_REAL 0x09 /* not yet parsed */
+#define ASN1_TAG_ENUMERATED 0x0A /* not yet parsed */
+#define ASN1_TAG_UTF8STRING 0x0C /* not yet parsed */
+#define ANS1_TAG_RELATIVE_OID 0x0D
+#define ASN1_TAG_SEQUENCE 0x10 /* shall be constructed */
+#define ASN1_TAG_SET 0x11
+#define ASN1_TAG_NUMERICSTRING 0x12 /* not yet parsed */
+#define ASN1_TAG_PRINTABLESTRING 0x13
+#define ASN1_TAG_TG1STRING 0x14 /* not yet parsed */
+#define ASN1_TAG_VIDEOTEXSTRING 0x15 /* not yet parsed */
+#define ASN1_TAG_IA5STRING 0x16
+#define ASN1_TAG_UTCTIME 0x17
+#define ASN1_TAG_GENERALIZEDTIME 0x18 /* not yet parsed */
+#define ASN1_TAG_GRAPHICSTRING 0x19 /* not yet parsed */
+#define ASN1_TAG_VISIBLESTRING 0x1A
+#define ASN1_TAG_GENERALSTRING 0x1B /* not yet parsed */
+#define ASN1_TAG_UNIVERSALSTRING 0x1C /* not yet parsed */
+#define ASN1_TAG_BMPSTRING 0x1D /* not yet parsed */
+
+#define ASN1_CLASS_UNIVERSAL 0
+#define ASN1_CLASS_APPLICATION 1
+#define ASN1_CLASS_CONTEXT_SPECIFIC 2
+#define ASN1_CLASS_PRIVATE 3
+
+
+struct asn1_hdr {
+ const u8 *payload;
+ u8 identifier, class, constructed;
+ unsigned int tag, length;
+};
+
+#define ASN1_MAX_OID_LEN 20
+struct asn1_oid {
+ unsigned long oid[ASN1_MAX_OID_LEN];
+ size_t len;
+};
+
+
+int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr);
+int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
+ const u8 **next);
+void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len);
+unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len);
+
+#endif /* ASN1_H */
diff --git a/contrib/wpa_supplicant/asn1_test.c b/contrib/wpa_supplicant/asn1_test.c
new file mode 100644
index 000000000000..a5c77535309f
--- /dev/null
+++ b/contrib/wpa_supplicant/asn1_test.c
@@ -0,0 +1,210 @@
+/*
+ * Testing tool for ASN.1/X.509v3 routines
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "asn1.h"
+#include "x509v3.h"
+
+extern int wpa_debug_level;
+
+
+static const char * asn1_class_str(int class)
+{
+ switch (class) {
+ case ASN1_CLASS_UNIVERSAL:
+ return "Universal";
+ case ASN1_CLASS_APPLICATION:
+ return "Application";
+ case ASN1_CLASS_CONTEXT_SPECIFIC:
+ return "Context-specific";
+ case ASN1_CLASS_PRIVATE:
+ return "Private";
+ default:
+ return "?";
+ }
+}
+
+
+int asn1_parse(const u8 *buf, size_t len, int level)
+{
+ const u8 *pos, *prev, *end;
+ char prefix[10], str[100];
+ int _level;
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+ u8 tmp;
+
+ _level = level;
+ if ((size_t) _level > sizeof(prefix) - 1)
+ _level = sizeof(prefix) - 1;
+ memset(prefix, ' ', _level);
+ prefix[_level] = '\0';
+
+ pos = buf;
+ end = buf + len;
+
+ while (pos < end) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0)
+ return -1;
+
+ prev = pos;
+ pos = hdr.payload;
+
+ wpa_printf(MSG_MSGDUMP, "ASN.1:%s Class %d(%s) P/C %d(%s) "
+ "Tag %u Length %u",
+ prefix, hdr.class, asn1_class_str(hdr.class),
+ hdr.constructed,
+ hdr.constructed ? "Constructed" : "Primitive",
+ hdr.tag, hdr.length);
+
+ if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC &&
+ hdr.constructed) {
+ if (asn1_parse(pos, hdr.length, level + 1) < 0)
+ return -1;
+ pos += hdr.length;
+ }
+
+ if (hdr.class != ASN1_CLASS_UNIVERSAL)
+ continue;
+
+ switch (hdr.tag) {
+ case ASN1_TAG_EOC:
+ if (hdr.length) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Non-zero "
+ "end-of-contents length (%u)",
+ hdr.length);
+ return -1;
+ }
+ wpa_printf(MSG_MSGDUMP, "ASN.1:%s EOC", prefix);
+ break;
+ case ASN1_TAG_BOOLEAN:
+ if (hdr.length != 1) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Unexpected "
+ "Boolean length (%u)", hdr.length);
+ return -1;
+ }
+ tmp = *pos++;
+ wpa_printf(MSG_MSGDUMP, "ASN.1:%s Boolean %s",
+ prefix, tmp ? "TRUE" : "FALSE");
+ break;
+ case ASN1_TAG_INTEGER:
+ wpa_hexdump(MSG_MSGDUMP, "ASN.1: INTEGER",
+ pos, hdr.length);
+ pos += hdr.length;
+ break;
+ case ASN1_TAG_BITSTRING:
+ wpa_hexdump(MSG_MSGDUMP, "ASN.1: BitString",
+ pos, hdr.length);
+ pos += hdr.length;
+ break;
+ case ASN1_TAG_OCTETSTRING:
+ wpa_hexdump(MSG_MSGDUMP, "ASN.1: OctetString",
+ pos, hdr.length);
+ pos += hdr.length;
+ break;
+ case ASN1_TAG_NULL:
+ if (hdr.length) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Non-zero Null "
+ "length (%u)", hdr.length);
+ return -1;
+ }
+ wpa_printf(MSG_MSGDUMP, "ASN.1:%s Null", prefix);
+ break;
+ case ASN1_TAG_OID:
+ if (asn1_get_oid(prev, end - prev, &oid, &prev) < 0) {
+ wpa_printf(MSG_DEBUG, "ASN.1: Invalid OID");
+ return -1;
+ }
+ asn1_oid_to_str(&oid, str, sizeof(str));
+ wpa_printf(MSG_DEBUG, "ASN.1:%s OID %s", prefix, str);
+ pos += hdr.length;
+ break;
+ case ANS1_TAG_RELATIVE_OID:
+ wpa_hexdump(MSG_MSGDUMP, "ASN.1: Relative OID",
+ pos, hdr.length);
+ pos += hdr.length;
+ break;
+ case ASN1_TAG_SEQUENCE:
+ wpa_printf(MSG_MSGDUMP, "ASN.1:%s SEQUENCE", prefix);
+ if (asn1_parse(pos, hdr.length, level + 1) < 0)
+ return -1;
+ pos += hdr.length;
+ break;
+ case ASN1_TAG_SET:
+ wpa_printf(MSG_MSGDUMP, "ASN.1:%s SET", prefix);
+ if (asn1_parse(pos, hdr.length, level + 1) < 0)
+ return -1;
+ pos += hdr.length;
+ break;
+ case ASN1_TAG_PRINTABLESTRING:
+ wpa_hexdump_ascii(MSG_MSGDUMP,
+ "ASN.1: PrintableString",
+ pos, hdr.length);
+ pos += hdr.length;
+ break;
+ case ASN1_TAG_IA5STRING:
+ wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: IA5String",
+ pos, hdr.length);
+ pos += hdr.length;
+ break;
+ case ASN1_TAG_UTCTIME:
+ wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: UTCTIME",
+ pos, hdr.length);
+ pos += hdr.length;
+ break;
+ case ASN1_TAG_VISIBLESTRING:
+ wpa_hexdump_ascii(MSG_MSGDUMP, "ASN.1: VisibleString",
+ pos, hdr.length);
+ pos += hdr.length;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ASN.1: Unknown tag %d",
+ hdr.tag);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+ FILE *f;
+ u8 buf[3000];
+ size_t len;
+ struct x509_certificate *cert;
+
+ wpa_debug_level = 0;
+
+ f = fopen(argv[1], "rb");
+ if (f == NULL)
+ return -1;
+ len = fread(buf, 1, sizeof(buf), f);
+ fclose(f);
+
+ if (asn1_parse(buf, len, 0) < 0)
+ printf("Failed to parse DER ASN.1\n");
+
+ printf("\n\n");
+
+ cert = x509_certificate_parse(buf, len);
+ if (cert == NULL)
+ printf("Failed to parse X.509 certificate\n");
+ x509_certificate_free(cert);
+
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/base64.c b/contrib/wpa_supplicant/base64.c
index 2717e30c6980..0c33e5881b64 100644
--- a/contrib/wpa_supplicant/base64.c
+++ b/contrib/wpa_supplicant/base64.c
@@ -1,6 +1,6 @@
/*
* Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,12 +12,12 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <string.h>
+#include "includes.h"
+#include "os.h"
#include "base64.h"
-static const unsigned char base64_table[64] =
+static const unsigned char base64_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/**
@@ -43,7 +43,7 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
olen += olen / 72; /* line feeds */
olen++; /* nul termination */
- out = malloc(olen);
+ out = os_malloc(olen);
if (out == NULL)
return NULL;
@@ -104,9 +104,9 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
unsigned char dtable[256], *out, *pos, in[4], block[4], tmp;
size_t i, count, olen;
- memset(dtable, 0x80, 256);
- for (i = 0; i < sizeof(base64_table); i++)
- dtable[base64_table[i]] = i;
+ os_memset(dtable, 0x80, 256);
+ for (i = 0; i < sizeof(base64_table) - 1; i++)
+ dtable[base64_table[i]] = (unsigned char) i;
dtable['='] = 0;
count = 0;
@@ -119,7 +119,7 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
return NULL;
olen = count / 4 * 3;
- pos = out = malloc(count);
+ pos = out = os_malloc(olen);
if (out == NULL)
return NULL;
@@ -166,19 +166,9 @@ int main(int argc, char *argv[])
return -1;
}
- f = fopen(argv[2], "r");
- if (f == NULL)
- return -1;
- fseek(f, 0, SEEK_END);
- len = ftell(f);
- fseek(f, 0, SEEK_SET);
- buf = malloc(len);
- if (buf == NULL) {
- fclose(f);
+ buf = os_readfile(argv[2], &len);
+ if (buf == NULL)
return -1;
- }
- fread(buf, 1, len, f);
- fclose(f);
if (strcmp(argv[1], "encode") == 0)
e = base64_encode(buf, len, &elen);
diff --git a/contrib/wpa_supplicant/base64.h b/contrib/wpa_supplicant/base64.h
index 7043328f678e..73312dde8f64 100644
--- a/contrib/wpa_supplicant/base64.h
+++ b/contrib/wpa_supplicant/base64.h
@@ -1,6 +1,6 @@
/*
* Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/contrib/wpa_supplicant/bignum.c b/contrib/wpa_supplicant/bignum.c
new file mode 100644
index 000000000000..4c304c2a5af5
--- /dev/null
+++ b/contrib/wpa_supplicant/bignum.c
@@ -0,0 +1,230 @@
+/*
+ * Big number math
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "bignum.h"
+
+#ifdef CONFIG_INTERNAL_LIBTOMMATH
+#include "libtommath.c"
+#else /* CONFIG_INTERNAL_LIBTOMMATH */
+#include <tommath.h>
+#endif /* CONFIG_INTERNAL_LIBTOMMATH */
+
+
+/*
+ * The current version is just a wrapper for LibTomMath library, so
+ * struct bignum is just typecast to mp_int.
+ */
+
+/**
+ * bignum_init - Allocate memory for bignum
+ * Returns: Pointer to allocated bignum or %NULL on failure
+ */
+struct bignum * bignum_init(void)
+{
+ struct bignum *n = os_zalloc(sizeof(mp_int));
+ if (n == NULL)
+ return NULL;
+ if (mp_init((mp_int *) n) != MP_OKAY) {
+ os_free(n);
+ n = NULL;
+ }
+ return n;
+}
+
+
+/**
+ * bignum_deinit - Free bignum
+ * @n: Bignum from bignum_init()
+ */
+void bignum_deinit(struct bignum *n)
+{
+ if (n) {
+ mp_clear((mp_int *) n);
+ os_free(n);
+ }
+}
+
+
+/**
+ * bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer
+ * @n: Bignum from bignum_init()
+ * Returns: Length of n if written to a binary buffer
+ */
+size_t bignum_get_unsigned_bin_len(struct bignum *n)
+{
+ return mp_unsigned_bin_size((mp_int *) n);
+}
+
+
+/**
+ * bignum_get_unsigned_bin - Set binary buffer to unsigned bignum
+ * @n: Bignum from bignum_init()
+ * @buf: Buffer for the binary number
+ * @len: Length of the buffer, can be %NULL if buffer is known to be long
+ * enough. Set to used buffer length on success if not %NULL.
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len)
+{
+ size_t need = mp_unsigned_bin_size((mp_int *) n);
+ if (len && need > *len) {
+ *len = need;
+ return -1;
+ }
+ if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) {
+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+ return -1;
+ }
+ if (len)
+ *len = need;
+ return 0;
+}
+
+
+/**
+ * bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer
+ * @a: Bignum from bignum_init(); to be set to the given value
+ * @buf: Buffer with unsigned binary value
+ * @len: Length of buf in octets
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len)
+{
+ if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) {
+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * bignum_cmp - Signed comparison
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_cmp(const struct bignum *a, const struct bignum *b)
+{
+ return mp_cmp((mp_int *) a, (mp_int *) b);
+}
+
+
+/**
+ * bignum_cmd_d - Compare bignum to standard integer
+ * @a: Bignum from bignum_init()
+ * @b: Small integer
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_cmp_d(const struct bignum *a, unsigned long b)
+{
+ return mp_cmp_d((mp_int *) a, b);
+}
+
+
+/**
+ * bignum_add - c = a + b
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * @c: Bignum from bignum_init(); used to store the result of a + b
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_add(const struct bignum *a, const struct bignum *b,
+ struct bignum *c)
+{
+ if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * bignum_sub - c = a - b
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * @c: Bignum from bignum_init(); used to store the result of a - b
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_sub(const struct bignum *a, const struct bignum *b,
+ struct bignum *c)
+{
+ if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * bignum_mul - c = a * b
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * @c: Bignum from bignum_init(); used to store the result of a * b
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_mul(const struct bignum *a, const struct bignum *b,
+ struct bignum *c)
+{
+ if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * bignum_mulmod - d = a * b (mod c)
+ * @a: Bignum from bignum_init()
+ * @b: Bignum from bignum_init()
+ * @c: Bignum from bignum_init(); modulus
+ * @d: Bignum from bignum_init(); used to store the result of a * b (mod c)
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_mulmod(const struct bignum *a, const struct bignum *b,
+ const struct bignum *c, struct bignum *d)
+{
+ if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
+ != MP_OKAY) {
+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * bignum_exptmod - Modular exponentiation: d = a^b (mod c)
+ * @a: Bignum from bignum_init(); base
+ * @b: Bignum from bignum_init(); exponent
+ * @c: Bignum from bignum_init(); modulus
+ * @d: Bignum from bignum_init(); used to store the result of a^b (mod c)
+ * Returns: 0 on success, -1 on failure
+ */
+int bignum_exptmod(const struct bignum *a, const struct bignum *b,
+ const struct bignum *c, struct bignum *d)
+{
+ if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
+ != MP_OKAY) {
+ wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
+ return -1;
+ }
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/bignum.h b/contrib/wpa_supplicant/bignum.h
new file mode 100644
index 000000000000..f25e26783a0a
--- /dev/null
+++ b/contrib/wpa_supplicant/bignum.h
@@ -0,0 +1,38 @@
+/*
+ * Big number math
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef BIGNUM_H
+#define BIGNUM_H
+
+struct bignum;
+
+struct bignum * bignum_init(void);
+void bignum_deinit(struct bignum *n);
+size_t bignum_get_unsigned_bin_len(struct bignum *n);
+int bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len);
+int bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len);
+int bignum_cmp(const struct bignum *a, const struct bignum *b);
+int bignum_cmp_d(const struct bignum *a, unsigned long b);
+int bignum_add(const struct bignum *a, const struct bignum *b,
+ struct bignum *c);
+int bignum_sub(const struct bignum *a, const struct bignum *b,
+ struct bignum *c);
+int bignum_mul(const struct bignum *a, const struct bignum *b,
+ struct bignum *c);
+int bignum_mulmod(const struct bignum *a, const struct bignum *b,
+ const struct bignum *c, struct bignum *d);
+int bignum_exptmod(const struct bignum *a, const struct bignum *b,
+ const struct bignum *c, struct bignum *d);
+
+#endif /* BIGNUM_H */
diff --git a/contrib/wpa_supplicant/build_config.h b/contrib/wpa_supplicant/build_config.h
new file mode 100644
index 000000000000..58bcda825345
--- /dev/null
+++ b/contrib/wpa_supplicant/build_config.h
@@ -0,0 +1,50 @@
+/*
+ * wpa_supplicant/hostapd - Build time configuration defines
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This header file can be used to define configuration defines that were
+ * originally defined in Makefile. This is mainly meant for IDE use or for
+ * systems that do not have suitable 'make' tool. In these cases, it may be
+ * easier to have a single place for defining all the needed C pre-processor
+ * defines.
+ */
+
+#ifndef BUILD_CONFIG_H
+#define BUILD_CONFIG_H
+
+/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */
+
+#ifdef CONFIG_WIN32_DEFAULTS
+#define CONFIG_NATIVE_WINDOWS
+#define CONFIG_ANSI_C_EXTRA
+#define CONFIG_WINPCAP
+#define IEEE8021X_EAPOL
+#define EAP_TLS_FUNCS
+#define PKCS12_FUNCS
+#define PCSC_FUNCS
+#define CONFIG_CTRL_IFACE
+#define CONFIG_CTRL_IFACE_NAMED_PIPE
+#define CONFIG_DRIVER_NDIS
+#define CONFIG_NDIS_EVENTS_INTEGRATED
+#define CONFIG_DEBUG_FILE
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define _CRT_SECURE_NO_DEPRECATE
+#endif /* CONFIG_WIN32_DEFAULTS */
+
+#endif /* BUILD_CONFIG_H */
diff --git a/contrib/wpa_supplicant/common.c b/contrib/wpa_supplicant/common.c
index 4b756d8f9292..c8d6f130a960 100644
--- a/contrib/wpa_supplicant/common.c
+++ b/contrib/wpa_supplicant/common.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,70 +12,20 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <time.h>
-#include <sys/time.h>
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock2.h>
-#include <wincrypt.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
#include "common.h"
+#ifdef CONFIG_DEBUG_FILE
+static FILE *out_file = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+int wpa_debug_use_file = 0;
int wpa_debug_level = MSG_INFO;
int wpa_debug_show_keys = 0;
int wpa_debug_timestamp = 0;
-int hostapd_get_rand(u8 *buf, size_t len)
-{
-#ifdef CONFIG_NATIVE_WINDOWS
- HCRYPTPROV prov;
- BOOL ret;
-
- if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL,
- CRYPT_VERIFYCONTEXT))
- return -1;
-
- ret = CryptGenRandom(prov, len, buf);
- CryptReleaseContext(prov, 0);
-
- return ret ? 0 : -1;
-#else /* CONFIG_NATIVE_WINDOWS */
- FILE *f;
- size_t rc;
-
- f = fopen("/dev/urandom", "r");
- if (f == NULL) {
- printf("Could not open /dev/urandom.\n");
- return -1;
- }
-
- rc = fread(buf, 1, len, f);
- fclose(f);
-
- return rc != len ? -1 : 0;
-#endif /* CONFIG_NATIVE_WINDOWS */
-}
-
-
-void hostapd_hexdump(const char *title, const u8 *buf, size_t len)
-{
- size_t i;
- printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
- for (i = 0; i < len; i++)
- printf(" %02x", buf[i]);
- printf("\n");
-}
-
-
static int hex2num(char c)
{
if (c >= '0' && c <= '9')
@@ -139,7 +89,8 @@ int hwaddr_aton(const char *txt, u8 *addr)
*/
int hexstr2bin(const char *hex, u8 *buf, size_t len)
{
- int i, a;
+ size_t i;
+ int a;
const char *ipos = hex;
u8 *opos = buf;
@@ -154,45 +105,6 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len)
}
-char * rel2abs_path(const char *rel_path)
-{
- char *buf = NULL, *cwd, *ret;
- size_t len = 128, cwd_len, rel_len, ret_len;
-
- if (rel_path[0] == '/')
- return strdup(rel_path);
-
- for (;;) {
- buf = malloc(len);
- if (buf == NULL)
- return NULL;
- cwd = getcwd(buf, len);
- if (cwd == NULL) {
- free(buf);
- if (errno != ERANGE) {
- return NULL;
- }
- len *= 2;
- } else {
- break;
- }
- }
-
- cwd_len = strlen(cwd);
- rel_len = strlen(rel_path);
- ret_len = cwd_len + 1 + rel_len + 1;
- ret = malloc(ret_len);
- if (ret) {
- memcpy(ret, cwd, cwd_len);
- ret[cwd_len] = '/';
- memcpy(ret + cwd_len + 1, rel_path, rel_len);
- ret[ret_len - 1] = '\0';
- }
- free(buf);
- return ret;
-}
-
-
/**
* inc_byte_array - Increment arbitrary length byte array by one
* @counter: Pointer to byte array
@@ -214,40 +126,40 @@ void inc_byte_array(u8 *counter, size_t len)
}
-void print_char(char c)
+void wpa_get_ntp_timestamp(u8 *buf)
{
- if (c >= 32 && c < 127)
- printf("%c", c);
- else
- printf("<%02x>", c);
+ struct os_time now;
+ u32 sec, usec;
+
+ /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
+ os_get_time(&now);
+ sec = host_to_be32(now.sec + 2208988800U); /* Epoch to 1900 */
+ /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
+ usec = now.usec;
+ usec = host_to_be32(4295 * usec - (usec >> 5) - (usec >> 9));
+ os_memcpy(buf, (u8 *) &sec, 4);
+ os_memcpy(buf + 4, (u8 *) &usec, 4);
}
-void fprint_char(FILE *f, char c)
-{
- if (c >= 32 && c < 127)
- fprintf(f, "%c", c);
- else
- fprintf(f, "<%02x>", c);
-}
-
#ifndef CONFIG_NO_STDOUT_DEBUG
void wpa_debug_print_timestamp(void)
{
- struct timeval tv;
- char buf[16];
+ struct os_time tv;
if (!wpa_debug_timestamp)
return;
- gettimeofday(&tv, NULL);
- if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S",
- localtime((const time_t *) &tv.tv_sec)) <= 0) {
- snprintf(buf, sizeof(buf), "%u", (int) tv.tv_sec);
- }
- printf("%s.%06u: ", buf, (unsigned int) tv.tv_usec);
+ os_get_time(&tv);
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
+ (unsigned int) tv.usec);
+ } else
+#endif /* CONFIG_DEBUG_FILE */
+ printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
}
@@ -269,8 +181,17 @@ void wpa_printf(int level, char *fmt, ...)
va_start(ap, fmt);
if (level >= wpa_debug_level) {
wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ vfprintf(out_file, fmt, ap);
+ fprintf(out_file, "\n");
+ } else {
+#endif /* CONFIG_DEBUG_FILE */
vprintf(fmt, ap);
printf("\n");
+#ifdef CONFIG_DEBUG_FILE
+ }
+#endif /* CONFIG_DEBUG_FILE */
}
va_end(ap);
}
@@ -283,6 +204,21 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
if (level < wpa_debug_level)
return;
wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ fprintf(out_file, "%s - hexdump(len=%lu):",
+ title, (unsigned long) len);
+ if (buf == NULL) {
+ fprintf(out_file, " [NULL]");
+ } else if (show) {
+ for (i = 0; i < len; i++)
+ fprintf(out_file, " %02x", buf[i]);
+ } else {
+ fprintf(out_file, " [REMOVED]");
+ }
+ fprintf(out_file, "\n");
+ } else {
+#endif /* CONFIG_DEBUG_FILE */
printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
if (buf == NULL) {
printf(" [NULL]");
@@ -293,6 +229,9 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
printf(" [REMOVED]");
}
printf("\n");
+#ifdef CONFIG_DEBUG_FILE
+ }
+#endif /* CONFIG_DEBUG_FILE */
}
void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
@@ -310,13 +249,51 @@ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
size_t len, int show)
{
- int i, llen;
+ size_t i, llen;
const u8 *pos = buf;
- const int line_len = 16;
+ const size_t line_len = 16;
if (level < wpa_debug_level)
return;
wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ if (!show) {
+ fprintf(out_file,
+ "%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ if (buf == NULL) {
+ fprintf(out_file,
+ "%s - hexdump_ascii(len=%lu): [NULL]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
+ title, (unsigned long) len);
+ while (len) {
+ llen = len > line_len ? line_len : len;
+ fprintf(out_file, " ");
+ for (i = 0; i < llen; i++)
+ fprintf(out_file, " %02x", pos[i]);
+ for (i = llen; i < line_len; i++)
+ fprintf(out_file, " ");
+ fprintf(out_file, " ");
+ for (i = 0; i < llen; i++) {
+ if (isprint(pos[i]))
+ fprintf(out_file, "%c", pos[i]);
+ else
+ fprintf(out_file, "_");
+ }
+ for (i = llen; i < line_len; i++)
+ fprintf(out_file, " ");
+ fprintf(out_file, "\n");
+ pos += llen;
+ len -= llen;
+ }
+ } else {
+#endif /* CONFIG_DEBUG_FILE */
if (!show) {
printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
title, (unsigned long) len);
@@ -348,6 +325,9 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
pos += llen;
len -= llen;
}
+#ifdef CONFIG_DEBUG_FILE
+ }
+#endif /* CONFIG_DEBUG_FILE */
}
@@ -363,26 +343,261 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
}
+
+int wpa_debug_open_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+ static int count = 0;
+ char fname[64];
+ if (!wpa_debug_use_file)
+ return 0;
+#ifdef _WIN32
+ os_snprintf(fname, sizeof(fname), "\\Temp\\wpa_supplicant-log-%d.txt",
+ count++);
+#else /* _WIN32 */
+ os_snprintf(fname, sizeof(fname), "/tmp/wpa_supplicant-log-%d.txt",
+ count++);
+#endif /* _WIN32 */
+ out_file = fopen(fname, "w");
+ return out_file == NULL ? -1 : 0;
+#else /* CONFIG_DEBUG_FILE */
+ return 0;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+
+void wpa_debug_close_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+ if (!wpa_debug_use_file)
+ return;
+ fclose(out_file);
+ out_file = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
#endif /* CONFIG_NO_STDOUT_DEBUG */
-#ifdef CONFIG_NATIVE_WINDOWS
+#ifndef CONFIG_NO_WPA_MSG
+static wpa_msg_cb_func wpa_msg_cb = NULL;
+
+void wpa_msg_register_cb(wpa_msg_cb_func func)
+{
+ wpa_msg_cb = func;
+}
+
+
+void wpa_msg(void *ctx, int level, char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ const int buflen = 2048;
+ int len;
-#define EPOCHFILETIME (116444736000000000ULL)
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
+ "buffer");
+ return;
+ }
+ va_start(ap, fmt);
+ len = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ wpa_printf(level, "%s", buf);
+ if (wpa_msg_cb)
+ wpa_msg_cb(ctx, level, buf, len);
+ os_free(buf);
+}
+#endif /* CONFIG_NO_WPA_MSG */
-int gettimeofday(struct timeval *tv, struct timezone *tz)
+
+static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
+ size_t len, int uppercase)
{
- FILETIME ft;
- LARGE_INTEGER li;
- ULONGLONG t;
+ size_t i;
+ char *pos = buf, *end = buf + buf_size;
+ int ret;
+ if (buf_size == 0)
+ return 0;
+ for (i = 0; i < len; i++) {
+ ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
+ data[i]);
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return pos - buf;
+ }
+ pos += ret;
+ }
+ end[-1] = '\0';
+ return pos - buf;
+}
- GetSystemTimeAsFileTime(&ft);
- li.LowPart = ft.dwLowDateTime;
- li.HighPart = ft.dwHighDateTime;
- t = (li.QuadPart - EPOCHFILETIME) / 10;
- tv->tv_sec = (long) (t / 1000000);
- tv->tv_usec = (long) (t % 1000000);
+/**
+ * wpa_snprintf_hex - Print data as a hex string into a buffer
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
+{
+ return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
+}
- return 0;
+
+/**
+ * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+ size_t len)
+{
+ return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
+}
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#ifdef _WIN32_WCE
+void perror(const char *s)
+{
+ wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
+ s, (int) GetLastError());
+}
+#endif /* _WIN32_WCE */
+
+
+int optind = 1;
+int optopt;
+char *optarg;
+
+int getopt(int argc, char *const argv[], const char *optstring)
+{
+ static int optchr = 1;
+ char *cp;
+
+ if (optchr == 1) {
+ if (optind >= argc) {
+ /* all arguments processed */
+ return EOF;
+ }
+
+ if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
+ /* no option characters */
+ return EOF;
+ }
+ }
+
+ if (os_strcmp(argv[optind], "--") == 0) {
+ /* no more options */
+ optind++;
+ return EOF;
+ }
+
+ optopt = argv[optind][optchr];
+ cp = os_strchr(optstring, optopt);
+ if (cp == NULL || optopt == ':') {
+ if (argv[optind][++optchr] == '\0') {
+ optchr = 1;
+ optind++;
+ }
+ return '?';
+ }
+
+ if (cp[1] == ':') {
+ /* Argument required */
+ optchr = 1;
+ if (argv[optind][optchr + 1]) {
+ /* No space between option and argument */
+ optarg = &argv[optind++][optchr + 1];
+ } else if (++optind >= argc) {
+ /* option requires an argument */
+ return '?';
+ } else {
+ /* Argument in the next argv */
+ optarg = argv[optind++];
+ }
+ } else {
+ /* No argument */
+ if (argv[optind][++optchr] == '\0') {
+ optchr = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return *cp;
+}
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+/**
+ * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
+ * @str: Pointer to string to convert
+ *
+ * This function converts a unicode string to ASCII using the same
+ * buffer for output. If UNICODE is not set, the buffer is not
+ * modified.
+ */
+void wpa_unicode2ascii_inplace(TCHAR *str)
+{
+#ifdef UNICODE
+ char *dst = (char *) str;
+ while (*str)
+ *dst++ = (char) *str++;
+ *dst = '\0';
+#endif /* UNICODE */
+}
+
+
+TCHAR * wpa_strdup_tchar(const char *str)
+{
+#ifdef UNICODE
+ TCHAR *buf;
+ buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
+ if (buf == NULL)
+ return NULL;
+ wsprintf(buf, L"%S", str);
+ return buf;
+#else /* UNICODE */
+ return os_strdup(str);
+#endif /* UNICODE */
}
#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+/**
+ * wpa_ssid_txt - Convert SSID to a printable string
+ * @ssid: SSID (32-octet string)
+ * @ssid_len: Length of ssid in octets
+ * Returns: Pointer to a printable string
+ *
+ * This function can be used to convert SSIDs into printable form. In most
+ * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
+ * does not limit the used character set, so anything could be used in an SSID.
+ *
+ * This function uses a static buffer, so only one call can be used at the
+ * time, i.e., this is not re-entrant and the returned buffer must be used
+ * before calling this again.
+ */
+const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
+{
+ static char ssid_txt[33];
+ char *pos;
+
+ if (ssid_len > 32)
+ ssid_len = 32;
+ os_memcpy(ssid_txt, ssid, ssid_len);
+ ssid_txt[ssid_len] = '\0';
+ for (pos = ssid_txt; *pos != '\0'; pos++) {
+ if ((u8) *pos < 32 || (u8) *pos >= 127)
+ *pos = '_';
+ }
+ return ssid_txt;
+}
diff --git a/contrib/wpa_supplicant/common.h b/contrib/wpa_supplicant/common.h
index 4bece7f6ecd9..b200b580d5df 100644
--- a/contrib/wpa_supplicant/common.h
+++ b/contrib/wpa_supplicant/common.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,12 +15,14 @@
#ifndef COMMON_H
#define COMMON_H
+#include "os.h"
+
#ifdef __linux__
#include <endian.h>
#include <byteswap.h>
#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
#include <sys/types.h>
#include <sys/endian.h>
#define __BYTE_ORDER _BYTE_ORDER
@@ -29,51 +31,22 @@
#define bswap_16 bswap16
#define bswap_32 bswap32
#define bswap_64 bswap64
-#endif /* defined(__FreeBSD__) || defined(__NetBSD__) */
-
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock2.h>
-
-static inline int daemon(int nochdir, int noclose)
-{
- printf("Windows - daemon() not supported yet\n");
- return -1;
-}
-
-static inline void sleep(int seconds)
-{
- Sleep(seconds * 1000);
-}
-
-static inline void usleep(unsigned long usec)
-{
- Sleep(usec / 1000);
-}
-
-#ifndef timersub
-#define timersub(a, b, res) do { \
- (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
- (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
- if ((res)->tv_usec < 0) { \
- (res)->tv_sec--; \
- (res)->tv_usec += 1000000; \
- } \
-} while (0)
+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
+ * defined(__DragonFly__) */
+
+#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 */
-struct timezone {
- int tz_minuteswest;
- int tz_dsttime;
-};
-
-int gettimeofday(struct timeval *tv, struct timezone *tz);
-
-static inline long int random(void)
-{
- return rand();
-}
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
-typedef int gid_t;
typedef int socklen_t;
#ifndef MSG_DONTWAIT
@@ -84,6 +57,10 @@ typedef int socklen_t;
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+#ifdef _MSC_VER
+#define inline __inline
+#endif /* _MSC_VER */
+
static inline unsigned short wpa_swap_16(unsigned short v)
{
return ((v & 0xff) << 8) | (v >> 8);
@@ -105,6 +82,18 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#else /* __CYGWIN__ */
+#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) (n)
#define host_to_le16(n) (n)
@@ -113,6 +102,10 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#define le_to_host32(n) (n)
#define be_to_host32(n) bswap_32(n)
#define host_to_be32(n) bswap_32(n)
+#define le_to_host64(n) (n)
+#define host_to_le64(n) (n)
+#define be_to_host64(n) bswap_64(n)
+#define host_to_be64(n) bswap_64(n)
#elif __BYTE_ORDER == __BIG_ENDIAN
#define le_to_host16(n) bswap_16(n)
#define host_to_le16(n) bswap_16(n)
@@ -121,6 +114,10 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#define le_to_host32(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
@@ -145,12 +142,88 @@ static inline unsigned int wpa_swap_32(unsigned int v)
(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); \
+ (a)[1] = (u8) (((u32) (val)) >> 8); \
+ (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); \
+ (a)[1] = (u8) (((u32) (val)) >> 16); \
+ (a)[2] = (u8) (((u32) (val)) >> 8); \
+ (a)[3] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#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)
+
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
+#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 */
+
+#ifndef WPA_TYPES_DEFINED
+#ifdef CONFIG_USE_INTTYPES_H
+#include <inttypes.h>
+#else
#include <stdint.h>
+#endif
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
@@ -159,19 +232,27 @@ typedef int64_t s64;
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
+#define WPA_TYPES_DEFINED
+#endif /* !WPA_TYPES_DEFINED */
-int hostapd_get_rand(u8 *buf, size_t len);
-void hostapd_hexdump(const char *title, const u8 *buf, size_t len);
+#define hostapd_get_rand os_get_random
int hwaddr_aton(const char *txt, u8 *addr);
int hexstr2bin(const char *hex, u8 *buf, size_t len);
-char * rel2abs_path(const char *rel_path);
void inc_byte_array(u8 *counter, size_t len);
-void print_char(char c);
-void fprint_char(FILE *f, char c);
+void wpa_get_ntp_timestamp(u8 *buf);
+
+
+#ifdef __GNUC__
+#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b))))
+#define STRUCT_PACKED __attribute__ ((packed))
+#else
+#define PRINTF_FORMAT(a,b)
+#define STRUCT_PACKED
+#endif
/* Debugging function - conditional printf and hex dump. Driver wrappers can
- * use these for debugging purposes. */
+ * use these for debugging purposes. */
enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
@@ -179,13 +260,18 @@ enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
#define wpa_debug_print_timestamp() do { } while (0)
#define wpa_printf(args...) do { } while (0)
-#define wpa_hexdump(args...) do { } while (0)
-#define wpa_hexdump_key(args...) do { } while (0)
-#define wpa_hexdump_ascii(args...) do { } while (0)
-#define wpa_hexdump_ascii_key(args...) do { } while (0)
+#define wpa_hexdump(l,t,b,le) do { } while (0)
+#define wpa_hexdump_key(l,t,b,le) 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() do { } while (0)
+#define wpa_debug_close_file() do { } while (0)
#else /* CONFIG_NO_STDOUT_DEBUG */
+int wpa_debug_open_file(void);
+void wpa_debug_close_file(void);
+
/**
* wpa_debug_printf_timestamp - Print timestamp for debug output
*
@@ -207,7 +293,7 @@ void wpa_debug_print_timestamp(void);
* Note: New line '\n' is added to the end of the text when printing to stdout.
*/
void wpa_printf(int level, char *fmt, ...)
-__attribute__ ((format (printf, 2, 3)));
+PRINTF_FORMAT(2, 3);
/**
* wpa_hexdump - conditional hex dump
@@ -273,6 +359,42 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
#endif /* CONFIG_NO_STDOUT_DEBUG */
+#ifdef CONFIG_NO_WPA_MSG
+#define wpa_msg(args...) do { } while (0)
+#define wpa_msg_register_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, char *fmt, ...) PRINTF_FORMAT(3, 4);
+
+typedef void (*wpa_msg_cb_func)(void *ctx, int level, 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 */
+
+
+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);
+
+
#ifdef EAPOL_TEST
#define WPA_ASSERT(a) \
do { \
@@ -287,4 +409,84 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
#define WPA_ASSERT(a) do { } while (0)
#endif
+
+#ifdef _MSC_VER
+#undef vsnprintf
+#define vsnprintf _vsnprintf
+#undef close
+#define close closesocket
+#endif /* _MSC_VER */
+
+
+#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 */
+
+#define wpa_zalloc(s) os_zalloc((s))
+
+#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 */
+
+const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len);
+
+typedef u32 __be32;
+typedef u64 __be64;
+
#endif /* COMMON_H */
diff --git a/contrib/wpa_supplicant/config.c b/contrib/wpa_supplicant/config.c
index 2bba4ab22171..171970dc210f 100644
--- a/contrib/wpa_supplicant/config.c
+++ b/contrib/wpa_supplicant/config.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration parser and common functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,14 +12,11 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "wpa.h"
#include "sha1.h"
-#include "wpa_supplicant.h"
#include "eapol_sm.h"
#include "eap.h"
#include "l2_packet.h"
@@ -46,9 +43,11 @@ struct parse_data {
/* Variable specific parameters for the parser. */
void *param1, *param2, *param3, *param4;
- /* 0 = this variable can be included in debug output
+ /* 0 = this variable can be included in debug output and ctrl_iface
* 1 = this variable contains key/private data and it must not be
- * included in debug output unless explicitly requested
+ * included in debug output unless explicitly requested. In
+ * addition, this variable will not be readable through the
+ * ctrl_iface.
*/
int key_data;
};
@@ -59,23 +58,23 @@ static char * wpa_config_parse_string(const char *value, size_t *len)
if (*value == '"') {
char *pos;
value++;
- pos = strchr(value, '"');
+ pos = os_strrchr(value, '"');
if (pos == NULL || pos[1] != '\0')
return NULL;
*pos = '\0';
- *len = strlen(value);
- return strdup(value);
+ *len = os_strlen(value);
+ return os_strdup(value);
} else {
u8 *str;
- size_t hlen = strlen(value);
- if (hlen % 1)
+ size_t hlen = os_strlen(value);
+ if (hlen & 1)
return NULL;
*len = hlen / 2;
- str = malloc(*len);
+ str = os_malloc(*len);
if (str == NULL)
return NULL;
if (hexstr2bin(value, str, *len)) {
- free(str);
+ os_free(str);
return NULL;
}
return (char *) str;
@@ -88,35 +87,29 @@ static int wpa_config_parse_str(const struct parse_data *data,
int line, const char *value)
{
size_t res_len, *dst_len;
- char **dst;
+ char **dst, *tmp;
- dst = (char **) (((u8 *) ssid) + (long) data->param1);
- dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
-
- free(*dst);
- *dst = wpa_config_parse_string(value, &res_len);
- if (*dst == NULL) {
+ tmp = wpa_config_parse_string(value, &res_len);
+ if (tmp == NULL) {
wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
- line, data->name, value);
+ line, data->name,
+ data->key_data ? "[KEY DATA REMOVED]" : value);
return -1;
}
- if (data->param2)
- *dst_len = res_len;
if (data->key_data) {
wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
- (u8 *) *dst, res_len);
+ (u8 *) tmp, res_len);
} else {
wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
- (u8 *) *dst, res_len);
+ (u8 *) tmp, res_len);
}
if (data->param3 && res_len < (size_t) data->param3) {
wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
"min_len=%ld)", line, data->name,
(unsigned long) res_len, (long) data->param3);
- free(*dst);
- *dst = NULL;
+ os_free(tmp);
return -1;
}
@@ -124,18 +117,24 @@ static int wpa_config_parse_str(const struct parse_data *data,
wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
"max_len=%ld)", line, data->name,
(unsigned long) res_len, (long) data->param4);
- free(*dst);
- *dst = NULL;
+ os_free(tmp);
return -1;
}
+ dst = (char **) (((u8 *) ssid) + (long) data->param1);
+ dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+ os_free(*dst);
+ *dst = tmp;
+ if (data->param2)
+ *dst_len = res_len;
+
return 0;
}
static int is_hex(const u8 *data, size_t len)
{
- int i;
+ size_t i;
for (i = 0; i < len; i++) {
if (data[i] < 32 || data[i] >= 127)
@@ -147,17 +146,15 @@ static int is_hex(const u8 *data, size_t len)
static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
{
- int i;
- char *buf, *pos, *end;
+ char *buf;
- pos = buf = malloc(len + 3);
+ buf = os_malloc(len + 3);
if (buf == NULL)
return NULL;
- end = buf + len + 3;
- pos += snprintf(pos, end - pos, "\"");
- for (i = 0; i < len; i++)
- pos += snprintf(pos, end - pos, "%c", value[i]);
- pos += snprintf(pos, end - pos, "\"");
+ buf[0] = '"';
+ os_memcpy(buf + 1, value, len);
+ buf[len + 1] = '"';
+ buf[len + 2] = '\0';
return buf;
}
@@ -165,16 +162,12 @@ static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
static char * wpa_config_write_string_hex(const u8 *value, size_t len)
{
- int i;
- char *buf, *pos, *end;
+ char *buf;
- pos = buf = malloc(2 * len + 1);
+ buf = os_zalloc(2 * len + 1);
if (buf == NULL)
return NULL;
- memset(buf, 0, 2 * len + 1);
- end = buf + 2 * len + 1;
- for (i = 0; i < len; i++)
- pos += snprintf(pos, end - pos, "%02x", value[i]);
+ wpa_snprintf_hex(buf, 2 * len + 1, value, len);
return buf;
}
@@ -205,7 +198,7 @@ static char * wpa_config_write_str(const struct parse_data *data,
if (data->param2)
len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
else
- len = strlen(*src);
+ len = os_strlen(*src);
return wpa_config_write_string((const u8 *) *src, len);
}
@@ -249,10 +242,11 @@ static char * wpa_config_write_int(const struct parse_data *data,
src = (int *) (((u8 *) ssid) + (long) data->param1);
- value = malloc(20);
+ value = os_malloc(20);
if (value == NULL)
return NULL;
- snprintf(value, 20, "%d", *src);
+ os_snprintf(value, 20, "%d", *src);
+ value[20 - 1] = '\0';
return value;
}
@@ -280,10 +274,11 @@ static char * wpa_config_write_bssid(const struct parse_data *data,
if (!ssid->bssid_set)
return NULL;
- value = malloc(20);
+ value = os_malloc(20);
if (value == NULL)
return NULL;
- snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
+ os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
+ value[20 - 1] = '\0';
return value;
}
@@ -293,14 +288,15 @@ static int wpa_config_parse_psk(const struct parse_data *data,
const char *value)
{
if (*value == '"') {
- char *pos;
+ const char *pos;
size_t len;
value++;
- pos = strrchr(value, '"');
+ pos = os_strrchr(value, '"');
if (pos)
- *pos = '\0';
- len = strlen(value);
+ len = pos - value;
+ else
+ len = os_strlen(value);
if (len < 8 || len > 63) {
wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
"length %lu (expected: 8..63) '%s'.",
@@ -309,8 +305,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
(u8 *) value, len);
- ssid->passphrase = strdup(value);
- return ssid->passphrase == NULL ? -1 : 0;
+ if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
+ os_memcmp(ssid->passphrase, value, len) == 0)
+ return 0;
+ ssid->psk_set = 0;
+ os_free(ssid->passphrase);
+ ssid->passphrase = os_malloc(len + 1);
+ if (ssid->passphrase == NULL)
+ return -1;
+ os_memcpy(ssid->passphrase, value, len);
+ ssid->passphrase[len] = '\0';
+ return 0;
}
if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
@@ -319,6 +324,10 @@ static int wpa_config_parse_psk(const struct parse_data *data,
line, value);
return -1;
}
+
+ os_free(ssid->passphrase);
+ ssid->passphrase = NULL;
+
ssid->psk_set = 1;
wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
return 0;
@@ -331,7 +340,7 @@ static char * wpa_config_write_psk(const struct parse_data *data,
if (ssid->passphrase)
return wpa_config_write_string_ascii(
(const u8 *) ssid->passphrase,
- strlen(ssid->passphrase));
+ os_strlen(ssid->passphrase));
if (ssid->psk_set)
return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
@@ -347,7 +356,7 @@ static int wpa_config_parse_proto(const struct parse_data *data,
int val = 0, last, errors = 0;
char *start, *end, *buf;
- buf = strdup(value);
+ buf = os_strdup(value);
if (buf == NULL)
return -1;
start = buf;
@@ -362,10 +371,10 @@ static int wpa_config_parse_proto(const struct parse_data *data,
end++;
last = *end == '\0';
*end = '\0';
- if (strcmp(start, "WPA") == 0)
+ if (os_strcmp(start, "WPA") == 0)
val |= WPA_PROTO_WPA;
- else if (strcmp(start, "RSN") == 0 ||
- strcmp(start, "WPA2") == 0)
+ else if (os_strcmp(start, "RSN") == 0 ||
+ os_strcmp(start, "WPA2") == 0)
val |= WPA_PROTO_RSN;
else {
wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
@@ -377,7 +386,7 @@ static int wpa_config_parse_proto(const struct parse_data *data,
break;
start = end + 1;
}
- free(buf);
+ os_free(buf);
if (val == 0) {
wpa_printf(MSG_ERROR,
@@ -394,22 +403,27 @@ static int wpa_config_parse_proto(const struct parse_data *data,
static char * wpa_config_write_proto(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- int first = 1;
+ int first = 1, ret;
char *buf, *pos, *end;
- pos = buf = malloc(10);
+ pos = buf = os_zalloc(10);
if (buf == NULL)
return NULL;
- memset(buf, 0, 10);
end = buf + 10;
if (ssid->proto & WPA_PROTO_WPA) {
- pos += snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return buf;
+ pos += ret;
first = 0;
}
if (ssid->proto & WPA_PROTO_RSN) {
- pos += snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return buf;
+ pos += ret;
first = 0;
}
@@ -424,7 +438,7 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
int val = 0, last, errors = 0;
char *start, *end, *buf;
- buf = strdup(value);
+ buf = os_strdup(value);
if (buf == NULL)
return -1;
start = buf;
@@ -439,15 +453,15 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
end++;
last = *end == '\0';
*end = '\0';
- if (strcmp(start, "WPA-PSK") == 0)
+ if (os_strcmp(start, "WPA-PSK") == 0)
val |= WPA_KEY_MGMT_PSK;
- else if (strcmp(start, "WPA-EAP") == 0)
+ else if (os_strcmp(start, "WPA-EAP") == 0)
val |= WPA_KEY_MGMT_IEEE8021X;
- else if (strcmp(start, "IEEE8021X") == 0)
+ else if (os_strcmp(start, "IEEE8021X") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
- else if (strcmp(start, "NONE") == 0)
+ else if (os_strcmp(start, "NONE") == 0)
val |= WPA_KEY_MGMT_NONE;
- else if (strcmp(start, "WPA-NONE") == 0)
+ else if (os_strcmp(start, "WPA-NONE") == 0)
val |= WPA_KEY_MGMT_WPA_NONE;
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
@@ -459,7 +473,7 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
break;
start = end + 1;
}
- free(buf);
+ os_free(buf);
if (val == 0) {
wpa_printf(MSG_ERROR,
@@ -476,40 +490,62 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
static char * wpa_config_write_key_mgmt(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- int first = 1;
char *buf, *pos, *end;
+ int ret;
- pos = buf = malloc(50);
+ pos = buf = os_zalloc(50);
if (buf == NULL)
return NULL;
- memset(buf, 0, 50);
end = buf + 50;
if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
- pos += snprintf(pos, end - pos, "%sWPA-PSK", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
- pos += snprintf(pos, end - pos, "%sWPA-EAP", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
- pos += snprintf(pos, end - pos, "%sIEEE8021X",
- first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
- pos += snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sNONE",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
- pos += snprintf(pos, end - pos, "%sWPA-NONE",
- first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
return buf;
@@ -521,7 +557,7 @@ static int wpa_config_parse_cipher(int line, const char *value)
int val = 0, last;
char *start, *end, *buf;
- buf = strdup(value);
+ buf = os_strdup(value);
if (buf == NULL)
return -1;
start = buf;
@@ -536,20 +572,20 @@ static int wpa_config_parse_cipher(int line, const char *value)
end++;
last = *end == '\0';
*end = '\0';
- if (strcmp(start, "CCMP") == 0)
+ if (os_strcmp(start, "CCMP") == 0)
val |= WPA_CIPHER_CCMP;
- else if (strcmp(start, "TKIP") == 0)
+ else if (os_strcmp(start, "TKIP") == 0)
val |= WPA_CIPHER_TKIP;
- else if (strcmp(start, "WEP104") == 0)
+ else if (os_strcmp(start, "WEP104") == 0)
val |= WPA_CIPHER_WEP104;
- else if (strcmp(start, "WEP40") == 0)
+ else if (os_strcmp(start, "WEP40") == 0)
val |= WPA_CIPHER_WEP40;
- else if (strcmp(start, "NONE") == 0)
+ else if (os_strcmp(start, "NONE") == 0)
val |= WPA_CIPHER_NONE;
else {
wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
line, start);
- free(buf);
+ os_free(buf);
return -1;
}
@@ -557,7 +593,7 @@ static int wpa_config_parse_cipher(int line, const char *value)
break;
start = end + 1;
}
- free(buf);
+ os_free(buf);
if (val == 0) {
wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
@@ -570,38 +606,62 @@ static int wpa_config_parse_cipher(int line, const char *value)
static char * wpa_config_write_cipher(int cipher)
{
- int first = 1;
char *buf, *pos, *end;
+ int ret;
- pos = buf = malloc(50);
+ pos = buf = os_zalloc(50);
if (buf == NULL)
return NULL;
- memset(buf, 0, 50);
end = buf + 50;
if (cipher & WPA_CIPHER_CCMP) {
- pos += snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sCCMP",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (cipher & WPA_CIPHER_TKIP) {
- pos += snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sTKIP",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (cipher & WPA_CIPHER_WEP104) {
- pos += snprintf(pos, end - pos, "%sWEP104", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sWEP104",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (cipher & WPA_CIPHER_WEP40) {
- pos += snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sWEP40",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (cipher & WPA_CIPHER_NONE) {
- pos += snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sNONE",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
return buf;
@@ -670,7 +730,7 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
int val = 0, last, errors = 0;
char *start, *end, *buf;
- buf = strdup(value);
+ buf = os_strdup(value);
if (buf == NULL)
return -1;
start = buf;
@@ -685,11 +745,11 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
end++;
last = *end == '\0';
*end = '\0';
- if (strcmp(start, "OPEN") == 0)
+ if (os_strcmp(start, "OPEN") == 0)
val |= WPA_AUTH_ALG_OPEN;
- else if (strcmp(start, "SHARED") == 0)
+ else if (os_strcmp(start, "SHARED") == 0)
val |= WPA_AUTH_ALG_SHARED;
- else if (strcmp(start, "LEAP") == 0)
+ else if (os_strcmp(start, "LEAP") == 0)
val |= WPA_AUTH_ALG_LEAP;
else {
wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
@@ -701,7 +761,7 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
break;
start = end + 1;
}
- free(buf);
+ os_free(buf);
if (val == 0) {
wpa_printf(MSG_ERROR,
@@ -718,44 +778,59 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
static char * wpa_config_write_auth_alg(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- int first = 1;
char *buf, *pos, *end;
+ int ret;
- pos = buf = malloc(30);
+ pos = buf = os_zalloc(30);
if (buf == NULL)
return NULL;
- memset(buf, 0, 30);
end = buf + 30;
if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
- pos += snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sOPEN",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
- pos += snprintf(pos, end - pos, "%sSHARED", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sSHARED",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
- pos += snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
- first = 0;
+ ret = os_snprintf(pos, end - pos, "%sLEAP",
+ pos == buf ? "" : " ");
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return buf;
+ }
+ pos += ret;
}
return buf;
}
+#ifdef IEEE8021X_EAPOL
static int wpa_config_parse_eap(const struct parse_data *data,
struct wpa_ssid *ssid, int line,
const char *value)
{
int last, errors = 0;
char *start, *end, *buf;
- u8 *methods = NULL, *tmp;
+ struct eap_method_type *methods = NULL, *tmp;
size_t num_methods = 0;
- buf = strdup(value);
+ buf = os_strdup(value);
if (buf == NULL)
return -1;
start = buf;
@@ -771,13 +846,17 @@ static int wpa_config_parse_eap(const struct parse_data *data,
last = *end == '\0';
*end = '\0';
tmp = methods;
- methods = realloc(methods, num_methods + 1);
+ methods = os_realloc(methods,
+ (num_methods + 1) * sizeof(*methods));
if (methods == NULL) {
- free(tmp);
+ os_free(tmp);
+ os_free(buf);
return -1;
}
- methods[num_methods] = eap_get_type(start);
- if (methods[num_methods] == EAP_TYPE_NONE) {
+ methods[num_methods].method = eap_get_type(
+ start, &methods[num_methods].vendor);
+ if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
+ methods[num_methods].method == EAP_TYPE_NONE) {
wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
"'%s'", line, start);
wpa_printf(MSG_ERROR, "You may need to add support for"
@@ -785,7 +864,8 @@ static int wpa_config_parse_eap(const struct parse_data *data,
"build time configuration.\n"
"See README for more information.");
errors++;
- } else if (methods[num_methods] == EAP_TYPE_LEAP)
+ } else if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
+ methods[num_methods].method == EAP_TYPE_LEAP)
ssid->leap++;
else
ssid->non_leap++;
@@ -794,18 +874,20 @@ static int wpa_config_parse_eap(const struct parse_data *data,
break;
start = end + 1;
}
- free(buf);
+ os_free(buf);
tmp = methods;
- methods = realloc(methods, num_methods + 1);
+ methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
if (methods == NULL) {
- free(tmp);
+ os_free(tmp);
return -1;
}
- methods[num_methods] = EAP_TYPE_NONE;
+ methods[num_methods].vendor = EAP_VENDOR_IETF;
+ methods[num_methods].method = EAP_TYPE_NONE;
num_methods++;
- wpa_hexdump(MSG_MSGDUMP, "eap methods", methods, num_methods);
+ wpa_hexdump(MSG_MSGDUMP, "eap methods",
+ (u8 *) methods, num_methods * sizeof(*methods));
ssid->eap_methods = methods;
return errors ? -1 : 0;
}
@@ -814,31 +896,37 @@ static int wpa_config_parse_eap(const struct parse_data *data,
static char * wpa_config_write_eap(const struct parse_data *data,
struct wpa_ssid *ssid)
{
- int first = 1;
+ int i, ret;
char *buf, *pos, *end;
- const u8 *eap_methods = ssid->eap_methods;
+ const struct eap_method_type *eap_methods = ssid->eap_methods;
const char *name;
if (eap_methods == NULL)
return NULL;
- pos = buf = malloc(100);
+ pos = buf = os_zalloc(100);
if (buf == NULL)
return NULL;
- memset(buf, 0, 100);
end = buf + 100;
- while (*eap_methods != EAP_TYPE_NONE) {
- name = eap_get_name(*eap_methods);
- if (name)
- pos += snprintf(pos, end - pos, "%s%s",
- first ? "" : " ", name);
- first = 0;
- eap_methods++;
+ for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF ||
+ eap_methods[i].method != EAP_TYPE_NONE; i++) {
+ name = eap_get_name(eap_methods[i].vendor,
+ eap_methods[i].method);
+ if (name) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ pos == buf ? "" : " ", name);
+ if (ret < 0 || ret >= end - pos)
+ break;
+ pos += ret;
+ }
}
+ end[-1] = '\0';
+
return buf;
}
+#endif /* IEEE8021X_EAPOL */
static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
@@ -855,12 +943,12 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
if (*len > MAX_WEP_KEY_LEN) {
wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
line, idx, value);
- free(buf);
+ os_free(buf);
return -1;
}
- memcpy(key, buf, *len);
- free(buf);
- snprintf(title, sizeof(title), "wep_key%d", idx);
+ os_memcpy(key, buf, *len);
+ os_free(buf);
+ os_snprintf(title, sizeof(title), "wep_key%d", idx);
wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
return 0;
}
@@ -945,42 +1033,50 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data,
/* Helper macros for network block parser */
+#ifdef OFFSET
+#undef OFFSET
+#endif /* OFFSET */
/* OFFSET: Get offset of a variable within the wpa_ssid structure */
#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
/* STR: Define a string variable for an ASCII string; f = field name */
-#define STR(f) .name = #f, .parser = wpa_config_parse_str, \
- .writer = wpa_config_write_str, .param1 = OFFSET(f)
+#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
+#define STR(f) _STR(f), NULL, NULL, NULL, 0
+#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
/* STR_LEN: Define a string variable with a separate variable for storing the
* data length. Unlike STR(), this can be used to store arbitrary binary data
* (i.e., even nul termination character). */
-#define STR_LEN(f) STR(f), .param2 = OFFSET(f ## _len)
+#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
+#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
+#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
* explicitly specified. */
-#define STR_RANGE(f, min, max) STR_LEN(f), .param3 = (void *) (min), \
- .param4 = (void *) (max)
+#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max)
+#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0
+#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1
+#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
+ OFFSET(f), (void *) 0
/* INT: Define an integer variable */
-#define INT(f) .name = #f, .parser = wpa_config_parse_int, \
- .writer = wpa_config_write_int, \
- .param1 = OFFSET(f), .param2 = (void *) 0
+#define INT(f) _INT(f), NULL, NULL, 0
-/* INT: Define an integer variable with allowed value range */
-#define INT_RANGE(f, min, max) INT(f), .param3 = (void *) (min), \
- .param4 = (void *) (max)
+/* INT_RANGE: Define an integer variable with allowed value range */
+#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
/* FUNC: Define a configuration variable that uses a custom function for
* parsing and writing the value. */
-#define FUNC(f) .name = #f, .parser = wpa_config_parse_ ## f, \
- .writer = wpa_config_write_ ## f
+#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \
+ NULL, NULL, NULL, NULL
+#define FUNC(f) _FUNC(f), 0
+#define FUNC_KEY(f) _FUNC(f), 1
/*
* Table of network configuration variables. This table is used to parse each
* network configuration variable, e.g., each line in wpa_supplicant.conf file
- * that is insider a network block.
+ * that is inside a network block.
*
* This table is generated using the helper macros defined above and with
* generous help from the C pre-processor. The field name is stored as a string
@@ -995,31 +1091,33 @@ static char * wpa_config_write_wep_key3(const struct parse_data *data,
* function (.parser) is then called to parse the actual value of the field.
*
* This kind of mechanism makes it easy to add new configuration parameters,
- * since only one line needs to be added into this table and in struct wpa_ssid
- * definitions if the new variable is either a string or integer. More complex
- * types will need to use their own parser and writer functions.
+ * since only one line needs to be added into this table and into the
+ * struct wpa_ssid definition if the new variable is either a string or
+ * integer. More complex types will need to use their own parser and writer
+ * functions.
*/
static const struct parse_data ssid_fields[] = {
{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
- { FUNC(psk), .key_data = 1 },
+ { FUNC_KEY(psk) },
{ FUNC(proto) },
{ FUNC(key_mgmt) },
{ FUNC(pairwise) },
{ FUNC(group) },
{ FUNC(auth_alg) },
+#ifdef IEEE8021X_EAPOL
{ FUNC(eap) },
{ STR_LEN(identity) },
{ STR_LEN(anonymous_identity) },
- { STR_RANGE(eappsk, EAP_PSK_LEN, EAP_PSK_LEN), .key_data = 1 },
+ { STR_RANGE_KEY(eappsk, EAP_PSK_LEN_MIN, EAP_PSK_LEN_MAX) },
{ STR_LEN(nai) },
- { STR_LEN(password), .key_data = 1 },
+ { STR_LEN_KEY(password) },
{ STR(ca_cert) },
{ STR(ca_path) },
{ STR(client_cert) },
{ STR(private_key) },
- { STR(private_key_passwd), .key_data = 1 },
+ { STR_KEY(private_key_passwd) },
{ STR(dh_file) },
{ STR(subject_match) },
{ STR(altsubject_match) },
@@ -1027,44 +1125,64 @@ static const struct parse_data ssid_fields[] = {
{ STR(ca_path2) },
{ STR(client_cert2) },
{ STR(private_key2) },
- { STR(private_key2_passwd), .key_data = 1 },
+ { STR_KEY(private_key2_passwd) },
{ STR(dh_file2) },
{ STR(subject_match2) },
{ STR(altsubject_match2) },
{ STR(phase1) },
{ STR(phase2) },
{ STR(pcsc) },
- { STR(pin), .key_data = 1 },
+ { STR_KEY(pin) },
{ STR(engine_id) },
{ STR(key_id) },
{ INT(engine) },
{ INT(eapol_flags) },
- { FUNC(wep_key0), .key_data = 1 },
- { FUNC(wep_key1), .key_data = 1 },
- { FUNC(wep_key2), .key_data = 1 },
- { FUNC(wep_key3), .key_data = 1 },
+#endif /* IEEE8021X_EAPOL */
+ { FUNC_KEY(wep_key0) },
+ { FUNC_KEY(wep_key1) },
+ { FUNC_KEY(wep_key2) },
+ { FUNC_KEY(wep_key3) },
{ INT(wep_tx_keyidx) },
{ INT(priority) },
+#ifdef IEEE8021X_EAPOL
{ INT(eap_workaround) },
{ STR(pac_file) },
+ { INT(fragment_size) },
+#endif /* IEEE8021X_EAPOL */
{ INT_RANGE(mode, 0, 1) },
{ INT_RANGE(proactive_key_caching, 0, 1) },
{ INT_RANGE(disabled, 0, 1) },
+ { STR(id_str) },
+#ifdef CONFIG_IEEE80211W
+ { INT_RANGE(ieee80211w, 0, 2) },
+#endif /* CONFIG_IEEE80211W */
+ { INT_RANGE(peerkey, 0, 1) },
+ { INT_RANGE(mixed_cell, 0, 1) }
};
#undef OFFSET
+#undef _STR
#undef STR
+#undef STR_KEY
+#undef _STR_LEN
#undef STR_LEN
+#undef STR_LEN_KEY
+#undef _STR_RANGE
#undef STR_RANGE
+#undef STR_RANGE_KEY
+#undef _INT
#undef INT
#undef INT_RANGE
+#undef _FUNC
#undef FUNC
+#undef FUNC_KEY
#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
/**
* wpa_config_add_prio_network - Add a network to priority lists
* @config: Configuration data from wpa_config_read()
+ * @ssid: Pointer to the network configuration to be added to the list
* Returns: 0 on success, -1 on failure
*
* This function is used to add a network block to the priority list of
@@ -1078,6 +1196,10 @@ int wpa_config_add_prio_network(struct wpa_config *config,
int prio;
struct wpa_ssid *prev, **nlist;
+ /*
+ * Add to an existing priority list if one is available for the
+ * configured priority level for this network.
+ */
for (prio = 0; prio < config->num_prio; prio++) {
prev = config->pssid[prio];
if (prev->priority == ssid->priority) {
@@ -1088,9 +1210,9 @@ int wpa_config_add_prio_network(struct wpa_config *config,
}
}
- /* First network for this priority - add new priority list */
- nlist = realloc(config->pssid,
- (config->num_prio + 1) * sizeof(struct wpa_ssid *));
+ /* First network for this priority - add a new priority list */
+ nlist = os_realloc(config->pssid,
+ (config->num_prio + 1) * sizeof(struct wpa_ssid *));
if (nlist == NULL)
return -1;
@@ -1099,8 +1221,8 @@ int wpa_config_add_prio_network(struct wpa_config *config,
break;
}
- memmove(&nlist[prio + 1], &nlist[prio],
- (config->num_prio - prio) * sizeof(struct wpa_ssid *));
+ os_memmove(&nlist[prio + 1], &nlist[prio],
+ (config->num_prio - prio) * sizeof(struct wpa_ssid *));
nlist[prio] = ssid;
config->num_prio++;
@@ -1124,7 +1246,7 @@ static int wpa_config_update_prio_list(struct wpa_config *config)
struct wpa_ssid *ssid;
int ret = 0;
- free(config->pssid);
+ os_free(config->pssid);
config->pssid = NULL;
config->num_prio = 0;
@@ -1144,46 +1266,49 @@ static int wpa_config_update_prio_list(struct wpa_config *config)
* wpa_config_free_ssid - Free network/ssid configuration data
* @ssid: Configuration data for the network
*
- * This function frees all resources allocated for the netowkr configuration
+ * This function frees all resources allocated for the network configuration
* data.
*/
void wpa_config_free_ssid(struct wpa_ssid *ssid)
{
- free(ssid->ssid);
- free(ssid->passphrase);
- free(ssid->eap_methods);
- free(ssid->identity);
- free(ssid->anonymous_identity);
- free(ssid->eappsk);
- free(ssid->nai);
- free(ssid->password);
- free(ssid->ca_cert);
- free(ssid->ca_path);
- free(ssid->client_cert);
- free(ssid->private_key);
- free(ssid->private_key_passwd);
- free(ssid->dh_file);
- free(ssid->subject_match);
- free(ssid->altsubject_match);
- free(ssid->ca_cert2);
- free(ssid->ca_path2);
- free(ssid->client_cert2);
- free(ssid->private_key2);
- free(ssid->private_key2_passwd);
- free(ssid->dh_file2);
- free(ssid->subject_match2);
- free(ssid->altsubject_match2);
- free(ssid->phase1);
- free(ssid->phase2);
- free(ssid->pcsc);
- free(ssid->pin);
- free(ssid->engine_id);
- free(ssid->key_id);
- free(ssid->otp);
- free(ssid->pending_req_otp);
- free(ssid->pac_file);
- free(ssid->new_password);
- free(ssid);
+ os_free(ssid->ssid);
+ os_free(ssid->passphrase);
+#ifdef IEEE8021X_EAPOL
+ os_free(ssid->eap_methods);
+ os_free(ssid->identity);
+ os_free(ssid->anonymous_identity);
+ os_free(ssid->eappsk);
+ os_free(ssid->nai);
+ os_free(ssid->password);
+ os_free(ssid->ca_cert);
+ os_free(ssid->ca_path);
+ os_free(ssid->client_cert);
+ os_free(ssid->private_key);
+ os_free(ssid->private_key_passwd);
+ os_free(ssid->dh_file);
+ os_free(ssid->subject_match);
+ os_free(ssid->altsubject_match);
+ os_free(ssid->ca_cert2);
+ os_free(ssid->ca_path2);
+ os_free(ssid->client_cert2);
+ os_free(ssid->private_key2);
+ os_free(ssid->private_key2_passwd);
+ os_free(ssid->dh_file2);
+ os_free(ssid->subject_match2);
+ os_free(ssid->altsubject_match2);
+ os_free(ssid->phase1);
+ os_free(ssid->phase2);
+ os_free(ssid->pcsc);
+ os_free(ssid->pin);
+ os_free(ssid->engine_id);
+ os_free(ssid->key_id);
+ os_free(ssid->otp);
+ os_free(ssid->pending_req_otp);
+ os_free(ssid->pac_file);
+ os_free(ssid->new_password);
+#endif /* IEEE8021X_EAPOL */
+ os_free(ssid->id_str);
+ os_free(ssid);
}
@@ -1213,37 +1338,43 @@ void wpa_config_free(struct wpa_config *config)
wpa_config_free_blob(prevblob);
}
- free(config->ctrl_interface);
- free(config->opensc_engine_path);
- free(config->pkcs11_engine_path);
- free(config->pkcs11_module_path);
- free(config->driver_param);
- free(config->pssid);
- free(config);
+ os_free(config->ctrl_interface);
+ os_free(config->ctrl_interface_group);
+ os_free(config->opensc_engine_path);
+ os_free(config->pkcs11_engine_path);
+ os_free(config->pkcs11_module_path);
+ os_free(config->driver_param);
+ os_free(config->pssid);
+ os_free(config);
}
+#ifdef IEEE8021X_EAPOL
/**
* wpa_config_allowed_eap_method - Check whether EAP method is allowed
- * @ssid: Pointer to a configuration data
+ * @ssid: Pointer to configuration data
+ * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
* @method: EAP type
* Returns: 1 = allowed EAP method, 0 = not allowed
*/
-int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method)
+int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int vendor,
+ u32 method)
{
- u8 *pos;
+ int i;
+ struct eap_method_type *m;
if (ssid == NULL || ssid->eap_methods == NULL)
return 1;
- pos = ssid->eap_methods;
- while (*pos != EAP_TYPE_NONE) {
- if (*pos == method)
+ m = ssid->eap_methods;
+ for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
+ m[i].method != EAP_TYPE_NONE; i++) {
+ if (m[i].vendor == vendor && m[i].method == method)
return 1;
- pos++;
}
return 0;
}
+#endif /* IEEE8021X_EAPOL */
/**
@@ -1287,10 +1418,9 @@ struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
}
id++;
- ssid = malloc(sizeof(*ssid));
+ ssid = os_zalloc(sizeof(*ssid));
if (ssid == NULL)
return NULL;
- memset(ssid, 0, sizeof(*ssid));
ssid->id = id;
if (last)
last->next = ssid;
@@ -1337,7 +1467,7 @@ int wpa_config_remove_network(struct wpa_config *config, int id)
/**
* wpa_config_set_network_defaults - Set network default values
- * @ssid: Pointer to a network configuration data
+ * @ssid: Pointer to network configuration data
*/
void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
{
@@ -1345,14 +1475,17 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
ssid->pairwise_cipher = DEFAULT_PAIRWISE;
ssid->group_cipher = DEFAULT_GROUP;
ssid->key_mgmt = DEFAULT_KEY_MGMT;
+#ifdef IEEE8021X_EAPOL
ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
+ ssid->fragment_size = DEFAULT_FRAGMENT_SIZE;
+#endif /* IEEE8021X_EAPOL */
}
/**
* wpa_config_set - Set a variable in network configuration
- * @ssid: Pointer to a network configuration data
+ * @ssid: Pointer to network configuration data
* @var: Variable name, e.g., "ssid"
* @value: Variable value
* @line: Line number in configuration file or 0 if not used
@@ -1366,14 +1499,15 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
int line)
{
- int i, ret = 0;
+ size_t i;
+ int ret = 0;
if (ssid == NULL || var == NULL || value == NULL)
return -1;
for (i = 0; i < NUM_SSID_FIELDS; i++) {
const struct parse_data *field = &ssid_fields[i];
- if (strcmp(var, field->name) != 0)
+ if (os_strcmp(var, field->name) != 0)
continue;
if (field->parser(field, ssid, line, value)) {
@@ -1399,7 +1533,7 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
/**
* wpa_config_get - Get a variable in network configuration
- * @ssid: Pointer to a network configuration data
+ * @ssid: Pointer to network configuration data
* @var: Variable name, e.g., "ssid"
* Returns: Value of the variable or %NULL on failure
*
@@ -1411,14 +1545,14 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
*/
char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
{
- int i;
+ size_t i;
if (ssid == NULL || var == NULL)
return NULL;
for (i = 0; i < NUM_SSID_FIELDS; i++) {
const struct parse_data *field = &ssid_fields[i];
- if (strcmp(var, field->name) == 0)
+ if (os_strcmp(var, field->name) == 0)
return field->writer(field, ssid);
}
@@ -1427,8 +1561,55 @@ char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
/**
+ * wpa_config_get_no_key - Get a variable in network configuration (no keys)
+ * @ssid: Pointer to network configuration data
+ * @var: Variable name, e.g., "ssid"
+ * Returns: Value of the variable or %NULL on failure
+ *
+ * This function can be used to get network configuration variable like
+ * wpa_config_get(). The only difference is that this functions does not expose
+ * key/password material from the configuration. In case a key/password field
+ * is requested, the returned value is an empty string or %NULL if the variable
+ * is not set or "*" if the variable is set (regardless of its value). The
+ * returned value is a copy of the configuration variable in text format, i.e,.
+ * the same format that the text-based configuration file and wpa_config_set()
+ * are using for the value. The caller is responsible for freeing the returned
+ * value.
+ */
+char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
+{
+ size_t i;
+
+ if (ssid == NULL || var == NULL)
+ return NULL;
+
+ for (i = 0; i < NUM_SSID_FIELDS; i++) {
+ const struct parse_data *field = &ssid_fields[i];
+ if (os_strcmp(var, field->name) == 0) {
+ char *res = field->writer(field, ssid);
+ if (field->key_data) {
+ if (res && res[0]) {
+ wpa_printf(MSG_DEBUG, "Do not allow "
+ "key_data field to be "
+ "exposed");
+ os_free(res);
+ return os_strdup("*");
+ }
+
+ os_free(res);
+ return NULL;
+ }
+ return res;
+ }
+ }
+
+ return NULL;
+}
+
+
+/**
* wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
- * @ssid: Pointer to a network configuration data
+ * @ssid: Pointer to network configuration data
*
* This function must be called to update WPA PSK when either SSID or the
* passphrase has changed for the network configuration.
@@ -1456,7 +1637,7 @@ const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
struct wpa_config_blob *blob = config->blobs;
while (blob) {
- if (strcmp(blob->name, name) == 0)
+ if (os_strcmp(blob->name, name) == 0)
return blob;
blob = blob->next;
}
@@ -1488,9 +1669,9 @@ void wpa_config_set_blob(struct wpa_config *config,
void wpa_config_free_blob(struct wpa_config_blob *blob)
{
if (blob) {
- free(blob->name);
- free(blob->data);
- free(blob);
+ os_free(blob->name);
+ os_free(blob->data);
+ os_free(blob);
}
}
@@ -1506,7 +1687,7 @@ int wpa_config_remove_blob(struct wpa_config *config, const char *name)
struct wpa_config_blob *pos = config->blobs, *prev = NULL;
while (pos) {
- if (strcmp(pos->name, name) == 0) {
+ if (os_strcmp(pos->name, name) == 0) {
if (prev)
prev->next = pos->next;
else
@@ -1534,18 +1715,42 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
{
struct wpa_config *config;
- config = malloc(sizeof(*config));
+ config = os_zalloc(sizeof(*config));
if (config == NULL)
return NULL;
- memset(config, 0, sizeof(*config));
config->eapol_version = DEFAULT_EAPOL_VERSION;
config->ap_scan = DEFAULT_AP_SCAN;
config->fast_reauth = DEFAULT_FAST_REAUTH;
if (ctrl_interface)
- config->ctrl_interface = strdup(ctrl_interface);
+ config->ctrl_interface = os_strdup(ctrl_interface);
if (driver_param)
- config->driver_param = strdup(driver_param);
+ config->driver_param = os_strdup(driver_param);
return config;
}
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+/**
+ * wpa_config_debug_dump_networks - Debug dump of configured networks
+ * @config: Configuration data from wpa_config_read()
+ */
+void wpa_config_debug_dump_networks(struct wpa_config *config)
+{
+ int prio;
+ struct wpa_ssid *ssid;
+
+ for (prio = 0; prio < config->num_prio; prio++) {
+ ssid = config->pssid[prio];
+ wpa_printf(MSG_DEBUG, "Priority group %d",
+ ssid->priority);
+ while (ssid) {
+ wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
+ ssid->id,
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ ssid = ssid->pnext;
+ }
+ }
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
diff --git a/contrib/wpa_supplicant/config.h b/contrib/wpa_supplicant/config.h
index bd479b6b4fb4..3852f9274e2b 100644
--- a/contrib/wpa_supplicant/config.h
+++ b/contrib/wpa_supplicant/config.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration file structures
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,12 +15,6 @@
#ifndef CONFIG_H
#define CONFIG_H
-#ifdef CONFIG_CTRL_IFACE
-#ifndef CONFIG_CTRL_IFACE_UDP
-#include <grp.h>
-#endif /* CONFIG_CTRL_IFACE_UDP */
-#endif /* CONFIG_CTRL_IFACE */
-
#define DEFAULT_EAPOL_VERSION 1
#define DEFAULT_AP_SCAN 1
#define DEFAULT_FAST_REAUTH 1
@@ -128,45 +122,67 @@ struct wpa_config {
int ap_scan;
/**
- * ctrl_interface - Directory for UNIX domain sockets
+ * ctrl_interface - Parameters for the control interface
*
- * This variable is used to configure where the UNIX domain sockets
- * for the control interface are created. If UDP-based ctrl_iface is
- * used, this variable can be set to any string (i.e., %NULL is not
- * allowed).
- */
- char *ctrl_interface;
-
-#ifdef CONFIG_CTRL_IFACE
-#ifndef CONFIG_CTRL_IFACE_UDP
- /**
- * ctrl_interface_gid - Group identity for the UNIX domain sockets
+ * If this is specified, %wpa_supplicant will open a control interface
+ * that is available for external programs to manage %wpa_supplicant.
+ * The meaning of this string depends on which control interface
+ * mechanism is used. For all cases, the existance of this parameter
+ * in configuration is used to determine whether the control interface
+ * is enabled.
+ *
+ * For UNIX domain sockets (default on Linux and BSD): This is a
+ * directory that will be created for UNIX domain sockets for listening
+ * to requests from external programs (CLI/GUI, etc.) for status
+ * information and configuration. The socket file will be named based
+ * on the interface name, so multiple %wpa_supplicant processes can be
+ * run at the same time if more than one interface is used.
+ * /var/run/wpa_supplicant is the recommended directory for sockets and
+ * by default, wpa_cli will use it when trying to connect with
+ * %wpa_supplicant.
*
* Access control for the control interface can be configured
* by setting the directory to allow only members of a group
* to use sockets. This way, it is possible to run
- * wpa_supplicant as root (since it needs to change network
+ * %wpa_supplicant as root (since it needs to change network
* configuration and open raw sockets) and still allow GUI/CLI
* components to be run as non-root users. However, since the
* control interface can be used to change the network
* configuration, this access needs to be protected in many
- * cases. By default, wpa_supplicant is configured to use gid
+ * cases. By default, %wpa_supplicant is configured to use gid
* 0 (root). If you want to allow non-root users to use the
* control interface, add a new group and change this value to
* match with that group. Add users that should have control
* interface access to this group.
+ *
+ * When configuring both the directory and group, use following format:
+ * DIR=/var/run/wpa_supplicant GROUP=wheel
+ * DIR=/var/run/wpa_supplicant GROUP=0
+ * (group can be either group name or gid)
+ *
+ * For UDP connections (default on Windows): The value will be ignored.
+ * This variable is just used to select that the control interface is
+ * to be created. The value can be set to, e.g., udp
+ * (ctrl_interface=udp).
+ *
+ * For Windows Named Pipe: This value can be used to set the security
+ * descriptor for controlling access to the control interface. Security
+ * descriptor can be set using Security Descriptor String Format (see
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/security_descriptor_string_format.asp).
+ * The descriptor string needs to be prefixed with SDDL=. For example,
+ * ctrl_interface=SDDL=D: would set an empty DACL (which will reject
+ * all connections).
*/
- gid_t ctrl_interface_gid;
-#endif /* CONFIG_CTRL_IFACE_UDP */
+ char *ctrl_interface;
+
/**
- * ctrl_interface_gid_set - Whether ctrl_interface_gid is used
+ * ctrl_interface_group - Control interface group (DEPRECATED)
*
- * If this variable is zero, ctrl_interface_gid value is not used and
- * group will not be changed from the value it got by default
- * when the directory or socket was created.
+ * This variable is only used for backwards compatibility. Group for
+ * UNIX domain sockets should now be specified using GROUP=<group> in
+ * ctrl_interface variable.
*/
- int ctrl_interface_gid_set;
-#endif /* CONFIG_CTRL_IFACE */
+ char *ctrl_interface_group;
/**
* fast_reauth - EAP fast re-authentication (session resumption)
@@ -257,7 +273,7 @@ struct wpa_config {
};
-/* Protypes for common functions from config.c */
+/* Prototypes for common functions from config.c */
void wpa_config_free(struct wpa_config *ssid);
void wpa_config_free_ssid(struct wpa_ssid *ssid);
@@ -268,6 +284,7 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid);
int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
int line);
char * wpa_config_get(struct wpa_ssid *ssid, const char *var);
+char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var);
void wpa_config_update_psk(struct wpa_ssid *ssid);
int wpa_config_add_prio_network(struct wpa_config *config,
struct wpa_ssid *ssid);
@@ -280,6 +297,11 @@ void wpa_config_free_blob(struct wpa_config_blob *blob);
int wpa_config_remove_blob(struct wpa_config *config, const char *name);
struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
const char *driver_param);
+#ifndef CONFIG_NO_STDOUT_DEBUG
+void wpa_config_debug_dump_networks(struct wpa_config *config);
+#else /* CONFIG_NO_STDOUT_DEBUG */
+#define wpa_config_debug_dump_networks(c) do { } while (0)
+#endif /* CONFIG_NO_STDOUT_DEBUG */
/* Prototypes for backend specific functions from the selected config_*.c */
diff --git a/contrib/wpa_supplicant/config_file.c b/contrib/wpa_supplicant/config_file.c
index b203893d7547..757a1b8b1d6b 100644
--- a/contrib/wpa_supplicant/config_file.c
+++ b/contrib/wpa_supplicant/config_file.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Configuration backend: text file
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,18 +16,30 @@
* described in the sample configuration file, wpa_supplicant.conf.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
-#include "wpa.h"
-#include "wpa_supplicant.h"
#include "config.h"
#include "base64.h"
-
-
-static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line)
+#include "eap_methods.h"
+
+
+/**
+ * wpa_config_get_line - Read the next configuration file line
+ * @s: Buffer for the line
+ * @size: The buffer length
+ * @stream: File stream to read from
+ * @line: Pointer to a variable storing the file line number
+ * @_pos: Buffer for the pointer to the beginning of data on the text line or
+ * %NULL if not needed (returned value used instead)
+ * Returns: Pointer to the beginning of data on the text line or %NULL if no
+ * more text lines are available.
+ *
+ * This function reads the next non-empty line from the configuration file and
+ * removes comments. The returned string is guaranteed to be null-terminated.
+ */
+static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line,
+ char **_pos)
{
char *pos, *end, *sstart;
@@ -36,39 +48,82 @@ static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line)
s[size - 1] = '\0';
pos = s;
+ /* Skip white space from the beginning of line. */
while (*pos == ' ' || *pos == '\t' || *pos == '\r')
pos++;
- if (*pos == '#' || *pos == '\n' || *pos == '\0' ||
- *pos == '\r')
+
+ /* Skip comment lines and empty lines */
+ if (*pos == '#' || *pos == '\n' || *pos == '\0')
continue;
- /* Remove # comments unless they are within a double quoted
- * string. Remove trailing white space. */
- sstart = strchr(pos, '"');
+ /*
+ * Remove # comments unless they are within a double quoted
+ * string.
+ */
+ sstart = os_strchr(pos, '"');
if (sstart)
- sstart = strrchr(sstart + 1, '"');
+ sstart = os_strrchr(sstart + 1, '"');
if (!sstart)
sstart = pos;
- end = strchr(sstart, '#');
+ end = os_strchr(sstart, '#');
if (end)
*end-- = '\0';
else
- end = pos + strlen(pos) - 1;
+ end = pos + os_strlen(pos) - 1;
+
+ /* Remove trailing white space. */
while (end > pos &&
(*end == '\n' || *end == ' ' || *end == '\t' ||
- *end == '\r')) {
+ *end == '\r'))
*end-- = '\0';
- }
+
if (*pos == '\0')
continue;
+ if (_pos)
+ *_pos = pos;
return pos;
}
+ if (_pos)
+ *_pos = NULL;
return NULL;
}
+static int wpa_config_validate_network(struct wpa_ssid *ssid, int line)
+{
+ int errors = 0;
+
+ if (ssid->passphrase) {
+ if (ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "Line %d: both PSK and "
+ "passphrase configured.", line);
+ errors++;
+ }
+ wpa_config_update_psk(ssid);
+ }
+
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
+ "management, but no PSK configured.", line);
+ errors++;
+ }
+
+ if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+ /* Group cipher cannot be stronger than the pairwise cipher. */
+ wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
+ " list since it was not allowed for pairwise "
+ "cipher", line);
+ ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+ }
+
+ return errors;
+}
+
+
static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
{
struct wpa_ssid *ssid;
@@ -77,21 +132,20 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
*line);
- ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
+ ssid = os_zalloc(sizeof(*ssid));
if (ssid == NULL)
return NULL;
- memset(ssid, 0, sizeof(*ssid));
ssid->id = id;
wpa_config_set_network_defaults(ssid);
- while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
- if (strcmp(pos, "}") == 0) {
+ while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
+ if (os_strcmp(pos, "}") == 0) {
end = 1;
break;
}
- pos2 = strchr(pos, '=');
+ pos2 = os_strchr(pos, '=');
if (pos2 == NULL) {
wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
"'%s'.", *line, pos);
@@ -101,7 +155,7 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
*pos2++ = '\0';
if (*pos2 == '"') {
- if (strchr(pos2 + 1, '"') == NULL) {
+ if (os_strchr(pos2 + 1, '"') == NULL) {
wpa_printf(MSG_ERROR, "Line %d: invalid "
"quotation '%s'.", *line, pos2);
errors++;
@@ -119,32 +173,10 @@ static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
errors++;
}
- if (ssid->passphrase) {
- if (ssid->psk_set) {
- wpa_printf(MSG_ERROR, "Line %d: both PSK and "
- "passphrase configured.", *line);
- errors++;
- }
- wpa_config_update_psk(ssid);
- }
-
- if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
- wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
- "management, but no PSK configured.", *line);
- errors++;
- }
-
- if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
- !(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) {
- /* Group cipher cannot be stronger than the pairwise cipher. */
- wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
- " list since it was not allowed for pairwise "
- "cipher", *line);
- ssid->group_cipher &= ~WPA_CIPHER_CCMP;
- }
+ errors += wpa_config_validate_network(ssid, *line);
if (errors) {
- free(ssid);
+ wpa_config_free_ssid(ssid);
ssid = NULL;
}
@@ -164,41 +196,40 @@ static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new named blob '%s'",
*line, name);
- while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
- if (strcmp(pos, "}") == 0) {
+ while (wpa_config_get_line(buf, sizeof(buf), f, line, &pos)) {
+ if (os_strcmp(pos, "}") == 0) {
end = 1;
break;
}
- len = strlen(pos);
- nencoded = realloc(encoded, encoded_len + len);
+ len = os_strlen(pos);
+ nencoded = os_realloc(encoded, encoded_len + len);
if (nencoded == NULL) {
wpa_printf(MSG_ERROR, "Line %d: not enough memory for "
"blob", *line);
- free(encoded);
+ os_free(encoded);
return NULL;
}
encoded = nencoded;
- memcpy(encoded + encoded_len, pos, len);
+ os_memcpy(encoded + encoded_len, pos, len);
encoded_len += len;
}
if (!end) {
wpa_printf(MSG_ERROR, "Line %d: blob was not terminated "
"properly", *line);
- free(encoded);
+ os_free(encoded);
return NULL;
}
- blob = malloc(sizeof(*blob));
+ blob = os_zalloc(sizeof(*blob));
if (blob == NULL) {
- free(encoded);
+ os_free(encoded);
return NULL;
}
- memset(blob, 0, sizeof(*blob));
- blob->name = strdup(name);
+ blob->name = os_strdup(name);
blob->data = base64_decode(encoded, encoded_len, &blob->len);
- free(encoded);
+ os_free(encoded);
if (blob->name == NULL || blob->data == NULL) {
wpa_config_free_blob(blob);
@@ -216,7 +247,7 @@ struct wpa_config * wpa_config_read(const char *name)
int errors = 0, line = 0;
struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
struct wpa_config *config;
- int id = 0, prio;
+ int id = 0;
config = wpa_config_alloc_empty(NULL, NULL);
if (config == NULL)
@@ -224,12 +255,12 @@ struct wpa_config * wpa_config_read(const char *name)
wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
f = fopen(name, "r");
if (f == NULL) {
- free(config);
+ os_free(config);
return NULL;
}
- while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) {
- if (strcmp(pos, "network={") == 0) {
+ while (wpa_config_get_line(buf, sizeof(buf), f, &line, &pos)) {
+ if (os_strcmp(pos, "network={") == 0) {
ssid = wpa_config_read_network(f, &line, id++);
if (ssid == NULL) {
wpa_printf(MSG_ERROR, "Line %d: failed to "
@@ -250,11 +281,11 @@ struct wpa_config * wpa_config_read(const char *name)
errors++;
continue;
}
- } else if (strncmp(pos, "blob-base64-", 12) == 0) {
- char *name = pos + 12, *name_end;
+ } else if (os_strncmp(pos, "blob-base64-", 12) == 0) {
+ char *bname = pos + 12, *name_end;
struct wpa_config_blob *blob;
- name_end = strchr(name, '=');
+ name_end = os_strchr(bname, '=');
if (name_end == NULL) {
wpa_printf(MSG_ERROR, "Line %d: no blob name "
"terminator", line);
@@ -263,51 +294,28 @@ struct wpa_config * wpa_config_read(const char *name)
}
*name_end = '\0';
- blob = wpa_config_read_blob(f, &line, name);
+ blob = wpa_config_read_blob(f, &line, bname);
if (blob == NULL) {
wpa_printf(MSG_ERROR, "Line %d: failed to read"
- " blob %s", line, name);
+ " blob %s", line, bname);
errors++;
continue;
}
wpa_config_set_blob(config, blob);
#ifdef CONFIG_CTRL_IFACE
- } else if (strncmp(pos, "ctrl_interface=", 15) == 0) {
- free(config->ctrl_interface);
- config->ctrl_interface = strdup(pos + 15);
+ } else if (os_strncmp(pos, "ctrl_interface=", 15) == 0) {
+ os_free(config->ctrl_interface);
+ config->ctrl_interface = os_strdup(pos + 15);
wpa_printf(MSG_DEBUG, "ctrl_interface='%s'",
config->ctrl_interface);
-#ifndef CONFIG_CTRL_IFACE_UDP
- } else if (strncmp(pos, "ctrl_interface_group=", 21) == 0) {
- struct group *grp;
- char *endp;
- const char *group = pos + 21;
-
- grp = getgrnam(group);
- if (grp) {
- config->ctrl_interface_gid = grp->gr_gid;
- config->ctrl_interface_gid_set = 1;
- wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
- " (from group name '%s')",
- (int) config->ctrl_interface_gid,
- group);
- continue;
- }
-
- /* Group name not found - try to parse this as gid */
- config->ctrl_interface_gid = strtol(group, &endp, 10);
- if (*group == '\0' || *endp != '\0') {
- wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
- "'%s'", line, group);
- errors++;
- continue;
- }
- config->ctrl_interface_gid_set = 1;
- wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
- (int) config->ctrl_interface_gid);
-#endif /* CONFIG_CTRL_IFACE_UDP */
+ } else if (os_strncmp(pos, "ctrl_interface_group=", 21) == 0) {
+ os_free(config->ctrl_interface_group);
+ config->ctrl_interface_group = os_strdup(pos + 21);
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group='%s' "
+ "(DEPRECATED)",
+ config->ctrl_interface_group);
#endif /* CONFIG_CTRL_IFACE */
- } else if (strncmp(pos, "eapol_version=", 14) == 0) {
+ } else if (os_strncmp(pos, "eapol_version=", 14) == 0) {
config->eapol_version = atoi(pos + 14);
if (config->eapol_version < 1 ||
config->eapol_version > 2) {
@@ -319,55 +327,69 @@ struct wpa_config * wpa_config_read(const char *name)
}
wpa_printf(MSG_DEBUG, "eapol_version=%d",
config->eapol_version);
- } else if (strncmp(pos, "ap_scan=", 8) == 0) {
+ } else if (os_strncmp(pos, "ap_scan=", 8) == 0) {
config->ap_scan = atoi(pos + 8);
wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan);
- } else if (strncmp(pos, "fast_reauth=", 12) == 0) {
+ } else if (os_strncmp(pos, "fast_reauth=", 12) == 0) {
config->fast_reauth = atoi(pos + 12);
wpa_printf(MSG_DEBUG, "fast_reauth=%d",
config->fast_reauth);
- } else if (strncmp(pos, "opensc_engine_path=", 19) == 0) {
- free(config->opensc_engine_path);
- config->opensc_engine_path = strdup(pos + 19);
+ } else if (os_strncmp(pos, "opensc_engine_path=", 19) == 0) {
+ os_free(config->opensc_engine_path);
+ config->opensc_engine_path = os_strdup(pos + 19);
wpa_printf(MSG_DEBUG, "opensc_engine_path='%s'",
config->opensc_engine_path);
- } else if (strncmp(pos, "pkcs11_engine_path=", 19) == 0) {
- free(config->pkcs11_engine_path);
- config->pkcs11_engine_path = strdup(pos + 19);
+ } else if (os_strncmp(pos, "pkcs11_engine_path=", 19) == 0) {
+ os_free(config->pkcs11_engine_path);
+ config->pkcs11_engine_path = os_strdup(pos + 19);
wpa_printf(MSG_DEBUG, "pkcs11_engine_path='%s'",
config->pkcs11_engine_path);
- } else if (strncmp(pos, "pkcs11_module_path=", 19) == 0) {
- free(config->pkcs11_module_path);
- config->pkcs11_module_path = strdup(pos + 19);
+ } else if (os_strncmp(pos, "pkcs11_module_path=", 19) == 0) {
+ os_free(config->pkcs11_module_path);
+ config->pkcs11_module_path = os_strdup(pos + 19);
wpa_printf(MSG_DEBUG, "pkcs11_module_path='%s'",
config->pkcs11_module_path);
- } else if (strncmp(pos, "driver_param=", 13) == 0) {
- free(config->driver_param);
- config->driver_param = strdup(pos + 13);
+ } else if (os_strncmp(pos, "driver_param=", 13) == 0) {
+ os_free(config->driver_param);
+ config->driver_param = os_strdup(pos + 13);
wpa_printf(MSG_DEBUG, "driver_param='%s'",
config->driver_param);
- } else if (strncmp(pos, "dot11RSNAConfigPMKLifetime=", 27) ==
- 0) {
+ } else if (os_strncmp(pos, "dot11RSNAConfigPMKLifetime=", 27)
+ == 0) {
config->dot11RSNAConfigPMKLifetime = atoi(pos + 27);
wpa_printf(MSG_DEBUG, "dot11RSNAConfigPMKLifetime=%d",
config->dot11RSNAConfigPMKLifetime);
- } else if (strncmp(pos, "dot11RSNAConfigPMKReauthThreshold=",
- 34) ==
- 0) {
+ } else if (os_strncmp(pos,
+ "dot11RSNAConfigPMKReauthThreshold=", 34)
+ == 0) {
config->dot11RSNAConfigPMKReauthThreshold =
atoi(pos + 34);
wpa_printf(MSG_DEBUG,
"dot11RSNAConfigPMKReauthThreshold=%d",
config->dot11RSNAConfigPMKReauthThreshold);
- } else if (strncmp(pos, "dot11RSNAConfigSATimeout=", 25) ==
+ } else if (os_strncmp(pos, "dot11RSNAConfigSATimeout=", 25) ==
0) {
config->dot11RSNAConfigSATimeout = atoi(pos + 25);
wpa_printf(MSG_DEBUG, "dot11RSNAConfigSATimeout=%d",
config->dot11RSNAConfigSATimeout);
- } else if (strncmp(pos, "update_config=", 14) == 0) {
+ } else if (os_strncmp(pos, "update_config=", 14) == 0) {
config->update_config = atoi(pos + 14);
wpa_printf(MSG_DEBUG, "update_config=%d",
config->update_config);
+ } else if (os_strncmp(pos, "load_dynamic_eap=", 17) == 0) {
+ char *so = pos + 17;
+ int ret;
+ wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
+ ret = eap_peer_method_load(so);
+ if (ret == -2) {
+ wpa_printf(MSG_DEBUG, "This EAP type was "
+ "already loaded - not reloading.");
+ } else if (ret) {
+ wpa_printf(MSG_ERROR, "Line %d: Failed to "
+ "load dynamic EAP method '%s'.",
+ line, so);
+ errors++;
+ }
} else {
wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
"line '%s'.", line, pos);
@@ -379,17 +401,8 @@ struct wpa_config * wpa_config_read(const char *name)
fclose(f);
config->ssid = head;
- for (prio = 0; prio < config->num_prio; prio++) {
- ssid = config->pssid[prio];
- wpa_printf(MSG_DEBUG, "Priority group %d",
- ssid->priority);
- while (ssid) {
- wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
- ssid->id,
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
- ssid = ssid->pnext;
- }
- }
+ wpa_config_debug_dump_networks(config);
+
if (errors) {
wpa_config_free(config);
config = NULL;
@@ -406,7 +419,7 @@ static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid)
if (value == NULL)
return;
fprintf(f, "\t%s=%s\n", field, value);
- free(value);
+ os_free(value);
}
@@ -424,7 +437,7 @@ static void write_bssid(FILE *f, struct wpa_ssid *ssid)
if (value == NULL)
return;
fprintf(f, "\tbssid=%s\n", value);
- free(value);
+ os_free(value);
}
@@ -434,7 +447,7 @@ static void write_psk(FILE *f, struct wpa_ssid *ssid)
if (value == NULL)
return;
fprintf(f, "\tpsk=%s\n", value);
- free(value);
+ os_free(value);
}
@@ -450,7 +463,7 @@ static void write_proto(FILE *f, struct wpa_ssid *ssid)
return;
if (value[0])
fprintf(f, "\tproto=%s\n", value);
- free(value);
+ os_free(value);
}
@@ -466,7 +479,7 @@ static void write_key_mgmt(FILE *f, struct wpa_ssid *ssid)
return;
if (value[0])
fprintf(f, "\tkey_mgmt=%s\n", value);
- free(value);
+ os_free(value);
}
@@ -482,7 +495,7 @@ static void write_pairwise(FILE *f, struct wpa_ssid *ssid)
return;
if (value[0])
fprintf(f, "\tpairwise=%s\n", value);
- free(value);
+ os_free(value);
}
@@ -498,7 +511,7 @@ static void write_group(FILE *f, struct wpa_ssid *ssid)
return;
if (value[0])
fprintf(f, "\tgroup=%s\n", value);
- free(value);
+ os_free(value);
}
@@ -514,10 +527,11 @@ static void write_auth_alg(FILE *f, struct wpa_ssid *ssid)
return;
if (value[0])
fprintf(f, "\tauth_alg=%s\n", value);
- free(value);
+ os_free(value);
}
+#ifdef IEEE8021X_EAPOL
static void write_eap(FILE *f, struct wpa_ssid *ssid)
{
char *value;
@@ -528,19 +542,20 @@ static void write_eap(FILE *f, struct wpa_ssid *ssid)
if (value[0])
fprintf(f, "\teap=%s\n", value);
- free(value);
+ os_free(value);
}
+#endif /* IEEE8021X_EAPOL */
static void write_wep_key(FILE *f, int idx, struct wpa_ssid *ssid)
{
char field[20], *value;
- snprintf(field, sizeof(field), "wep_key%d", idx);
+ os_snprintf(field, sizeof(field), "wep_key%d", idx);
value = wpa_config_get(ssid, field);
if (value) {
fprintf(f, "\t%s=%s\n", field, value);
- free(value);
+ os_free(value);
}
}
@@ -562,6 +577,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
write_pairwise(f, ssid);
write_group(f, ssid);
write_auth_alg(f, ssid);
+#ifdef IEEE8021X_EAPOL
write_eap(f, ssid);
STR(identity);
STR(anonymous_identity);
@@ -569,6 +585,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(nai);
STR(password);
STR(ca_cert);
+ STR(ca_path);
STR(client_cert);
STR(private_key);
STR(private_key_passwd);
@@ -576,6 +593,7 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(subject_match);
STR(altsubject_match);
STR(ca_cert2);
+ STR(ca_path2);
STR(client_cert2);
STR(private_key2);
STR(private_key2_passwd);
@@ -590,15 +608,24 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
STR(key_id);
INT(engine);
INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+#endif /* IEEE8021X_EAPOL */
for (i = 0; i < 4; i++)
write_wep_key(f, i, ssid);
INT(wep_tx_keyidx);
INT(priority);
+#ifdef IEEE8021X_EAPOL
INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
STR(pac_file);
+ INT_DEF(fragment_size, DEFAULT_FRAGMENT_SIZE);
+#endif /* IEEE8021X_EAPOL */
INT(mode);
INT(proactive_key_caching);
INT(disabled);
+ INT(peerkey);
+#ifdef CONFIG_IEEE80211W
+ INT(ieee80211w);
+#endif /* CONFIG_IEEE80211W */
+ STR(id_str);
#undef STR
#undef INT
@@ -615,36 +642,19 @@ static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
return -1;
fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded);
- free(encoded);
+ os_free(encoded);
return 0;
}
-int wpa_config_write(const char *name, struct wpa_config *config)
+static void wpa_config_write_global(FILE *f, struct wpa_config *config)
{
- FILE *f;
- struct wpa_ssid *ssid;
- struct wpa_config_blob *blob;
- int ret = 0;
-
- wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
-
-
- f = fopen(name, "w");
- if (f == NULL) {
- wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name);
- return -1;
- }
-
#ifdef CONFIG_CTRL_IFACE
if (config->ctrl_interface)
fprintf(f, "ctrl_interface=%s\n", config->ctrl_interface);
-#ifndef CONFIG_CTRL_IFACE_UDP
- if (config->ctrl_interface_gid_set) {
- fprintf(f, "ctrl_interface_group=%d\n",
- (int) config->ctrl_interface_gid);
- }
-#endif /* CONFIG_CTRL_IFACE_UDP */
+ if (config->ctrl_interface_group)
+ fprintf(f, "ctrl_interface_group=%s\n",
+ config->ctrl_interface_group);
#endif /* CONFIG_CTRL_IFACE */
if (config->eapol_version != DEFAULT_EAPOL_VERSION)
fprintf(f, "eapol_version=%d\n", config->eapol_version);
@@ -674,6 +684,25 @@ int wpa_config_write(const char *name, struct wpa_config *config)
config->dot11RSNAConfigSATimeout);
if (config->update_config)
fprintf(f, "update_config=%d\n", config->update_config);
+}
+
+
+int wpa_config_write(const char *name, struct wpa_config *config)
+{
+ FILE *f;
+ struct wpa_ssid *ssid;
+ struct wpa_config_blob *blob;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
+
+ f = fopen(name, "w");
+ if (f == NULL) {
+ wpa_printf(MSG_DEBUG, "Failed to open '%s' for writing", name);
+ return -1;
+ }
+
+ wpa_config_write_global(f, config);
for (ssid = config->ssid; ssid; ssid = ssid->next) {
fprintf(f, "\nnetwork={\n");
diff --git a/contrib/wpa_supplicant/config_none.c b/contrib/wpa_supplicant/config_none.c
new file mode 100644
index 000000000000..2e9ccc0a2835
--- /dev/null
+++ b/contrib/wpa_supplicant/config_none.c
@@ -0,0 +1,57 @@
+/*
+ * WPA Supplicant / Configuration backend: empty starting point
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file implements dummy example of a configuration backend. None of the
+ * functions are actually implemented so this can be used as a simple
+ * compilation test or a starting point for a new configuration backend.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "config.h"
+#include "base64.h"
+
+
+struct wpa_config * wpa_config_read(const char *name)
+{
+ struct wpa_config *config;
+
+ config = wpa_config_alloc_empty(NULL, NULL);
+ if (config == NULL)
+ return NULL;
+ /* TODO: fill in configuration data */
+ return config;
+}
+
+
+int wpa_config_write(const char *name, struct wpa_config *config)
+{
+ struct wpa_ssid *ssid;
+ struct wpa_config_blob *blob;
+
+ wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
+
+ /* TODO: write global config parameters */
+
+
+ for (ssid = config->ssid; ssid; ssid = ssid->next) {
+ /* TODO: write networks */
+ }
+
+ for (blob = config->blobs; blob; blob = blob->next) {
+ /* TODO: write blobs */
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/config_ssid.h b/contrib/wpa_supplicant/config_ssid.h
index 14dc0f47dadc..d4c36541194d 100644
--- a/contrib/wpa_supplicant/config_ssid.h
+++ b/contrib/wpa_supplicant/config_ssid.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / Network configuration structures
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,11 +15,18 @@
#ifndef CONFIG_SSID_H
#define CONFIG_SSID_H
+#ifndef BIT
+#define BIT(n) (1 << (n))
+#endif
+
#define WPA_CIPHER_NONE BIT(0)
#define WPA_CIPHER_WEP40 BIT(1)
#define WPA_CIPHER_WEP104 BIT(2)
#define WPA_CIPHER_TKIP BIT(3)
#define WPA_CIPHER_CCMP BIT(4)
+#ifdef CONFIG_IEEE80211W
+#define WPA_CIPHER_AES_128_CMAC BIT(5)
+#endif /* CONFIG_IEEE80211W */
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
@@ -36,7 +43,8 @@
#define MAX_SSID_LEN 32
#define PMK_LEN 32
-#define EAP_PSK_LEN 16
+#define EAP_PSK_LEN_MIN 16
+#define EAP_PSK_LEN_MAX 32
#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
@@ -47,6 +55,7 @@
#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \
WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
+#define DEFAULT_FRAGMENT_SIZE 1398
/**
* struct wpa_ssid - Network configuration data
@@ -191,6 +200,8 @@ struct wpa_ssid {
*/
int scan_ssid;
+#ifdef IEEE8021X_EAPOL
+
/**
* identity - EAP Identity
*/
@@ -216,19 +227,20 @@ struct wpa_ssid {
size_t anonymous_identity_len;
/**
- * eappsk - EAP-PSK pre-shared key
+ * eappsk - EAP-PSK/PAX/SAKE pre-shared key
*/
u8 *eappsk;
/**
- * eappsk_len - EAP-PSK pre-shared key length
+ * eappsk_len - EAP-PSK/PAX/SAKE pre-shared key length
*
- * This field is always 16 for the current version of EAP-PSK.
+ * This field is always 16 for the current version of EAP-PSK/PAX and
+ * 32 for EAP-SAKE.
*/
size_t eappsk_len;
/**
- * nai - User NAI (for EAP-PSK)
+ * nai - User NAI (for EAP-PSK/PAX/SAKE)
*/
u8 *nai;
@@ -263,6 +275,9 @@ struct wpa_ssid {
* 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;
@@ -309,6 +324,10 @@ struct wpa_ssid {
*
* 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>.
*/
@@ -354,14 +373,16 @@ struct wpa_ssid {
/**
* altsubject_match - Constraint for server certificate alt. subject
*
- * This substring is 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 this string in an
- * alternative subject name extension.
+ * 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: DNS:server.example.com
+ * Example: EMAIL:server@example.com
+ * Example: DNS:server.example.com;DNS:server2.example.com
*
* Following types are supported: EMAIL, DNS, URI
*/
@@ -465,10 +486,10 @@ struct wpa_ssid {
/**
* eap_methods - Allowed EAP methods
*
- * Zero (EAP_TYPE_NONE) terminated list of allowed EAP methods or %NULL
- * if all methods are accepted.
+ * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
+ * allowed EAP methods or %NULL if all methods are accepted.
*/
- u8 *eap_methods;
+ struct eap_method_type *eap_methods;
/**
* phase1 - Phase 1 (outer authentication) parameters
@@ -569,6 +590,8 @@ struct wpa_ssid {
*/
int eapol_flags;
+#endif /* IEEE8021X_EAPOL */
+
#define NUM_WEP_KEYS 4
#define MAX_WEP_KEY_LEN 16
/**
@@ -602,6 +625,18 @@ struct wpa_ssid {
int proactive_key_caching;
/**
+ * mixed_cell - Whether mixed cells are allowed
+ *
+ * This option can be used to configure whether so called mixed cells,
+ * i.e., networks that use both plaintext and encryption in the same
+ * SSID, are allowed. This is disabled (0) by default. Enable by
+ * setting this to 1.
+ */
+ int mixed_cell;
+
+#ifdef IEEE8021X_EAPOL
+
+ /**
* otp - One-time-password
*
* This field should not be set in configuration step. It is only used
@@ -715,6 +750,8 @@ struct wpa_ssid {
*/
char *pac_file;
+#endif /* IEEE8021X_EAPOL */
+
/**
* mode - IEEE 802.11 operation mode (Infrastucture/IBSS)
*
@@ -731,6 +768,8 @@ struct wpa_ssid {
*/
int mode;
+#ifdef IEEE8021X_EAPOL
+
/**
* mschapv2_retry - MSCHAPv2 retry in progress
*
@@ -753,6 +792,8 @@ struct wpa_ssid {
*/
size_t new_password_len;
+#endif /* IEEE8021X_EAPOL */
+
/**
* disabled - Whether this network is currently disabled
*
@@ -761,8 +802,58 @@ struct wpa_ssid {
* ctrl_iface, e.g., with wpa_cli or wpa_gui).
*/
int disabled;
+
+ /**
+ * peerkey - Whether PeerKey handshake for direct links is allowed
+ *
+ * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
+ * enabled.
+ *
+ * 0 = disabled (default)
+ * 1 = enabled
+ */
+ int peerkey;
+
+#ifdef IEEE8021X_EAPOL
+
+ /**
+ * 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;
+
+#endif /* IEEE8021X_EAPOL */
+
+ /**
+ * id_str - Network identifier string for external scripts
+ *
+ * This value is passed to external ctrl_iface monitors in
+ * WPA_EVENT_CONNECTED event and wpa_cli sets this as WPA_ID_STR
+ * environment variable for action scripts.
+ */
+ char *id_str;
+
+#ifdef CONFIG_IEEE80211W
+ /**
+ * ieee80211w - Whether management frame protection is enabled
+ *
+ * This value is used to configure policy for management frame
+ * protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required.
+ */
+ enum {
+ NO_IEEE80211W = 0,
+ IEEE80211W_OPTIONAL = 1,
+ IEEE80211W_REQUIRED = 2
+ } ieee80211w;
+#endif /* CONFIG_IEEE80211W */
};
-int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method);
+int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int vendor,
+ u32 method);
#endif /* CONFIG_SSID_H */
diff --git a/contrib/wpa_supplicant/config_types.h b/contrib/wpa_supplicant/config_types.h
index 12b57cb4acf1..ffcffa3c0cd4 100644
--- a/contrib/wpa_supplicant/config_types.h
+++ b/contrib/wpa_supplicant/config_types.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / Shared configuration file defines
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifndef CONFIG_TYPES_H
#define CONFIG_TYPES_H
diff --git a/contrib/wpa_supplicant/config_winreg.c b/contrib/wpa_supplicant/config_winreg.c
new file mode 100644
index 000000000000..8a3ba53734f9
--- /dev/null
+++ b/contrib/wpa_supplicant/config_winreg.c
@@ -0,0 +1,882 @@
+/*
+ * WPA Supplicant / Configuration backend: Windows registry
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file implements a configuration backend for Windows registry.. All the
+ * configuration information is stored in the registry and the format for
+ * network configuration fields is same as described in the sample
+ * configuration file, wpa_supplicant.conf.
+ *
+ * Configuration data is in HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs
+ * key. Each configuration profile has its own key under this. In terms of text
+ * files, each profile would map to a separate text file with possibly multiple
+ * networks. Under each profile, there is a networks key that lists all
+ * networks as a subkey. Each network has set of values in the same way as
+ * network block in the configuration file. In addition, blobs subkey has
+ * possible blobs as values.
+ *
+ * HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
+ * ssid="example"
+ * key_mgmt=WPA-PSK
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "config.h"
+
+#ifndef WPA_KEY_ROOT
+#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
+#endif
+#ifndef WPA_KEY_PREFIX
+#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
+#endif
+
+#ifdef UNICODE
+#define TSTR "%S"
+#else /* UNICODE */
+#define TSTR "%s"
+#endif /* UNICODE */
+
+
+static int wpa_config_read_blobs(struct wpa_config *config, HKEY hk)
+{
+ struct wpa_config_blob *blob;
+ int errors = 0;
+ HKEY bhk;
+ LONG ret;
+ DWORD i;
+
+ ret = RegOpenKeyEx(hk, TEXT("blobs"), 0, KEY_QUERY_VALUE, &bhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
+ "blobs key");
+ return 0; /* assume no blobs */
+ }
+
+ for (i = 0; ; i++) {
+#define TNAMELEN 255
+ TCHAR name[TNAMELEN];
+ char data[4096];
+ DWORD namelen, datalen, type;
+
+ namelen = TNAMELEN;
+ datalen = sizeof(data);
+ ret = RegEnumValue(bhk, i, name, &namelen, NULL, &type,
+ (LPBYTE) data, &datalen);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegEnumValue failed: 0x%x",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= TNAMELEN)
+ namelen = TNAMELEN - 1;
+ name[namelen] = TEXT('\0');
+ wpa_unicode2ascii_inplace(name);
+
+ if (datalen >= sizeof(data))
+ datalen = sizeof(data) - 1;
+
+ wpa_printf(MSG_MSGDUMP, "blob %d: field='%s' len %d",
+ (int) i, name, (int) datalen);
+
+ blob = os_zalloc(sizeof(*blob));
+ if (blob == NULL) {
+ errors++;
+ break;
+ }
+ blob->name = os_strdup((char *) name);
+ blob->data = os_malloc(datalen);
+ if (blob->name == NULL || blob->data == NULL) {
+ wpa_config_free_blob(blob);
+ errors++;
+ break;
+ }
+ os_memcpy(blob->data, data, datalen);
+ blob->len = datalen;
+
+ wpa_config_set_blob(config, blob);
+ }
+
+ RegCloseKey(bhk);
+
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_read_reg_dword(HKEY hk, const TCHAR *name, int *_val)
+{
+ DWORD val, buflen;
+ LONG ret;
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+ wpa_printf(MSG_DEBUG, TSTR "=%d", name, (int) val);
+ *_val = val;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static char * wpa_config_read_reg_string(HKEY hk, const TCHAR *name)
+{
+ DWORD buflen;
+ LONG ret;
+ TCHAR *val;
+
+ buflen = 0;
+ ret = RegQueryValueEx(hk, name, NULL, NULL, NULL, &buflen);
+ if (ret != ERROR_SUCCESS)
+ return NULL;
+ val = os_malloc(buflen);
+ if (val == NULL)
+ return NULL;
+
+ ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) val, &buflen);
+ if (ret != ERROR_SUCCESS) {
+ os_free(val);
+ return NULL;
+ }
+
+ wpa_unicode2ascii_inplace(val);
+ wpa_printf(MSG_DEBUG, TSTR "=%s", name, (char *) val);
+ return (char *) val;
+}
+
+
+static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
+{
+ int errors = 0;
+
+ wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
+ wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
+ &config->fast_reauth);
+ wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
+ &config->dot11RSNAConfigPMKLifetime);
+ wpa_config_read_reg_dword(hk,
+ TEXT("dot11RSNAConfigPMKReauthThreshold"),
+ &config->dot11RSNAConfigPMKReauthThreshold);
+ wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
+ &config->dot11RSNAConfigSATimeout);
+ wpa_config_read_reg_dword(hk, TEXT("update_config"),
+ &config->update_config);
+
+ if (wpa_config_read_reg_dword(hk, TEXT("eapol_version"),
+ &config->eapol_version) == 0) {
+ if (config->eapol_version < 1 ||
+ config->eapol_version > 2) {
+ wpa_printf(MSG_ERROR, "Invalid EAPOL version (%d)",
+ config->eapol_version);
+ errors++;
+ }
+ }
+
+ config->ctrl_interface = wpa_config_read_reg_string(
+ hk, TEXT("ctrl_interface"));
+
+ return errors ? -1 : 0;
+}
+
+
+static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
+ int id)
+{
+ HKEY nhk;
+ LONG ret;
+ DWORD i;
+ struct wpa_ssid *ssid;
+ int errors = 0;
+
+ ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
+ "network '" TSTR "'", netw);
+ return NULL;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw);
+ ssid = os_zalloc(sizeof(*ssid));
+ if (ssid == NULL) {
+ RegCloseKey(nhk);
+ return NULL;
+ }
+ ssid->id = id;
+
+ wpa_config_set_network_defaults(ssid);
+
+ for (i = 0; ; i++) {
+ TCHAR name[255], data[1024];
+ DWORD namelen, datalen, type;
+
+ namelen = 255;
+ datalen = sizeof(data);
+ ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type,
+ (LPBYTE) data, &datalen);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = TEXT('\0');
+
+ if (datalen >= 1024)
+ datalen = 1024 - 1;
+ data[datalen] = TEXT('\0');
+
+ wpa_unicode2ascii_inplace(name);
+ wpa_unicode2ascii_inplace(data);
+ if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0)
+ errors++;
+ }
+
+ RegCloseKey(nhk);
+
+ if (ssid->passphrase) {
+ if (ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "Both PSK and passphrase "
+ "configured for network '" TSTR "'.", netw);
+ errors++;
+ }
+ wpa_config_update_psk(ssid);
+ }
+
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, "
+ "but no PSK configured for network '" TSTR "'.",
+ netw);
+ errors++;
+ }
+
+ if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+ /* Group cipher cannot be stronger than the pairwise cipher. */
+ wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher "
+ "list since it was not allowed for pairwise "
+ "cipher for network '" TSTR "'.", netw);
+ ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+ }
+
+ if (errors) {
+ wpa_config_free_ssid(ssid);
+ ssid = NULL;
+ }
+
+ return ssid;
+}
+
+
+static int wpa_config_read_networks(struct wpa_config *config, HKEY hk)
+{
+ HKEY nhk;
+ struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+ int errors = 0;
+ LONG ret;
+ DWORD i;
+
+ ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_ENUMERATE_SUB_KEYS,
+ &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Could not open wpa_supplicant networks "
+ "registry key");
+ return -1;
+ }
+
+ for (i = 0; ; i++) {
+ TCHAR name[255];
+ DWORD namelen;
+
+ namelen = 255;
+ ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
+ NULL);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = '\0';
+
+ ssid = wpa_config_read_network(nhk, name, i);
+ if (ssid == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to parse network "
+ "profile '%s'.", name);
+ errors++;
+ continue;
+ }
+ if (head == NULL) {
+ head = tail = ssid;
+ } else {
+ tail->next = ssid;
+ tail = ssid;
+ }
+ if (wpa_config_add_prio_network(config, ssid)) {
+ wpa_printf(MSG_ERROR, "Failed to add network profile "
+ "'%s' to priority list.", name);
+ errors++;
+ continue;
+ }
+ }
+
+ RegCloseKey(nhk);
+
+ config->ssid = head;
+
+ return errors ? -1 : 0;
+}
+
+
+struct wpa_config * wpa_config_read(const char *name)
+{
+ TCHAR buf[256];
+ int errors = 0;
+ struct wpa_config *config;
+ HKEY hk;
+ LONG ret;
+
+ config = wpa_config_alloc_empty(NULL, NULL);
+ if (config == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name);
+
+#ifdef UNICODE
+ _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
+#else /* UNICODE */
+ os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
+#endif /* UNICODE */
+
+ ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_QUERY_VALUE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
+ "configuration registry HKLM\\" TSTR, buf);
+ os_free(config);
+ return NULL;
+ }
+
+ if (wpa_config_read_global(config, hk))
+ errors++;
+
+ if (wpa_config_read_networks(config, hk))
+ errors++;
+
+ if (wpa_config_read_blobs(config, hk))
+ errors++;
+
+ wpa_config_debug_dump_networks(config);
+
+ RegCloseKey(hk);
+
+ if (errors) {
+ wpa_config_free(config);
+ config = NULL;
+ }
+
+ return config;
+}
+
+
+static int wpa_config_write_reg_dword(HKEY hk, const TCHAR *name, int val,
+ int def)
+{
+ LONG ret;
+ DWORD _val = val;
+
+ if (val == def) {
+ RegDeleteValue(hk, name);
+ return 0;
+ }
+
+ ret = RegSetValueEx(hk, name, 0, REG_DWORD, (LPBYTE) &_val,
+ sizeof(_val));
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "WINREG: Failed to set %s=%d: error %d",
+ name, val, (int) GetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_config_write_reg_string(HKEY hk, const char *name,
+ const char *val)
+{
+ LONG ret;
+ TCHAR *_name, *_val;
+
+ _name = wpa_strdup_tchar(name);
+ if (_name == NULL)
+ return -1;
+
+ if (val == NULL) {
+ RegDeleteValue(hk, _name);
+ os_free(_name);
+ return 0;
+ }
+
+ _val = wpa_strdup_tchar(val);
+ if (_val == NULL) {
+ os_free(_name);
+ return -1;
+ }
+ ret = RegSetValueEx(hk, _name, 0, REG_SZ, (BYTE *) _val,
+ (os_strlen(val) + 1) * sizeof(TCHAR));
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "WINREG: Failed to set %s='%s': "
+ "error %d", name, val, (int) GetLastError());
+ os_free(_name);
+ os_free(_val);
+ return -1;
+ }
+
+ os_free(_name);
+ os_free(_val);
+ return 0;
+}
+
+
+static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
+{
+#ifdef CONFIG_CTRL_IFACE
+ wpa_config_write_reg_string(hk, "ctrl_interface",
+ config->ctrl_interface);
+#endif /* CONFIG_CTRL_IFACE */
+
+ wpa_config_write_reg_dword(hk, TEXT("eapol_version"),
+ config->eapol_version,
+ DEFAULT_EAPOL_VERSION);
+ wpa_config_write_reg_dword(hk, TEXT("ap_scan"), config->ap_scan,
+ DEFAULT_AP_SCAN);
+ wpa_config_write_reg_dword(hk, TEXT("fast_reauth"),
+ config->fast_reauth, DEFAULT_FAST_REAUTH);
+ wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
+ config->dot11RSNAConfigPMKLifetime, 0);
+ wpa_config_write_reg_dword(hk,
+ TEXT("dot11RSNAConfigPMKReauthThreshold"),
+ config->dot11RSNAConfigPMKReauthThreshold,
+ 0);
+ wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
+ config->dot11RSNAConfigSATimeout, 0);
+ wpa_config_write_reg_dword(hk, TEXT("update_config"),
+ config->update_config,
+ 0);
+
+ return 0;
+}
+
+
+static int wpa_config_delete_subkeys(HKEY hk, const TCHAR *key)
+{
+ HKEY nhk;
+ int i, errors = 0;
+ LONG ret;
+
+ ret = RegOpenKeyEx(hk, key, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not open key '" TSTR
+ "' for subkey deletion: error 0x%x (%d)", key,
+ (unsigned int) ret, (int) GetLastError());
+ return 0;
+ }
+
+ for (i = 0; ; i++) {
+ TCHAR name[255];
+ DWORD namelen;
+
+ namelen = 255;
+ ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
+ NULL);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = TEXT('\0');
+
+ ret = RegDeleteKey(nhk, name);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegDeleteKey failed: 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ errors++;
+ }
+ }
+
+ RegCloseKey(nhk);
+
+ return errors ? -1 : 0;
+}
+
+
+static void write_str(HKEY hk, const char *field, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, field);
+ if (value == NULL)
+ return;
+ wpa_config_write_reg_string(hk, field, value);
+ os_free(value);
+}
+
+
+static void write_int(HKEY hk, const char *field, int value, int def)
+{
+ char val[20];
+ if (value == def)
+ return;
+ os_snprintf(val, sizeof(val), "%d", value);
+ wpa_config_write_reg_string(hk, field, val);
+}
+
+
+static void write_bssid(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "bssid");
+ if (value == NULL)
+ return;
+ wpa_config_write_reg_string(hk, "bssid", value);
+ os_free(value);
+}
+
+
+static void write_psk(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "psk");
+ if (value == NULL)
+ return;
+ wpa_config_write_reg_string(hk, "psk", value);
+ os_free(value);
+}
+
+
+static void write_proto(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->proto == DEFAULT_PROTO)
+ return;
+
+ value = wpa_config_get(ssid, "proto");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "proto", value);
+ os_free(value);
+}
+
+
+static void write_key_mgmt(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
+ return;
+
+ value = wpa_config_get(ssid, "key_mgmt");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "key_mgmt", value);
+ os_free(value);
+}
+
+
+static void write_pairwise(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
+ return;
+
+ value = wpa_config_get(ssid, "pairwise");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "pairwise", value);
+ os_free(value);
+}
+
+
+static void write_group(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->group_cipher == DEFAULT_GROUP)
+ return;
+
+ value = wpa_config_get(ssid, "group");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "group", value);
+ os_free(value);
+}
+
+
+static void write_auth_alg(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->auth_alg == 0)
+ return;
+
+ value = wpa_config_get(ssid, "auth_alg");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "auth_alg", value);
+ os_free(value);
+}
+
+
+#ifdef IEEE8021X_EAPOL
+static void write_eap(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ value = wpa_config_get(ssid, "eap");
+ if (value == NULL)
+ return;
+
+ if (value[0])
+ wpa_config_write_reg_string(hk, "eap", value);
+ os_free(value);
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
+{
+ char field[20], *value;
+
+ os_snprintf(field, sizeof(field), "wep_key%d", idx);
+ value = wpa_config_get(ssid, field);
+ if (value) {
+ wpa_config_write_reg_string(hk, field, value);
+ os_free(value);
+ }
+}
+
+
+static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
+{
+ int i, errors = 0;
+ HKEY nhk, netw;
+ LONG ret;
+ TCHAR name[5];
+
+ ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_CREATE_SUB_KEY, &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not open networks key "
+ "for subkey addition: error 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ return 0;
+ }
+
+#ifdef UNICODE
+ wsprintf(name, L"%04d", id);
+#else /* UNICODE */
+ os_snprintf(name, sizeof(name), "%04d", id);
+#endif /* UNICODE */
+ ret = RegCreateKeyEx(nhk, name, 0, NULL, 0, KEY_WRITE, NULL, &netw,
+ NULL);
+ RegCloseKey(nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not add network key '%s':"
+ " error 0x%x (%d)",
+ name, (unsigned int) ret, (int) GetLastError());
+ return -1;
+ }
+
+#define STR(t) write_str(netw, #t, ssid)
+#define INT(t) write_int(netw, #t, ssid->t, 0)
+#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def)
+
+ STR(ssid);
+ INT(scan_ssid);
+ write_bssid(netw, ssid);
+ write_psk(netw, ssid);
+ write_proto(netw, ssid);
+ write_key_mgmt(netw, ssid);
+ write_pairwise(netw, ssid);
+ write_group(netw, ssid);
+ write_auth_alg(netw, ssid);
+#ifdef IEEE8021X_EAPOL
+ write_eap(netw, ssid);
+ STR(identity);
+ STR(anonymous_identity);
+ STR(eappsk);
+ STR(nai);
+ STR(password);
+ STR(ca_cert);
+ STR(ca_path);
+ STR(client_cert);
+ STR(private_key);
+ STR(private_key_passwd);
+ STR(dh_file);
+ STR(subject_match);
+ STR(altsubject_match);
+ STR(ca_cert2);
+ STR(ca_path2);
+ STR(client_cert2);
+ STR(private_key2);
+ STR(private_key2_passwd);
+ STR(dh_file2);
+ STR(subject_match2);
+ STR(altsubject_match2);
+ STR(phase1);
+ STR(phase2);
+ STR(pcsc);
+ STR(pin);
+ STR(engine_id);
+ STR(key_id);
+ INT(engine);
+ INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+#endif /* IEEE8021X_EAPOL */
+ for (i = 0; i < 4; i++)
+ write_wep_key(netw, i, ssid);
+ INT(wep_tx_keyidx);
+ INT(priority);
+#ifdef IEEE8021X_EAPOL
+ INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
+ STR(pac_file);
+ INT_DEF(fragment_size, DEFAULT_FRAGMENT_SIZE);
+#endif /* IEEE8021X_EAPOL */
+ INT(mode);
+ INT(proactive_key_caching);
+ INT(disabled);
+ INT(peerkey);
+#ifdef CONFIG_IEEE80211W
+ INT(ieee80211w);
+#endif /* CONFIG_IEEE80211W */
+ STR(id_str);
+
+#undef STR
+#undef INT
+#undef INT_DEF
+
+ RegCloseKey(netw);
+
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_write_blob(HKEY hk, struct wpa_config_blob *blob)
+{
+ HKEY bhk;
+ LONG ret;
+ TCHAR *name;
+
+ ret = RegCreateKeyEx(hk, TEXT("blobs"), 0, NULL, 0, KEY_WRITE, NULL,
+ &bhk, NULL);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not add blobs key: "
+ "error 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ return -1;
+ }
+
+ name = wpa_strdup_tchar(blob->name);
+ ret = RegSetValueEx(bhk, name, 0, REG_BINARY, blob->data,
+ blob->len);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "WINREG: Failed to set blob %s': "
+ "error 0x%x (%d)", blob->name, (unsigned int) ret,
+ (int) GetLastError());
+ RegCloseKey(bhk);
+ os_free(name);
+ return -1;
+ }
+ os_free(name);
+
+ RegCloseKey(bhk);
+
+ return 0;
+}
+
+
+int wpa_config_write(const char *name, struct wpa_config *config)
+{
+ TCHAR buf[256];
+ HKEY hk;
+ LONG ret;
+ int errors = 0;
+ struct wpa_ssid *ssid;
+ struct wpa_config_blob *blob;
+ int id;
+
+ wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
+
+#ifdef UNICODE
+ _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
+#else /* UNICODE */
+ os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
+#endif /* UNICODE */
+
+ ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_SET_VALUE | DELETE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
+ "configuration registry %s: error %d", buf,
+ (int) GetLastError());
+ return -1;
+ }
+
+ if (wpa_config_write_global(config, hk)) {
+ wpa_printf(MSG_ERROR, "Failed to write global configuration "
+ "data");
+ errors++;
+ }
+
+ wpa_config_delete_subkeys(hk, TEXT("networks"));
+ for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) {
+ if (wpa_config_write_network(hk, ssid, id))
+ errors++;
+ }
+
+ RegDeleteKey(hk, TEXT("blobs"));
+ for (blob = config->blobs; blob; blob = blob->next) {
+ if (wpa_config_write_blob(hk, blob))
+ errors++;
+ }
+
+ RegCloseKey(hk);
+
+ wpa_printf(MSG_DEBUG, "Configuration '%s' written %ssuccessfully",
+ name, errors ? "un" : "");
+ return errors ? -1 : 0;
+}
diff --git a/contrib/wpa_supplicant/crypto.c b/contrib/wpa_supplicant/crypto.c
index b4c81892c66e..c5edd24c4b55 100644
--- a/contrib/wpa_supplicant/crypto.c
+++ b/contrib/wpa_supplicant/crypto.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for libcrypto
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,8 @@
* See README and COPYING for more details.
*/
-#include <string.h>
-#include <sys/types.h>
-
+#include "includes.h"
+#include <openssl/opensslv.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
@@ -36,7 +35,7 @@
void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD4_CTX ctx;
- int i;
+ size_t i;
MD4_Init(&ctx);
for (i = 0; i < num_elem; i++)
@@ -70,7 +69,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD5_CTX ctx;
- int i;
+ size_t i;
MD5_Init(&ctx);
for (i = 0; i < num_elem; i++)
@@ -82,7 +81,7 @@ void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
SHA_CTX ctx;
- int i;
+ size_t i;
SHA1_Init(&ctx);
for (i = 0; i < num_elem; i++)
@@ -91,24 +90,78 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
}
-void sha1_transform(u8 *state, const u8 data[64])
+static void sha1_transform(u8 *state, const u8 data[64])
{
SHA_CTX context;
- memset(&context, 0, sizeof(context));
- memcpy(&context.h0, state, 5 * 4);
+ os_memset(&context, 0, sizeof(context));
+ os_memcpy(&context.h0, state, 5 * 4);
SHA1_Transform(&context, data);
- memcpy(state, &context.h0, 5 * 4);
+ os_memcpy(state, &context.h0, 5 * 4);
+}
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+ u8 xkey[64];
+ u32 t[5], _t[5];
+ int i, j, m, k;
+ u8 *xpos = x;
+ u32 carry;
+
+ if (seed_len > sizeof(xkey))
+ seed_len = sizeof(xkey);
+
+ /* FIPS 186-2 + change notice 1 */
+
+ os_memcpy(xkey, seed, seed_len);
+ os_memset(xkey + seed_len, 0, 64 - seed_len);
+ t[0] = 0x67452301;
+ t[1] = 0xEFCDAB89;
+ t[2] = 0x98BADCFE;
+ t[3] = 0x10325476;
+ t[4] = 0xC3D2E1F0;
+
+ m = xlen / 40;
+ for (j = 0; j < m; j++) {
+ /* XSEED_j = 0 */
+ for (i = 0; i < 2; i++) {
+ /* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+ /* w_i = G(t, XVAL) */
+ os_memcpy(_t, t, 20);
+ sha1_transform((u8 *) _t, xkey);
+ _t[0] = host_to_be32(_t[0]);
+ _t[1] = host_to_be32(_t[1]);
+ _t[2] = host_to_be32(_t[2]);
+ _t[3] = host_to_be32(_t[3]);
+ _t[4] = host_to_be32(_t[4]);
+ os_memcpy(xpos, _t, 20);
+
+ /* XKEY = (1 + XKEY + w_i) mod 2^b */
+ carry = 1;
+ for (k = 19; k >= 0; k--) {
+ carry += xkey[k] + xpos[k];
+ xkey[k] = carry & 0xff;
+ carry >>= 8;
+ }
+
+ xpos += 20;
+ }
+ /* x_j = w_0|w_1 */
+ }
+
+ return 0;
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
- ak = malloc(sizeof(*ak));
+ ak = os_malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
- free(ak);
+ os_free(ak);
return NULL;
}
return ak;
@@ -123,18 +176,18 @@ void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
void aes_encrypt_deinit(void *ctx)
{
- free(ctx);
+ os_free(ctx);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
- ak = malloc(sizeof(*ak));
+ ak = os_malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
- free(ak);
+ os_free(ak);
return NULL;
}
return ak;
@@ -149,6 +202,6 @@ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
void aes_decrypt_deinit(void *ctx)
{
- free(ctx);
+ os_free(ctx);
}
#endif /* EAP_TLS_FUNCS */
diff --git a/contrib/wpa_supplicant/crypto.h b/contrib/wpa_supplicant/crypto.h
index e664861afe71..00b13b91c48e 100644
--- a/contrib/wpa_supplicant/crypto.h
+++ b/contrib/wpa_supplicant/crypto.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for crypto libraries
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -56,16 +56,28 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
/**
- * sha1_transform - Perform one SHA-1 transform step
- * @state: SHA-1 state
- * @data: Input data for the SHA-1 transform
+ * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF
+ * @seed: Seed/key for the PRF
+ * @seed_len: Seed length in bytes
+ * @x: Buffer for PRF output
+ * @xlen: Output length in bytes
+ * Returns: 0 on success, -1 on failure
*
- * This function is used to implement random number generation specified in
- * NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is
- * similar to SHA-1, but has different message padding and as such, access to
- * just part of the SHA-1 is needed.
+ * This function implements random number generation specified in NIST FIPS
+ * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to
+ * SHA-1, but has different message padding.
*/
-void sha1_transform(u8 *state, const u8 data[64]);
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen);
+
+/**
+ * sha256_vector - SHA256 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ */
+void sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac);
/**
* des_encrypt - Encrypt one block with DES
@@ -120,4 +132,282 @@ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
void aes_decrypt_deinit(void *ctx);
+enum crypto_hash_alg {
+ CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
+ CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1
+};
+
+struct crypto_hash;
+
+/**
+ * crypto_hash_init - Initialize hash/HMAC function
+ * @alg: Hash algorithm
+ * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed
+ * @key_len: Length of the key in bytes
+ * Returns: Pointer to hash context to use with other hash functions or %NULL
+ * on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len);
+
+/**
+ * crypto_hash_update - Add data to hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @data: Data buffer to add
+ * @len: Length of the buffer
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len);
+
+/**
+ * crypto_hash_finish - Complete hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @hash: Buffer for hash value or %NULL if caller is just freeing the hash
+ * context
+ * @len: Pointer to length of the buffer or %NULL if caller is just freeing the
+ * hash context; on return, this is set to the actual length of the hash value
+ * Returns: 0 on success, -1 if buffer is too small (len set to needed length),
+ * or -2 on other failures (including failed crypto_hash_update() operations)
+ *
+ * This function calculates the hash value and frees the context buffer that
+ * was used for hash calculation.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len);
+
+
+enum crypto_cipher_alg {
+ CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,
+ CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4
+};
+
+struct crypto_cipher;
+
+/**
+ * crypto_cipher_init - Initialize block/stream cipher function
+ * @alg: Cipher algorithm
+ * @iv: Initialization vector for block ciphers or %NULL for stream ciphers
+ * @key: Cipher key
+ * @key_len: Length of key in bytes
+ * Returns: Pointer to cipher context to use with other cipher functions or
+ * %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len);
+
+/**
+ * crypto_cipher_encrypt - Cipher encrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @plain: Plaintext to cipher
+ * @crypt: Resulting ciphertext
+ * @len: Length of the plaintext
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Cipher decrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @crypt: Ciphertext to decrypt
+ * @plain: Resulting plaintext
+ * @len: Length of the cipher text
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Free cipher context
+ * @ctx: Context pointer from crypto_cipher_init()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_cipher_deinit(struct crypto_cipher *ctx);
+
+
+struct crypto_public_key;
+struct crypto_private_key;
+
+/**
+ * crypto_public_key_import - Import an RSA public key
+ * @key: Key buffer (DER encoded RSA public key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library supports X.509
+ * parsing. In that case, crypto_public_key_from_cert() is used to import the
+ * public key from a certificate.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
+
+/**
+ * crypto_private_key_import - Import an RSA private key
+ * @key: Key buffer (DER encoded RSA private key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the private key or %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+ size_t len);
+
+/**
+ * crypto_public_key_from_cert - Import an RSA public key from a certificate
+ * @buf: DER encoded X.509 certificate
+ * @len: Certificate buffer length in bytes
+ * Returns: Pointer to public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library does not support
+ * X.509 parsing. In that case, internal code will be used to parse the
+ * certificate and public key is imported using crypto_public_key_import().
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+ size_t len);
+
+/**
+ * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5)
+ * @key: Public key
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen);
+
+/**
+ * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
+ * @key: Private key from crypto_private_key_import()
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted (signed) data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen);
+
+/**
+ * crypto_public_key_free - Free public key
+ * @key: Public key
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_public_key_free(struct crypto_public_key *key);
+
+/**
+ * crypto_private_key_free - Free private key
+ * @key: Private key from crypto_private_key_import()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_private_key_free(struct crypto_private_key *key);
+
+/**
+ * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature
+ * @key: Public key
+ * @crypt: Encrypted signature data (using the private key)
+ * @crypt_len: Encrypted signature data length
+ * @plain: Buffer for plaintext (at least crypt_len bytes)
+ * @plain_len: Plaintext length (max buffer size on input, real len on output);
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
+ const u8 *crypt, size_t crypt_len,
+ u8 *plain, size_t *plain_len);
+
+/**
+ * crypto_global_init - Initialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_global_init(void);
+
+/**
+ * crypto_global_deinit - Deinitialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_global_deinit(void);
+
+/**
+ * crypto_mod_exp - Modular exponentiation of large integers
+ * @base: Base integer (big endian byte array)
+ * @base_len: Length of base integer in bytes
+ * @power: Power integer (big endian byte array)
+ * @power_len: Length of power integer in bytes
+ * @modulus: Modulus integer (big endian byte array)
+ * @modulus_len: Length of modulus integer in bytes
+ * @result: Buffer for the result
+ * @result_len: Result length (max buffer size on input, real len on output)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function calculates result = base ^ power mod modulus. modules_len is
+ * used as the maximum size of modulus buffer. It is set to the used size on
+ * success.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_mod_exp(const u8 *base, size_t base_len,
+ const u8 *power, size_t power_len,
+ const u8 *modulus, size_t modulus_len,
+ u8 *result, size_t *result_len);
+
#endif /* CRYPTO_H */
diff --git a/contrib/wpa_supplicant/crypto_cryptoapi.c b/contrib/wpa_supplicant/crypto_cryptoapi.c
new file mode 100644
index 000000000000..bb0573078d24
--- /dev/null
+++ b/contrib/wpa_supplicant/crypto_cryptoapi.c
@@ -0,0 +1,801 @@
+/*
+ * WPA Supplicant / Crypto wrapper for Microsoft CryptoAPI
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <windows.h>
+#include <wincrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+#ifndef MS_ENH_RSA_AES_PROV
+#ifdef UNICODE
+#define MS_ENH_RSA_AES_PROV \
+L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
+#else
+#define MS_ENH_RSA_AES_PROV \
+"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
+#endif
+#endif /* MS_ENH_RSA_AES_PROV */
+
+#ifndef CALG_HMAC
+#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
+#endif
+
+#ifdef CONFIG_TLS_INTERNAL
+#ifdef __MINGW32_VERSION
+/*
+ * MinGW does not yet include all the needed definitions for CryptoAPI, so
+ * define here whatever extra is needed.
+ */
+
+static PCCERT_CONTEXT WINAPI
+(*CertCreateCertificateContext)(DWORD dwCertEncodingType,
+ const BYTE *pbCertEncoded,
+ DWORD cbCertEncoded)
+= NULL; /* to be loaded from crypt32.dll */
+
+static BOOL WINAPI
+(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
+ PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
+= NULL; /* to be loaded from crypt32.dll */
+
+
+static int mingw_load_crypto_func(void)
+{
+ HINSTANCE dll;
+
+ /* MinGW does not yet have full CryptoAPI support, so load the needed
+ * function here. */
+
+ if (CertCreateCertificateContext)
+ return 0;
+
+ dll = LoadLibrary("crypt32");
+ if (dll == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
+ "library");
+ return -1;
+ }
+
+ CertCreateCertificateContext = (void *) GetProcAddress(
+ dll, "CertCreateCertificateContext");
+ if (CertCreateCertificateContext == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+ "CertCreateCertificateContext() address from "
+ "crypt32 library");
+ return -1;
+ }
+
+ CryptImportPublicKeyInfo = GetProcAddress(
+ dll, "CryptImportPublicKeyInfo");
+ if (CryptImportPublicKeyInfo == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+ "CryptImportPublicKeyInfo() address from "
+ "crypt32 library");
+ return -1;
+ }
+
+ return 0;
+}
+
+#else /* __MINGW32_VERSION */
+
+static int mingw_load_crypto_func(void)
+{
+ return 0;
+}
+
+#endif /* __MINGW32_VERSION */
+#endif /* CONFIG_TLS_INTERNAL */
+
+
+static void cryptoapi_report_error(const char *msg)
+{
+ char *s, *pos;
+ DWORD err = GetLastError();
+
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
+ }
+
+ pos = s;
+ while (*pos) {
+ if (*pos == '\n' || *pos == '\r') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+
+ wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
+ LocalFree(s);
+}
+
+
+int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ HCRYPTPROV prov;
+ HCRYPTHASH hash;
+ size_t i;
+ DWORD hlen;
+ int ret = 0;
+
+ if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
+ cryptoapi_report_error("CryptAcquireContext");
+ return -1;
+ }
+
+ if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
+ cryptoapi_report_error("CryptCreateHash");
+ CryptReleaseContext(prov, 0);
+ return -1;
+ }
+
+ for (i = 0; i < num_elem; i++) {
+ if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
+ cryptoapi_report_error("CryptHashData");
+ CryptDestroyHash(hash);
+ CryptReleaseContext(prov, 0);
+ }
+ }
+
+ hlen = hash_len;
+ if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
+ cryptoapi_report_error("CryptGetHashParam");
+ ret = -1;
+ }
+
+ CryptDestroyHash(hash);
+ CryptReleaseContext(prov, 0);
+
+ return ret;
+}
+
+
+void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ u8 next, tmp;
+ int i;
+ HCRYPTPROV prov;
+ HCRYPTKEY ckey;
+ DWORD dlen;
+ struct {
+ BLOBHEADER hdr;
+ DWORD len;
+ BYTE key[8];
+ } key_blob;
+ DWORD mode = CRYPT_MODE_ECB;
+
+ key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob.hdr.reserved = 0;
+ key_blob.hdr.aiKeyAlg = CALG_DES;
+ key_blob.len = 8;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ key_blob.key[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ key_blob.key[i] = next | 1;
+
+ if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
+ "%d", (int) GetLastError());
+ return;
+ }
+
+ if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
+ &ckey)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
+ (int) GetLastError());
+ CryptReleaseContext(prov, 0);
+ return;
+ }
+
+ if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
+ "failed: %d", (int) GetLastError());
+ CryptDestroyKey(ckey);
+ CryptReleaseContext(prov, 0);
+ return;
+ }
+
+ os_memcpy(cypher, clear, 8);
+ dlen = 8;
+ if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
+ (int) GetLastError());
+ os_memset(cypher, 0, 8);
+ }
+
+ CryptDestroyKey(ckey);
+ CryptReleaseContext(prov, 0);
+}
+
+
+#ifdef EAP_TLS_FUNCS
+void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
+}
+
+
+void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
+}
+
+
+struct aes_context {
+ HCRYPTPROV prov;
+ HCRYPTKEY ckey;
+};
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ struct aes_context *akey;
+ struct {
+ BLOBHEADER hdr;
+ DWORD len;
+ BYTE key[16];
+ } key_blob;
+ DWORD mode = CRYPT_MODE_ECB;
+
+ if (len != 16)
+ return NULL;
+
+ key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob.hdr.reserved = 0;
+ key_blob.hdr.aiKeyAlg = CALG_AES_128;
+ key_blob.len = len;
+ os_memcpy(key_blob.key, key, len);
+
+ akey = os_zalloc(sizeof(*akey));
+ if (akey == NULL)
+ return NULL;
+
+ if (!CryptAcquireContext(&akey->prov, NULL,
+ MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
+ CRYPT_VERIFYCONTEXT)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
+ "%d", (int) GetLastError());
+ os_free(akey);
+ return NULL;
+ }
+
+ if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
+ 0, 0, &akey->ckey)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
+ (int) GetLastError());
+ CryptReleaseContext(akey->prov, 0);
+ os_free(akey);
+ return NULL;
+ }
+
+ if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
+ "failed: %d", (int) GetLastError());
+ CryptDestroyKey(akey->ckey);
+ CryptReleaseContext(akey->prov, 0);
+ os_free(akey);
+ return NULL;
+ }
+
+ return akey;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ struct aes_context *akey = ctx;
+ DWORD dlen;
+
+ os_memcpy(crypt, plain, 16);
+ dlen = 16;
+ if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
+ (int) GetLastError());
+ os_memset(crypt, 0, 16);
+ }
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ struct aes_context *akey = ctx;
+ if (akey) {
+ CryptDestroyKey(akey->ckey);
+ CryptReleaseContext(akey->prov, 0);
+ os_free(akey);
+ }
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ return aes_encrypt_init(key, len);
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ struct aes_context *akey = ctx;
+ DWORD dlen;
+
+ os_memcpy(plain, crypt, 16);
+ dlen = 16;
+
+ if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
+ (int) GetLastError());
+ }
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ aes_encrypt_deinit(ctx);
+}
+
+#ifdef CONFIG_TLS_INTERNAL
+
+struct crypto_hash {
+ enum crypto_hash_alg alg;
+ int error;
+ HCRYPTPROV prov;
+ HCRYPTHASH hash;
+ HCRYPTKEY key;
+};
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ctx;
+ ALG_ID calg;
+ struct {
+ BLOBHEADER hdr;
+ DWORD len;
+ BYTE key[32];
+ } key_blob;
+
+ os_memset(&key_blob, 0, sizeof(key_blob));
+ switch (alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ calg = CALG_MD5;
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ calg = CALG_SHA;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ calg = CALG_HMAC;
+ key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob.hdr.reserved = 0;
+ /*
+ * Note: RC2 is not really used, but that can be used to
+ * import HMAC keys of up to 16 byte long.
+ * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
+ * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
+ */
+ key_blob.hdr.aiKeyAlg = CALG_RC2;
+ key_blob.len = key_len;
+ if (key_len > sizeof(key_blob.key))
+ return NULL;
+ os_memcpy(key_blob.key, key, key_len);
+ break;
+ default:
+ return NULL;
+ }
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->alg = alg;
+
+ if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
+ cryptoapi_report_error("CryptAcquireContext");
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (calg == CALG_HMAC) {
+#ifndef CRYPT_IPSEC_HMAC_KEY
+#define CRYPT_IPSEC_HMAC_KEY 0x00000100
+#endif
+ if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
+ sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
+ &ctx->key)) {
+ cryptoapi_report_error("CryptImportKey");
+ CryptReleaseContext(ctx->prov, 0);
+ os_free(ctx);
+ return NULL;
+ }
+ }
+
+ if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
+ cryptoapi_report_error("CryptCreateHash");
+ CryptReleaseContext(ctx->prov, 0);
+ os_free(ctx);
+ return NULL;
+ }
+
+ if (calg == CALG_HMAC) {
+ HMAC_INFO info;
+ os_memset(&info, 0, sizeof(info));
+ switch (alg) {
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ info.HashAlgid = CALG_MD5;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ info.HashAlgid = CALG_SHA;
+ break;
+ default:
+ /* unreachable */
+ break;
+ }
+
+ if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
+ 0)) {
+ cryptoapi_report_error("CryptSetHashParam");
+ CryptDestroyHash(ctx->hash);
+ CryptReleaseContext(ctx->prov, 0);
+ os_free(ctx);
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ if (ctx == NULL || ctx->error)
+ return;
+
+ if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
+ cryptoapi_report_error("CryptHashData");
+ ctx->error = 1;
+ }
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ int ret = 0;
+ DWORD hlen;
+
+ if (ctx == NULL)
+ return -2;
+
+ if (mac == NULL || len == NULL)
+ goto done;
+
+ if (ctx->error) {
+ ret = -2;
+ goto done;
+ }
+
+ hlen = *len;
+ if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
+ cryptoapi_report_error("CryptGetHashParam");
+ ret = -2;
+ }
+ *len = hlen;
+
+done:
+ if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
+ ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
+ CryptDestroyKey(ctx->key);
+
+ os_free(ctx);
+
+ return ret;
+}
+
+
+struct crypto_cipher {
+ HCRYPTPROV prov;
+ HCRYPTKEY key;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+ struct {
+ BLOBHEADER hdr;
+ DWORD len;
+ BYTE key[32];
+ } key_blob;
+ DWORD mode = CRYPT_MODE_CBC;
+
+ key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+ key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+ key_blob.hdr.reserved = 0;
+ key_blob.len = key_len;
+ if (key_len > sizeof(key_blob.key))
+ return NULL;
+ os_memcpy(key_blob.key, key, key_len);
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_AES:
+ if (key_len == 32)
+ key_blob.hdr.aiKeyAlg = CALG_AES_256;
+ else if (key_len == 24)
+ key_blob.hdr.aiKeyAlg = CALG_AES_192;
+ else
+ key_blob.hdr.aiKeyAlg = CALG_AES_128;
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ key_blob.hdr.aiKeyAlg = CALG_3DES;
+ break;
+ case CRYPTO_CIPHER_ALG_DES:
+ key_blob.hdr.aiKeyAlg = CALG_DES;
+ break;
+ case CRYPTO_CIPHER_ALG_RC2:
+ key_blob.hdr.aiKeyAlg = CALG_RC2;
+ break;
+ case CRYPTO_CIPHER_ALG_RC4:
+ key_blob.hdr.aiKeyAlg = CALG_RC4;
+ break;
+ default:
+ return NULL;
+ }
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
+ PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
+ cryptoapi_report_error("CryptAcquireContext");
+ goto fail1;
+ }
+
+ if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
+ sizeof(key_blob), 0, 0, &ctx->key)) {
+ cryptoapi_report_error("CryptImportKey");
+ goto fail2;
+ }
+
+ if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
+ cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
+ goto fail3;
+ }
+
+ if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
+ cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
+ goto fail3;
+ }
+
+ return ctx;
+
+fail3:
+ CryptDestroyKey(ctx->key);
+fail2:
+ CryptReleaseContext(ctx->prov, 0);
+fail1:
+ os_free(ctx);
+ return NULL;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ DWORD dlen;
+
+ os_memcpy(crypt, plain, len);
+ dlen = len;
+ if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
+ cryptoapi_report_error("CryptEncrypt");
+ os_memset(crypt, 0, len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ DWORD dlen;
+
+ os_memcpy(plain, crypt, len);
+ dlen = len;
+ if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
+ cryptoapi_report_error("CryptDecrypt");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ CryptDestroyKey(ctx->key);
+ CryptReleaseContext(ctx->prov, 0);
+ os_free(ctx);
+}
+
+
+struct crypto_public_key {
+ HCRYPTPROV prov;
+ HCRYPTKEY rsa;
+};
+
+struct crypto_private_key {
+ HCRYPTPROV prov;
+ HCRYPTKEY rsa;
+};
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+ /* Use crypto_public_key_from_cert() instead. */
+ return NULL;
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+ size_t len)
+{
+ /* TODO */
+ return NULL;
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+ size_t len)
+{
+ struct crypto_public_key *pk;
+ PCCERT_CONTEXT cc;
+
+ pk = os_zalloc(sizeof(*pk));
+ if (pk == NULL)
+ return NULL;
+
+ cc = CertCreateCertificateContext(X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING, buf, len);
+ if (!cc) {
+ cryptoapi_report_error("CryptCreateCertificateContext");
+ os_free(pk);
+ return NULL;
+ }
+
+ if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+ 0)) {
+ cryptoapi_report_error("CryptAcquireContext");
+ os_free(pk);
+ CertFreeCertificateContext(cc);
+ return NULL;
+ }
+
+ if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING,
+ &cc->pCertInfo->SubjectPublicKeyInfo,
+ &pk->rsa)) {
+ cryptoapi_report_error("CryptImportPublicKeyInfo");
+ CryptReleaseContext(pk->prov, 0);
+ os_free(pk);
+ CertFreeCertificateContext(cc);
+ return NULL;
+ }
+
+ CertFreeCertificateContext(cc);
+
+ return pk;
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ DWORD clen;
+ u8 *tmp;
+ size_t i;
+
+ if (*outlen < inlen)
+ return -1;
+ tmp = malloc(*outlen);
+ if (tmp == NULL)
+ return -1;
+
+ os_memcpy(tmp, in, inlen);
+ clen = inlen;
+ if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
+ "public key: %d", (int) GetLastError());
+ os_free(tmp);
+ return -1;
+ }
+
+ *outlen = clen;
+
+ /* Reverse the output */
+ for (i = 0; i < *outlen; i++)
+ out[i] = tmp[*outlen - 1 - i];
+
+ os_free(tmp);
+
+ return 0;
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ /* TODO */
+ return -1;
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+ if (key) {
+ CryptDestroyKey(key->rsa);
+ CryptReleaseContext(key->prov, 0);
+ os_free(key);
+ }
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+ if (key) {
+ CryptDestroyKey(key->rsa);
+ CryptReleaseContext(key->prov, 0);
+ os_free(key);
+ }
+}
+
+
+int crypto_global_init(void)
+{
+ return mingw_load_crypto_func();
+}
+
+
+void crypto_global_deinit(void)
+{
+}
+
+#endif /* CONFIG_TLS_INTERNAL */
+
+#endif /* EAP_TLS_FUNCS */
diff --git a/contrib/wpa_supplicant/crypto_gnutls.c b/contrib/wpa_supplicant/crypto_gnutls.c
index 15f9b54ae804..4bf75f132a00 100644
--- a/contrib/wpa_supplicant/crypto_gnutls.c
+++ b/contrib/wpa_supplicant/crypto_gnutls.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for libgcrypt
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,8 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdio.h>
-#include <sys/types.h>
+#include "includes.h"
#include <gcrypt.h>
#include "common.h"
@@ -23,7 +22,7 @@ void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
- int i;
+ size_t i;
if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
return;
@@ -63,7 +62,7 @@ void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
- int i;
+ size_t i;
if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
return;
@@ -80,7 +79,7 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
unsigned char *p;
- int i;
+ size_t i;
if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
return;
@@ -93,9 +92,10 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
}
-void sha1_transform(u8 *state, const u8 data[64])
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
{
/* FIX: how to do this with libgcrypt? */
+ return -1;
}
diff --git a/contrib/wpa_supplicant/crypto_internal.c b/contrib/wpa_supplicant/crypto_internal.c
new file mode 100644
index 000000000000..d0c20371a73d
--- /dev/null
+++ b/contrib/wpa_supplicant/crypto_internal.c
@@ -0,0 +1,670 @@
+/*
+ * WPA Supplicant / Crypto wrapper for internal crypto implementation
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "md5.h"
+#include "sha1.h"
+#include "rc4.h"
+#include "aes.h"
+#include "rsa.h"
+#include "bignum.h"
+
+
+#ifdef EAP_TLS_FUNCS
+
+#ifdef CONFIG_TLS_INTERNAL
+
+/* from des.c */
+struct des3_key_s {
+ u32 ek[3][32];
+ u32 dk[3][32];
+};
+
+void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
+
+
+struct MD5Context {
+ u32 buf[4];
+ u32 bits[2];
+ u8 in[64];
+};
+
+struct SHA1Context {
+ u32 state[5];
+ u32 count[2];
+ unsigned char buffer[64];
+};
+
+
+struct crypto_hash {
+ enum crypto_hash_alg alg;
+ union {
+ struct MD5Context md5;
+ struct SHA1Context sha1;
+ } u;
+ u8 key[64];
+ size_t key_len;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ctx;
+ u8 k_pad[64];
+ u8 tk[20];
+ size_t i;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->alg = alg;
+
+ switch (alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ MD5Init(&ctx->u.md5);
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ SHA1Init(&ctx->u.sha1);
+ break;
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ if (key_len > sizeof(k_pad)) {
+ MD5Init(&ctx->u.md5);
+ MD5Update(&ctx->u.md5, key, key_len);
+ MD5Final(tk, &ctx->u.md5);
+ key = tk;
+ key_len = 16;
+ }
+ os_memcpy(ctx->key, key, key_len);
+ ctx->key_len = key_len;
+
+ os_memcpy(k_pad, key, key_len);
+ os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+ for (i = 0; i < sizeof(k_pad); i++)
+ k_pad[i] ^= 0x36;
+ MD5Init(&ctx->u.md5);
+ MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ if (key_len > sizeof(k_pad)) {
+ SHA1Init(&ctx->u.sha1);
+ SHA1Update(&ctx->u.sha1, key, key_len);
+ SHA1Final(tk, &ctx->u.sha1);
+ key = tk;
+ key_len = 20;
+ }
+ os_memcpy(ctx->key, key, key_len);
+ ctx->key_len = key_len;
+
+ os_memcpy(k_pad, key, key_len);
+ os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+ for (i = 0; i < sizeof(k_pad); i++)
+ k_pad[i] ^= 0x36;
+ SHA1Init(&ctx->u.sha1);
+ SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ if (ctx == NULL)
+ return;
+
+ switch (ctx->alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ MD5Update(&ctx->u.md5, data, len);
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ SHA1Update(&ctx->u.sha1, data, len);
+ break;
+ }
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ u8 k_pad[64];
+ size_t i;
+
+ if (ctx == NULL)
+ return -2;
+
+ if (mac == NULL || len == NULL) {
+ os_free(ctx);
+ return 0;
+ }
+
+ switch (ctx->alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ if (*len < 16) {
+ *len = 16;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 16;
+ MD5Final(mac, &ctx->u.md5);
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ if (*len < 20) {
+ *len = 20;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 20;
+ SHA1Final(mac, &ctx->u.sha1);
+ break;
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ if (*len < 16) {
+ *len = 16;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 16;
+
+ MD5Final(mac, &ctx->u.md5);
+
+ os_memcpy(k_pad, ctx->key, ctx->key_len);
+ os_memset(k_pad + ctx->key_len, 0,
+ sizeof(k_pad) - ctx->key_len);
+ for (i = 0; i < sizeof(k_pad); i++)
+ k_pad[i] ^= 0x5c;
+ MD5Init(&ctx->u.md5);
+ MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
+ MD5Update(&ctx->u.md5, mac, 16);
+ MD5Final(mac, &ctx->u.md5);
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ if (*len < 20) {
+ *len = 20;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 20;
+
+ SHA1Final(mac, &ctx->u.sha1);
+
+ os_memcpy(k_pad, ctx->key, ctx->key_len);
+ os_memset(k_pad + ctx->key_len, 0,
+ sizeof(k_pad) - ctx->key_len);
+ for (i = 0; i < sizeof(k_pad); i++)
+ k_pad[i] ^= 0x5c;
+ SHA1Init(&ctx->u.sha1);
+ SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
+ SHA1Update(&ctx->u.sha1, mac, 20);
+ SHA1Final(mac, &ctx->u.sha1);
+ break;
+ }
+
+ os_free(ctx);
+
+ return 0;
+}
+
+
+struct crypto_cipher {
+ enum crypto_cipher_alg alg;
+ union {
+ struct {
+ size_t used_bytes;
+ u8 key[16];
+ size_t keylen;
+ } rc4;
+ struct {
+ u8 cbc[32];
+ size_t block_size;
+ void *ctx_enc;
+ void *ctx_dec;
+ } aes;
+ struct {
+ struct des3_key_s key;
+ u8 cbc[8];
+ } des3;
+ } u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->alg = alg;
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ if (key_len > sizeof(ctx->u.rc4.key)) {
+ os_free(ctx);
+ return NULL;
+ }
+ ctx->u.rc4.keylen = key_len;
+ os_memcpy(ctx->u.rc4.key, key, key_len);
+ break;
+ case CRYPTO_CIPHER_ALG_AES:
+ if (key_len > sizeof(ctx->u.aes.cbc)) {
+ os_free(ctx);
+ return NULL;
+ }
+ ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
+ if (ctx->u.aes.ctx_enc == NULL) {
+ os_free(ctx);
+ return NULL;
+ }
+ ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
+ if (ctx->u.aes.ctx_dec == NULL) {
+ aes_encrypt_deinit(ctx->u.aes.ctx_enc);
+ os_free(ctx);
+ return NULL;
+ }
+ ctx->u.aes.block_size = key_len;
+ os_memcpy(ctx->u.aes.cbc, iv, ctx->u.aes.block_size);
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (key_len != 24) {
+ os_free(ctx);
+ return NULL;
+ }
+ des3_key_setup(key, &ctx->u.des3.key);
+ os_memcpy(ctx->u.des3.cbc, iv, 8);
+ break;
+ default:
+ os_free(ctx);
+ return NULL;
+ }
+
+ return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ size_t i, j, blocks;
+
+ switch (ctx->alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ if (plain != crypt)
+ os_memcpy(crypt, plain, len);
+ rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+ ctx->u.rc4.used_bytes, crypt, len);
+ ctx->u.rc4.used_bytes += len;
+ break;
+ case CRYPTO_CIPHER_ALG_AES:
+ if (len % ctx->u.aes.block_size)
+ return -1;
+ blocks = len / ctx->u.aes.block_size;
+ for (i = 0; i < blocks; i++) {
+ for (j = 0; j < ctx->u.aes.block_size; j++)
+ ctx->u.aes.cbc[j] ^= plain[j];
+ aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
+ ctx->u.aes.cbc);
+ os_memcpy(crypt, ctx->u.aes.cbc,
+ ctx->u.aes.block_size);
+ plain += ctx->u.aes.block_size;
+ crypt += ctx->u.aes.block_size;
+ }
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (len % 8)
+ return -1;
+ blocks = len / 8;
+ for (i = 0; i < blocks; i++) {
+ for (j = 0; j < 8; j++)
+ ctx->u.des3.cbc[j] ^= plain[j];
+ des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
+ ctx->u.des3.cbc);
+ os_memcpy(crypt, ctx->u.des3.cbc, 8);
+ plain += 8;
+ crypt += 8;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ size_t i, j, blocks;
+ u8 tmp[32];
+
+ switch (ctx->alg) {
+ case CRYPTO_CIPHER_ALG_RC4:
+ if (plain != crypt)
+ os_memcpy(plain, crypt, len);
+ rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+ ctx->u.rc4.used_bytes, plain, len);
+ ctx->u.rc4.used_bytes += len;
+ break;
+ case CRYPTO_CIPHER_ALG_AES:
+ if (len % ctx->u.aes.block_size)
+ return -1;
+ blocks = len / ctx->u.aes.block_size;
+ for (i = 0; i < blocks; i++) {
+ os_memcpy(tmp, crypt, ctx->u.aes.block_size);
+ aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
+ for (j = 0; j < ctx->u.aes.block_size; j++)
+ plain[j] ^= ctx->u.aes.cbc[j];
+ os_memcpy(ctx->u.aes.cbc, tmp, ctx->u.aes.block_size);
+ plain += ctx->u.aes.block_size;
+ crypt += ctx->u.aes.block_size;
+ }
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ if (len % 8)
+ return -1;
+ blocks = len / 8;
+ for (i = 0; i < blocks; i++) {
+ os_memcpy(tmp, crypt, 8);
+ des3_decrypt(crypt, &ctx->u.des3.key, plain);
+ for (j = 0; j < 8; j++)
+ plain[j] ^= ctx->u.des3.cbc[j];
+ os_memcpy(ctx->u.des3.cbc, tmp, 8);
+ plain += 8;
+ crypt += 8;
+ }
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ switch (ctx->alg) {
+ case CRYPTO_CIPHER_ALG_AES:
+ aes_encrypt_deinit(ctx->u.aes.ctx_enc);
+ aes_decrypt_deinit(ctx->u.aes.ctx_dec);
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ break;
+ default:
+ break;
+ }
+ os_free(ctx);
+}
+
+
+/* Dummy structures; these are just typecast to struct crypto_rsa_key */
+struct crypto_public_key;
+struct crypto_private_key;
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+ return (struct crypto_public_key *)
+ crypto_rsa_import_public_key(key, len);
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+ size_t len)
+{
+ return (struct crypto_private_key *)
+ crypto_rsa_import_private_key(key, len);
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+ size_t len)
+{
+ /* No X.509 support in crypto_internal.c */
+ return NULL;
+}
+
+
+static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ size_t ps_len;
+ u8 *pos;
+
+ /*
+ * PKCS #1 v1.5, 8.1:
+ *
+ * EB = 00 || BT || PS || 00 || D
+ * BT = 00 or 01 for private-key operation; 02 for public-key operation
+ * PS = k-3-||D||; at least eight octets
+ * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
+ * k = length of modulus in octets (modlen)
+ */
+
+ if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
+ "lengths (modlen=%lu outlen=%lu inlen=%lu)",
+ __func__, (unsigned long) modlen,
+ (unsigned long) *outlen,
+ (unsigned long) inlen);
+ return -1;
+ }
+
+ pos = out;
+ *pos++ = 0x00;
+ *pos++ = block_type; /* BT */
+ ps_len = modlen - inlen - 3;
+ switch (block_type) {
+ case 0:
+ os_memset(pos, 0x00, ps_len);
+ pos += ps_len;
+ break;
+ case 1:
+ os_memset(pos, 0xff, ps_len);
+ pos += ps_len;
+ break;
+ case 2:
+ if (os_get_random(pos, ps_len) < 0) {
+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
+ "random data for PS", __func__);
+ return -1;
+ }
+ while (ps_len--) {
+ if (*pos == 0x00)
+ *pos = 0x01;
+ pos++;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
+ "%d", __func__, block_type);
+ return -1;
+ }
+ *pos++ = 0x00;
+ os_memcpy(pos, in, inlen); /* D */
+
+ return 0;
+}
+
+
+static int crypto_rsa_encrypt_pkcs1(int block_type, struct crypto_rsa_key *key,
+ int use_private,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ size_t modlen;
+
+ modlen = crypto_rsa_get_modulus_len(key);
+
+ if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
+ out, outlen) < 0)
+ return -1;
+
+ return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private);
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ return crypto_rsa_encrypt_pkcs1(2, (struct crypto_rsa_key *) key,
+ 0, in, inlen, out, outlen);
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ return crypto_rsa_encrypt_pkcs1(1, (struct crypto_rsa_key *) key,
+ 1, in, inlen, out, outlen);
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+ crypto_rsa_free((struct crypto_rsa_key *) key);
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+ crypto_rsa_free((struct crypto_rsa_key *) key);
+}
+
+
+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
+ const u8 *crypt, size_t crypt_len,
+ u8 *plain, size_t *plain_len)
+{
+ size_t len;
+ u8 *pos;
+
+ len = *plain_len;
+ if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len,
+ (struct crypto_rsa_key *) key, 0) < 0)
+ return -1;
+
+ /*
+ * PKCS #1 v1.5, 8.1:
+ *
+ * EB = 00 || BT || PS || 00 || D
+ * BT = 01
+ * PS = k-3-||D|| times FF
+ * k = length of modulus in octets
+ */
+
+ if (len < 3 + 8 + 16 /* min hash len */ ||
+ plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+ "structure");
+ return -1;
+ }
+
+ pos = plain + 3;
+ while (pos < plain + len && *pos == 0xff)
+ pos++;
+ if (pos - plain - 2 < 8) {
+ /* PKCS #1 v1.5, 8.1: At least eight octets long PS */
+ wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
+ "padding");
+ return -1;
+ }
+
+ if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+ "structure (2)");
+ return -1;
+ }
+ pos++;
+ len -= pos - plain;
+
+ /* Strip PKCS #1 header */
+ os_memmove(plain, pos, len);
+ *plain_len = len;
+
+ return 0;
+}
+
+
+int crypto_global_init(void)
+{
+ return 0;
+}
+
+
+void crypto_global_deinit(void)
+{
+}
+
+
+#ifdef EAP_FAST
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+ const u8 *power, size_t power_len,
+ const u8 *modulus, size_t modulus_len,
+ u8 *result, size_t *result_len)
+{
+ struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result;
+ int ret = 0;
+
+ bn_base = bignum_init();
+ bn_exp = bignum_init();
+ bn_modulus = bignum_init();
+ bn_result = bignum_init();
+
+ if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
+ bn_result == NULL)
+ goto error;
+
+ if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 ||
+ bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 ||
+ bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0)
+ goto error;
+
+ if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0)
+ goto error;
+
+ ret = bignum_get_unsigned_bin(bn_result, result, result_len);
+
+error:
+ bignum_deinit(bn_base);
+ bignum_deinit(bn_exp);
+ bignum_deinit(bn_modulus);
+ bignum_deinit(bn_result);
+ return ret;
+}
+
+#endif /* EAP_FAST */
+
+
+#endif /* CONFIG_TLS_INTERNAL */
+
+#endif /* EAP_TLS_FUNCS */
diff --git a/contrib/wpa_supplicant/crypto_libtomcrypt.c b/contrib/wpa_supplicant/crypto_libtomcrypt.c
new file mode 100644
index 000000000000..e82097f10a00
--- /dev/null
+++ b/contrib/wpa_supplicant/crypto_libtomcrypt.c
@@ -0,0 +1,736 @@
+/*
+ * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <tomcrypt.h>
+
+#include "common.h"
+#include "rc4.h"
+#include "crypto.h"
+
+#ifndef mp_init_multi
+#define mp_init_multi ltc_init_multi
+#define mp_clear_multi ltc_deinit_multi
+#define mp_unsigned_bin_size(a) ltc_mp.unsigned_size(a)
+#define mp_to_unsigned_bin(a, b) ltc_mp.unsigned_write(a, b)
+#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
+#define mp_exptmod(a,b,c,d) ltc_mp.exptmod(a,b,c,d)
+#endif
+
+
+void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ hash_state md;
+ size_t i;
+
+ md4_init(&md);
+ for (i = 0; i < num_elem; i++)
+ md4_process(&md, addr[i], len[i]);
+ md4_done(&md, mac);
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ u8 pkey[8], next, tmp;
+ int i;
+ symmetric_key skey;
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ des_setup(pkey, 8, 0, &skey);
+ des_ecb_encrypt(clear, cypher, &skey);
+ des_done(&skey);
+}
+
+
+#ifdef EAP_TLS_FUNCS
+void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ hash_state md;
+ size_t i;
+
+ md5_init(&md);
+ for (i = 0; i < num_elem; i++)
+ md5_process(&md, addr[i], len[i]);
+ md5_done(&md, mac);
+}
+
+
+void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ hash_state md;
+ size_t i;
+
+ sha1_init(&md);
+ for (i = 0; i < num_elem; i++)
+ sha1_process(&md, addr[i], len[i]);
+ sha1_done(&md, mac);
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ symmetric_key *skey;
+ skey = os_malloc(sizeof(*skey));
+ if (skey == NULL)
+ return NULL;
+ if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
+ os_free(skey);
+ return NULL;
+ }
+ return skey;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ symmetric_key *skey = ctx;
+ aes_ecb_encrypt(plain, crypt, skey);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ symmetric_key *skey = ctx;
+ aes_done(skey);
+ os_free(skey);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ symmetric_key *skey;
+ skey = os_malloc(sizeof(*skey));
+ if (skey == NULL)
+ return NULL;
+ if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
+ os_free(skey);
+ return NULL;
+ }
+ return skey;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ symmetric_key *skey = ctx;
+ aes_ecb_encrypt(plain, (u8 *) crypt, skey);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ symmetric_key *skey = ctx;
+ aes_done(skey);
+ os_free(skey);
+}
+
+
+#ifdef CONFIG_TLS_INTERNAL
+
+struct crypto_hash {
+ enum crypto_hash_alg alg;
+ int error;
+ union {
+ hash_state md;
+ hmac_state hmac;
+ } u;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_hash *ctx;
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ ctx->alg = alg;
+
+ switch (alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ if (md5_init(&ctx->u.md) != CRYPT_OK)
+ goto fail;
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ if (sha1_init(&ctx->u.md) != CRYPT_OK)
+ goto fail;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
+ CRYPT_OK)
+ goto fail;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
+ CRYPT_OK)
+ goto fail;
+ break;
+ default:
+ goto fail;
+ }
+
+ return ctx;
+
+fail:
+ os_free(ctx);
+ return NULL;
+}
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+ if (ctx == NULL || ctx->error)
+ return;
+
+ switch (ctx->alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
+ break;
+ }
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+ int ret = 0;
+ unsigned long clen;
+
+ if (ctx == NULL)
+ return -2;
+
+ if (mac == NULL || len == NULL) {
+ os_free(ctx);
+ return 0;
+ }
+
+ if (ctx->error) {
+ os_free(ctx);
+ return -2;
+ }
+
+ switch (ctx->alg) {
+ case CRYPTO_HASH_ALG_MD5:
+ if (*len < 16) {
+ *len = 16;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 16;
+ if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
+ ret = -2;
+ break;
+ case CRYPTO_HASH_ALG_SHA1:
+ if (*len < 20) {
+ *len = 20;
+ os_free(ctx);
+ return -1;
+ }
+ *len = 20;
+ if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
+ ret = -2;
+ break;
+ case CRYPTO_HASH_ALG_HMAC_SHA1:
+ if (*len < 20) {
+ *len = 20;
+ os_free(ctx);
+ return -1;
+ }
+ /* continue */
+ case CRYPTO_HASH_ALG_HMAC_MD5:
+ if (*len < 16) {
+ *len = 16;
+ os_free(ctx);
+ return -1;
+ }
+ clen = *len;
+ if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
+ os_free(ctx);
+ return -1;
+ }
+ *len = clen;
+ break;
+ default:
+ ret = -2;
+ break;
+ }
+
+ os_free(ctx);
+
+ return ret;
+}
+
+
+struct crypto_cipher {
+ int rc4;
+ union {
+ symmetric_CBC cbc;
+ struct {
+ size_t used_bytes;
+ u8 key[16];
+ size_t keylen;
+ } rc4;
+ } u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len)
+{
+ struct crypto_cipher *ctx;
+ int idx, res, rc4 = 0;
+
+ switch (alg) {
+ case CRYPTO_CIPHER_ALG_AES:
+ idx = find_cipher("aes");
+ break;
+ case CRYPTO_CIPHER_ALG_3DES:
+ idx = find_cipher("3des");
+ break;
+ case CRYPTO_CIPHER_ALG_DES:
+ idx = find_cipher("des");
+ break;
+ case CRYPTO_CIPHER_ALG_RC2:
+ idx = find_cipher("rc2");
+ break;
+ case CRYPTO_CIPHER_ALG_RC4:
+ idx = -1;
+ rc4 = 1;
+ break;
+ default:
+ return NULL;
+ }
+
+ ctx = os_zalloc(sizeof(*ctx));
+ if (ctx == NULL)
+ return NULL;
+
+ if (rc4) {
+ ctx->rc4 = 1;
+ if (key_len > sizeof(ctx->u.rc4.key)) {
+ os_free(ctx);
+ return NULL;
+ }
+ ctx->u.rc4.keylen = key_len;
+ os_memcpy(ctx->u.rc4.key, key, key_len);
+ } else {
+ res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
+ if (res != CRYPT_OK) {
+ wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
+ "failed: %s", error_to_string(res));
+ os_free(ctx);
+ return NULL;
+ }
+ }
+
+ return ctx;
+}
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len)
+{
+ int res;
+
+ if (ctx->rc4) {
+ if (plain != crypt)
+ os_memcpy(crypt, plain, len);
+ rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+ ctx->u.rc4.used_bytes, crypt, len);
+ ctx->u.rc4.used_bytes += len;
+ return 0;
+ }
+
+ res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
+ if (res != CRYPT_OK) {
+ wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
+ "failed: %s", error_to_string(res));
+ return -1;
+ }
+ return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len)
+{
+ int res;
+
+ if (ctx->rc4) {
+ if (plain != crypt)
+ os_memcpy(plain, crypt, len);
+ rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+ ctx->u.rc4.used_bytes, plain, len);
+ ctx->u.rc4.used_bytes += len;
+ return 0;
+ }
+
+ res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
+ if (res != CRYPT_OK) {
+ wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
+ "failed: %s", error_to_string(res));
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+ if (!ctx->rc4)
+ cbc_done(&ctx->u.cbc);
+ os_free(ctx);
+}
+
+
+struct crypto_public_key {
+ rsa_key rsa;
+};
+
+struct crypto_private_key {
+ rsa_key rsa;
+};
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+ int res;
+ struct crypto_public_key *pk;
+
+ pk = os_zalloc(sizeof(*pk));
+ if (pk == NULL)
+ return NULL;
+
+ res = rsa_import(key, len, &pk->rsa);
+ if (res != CRYPT_OK) {
+ wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
+ "public key (res=%d '%s')",
+ res, error_to_string(res));
+ os_free(pk);
+ return NULL;
+ }
+
+ if (pk->rsa.type != PK_PUBLIC) {
+ wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
+ "correct type");
+ rsa_free(&pk->rsa);
+ os_free(pk);
+ return NULL;
+ }
+
+ return pk;
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+ size_t len)
+{
+ int res;
+ struct crypto_private_key *pk;
+
+ pk = os_zalloc(sizeof(*pk));
+ if (pk == NULL)
+ return NULL;
+
+ res = rsa_import(key, len, &pk->rsa);
+ if (res != CRYPT_OK) {
+ wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
+ "private key (res=%d '%s')",
+ res, error_to_string(res));
+ os_free(pk);
+ return NULL;
+ }
+
+ if (pk->rsa.type != PK_PRIVATE) {
+ wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
+ "correct type");
+ rsa_free(&pk->rsa);
+ os_free(pk);
+ return NULL;
+ }
+
+ return pk;
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+ size_t len)
+{
+ /* No X.509 support in LibTomCrypt */
+ return NULL;
+}
+
+
+static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ size_t ps_len;
+ u8 *pos;
+
+ /*
+ * PKCS #1 v1.5, 8.1:
+ *
+ * EB = 00 || BT || PS || 00 || D
+ * BT = 00 or 01 for private-key operation; 02 for public-key operation
+ * PS = k-3-||D||; at least eight octets
+ * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
+ * k = length of modulus in octets (modlen)
+ */
+
+ if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
+ "lengths (modlen=%lu outlen=%lu inlen=%lu)",
+ __func__, (unsigned long) modlen,
+ (unsigned long) *outlen,
+ (unsigned long) inlen);
+ return -1;
+ }
+
+ pos = out;
+ *pos++ = 0x00;
+ *pos++ = block_type; /* BT */
+ ps_len = modlen - inlen - 3;
+ switch (block_type) {
+ case 0:
+ os_memset(pos, 0x00, ps_len);
+ pos += ps_len;
+ break;
+ case 1:
+ os_memset(pos, 0xff, ps_len);
+ pos += ps_len;
+ break;
+ case 2:
+ if (os_get_random(pos, ps_len) < 0) {
+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
+ "random data for PS", __func__);
+ return -1;
+ }
+ while (ps_len--) {
+ if (*pos == 0x00)
+ *pos = 0x01;
+ pos++;
+ }
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
+ "%d", __func__, block_type);
+ return -1;
+ }
+ *pos++ = 0x00;
+ os_memcpy(pos, in, inlen); /* D */
+
+ return 0;
+}
+
+
+static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ unsigned long len, modlen;
+ int res;
+
+ modlen = mp_unsigned_bin_size(key->N);
+
+ if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
+ out, outlen) < 0)
+ return -1;
+
+ len = *outlen;
+ res = rsa_exptmod(out, modlen, out, &len, key_type, key);
+ if (res != CRYPT_OK) {
+ wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
+ error_to_string(res));
+ return -1;
+ }
+ *outlen = len;
+
+ return 0;
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
+ out, outlen);
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen)
+{
+ return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
+ out, outlen);
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+ if (key) {
+ rsa_free(&key->rsa);
+ os_free(key);
+ }
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+ if (key) {
+ rsa_free(&key->rsa);
+ os_free(key);
+ }
+}
+
+
+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
+ const u8 *crypt, size_t crypt_len,
+ u8 *plain, size_t *plain_len)
+{
+ int res;
+ unsigned long len;
+ u8 *pos;
+
+ len = *plain_len;
+ res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
+ &key->rsa);
+ if (res != CRYPT_OK) {
+ wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
+ error_to_string(res));
+ return -1;
+ }
+
+ /*
+ * PKCS #1 v1.5, 8.1:
+ *
+ * EB = 00 || BT || PS || 00 || D
+ * BT = 01
+ * PS = k-3-||D|| times FF
+ * k = length of modulus in octets
+ */
+
+ if (len < 3 + 8 + 16 /* min hash len */ ||
+ plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+ "structure");
+ return -1;
+ }
+
+ pos = plain + 3;
+ while (pos < plain + len && *pos == 0xff)
+ pos++;
+ if (pos - plain - 2 < 8) {
+ /* PKCS #1 v1.5, 8.1: At least eight octets long PS */
+ wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
+ "padding");
+ return -1;
+ }
+
+ if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
+ wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+ "structure (2)");
+ return -1;
+ }
+ pos++;
+ len -= pos - plain;
+
+ /* Strip PKCS #1 header */
+ os_memmove(plain, pos, len);
+ *plain_len = len;
+
+ return 0;
+}
+
+
+int crypto_global_init(void)
+{
+ ltc_mp = tfm_desc;
+ /* TODO: only register algorithms that are really needed */
+ if (register_hash(&md4_desc) < 0 ||
+ register_hash(&md5_desc) < 0 ||
+ register_hash(&sha1_desc) < 0 ||
+ register_cipher(&aes_desc) < 0 ||
+ register_cipher(&des_desc) < 0 ||
+ register_cipher(&des3_desc) < 0) {
+ wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
+ "hash/cipher functions");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void crypto_global_deinit(void)
+{
+}
+
+
+#ifdef EAP_FAST
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+ const u8 *power, size_t power_len,
+ const u8 *modulus, size_t modulus_len,
+ u8 *result, size_t *result_len)
+{
+ void *b, *p, *m, *r;
+
+ if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
+ return -1;
+
+ if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
+ mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
+ mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
+ goto fail;
+
+ if (mp_exptmod(b, p, m, r) != CRYPT_OK)
+ goto fail;
+
+ *result_len = mp_unsigned_bin_size(r);
+ if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
+ goto fail;
+
+ mp_clear_multi(b, p, m, r, NULL);
+ return 0;
+
+fail:
+ mp_clear_multi(b, p, m, r, NULL);
+ return -1;
+}
+
+#endif /* EAP_FAST */
+
+#endif /* CONFIG_TLS_INTERNAL */
+
+#endif /* EAP_TLS_FUNCS */
diff --git a/contrib/wpa_supplicant/crypto_none.c b/contrib/wpa_supplicant/crypto_none.c
new file mode 100644
index 000000000000..f18c2a8ded95
--- /dev/null
+++ b/contrib/wpa_supplicant/crypto_none.c
@@ -0,0 +1,28 @@
+/*
+ * WPA Supplicant / Empty template functions for crypto wrapper
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+
+void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+}
diff --git a/contrib/wpa_supplicant/ctrl_iface.c b/contrib/wpa_supplicant/ctrl_iface.c
index 01ea456af134..c864c91c5e03 100644
--- a/contrib/wpa_supplicant/ctrl_iface.c
+++ b/contrib/wpa_supplicant/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / UNIX domain and UDP socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * WPA Supplicant / Control interface (shared code for all backends)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,20 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/un.h>
-#include <sys/uio.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
#include "common.h"
#include "eloop.h"
@@ -37,31 +24,13 @@
#include "ctrl_iface.h"
#include "l2_packet.h"
#include "preauth.h"
+#include "pmksa_cache.h"
#include "wpa_ctrl.h"
#include "eap.h"
-#ifdef CONFIG_CTRL_IFACE_UDP
-#define CTRL_IFACE_SOCK struct sockaddr_in
-#else /* CONFIG_CTRL_IFACE_UDP */
-#define CTRL_IFACE_SOCK struct sockaddr_un
-#endif /* CONFIG_CTRL_IFACE_UDP */
-
-
-/**
- * struct wpa_ctrl_dst - Internal data structure of control interface monitors
- *
- * This structure is used to store information about registered control
- * interface monitors into struct wpa_supplicant. This data is private to
- * ctrl_iface.c and should not be touched directly from other files.
- */
-struct wpa_ctrl_dst {
- struct wpa_ctrl_dst *next;
- CTRL_IFACE_SOCK addr;
- socklen_t addrlen;
- int debug_level;
- int errors;
-};
+static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+ char *buf, int len);
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
@@ -70,33 +39,34 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *value;
int ret = 0;
- value = strchr(cmd, ' ');
+ value = os_strchr(cmd, ' ');
if (value == NULL)
return -1;
*value++ = '\0';
wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
- if (strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
+ if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
eapol_sm_configure(wpa_s->eapol,
atoi(value), -1, -1, -1);
- } else if (strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
+ } else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
eapol_sm_configure(wpa_s->eapol,
-1, atoi(value), -1, -1);
- } else if (strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
+ } else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
eapol_sm_configure(wpa_s->eapol,
-1, -1, atoi(value), -1);
- } else if (strcasecmp(cmd, "EAPOL::maxStart") == 0) {
+ } else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
eapol_sm_configure(wpa_s->eapol,
-1, -1, -1, atoi(value));
- } else if (strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
+ } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
atoi(value)))
ret = -1;
- } else if (strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") == 0) {
+ } else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
+ 0) {
if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
atoi(value)))
ret = -1;
- } else if (strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
+ } else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
ret = -1;
} else
@@ -126,129 +96,48 @@ static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_ctrl_iface_attach(struct wpa_supplicant *wpa_s,
- CTRL_IFACE_SOCK *from,
- socklen_t fromlen)
+#ifdef CONFIG_PEERKEY
+/* MLME-STKSTART.request(peer) */
+static int wpa_supplicant_ctrl_iface_stkstart(
+ struct wpa_supplicant *wpa_s, char *addr)
{
- struct wpa_ctrl_dst *dst;
+ u8 peer[ETH_ALEN];
- dst = malloc(sizeof(*dst));
- if (dst == NULL)
+ if (hwaddr_aton(addr, peer)) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
+ "address '%s'", peer);
return -1;
- memset(dst, 0, sizeof(*dst));
- memcpy(&dst->addr, from, sizeof(CTRL_IFACE_SOCK));
- dst->addrlen = fromlen;
- dst->debug_level = MSG_INFO;
- dst->next = wpa_s->ctrl_dst;
- wpa_s->ctrl_dst = dst;
-#ifdef CONFIG_CTRL_IFACE_UDP
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
- inet_ntoa(from->sin_addr), ntohs(from->sin_port));
-#else /* CONFIG_CTRL_IFACE_UDP */
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
- (u8 *) from->sun_path, fromlen);
-#endif /* CONFIG_CTRL_IFACE_UDP */
- return 0;
-}
-
-
-static int wpa_supplicant_ctrl_iface_detach(struct wpa_supplicant *wpa_s,
- CTRL_IFACE_SOCK *from,
- socklen_t fromlen)
-{
- struct wpa_ctrl_dst *dst, *prev = NULL;
-
- dst = wpa_s->ctrl_dst;
- while (dst) {
-#ifdef CONFIG_CTRL_IFACE_UDP
- if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
- from->sin_port == dst->addr.sin_port) {
- if (prev == NULL)
- wpa_s->ctrl_dst = dst->next;
- else
- prev->next = dst->next;
- free(dst);
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
- "%s:%d", inet_ntoa(from->sin_addr),
- ntohs(from->sin_port));
- return 0;
- }
-#else /* CONFIG_CTRL_IFACE_UDP */
- if (fromlen == dst->addrlen &&
- memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
- if (prev == NULL)
- wpa_s->ctrl_dst = dst->next;
- else
- prev->next = dst->next;
- free(dst);
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
- (u8 *) from->sun_path, fromlen);
- return 0;
- }
-#endif /* CONFIG_CTRL_IFACE_UDP */
- prev = dst;
- dst = dst->next;
}
- return -1;
-}
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
+ MAC2STR(peer));
-static int wpa_supplicant_ctrl_iface_level(struct wpa_supplicant *wpa_s,
- CTRL_IFACE_SOCK *from,
- socklen_t fromlen,
- char *level)
-{
- struct wpa_ctrl_dst *dst;
-
- wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
-
- dst = wpa_s->ctrl_dst;
- while (dst) {
-#ifdef CONFIG_CTRL_IFACE_UDP
- if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
- from->sin_port == dst->addr.sin_port) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
- "level %s:%d", inet_ntoa(from->sin_addr),
- ntohs(from->sin_port));
- dst->debug_level = atoi(level);
- return 0;
- }
-#else /* CONFIG_CTRL_IFACE_UDP */
- if (fromlen == dst->addrlen &&
- memcmp(from->sun_path, dst->addr.sun_path, fromlen) == 0) {
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
- "level", (u8 *) from->sun_path, fromlen);
- dst->debug_level = atoi(level);
- return 0;
- }
-#endif /* CONFIG_CTRL_IFACE_UDP */
- dst = dst->next;
- }
-
- return -1;
+ return wpa_sm_stkstart(wpa_s->wpa, peer);
}
+#endif /* CONFIG_PEERKEY */
static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
char *rsp)
{
+#ifdef IEEE8021X_EAPOL
char *pos, *id_pos;
int id;
struct wpa_ssid *ssid;
- pos = strchr(rsp, '-');
+ pos = os_strchr(rsp, '-');
if (pos == NULL)
return -1;
*pos++ = '\0';
id_pos = pos;
- pos = strchr(pos, ':');
+ pos = os_strchr(pos, ':');
if (pos == NULL)
return -1;
*pos++ = '\0';
id = atoi(id_pos);
wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
- (u8 *) pos, strlen(pos));
+ (u8 *) pos, os_strlen(pos));
ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid == NULL) {
@@ -257,43 +146,43 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
return -1;
}
- if (strcmp(rsp, "IDENTITY") == 0) {
- free(ssid->identity);
- ssid->identity = (u8 *) strdup(pos);
- ssid->identity_len = strlen(pos);
+ if (os_strcmp(rsp, "IDENTITY") == 0) {
+ os_free(ssid->identity);
+ ssid->identity = (u8 *) os_strdup(pos);
+ ssid->identity_len = os_strlen(pos);
ssid->pending_req_identity = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
- } else if (strcmp(rsp, "PASSWORD") == 0) {
- free(ssid->password);
- ssid->password = (u8 *) strdup(pos);
- ssid->password_len = strlen(pos);
+ } else if (os_strcmp(rsp, "PASSWORD") == 0) {
+ os_free(ssid->password);
+ ssid->password = (u8 *) os_strdup(pos);
+ ssid->password_len = os_strlen(pos);
ssid->pending_req_password = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
- } else if (strcmp(rsp, "NEW_PASSWORD") == 0) {
- free(ssid->new_password);
- ssid->new_password = (u8 *) strdup(pos);
- ssid->new_password_len = strlen(pos);
+ } else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
+ os_free(ssid->new_password);
+ ssid->new_password = (u8 *) os_strdup(pos);
+ ssid->new_password_len = os_strlen(pos);
ssid->pending_req_new_password = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
- } else if (strcmp(rsp, "PIN") == 0) {
- free(ssid->pin);
- ssid->pin = strdup(pos);
+ } else if (os_strcmp(rsp, "PIN") == 0) {
+ os_free(ssid->pin);
+ ssid->pin = os_strdup(pos);
ssid->pending_req_pin = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
- } else if (strcmp(rsp, "OTP") == 0) {
- free(ssid->otp);
- ssid->otp = (u8 *) strdup(pos);
- ssid->otp_len = strlen(pos);
- free(ssid->pending_req_otp);
+ } else if (os_strcmp(rsp, "OTP") == 0) {
+ os_free(ssid->otp);
+ ssid->otp = (u8 *) os_strdup(pos);
+ ssid->otp_len = os_strlen(pos);
+ os_free(ssid->pending_req_otp);
ssid->pending_req_otp = NULL;
ssid->pending_req_otp_len = 0;
- } else if (strcmp(rsp, "PASSPHRASE") == 0) {
- free(ssid->private_key_passwd);
- ssid->private_key_passwd = (u8 *) strdup(pos);
+ } else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
+ os_free(ssid->private_key_passwd);
+ ssid->private_key_passwd = (u8 *) os_strdup(pos);
ssid->pending_req_passphrase = 0;
if (ssid == wpa_s->current_ssid)
wpa_s->reassociate = 1;
@@ -303,6 +192,10 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
}
return 0;
+#else /* IEEE8021X_EAPOL */
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+ return -1;
+#endif /* IEEE8021X_EAPOL */
}
@@ -311,29 +204,62 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
char *buf, size_t buflen)
{
char *pos, *end, tmp[30];
- int res, verbose;
+ int res, verbose, ret;
- verbose = strcmp(params, "-VERBOSE") == 0;
+ verbose = os_strcmp(params, "-VERBOSE") == 0;
pos = buf;
end = buf + buflen;
if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
- pos += snprintf(pos, end - pos, "bssid=" MACSTR "\n",
- MAC2STR(wpa_s->bssid));
- if (wpa_s->current_ssid) {
- pos += snprintf(pos, end - pos, "ssid=%s\n",
- wpa_ssid_txt(wpa_s->current_ssid->ssid,
- wpa_s->current_ssid->
- ssid_len));
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
+ MAC2STR(wpa_s->bssid));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ if (ssid) {
+ u8 *_ssid = ssid->ssid;
+ size_t ssid_len = ssid->ssid_len;
+ u8 ssid_buf[MAX_SSID_LEN];
+ if (ssid_len == 0) {
+ int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
+ if (_res < 0)
+ ssid_len = 0;
+ else
+ ssid_len = _res;
+ _ssid = ssid_buf;
+ }
+ ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
+ wpa_ssid_txt(_ssid, ssid_len),
+ ssid->id);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+
+ if (ssid->id_str) {
+ ret = os_snprintf(pos, end - pos,
+ "id_str=%s\n",
+ ssid->id_str);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
}
pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
}
- pos += snprintf(pos, end - pos, "wpa_state=%s\n",
- wpa_supplicant_state_txt(wpa_s->wpa_state));
+ ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
+ wpa_supplicant_state_txt(wpa_s->wpa_state));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
if (wpa_s->l2 &&
- l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0)
- pos += snprintf(pos, end - pos, "ip_address=%s\n", tmp);
+ l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
+ ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
@@ -360,7 +286,7 @@ static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
u8 bssid[ETH_ALEN];
/* cmd: "<network id> <BSSID>" */
- pos = strchr(cmd, ' ');
+ pos = os_strchr(cmd, ' ');
if (pos == NULL)
return -1;
*pos++ = '\0';
@@ -378,9 +304,9 @@ static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
return -1;
}
- memcpy(ssid->bssid, bssid, ETH_ALEN);
+ os_memcpy(ssid->bssid, bssid, ETH_ALEN);
ssid->bssid_set =
- memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0;
+ os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0;
return 0;
@@ -392,26 +318,44 @@ static int wpa_supplicant_ctrl_iface_list_networks(
{
char *pos, *end;
struct wpa_ssid *ssid;
+ int ret;
pos = buf;
end = buf + buflen;
- pos += snprintf(pos, end - pos, "network id / ssid / bssid / flags\n");
+ ret = os_snprintf(pos, end - pos,
+ "network id / ssid / bssid / flags\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
ssid = wpa_s->conf->ssid;
while (ssid) {
- pos += snprintf(pos, end - pos, "%d\t%s",
- ssid->id,
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ ret = os_snprintf(pos, end - pos, "%d\t%s",
+ ssid->id,
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
if (ssid->bssid_set) {
- pos += snprintf(pos, end - pos, "\t" MACSTR,
- MAC2STR(ssid->bssid));
+ ret = os_snprintf(pos, end - pos, "\t" MACSTR,
+ MAC2STR(ssid->bssid));
} else {
- pos += snprintf(pos, end - pos, "\tany");
+ ret = os_snprintf(pos, end - pos, "\tany");
}
- pos += snprintf(pos, end - pos, "\t%s%s",
- ssid == wpa_s->current_ssid ? "[CURRENT]" : "",
- ssid->disabled ? "[DISABLED]" : "");
- pos += snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ ret = os_snprintf(pos, end - pos, "\t%s%s",
+ ssid == wpa_s->current_ssid ?
+ "[CURRENT]" : "",
+ ssid->disabled ? "[DISABLED]" : "");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
ssid = ssid->next;
}
@@ -422,66 +366,106 @@ static int wpa_supplicant_ctrl_iface_list_networks(
static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
{
- int first = 1;
- pos += snprintf(pos, end - pos, "-");
+ int first = 1, ret;
+ ret = os_snprintf(pos, end - pos, "-");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
if (cipher & WPA_CIPHER_NONE) {
- pos += snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
first = 0;
}
if (cipher & WPA_CIPHER_WEP40) {
- pos += snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
first = 0;
}
if (cipher & WPA_CIPHER_WEP104) {
- pos += snprintf(pos, end - pos, "%sWEP104", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sWEP104",
+ first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
first = 0;
}
if (cipher & WPA_CIPHER_TKIP) {
- pos += snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
first = 0;
}
if (cipher & WPA_CIPHER_CCMP) {
- pos += snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
first = 0;
}
return pos;
}
-static char * wpa_supplicant_ie_txt(struct wpa_supplicant *wpa_s,
- char *pos, char *end, const char *proto,
+static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
const u8 *ie, size_t ie_len)
{
struct wpa_ie_data data;
- int first;
+ int first, ret;
- pos += snprintf(pos, end - pos, "[%s-", proto);
+ ret = os_snprintf(pos, end - pos, "[%s-", proto);
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
- pos += snprintf(pos, end - pos, "?]");
+ ret = os_snprintf(pos, end - pos, "?]");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
return pos;
}
first = 1;
if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
- pos += snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
- pos += snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
first = 0;
}
if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
- pos += snprintf(pos, end - pos, "%sNone", first ? "" : "+");
+ ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
first = 0;
}
pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
- if (data.capabilities & WPA_CAPABILITY_PREAUTH)
- pos += snprintf(pos, end - pos, "-preauth");
+ if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
+ ret = os_snprintf(pos, end - pos, "-preauth");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
+ }
- pos += snprintf(pos, end - pos, "]");
+ ret = os_snprintf(pos, end - pos, "]");
+ if (ret < 0 || ret >= end - pos)
+ return pos;
+ pos += ret;
return pos;
}
@@ -492,41 +476,63 @@ static int wpa_supplicant_ctrl_iface_scan_results(
{
char *pos, *end;
struct wpa_scan_result *res;
- int i;
+ int i, ret;
if (wpa_s->scan_results == NULL &&
wpa_supplicant_get_scan_results(wpa_s) < 0)
return 0;
+ if (wpa_s->scan_results == NULL)
+ return 0;
pos = buf;
end = buf + buflen;
- pos += snprintf(pos, end - pos, "bssid / frequency / signal level / "
- "flags / ssid\n");
+ ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
+ "flags / ssid\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
for (i = 0; i < wpa_s->num_scan_results; i++) {
res = &wpa_s->scan_results[i];
- pos += snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
- MAC2STR(res->bssid), res->freq, res->level);
+ ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
+ MAC2STR(res->bssid), res->freq, res->level);
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
if (res->wpa_ie_len) {
- pos = wpa_supplicant_ie_txt(wpa_s, pos, end, "WPA",
+ pos = wpa_supplicant_ie_txt(pos, end, "WPA",
res->wpa_ie,
res->wpa_ie_len);
}
if (res->rsn_ie_len) {
- pos = wpa_supplicant_ie_txt(wpa_s, pos, end, "WPA2",
+ pos = wpa_supplicant_ie_txt(pos, end, "WPA2",
res->rsn_ie,
res->rsn_ie_len);
}
if (!res->wpa_ie_len && !res->rsn_ie_len &&
- res->caps & IEEE80211_CAP_PRIVACY)
- pos += snprintf(pos, end - pos, "[WEP]");
- if (res->caps & IEEE80211_CAP_IBSS)
- pos += snprintf(pos, end - pos, "[IBSS]");
+ res->caps & IEEE80211_CAP_PRIVACY) {
+ ret = os_snprintf(pos, end - pos, "[WEP]");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
+ if (res->caps & IEEE80211_CAP_IBSS) {
+ ret = os_snprintf(pos, end - pos, "[IBSS]");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
- pos += snprintf(pos, end - pos, "\t%s",
- wpa_ssid_txt(res->ssid, res->ssid_len));
+ ret = os_snprintf(pos, end - pos, "\t%s",
+ wpa_ssid_txt(res->ssid, res->ssid_len));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
- pos += snprintf(pos, end - pos, "\n");
+ ret = os_snprintf(pos, end - pos, "\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
}
return pos - buf;
@@ -540,7 +546,7 @@ static int wpa_supplicant_ctrl_iface_select_network(
struct wpa_ssid *ssid;
/* cmd: "<network id>" or "any" */
- if (strcmp(cmd, "any") == 0) {
+ if (os_strcmp(cmd, "any") == 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
ssid = wpa_s->conf->ssid;
while (ssid) {
@@ -637,6 +643,7 @@ static int wpa_supplicant_ctrl_iface_add_network(
struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
{
struct wpa_ssid *ssid;
+ int ret;
wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
@@ -646,7 +653,10 @@ static int wpa_supplicant_ctrl_iface_add_network(
ssid->disabled = 1;
wpa_config_set_network_defaults(ssid);
- return snprintf(buf, buflen, "%d\n", ssid->id);
+ ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
}
@@ -668,8 +678,15 @@ static int wpa_supplicant_ctrl_iface_remove_network(
return -1;
}
- if (ssid == wpa_s->current_ssid)
+ if (ssid == wpa_s->current_ssid) {
+ /*
+ * Invalidate the EAP session cache if the current network is
+ * removed.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+
wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
+ }
return 0;
}
@@ -683,19 +700,21 @@ static int wpa_supplicant_ctrl_iface_set_network(
char *name, *value;
/* cmd: "<network id> <variable name> <value>" */
- name = strchr(cmd, ' ');
+ name = os_strchr(cmd, ' ');
if (name == NULL)
return -1;
*name++ = '\0';
- value = strchr(name, ' ');
+ value = os_strchr(name, ' ');
if (value == NULL)
return -1;
*value++ = '\0';
id = atoi(cmd);
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s' "
- "value='%s'", id, name, value);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
+ id, name);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+ (u8 *) value, os_strlen(value));
ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid == NULL) {
@@ -706,12 +725,21 @@ static int wpa_supplicant_ctrl_iface_set_network(
if (wpa_config_set(ssid, name, value, 0) < 0) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
- "variable '%s' to '%s'", name, value);
+ "variable '%s'", name);
return -1;
}
- if ((strcmp(name, "psk") == 0 && value[0] == '"' && ssid->ssid_len) ||
- (strcmp(name, "ssid") == 0 && ssid->passphrase))
+ if (wpa_s->current_ssid == ssid) {
+ /*
+ * Invalidate the EAP session cache if anything in the current
+ * configuration changes.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
+
+ if ((os_strcmp(name, "psk") == 0 &&
+ value[0] == '"' && ssid->ssid_len) ||
+ (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
wpa_config_update_psk(ssid);
return 0;
@@ -726,8 +754,8 @@ static int wpa_supplicant_ctrl_iface_get_network(
char *name, *value;
/* cmd: "<network id> <variable name>" */
- name = strchr(cmd, ' ');
- if (name == NULL)
+ name = os_strchr(cmd, ' ');
+ if (name == NULL || buflen == 0)
return -1;
*name++ = '\0';
@@ -742,18 +770,19 @@ static int wpa_supplicant_ctrl_iface_get_network(
return -1;
}
- value = wpa_config_get(ssid, name);
+ value = wpa_config_get_no_key(ssid, name);
if (value == NULL) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
"variable '%s'", name);
return -1;
}
- snprintf(buf, buflen, "%s", value);
+ os_snprintf(buf, buflen, "%s", value);
+ buf[buflen - 1] = '\0';
- free(value);
+ os_free(value);
- return strlen(buf);
+ return os_strlen(buf);
}
@@ -781,16 +810,28 @@ static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
static int wpa_supplicant_ctrl_iface_get_capability(
- struct wpa_supplicant *wpa_s, const char *field, char *buf,
+ struct wpa_supplicant *wpa_s, const char *_field, char *buf,
size_t buflen)
{
struct wpa_driver_capa capa;
- int res, first = 1;
- char *pos, *end;
+ int res, first = 1, ret;
+ char *pos, *end, *strict;
+ char field[30];
+
+ /* Determine whether or not strict checking was requested */
+ os_snprintf(field, sizeof(field), "%s", _field);
+ field[sizeof(field) - 1] = '\0';
+ strict = os_strchr(field, ' ');
+ if (strict != NULL) {
+ *strict++ = '\0';
+ if (os_strcmp(strict, "strict") != 0)
+ return -1;
+ }
- wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
+ field, strict ? strict : "");
- if (strcmp(field, "eap") == 0) {
+ if (os_strcmp(field, "eap") == 0) {
return eap_get_names(buf, buflen);
}
@@ -799,124 +840,205 @@ static int wpa_supplicant_ctrl_iface_get_capability(
pos = buf;
end = pos + buflen;
- if (strcmp(field, "pairwise") == 0) {
- if (res < 0)
- return snprintf(buf, buflen, "CCMP TKIP NONE");
+ if (os_strcmp(field, "pairwise") == 0) {
+ if (res < 0) {
+ if (strict)
+ return 0;
+ ret = os_snprintf(buf, buflen, "CCMP TKIP NONE");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+ }
if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- pos += snprintf(pos, end - pos, "%sCCMP",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sCCMP",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- pos += snprintf(pos, end - pos, "%sTKIP",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sTKIP",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
- pos += snprintf(pos, end - pos, "%sNONE",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sNONE",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
return pos - buf;
}
- if (strcmp(field, "group") == 0) {
- if (res < 0)
- return snprintf(buf, buflen, "CCMP TKIP WEP104 WEP40");
+ if (os_strcmp(field, "group") == 0) {
+ if (res < 0) {
+ if (strict)
+ return 0;
+ ret = os_snprintf(buf, buflen,
+ "CCMP TKIP WEP104 WEP40");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+ }
if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
- pos += snprintf(pos, end - pos, "%sCCMP",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sCCMP",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
- pos += snprintf(pos, end - pos, "%sTKIP",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sTKIP",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
- pos += snprintf(pos, end - pos, "%sWEP104",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sWEP104",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
- pos += snprintf(pos, end - pos, "%sWEP40",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sWEP40",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
return pos - buf;
}
- if (strcmp(field, "key_mgmt") == 0) {
+ if (os_strcmp(field, "key_mgmt") == 0) {
if (res < 0) {
- return snprintf(buf, buflen, "WPA-PSK WPA-EAP "
- "IEEE8021X WPA-NONE NONE");
+ if (strict)
+ return 0;
+ ret = os_snprintf(buf, buflen, "WPA-PSK WPA-EAP "
+ "IEEE8021X WPA-NONE NONE");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
}
- pos += snprintf(pos, end - pos, "NONE IEEE8021X");
+ ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2))
- pos += snprintf(pos, end - pos, " WPA-EAP");
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+ ret = os_snprintf(pos, end - pos, " WPA-EAP");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
- WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK))
- pos += snprintf(pos, end - pos, " WPA-PSK");
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ ret = os_snprintf(pos, end - pos, " WPA-PSK");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
- if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE)
- pos += snprintf(pos, end - pos, " WPA-NONE");
+ if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+ ret = os_snprintf(pos, end - pos, " WPA-NONE");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
+ }
return pos - buf;
}
- if (strcmp(field, "proto") == 0) {
- if (res < 0)
- return snprintf(buf, buflen, "RSN WPA");
+ if (os_strcmp(field, "proto") == 0) {
+ if (res < 0) {
+ if (strict)
+ return 0;
+ ret = os_snprintf(buf, buflen, "RSN WPA");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+ }
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
- pos += snprintf(pos, end - pos, "%sRSN",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sRSN",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
- pos += snprintf(pos, end - pos, "%sWPA",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sWPA",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
return pos - buf;
}
- if (strcmp(field, "auth_alg") == 0) {
- if (res < 0)
- return snprintf(buf, buflen, "OPEN SHARED LEAP");
+ if (os_strcmp(field, "auth_alg") == 0) {
+ if (res < 0) {
+ if (strict)
+ return 0;
+ ret = os_snprintf(buf, buflen, "OPEN SHARED LEAP");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return -1;
+ return ret;
+ }
if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
- pos += snprintf(pos, end - pos, "%sOPEN",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sOPEN",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
- pos += snprintf(pos, end - pos, "%sSHARED",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sSHARED",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
- pos += snprintf(pos, end - pos, "%sLEAP",
- first ? "" : " ");
+ ret = os_snprintf(pos, end - pos, "%sLEAP",
+ first ? "" : " ");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
first = 0;
}
@@ -930,49 +1052,51 @@ static int wpa_supplicant_ctrl_iface_get_capability(
}
-static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
- void *sock_ctx)
+static int wpa_supplicant_ctrl_iface_ap_scan(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int ap_scan = atoi(cmd);
+
+ if (ap_scan < 0 || ap_scan > 2)
+ return -1;
+ wpa_s->conf->ap_scan = ap_scan;
+ return 0;
+}
+
+
+char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
+ char *buf, size_t *resp_len)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- char buf[256];
- int res;
- CTRL_IFACE_SOCK from;
- socklen_t fromlen = sizeof(from);
char *reply;
const int reply_size = 2048;
+ int ctrl_rsp = 0;
int reply_len;
- int new_attached = 0, ctrl_rsp = 0;
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
- (struct sockaddr *) &from, &fromlen);
- if (res < 0) {
- perror("recvfrom(ctrl_iface)");
- return;
- }
- buf[res] = '\0';
- if (strncmp(buf, WPA_CTRL_RSP, strlen(WPA_CTRL_RSP)) == 0) {
+ if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
+ os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
- (u8 *) buf, res);
+ (const u8 *) buf, os_strlen(buf));
} else {
- wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface", (u8 *) buf, res);
+ wpa_hexdump_ascii(MSG_DEBUG, "RX ctrl_iface",
+ (const u8 *) buf, os_strlen(buf));
}
- reply = malloc(reply_size);
+ reply = os_malloc(reply_size);
if (reply == NULL) {
- sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
- fromlen);
- return;
+ *resp_len = 1;
+ return NULL;
}
- memcpy(reply, "OK\n", 3);
+ os_memcpy(reply, "OK\n", 3);
reply_len = 3;
- if (strcmp(buf, "PING") == 0) {
- memcpy(reply, "PONG\n", 5);
+ if (os_strcmp(buf, "PING") == 0) {
+ os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
- } else if (strcmp(buf, "MIB") == 0) {
+ } else if (os_strcmp(buf, "MIB") == 0) {
reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
if (reply_len >= 0) {
+ int res;
res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
reply_size - reply_len);
if (res < 0)
@@ -980,452 +1104,105 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
else
reply_len += res;
}
- } else if (strncmp(buf, "STATUS", 6) == 0) {
+ } else if (os_strncmp(buf, "STATUS", 6) == 0) {
reply_len = wpa_supplicant_ctrl_iface_status(
wpa_s, buf + 6, reply, reply_size);
- } else if (strcmp(buf, "PMKSA") == 0) {
+ } else if (os_strcmp(buf, "PMKSA") == 0) {
reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size);
- } else if (strncmp(buf, "SET ", 4) == 0) {
+ } else if (os_strncmp(buf, "SET ", 4) == 0) {
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
reply_len = -1;
- } else if (strcmp(buf, "LOGON") == 0) {
+ } else if (os_strcmp(buf, "LOGON") == 0) {
eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
- } else if (strcmp(buf, "LOGOFF") == 0) {
+ } else if (os_strcmp(buf, "LOGOFF") == 0) {
eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
- } else if (strcmp(buf, "REASSOCIATE") == 0) {
+ } else if (os_strcmp(buf, "REASSOCIATE") == 0) {
wpa_s->disconnected = 0;
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else if (strncmp(buf, "PREAUTH ", 8) == 0) {
+ } else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
reply_len = -1;
- } else if (strcmp(buf, "ATTACH") == 0) {
- if (wpa_supplicant_ctrl_iface_attach(wpa_s, &from, fromlen))
- reply_len = -1;
- else
- new_attached = 1;
- } else if (strcmp(buf, "DETACH") == 0) {
- if (wpa_supplicant_ctrl_iface_detach(wpa_s, &from, fromlen))
- reply_len = -1;
- } else if (strncmp(buf, "LEVEL ", 6) == 0) {
- if (wpa_supplicant_ctrl_iface_level(wpa_s, &from, fromlen,
- buf + 6))
+#ifdef CONFIG_PEERKEY
+ } else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
+ if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
reply_len = -1;
- } else if (strncmp(buf, WPA_CTRL_RSP, strlen(WPA_CTRL_RSP)) == 0) {
+#endif /* CONFIG_PEERKEY */
+ } else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
+ {
if (wpa_supplicant_ctrl_iface_ctrl_rsp(
- wpa_s, buf + strlen(WPA_CTRL_RSP)))
+ wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
reply_len = -1;
else
ctrl_rsp = 1;
- } else if (strcmp(buf, "RECONFIGURE") == 0) {
+ } else if (os_strcmp(buf, "RECONFIGURE") == 0) {
if (wpa_supplicant_reload_configuration(wpa_s))
reply_len = -1;
- } else if (strcmp(buf, "TERMINATE") == 0) {
+ } else if (os_strcmp(buf, "TERMINATE") == 0) {
eloop_terminate();
- } else if (strncmp(buf, "BSSID ", 6) == 0) {
+ } else if (os_strncmp(buf, "BSSID ", 6) == 0) {
if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
reply_len = -1;
- } else if (strcmp(buf, "LIST_NETWORKS") == 0) {
+ } else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_list_networks(
wpa_s, reply, reply_size);
- } else if (strcmp(buf, "DISCONNECT") == 0) {
+ } else if (os_strcmp(buf, "DISCONNECT") == 0) {
wpa_s->disconnected = 1;
wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
- } else if (strcmp(buf, "SCAN") == 0) {
+ } else if (os_strcmp(buf, "SCAN") == 0) {
wpa_s->scan_req = 2;
wpa_supplicant_req_scan(wpa_s, 0, 0);
- } else if (strcmp(buf, "SCAN_RESULTS") == 0) {
+ } else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
reply_len = wpa_supplicant_ctrl_iface_scan_results(
wpa_s, reply, reply_size);
- } else if (strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
+ } else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
reply_len = -1;
- } else if (strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
+ } else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
reply_len = -1;
- } else if (strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
+ } else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
reply_len = -1;
- } else if (strcmp(buf, "ADD_NETWORK") == 0) {
+ } else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
reply_len = wpa_supplicant_ctrl_iface_add_network(
wpa_s, reply, reply_size);
- } else if (strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
+ } else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
reply_len = -1;
- } else if (strncmp(buf, "SET_NETWORK ", 12) == 0) {
+ } else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
reply_len = -1;
- } else if (strncmp(buf, "GET_NETWORK ", 12) == 0) {
+ } else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
reply_len = wpa_supplicant_ctrl_iface_get_network(
wpa_s, buf + 12, reply, reply_size);
- } else if (strcmp(buf, "SAVE_CONFIG") == 0) {
+ } else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
reply_len = -1;
- } else if (strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
+ } else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
reply_len = wpa_supplicant_ctrl_iface_get_capability(
wpa_s, buf + 15, reply, reply_size);
+ } else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
+ if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
+ reply_len = -1;
+ } else if (os_strcmp(buf, "INTERFACES") == 0) {
+ reply_len = wpa_supplicant_global_iface_interfaces(
+ wpa_s->global, reply, reply_size);
} else {
- memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
}
if (reply_len < 0) {
- memcpy(reply, "FAIL\n", 5);
+ os_memcpy(reply, "FAIL\n", 5);
reply_len = 5;
}
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
- free(reply);
- if (new_attached)
- eapol_sm_notify_ctrl_attached(wpa_s->eapol);
if (ctrl_rsp)
eapol_sm_notify_ctrl_response(wpa_s->eapol);
-}
-
-
-#ifndef CONFIG_CTRL_IFACE_UDP
-static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
-{
- char *buf;
- size_t len;
-
- if (wpa_s->conf->ctrl_interface == NULL)
- return NULL;
-
- len = strlen(wpa_s->conf->ctrl_interface) + strlen(wpa_s->ifname) + 2;
- buf = malloc(len);
- if (buf == NULL)
- return NULL;
-
- snprintf(buf, len, "%s/%s",
- wpa_s->conf->ctrl_interface, wpa_s->ifname);
-#ifdef __CYGWIN__
- {
- /* Windows/WinPcap uses interface names that are not suitable
- * as a file name - convert invalid chars to underscores */
- char *pos = buf;
- while (*pos) {
- if (*pos == '\\')
- *pos = '_';
- pos++;
- }
- }
-#endif /* __CYGWIN__ */
- return buf;
-}
-#endif /* CONFIG_CTRL_IFACE_UDP */
-
-
-/**
- * wpa_supplicant_ctrl_iface_init - Initialize control interface
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: 0 on success, -1 on failure
- *
- * Initialize the control interface and start receiving commands from external
- * programs.
- */
-int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
-{
- CTRL_IFACE_SOCK addr;
- int s = -1;
-#ifndef CONFIG_CTRL_IFACE_UDP
- char *fname = NULL;
-#endif /* CONFIG_CTRL_IFACE_UDP */
-
- wpa_s->ctrl_sock = -1;
-
- if (wpa_s->conf->ctrl_interface == NULL)
- return 0;
-
-#ifdef CONFIG_CTRL_IFACE_UDP
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket(PF_INET)");
- goto fail;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(AF_INET)");
- goto fail;
- }
-#else /* CONFIG_CTRL_IFACE_UDP */
- if (mkdir(wpa_s->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
- if (errno == EEXIST) {
- wpa_printf(MSG_DEBUG, "Using existing control "
- "interface directory.");
- } else {
- perror("mkdir[ctrl_interface]");
- goto fail;
- }
- }
-
- if (wpa_s->conf->ctrl_interface_gid_set &&
- chown(wpa_s->conf->ctrl_interface, 0,
- wpa_s->conf->ctrl_interface_gid) < 0) {
- perror("chown[ctrl_interface]");
- return -1;
- }
-
- if (strlen(wpa_s->conf->ctrl_interface) + 1 + strlen(wpa_s->ifname) >=
- sizeof(addr.sun_path))
- goto fail;
-
- s = socket(PF_UNIX, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket(PF_UNIX)");
- goto fail;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- fname = wpa_supplicant_ctrl_iface_path(wpa_s);
- if (fname == NULL)
- goto fail;
- strncpy(addr.sun_path, fname, sizeof(addr.sun_path));
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
- if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
- " allow connections - assuming it was left"
- "over from forced program termination");
- if (unlink(fname) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- fname);
- goto fail;
- }
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
- 0) {
- perror("bind(PF_UNIX)");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
- "ctrl_iface socket '%s'", fname);
- } else {
- wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
- "be in use - cannot override it");
- wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
- "not used anymore", fname);
- free(fname);
- fname = NULL;
- goto fail;
- }
- }
-
- if (wpa_s->conf->ctrl_interface_gid_set &&
- chown(fname, 0, wpa_s->conf->ctrl_interface_gid) < 0) {
- perror("chown[ctrl_interface/ifname]");
- goto fail;
- }
-
- if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
- perror("chmod[ctrl_interface/ifname]");
- goto fail;
- }
- free(fname);
-#endif /* CONFIG_CTRL_IFACE_UDP */
-
- wpa_s->ctrl_sock = s;
- eloop_register_read_sock(s, wpa_supplicant_ctrl_iface_receive, wpa_s,
- NULL);
- return 0;
-
-fail:
- if (s >= 0)
- close(s);
-#ifndef CONFIG_CTRL_IFACE_UDP
- if (fname) {
- unlink(fname);
- free(fname);
- }
-#endif /* CONFIG_CTRL_IFACE_UDP */
- return -1;
-}
-
-
-/**
- * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface
- * @wpa_s: Pointer to wpa_supplicant data
- *
- * Deinitialize the control interface that was initialized with
- * wpa_supplicant_ctrl_iface_init().
- */
-void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s)
-{
- struct wpa_ctrl_dst *dst, *prev;
-
- if (wpa_s->ctrl_sock > -1) {
-#ifndef CONFIG_CTRL_IFACE_UDP
- char *fname;
-#endif /* CONFIG_CTRL_IFACE_UDP */
- eloop_unregister_read_sock(wpa_s->ctrl_sock);
- if (wpa_s->ctrl_dst) {
- /*
- * Wait a second before closing the control socket if
- * there are any attached monitors in order to allow
- * them to receive any pending messages.
- */
- wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
- "monitors to receive messages");
- sleep(1);
- }
- close(wpa_s->ctrl_sock);
- wpa_s->ctrl_sock = -1;
-#ifndef CONFIG_CTRL_IFACE_UDP
- fname = wpa_supplicant_ctrl_iface_path(wpa_s);
- if (fname)
- unlink(fname);
- free(fname);
-
- if (rmdir(wpa_s->conf->ctrl_interface) < 0) {
- if (errno == ENOTEMPTY) {
- wpa_printf(MSG_DEBUG, "Control interface "
- "directory not empty - leaving it "
- "behind");
- } else {
- perror("rmdir[ctrl_interface]");
- }
- }
-#endif /* CONFIG_CTRL_IFACE_UDP */
- }
-
- dst = wpa_s->ctrl_dst;
- while (dst) {
- prev = dst;
- dst = dst->next;
- free(prev);
- }
-}
-
-
-/**
- * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
- * @wpa_s: Pointer to wpa_supplicant data
- * @level: Priority level of the message
- * @buf: Message data
- * @len: Message length
- *
- * Send a packet to all monitor programs attached to the control interface.
- */
-void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
- char *buf, size_t len)
-{
- struct wpa_ctrl_dst *dst, *next;
- char levelstr[10];
- int idx;
-#ifdef CONFIG_CTRL_IFACE_UDP
- char *sbuf;
- int llen;
-
- dst = wpa_s->ctrl_dst;
- if (wpa_s->ctrl_sock < 0 || dst == NULL)
- return;
-
- snprintf(levelstr, sizeof(levelstr), "<%d>", level);
-
- llen = strlen(levelstr);
- sbuf = malloc(llen + len);
- if (sbuf == NULL)
- return;
-
- memcpy(sbuf, levelstr, llen);
- memcpy(sbuf + llen, buf, len);
-
- idx = 0;
- while (dst) {
- next = dst->next;
- if (level >= dst->debug_level) {
- wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
- inet_ntoa(dst->addr.sin_addr),
- ntohs(dst->addr.sin_port));
- if (sendto(wpa_s->ctrl_sock, sbuf, llen + len, 0,
- (struct sockaddr *) &dst->addr,
- sizeof(dst->addr)) < 0) {
- perror("sendto(CTRL_IFACE monitor)");
- dst->errors++;
- if (dst->errors > 10) {
- wpa_supplicant_ctrl_iface_detach(
- wpa_s, &dst->addr,
- dst->addrlen);
- }
- } else
- dst->errors = 0;
- }
- idx++;
- dst = next;
- }
- free(sbuf);
-#else /* CONFIG_CTRL_IFACE_UDP */
- struct msghdr msg;
- struct iovec io[2];
-
- dst = wpa_s->ctrl_dst;
- if (wpa_s->ctrl_sock < 0 || dst == NULL)
- return;
-
- snprintf(levelstr, sizeof(levelstr), "<%d>", level);
- io[0].iov_base = levelstr;
- io[0].iov_len = strlen(levelstr);
- io[1].iov_base = buf;
- io[1].iov_len = len;
- memset(&msg, 0, sizeof(msg));
- msg.msg_iov = io;
- msg.msg_iovlen = 2;
-
- idx = 0;
- while (dst) {
- next = dst->next;
- if (level >= dst->debug_level) {
- wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
- (u8 *) dst->addr.sun_path, dst->addrlen);
- msg.msg_name = &dst->addr;
- msg.msg_namelen = dst->addrlen;
- if (sendmsg(wpa_s->ctrl_sock, &msg, 0) < 0) {
- perror("sendmsg(CTRL_IFACE monitor)");
- dst->errors++;
- if (dst->errors > 10) {
- wpa_supplicant_ctrl_iface_detach(
- wpa_s, &dst->addr,
- dst->addrlen);
- }
- } else
- dst->errors = 0;
- }
- idx++;
- dst = next;
- }
-#endif /* CONFIG_CTRL_IFACE_UDP */
-}
-
-
-/**
- * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor
- * @wpa_s: Pointer to wpa_supplicant data
- *
- * Wait until the first message from an external program using the control
- * interface is received. This function can be used to delay normal startup
- * processing to allow control interface programs to attach with
- * %wpa_supplicant before normal operations are started.
- */
-void wpa_supplicant_ctrl_iface_wait(struct wpa_supplicant *wpa_s)
-{
- fd_set rfds;
-
- if (wpa_s->ctrl_sock < 0)
- return;
-
- wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
- wpa_s->ifname);
-
- FD_ZERO(&rfds);
- FD_SET(wpa_s->ctrl_sock, &rfds);
- select(wpa_s->ctrl_sock + 1, &rfds, NULL, NULL, NULL);
+ *resp_len = reply_len;
+ return reply;
}
@@ -1437,14 +1214,15 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
/*
* <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
+ * TAB<bridge_ifname>
*/
wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
- memset(&iface, 0, sizeof(iface));
+ os_memset(&iface, 0, sizeof(iface));
do {
iface.ifname = pos = cmd;
- pos = strchr(pos, '\t');
+ pos = os_strchr(pos, '\t');
if (pos)
*pos++ = '\0';
if (iface.ifname[0] == '\0')
@@ -1453,7 +1231,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
break;
iface.confname = pos;
- pos = strchr(pos, '\t');
+ pos = os_strchr(pos, '\t');
if (pos)
*pos++ = '\0';
if (iface.confname[0] == '\0')
@@ -1462,7 +1240,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
break;
iface.driver = pos;
- pos = strchr(pos, '\t');
+ pos = os_strchr(pos, '\t');
if (pos)
*pos++ = '\0';
if (iface.driver[0] == '\0')
@@ -1471,7 +1249,7 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
break;
iface.ctrl_interface = pos;
- pos = strchr(pos, '\t');
+ pos = os_strchr(pos, '\t');
if (pos)
*pos++ = '\0';
if (iface.ctrl_interface[0] == '\0')
@@ -1480,13 +1258,22 @@ static int wpa_supplicant_global_iface_add(struct wpa_global *global,
break;
iface.driver_param = pos;
- pos = strchr(pos, '\t');
+ pos = os_strchr(pos, '\t');
if (pos)
*pos++ = '\0';
if (iface.driver_param[0] == '\0')
iface.driver_param = NULL;
if (pos == NULL)
break;
+
+ iface.bridge_ifname = pos;
+ pos = os_strchr(pos, '\t');
+ if (pos)
+ *pos++ = '\0';
+ if (iface.bridge_ifname[0] == '\0')
+ iface.bridge_ifname = NULL;
+ if (pos == NULL)
+ break;
} while (0);
if (wpa_supplicant_get_iface(global, iface.ifname))
@@ -1510,179 +1297,73 @@ static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
}
-static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
- void *sock_ctx)
+static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+ char *buf, int len)
{
- struct wpa_global *global = eloop_ctx;
- char buf[256];
int res;
- CTRL_IFACE_SOCK from;
- socklen_t fromlen = sizeof(from);
+ char *pos, *end;
+ struct wpa_supplicant *wpa_s;
+
+ wpa_s = global->ifaces;
+ pos = buf;
+ end = buf + len;
+
+ while (wpa_s) {
+ res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
+ if (res < 0 || res >= end - pos) {
+ *pos = '\0';
+ break;
+ }
+ pos += res;
+ wpa_s = wpa_s->next;
+ }
+ return pos - buf;
+}
+
+
+char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
+ char *buf, size_t *resp_len)
+{
char *reply;
const int reply_size = 2048;
int reply_len;
- res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
- (struct sockaddr *) &from, &fromlen);
- if (res < 0) {
- perror("recvfrom(ctrl_iface)");
- return;
- }
- buf[res] = '\0';
- wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface", (u8 *) buf, res);
+ wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
+ (const u8 *) buf, os_strlen(buf));
- reply = malloc(reply_size);
+ reply = os_malloc(reply_size);
if (reply == NULL) {
- sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
- fromlen);
- return;
+ *resp_len = 1;
+ return NULL;
}
- memcpy(reply, "OK\n", 3);
+ os_memcpy(reply, "OK\n", 3);
reply_len = 3;
- if (strcmp(buf, "PING") == 0) {
- memcpy(reply, "PONG\n", 5);
+ if (os_strcmp(buf, "PING") == 0) {
+ os_memcpy(reply, "PONG\n", 5);
reply_len = 5;
- } else if (strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
+ } else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
if (wpa_supplicant_global_iface_add(global, buf + 14))
reply_len = -1;
- } else if (strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
+ } else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
if (wpa_supplicant_global_iface_remove(global, buf + 17))
reply_len = -1;
+ } else if (os_strcmp(buf, "INTERFACES") == 0) {
+ reply_len = wpa_supplicant_global_iface_interfaces(
+ global, reply, reply_size);
+ } else if (os_strcmp(buf, "TERMINATE") == 0) {
+ eloop_terminate();
} else {
- memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
}
if (reply_len < 0) {
- memcpy(reply, "FAIL\n", 5);
+ os_memcpy(reply, "FAIL\n", 5);
reply_len = 5;
}
- sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
- free(reply);
-}
-
-
-/**
- * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface
- * @global: Pointer to global data from wpa_supplicant_init()
- * Returns: 0 on success, -1 on failure
- *
- * Initialize the global control interface and start receiving commands from
- * external programs.
- */
-int wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
-{
- CTRL_IFACE_SOCK addr;
- int s = -1;
-#ifndef CONFIG_CTRL_IFACE_UDP
- char *fname = NULL;
-#endif /* CONFIG_CTRL_IFACE_UDP */
-
- global->ctrl_sock = -1;
-
- if (global->params.ctrl_interface == NULL)
- return 0;
-
- wpa_printf(MSG_DEBUG, "Global control interface '%s'",
- global->params.ctrl_interface);
-
-#ifdef CONFIG_CTRL_IFACE_UDP
- s = socket(PF_INET, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket(PF_INET)");
- goto fail;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(AF_INET)");
- goto fail;
- }
-#else /* CONFIG_CTRL_IFACE_UDP */
- s = socket(PF_UNIX, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket(PF_UNIX)");
- goto fail;
- }
-
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, global->params.ctrl_interface,
- sizeof(addr.sun_path));
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
- if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
- " allow connections - assuming it was left"
- "over from forced program termination");
- if (unlink(global->params.ctrl_interface) < 0) {
- perror("unlink[ctrl_iface]");
- wpa_printf(MSG_ERROR, "Could not unlink "
- "existing ctrl_iface socket '%s'",
- global->params.ctrl_interface);
- goto fail;
- }
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
- 0) {
- perror("bind(PF_UNIX)");
- goto fail;
- }
- wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
- "ctrl_iface socket '%s'",
- global->params.ctrl_interface);
- } else {
- wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
- "be in use - cannot override it");
- wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
- "not used anymore",
- global->params.ctrl_interface);
- goto fail;
- }
- }
-#endif /* CONFIG_CTRL_IFACE_UDP */
-
- global->ctrl_sock = s;
- eloop_register_read_sock(s, wpa_supplicant_global_ctrl_iface_receive,
- global, NULL);
-
- return 0;
-
-fail:
- if (s >= 0)
- close(s);
-#ifndef CONFIG_CTRL_IFACE_UDP
- if (fname) {
- unlink(fname);
- free(fname);
- }
-#endif /* CONFIG_CTRL_IFACE_UDP */
- return -1;
-}
-
-
-/**
- * wpa_supplicant_global_ctrl_iface_deinit - Deinitialize global ctrl interface
- * @global: Pointer to global data from wpa_supplicant_init()
- *
- * Deinitialize the global control interface that was initialized with
- * wpa_supplicant_global_ctrl_iface_init().
- */
-void wpa_supplicant_global_ctrl_iface_deinit(struct wpa_global *global)
-{
- if (global->ctrl_sock < 0)
- return;
-
- eloop_unregister_read_sock(global->ctrl_sock);
- close(global->ctrl_sock);
- global->ctrl_sock = -1;
-#ifndef CONFIG_CTRL_IFACE_UDP
- if (global->params.ctrl_interface)
- unlink(global->params.ctrl_interface);
-#endif /* CONFIG_CTRL_IFACE_UDP */
+ *resp_len = reply_len;
+ return reply;
}
diff --git a/contrib/wpa_supplicant/ctrl_iface.h b/contrib/wpa_supplicant/ctrl_iface.h
index affa6040a7e8..051d99a67dc6 100644
--- a/contrib/wpa_supplicant/ctrl_iface.h
+++ b/contrib/wpa_supplicant/ctrl_iface.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / UNIX domain socket -based control interface
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,45 +17,140 @@
#ifdef CONFIG_CTRL_IFACE
-int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
- char *buf, size_t len);
-void wpa_supplicant_ctrl_iface_wait(struct wpa_supplicant *wpa_s);
-int wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global);
-void wpa_supplicant_global_ctrl_iface_deinit(struct wpa_global *global);
+/* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */
+
+/**
+ * wpa_supplicant_ctrl_iface_process - Process ctrl_iface command
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @buf: Received command buffer (nul terminated string)
+ * @resp_len: Variable to be set to the response length
+ * Returns: Response (*resp_len bytes) or %NULL on failure
+ *
+ * Control interface backends call this function when receiving a message that
+ * they do not process internally, i.e., anything else than ATTACH, DETACH,
+ * and LEVEL. The return response value is then sent to the external program
+ * that sent the command. Caller is responsible for freeing the buffer after
+ * this. If %NULL is returned, *resp_len can be set to two special values:
+ * 1 = send "FAIL\n" response, 2 = send "OK\n" response. If *resp_len has any
+ * other value, no response is sent.
+ */
+char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
+ char *buf, size_t *resp_len);
+
+/**
+ * wpa_supplicant_ctrl_iface_process - Process global ctrl_iface command
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @buf: Received command buffer (nul terminated string)
+ * @resp_len: Variable to be set to the response length
+ * Returns: Response (*resp_len bytes) or %NULL on failure
+ *
+ * Control interface backends call this function when receiving a message from
+ * the global ctrl_iface connection. The return response value is then sent to
+ * the external program that sent the command. Caller is responsible for
+ * freeing the buffer after this. If %NULL is returned, *resp_len can be set to
+ * two special values: 1 = send "FAIL\n" response, 2 = send "OK\n" response. If
+ * *resp_len has any other value, no response is sent.
+ */
+char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
+ char *buf, size_t *resp_len);
+
+
+/* Functions that each ctrl_iface backend must implement */
+
+/**
+ * wpa_supplicant_ctrl_iface_init - Initialize control interface
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: Pointer to private data on success, %NULL on failure
+ *
+ * Initialize the control interface and start receiving commands from external
+ * programs.
+ *
+ * Required to be implemented in each control interface backend.
+ */
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s);
+
+/**
+ * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ *
+ * Deinitialize the control interface that was initialized with
+ * wpa_supplicant_ctrl_iface_init().
+ *
+ * Required to be implemented in each control interface backend.
+ */
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv);
+
+/**
+ * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ *
+ * Wait until the first message from an external program using the control
+ * interface is received. This function can be used to delay normal startup
+ * processing to allow control interface programs to attach with
+ * %wpa_supplicant before normal operations are started.
+ *
+ * Required to be implemented in each control interface backend.
+ */
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv);
+
+/**
+ * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: Pointer to private data on success, %NULL on failure
+ *
+ * Initialize the global control interface and start receiving commands from
+ * external programs.
+ *
+ * Required to be implemented in each control interface backend.
+ */
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global);
+
+/**
+ * wpa_supplicant_global_ctrl_iface_deinit - Deinitialize global ctrl interface
+ * @priv: Pointer to private data from wpa_supplicant_global_ctrl_iface_init()
+ *
+ * Deinitialize the global control interface that was initialized with
+ * wpa_supplicant_global_ctrl_iface_init().
+ *
+ * Required to be implemented in each control interface backend.
+ */
+void wpa_supplicant_global_ctrl_iface_deinit(
+ struct ctrl_iface_global_priv *priv);
#else /* CONFIG_CTRL_IFACE */
-static inline int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+static inline struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
{
- return 0;
+ return (void *) -1;
}
static inline void
-wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s)
+wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
{
}
static inline void
-wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
+wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int level,
char *buf, size_t len)
{
}
static inline void
-wpa_supplicant_ctrl_iface_wait(struct wpa_supplicant *wpa_s)
+wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
{
}
-static inline int
+static inline struct ctrl_iface_global_priv *
wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
{
- return 0;
+ return (void *) 1;
}
static inline void
-wpa_supplicant_global_ctrl_iface_deinit(struct wpa_global *global)
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
{
}
diff --git a/contrib/wpa_supplicant/ctrl_iface_dbus.c b/contrib/wpa_supplicant/ctrl_iface_dbus.c
new file mode 100644
index 000000000000..1d66c9633d5c
--- /dev/null
+++ b/contrib/wpa_supplicant/ctrl_iface_dbus.c
@@ -0,0 +1,1043 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#include "includes.h"
+
+#include <dbus/dbus.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "wpa.h"
+#include "wpa_supplicant.h"
+#include "config.h"
+#include "eapol_sm.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface_dbus.h"
+#include "ctrl_iface_dbus_handlers.h"
+#include "l2_packet.h"
+#include "preauth.h"
+#include "wpa_ctrl.h"
+#include "eap.h"
+
+struct ctrl_iface_dbus_priv {
+ DBusConnection *con;
+ int should_dispatch;
+ struct wpa_global *global;
+
+ u32 next_objid;
+};
+
+
+static void process_watch(struct ctrl_iface_dbus_priv *iface,
+ DBusWatch *watch, eloop_event_type type)
+{
+ dbus_connection_ref(iface->con);
+
+ iface->should_dispatch = 0;
+
+ if (type == EVENT_TYPE_READ)
+ dbus_watch_handle(watch, DBUS_WATCH_READABLE);
+ else if (type == EVENT_TYPE_WRITE)
+ dbus_watch_handle(watch, DBUS_WATCH_WRITABLE);
+ else if (type == EVENT_TYPE_EXCEPTION)
+ dbus_watch_handle(watch, DBUS_WATCH_ERROR);
+
+ if (iface->should_dispatch) {
+ while (dbus_connection_get_dispatch_status(iface->con) ==
+ DBUS_DISPATCH_DATA_REMAINS)
+ dbus_connection_dispatch(iface->con);
+ iface->should_dispatch = 0;
+ }
+
+ dbus_connection_unref(iface->con);
+}
+
+
+static void process_watch_exception(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_EXCEPTION);
+}
+
+
+static void process_watch_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_READ);
+}
+
+
+static void process_watch_write(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ process_watch(eloop_ctx, sock_ctx, EVENT_TYPE_WRITE);
+}
+
+
+static void connection_setup_add_watch(struct ctrl_iface_dbus_priv *iface,
+ DBusWatch *watch)
+{
+ unsigned int flags;
+ int fd;
+
+ if (!dbus_watch_get_enabled(watch))
+ return;
+
+ flags = dbus_watch_get_flags(watch);
+ fd = dbus_watch_get_fd(watch);
+
+ eloop_register_sock(fd, EVENT_TYPE_EXCEPTION, process_watch_exception,
+ iface, watch);
+
+ if (flags & DBUS_WATCH_READABLE) {
+ eloop_register_sock(fd, EVENT_TYPE_READ, process_watch_read,
+ iface, watch);
+ }
+ if (flags & DBUS_WATCH_WRITABLE) {
+ eloop_register_sock(fd, EVENT_TYPE_WRITE, process_watch_write,
+ iface, watch);
+ }
+
+ dbus_watch_set_data(watch, iface, NULL);
+}
+
+
+static void connection_setup_remove_watch(struct ctrl_iface_dbus_priv *iface,
+ DBusWatch *watch)
+{
+ unsigned int flags;
+ int fd;
+
+ flags = dbus_watch_get_flags(watch);
+ fd = dbus_watch_get_fd(watch);
+
+ eloop_unregister_sock(fd, EVENT_TYPE_EXCEPTION);
+
+ if (flags & DBUS_WATCH_READABLE)
+ eloop_unregister_sock(fd, EVENT_TYPE_READ);
+ if (flags & DBUS_WATCH_WRITABLE)
+ eloop_unregister_sock(fd, EVENT_TYPE_WRITE);
+
+ dbus_watch_set_data(watch, NULL, NULL);
+}
+
+
+static dbus_bool_t add_watch(DBusWatch *watch, void *data)
+{
+ connection_setup_add_watch(data, watch);
+ return TRUE;
+}
+
+
+static void remove_watch(DBusWatch *watch, void *data)
+{
+ connection_setup_remove_watch(data, watch);
+}
+
+
+static void watch_toggled(DBusWatch *watch, void *data)
+{
+ if (dbus_watch_get_enabled(watch))
+ add_watch(watch, data);
+ else
+ remove_watch(watch, data);
+}
+
+
+static void process_timeout(void *eloop_ctx, void *sock_ctx)
+{
+ DBusTimeout *timeout = sock_ctx;
+
+ dbus_timeout_handle(timeout);
+}
+
+
+static void connection_setup_add_timeout(struct ctrl_iface_dbus_priv *iface,
+ DBusTimeout *timeout)
+{
+ if (!dbus_timeout_get_enabled(timeout))
+ return;
+
+ eloop_register_timeout(0, dbus_timeout_get_interval(timeout) * 1000,
+ process_timeout, iface, timeout);
+
+ dbus_timeout_set_data(timeout, iface, NULL);
+}
+
+
+static void connection_setup_remove_timeout(struct ctrl_iface_dbus_priv *iface,
+ DBusTimeout *timeout)
+{
+ eloop_cancel_timeout(process_timeout, iface, timeout);
+ dbus_timeout_set_data(timeout, NULL, NULL);
+}
+
+
+static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
+{
+ if (!dbus_timeout_get_enabled(timeout))
+ return TRUE;
+
+ connection_setup_add_timeout(data, timeout);
+
+ return TRUE;
+}
+
+
+static void remove_timeout(DBusTimeout *timeout, void *data)
+{
+ connection_setup_remove_timeout(data, timeout);
+}
+
+
+static void timeout_toggled(DBusTimeout *timeout, void *data)
+{
+ if (dbus_timeout_get_enabled(timeout))
+ add_timeout(timeout, data);
+ else
+ remove_timeout(timeout, data);
+}
+
+
+static void process_wakeup_main(int sig, void *eloop_ctx, void *signal_ctx)
+{
+ struct ctrl_iface_dbus_priv *iface = signal_ctx;
+
+ if (sig != SIGPOLL || !iface->con)
+ return;
+
+ if (dbus_connection_get_dispatch_status(iface->con) !=
+ DBUS_DISPATCH_DATA_REMAINS)
+ return;
+
+ /* Only dispatch once - we do not want to starve other events */
+ dbus_connection_ref(iface->con);
+ dbus_connection_dispatch(iface->con);
+ dbus_connection_unref(iface->con);
+}
+
+
+/**
+ * wakeup_main - Attempt to wake our mainloop up
+ * @data: dbus control interface private data
+ *
+ * Try to wake up the main eloop so it will process
+ * dbus events that may have happened.
+ */
+static void wakeup_main(void *data)
+{
+ struct ctrl_iface_dbus_priv *iface = data;
+
+ /* Use SIGPOLL to break out of the eloop select() */
+ raise(SIGPOLL);
+ iface->should_dispatch = 1;
+}
+
+
+/**
+ * connection_setup_wakeup_main - Tell dbus about our wakeup_main function
+ * @iface: dbus control interface private data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register our wakeup_main handler with dbus
+ */
+static int connection_setup_wakeup_main(struct ctrl_iface_dbus_priv *iface)
+{
+ if (eloop_register_signal(SIGPOLL, process_wakeup_main, iface))
+ return -1;
+
+ dbus_connection_set_wakeup_main_function(iface->con, wakeup_main,
+ iface, NULL);
+
+ return 0;
+}
+
+
+/**
+ * wpa_supplicant_dbus_next_objid - Return next available object id
+ * @iface: dbus control interface private data
+ * Returns: Object id
+ */
+u32 wpa_supplicant_dbus_next_objid (struct ctrl_iface_dbus_priv *iface)
+{
+ return iface->next_objid++;
+}
+
+
+/**
+ * wpas_dbus_decompose_object_path - Decompose an interface object path into parts
+ * @path: The dbus object path
+ * @network: (out) the configured network this object path refers to, if any
+ * @bssid: (out) the scanned bssid this object path refers to, if any
+ * Returns: The object path of the network interface this path refers to
+ *
+ * For a given object path, decomposes the object path into object id, network,
+ * and BSSID parts, if those parts exist.
+ */
+char * wpas_dbus_decompose_object_path(const char *path, char **network,
+ char **bssid)
+{
+ const unsigned int dev_path_prefix_len =
+ strlen(WPAS_DBUS_PATH_INTERFACES "/");
+ char *obj_path_only;
+ char *next_sep;
+
+ /* Be a bit paranoid about path */
+ if (!path || strncmp(path, WPAS_DBUS_PATH_INTERFACES "/",
+ dev_path_prefix_len))
+ return NULL;
+
+ /* Ensure there's something at the end of the path */
+ if ((path + dev_path_prefix_len)[0] == '\0')
+ return NULL;
+
+ obj_path_only = strdup(path);
+ if (obj_path_only == NULL)
+ return NULL;
+
+ next_sep = strchr(obj_path_only + dev_path_prefix_len, '/');
+ if (next_sep != NULL) {
+ const char *net_part = strstr(next_sep,
+ WPAS_DBUS_NETWORKS_PART "/");
+ const char *bssid_part = strstr(next_sep,
+ WPAS_DBUS_BSSIDS_PART "/");
+
+ if (network && net_part) {
+ /* Deal with a request for a configured network */
+ const char *net_name = net_part +
+ strlen(WPAS_DBUS_NETWORKS_PART "/");
+ *network = NULL;
+ if (strlen(net_name))
+ *network = strdup(net_name);
+ } else if (bssid && bssid_part) {
+ /* Deal with a request for a scanned BSSID */
+ const char *bssid_name = bssid_part +
+ strlen(WPAS_DBUS_BSSIDS_PART "/");
+ if (strlen(bssid_name))
+ *bssid = strdup(bssid_name);
+ else
+ *bssid = NULL;
+ }
+
+ /* Cut off interface object path before "/" */
+ *next_sep = '\0';
+ }
+
+ return obj_path_only;
+}
+
+
+/**
+ * wpas_dbus_new_invalid_iface_error - Return a new invalid interface error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: A dbus error message
+ *
+ * Convenience function to create and return an invalid interface error
+ */
+DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
+{
+ return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
+ "wpa_supplicant knows nothing about "
+ "this interface.");
+}
+
+
+/**
+ * wpas_dbus_new_invalid_network_error - Return a new invalid network error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid network error
+ */
+DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message)
+{
+ return dbus_message_new_error(message, WPAS_ERROR_INVALID_NETWORK,
+ "The requested network does not exist.");
+}
+
+
+/**
+ * wpas_dbus_new_invalid_bssid_error - Return a new invalid bssid error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid bssid error
+ */
+static DBusMessage * wpas_dbus_new_invalid_bssid_error(DBusMessage *message)
+{
+ return dbus_message_new_error(message, WPAS_ERROR_INVALID_BSSID,
+ "The BSSID requested was invalid.");
+}
+
+
+/**
+ * wpas_dispatch_network_method - dispatch messages for configured networks
+ * @message: the incoming dbus message
+ * @wpa_s: a network interface's data
+ * @network_id: id of the configured network we're interested in
+ * Returns: a reply dbus message, or a dbus error message
+ *
+ * This function dispatches all incoming dbus messages for configured networks.
+ */
+static DBusMessage * wpas_dispatch_network_method(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ int network_id)
+{
+ DBusMessage *reply = NULL;
+ const char *method = dbus_message_get_member(message);
+ struct wpa_ssid *ssid;
+
+ ssid = wpa_config_get_network(wpa_s->conf, network_id);
+ if (ssid == NULL)
+ return wpas_dbus_new_invalid_network_error(message);
+
+ if (!strcmp(method, "set"))
+ reply = wpas_dbus_iface_set_network(message, wpa_s, ssid);
+ else if (!strcmp(method, "enable"))
+ reply = wpas_dbus_iface_enable_network(message, wpa_s, ssid);
+ else if (!strcmp(method, "disable"))
+ reply = wpas_dbus_iface_disable_network(message, wpa_s, ssid);
+
+ return reply;
+}
+
+
+/**
+ * wpas_dispatch_bssid_method - dispatch messages for scanned networks
+ * @message: the incoming dbus message
+ * @wpa_s: a network interface's data
+ * @bssid: bssid of the scanned network we're interested in
+ * Returns: a reply dbus message, or a dbus error message
+ *
+ * This function dispatches all incoming dbus messages for scanned networks.
+ */
+static DBusMessage * wpas_dispatch_bssid_method(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ const char *bssid)
+{
+ DBusMessage *reply = NULL;
+ const char *method = dbus_message_get_member(message);
+ struct wpa_scan_result * res = NULL;
+ int i;
+
+ /* Ensure we actually have scan data */
+ if (wpa_s->scan_results == NULL &&
+ wpa_supplicant_get_scan_results(wpa_s) < 0) {
+ reply = wpas_dbus_new_invalid_bssid_error(message);
+ goto out;
+ }
+
+ /* Find the bssid's scan data */
+ for (i = 0; i < wpa_s->num_scan_results; i++) {
+ struct wpa_scan_result * search_res = &wpa_s->scan_results[i];
+ char mac_str[18];
+
+ memset(mac_str, 0, sizeof(mac_str));
+ snprintf(mac_str, sizeof(mac_str) - 1, WPAS_DBUS_BSSID_FORMAT,
+ MAC2STR(search_res->bssid));
+ if (!strcmp(bssid, mac_str)) {
+ res = search_res;
+ }
+ }
+
+ if (!res) {
+ reply = wpas_dbus_new_invalid_bssid_error(message);
+ goto out;
+ }
+
+ /* Dispatch the method call against the scanned bssid */
+ if (!strcmp(method, "properties"))
+ reply = wpas_dbus_bssid_properties(message, wpa_s, res);
+
+out:
+ return reply;
+}
+
+
+/**
+ * wpas_iface_message_handler - Dispatch messages for interfaces or networks
+ * @connection: Connection to the system message bus
+ * @message: An incoming dbus message
+ * @user_data: A pointer to a dbus control interface data structure
+ * Returns: Whether or not the message was handled
+ *
+ * This function dispatches all incoming dbus messages for network interfaces,
+ * or objects owned by them, such as scanned BSSIDs and configured networks.
+ */
+static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
+ DBusMessage *message,
+ void *user_data)
+{
+ struct wpa_supplicant *wpa_s = user_data;
+ const char *method = dbus_message_get_member(message);
+ const char *path = dbus_message_get_path(message);
+ const char *msg_interface = dbus_message_get_interface(message);
+ char *iface_obj_path = NULL;
+ char *network = NULL;
+ char *bssid = NULL;
+ DBusMessage *reply = NULL;
+
+ /* Caller must specify a message interface */
+ if (!msg_interface)
+ goto out;
+
+ iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
+ &bssid);
+ if (iface_obj_path == NULL) {
+ reply = wpas_dbus_new_invalid_iface_error(message);
+ goto out;
+ }
+
+ /* Make sure the message's object path actually refers to the
+ * wpa_supplicant structure it's supposed to (which is wpa_s)
+ */
+ if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
+ iface_obj_path) != wpa_s) {
+ reply = wpas_dbus_new_invalid_iface_error(message);
+ goto out;
+ }
+
+ if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
+ /* A method for one of this interface's configured networks */
+ int nid = strtoul(network, NULL, 10);
+ if (errno != EINVAL)
+ reply = wpas_dispatch_network_method(message, wpa_s,
+ nid);
+ else
+ reply = wpas_dbus_new_invalid_network_error(message);
+ } else if (bssid && !strcmp(msg_interface, WPAS_DBUS_IFACE_BSSID)) {
+ /* A method for one of this interface's scanned BSSIDs */
+ reply = wpas_dispatch_bssid_method(message, wpa_s, bssid);
+ } else if (!strcmp(msg_interface, WPAS_DBUS_IFACE_INTERFACE)) {
+ /* A method for an interface only. */
+ if (!strcmp(method, "scan"))
+ reply = wpas_dbus_iface_scan(message, wpa_s);
+ else if (!strcmp(method, "scanResults"))
+ reply = wpas_dbus_iface_scan_results(message, wpa_s);
+ else if (!strcmp(method, "addNetwork"))
+ reply = wpas_dbus_iface_add_network(message, wpa_s);
+ else if (!strcmp(method, "removeNetwork"))
+ reply = wpas_dbus_iface_remove_network(message, wpa_s);
+ else if (!strcmp(method, "selectNetwork"))
+ reply = wpas_dbus_iface_select_network(message, wpa_s);
+ else if (!strcmp(method, "capabilities"))
+ reply = wpas_dbus_iface_capabilities(message, wpa_s);
+ else if (!strcmp(method, "disconnect"))
+ reply = wpas_dbus_iface_disconnect(message, wpa_s);
+ else if (!strcmp(method, "setAPScan"))
+ reply = wpas_dbus_iface_set_ap_scan(message, wpa_s);
+ else if (!strcmp(method, "state"))
+ reply = wpas_dbus_iface_get_state(message, wpa_s);
+ }
+
+ /* If the message was handled, send back the reply */
+ if (reply) {
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ }
+
+out:
+ free(iface_obj_path);
+ free(network);
+ free(bssid);
+ return reply ? DBUS_HANDLER_RESULT_HANDLED :
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+/**
+ * wpas_message_handler - dispatch incoming dbus messages
+ * @connection: connection to the system message bus
+ * @message: an incoming dbus message
+ * @user_data: a pointer to a dbus control interface data structure
+ * Returns: whether or not the message was handled
+ *
+ * This function dispatches all incoming dbus messages to the correct
+ * handlers, depending on what the message's target object path is,
+ * and what the method call is.
+ */
+static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
+ DBusMessage *message, void *user_data)
+{
+ struct ctrl_iface_dbus_priv *ctrl_iface = user_data;
+ const char *method;
+ const char *path;
+ const char *msg_interface;
+ DBusMessage *reply = NULL;
+
+ method = dbus_message_get_member(message);
+ path = dbus_message_get_path(message);
+ msg_interface = dbus_message_get_interface(message);
+ if (!method || !path || !ctrl_iface || !msg_interface)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ /* Validate the method interface */
+ if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+ if (!strcmp(path, WPAS_DBUS_PATH)) {
+ /* dispatch methods against our global dbus interface here */
+ if (!strcmp(method, "addInterface")) {
+ reply = wpas_dbus_global_add_interface(
+ message, ctrl_iface->global);
+ } else if (!strcmp(method, "removeInterface")) {
+ reply = wpas_dbus_global_remove_interface(
+ message, ctrl_iface->global);
+ } else if (!strcmp(method, "getInterface")) {
+ reply = wpas_dbus_global_get_interface(
+ message, ctrl_iface->global);
+ }
+ }
+
+ /* If the message was handled, send back the reply */
+ if (reply) {
+ dbus_connection_send(connection, reply, NULL);
+ dbus_message_unref(reply);
+ }
+
+ return reply ? DBUS_HANDLER_RESULT_HANDLED :
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+
+/**
+ * wpa_supplicant_dbus_notify_scan_results - Send a scan results signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Notify listeners that this interface has updated scan results.
+ */
+void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface;
+ DBusMessage *signal;
+ const char *path;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ path = wpa_supplicant_get_dbus_path(wpa_s);
+ if (path == NULL) {
+ perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
+ "interface didn't have a dbus path");
+ wpa_printf(MSG_ERROR,
+ "wpa_supplicant_dbus_notify_scan_results[dbus]: "
+ "interface didn't have a dbus path; can't send "
+ "scan result signal.");
+ return;
+ }
+ signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
+ "ScanResultsAvailable");
+ if (signal == NULL) {
+ perror("wpa_supplicant_dbus_notify_scan_results[dbus]: "
+ "couldn't create dbus signal; likely out of memory");
+ wpa_printf(MSG_ERROR, "dbus control interface: not enough "
+ "memory to send scan results signal.");
+ return;
+ }
+ dbus_connection_send(iface->con, signal, NULL);
+}
+
+
+/**
+ * wpa_supplicant_dbus_notify_state_change - Send a state change signal
+ * @wpa_s: %wpa_supplicant network interface data
+ * @new_state: new state wpa_supplicant is entering
+ * @old_state: old state wpa_supplicant is leaving
+ * Returns: 0 on success, -1 on failure
+ *
+ * Notify listeners that wpa_supplicant has changed state
+ */
+void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
+ wpa_states new_state,
+ wpa_states old_state)
+{
+ struct ctrl_iface_dbus_priv *iface;
+ DBusMessage *signal;
+ const char *path;
+ const char *new_state_str, *old_state_str;
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s->global == NULL)
+ return;
+ iface = wpa_s->global->dbus_ctrl_iface;
+ if (iface == NULL)
+ return;
+
+ /* Only send signal if state really changed */
+ if (new_state == old_state)
+ return;
+
+ path = wpa_supplicant_get_dbus_path(wpa_s);
+ if (path == NULL) {
+ perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
+ "interface didn't have a dbus path");
+ wpa_printf(MSG_ERROR,
+ "wpa_supplicant_dbus_notify_state_change[dbus]: "
+ "interface didn't have a dbus path; can't send "
+ "signal.");
+ return;
+ }
+ signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
+ "StateChange");
+ if (signal == NULL) {
+ perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
+ "couldn't create dbus signal; likely out of memory");
+ wpa_printf(MSG_ERROR,
+ "wpa_supplicant_dbus_notify_state_change[dbus]: "
+ "couldn't create dbus signal; likely out of "
+ "memory.");
+ return;
+ }
+
+ new_state_str = wpa_supplicant_state_txt(new_state);
+ old_state_str = wpa_supplicant_state_txt(old_state);
+ if (new_state_str == NULL || old_state_str == NULL) {
+ perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
+ "couldn't convert state strings");
+ wpa_printf(MSG_ERROR,
+ "wpa_supplicant_dbus_notify_state_change[dbus]: "
+ "couldn't convert state strings.");
+ return;
+ }
+
+ if (!dbus_message_append_args(signal,
+ DBUS_TYPE_STRING, &new_state_str,
+ DBUS_TYPE_STRING, &old_state_str,
+ DBUS_TYPE_INVALID)) {
+ perror("wpa_supplicant_dbus_notify_state_change[dbus]: "
+ "not enough memory to construct state change signal.");
+ wpa_printf(MSG_ERROR,
+ "wpa_supplicant_dbus_notify_state_change[dbus]: "
+ "not enough memory to construct state change "
+ "signal.");
+ }
+ dbus_connection_send(iface->con, signal, NULL);
+}
+
+
+/**
+ * integrate_with_eloop - Register our mainloop integration with dbus
+ * @connection: connection to the system message bus
+ * @iface: a dbus control interface data structure
+ * Returns: 0 on success, -1 on failure
+ *
+ * We register our mainloop integration functions with dbus here.
+ */
+static int integrate_with_eloop(DBusConnection *connection,
+ struct ctrl_iface_dbus_priv *iface)
+{
+ if (!dbus_connection_set_watch_functions(connection, add_watch,
+ remove_watch, watch_toggled,
+ iface, NULL)) {
+ perror("dbus_connection_set_watch_functions[dbus]");
+ wpa_printf(MSG_ERROR, "Not enough memory to set up dbus.");
+ return -1;
+ }
+
+ if (!dbus_connection_set_timeout_functions(connection, add_timeout,
+ remove_timeout,
+ timeout_toggled, iface,
+ NULL)) {
+ perror("dbus_connection_set_timeout_functions[dbus]");
+ wpa_printf(MSG_ERROR, "Not enough memory to set up dbus.");
+ return -1;
+ }
+
+ if (connection_setup_wakeup_main(iface) < 0) {
+ perror("connection_setup_wakeup_main[dbus]");
+ wpa_printf(MSG_ERROR, "Could not setup main wakeup function.");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * dispatch_initial_dbus_messages - Dispatch initial dbus messages after
+ * claiming bus name
+ * @eloop_ctx: the DBusConnection to dispatch on
+ * @timeout_ctx: unused
+ *
+ * If clients are quick to notice that wpa_supplicant claimed its bus name,
+ * there may have been messages that came in before initialization was
+ * all finished. Dispatch those here.
+ */
+static void dispatch_initial_dbus_messages(void *eloop_ctx, void *timeout_ctx)
+{
+ DBusConnection *con = eloop_ctx;
+
+ while (dbus_connection_get_dispatch_status(con) ==
+ DBUS_DISPATCH_DATA_REMAINS)
+ dbus_connection_dispatch(con);
+}
+
+
+/**
+ * wpa_supplicant_dbus_ctrl_iface_init - Initialize dbus control interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: Pointer to dbus_ctrl_iface date or %NULL on failure
+ *
+ * Initialize the dbus control interface and start receiving commands from
+ * external programs over the bus.
+ */
+struct ctrl_iface_dbus_priv *
+wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global)
+{
+ struct ctrl_iface_dbus_priv *iface;
+ DBusError error;
+ int ret = -1;
+ DBusObjectPathVTable wpas_vtable = {
+ NULL, &wpas_message_handler, NULL, NULL, NULL, NULL
+ };
+
+ iface = wpa_zalloc(sizeof(struct ctrl_iface_dbus_priv));
+ if (iface == NULL)
+ return NULL;
+
+ iface->global = global;
+
+ /* Get a reference to the system bus */
+ dbus_error_init(&error);
+ iface->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
+ dbus_error_free(&error);
+ if (!iface->con) {
+ perror("dbus_bus_get[ctrl_iface_dbus]");
+ wpa_printf(MSG_ERROR, "Could not acquire the system bus.");
+ goto fail;
+ }
+
+ /* Tell dbus about our mainloop integration functions */
+ if (integrate_with_eloop(iface->con, iface))
+ goto fail;
+
+ /* Register the message handler for the global dbus interface */
+ if (!dbus_connection_register_object_path(iface->con,
+ WPAS_DBUS_PATH, &wpas_vtable,
+ iface)) {
+ perror("dbus_connection_register_object_path[dbus]");
+ wpa_printf(MSG_ERROR, "Could not set up DBus message "
+ "handler.");
+ goto fail;
+ }
+
+ /* Register our service with the message bus */
+ dbus_error_init(&error);
+ switch (dbus_bus_request_name(iface->con, WPAS_DBUS_SERVICE,
+ 0, &error)) {
+ case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
+ ret = 0;
+ break;
+ case DBUS_REQUEST_NAME_REPLY_EXISTS:
+ case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
+ case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
+ perror("dbus_bus_request_name[dbus]");
+ wpa_printf(MSG_ERROR, "Could not request DBus service name: "
+ "already registered.");
+ break;
+ default:
+ perror("dbus_bus_request_name[dbus]");
+ wpa_printf(MSG_ERROR, "Could not request DBus service name: "
+ "%s %s.", error.name, error.message);
+ break;
+ }
+ dbus_error_free(&error);
+
+ if (ret != 0)
+ goto fail;
+
+ wpa_printf(MSG_DEBUG, "Providing DBus service '" WPAS_DBUS_SERVICE
+ "'.");
+
+ /*
+ * Dispatch initial DBus messages that may have come in since the bus
+ * name was claimed above. Happens when clients are quick to notice the
+ * wpa_supplicant service.
+ *
+ * FIXME: is there a better solution to this problem?
+ */
+ eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
+ iface->con, NULL);
+
+ return iface;
+
+fail:
+ wpa_supplicant_dbus_ctrl_iface_deinit(iface);
+ return NULL;
+}
+
+
+/**
+ * wpa_supplicant_dbus_ctrl_iface_deinit - Deinitialize dbus ctrl interface
+ * @iface: Pointer to dbus private data from
+ * wpa_supplicant_dbus_ctrl_iface_init()
+ *
+ * Deinitialize the dbus control interface that was initialized with
+ * wpa_supplicant_dbus_ctrl_iface_init().
+ */
+void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface)
+{
+ if (iface == NULL)
+ return;
+
+ if (iface->con) {
+ eloop_cancel_timeout(dispatch_initial_dbus_messages,
+ iface->con, NULL);
+ dbus_connection_set_watch_functions(iface->con, NULL, NULL,
+ NULL, NULL, NULL);
+ dbus_connection_set_timeout_functions(iface->con, NULL, NULL,
+ NULL, NULL, NULL);
+ dbus_connection_unref(iface->con);
+ }
+
+ memset(iface, 0, sizeof(struct ctrl_iface_dbus_priv));
+ free(iface);
+}
+
+
+/**
+ * wpas_dbus_register_new_iface - Register a new interface with dbus
+ * @global: Global %wpa_supplicant data
+ * @wpa_s: %wpa_supplicant interface description structure to register
+ * Returns: 0 on success, -1 on error
+ *
+ * Registers a new interface with dbus and assigns it a dbus object path.
+ */
+int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_dbus_priv *ctrl_iface =
+ wpa_s->global->dbus_ctrl_iface;
+ DBusConnection * con;
+ u32 next;
+ DBusObjectPathVTable vtable = {
+ NULL, &wpas_iface_message_handler, NULL, NULL, NULL, NULL
+ };
+ char *path;
+ int ret = -1;
+
+ /* Do nothing if the control interface is not turned on */
+ if (ctrl_iface == NULL)
+ return 0;
+
+ con = ctrl_iface->con;
+ next = wpa_supplicant_dbus_next_objid(ctrl_iface);
+
+ /* Create and set the interface's object path */
+ path = wpa_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+ if (path == NULL)
+ return -1;
+ snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+ WPAS_DBUS_PATH_INTERFACES "/%u",
+ next);
+ if (wpa_supplicant_set_dbus_path(wpa_s, path)) {
+ wpa_printf(MSG_DEBUG,
+ "Failed to set dbus path for interface %s",
+ wpa_s->ifname);
+ goto out;
+ }
+
+ /* Register the message handler for the interface functions */
+ if (!dbus_connection_register_fallback(con, path, &vtable, wpa_s)) {
+ perror("wpas_dbus_register_iface [dbus]");
+ wpa_printf(MSG_ERROR, "Could not set up DBus message "
+ "handler for interface %s.", wpa_s->ifname);
+ goto out;
+ }
+ ret = 0;
+
+out:
+ free(path);
+ return ret;
+}
+
+
+/**
+ * wpas_dbus_unregister_iface - Unregister an interface from dbus
+ * @wpa_s: wpa_supplicant interface structure
+ * Returns: 0 on success, -1 on failure
+ *
+ * Unregisters the interface with dbus
+ */
+int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_dbus_priv *ctrl_iface;
+ DBusConnection *con;
+ const char *path;
+
+ /* Do nothing if the control interface is not turned on */
+ if (wpa_s == NULL || wpa_s->global == NULL)
+ return 0;
+ ctrl_iface = wpa_s->global->dbus_ctrl_iface;
+ if (ctrl_iface == NULL)
+ return 0;
+
+ con = ctrl_iface->con;
+ path = wpa_supplicant_get_dbus_path(wpa_s);
+
+ if (!dbus_connection_unregister_object_path(con, path))
+ return -1;
+
+ free(wpa_s->dbus_path);
+ wpa_s->dbus_path = NULL;
+
+ return 0;
+}
+
+
+/**
+ * wpa_supplicant_get_iface_by_dbus_path - Get a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @path: Pointer to a dbus object path representing an interface
+ * Returns: Pointer to the interface or %NULL if not found
+ */
+struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
+ struct wpa_global *global, const char *path)
+{
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (strcmp(wpa_s->dbus_path, path) == 0)
+ return wpa_s;
+ }
+ return NULL;
+}
+
+
+/**
+ * wpa_supplicant_set_dbus_path - Assign a dbus path to an interface
+ * @wpa_s: wpa_supplicant interface structure
+ * @path: dbus path to set on the interface
+ * Returns: 0 on succes, -1 on error
+ */
+int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s,
+ const char *path)
+{
+ u32 len = strlen (path);
+ if (len >= WPAS_DBUS_OBJECT_PATH_MAX)
+ return -1;
+ if (wpa_s->dbus_path)
+ return -1;
+ wpa_s->dbus_path = strdup(path);
+ return 0;
+}
+
+
+/**
+ * wpa_supplicant_get_dbus_path - Get an interface's dbus path
+ * @wpa_s: %wpa_supplicant interface structure
+ * Returns: Interface's dbus object path, or %NULL on error
+ */
+const char * wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s)
+{
+ return wpa_s->dbus_path;
+}
diff --git a/contrib/wpa_supplicant/ctrl_iface_dbus.h b/contrib/wpa_supplicant/ctrl_iface_dbus.h
new file mode 100644
index 000000000000..b66c179c596e
--- /dev/null
+++ b/contrib/wpa_supplicant/ctrl_iface_dbus.h
@@ -0,0 +1,146 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef CTRL_IFACE_DBUS_H
+#define CTRL_IFACE_DBUS_H
+
+#ifdef CONFIG_CTRL_IFACE_DBUS
+
+#ifndef SIGPOLL
+#ifdef SIGIO
+/*
+ * If we do not have SIGPOLL, try to use SIGIO instead. This is needed for
+ * FreeBSD.
+ */
+#define SIGPOLL SIGIO
+#endif
+#endif
+
+#include <dbus/dbus.h>
+
+#define WPAS_DBUS_OBJECT_PATH_MAX 150
+
+#define WPAS_DBUS_SERVICE "fi.epitest.hostap.WPASupplicant"
+#define WPAS_DBUS_PATH "/fi/epitest/hostap/WPASupplicant"
+#define WPAS_DBUS_INTERFACE "fi.epitest.hostap.WPASupplicant"
+
+#define WPAS_DBUS_PATH_INTERFACES WPAS_DBUS_PATH "/Interfaces"
+#define WPAS_DBUS_IFACE_INTERFACE WPAS_DBUS_INTERFACE ".Interface"
+
+#define WPAS_DBUS_NETWORKS_PART "Networks"
+#define WPAS_DBUS_IFACE_NETWORK WPAS_DBUS_INTERFACE ".Network"
+
+#define WPAS_DBUS_BSSIDS_PART "BSSIDs"
+#define WPAS_DBUS_IFACE_BSSID WPAS_DBUS_INTERFACE ".BSSID"
+
+
+/* Errors */
+#define WPAS_ERROR_INVALID_NETWORK \
+ WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork"
+#define WPAS_ERROR_INVALID_BSSID \
+ WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID"
+
+#define WPAS_ERROR_INVALID_OPTS \
+ WPAS_DBUS_INTERFACE ".InvalidOptions"
+#define WPAS_ERROR_INVALID_IFACE \
+ WPAS_DBUS_INTERFACE ".InvalidInterface"
+
+#define WPAS_ERROR_ADD_ERROR \
+ WPAS_DBUS_INTERFACE ".AddError"
+#define WPAS_ERROR_EXISTS_ERROR \
+ WPAS_DBUS_INTERFACE ".ExistsError"
+#define WPAS_ERROR_REMOVE_ERROR \
+ WPAS_DBUS_INTERFACE ".RemoveError"
+
+#define WPAS_ERROR_SCAN_ERROR \
+ WPAS_DBUS_IFACE_INTERFACE ".ScanError"
+#define WPAS_ERROR_ADD_NETWORK_ERROR \
+ WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError"
+#define WPAS_ERROR_INTERNAL_ERROR \
+ WPAS_DBUS_IFACE_INTERFACE ".InternalError"
+#define WPAS_ERROR_REMOVE_NETWORK_ERROR \
+ WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError"
+
+#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+struct ctrl_iface_dbus_priv *
+wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global);
+void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface);
+void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
+ wpa_states new_state,
+ wpa_states old_state);
+
+char * wpas_dbus_decompose_object_path(const char *path, char **network,
+ char **bssid);
+
+int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
+int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
+
+
+/* Methods internal to the dbus control interface */
+u32 wpa_supplicant_dbus_next_objid(struct ctrl_iface_dbus_priv *iface);
+
+int wpa_supplicant_set_dbus_path(struct wpa_supplicant *wpa_s,
+ const char *path);
+const char *wpa_supplicant_get_dbus_path(struct wpa_supplicant *wpa_s);
+struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
+ struct wpa_global *global, const char *path);
+
+DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message);
+DBusMessage * wpas_dbus_new_invalid_network_error(DBusMessage *message);
+
+#else /* CONFIG_CTRL_IFACE_DBUS */
+
+static inline struct ctrl_iface_dbus_priv *
+wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global)
+{
+ return (struct ctrl_iface_dbus_priv *) 1;
+}
+
+static inline void
+wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_dbus_priv *iface)
+{
+}
+
+static inline void
+wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void
+wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
+ wpa_states new_state,
+ wpa_states old_state)
+{
+}
+
+static inline int
+wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline int
+wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+#endif /* CONFIG_CTRL_IFACE_DBUS */
+
+#endif /* CTRL_IFACE_DBUS_H */
diff --git a/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.c b/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.c
new file mode 100644
index 000000000000..5e952ec5ffa9
--- /dev/null
+++ b/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.c
@@ -0,0 +1,1205 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#include "includes.h"
+
+#include <dbus/dbus.h>
+
+#include "common.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface_dbus.h"
+#include "ctrl_iface_dbus_handlers.h"
+#include "l2_packet.h"
+#include "eap_methods.h"
+#include "dbus_dict_helpers.h"
+#include "wpa.h"
+
+
+/**
+ * wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
+ * @message: Pointer to incoming dbus message this error refers to
+ * Returns: a dbus error message
+ *
+ * Convenience function to create and return an invalid options error
+ */
+static DBusMessage * wpas_dbus_new_invalid_opts_error(DBusMessage *message,
+ const char *arg)
+{
+ DBusMessage *reply;
+
+ reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
+ "Did not receive correct message "
+ "arguments.");
+ if (arg != NULL)
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
+ DBUS_TYPE_INVALID);
+
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_new_success_reply - Return a new success reply message
+ * @message: Pointer to incoming dbus message this reply refers to
+ * Returns: a dbus message containing a single UINT32 that indicates
+ * success (ie, a value of 1)
+ *
+ * Convenience function to create and return a success reply message
+ */
+static DBusMessage * wpas_dbus_new_success_reply(DBusMessage *message)
+{
+ DBusMessage *reply;
+ unsigned int success = 1;
+
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply, DBUS_TYPE_UINT32, &success,
+ DBUS_TYPE_INVALID);
+ return reply;
+}
+
+
+static void wpas_dbus_free_wpa_interface(struct wpa_interface *iface)
+{
+ free((char *) iface->driver);
+ free((char *) iface->driver_param);
+ free((char *) iface->confname);
+ free((char *) iface->bridge_ifname);
+}
+
+
+/**
+ * wpas_dbus_global_add_interface - Request registration of a network interface
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: The object path of the new interface object,
+ * or a dbus error message with more information
+ *
+ * Handler function for "addInterface" method call. Handles requests
+ * by dbus clients to register a network interface that wpa_supplicant
+ * will manage.
+ */
+DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
+ struct wpa_global *global)
+{
+ struct wpa_interface iface;
+ char *ifname = NULL;
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+
+ memset(&iface, 0, sizeof(iface));
+
+ dbus_message_iter_init(message, &iter);
+
+ /* First argument: interface name (DBUS_TYPE_STRING)
+ * Required; must be non-zero length
+ */
+ if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+ goto error;
+ dbus_message_iter_get_basic(&iter, &ifname);
+ if (!strlen(ifname))
+ goto error;
+ iface.ifname = ifname;
+
+ /* Second argument: dict of options */
+ if (dbus_message_iter_next(&iter)) {
+ DBusMessageIter iter_dict;
+ struct wpa_dbus_dict_entry entry;
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+ goto error;
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+ goto error;
+ if (!strcmp(entry.key, "driver") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ iface.driver = strdup(entry.str_value);
+ if (iface.driver == NULL)
+ goto error;
+ } else if (!strcmp(entry.key, "driver-params") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ iface.driver_param = strdup(entry.str_value);
+ if (iface.driver_param == NULL)
+ goto error;
+ } else if (!strcmp(entry.key, "config-file") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ iface.confname = strdup(entry.str_value);
+ if (iface.confname == NULL)
+ goto error;
+ } else if (!strcmp(entry.key, "bridge-ifname") &&
+ (entry.type == DBUS_TYPE_STRING)) {
+ iface.bridge_ifname = strdup(entry.str_value);
+ if (iface.bridge_ifname == NULL)
+ goto error;
+ } else {
+ wpa_dbus_dict_entry_clear(&entry);
+ goto error;
+ }
+ wpa_dbus_dict_entry_clear(&entry);
+ }
+ }
+
+ /*
+ * Try to get the wpa_supplicant record for this iface, return
+ * an error if we already control it.
+ */
+ if (wpa_supplicant_get_iface(global, iface.ifname) != 0) {
+ reply = dbus_message_new_error(message,
+ WPAS_ERROR_EXISTS_ERROR,
+ "wpa_supplicant already "
+ "controls this interface.");
+ } else {
+ struct wpa_supplicant *wpa_s;
+ /* Otherwise, have wpa_supplicant attach to it. */
+ if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+ const char *path = wpa_supplicant_get_dbus_path(wpa_s);
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
+ &path, DBUS_TYPE_INVALID);
+ } else {
+ reply = dbus_message_new_error(message,
+ WPAS_ERROR_ADD_ERROR,
+ "wpa_supplicant "
+ "couldn't grab this "
+ "interface.");
+ }
+ }
+ wpas_dbus_free_wpa_interface(&iface);
+ return reply;
+
+error:
+ wpas_dbus_free_wpa_interface(&iface);
+ return wpas_dbus_new_invalid_opts_error(message, NULL);
+}
+
+
+/**
+ * wpas_dbus_global_remove_interface - Request deregistration of an interface
+ * @message: Pointer to incoming dbus message
+ * @global: wpa_supplicant global data structure
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ * failure (0), or returns a dbus error message with more information
+ *
+ * Handler function for "removeInterface" method call. Handles requests
+ * by dbus clients to deregister a network interface that wpa_supplicant
+ * currently manages.
+ */
+DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
+ struct wpa_global *global)
+{
+ struct wpa_supplicant *wpa_s;
+ char *path;
+ DBusMessage *reply = NULL;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID)) {
+ reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+ goto out;
+ }
+
+ wpa_s = wpa_supplicant_get_iface_by_dbus_path(global, path);
+ if (wpa_s == NULL) {
+ reply = wpas_dbus_new_invalid_iface_error(message);
+ goto out;
+ }
+
+ if (!wpa_supplicant_remove_iface(global, wpa_s)) {
+ reply = wpas_dbus_new_success_reply(message);
+ } else {
+ reply = dbus_message_new_error(message,
+ WPAS_ERROR_REMOVE_ERROR,
+ "wpa_supplicant couldn't "
+ "remove this interface.");
+ }
+
+out:
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_global_get_interface - Get the object path for an interface name
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: The object path of the interface object,
+ * or a dbus error message with more information
+ *
+ * Handler function for "getInterface" method call. Handles requests
+ * by dbus clients for the object path of an specific network interface.
+ */
+DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
+ struct wpa_global *global)
+{
+ DBusMessage *reply = NULL;
+ const char *ifname;
+ const char *path;
+ struct wpa_supplicant *wpa_s;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_STRING, &ifname,
+ DBUS_TYPE_INVALID)) {
+ reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+ goto out;
+ }
+
+ wpa_s = wpa_supplicant_get_iface(global, ifname);
+ if (wpa_s == NULL) {
+ reply = wpas_dbus_new_invalid_iface_error(message);
+ goto out;
+ }
+
+ path = wpa_supplicant_get_dbus_path(wpa_s);
+ if (path == NULL) {
+ reply = dbus_message_new_error(message,
+ WPAS_ERROR_INTERNAL_ERROR,
+ "an internal error occurred "
+ "getting the interface.");
+ goto out;
+ }
+
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID);
+
+out:
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_scan - Request a wireless scan on an interface
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ * failure (0)
+ *
+ * Handler function for "scan" method call of a network device. Requests
+ * that wpa_supplicant perform a wireless scan as soon as possible
+ * on a particular wireless interface.
+ */
+DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ wpa_s->scan_req = 2;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_scan_results - Get the results of a recent scan request
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: a dbus message containing a dbus array of objects paths, or returns
+ * a dbus error message if not scan results could be found
+ *
+ * Handler function for "scanResults" method call of a network device. Returns
+ * a dbus message containing the object paths of wireless networks found.
+ */
+DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ DBusMessageIter iter;
+ DBusMessageIter sub_iter;
+ int i;
+
+ /* Ensure we've actually got scan results to return */
+ if (wpa_s->scan_results == NULL &&
+ wpa_supplicant_get_scan_results(wpa_s) < 0) {
+ reply = dbus_message_new_error(message, WPAS_ERROR_SCAN_ERROR,
+ "An error ocurred getting scan "
+ "results.");
+ goto out;
+ }
+
+ /* Create and initialize the return message */
+ reply = dbus_message_new_method_return(message);
+ dbus_message_iter_init_append(reply, &iter);
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_OBJECT_PATH_AS_STRING,
+ &sub_iter);
+
+ /* Loop through scan results and append each result's object path */
+ for (i = 0; i < wpa_s->num_scan_results; i++) {
+ struct wpa_scan_result *res = &wpa_s->scan_results[i];
+ char *path;
+
+ path = wpa_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+ if (path == NULL) {
+ perror("wpas_dbus_iface_scan_results[dbus]: out of "
+ "memory.");
+ wpa_printf(MSG_ERROR, "dbus control interface: not "
+ "enough memory to send scan results "
+ "signal.");
+ break;
+ }
+ /* Construct the object path for this network. Note that ':'
+ * is not a valid character in dbus object paths.
+ */
+ snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_BSSIDS_PART "/"
+ WPAS_DBUS_BSSID_FORMAT,
+ wpa_supplicant_get_dbus_path(wpa_s),
+ MAC2STR(res->bssid));
+ dbus_message_iter_append_basic(&sub_iter,
+ DBUS_TYPE_OBJECT_PATH, &path);
+ free(path);
+ }
+
+ dbus_message_iter_close_container(&iter, &sub_iter);
+
+out:
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_bssid_properties - Return the properties of a scanned network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @res: wpa_supplicant scan result for which to get properties
+ * Returns: a dbus message containing the properties for the requested network
+ *
+ * Handler function for "properties" method call of a scanned network.
+ * Returns a dbus message containing the the properties.
+ */
+DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *res)
+{
+ DBusMessage *reply = NULL;
+ char *bssid_data, *ssid_data, *wpa_ie_data, *rsn_ie_data;
+ DBusMessageIter iter, iter_dict;
+
+ /* dbus needs the address of a pointer to the actual value
+ * for array types, not the address of the value itself.
+ */
+ bssid_data = (char *) &res->bssid;
+ ssid_data = (char *) &res->ssid;
+ wpa_ie_data = (char *) &res->wpa_ie;
+ rsn_ie_data = (char *) &res->rsn_ie;
+
+ /* Dump the properties into a dbus message */
+ reply = dbus_message_new_method_return(message);
+
+ dbus_message_iter_init_append(reply, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
+ goto error;
+
+ if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
+ bssid_data, ETH_ALEN))
+ goto error;
+ if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
+ ssid_data, res->ssid_len))
+ goto error;
+ if (res->wpa_ie_len) {
+ if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
+ wpa_ie_data,
+ res->wpa_ie_len)) {
+ goto error;
+ }
+ }
+ if (res->rsn_ie_len) {
+ if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
+ rsn_ie_data,
+ res->rsn_ie_len)) {
+ goto error;
+ }
+ }
+ if (res->freq) {
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
+ res->freq))
+ goto error;
+ }
+ if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
+ res->caps))
+ goto error;
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "quality", res->qual))
+ goto error;
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", res->noise))
+ goto error;
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "level", res->level))
+ goto error;
+ if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate", res->maxrate))
+ goto error;
+
+ if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+ goto error;
+
+ return reply;
+
+error:
+ if (reply)
+ dbus_message_unref(reply);
+ return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
+ "an internal error occurred returning "
+ "BSSID properties.");
+}
+
+
+/**
+ * wpas_dbus_iface_capabilities - Return interface capabilities
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a dict of strings
+ *
+ * Handler function for "capabilities" method call of an interface.
+ */
+DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ struct wpa_driver_capa capa;
+ int res;
+ DBusMessageIter iter, iter_dict;
+ char **eap_methods;
+ size_t num_items;
+ dbus_bool_t strict = FALSE;
+ DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_BOOLEAN, &strict,
+ DBUS_TYPE_INVALID))
+ strict = FALSE;
+
+ reply = dbus_message_new_method_return(message);
+
+ dbus_message_iter_init_append(reply, &iter);
+ if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
+ goto error;
+
+ /* EAP methods */
+ eap_methods = eap_get_names_as_string_array(&num_items);
+ if (eap_methods) {
+ dbus_bool_t success = FALSE;
+ size_t i = 0;
+
+ success = wpa_dbus_dict_append_string_array(
+ &iter_dict, "eap", (const char **) eap_methods,
+ num_items);
+
+ /* free returned method array */
+ while (eap_methods[i])
+ free(eap_methods[i++]);
+ free(eap_methods);
+
+ if (!success)
+ goto error;
+ }
+
+ res = wpa_drv_get_capa(wpa_s, &capa);
+
+ /***** pairwise cipher */
+ if (res < 0) {
+ if (!strict) {
+ const char *args[] = {"CCMP", "TKIP", "NONE"};
+ if (!wpa_dbus_dict_append_string_array(
+ &iter_dict, "pairwise", args,
+ sizeof(args) / sizeof(char*)))
+ goto error;
+ }
+ } else {
+ if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "CCMP"))
+ goto error;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "TKIP"))
+ goto error;
+ }
+
+ if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "NONE"))
+ goto error;
+ }
+
+ if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+ }
+
+ /***** group cipher */
+ if (res < 0) {
+ if (!strict) {
+ const char *args[] = {
+ "CCMP", "TKIP", "WEP104", "WEP40"
+ };
+ if (!wpa_dbus_dict_append_string_array(
+ &iter_dict, "group", args,
+ sizeof(args) / sizeof(char*)))
+ goto error;
+ }
+ } else {
+ if (!wpa_dbus_dict_begin_string_array(&iter_dict, "group",
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "CCMP"))
+ goto error;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "TKIP"))
+ goto error;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WEP104"))
+ goto error;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WEP40"))
+ goto error;
+ }
+
+ if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+ }
+
+ /***** key management */
+ if (res < 0) {
+ if (!strict) {
+ const char *args[] = {
+ "WPA-PSK", "WPA-EAP", "IEEE8021X", "WPA-NONE",
+ "NONE"
+ };
+ if (!wpa_dbus_dict_append_string_array(
+ &iter_dict, "key_mgmt", args,
+ sizeof(args) / sizeof(char*)))
+ goto error;
+ }
+ } else {
+ if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+
+ if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+ "NONE"))
+ goto error;
+
+ if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+ "IEEE8021X"))
+ goto error;
+
+ if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WPA-EAP"))
+ goto error;
+ }
+
+ if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WPA-PSK"))
+ goto error;
+ }
+
+ if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WPA-NONE"))
+ goto error;
+ }
+
+ if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+ }
+
+ /***** WPA protocol */
+ if (res < 0) {
+ if (!strict) {
+ const char *args[] = { "RSN", "WPA" };
+ if (!wpa_dbus_dict_append_string_array(
+ &iter_dict, "proto", args,
+ sizeof(args) / sizeof(char*)))
+ goto error;
+ }
+ } else {
+ if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+
+ if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "RSN"))
+ goto error;
+ }
+
+ if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "WPA"))
+ goto error;
+ }
+
+ if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+ }
+
+ /***** auth alg */
+ if (res < 0) {
+ if (!strict) {
+ const char *args[] = { "OPEN", "SHARED", "LEAP" };
+ if (!wpa_dbus_dict_append_string_array(
+ &iter_dict, "auth_alg", args,
+ sizeof(args) / sizeof(char*)))
+ goto error;
+ }
+ } else {
+ if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+
+ if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "OPEN"))
+ goto error;
+ }
+
+ if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "SHARED"))
+ goto error;
+ }
+
+ if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
+ if (!wpa_dbus_dict_string_array_add_element(
+ &iter_array, "LEAP"))
+ goto error;
+ }
+
+ if (!wpa_dbus_dict_end_string_array(&iter_dict,
+ &iter_dict_entry,
+ &iter_dict_val,
+ &iter_array))
+ goto error;
+ }
+
+ if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+ goto error;
+
+ return reply;
+
+error:
+ if (reply)
+ dbus_message_unref(reply);
+ return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
+ "an internal error occurred returning "
+ "interface capabilities.");
+}
+
+
+/**
+ * wpas_dbus_iface_add_network - Add a new configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing the object path of the new network
+ *
+ * Handler function for "addNetwork" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ struct wpa_ssid *ssid;
+ char *path = NULL;
+
+ path = wpa_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
+ if (path == NULL) {
+ perror("wpas_dbus_iface_scan_results[dbus]: out of "
+ "memory.");
+ wpa_printf(MSG_ERROR, "dbus control interface: not "
+ "enough memory to send scan results "
+ "signal.");
+ goto out;
+ }
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (ssid == NULL) {
+ reply = dbus_message_new_error(message,
+ WPAS_ERROR_ADD_NETWORK_ERROR,
+ "wpa_supplicant could not add "
+ "a network on this interface.");
+ goto out;
+ }
+ ssid->disabled = 1;
+ wpa_config_set_network_defaults(ssid);
+
+ /* Construct the object path for this network. */
+ snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+ "%s/" WPAS_DBUS_NETWORKS_PART "/%d",
+ wpa_supplicant_get_dbus_path(wpa_s),
+ ssid->id);
+
+ reply = dbus_message_new_method_return(message);
+ dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
+ &path, DBUS_TYPE_INVALID);
+
+out:
+ free(path);
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_remove_network - Remove a configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ * failure (0)
+ *
+ * Handler function for "removeNetwork" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ const char *op;
+ char *iface = NULL, *net_id = NULL;
+ int id;
+ struct wpa_ssid *ssid;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_OBJECT_PATH, &op,
+ DBUS_TYPE_INVALID)) {
+ reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+ goto out;
+ }
+
+ /* Extract the network ID */
+ iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
+ if (iface == NULL) {
+ reply = wpas_dbus_new_invalid_network_error(message);
+ goto out;
+ }
+ /* Ensure the network is actually a child of this interface */
+ if (strcmp(iface, wpa_supplicant_get_dbus_path(wpa_s)) != 0) {
+ reply = wpas_dbus_new_invalid_network_error(message);
+ goto out;
+ }
+
+ id = strtoul(net_id, NULL, 10);
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ reply = wpas_dbus_new_invalid_network_error(message);
+ goto out;
+ }
+
+ if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ reply = dbus_message_new_error(message,
+ WPAS_ERROR_REMOVE_NETWORK_ERROR,
+ "error removing the specified "
+ "on this interface.");
+ goto out;
+ }
+
+ if (ssid == wpa_s->current_ssid)
+ wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
+ reply = wpas_dbus_new_success_reply(message);
+
+out:
+ free(iface);
+ free(net_id);
+ return reply;
+}
+
+
+static const char *dont_quote[] = {
+ "key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
+ "opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
+ "bssid", NULL
+};
+
+static dbus_bool_t should_quote_opt(const char *key)
+{
+ int i = 0;
+ while (dont_quote[i] != NULL) {
+ if (strcmp(key, dont_quote[i]) == 0)
+ return FALSE;
+ i++;
+ }
+ return TRUE;
+}
+
+/**
+ * wpas_dbus_iface_set_network - Set options for a configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ * failure (0)
+ *
+ * Handler function for "set" method call of a configured network.
+ */
+DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ DBusMessage *reply = NULL;
+ struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
+ DBusMessageIter iter, iter_dict;
+
+ dbus_message_iter_init(message, &iter);
+
+ if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) {
+ reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+ goto out;
+ }
+
+ while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+ char *value = NULL;
+ size_t size = 50;
+ int ret;
+
+ if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+ reply = wpas_dbus_new_invalid_opts_error(message,
+ NULL);
+ goto out;
+ }
+
+ /* Type conversions, since wpa_supplicant wants strings */
+ if (entry.type == DBUS_TYPE_ARRAY &&
+ entry.array_type == DBUS_TYPE_BYTE) {
+ if (entry.array_len <= 0)
+ goto error;
+
+ size = entry.array_len * 2 + 1;
+ value = wpa_zalloc(size);
+ if (value == NULL)
+ goto error;
+ ret = wpa_snprintf_hex(value, size,
+ (u8 *) entry.bytearray_value,
+ entry.array_len);
+ if (ret <= 0)
+ goto error;
+ } else if (entry.type == DBUS_TYPE_STRING) {
+ if (should_quote_opt(entry.key)) {
+ size = strlen(entry.str_value);
+ /* Zero-length option check */
+ if (size <= 0)
+ goto error;
+ size += 3; /* For quotes and terminator */
+ value = wpa_zalloc(size);
+ if (value == NULL)
+ goto error;
+ ret = snprintf(value, size, "\"%s\"",
+ entry.str_value);
+ if (ret < 0 || (size_t) ret != (size - 1))
+ goto error;
+ } else {
+ value = strdup(entry.str_value);
+ if (value == NULL)
+ goto error;
+ }
+ } else if (entry.type == DBUS_TYPE_UINT32) {
+ value = wpa_zalloc(size);
+ if (value == NULL)
+ goto error;
+ ret = snprintf(value, size, "%u", entry.uint32_value);
+ if (ret <= 0)
+ goto error;
+ } else if (entry.type == DBUS_TYPE_INT32) {
+ value = wpa_zalloc(size);
+ if (value == NULL)
+ goto error;
+ ret = snprintf(value, size, "%d", entry.int32_value);
+ if (ret <= 0)
+ goto error;
+ } else
+ goto error;
+
+ if (wpa_config_set(ssid, entry.key, value, 0) < 0)
+ goto error;
+
+ if ((strcmp(entry.key, "psk") == 0 &&
+ value[0] == '"' && ssid->ssid_len) ||
+ (strcmp(entry.key, "ssid") == 0 && ssid->passphrase))
+ wpa_config_update_psk(ssid);
+
+ free(value);
+ wpa_dbus_dict_entry_clear(&entry);
+ continue;
+
+ error:
+ free(value);
+ reply = wpas_dbus_new_invalid_opts_error(message, entry.key);
+ wpa_dbus_dict_entry_clear(&entry);
+ break;
+ }
+
+ if (!reply)
+ reply = wpas_dbus_new_success_reply(message);
+
+out:
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_enable_network - Mark a configured network as enabled
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ * failure (0)
+ *
+ * Handler function for "enable" method call of a configured network.
+ */
+DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (wpa_s->current_ssid == NULL && ssid->disabled) {
+ /*
+ * Try to reassociate since there is no current configuration
+ * and a new network was made available.
+ */
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+ ssid->disabled = 0;
+
+ return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_disable_network - Mark a configured network as disabled
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ * failure (0)
+ *
+ * Handler function for "disable" method call of a configured network.
+ */
+DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ if (ssid == wpa_s->current_ssid)
+ wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
+ ssid->disabled = 1;
+
+ return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_select_network - Attempt association with a configured network
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ * failure (0)
+ *
+ * Handler function for "selectNetwork" method call of network interface.
+ */
+DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ const char *op;
+ struct wpa_ssid *ssid;
+ char *iface_obj_path = NULL;
+ char *network = NULL;
+
+ if (strlen(dbus_message_get_signature(message)) == 0) {
+ /* Any network */
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ ssid->disabled = 0;
+ ssid = ssid->next;
+ }
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else {
+ const char *obj_path;
+ int nid;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_OBJECT_PATH, &op,
+ DBUS_TYPE_INVALID)) {
+ reply = wpas_dbus_new_invalid_opts_error(message,
+ NULL);
+ goto out;
+ }
+
+ /* Extract the network number */
+ iface_obj_path = wpas_dbus_decompose_object_path(op,
+ &network,
+ NULL);
+ if (iface_obj_path == NULL) {
+ reply = wpas_dbus_new_invalid_iface_error(message);
+ goto out;
+ }
+ /* Ensure the object path really points to this interface */
+ obj_path = wpa_supplicant_get_dbus_path(wpa_s);
+ if (strcmp(iface_obj_path, obj_path) != 0) {
+ reply = wpas_dbus_new_invalid_network_error(message);
+ goto out;
+ }
+
+ nid = strtoul(network, NULL, 10);
+ if (errno == EINVAL) {
+ reply = wpas_dbus_new_invalid_network_error(message);
+ goto out;
+ }
+
+ ssid = wpa_config_get_network(wpa_s->conf, nid);
+ if (ssid == NULL) {
+ reply = wpas_dbus_new_invalid_network_error(message);
+ goto out;
+ }
+
+ /* Finally, associate with the network */
+ if (ssid != wpa_s->current_ssid && wpa_s->current_ssid)
+ wpa_supplicant_disassociate(wpa_s,
+ REASON_DEAUTH_LEAVING);
+
+ /* Mark all other networks disabled and trigger reassociation
+ */
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ ssid->disabled = (nid != ssid->id);
+ ssid = ssid->next;
+ }
+ wpa_s->disconnected = 0;
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+
+ reply = wpas_dbus_new_success_reply(message);
+
+out:
+ free(iface_obj_path);
+ free(network);
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_disconnect - Terminate the current connection
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ * failure (0)
+ *
+ * Handler function for "disconnect" method call of network interface.
+ */
+DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ wpa_s->disconnected = 1;
+ wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
+
+ return wpas_dbus_new_success_reply(message);
+}
+
+
+/**
+ * wpas_dbus_iface_set_ap_scan - Control roaming mode
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a UINT32 indicating success (1) or
+ * failure (0)
+ *
+ * Handler function for "setAPScan" method call.
+ */
+DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ dbus_uint32_t ap_scan = 1;
+
+ if (!dbus_message_get_args(message, NULL, DBUS_TYPE_UINT32, &ap_scan,
+ DBUS_TYPE_INVALID)) {
+ reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+ goto out;
+ }
+
+ if (ap_scan > 2) {
+ reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+ goto out;
+ }
+ wpa_s->conf->ap_scan = ap_scan;
+ reply = wpas_dbus_new_success_reply(message);
+
+out:
+ return reply;
+}
+
+
+/**
+ * wpas_dbus_iface_get_state - Get interface state
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing a STRING representing the current
+ * interface state
+ *
+ * Handler function for "state" method call.
+ */
+DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ const char *str_state;
+
+ reply = dbus_message_new_method_return(message);
+ if (reply != NULL) {
+ str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
+ dbus_message_append_args(reply, DBUS_TYPE_STRING, &str_state,
+ DBUS_TYPE_INVALID);
+ }
+
+ return reply;
+}
diff --git a/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.h b/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.h
new file mode 100644
index 000000000000..0fd1d3164267
--- /dev/null
+++ b/contrib/wpa_supplicant/ctrl_iface_dbus_handlers.h
@@ -0,0 +1,77 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef CTRL_IFACE_DBUS_HANDLERS_H
+#define CTRL_IFACE_DBUS_HANDLERS_H
+
+#ifdef CONFIG_CTRL_IFACE_DBUS
+
+DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message);
+
+DBusMessage * wpas_dbus_global_add_interface(DBusMessage *message,
+ struct wpa_global *global);
+
+DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
+ struct wpa_global *global);
+
+DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
+ struct wpa_global *global);
+
+DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_scan_results(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_bssid_properties(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *res);
+
+DBusMessage * wpas_dbus_iface_capabilities(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_add_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_remove_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_set_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+
+DBusMessage * wpas_dbus_iface_enable_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+
+DBusMessage * wpas_dbus_iface_disable_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+
+DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
+#endif /* CONFIG_CTRL_IFACE_DBUS */
+
+#endif /* CTRL_IFACE_DBUS_HANDLERS_H */
+
diff --git a/contrib/wpa_supplicant/ctrl_iface_named_pipe.c b/contrib/wpa_supplicant/ctrl_iface_named_pipe.c
new file mode 100644
index 000000000000..5813e089a86c
--- /dev/null
+++ b/contrib/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -0,0 +1,834 @@
+/*
+ * WPA Supplicant / Windows Named Pipe -based control interface
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "config.h"
+#include "eapol_sm.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface.h"
+#include "wpa_ctrl.h"
+
+#ifdef __MINGW32_VERSION
+/* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here
+ */
+#define SDDL_REVISION_1 1
+BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA(
+ LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
+BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW(
+ LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
+#ifdef UNICODE
+#define ConvertStringSecurityDescriptorToSecurityDescriptor \
+ConvertStringSecurityDescriptorToSecurityDescriptorW
+#else
+#define ConvertStringSecurityDescriptorToSecurityDescriptor \
+ConvertStringSecurityDescriptorToSecurityDescriptorA
+#endif
+#else /* __MINGW32_VERSION */
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <sddl.h>
+#endif /* __MINGW32_VERSION */
+
+#ifndef WPA_SUPPLICANT_NAMED_PIPE
+#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
+#endif
+#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
+
+/* Per-interface ctrl_iface */
+
+#define REQUEST_BUFSIZE 256
+#define REPLY_BUFSIZE 4096
+
+struct ctrl_iface_priv;
+
+/**
+ * struct wpa_ctrl_dst - Internal data structure of control interface clients
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant. This data is private to
+ * ctrl_iface_named_pipe.c and should not be touched directly from other files.
+ */
+struct wpa_ctrl_dst {
+ /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */
+ OVERLAPPED overlap;
+ struct wpa_ctrl_dst *next, *prev;
+ struct ctrl_iface_priv *priv;
+ HANDLE pipe;
+ int attached;
+ int debug_level;
+ int errors;
+ char req_buf[REQUEST_BUFSIZE];
+ char *rsp_buf;
+ int used;
+};
+
+
+struct ctrl_iface_priv {
+ struct wpa_supplicant *wpa_s;
+ struct wpa_ctrl_dst *ctrl_dst;
+ SECURITY_ATTRIBUTES attr;
+ int sec_attr_set;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+ int level, const char *buf,
+ size_t len);
+
+static void ctrl_close_pipe(struct wpa_ctrl_dst *dst);
+static void wpa_supplicant_ctrl_iface_receive(void *, void *);
+static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap);
+
+struct wpa_global_dst;
+static void global_close_pipe(struct wpa_global_dst *dst);
+static void wpa_supplicant_global_iface_receive(void *eloop_data,
+ void *user_ctx);
+static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap);
+
+
+static int ctrl_broken_pipe(HANDLE pipe, int used)
+{
+ DWORD err;
+
+ if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL))
+ return 0;
+
+ err = GetLastError();
+ if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used))
+ return 1;
+ return 0;
+}
+
+
+static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv)
+{
+ struct wpa_ctrl_dst *dst, *next;
+
+ dst = priv->ctrl_dst;
+
+ while (dst) {
+ next = dst->next;
+ if (ctrl_broken_pipe(dst->pipe, dst->used)) {
+ wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
+ dst);
+ ctrl_close_pipe(dst);
+ }
+ dst = next;
+ }
+}
+
+
+static int ctrl_open_pipe(struct ctrl_iface_priv *priv)
+{
+ struct wpa_ctrl_dst *dst;
+ DWORD err;
+ TCHAR name[256];
+
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
+
+ dst->priv = priv;
+ dst->debug_level = MSG_INFO;
+ dst->pipe = INVALID_HANDLE_VALUE;
+
+ dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (dst->overlap.hEvent == NULL) {
+ wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
+ (int) GetLastError());
+ goto fail;
+ }
+
+ eloop_register_event(dst->overlap.hEvent,
+ sizeof(dst->overlap.hEvent),
+ wpa_supplicant_ctrl_iface_receive, dst, NULL);
+
+#ifdef UNICODE
+ _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
+ priv->wpa_s->ifname);
+#else /* UNICODE */
+ os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
+ priv->wpa_s->ifname);
+#endif /* UNICODE */
+
+ /* TODO: add support for configuring access list for the pipe */
+ dst->pipe = CreateNamedPipe(name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_MESSAGE |
+ PIPE_READMODE_MESSAGE |
+ PIPE_WAIT,
+ 15, REPLY_BUFSIZE, REQUEST_BUFSIZE,
+ 1000,
+ priv->sec_attr_set ? &priv->attr : NULL);
+ if (dst->pipe == INVALID_HANDLE_VALUE) {
+ wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
+ (int) GetLastError());
+ goto fail;
+ }
+
+ if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
+ wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
+ (int) GetLastError());
+ CloseHandle(dst->pipe);
+ os_free(dst);
+ return -1;
+ }
+
+ err = GetLastError();
+ switch (err) {
+ case ERROR_IO_PENDING:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
+ "progress");
+ break;
+ case ERROR_PIPE_CONNECTED:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
+ "connected");
+ if (SetEvent(dst->overlap.hEvent))
+ break;
+ /* fall through */
+ default:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
+ (int) err);
+ CloseHandle(dst->pipe);
+ os_free(dst);
+ return -1;
+ }
+
+ dst->next = priv->ctrl_dst;
+ if (dst->next)
+ dst->next->prev = dst;
+ priv->ctrl_dst = dst;
+
+ return 0;
+
+fail:
+ ctrl_close_pipe(dst);
+ return -1;
+}
+
+
+static void ctrl_close_pipe(struct wpa_ctrl_dst *dst)
+{
+ wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
+
+ if (dst->overlap.hEvent) {
+ eloop_unregister_event(dst->overlap.hEvent,
+ sizeof(dst->overlap.hEvent));
+ CloseHandle(dst->overlap.hEvent);
+ }
+
+ if (dst->pipe != INVALID_HANDLE_VALUE) {
+ /*
+ * Could use FlushFileBuffers() here to guarantee that all data
+ * gets delivered to the client, but that can block, so let's
+ * not do this for now.
+ * FlushFileBuffers(dst->pipe);
+ */
+ CloseHandle(dst->pipe);
+ }
+
+ if (dst->prev)
+ dst->prev->next = dst->next;
+ else
+ dst->priv->ctrl_dst = dst->next;
+ if (dst->next)
+ dst->next->prev = dst->prev;
+
+ os_free(dst->rsp_buf);
+ os_free(dst);
+}
+
+
+static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap)
+{
+ struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
+ "err=%d bytes=%d", dst, (int) err, (int) bytes);
+ if (err) {
+ ctrl_close_pipe(dst);
+ return;
+ }
+
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = NULL;
+
+ if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
+ &dst->overlap, ctrl_iface_read_completed)) {
+ wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
+ (int) GetLastError());
+ ctrl_close_pipe(dst);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
+}
+
+
+static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len)
+{
+ struct wpa_supplicant *wpa_s = dst->priv->wpa_s;
+ char *reply = NULL, *send_buf;
+ size_t reply_len = 0, send_len;
+ int new_attached = 0;
+ char *buf = dst->req_buf;
+
+ dst->used = 1;
+ if (len >= REQUEST_BUFSIZE)
+ len = REQUEST_BUFSIZE - 1;
+ buf[len] = '\0';
+
+ if (os_strcmp(buf, "ATTACH") == 0) {
+ dst->attached = 1;
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached");
+ new_attached = 1;
+ reply_len = 2;
+ } else if (os_strcmp(buf, "DETACH") == 0) {
+ dst->attached = 0;
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached");
+ reply_len = 2;
+ } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6);
+ dst->debug_level = atoi(buf + 6);
+ reply_len = 2;
+ } else {
+ reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+ &reply_len);
+ }
+
+ if (reply) {
+ send_buf = reply;
+ send_len = reply_len;
+ } else if (reply_len == 2) {
+ send_buf = "OK\n";
+ send_len = 3;
+ } else {
+ send_buf = "FAIL\n";
+ send_len = 5;
+ }
+
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = os_malloc(send_len);
+ if (dst->rsp_buf == NULL) {
+ ctrl_close_pipe(dst);
+ os_free(reply);
+ return;
+ }
+ os_memcpy(dst->rsp_buf, send_buf, send_len);
+ os_free(reply);
+
+ if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
+ ctrl_iface_write_completed)) {
+ wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
+ (int) GetLastError());
+ ctrl_close_pipe(dst);
+ } else {
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p",
+ dst);
+ }
+
+ if (new_attached)
+ eapol_sm_notify_ctrl_attached(wpa_s->eapol);
+}
+
+
+static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap)
+{
+ struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
+ "bytes=%d", dst, (int) err, (int) bytes);
+ if (err == 0 && bytes > 0)
+ wpa_supplicant_ctrl_iface_rx(dst, bytes);
+}
+
+
+static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx)
+{
+ struct wpa_ctrl_dst *dst = eloop_data;
+ struct ctrl_iface_priv *priv = dst->priv;
+ DWORD bytes;
+
+ wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive");
+ ResetEvent(dst->overlap.hEvent);
+
+ if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
+ wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
+ (int) GetLastError());
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
+ "connected");
+
+ /* Open a new named pipe for the next client. */
+ ctrl_open_pipe(priv);
+
+ /* Use write completion function to start reading a command */
+ ctrl_iface_write_completed(0, 0, &dst->overlap);
+
+ ctrl_flush_broken_pipes(priv);
+}
+
+
+static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params)
+{
+ const char *sddl = NULL;
+ TCHAR *t_sddl;
+
+ if (os_strncmp(params, "SDDL=", 5) == 0)
+ sddl = params + 5;
+ if (!sddl) {
+ sddl = os_strstr(params, " SDDL=");
+ if (sddl)
+ sddl += 6;
+ }
+
+ if (!sddl)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl);
+ os_memset(&priv->attr, 0, sizeof(priv->attr));
+ priv->attr.nLength = sizeof(priv->attr);
+ priv->attr.bInheritHandle = FALSE;
+ t_sddl = wpa_strdup_tchar(sddl);
+ if (t_sddl == NULL)
+ return -1;
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
+ t_sddl, SDDL_REVISION_1,
+ (PSECURITY_DESCRIPTOR *) &priv->attr.lpSecurityDescriptor,
+ NULL)) {
+ os_free(t_sddl);
+ wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to "
+ "security descriptor: %d",
+ sddl, (int) GetLastError());
+ return -1;
+ }
+ os_free(t_sddl);
+
+ priv->sec_attr_set = 1;
+
+ return 0;
+}
+
+
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+ const char *txt, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+ return;
+ wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ priv->wpa_s = wpa_s;
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return priv;
+
+ if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ if (ctrl_open_pipe(priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+ return priv;
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+ while (priv->ctrl_dst)
+ ctrl_close_pipe(priv->ctrl_dst);
+ if (priv->sec_attr_set)
+ LocalFree(priv->attr.lpSecurityDescriptor);
+ os_free(priv);
+}
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+ int level, const char *buf,
+ size_t len)
+{
+ struct wpa_ctrl_dst *dst, *next;
+ char levelstr[10];
+ int idx;
+ char *sbuf;
+ int llen;
+ DWORD written;
+
+ dst = priv->ctrl_dst;
+ if (dst == NULL)
+ return;
+
+ os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+
+ llen = os_strlen(levelstr);
+ sbuf = os_malloc(llen + len);
+ if (sbuf == NULL)
+ return;
+
+ os_memcpy(sbuf, levelstr, llen);
+ os_memcpy(sbuf + llen, buf, len);
+
+ idx = 0;
+ while (dst) {
+ next = dst->next;
+ if (dst->attached && level >= dst->debug_level) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p",
+ dst);
+ if (!WriteFile(dst->pipe, sbuf, llen + len, &written,
+ NULL)) {
+ wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst "
+ "%p failed: %d",
+ dst, (int) GetLastError());
+ dst->errors++;
+ if (dst->errors > 10)
+ ctrl_close_pipe(dst);
+ } else
+ dst->errors = 0;
+ }
+ idx++;
+ dst = next;
+ }
+ os_free(sbuf);
+}
+
+
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
+ priv->wpa_s->ifname);
+ if (priv->ctrl_dst == NULL)
+ return;
+ WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE);
+}
+
+
+/* Global ctrl_iface */
+
+struct ctrl_iface_global_priv;
+
+struct wpa_global_dst {
+ /* Note: OVERLAPPED must be the first member of struct wpa_global_dst
+ */
+ OVERLAPPED overlap;
+ struct wpa_global_dst *next, *prev;
+ struct ctrl_iface_global_priv *priv;
+ HANDLE pipe;
+ char req_buf[REQUEST_BUFSIZE];
+ char *rsp_buf;
+ int used;
+};
+
+struct ctrl_iface_global_priv {
+ struct wpa_global *global;
+ struct wpa_global_dst *ctrl_dst;
+};
+
+
+static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv)
+{
+ struct wpa_global_dst *dst, *next;
+
+ dst = priv->ctrl_dst;
+
+ while (dst) {
+ next = dst->next;
+ if (ctrl_broken_pipe(dst->pipe, dst->used)) {
+ wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
+ dst);
+ global_close_pipe(dst);
+ }
+ dst = next;
+ }
+}
+
+
+static int global_open_pipe(struct ctrl_iface_global_priv *priv)
+{
+ struct wpa_global_dst *dst;
+ DWORD err;
+
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
+
+ dst->priv = priv;
+ dst->pipe = INVALID_HANDLE_VALUE;
+
+ dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (dst->overlap.hEvent == NULL) {
+ wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
+ (int) GetLastError());
+ goto fail;
+ }
+
+ eloop_register_event(dst->overlap.hEvent,
+ sizeof(dst->overlap.hEvent),
+ wpa_supplicant_global_iface_receive, dst, NULL);
+
+ /* TODO: add support for configuring access list for the pipe */
+ dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_MESSAGE |
+ PIPE_READMODE_MESSAGE |
+ PIPE_WAIT,
+ 10, REPLY_BUFSIZE, REQUEST_BUFSIZE,
+ 1000, NULL);
+ if (dst->pipe == INVALID_HANDLE_VALUE) {
+ wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
+ (int) GetLastError());
+ goto fail;
+ }
+
+ if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
+ wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
+ (int) GetLastError());
+ CloseHandle(dst->pipe);
+ os_free(dst);
+ return -1;
+ }
+
+ err = GetLastError();
+ switch (err) {
+ case ERROR_IO_PENDING:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
+ "progress");
+ break;
+ case ERROR_PIPE_CONNECTED:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
+ "connected");
+ if (SetEvent(dst->overlap.hEvent))
+ break;
+ /* fall through */
+ default:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
+ (int) err);
+ CloseHandle(dst->pipe);
+ os_free(dst);
+ return -1;
+ }
+
+ dst->next = priv->ctrl_dst;
+ if (dst->next)
+ dst->next->prev = dst;
+ priv->ctrl_dst = dst;
+
+ return 0;
+
+fail:
+ global_close_pipe(dst);
+ return -1;
+}
+
+
+static void global_close_pipe(struct wpa_global_dst *dst)
+{
+ wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
+
+ if (dst->overlap.hEvent) {
+ eloop_unregister_event(dst->overlap.hEvent,
+ sizeof(dst->overlap.hEvent));
+ CloseHandle(dst->overlap.hEvent);
+ }
+
+ if (dst->pipe != INVALID_HANDLE_VALUE) {
+ /*
+ * Could use FlushFileBuffers() here to guarantee that all data
+ * gets delivered to the client, but that can block, so let's
+ * not do this for now.
+ * FlushFileBuffers(dst->pipe);
+ */
+ CloseHandle(dst->pipe);
+ }
+
+ if (dst->prev)
+ dst->prev->next = dst->next;
+ else
+ dst->priv->ctrl_dst = dst->next;
+ if (dst->next)
+ dst->next->prev = dst->prev;
+
+ os_free(dst->rsp_buf);
+ os_free(dst);
+}
+
+
+static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap)
+{
+ struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
+ "err=%d bytes=%d", dst, (int) err, (int) bytes);
+ if (err) {
+ global_close_pipe(dst);
+ return;
+ }
+
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = NULL;
+
+ if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
+ &dst->overlap, global_iface_read_completed)) {
+ wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
+ (int) GetLastError());
+ global_close_pipe(dst);
+ /* FIX: if this was the pipe waiting for new global
+ * connections, at this point there are no open global pipes..
+ * Should try to open a new pipe.. */
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
+}
+
+
+static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst,
+ size_t len)
+{
+ struct wpa_global *global = dst->priv->global;
+ char *reply = NULL, *send_buf;
+ size_t reply_len = 0, send_len;
+ char *buf = dst->req_buf;
+
+ dst->used = 1;
+ if (len >= REQUEST_BUFSIZE)
+ len = REQUEST_BUFSIZE - 1;
+ buf[len] = '\0';
+
+ reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
+ &reply_len);
+ if (reply) {
+ send_buf = reply;
+ send_len = reply_len;
+ } else if (reply_len) {
+ send_buf = "FAIL\n";
+ send_len = 5;
+ } else {
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = NULL;
+ return;
+ }
+
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = os_malloc(send_len);
+ if (dst->rsp_buf == NULL) {
+ global_close_pipe(dst);
+ os_free(reply);
+ return;
+ }
+ os_memcpy(dst->rsp_buf, send_buf, send_len);
+ os_free(reply);
+
+ if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
+ global_iface_write_completed)) {
+ wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
+ (int) GetLastError());
+ global_close_pipe(dst);
+ } else {
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p",
+ dst);
+ }
+}
+
+
+static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap)
+{
+ struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
+ "bytes=%d", dst, (int) err, (int) bytes);
+ if (err == 0 && bytes > 0)
+ wpa_supplicant_global_iface_rx(dst, bytes);
+}
+
+
+static void wpa_supplicant_global_iface_receive(void *eloop_data,
+ void *user_ctx)
+{
+ struct wpa_global_dst *dst = eloop_data;
+ struct ctrl_iface_global_priv *priv = dst->priv;
+ DWORD bytes;
+
+ wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive");
+ ResetEvent(dst->overlap.hEvent);
+
+ if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
+ wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
+ (int) GetLastError());
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
+ "connected");
+
+ /* Open a new named pipe for the next client. */
+ if (global_open_pipe(priv) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed");
+ return;
+ }
+
+ /* Use write completion function to start reading a command */
+ global_iface_write_completed(0, 0, &dst->overlap);
+
+ global_flush_broken_pipes(priv);
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+ struct ctrl_iface_global_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ priv->global = global;
+
+ if (global_open_pipe(priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ return priv;
+}
+
+
+void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+ while (priv->ctrl_dst)
+ global_close_pipe(priv->ctrl_dst);
+ os_free(priv);
+}
diff --git a/contrib/wpa_supplicant/ctrl_iface_udp.c b/contrib/wpa_supplicant/ctrl_iface_udp.c
new file mode 100644
index 000000000000..bb6f11d50c9c
--- /dev/null
+++ b/contrib/wpa_supplicant/ctrl_iface_udp.c
@@ -0,0 +1,561 @@
+/*
+ * WPA Supplicant / UDP socket -based control interface
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "config.h"
+#include "eapol_sm.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface.h"
+#include "wpa_ctrl.h"
+
+
+#define COOKIE_LEN 8
+
+/* Per-interface ctrl_iface */
+
+/**
+ * struct wpa_ctrl_dst - Internal data structure of control interface monitors
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant. This data is private to
+ * ctrl_iface_udp.c and should not be touched directly from other files.
+ */
+struct wpa_ctrl_dst {
+ struct wpa_ctrl_dst *next;
+ struct sockaddr_in addr;
+ socklen_t addrlen;
+ int debug_level;
+ int errors;
+};
+
+
+struct ctrl_iface_priv {
+ struct wpa_supplicant *wpa_s;
+ int sock;
+ struct wpa_ctrl_dst *ctrl_dst;
+ u8 cookie[COOKIE_LEN];
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+ int level, const char *buf,
+ size_t len);
+
+
+static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+ struct sockaddr_in *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst;
+
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ os_memcpy(&dst->addr, from, sizeof(struct sockaddr_in));
+ dst->addrlen = fromlen;
+ dst->debug_level = MSG_INFO;
+ dst->next = priv->ctrl_dst;
+ priv->ctrl_dst = dst;
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached %s:%d",
+ inet_ntoa(from->sin_addr), ntohs(from->sin_port));
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+ struct sockaddr_in *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst, *prev = NULL;
+
+ dst = priv->ctrl_dst;
+ while (dst) {
+ if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
+ from->sin_port == dst->addr.sin_port) {
+ if (prev == NULL)
+ priv->ctrl_dst = dst->next;
+ else
+ prev->next = dst->next;
+ os_free(dst);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
+ "%s:%d", inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port));
+ return 0;
+ }
+ prev = dst;
+ dst = dst->next;
+ }
+ return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
+ struct sockaddr_in *from,
+ socklen_t fromlen,
+ char *level)
+{
+ struct wpa_ctrl_dst *dst;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+ dst = priv->ctrl_dst;
+ while (dst) {
+ if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
+ from->sin_port == dst->addr.sin_port) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE changed monitor "
+ "level %s:%d", inet_ntoa(from->sin_addr),
+ ntohs(from->sin_port));
+ dst->debug_level = atoi(level);
+ return 0;
+ }
+ dst = dst->next;
+ }
+
+ return -1;
+}
+
+
+static char *
+wpa_supplicant_ctrl_iface_get_cookie(struct ctrl_iface_priv *priv,
+ size_t *reply_len)
+{
+ char *reply;
+ reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
+ if (reply == NULL) {
+ *reply_len = 1;
+ return NULL;
+ }
+
+ os_memcpy(reply, "COOKIE=", 7);
+ wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+ priv->cookie, COOKIE_LEN);
+
+ *reply_len = 7 + 2 * COOKIE_LEN;
+ return reply;
+}
+
+
+static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct ctrl_iface_priv *priv = sock_ctx;
+ char buf[256], *pos;
+ int res;
+ struct sockaddr_in from;
+ socklen_t fromlen = sizeof(from);
+ char *reply = NULL;
+ size_t reply_len = 0;
+ int new_attached = 0;
+ u8 cookie[COOKIE_LEN];
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
+ /*
+ * The OS networking stack is expected to drop this kind of
+ * frames since the socket is bound to only localhost address.
+ * Just in case, drop the frame if it is coming from any other
+ * address.
+ */
+ wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
+ "source %s", inet_ntoa(from.sin_addr));
+ return;
+ }
+ buf[res] = '\0';
+
+ if (os_strcmp(buf, "GET_COOKIE") == 0) {
+ reply = wpa_supplicant_ctrl_iface_get_cookie(priv, &reply_len);
+ goto done;
+ }
+
+ /*
+ * Require that the client includes a prefix with the 'cookie' value
+ * fetched with GET_COOKIE command. This is used to verify that the
+ * client has access to a bidirectional link over UDP in order to
+ * avoid attacks using forged localhost IP address even if the OS does
+ * not block such frames from remote destinations.
+ */
+ if (os_strncmp(buf, "COOKIE=", 7) != 0) {
+ wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
+ "drop request");
+ return;
+ }
+
+ if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
+ "request - drop request");
+ return;
+ }
+
+ if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
+ "drop request");
+ return;
+ }
+
+ pos = buf + 7 + 2 * COOKIE_LEN;
+ while (*pos == ' ')
+ pos++;
+
+ if (os_strcmp(pos, "ATTACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+ reply_len = 1;
+ else {
+ new_attached = 1;
+ reply_len = 2;
+ }
+ } else if (os_strcmp(pos, "DETACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else if (os_strncmp(pos, "LEVEL ", 6) == 0) {
+ if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
+ pos + 6))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else {
+ reply = wpa_supplicant_ctrl_iface_process(wpa_s, pos,
+ &reply_len);
+ }
+
+ done:
+ if (reply) {
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen);
+ os_free(reply);
+ } else if (reply_len == 1) {
+ sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen);
+ } else if (reply_len == 2) {
+ sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
+ fromlen);
+ }
+
+ if (new_attached)
+ eapol_sm_notify_ctrl_attached(wpa_s->eapol);
+}
+
+
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+ const char *txt, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+ return;
+ wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_priv *priv;
+ struct sockaddr_in addr;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ priv->wpa_s = wpa_s;
+ priv->sock = -1;
+ os_get_random(priv->cookie, COOKIE_LEN);
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return priv;
+
+ priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (priv->sock < 0) {
+ perror("socket(PF_INET)");
+ goto fail;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl((127 << 24) | 1);
+ addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
+ if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(AF_INET)");
+ goto fail;
+ }
+
+ eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
+ wpa_s, priv);
+ wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+ return priv;
+
+fail:
+ if (priv->sock >= 0)
+ close(priv->sock);
+ os_free(priv);
+ return NULL;
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+ struct wpa_ctrl_dst *dst, *prev;
+
+ if (priv->sock > -1) {
+ eloop_unregister_read_sock(priv->sock);
+ if (priv->ctrl_dst) {
+ /*
+ * Wait a second before closing the control socket if
+ * there are any attached monitors in order to allow
+ * them to receive any pending messages.
+ */
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
+ "monitors to receive messages");
+ os_sleep(1, 0);
+ }
+ close(priv->sock);
+ priv->sock = -1;
+ }
+
+ dst = priv->ctrl_dst;
+ while (dst) {
+ prev = dst;
+ dst = dst->next;
+ os_free(prev);
+ }
+ os_free(priv);
+}
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+ int level, const char *buf,
+ size_t len)
+{
+ struct wpa_ctrl_dst *dst, *next;
+ char levelstr[10];
+ int idx;
+ char *sbuf;
+ int llen;
+
+ dst = priv->ctrl_dst;
+ if (priv->sock < 0 || dst == NULL)
+ return;
+
+ os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+
+ llen = os_strlen(levelstr);
+ sbuf = os_malloc(llen + len);
+ if (sbuf == NULL)
+ return;
+
+ os_memcpy(sbuf, levelstr, llen);
+ os_memcpy(sbuf + llen, buf, len);
+
+ idx = 0;
+ while (dst) {
+ next = dst->next;
+ if (level >= dst->debug_level) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %s:%d",
+ inet_ntoa(dst->addr.sin_addr),
+ ntohs(dst->addr.sin_port));
+ if (sendto(priv->sock, sbuf, llen + len, 0,
+ (struct sockaddr *) &dst->addr,
+ sizeof(dst->addr)) < 0) {
+ perror("sendto(CTRL_IFACE monitor)");
+ dst->errors++;
+ if (dst->errors > 10) {
+ wpa_supplicant_ctrl_iface_detach(
+ priv, &dst->addr,
+ dst->addrlen);
+ }
+ } else
+ dst->errors = 0;
+ }
+ idx++;
+ dst = next;
+ }
+ os_free(sbuf);
+}
+
+
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
+ priv->wpa_s->ifname);
+ eloop_wait_for_read_sock(priv->sock);
+}
+
+
+/* Global ctrl_iface */
+
+struct ctrl_iface_global_priv {
+ int sock;
+ u8 cookie[COOKIE_LEN];
+};
+
+
+static char *
+wpa_supplicant_global_get_cookie(struct ctrl_iface_global_priv *priv,
+ size_t *reply_len)
+{
+ char *reply;
+ reply = os_malloc(7 + 2 * COOKIE_LEN + 1);
+ if (reply == NULL) {
+ *reply_len = 1;
+ return NULL;
+ }
+
+ os_memcpy(reply, "COOKIE=", 7);
+ wpa_snprintf_hex(reply + 7, 2 * COOKIE_LEN + 1,
+ priv->cookie, COOKIE_LEN);
+
+ *reply_len = 7 + 2 * COOKIE_LEN;
+ return reply;
+}
+
+
+static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_global *global = eloop_ctx;
+ struct ctrl_iface_global_priv *priv = sock_ctx;
+ char buf[256], *pos;
+ int res;
+ struct sockaddr_in from;
+ socklen_t fromlen = sizeof(from);
+ char *reply;
+ size_t reply_len;
+ u8 cookie[COOKIE_LEN];
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ if (from.sin_addr.s_addr != htonl((127 << 24) | 1)) {
+ /*
+ * The OS networking stack is expected to drop this kind of
+ * frames since the socket is bound to only localhost address.
+ * Just in case, drop the frame if it is coming from any other
+ * address.
+ */
+ wpa_printf(MSG_DEBUG, "CTRL: Drop packet from unexpected "
+ "source %s", inet_ntoa(from.sin_addr));
+ return;
+ }
+ buf[res] = '\0';
+
+ if (os_strcmp(buf, "GET_COOKIE") == 0) {
+ reply = wpa_supplicant_global_get_cookie(priv, &reply_len);
+ goto done;
+ }
+
+ if (os_strncmp(buf, "COOKIE=", 7) != 0) {
+ wpa_printf(MSG_DEBUG, "CTLR: No cookie in the request - "
+ "drop request");
+ return;
+ }
+
+ if (hexstr2bin(buf + 7, cookie, COOKIE_LEN) < 0) {
+ wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie format in the "
+ "request - drop request");
+ return;
+ }
+
+ if (os_memcmp(cookie, priv->cookie, COOKIE_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "CTLR: Invalid cookie in the request - "
+ "drop request");
+ return;
+ }
+
+ pos = buf + 7 + 2 * COOKIE_LEN;
+ while (*pos == ' ')
+ pos++;
+
+ reply = wpa_supplicant_global_ctrl_iface_process(global, pos,
+ &reply_len);
+
+ done:
+ if (reply) {
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen);
+ os_free(reply);
+ } else if (reply_len) {
+ sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen);
+ }
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+ struct ctrl_iface_global_priv *priv;
+ struct sockaddr_in addr;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ priv->sock = -1;
+ os_get_random(priv->cookie, COOKIE_LEN);
+
+ if (global->params.ctrl_interface == NULL)
+ return priv;
+
+ wpa_printf(MSG_DEBUG, "Global control interface '%s'",
+ global->params.ctrl_interface);
+
+ priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (priv->sock < 0) {
+ perror("socket(PF_INET)");
+ goto fail;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = htonl((127 << 24) | 1);
+ addr.sin_port = htons(WPA_GLOBAL_CTRL_IFACE_PORT);
+ if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(AF_INET)");
+ goto fail;
+ }
+
+ eloop_register_read_sock(priv->sock,
+ wpa_supplicant_global_ctrl_iface_receive,
+ global, priv);
+
+ return priv;
+
+fail:
+ if (priv->sock >= 0)
+ close(priv->sock);
+ os_free(priv);
+ return NULL;
+}
+
+
+void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+ if (priv->sock >= 0) {
+ eloop_unregister_read_sock(priv->sock);
+ close(priv->sock);
+ }
+ os_free(priv);
+}
diff --git a/contrib/wpa_supplicant/ctrl_iface_unix.c b/contrib/wpa_supplicant/ctrl_iface_unix.c
new file mode 100644
index 000000000000..e9bc47239c63
--- /dev/null
+++ b/contrib/wpa_supplicant/ctrl_iface_unix.c
@@ -0,0 +1,656 @@
+/*
+ * WPA Supplicant / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <grp.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "config.h"
+#include "eapol_sm.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface.h"
+
+/* Per-interface ctrl_iface */
+
+/**
+ * struct wpa_ctrl_dst - Internal data structure of control interface monitors
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant. This data is private to
+ * ctrl_iface_unix.c and should not be touched directly from other files.
+ */
+struct wpa_ctrl_dst {
+ struct wpa_ctrl_dst *next;
+ struct sockaddr_un addr;
+ socklen_t addrlen;
+ int debug_level;
+ int errors;
+};
+
+
+struct ctrl_iface_priv {
+ struct wpa_supplicant *wpa_s;
+ int sock;
+ struct wpa_ctrl_dst *ctrl_dst;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+ int level, const char *buf,
+ size_t len);
+
+
+static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst;
+
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+ dst->addrlen = fromlen;
+ dst->debug_level = MSG_INFO;
+ dst->next = priv->ctrl_dst;
+ priv->ctrl_dst = dst;
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+ (u8 *) from->sun_path, fromlen - sizeof(from->sun_family));
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+ struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct wpa_ctrl_dst *dst, *prev = NULL;
+
+ dst = priv->ctrl_dst;
+ while (dst) {
+ if (fromlen == dst->addrlen &&
+ os_memcmp(from->sun_path, dst->addr.sun_path,
+ fromlen - sizeof(from->sun_family)) == 0) {
+ if (prev == NULL)
+ priv->ctrl_dst = dst->next;
+ else
+ prev->next = dst->next;
+ os_free(dst);
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+ (u8 *) from->sun_path,
+ fromlen - sizeof(from->sun_family));
+ return 0;
+ }
+ prev = dst;
+ dst = dst->next;
+ }
+ return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
+ struct sockaddr_un *from,
+ socklen_t fromlen,
+ char *level)
+{
+ struct wpa_ctrl_dst *dst;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+ dst = priv->ctrl_dst;
+ while (dst) {
+ if (fromlen == dst->addrlen &&
+ os_memcmp(from->sun_path, dst->addr.sun_path,
+ fromlen - sizeof(from->sun_family)) == 0) {
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
+ "level", (u8 *) from->sun_path,
+ fromlen - sizeof(from->sun_family));
+ dst->debug_level = atoi(level);
+ return 0;
+ }
+ dst = dst->next;
+ }
+
+ return -1;
+}
+
+
+static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct ctrl_iface_priv *priv = sock_ctx;
+ char buf[256];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ char *reply = NULL;
+ size_t reply_len = 0;
+ int new_attached = 0;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ buf[res] = '\0';
+
+ if (os_strcmp(buf, "ATTACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+ reply_len = 1;
+ else {
+ new_attached = 1;
+ reply_len = 2;
+ }
+ } else if (os_strcmp(buf, "DETACH") == 0) {
+ if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+ if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
+ buf + 6))
+ reply_len = 1;
+ else
+ reply_len = 2;
+ } else {
+ reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+ &reply_len);
+ }
+
+ if (reply) {
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen);
+ os_free(reply);
+ } else if (reply_len == 1) {
+ sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen);
+ } else if (reply_len == 2) {
+ sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
+ fromlen);
+ }
+
+ if (new_attached)
+ eapol_sm_notify_ctrl_attached(wpa_s->eapol);
+}
+
+
+static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
+{
+ char *buf;
+ size_t len;
+ char *pbuf, *dir = NULL, *gid_str = NULL;
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return NULL;
+
+ pbuf = os_strdup(wpa_s->conf->ctrl_interface);
+ if (pbuf == NULL)
+ return NULL;
+ if (os_strncmp(pbuf, "DIR=", 4) == 0) {
+ dir = pbuf + 4;
+ gid_str = os_strstr(dir, " GROUP=");
+ if (gid_str) {
+ *gid_str = '\0';
+ gid_str += 7;
+ }
+ } else
+ dir = pbuf;
+
+ len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2;
+ buf = os_malloc(len);
+ if (buf == NULL) {
+ os_free(pbuf);
+ return NULL;
+ }
+
+ os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
+#ifdef __CYGWIN__
+ {
+ /* Windows/WinPcap uses interface names that are not suitable
+ * as a file name - convert invalid chars to underscores */
+ char *pos = buf;
+ while (*pos) {
+ if (*pos == '\\')
+ *pos = '_';
+ pos++;
+ }
+ }
+#endif /* __CYGWIN__ */
+ os_free(pbuf);
+ return buf;
+}
+
+
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+ const char *txt, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+ return;
+ wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_priv *priv;
+ struct sockaddr_un addr;
+ char *fname = NULL;
+ gid_t gid = 0;
+ int gid_set = 0;
+ char *buf, *dir = NULL, *gid_str = NULL;
+ struct group *grp;
+ char *endp;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ priv->wpa_s = wpa_s;
+ priv->sock = -1;
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return priv;
+
+ buf = os_strdup(wpa_s->conf->ctrl_interface);
+ if (buf == NULL)
+ goto fail;
+ if (os_strncmp(buf, "DIR=", 4) == 0) {
+ dir = buf + 4;
+ gid_str = os_strstr(dir, " GROUP=");
+ if (gid_str) {
+ *gid_str = '\0';
+ gid_str += 7;
+ }
+ } else {
+ dir = buf;
+ gid_str = wpa_s->conf->ctrl_interface_group;
+ }
+
+ if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) {
+ if (errno == EEXIST) {
+ wpa_printf(MSG_DEBUG, "Using existing control "
+ "interface directory.");
+ } else {
+ perror("mkdir[ctrl_interface]");
+ goto fail;
+ }
+ }
+
+ if (gid_str) {
+ grp = getgrnam(gid_str);
+ if (grp) {
+ gid = grp->gr_gid;
+ gid_set = 1;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+ " (from group name '%s')",
+ (int) gid, gid_str);
+ } else {
+ /* Group name not found - try to parse this as gid */
+ gid = strtol(gid_str, &endp, 10);
+ if (*gid_str == '\0' || *endp != '\0') {
+ wpa_printf(MSG_DEBUG, "CTRL: Invalid group "
+ "'%s'", gid_str);
+ goto fail;
+ }
+ gid_set = 1;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+ (int) gid);
+ }
+ }
+
+ if (gid_set && chown(dir, -1, gid) < 0) {
+ perror("chown[ctrl_interface]");
+ goto fail;
+ }
+
+ if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >=
+ sizeof(addr.sun_path))
+ goto fail;
+
+ priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (priv->sock < 0) {
+ perror("socket(PF_UNIX)");
+ goto fail;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ fname = wpa_supplicant_ctrl_iface_path(wpa_s);
+ if (fname == NULL)
+ goto fail;
+ os_strncpy(addr.sun_path, fname, sizeof(addr.sun_path));
+ if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+ strerror(errno));
+ if (connect(priv->sock, (struct sockaddr *) &addr,
+ sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+ " allow connections - assuming it was left"
+ "over from forced program termination");
+ if (unlink(fname) < 0) {
+ perror("unlink[ctrl_iface]");
+ wpa_printf(MSG_ERROR, "Could not unlink "
+ "existing ctrl_iface socket '%s'",
+ fname);
+ goto fail;
+ }
+ if (bind(priv->sock, (struct sockaddr *) &addr,
+ sizeof(addr)) < 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+ "ctrl_iface socket '%s'", fname);
+ } else {
+ wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+ "be in use - cannot override it");
+ wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+ "not used anymore", fname);
+ os_free(fname);
+ fname = NULL;
+ goto fail;
+ }
+ }
+
+ if (gid_set && chown(fname, -1, gid) < 0) {
+ perror("chown[ctrl_interface/ifname]");
+ goto fail;
+ }
+
+ if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+ perror("chmod[ctrl_interface/ifname]");
+ goto fail;
+ }
+ os_free(fname);
+
+ eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
+ wpa_s, priv);
+ wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+ os_free(buf);
+ return priv;
+
+fail:
+ if (priv->sock >= 0)
+ close(priv->sock);
+ os_free(priv);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+ os_free(buf);
+ return NULL;
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+ struct wpa_ctrl_dst *dst, *prev;
+
+ if (priv->sock > -1) {
+ char *fname;
+ char *buf, *dir = NULL, *gid_str = NULL;
+ eloop_unregister_read_sock(priv->sock);
+ if (priv->ctrl_dst) {
+ /*
+ * Wait a second before closing the control socket if
+ * there are any attached monitors in order to allow
+ * them to receive any pending messages.
+ */
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
+ "monitors to receive messages");
+ os_sleep(1, 0);
+ }
+ close(priv->sock);
+ priv->sock = -1;
+ fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
+ if (fname) {
+ unlink(fname);
+ os_free(fname);
+ }
+
+ buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
+ if (buf == NULL)
+ goto free_dst;
+ if (os_strncmp(buf, "DIR=", 4) == 0) {
+ dir = buf + 4;
+ gid_str = os_strstr(dir, " GROUP=");
+ if (gid_str) {
+ *gid_str = '\0';
+ gid_str += 7;
+ }
+ } else
+ dir = buf;
+
+ if (rmdir(dir) < 0) {
+ if (errno == ENOTEMPTY) {
+ wpa_printf(MSG_DEBUG, "Control interface "
+ "directory not empty - leaving it "
+ "behind");
+ } else {
+ perror("rmdir[ctrl_interface]");
+ }
+ }
+ os_free(buf);
+ }
+
+free_dst:
+ dst = priv->ctrl_dst;
+ while (dst) {
+ prev = dst;
+ dst = dst->next;
+ os_free(prev);
+ }
+ os_free(priv);
+}
+
+
+/**
+ * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ * @level: Priority level of the message
+ * @buf: Message data
+ * @len: Message length
+ *
+ * Send a packet to all monitor programs attached to the control interface.
+ */
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+ int level, const char *buf,
+ size_t len)
+{
+ struct wpa_ctrl_dst *dst, *next;
+ char levelstr[10];
+ int idx;
+ struct msghdr msg;
+ struct iovec io[2];
+
+ dst = priv->ctrl_dst;
+ if (priv->sock < 0 || dst == NULL)
+ return;
+
+ os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+ io[0].iov_base = levelstr;
+ io[0].iov_len = os_strlen(levelstr);
+ io[1].iov_base = (char *) buf;
+ io[1].iov_len = len;
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+
+ idx = 0;
+ while (dst) {
+ next = dst->next;
+ if (level >= dst->debug_level) {
+ wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+ (u8 *) dst->addr.sun_path, dst->addrlen -
+ sizeof(dst->addr.sun_family));
+ msg.msg_name = (void *) &dst->addr;
+ msg.msg_namelen = dst->addrlen;
+ if (sendmsg(priv->sock, &msg, 0) < 0) {
+ perror("sendmsg(CTRL_IFACE monitor)");
+ dst->errors++;
+ if (dst->errors > 10) {
+ wpa_supplicant_ctrl_iface_detach(
+ priv, &dst->addr,
+ dst->addrlen);
+ }
+ } else
+ dst->errors = 0;
+ }
+ idx++;
+ dst = next;
+ }
+}
+
+
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
+ priv->wpa_s->ifname);
+ eloop_wait_for_read_sock(priv->sock);
+}
+
+
+/* Global ctrl_iface */
+
+struct ctrl_iface_global_priv {
+ struct wpa_global *global;
+ int sock;
+};
+
+
+static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_global *global = eloop_ctx;
+ char buf[256];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ char *reply;
+ size_t reply_len;
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(ctrl_iface)");
+ return;
+ }
+ buf[res] = '\0';
+
+ reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
+ &reply_len);
+
+ if (reply) {
+ sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+ fromlen);
+ os_free(reply);
+ } else if (reply_len) {
+ sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen);
+ }
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+ struct ctrl_iface_global_priv *priv;
+ struct sockaddr_un addr;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ priv->global = global;
+ priv->sock = -1;
+
+ if (global->params.ctrl_interface == NULL)
+ return priv;
+
+ wpa_printf(MSG_DEBUG, "Global control interface '%s'",
+ global->params.ctrl_interface);
+
+ priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (priv->sock < 0) {
+ perror("socket(PF_UNIX)");
+ goto fail;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_strncpy(addr.sun_path, global->params.ctrl_interface,
+ sizeof(addr.sun_path));
+ if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(PF_UNIX)");
+ if (connect(priv->sock, (struct sockaddr *) &addr,
+ sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+ " allow connections - assuming it was left"
+ "over from forced program termination");
+ if (unlink(global->params.ctrl_interface) < 0) {
+ perror("unlink[ctrl_iface]");
+ wpa_printf(MSG_ERROR, "Could not unlink "
+ "existing ctrl_iface socket '%s'",
+ global->params.ctrl_interface);
+ goto fail;
+ }
+ if (bind(priv->sock, (struct sockaddr *) &addr,
+ sizeof(addr)) < 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+ "ctrl_iface socket '%s'",
+ global->params.ctrl_interface);
+ } else {
+ wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+ "be in use - cannot override it");
+ wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+ "not used anymore",
+ global->params.ctrl_interface);
+ goto fail;
+ }
+ }
+
+ eloop_register_read_sock(priv->sock,
+ wpa_supplicant_global_ctrl_iface_receive,
+ global, NULL);
+
+ return priv;
+
+fail:
+ if (priv->sock >= 0)
+ close(priv->sock);
+ os_free(priv);
+ return NULL;
+}
+
+
+void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+ if (priv->sock >= 0) {
+ eloop_unregister_read_sock(priv->sock);
+ close(priv->sock);
+ }
+ if (priv->global->params.ctrl_interface)
+ unlink(priv->global->params.ctrl_interface);
+ os_free(priv);
+}
diff --git a/contrib/wpa_supplicant/dbus-wpa_supplicant.conf b/contrib/wpa_supplicant/dbus-wpa_supplicant.conf
new file mode 100644
index 000000000000..1622af579030
--- /dev/null
+++ b/contrib/wpa_supplicant/dbus-wpa_supplicant.conf
@@ -0,0 +1,20 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="root">
+ <allow own="fi.epitest.hostap.WPASupplicant"/>
+
+ <allow send_destination="fi.epitest.hostap.WPASupplicant"/>
+ <allow send_interface="fi.epitest.hostap.WPASupplicant"/>
+ </policy>
+ <policy at_console="true">
+ <allow send_destination="fi.epitest.hostap.WPASupplicant"/>
+ <allow send_interface="fi.epitest.hostap.WPASupplicant"/>
+ </policy>
+ <policy context="default">
+ <deny own="fi.epitest.hostap.WPASupplicant"/>
+ <deny send_destination="fi.epitest.hostap.WPASupplicant"/>
+ <deny send_interface="fi.epitest.hostap.WPASupplicant"/>
+ </policy>
+</busconfig>
diff --git a/contrib/wpa_supplicant/dbus_dict_helpers.c b/contrib/wpa_supplicant/dbus_dict_helpers.c
new file mode 100644
index 000000000000..2852ed522cd4
--- /dev/null
+++ b/contrib/wpa_supplicant/dbus_dict_helpers.c
@@ -0,0 +1,957 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#include <dbus/dbus.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "common.h"
+#include "dbus_dict_helpers.h"
+
+
+/**
+ * Start a dict in a dbus message. Should be paired with a call to
+ * {@link wpa_dbus_dict_close_write}.
+ *
+ * @param iter A valid dbus message iterator
+ * @param iter_dict (out) A dict iterator to pass to further dict functions
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
+ DBusMessageIter *iter_dict)
+{
+ dbus_bool_t result;
+
+ if (!iter || !iter_dict)
+ return FALSE;
+
+ result = dbus_message_iter_open_container(
+ iter,
+ DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING
+ DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+ iter_dict);
+ return result;
+}
+
+
+/**
+ * End a dict element in a dbus message. Should be paired with
+ * a call to {@link wpa_dbus_dict_open_write}.
+ *
+ * @param iter valid dbus message iterator, same as passed to
+ * wpa_dbus_dict_open_write()
+ * @param iter_dict a dbus dict iterator returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
+ DBusMessageIter *iter_dict)
+{
+ if (!iter || !iter_dict)
+ return FALSE;
+
+ return dbus_message_iter_close_container(iter, iter_dict);
+}
+
+
+static const char * _wpa_get_type_as_string_from_type(const int type)
+{
+ switch(type) {
+ case DBUS_TYPE_BYTE:
+ return DBUS_TYPE_BYTE_AS_STRING;
+ case DBUS_TYPE_BOOLEAN:
+ return DBUS_TYPE_BOOLEAN_AS_STRING;
+ case DBUS_TYPE_INT16:
+ return DBUS_TYPE_INT16_AS_STRING;
+ case DBUS_TYPE_UINT16:
+ return DBUS_TYPE_UINT16_AS_STRING;
+ case DBUS_TYPE_INT32:
+ return DBUS_TYPE_INT32_AS_STRING;
+ case DBUS_TYPE_UINT32:
+ return DBUS_TYPE_UINT32_AS_STRING;
+ case DBUS_TYPE_INT64:
+ return DBUS_TYPE_INT64_AS_STRING;
+ case DBUS_TYPE_UINT64:
+ return DBUS_TYPE_UINT64_AS_STRING;
+ case DBUS_TYPE_DOUBLE:
+ return DBUS_TYPE_DOUBLE_AS_STRING;
+ case DBUS_TYPE_STRING:
+ return DBUS_TYPE_STRING_AS_STRING;
+ case DBUS_TYPE_OBJECT_PATH:
+ return DBUS_TYPE_OBJECT_PATH_AS_STRING;
+ case DBUS_TYPE_ARRAY:
+ return DBUS_TYPE_ARRAY_AS_STRING;
+ default:
+ return NULL;
+ }
+}
+
+
+static dbus_bool_t _wpa_dbus_add_dict_entry_start(
+ DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
+ const char *key, const int value_type)
+{
+ if (!dbus_message_iter_open_container(iter_dict,
+ DBUS_TYPE_DICT_ENTRY, NULL,
+ iter_dict_entry))
+ return FALSE;
+
+ if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
+ &key))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static dbus_bool_t _wpa_dbus_add_dict_entry_end(
+ DBusMessageIter *iter_dict, DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val)
+{
+ if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
+ return FALSE;
+ if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static dbus_bool_t _wpa_dbus_add_dict_entry_basic(DBusMessageIter *iter_dict,
+ const char *key,
+ const int value_type,
+ const void *value)
+{
+ DBusMessageIter iter_dict_entry, iter_dict_val;
+ const char *type_as_string = NULL;
+
+ type_as_string = _wpa_get_type_as_string_from_type(value_type);
+ if (!type_as_string)
+ return FALSE;
+
+ if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
+ key, value_type))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(&iter_dict_entry,
+ DBUS_TYPE_VARIANT,
+ type_as_string, &iter_dict_val))
+ return FALSE;
+
+ if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
+ return FALSE;
+
+ if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+ &iter_dict_val))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static dbus_bool_t _wpa_dbus_add_dict_entry_byte_array(
+ DBusMessageIter *iter_dict, const char *key,
+ const char *value, const dbus_uint32_t value_len)
+{
+ DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+ dbus_uint32_t i;
+
+ if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
+ key, DBUS_TYPE_ARRAY))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(&iter_dict_entry,
+ DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_BYTE_AS_STRING,
+ &iter_dict_val))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ &iter_array))
+ return FALSE;
+
+ for (i = 0; i < value_len; i++) {
+ if (!dbus_message_iter_append_basic(&iter_array,
+ DBUS_TYPE_BYTE,
+ &(value[i])))
+ return FALSE;
+ }
+
+ if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
+ return FALSE;
+
+ if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+ &iter_dict_val))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/**
+ * Add a string entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The string value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
+ const char *key, const char *value)
+{
+ if (!key || !value)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_STRING,
+ &value);
+}
+
+
+/**
+ * Add a byte entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The byte value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
+ const char *key, const char value)
+{
+ if (!key)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_BYTE,
+ &value);
+}
+
+
+/**
+ * Add a boolean entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The boolean value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
+ const char *key, const dbus_bool_t value)
+{
+ if (!key)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
+ DBUS_TYPE_BOOLEAN, &value);
+}
+
+
+/**
+ * Add a 16-bit signed integer entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The 16-bit signed integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_int16_t value)
+{
+ if (!key)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT16,
+ &value);
+}
+
+
+/**
+ * Add a 16-bit unsigned integer entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The 16-bit unsigned integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_uint16_t value)
+{
+ if (!key)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT16,
+ &value);
+}
+
+
+/**
+ * Add a 32-bit signed integer to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The 32-bit signed integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_int32_t value)
+{
+ if (!key)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT32,
+ &value);
+}
+
+
+/**
+ * Add a 32-bit unsigned integer entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The 32-bit unsigned integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_uint32_t value)
+{
+ if (!key)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT32,
+ &value);
+}
+
+
+/**
+ * Add a 64-bit integer entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The 64-bit integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_int64_t value)
+{
+ if (!key)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_INT64,
+ &value);
+}
+
+
+/**
+ * Add a 64-bit unsigned integer entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The 64-bit unsigned integer value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_uint64_t value)
+{
+ if (!key)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_UINT64,
+ &value);
+}
+
+
+/**
+ * Add a double-precision floating point entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The double-precision floating point value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
+ const char * key,
+ const double value)
+{
+ if (!key)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key, DBUS_TYPE_DOUBLE,
+ &value);
+}
+
+
+/**
+ * Add a DBus object path entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The DBus object path value
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
+ const char *key,
+ const char *value)
+{
+ if (!key || !value)
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_basic(iter_dict, key,
+ DBUS_TYPE_OBJECT_PATH, &value);
+}
+
+
+/**
+ * Add a byte array entry to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param value The byte array
+ * @param value_len The length of the byte array, in bytes
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
+ const char *key,
+ const char *value,
+ const dbus_uint32_t value_len)
+{
+ if (!key)
+ return FALSE;
+ if (!value && (value_len != 0))
+ return FALSE;
+ return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
+ value_len);
+}
+
+
+/**
+ * Begin a string array entry in the dict
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link nmu_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param iter_dict_entry A private DBusMessageIter provided by the caller to
+ * be passed to {@link wpa_dbus_dict_end_string_array}
+ * @param iter_dict_val A private DBusMessageIter provided by the caller to
+ * be passed to {@link wpa_dbus_dict_end_string_array}
+ * @param iter_array On return, the DBusMessageIter to be passed to
+ * {@link wpa_dbus_dict_string_array_add_element}
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
+ const char *key,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array)
+{
+ if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
+ return FALSE;
+
+ if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
+ key, DBUS_TYPE_ARRAY))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(iter_dict_entry,
+ DBUS_TYPE_VARIANT,
+ DBUS_TYPE_ARRAY_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING,
+ iter_dict_val))
+ return FALSE;
+
+ if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
+ DBUS_TYPE_BYTE_AS_STRING,
+ iter_array))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/**
+ * Add a single string element to a string array dict entry
+ *
+ * @param iter_array A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_begin_string_array}'s
+ * iter_array parameter
+ * @param elem The string element to be added to the dict entry's string array
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
+ const char *elem)
+{
+ if (!iter_array || !elem)
+ return FALSE;
+
+ return dbus_message_iter_append_basic(iter_array, DBUS_TYPE_STRING,
+ &elem);
+}
+
+
+/**
+ * End a string array dict entry
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link nmu_dbus_dict_open_write}
+ * @param iter_dict_entry A private DBusMessageIter returned from
+ * {@link wpa_dbus_dict_end_string_array}
+ * @param iter_dict_val A private DBusMessageIter returned from
+ * {@link wpa_dbus_dict_end_string_array}
+ * @param iter_array A DBusMessageIter returned from
+ * {@link wpa_dbus_dict_end_string_array}
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array)
+{
+ if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
+ return FALSE;
+
+ if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
+ return FALSE;
+
+ if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
+ iter_dict_val))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/**
+ * Convenience function to add an entire string array to the dict.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link nmu_dbus_dict_open_write}
+ * @param key The key of the dict item
+ * @param items The array of strings
+ * @param num_items The number of strings in the array
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
+ const char *key,
+ const char **items,
+ const dbus_uint32_t num_items)
+{
+ DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
+ dbus_uint32_t i;
+
+ if (!key)
+ return FALSE;
+ if (!items && (num_items != 0))
+ return FALSE;
+
+ if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
+ &iter_dict_entry, &iter_dict_val,
+ &iter_array))
+ return FALSE;
+
+ for (i = 0; i < num_items; i++) {
+ if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+ items[i]))
+ return FALSE;
+ }
+
+ if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
+ &iter_dict_val, &iter_array))
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/*****************************************************/
+/* Stuff for reading dicts */
+/*****************************************************/
+
+/**
+ * Start reading from a dbus dict.
+ *
+ * @param iter A valid DBusMessageIter pointing to the start of the dict
+ * @param iter_dict (out) A DBusMessageIter to be passed to
+ * {@link wpa_dbus_dict_read_next_entry}
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
+ DBusMessageIter *iter_dict)
+{
+ if (!iter || !iter_dict)
+ return FALSE;
+
+ if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
+ dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY)
+ return FALSE;
+
+ dbus_message_iter_recurse(iter, iter_dict);
+ return TRUE;
+}
+
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_byte_array(
+ DBusMessageIter *iter, int array_len, int array_type,
+ struct wpa_dbus_dict_entry *entry)
+{
+ dbus_uint32_t i = 0;
+ dbus_bool_t success = FALSE;
+ char byte;
+
+ /* Zero-length arrays are valid. */
+ if (array_len == 0) {
+ entry->bytearray_value = NULL;
+ entry->array_type = DBUS_TYPE_BYTE;
+ success = TRUE;
+ goto done;
+ }
+
+ entry->bytearray_value = wpa_zalloc(array_len * sizeof(char));
+ if (!entry->bytearray_value) {
+ perror("_wpa_dbus_dict_entry_get_byte_array[dbus]: out of "
+ "memory");
+ goto done;
+ }
+
+ entry->array_type = DBUS_TYPE_BYTE;
+ entry->array_len = array_len;
+ while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
+ dbus_message_iter_get_basic(iter, &byte);
+ entry->bytearray_value[i++] = byte;
+ dbus_message_iter_next(iter);
+ }
+ success = TRUE;
+
+done:
+ return success;
+}
+
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_string_array(
+ DBusMessageIter *iter, int array_len, int array_type,
+ struct wpa_dbus_dict_entry *entry)
+{
+ dbus_uint32_t count = 0;
+ dbus_bool_t success = FALSE;
+ char **buffer;
+
+ entry->strarray_value = NULL;
+ entry->array_type = DBUS_TYPE_STRING;
+
+ /* Zero-length arrays are valid. */
+ if (array_len == 0) {
+ success = TRUE;
+ goto done;
+ }
+
+ buffer = wpa_zalloc(sizeof (char *) * 8);
+ if (buffer == NULL) {
+ perror("_wpa_dbus_dict_entry_get_string_array[dbus] out of "
+ "memory trying to retrieve a string array");
+ goto done;
+ }
+
+ entry->strarray_value = buffer;
+ entry->array_len = 0;
+ while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+ const char *value;
+ char *str;
+
+ if ((count % 8) == 0 && count != 0) {
+ char **tmp;
+ tmp = realloc(buffer, sizeof(char *) * (count + 8));
+ if (tmp == NULL) {
+ perror("_wpa_dbus_dict_entry_get_string_array["
+ "dbus] out of memory trying to "
+ "retrieve the string array");
+ free(buffer);
+ buffer = NULL;
+ goto done;
+ }
+ buffer = tmp;
+ }
+ entry->strarray_value = buffer;
+
+ dbus_message_iter_get_basic(iter, &value);
+ str = strdup(value);
+ if (str == NULL) {
+ perror("_wpa_dbus_dict_entry_get_string_array[dbus] "
+ "out of memory trying to duplicate the string "
+ "array");
+ goto done;
+ }
+ entry->strarray_value[count] = str;
+ entry->array_len = ++count;
+ dbus_message_iter_next(iter);
+ }
+ success = TRUE;
+
+done:
+ return success;
+}
+
+
+static dbus_bool_t _wpa_dbus_dict_entry_get_array(
+ DBusMessageIter *iter_dict_val, struct wpa_dbus_dict_entry *entry)
+{
+ int array_type = dbus_message_iter_get_element_type(iter_dict_val);
+ int array_len;
+ dbus_bool_t success = FALSE;
+ DBusMessageIter iter_array;
+
+ if (!entry)
+ return FALSE;
+
+ dbus_message_iter_recurse(iter_dict_val, &iter_array);
+
+ array_len = dbus_message_iter_get_array_len(&iter_array);
+ if (array_len < 0)
+ return FALSE;
+
+ switch (array_type) {
+ case DBUS_TYPE_BYTE:
+ success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
+ array_len,
+ array_type,
+ entry);
+ break;
+ case DBUS_TYPE_STRING:
+ success = _wpa_dbus_dict_entry_get_string_array(&iter_array,
+ array_len,
+ array_type,
+ entry);
+ break;
+ default:
+ break;
+ }
+
+ return success;
+}
+
+
+static dbus_bool_t _wpa_dbus_dict_fill_value_from_variant(
+ struct wpa_dbus_dict_entry *entry, DBusMessageIter *iter_dict_val)
+{
+ dbus_bool_t success = TRUE;
+
+ switch (entry->type) {
+ case DBUS_TYPE_STRING: {
+ const char *v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->str_value = strdup(v);
+ break;
+ }
+ case DBUS_TYPE_BOOLEAN: {
+ dbus_bool_t v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->bool_value = v;
+ break;
+ }
+ case DBUS_TYPE_BYTE: {
+ char v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->byte_value = v;
+ break;
+ }
+ case DBUS_TYPE_INT16: {
+ dbus_int16_t v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->int16_value = v;
+ break;
+ }
+ case DBUS_TYPE_UINT16: {
+ dbus_uint16_t v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->uint16_value = v;
+ break;
+ }
+ case DBUS_TYPE_INT32: {
+ dbus_int32_t v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->int32_value = v;
+ break;
+ }
+ case DBUS_TYPE_UINT32: {
+ dbus_uint32_t v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->uint32_value = v;
+ break;
+ }
+ case DBUS_TYPE_INT64: {
+ dbus_int64_t v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->int64_value = v;
+ break;
+ }
+ case DBUS_TYPE_UINT64: {
+ dbus_uint64_t v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->uint64_value = v;
+ break;
+ }
+ case DBUS_TYPE_DOUBLE: {
+ double v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->double_value = v;
+ break;
+ }
+ case DBUS_TYPE_OBJECT_PATH: {
+ char *v;
+ dbus_message_iter_get_basic(iter_dict_val, &v);
+ entry->str_value = strdup(v);
+ break;
+ }
+ case DBUS_TYPE_ARRAY: {
+ success = _wpa_dbus_dict_entry_get_array(iter_dict_val, entry);
+ break;
+ }
+ default:
+ success = FALSE;
+ break;
+ }
+
+ return success;
+}
+
+
+/**
+ * Read the current key/value entry from the dict. Entries are dynamically
+ * allocated when needed and must be freed after use with the
+ * {@link wpa_dbus_dict_entry_clear} function.
+ *
+ * The returned entry object will be filled with the type and value of the next
+ * entry in the dict, or the type will be DBUS_TYPE_INVALID if an error
+ * occurred.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_read}
+ * @param entry A valid dict entry object into which the dict key and value
+ * will be placed
+ * @return TRUE on success, FALSE on failure
+ *
+ */
+dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
+ struct wpa_dbus_dict_entry * entry)
+{
+ DBusMessageIter iter_dict_entry, iter_dict_val;
+ int type;
+ const char *key;
+
+ if (!iter_dict || !entry)
+ goto error;
+
+ if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
+ goto error;
+
+ dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
+ dbus_message_iter_get_basic(&iter_dict_entry, &key);
+ entry->key = key;
+
+ if (!dbus_message_iter_next(&iter_dict_entry))
+ goto error;
+ type = dbus_message_iter_get_arg_type(&iter_dict_entry);
+ if (type != DBUS_TYPE_VARIANT)
+ goto error;
+
+ dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
+ entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
+ if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
+ goto error;
+
+ dbus_message_iter_next(iter_dict);
+ return TRUE;
+
+error:
+ if (entry) {
+ wpa_dbus_dict_entry_clear(entry);
+ entry->type = DBUS_TYPE_INVALID;
+ entry->array_type = DBUS_TYPE_INVALID;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ * Return whether or not there are additional dictionary entries.
+ *
+ * @param iter_dict A valid DBusMessageIter returned from
+ * {@link wpa_dbus_dict_open_read}
+ * @return TRUE if more dict entries exists, FALSE if no more dict entries
+ * exist
+ */
+dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict)
+{
+ if (!iter_dict) {
+ perror("wpa_dbus_dict_has_dict_entry[dbus]: out of memory");
+ return FALSE;
+ }
+ return dbus_message_iter_get_arg_type(iter_dict) ==
+ DBUS_TYPE_DICT_ENTRY;
+}
+
+
+/**
+ * Free any memory used by the entry object.
+ *
+ * @param entry The entry object
+ */
+void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry)
+{
+ if (!entry)
+ return;
+ switch (entry->type) {
+ case DBUS_TYPE_OBJECT_PATH:
+ case DBUS_TYPE_STRING:
+ free(entry->str_value);
+ break;
+ case DBUS_TYPE_ARRAY:
+ switch (entry->array_type) {
+ case DBUS_TYPE_BYTE:
+ free(entry->bytearray_value);
+ break;
+ }
+ break;
+ }
+
+ memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
+}
diff --git a/contrib/wpa_supplicant/dbus_dict_helpers.h b/contrib/wpa_supplicant/dbus_dict_helpers.h
new file mode 100644
index 000000000000..f873efcbcb13
--- /dev/null
+++ b/contrib/wpa_supplicant/dbus_dict_helpers.h
@@ -0,0 +1,135 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ *
+ * 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.
+ */
+
+#ifndef DBUS_DICT_HELPERS_H
+#define DBUS_DICT_HELPERS_H
+
+/*
+ * Adding a dict to a DBusMessage
+ */
+
+dbus_bool_t wpa_dbus_dict_open_write(DBusMessageIter *iter,
+ DBusMessageIter *iter_dict);
+
+dbus_bool_t wpa_dbus_dict_close_write(DBusMessageIter *iter,
+ DBusMessageIter *iter_dict);
+
+dbus_bool_t wpa_dbus_dict_append_string(DBusMessageIter *iter_dict,
+ const char *key, const char *value);
+
+dbus_bool_t wpa_dbus_dict_append_byte(DBusMessageIter *iter_dict,
+ const char *key, const char value);
+
+dbus_bool_t wpa_dbus_dict_append_bool(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_bool_t value);
+
+dbus_bool_t wpa_dbus_dict_append_int16(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_int16_t value);
+
+dbus_bool_t wpa_dbus_dict_append_uint16(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_uint16_t value);
+
+dbus_bool_t wpa_dbus_dict_append_int32(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_int32_t value);
+
+dbus_bool_t wpa_dbus_dict_append_uint32(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_uint32_t value);
+
+dbus_bool_t wpa_dbus_dict_append_int64(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_int64_t value);
+
+dbus_bool_t wpa_dbus_dict_append_uint64(DBusMessageIter *iter_dict,
+ const char *key,
+ const dbus_uint64_t value);
+
+dbus_bool_t wpa_dbus_dict_append_double(DBusMessageIter *iter_dict,
+ const char *key,
+ const double value);
+
+dbus_bool_t wpa_dbus_dict_append_object_path(DBusMessageIter *iter_dict,
+ const char *key,
+ const char *value);
+
+dbus_bool_t wpa_dbus_dict_append_byte_array(DBusMessageIter *iter_dict,
+ const char *key,
+ const char *value,
+ const dbus_uint32_t value_len);
+
+/* Manual construction and addition of string array elements */
+dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
+ const char *key,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
+
+dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
+ const char *elem);
+
+dbus_bool_t wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
+ DBusMessageIter *iter_dict_entry,
+ DBusMessageIter *iter_dict_val,
+ DBusMessageIter *iter_array);
+
+/* Convenience function to add a whole string list */
+dbus_bool_t wpa_dbus_dict_append_string_array(DBusMessageIter *iter_dict,
+ const char *key,
+ const char **items,
+ const dbus_uint32_t num_items);
+
+/*
+ * Reading a dict from a DBusMessage
+ */
+
+struct wpa_dbus_dict_entry {
+ int type; /** the dbus type of the dict entry's value */
+ int array_type; /** the dbus type of the array elements if the dict
+ entry value contains an array */
+ const char *key; /** key of the dict entry */
+
+ /** Possible values of the property */
+ union {
+ char *str_value;
+ char byte_value;
+ dbus_bool_t bool_value;
+ dbus_int16_t int16_value;
+ dbus_uint16_t uint16_value;
+ dbus_int32_t int32_value;
+ dbus_uint32_t uint32_value;
+ dbus_int64_t int64_value;
+ dbus_uint64_t uint64_value;
+ double double_value;
+ char *bytearray_value;
+ char **strarray_value;
+ };
+ dbus_uint32_t array_len; /** length of the array if the dict entry's
+ value contains an array */
+};
+
+dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
+ DBusMessageIter *iter_dict);
+
+dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
+ struct wpa_dbus_dict_entry *entry);
+
+dbus_bool_t wpa_dbus_dict_has_dict_entry(DBusMessageIter *iter_dict);
+
+void wpa_dbus_dict_entry_clear(struct wpa_dbus_dict_entry *entry);
+
+#endif /* DBUS_DICT_HELPERS_H */
diff --git a/contrib/wpa_supplicant/defconfig b/contrib/wpa_supplicant/defconfig
index be013b48df10..d9526efd73f4 100644
--- a/contrib/wpa_supplicant/defconfig
+++ b/contrib/wpa_supplicant/defconfig
@@ -6,15 +6,20 @@
# just setting VARIABLE=n is not disabling that variable.
#
# This file is included in Makefile, so variables like CFLAGS and LIBS can also
-# be modified from here. In most cass, these lines should use += in order not
+# be modified from here. In most cases, these lines should use += in order not
# to override previous values of the variables.
-# Uncomment following two lines and fix the paths if you have installed openssl
-# in non-default location
+# Uncomment following two lines and fix the paths if you have installed OpenSSL
+# or GnuTLS in non-default location
#CFLAGS += -I/usr/local/openssl/include
#LIBS += -L/usr/local/openssl/lib
+# Some Red Hat versions seem to include kerberos header files from OpenSSL, but
+# the kerberos files are not in the default include path. Following line can be
+# used to fix build issues on such systems (krb5.h not found).
+#CFLAGS += -I/usr/include/kerberos
+
# Example configuration for various cross-compilation platforms
#### sveasoft (e.g., for Linksys WRT54G) ######################################
@@ -86,6 +91,11 @@ CONFIG_DRIVER_WEXT=y
#CFLAGS += -I/opt/mingw/mingw32/include/ddk
#LIBS += -L/opt/mingw/mingw32/lib
#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
# Driver interface for development testing
#CONFIG_DRIVER_TEST=y
@@ -97,10 +107,10 @@ CONFIG_DRIVER_WIRED=y
# included)
CONFIG_IEEE8021X_EAPOL=y
-# EAP-MD5 (automatically included if EAP-TTLS is enabled)
+# EAP-MD5
CONFIG_EAP_MD5=y
-# EAP-MSCHAPv2 (automatically included if EAP-PEAP is enabled)
+# EAP-MSCHAPv2
CONFIG_EAP_MSCHAPV2=y
# EAP-TLS
@@ -112,6 +122,13 @@ CONFIG_EAP_PEAP=y
# EAP-TTLS
CONFIG_EAP_TTLS=y
+# EAP-FAST
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
# EAP-GTC
CONFIG_EAP_GTC=y
@@ -133,6 +150,14 @@ CONFIG_EAP_LEAP=y
# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
#CONFIG_EAP_AKA=y
+# EAP-SAKE
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
@@ -148,11 +173,13 @@ CONFIG_SMARTCARD=y
# Development testing
#CONFIG_EAPOL_TEST=y
-# Replace native Linux implementation of packet sockets with libdnet/libpcap.
-# This will be automatically set for non-Linux OS.
-#CONFIG_DNET_PCAP=y
-
-# Include control interface for external programs, e.g, wpa_cli
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
CONFIG_CTRL_IFACE=y
# Include support for GNU Readline and History Libraries in wpa_cli.
@@ -171,6 +198,121 @@ CONFIG_CTRL_IFACE=y
# 35-50 kB in code size.
#CONFIG_NO_WPA=y
+# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
+# save about 1 kB in code size when building only WPA-Personal (no EAP support)
+# or 6 kB if building for WPA-Enterprise.
+#CONFIG_NO_WPA2=y
+
+# Remove AES extra functions. This can be used to reduce code size by about
+# 1.5 kB by removing extra AES modes that are not needed for commonly used
+# client configurations (they are needed for some EAP types).
+#CONFIG_NO_AES_EXTRAS=y
+
# Select configuration backend:
# file = text file (e.g., wpa_supplicant.conf)
+# winreg = Windows registry (see win_example.reg for an example)
CONFIG_BACKEND=file
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+# eloop_none = Empty template
+#CONFIG_ELOOP=eloop
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+#CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+#CONFIG_TLS=openssl
+
+# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
+# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
+# even though the core GnuTLS library is released under LGPL, this extra
+# library uses GPL and as such, the terms of GPL apply to the combination
+# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
+# apply for distribution of the resulting binary.
+#CONFIG_GNUTLS_EXTRA=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for DBus control interface
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# Include client MLME (management frame processing).
+# This can be used to move MLME processing of Devicescape IEEE 802.11 stack
+# into user space.
+#CONFIG_CLIENT_MLME=y
+# Currently, driver_devicescape.c build requires some additional parameters
+# to be able to include some of the kernel header files. Following lines can
+# be used to set these (WIRELESS_DEV must point to the root directory of the
+# wireless-dev.git tree).
+#WIRELESS_DEV=/usr/src/wireless-dev
+#CFLAGS += -I$(WIRELESS_DEV)/net/mac80211
diff --git a/contrib/wpa_supplicant/defs.h b/contrib/wpa_supplicant/defs.h
index 6f9881d71d03..603fc55c110a 100644
--- a/contrib/wpa_supplicant/defs.h
+++ b/contrib/wpa_supplicant/defs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Common definitions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -24,7 +24,8 @@
typedef enum { FALSE = 0, TRUE = 1 } Boolean;
-typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
+typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP,
+ WPA_ALG_IGTK, WPA_ALG_DHV } wpa_alg;
typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
CIPHER_WEP104 } wpa_cipher;
typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
@@ -128,4 +129,12 @@ typedef enum {
WPA_COMPLETED
} wpa_states;
+#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
+#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
+
+#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
+#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
+
#endif /* DEFS_H */
diff --git a/contrib/wpa_supplicant/des.c b/contrib/wpa_supplicant/des.c
new file mode 100644
index 000000000000..8e0d56fc6af1
--- /dev/null
+++ b/contrib/wpa_supplicant/des.c
@@ -0,0 +1,476 @@
+/*
+ * DES and 3DES-EDE ciphers
+ *
+ * Modifications to LibTomCrypt implementation:
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+
+#ifdef INTERNAL_DES
+
+/*
+ * This implementation is based on a DES implementation included in
+ * LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd
+ * coding style.
+ */
+
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
+ */
+
+/**
+ DES code submitted by Dobes Vandermeer
+*/
+
+#define ROLc(x, y) \
+ ((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \
+ (((unsigned long) (x) & 0xFFFFFFFFUL) >> \
+ (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) \
+ (((((unsigned long) (x) & 0xFFFFFFFFUL) >> \
+ (unsigned long) ((y) & 31)) | \
+ ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \
+ 0xFFFFFFFFUL)
+
+
+static const u32 bytebit[8] =
+{
+ 0200, 0100, 040, 020, 010, 04, 02, 01
+};
+
+static const u32 bigbyte[24] =
+{
+ 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL,
+ 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL,
+ 0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL,
+ 0x800UL, 0x400UL, 0x200UL, 0x100UL,
+ 0x80UL, 0x40UL, 0x20UL, 0x10UL,
+ 0x8UL, 0x4UL, 0x2UL, 0x1L
+};
+
+/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
+
+static const u8 pc1[56] = {
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
+};
+
+static const u8 totrot[16] = {
+ 1, 2, 4, 6,
+ 8, 10, 12, 14,
+ 15, 17, 19, 21,
+ 23, 25, 27, 28
+};
+
+static const u8 pc2[48] = {
+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
+};
+
+
+static const u32 SP1[64] =
+{
+ 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL,
+ 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL,
+ 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL,
+ 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL,
+ 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL,
+ 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL,
+ 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL,
+ 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL,
+ 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL,
+ 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL,
+ 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL,
+ 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL,
+ 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL,
+ 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL,
+ 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL,
+ 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL
+};
+
+static const u32 SP2[64] =
+{
+ 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL,
+ 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL,
+ 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL,
+ 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL,
+ 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL,
+ 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL,
+ 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL,
+ 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL,
+ 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL,
+ 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL,
+ 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL,
+ 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL,
+ 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL,
+ 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL,
+ 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL,
+ 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL
+};
+
+static const u32 SP3[64] =
+{
+ 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL,
+ 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL,
+ 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL,
+ 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL,
+ 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL,
+ 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL,
+ 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL,
+ 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL,
+ 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL,
+ 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL,
+ 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL,
+ 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL,
+ 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL,
+ 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL,
+ 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL,
+ 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL
+};
+
+static const u32 SP4[64] =
+{
+ 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+ 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL,
+ 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL,
+ 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL,
+ 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL,
+ 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL,
+ 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL,
+ 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL,
+ 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL,
+ 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL,
+ 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL,
+ 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+ 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL,
+ 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL,
+ 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL,
+ 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL
+};
+
+static const u32 SP5[64] =
+{
+ 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL,
+ 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL,
+ 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL,
+ 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL,
+ 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL,
+ 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL,
+ 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL,
+ 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL,
+ 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL,
+ 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL,
+ 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL,
+ 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL,
+ 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL,
+ 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL,
+ 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL,
+ 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL
+};
+
+static const u32 SP6[64] =
+{
+ 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL,
+ 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL,
+ 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL,
+ 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+ 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL,
+ 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL,
+ 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL,
+ 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL,
+ 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL,
+ 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL,
+ 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+ 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL,
+ 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL,
+ 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL,
+ 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL,
+ 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL
+};
+
+static const u32 SP7[64] =
+{
+ 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL,
+ 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL,
+ 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL,
+ 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL,
+ 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL,
+ 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL,
+ 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL,
+ 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL,
+ 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL,
+ 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL,
+ 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL,
+ 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL,
+ 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL,
+ 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL,
+ 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL,
+ 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL
+};
+
+static const u32 SP8[64] =
+{
+ 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL,
+ 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL,
+ 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL,
+ 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL,
+ 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL,
+ 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL,
+ 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL,
+ 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL,
+ 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL,
+ 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL,
+ 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL,
+ 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL,
+ 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL,
+ 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL,
+ 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL,
+ 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL
+};
+
+
+static void cookey(const u32 *raw1, u32 *keyout)
+{
+ u32 *cook;
+ const u32 *raw0;
+ u32 dough[32];
+ int i;
+
+ cook = dough;
+ for (i = 0; i < 16; i++, raw1++) {
+ raw0 = raw1++;
+ *cook = (*raw0 & 0x00fc0000L) << 6;
+ *cook |= (*raw0 & 0x00000fc0L) << 10;
+ *cook |= (*raw1 & 0x00fc0000L) >> 10;
+ *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+ *cook = (*raw0 & 0x0003f000L) << 12;
+ *cook |= (*raw0 & 0x0000003fL) << 16;
+ *cook |= (*raw1 & 0x0003f000L) >> 4;
+ *cook++ |= (*raw1 & 0x0000003fL);
+ }
+
+ os_memcpy(keyout, dough, sizeof(dough));
+}
+
+
+static void deskey(const u8 *key, int decrypt, u32 *keyout)
+{
+ u32 i, j, l, m, n, kn[32];
+ u8 pc1m[56], pcr[56];
+
+ for (j = 0; j < 56; j++) {
+ l = (u32) pc1[j];
+ m = l & 7;
+ pc1m[j] = (u8)
+ ((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0);
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (decrypt)
+ m = (15 - i) << 1;
+ else
+ m = i << 1;
+ n = m + 1;
+ kn[m] = kn[n] = 0L;
+ for (j = 0; j < 28; j++) {
+ l = j + (u32) totrot[i];
+ if (l < 28)
+ pcr[j] = pc1m[l];
+ else
+ pcr[j] = pc1m[l - 28];
+ }
+ for (/* j = 28 */; j < 56; j++) {
+ l = j + (u32) totrot[i];
+ if (l < 56)
+ pcr[j] = pc1m[l];
+ else
+ pcr[j] = pc1m[l - 28];
+ }
+ for (j = 0; j < 24; j++) {
+ if ((int) pcr[(int) pc2[j]] != 0)
+ kn[m] |= bigbyte[j];
+ if ((int) pcr[(int) pc2[j + 24]] != 0)
+ kn[n] |= bigbyte[j];
+ }
+ }
+
+ cookey(kn, keyout);
+}
+
+
+static void desfunc(u32 *block, const u32 *keys)
+{
+ u32 work, right, leftt;
+ int cur_round;
+
+ leftt = block[0];
+ right = block[1];
+
+ work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+ right ^= work;
+ leftt ^= (work << 4);
+
+ work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+ right ^= work;
+ leftt ^= (work << 16);
+
+ work = ((right >> 2) ^ leftt) & 0x33333333L;
+ leftt ^= work;
+ right ^= (work << 2);
+
+ work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+ leftt ^= work;
+ right ^= (work << 8);
+
+ right = ROLc(right, 1);
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+
+ leftt ^= work;
+ right ^= work;
+ leftt = ROLc(leftt, 1);
+
+ for (cur_round = 0; cur_round < 8; cur_round++) {
+ work = RORc(right, 4) ^ *keys++;
+ leftt ^= SP7[work & 0x3fL]
+ ^ SP5[(work >> 8) & 0x3fL]
+ ^ SP3[(work >> 16) & 0x3fL]
+ ^ SP1[(work >> 24) & 0x3fL];
+ work = right ^ *keys++;
+ leftt ^= SP8[ work & 0x3fL]
+ ^ SP6[(work >> 8) & 0x3fL]
+ ^ SP4[(work >> 16) & 0x3fL]
+ ^ SP2[(work >> 24) & 0x3fL];
+
+ work = RORc(leftt, 4) ^ *keys++;
+ right ^= SP7[ work & 0x3fL]
+ ^ SP5[(work >> 8) & 0x3fL]
+ ^ SP3[(work >> 16) & 0x3fL]
+ ^ SP1[(work >> 24) & 0x3fL];
+ work = leftt ^ *keys++;
+ right ^= SP8[ work & 0x3fL]
+ ^ SP6[(work >> 8) & 0x3fL]
+ ^ SP4[(work >> 16) & 0x3fL]
+ ^ SP2[(work >> 24) & 0x3fL];
+ }
+
+ right = RORc(right, 1);
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+ leftt ^= work;
+ right ^= work;
+ leftt = RORc(leftt, 1);
+ work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+ right ^= work;
+ leftt ^= (work << 8);
+ /* -- */
+ work = ((leftt >> 2) ^ right) & 0x33333333L;
+ right ^= work;
+ leftt ^= (work << 2);
+ work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+ leftt ^= work;
+ right ^= (work << 16);
+ work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+ leftt ^= work;
+ right ^= (work << 4);
+
+ block[0] = right;
+ block[1] = leftt;
+}
+
+
+/* wpa_supplicant/hostapd specific wrapper */
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ u8 pkey[8], next, tmp;
+ int i;
+ u32 ek[32], work[2];
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ deskey(pkey, 0, ek);
+
+ work[0] = WPA_GET_BE32(clear);
+ work[1] = WPA_GET_BE32(clear + 4);
+ desfunc(work, ek);
+ WPA_PUT_BE32(cypher, work[0]);
+ WPA_PUT_BE32(cypher + 4, work[1]);
+}
+
+
+struct des3_key_s {
+ u32 ek[3][32];
+ u32 dk[3][32];
+};
+
+void des3_key_setup(const u8 *key, struct des3_key_s *dkey)
+{
+ deskey(key, 0, dkey->ek[0]);
+ deskey(key + 8, 1, dkey->ek[1]);
+ deskey(key + 16, 0, dkey->ek[2]);
+
+ deskey(key, 1, dkey->dk[2]);
+ deskey(key + 8, 0, dkey->dk[1]);
+ deskey(key + 16, 1, dkey->dk[0]);
+}
+
+
+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt)
+{
+ u32 work[2];
+
+ work[0] = WPA_GET_BE32(plain);
+ work[1] = WPA_GET_BE32(plain + 4);
+ desfunc(work, key->ek[0]);
+ desfunc(work, key->ek[1]);
+ desfunc(work, key->ek[2]);
+ WPA_PUT_BE32(crypt, work[0]);
+ WPA_PUT_BE32(crypt + 4, work[1]);
+}
+
+
+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain)
+{
+ u32 work[2];
+
+ work[0] = WPA_GET_BE32(crypt);
+ work[1] = WPA_GET_BE32(crypt + 4);
+ desfunc(work, key->dk[0]);
+ desfunc(work, key->dk[1]);
+ desfunc(work, key->dk[2]);
+ WPA_PUT_BE32(plain, work[0]);
+ WPA_PUT_BE32(plain + 4, work[1]);
+}
+
+#endif /* INTERNAL_DES */
diff --git a/contrib/wpa_supplicant/doc/code_structure.doxygen b/contrib/wpa_supplicant/doc/code_structure.doxygen
index 6a32e590e223..23b7f22a05bc 100644
--- a/contrib/wpa_supplicant/doc/code_structure.doxygen
+++ b/contrib/wpa_supplicant/doc/code_structure.doxygen
@@ -219,6 +219,12 @@ eap_pax.c, eap_pax_common.h, eap_pax_common.c
eap_psk.c, eap_psk_common.h, eap_psk_common.c
EAP-PSK (note: this is not needed for WPA-PSK)
+eap_sake.c, eap_sake_common.h, eap_sake_common.c
+ EAP-SAKE
+
+eap_gpsk.c, eap_gpsk_common.h, eap_gpsk_common.c
+ EAP-GPSK
+
eap_aka.c, eap_fast.c, eap_gtc.c, eap_leap.c, eap_md5.c, eap_mschapv2.c,
eap_otp.c, eap_peap.c, eap_sim.c, eap_tls.c
Other EAP method implementations
diff --git a/contrib/wpa_supplicant/doc/ctrl_iface.doxygen b/contrib/wpa_supplicant/doc/ctrl_iface.doxygen
index fd1b9c406bab..f9e7d0e73b44 100644
--- a/contrib/wpa_supplicant/doc/ctrl_iface.doxygen
+++ b/contrib/wpa_supplicant/doc/ctrl_iface.doxygen
@@ -138,6 +138,7 @@ Same as STATUS, but with more verbosity (i.e., more \c variable=value pairs).
\verbatim
bssid=02:00:01:02:03:04
ssid=test network
+id=0
pairwise_cipher=CCMP
group_cipher=CCMP
key_mgmt=WPA-PSK
@@ -368,11 +369,15 @@ CTRL-RSP-PASSWORD-1-secret
\endverbatim
-\subsection ctrl_iface_GET_CAPABILITY GET_CAPABILITY <option>
+\subsection ctrl_iface_GET_CAPABILITY GET_CAPABILITY <option> [strict]
Get list of supported functionality (eap, pairwise, group,
proto). Supported functionality is shown as space separate lists of
values used in the same format as in %wpa_supplicant configuration.
+If optional argument, 'strict', is added, only the values that the
+driver claims to explicitly support are included. Without this, all
+available capabilities are included if the driver does not provide
+a mechanism for querying capabilities.
Example request/reply pairs:
@@ -387,6 +392,10 @@ CCMP TKIP NONE
\endverbatim
\verbatim
+GET_CAPABILITY pairwise strict
+\endverbatim
+
+\verbatim
GET_CAPABILITY group
CCMP TKIP WEP104 WEP40
\endverbatim
@@ -406,4 +415,23 @@ GET_CAPABILITY auth_alg
OPEN SHARED LEAP
\endverbatim
+
+\subsection ctrl_iface_AP_SCAN AP_SCAN <ap_scan value>
+
+Change ap_scan value:
+0 = no scanning,
+1 = %wpa_supplicant requests scans and uses scan results to select the AP,
+2 = %wpa_supplicant does not use scanning and just requests driver to
+associate and take care of AP selection
+
+
+\subsection ctrl_iface_INTERFACES INTERFACES
+
+List configured interfaces.
+
+\verbatim
+wlan0
+eth0
+\endverbatim
+
*/
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_background.8 b/contrib/wpa_supplicant/doc/docbook/wpa_background.8
index 3a7be2817c26..7f9d637ba771 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_background.8
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_background.8
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_BACKGROUND" "8" "08 February 2006" "" ""
+.TH "WPA_BACKGROUND" "8" "28 May 2007" "" ""
.SH NAME
wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i
@@ -76,7 +76,7 @@ pre-authentication, and PMKSA caching).
.SH "LEGAL"
.PP
wpa_supplicant is copyright (c) 2003-2005,
-Jouni Malinen <jkmaline@cc.hut.fi> and
+Jouni Malinen <j@w1.fi> and
contributors.
All Rights Reserved.
.PP
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_background.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_background.sgml
index dc6436025393..91b08bc42d0d 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_background.sgml
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -91,7 +91,7 @@
<refsect1>
<title>Legal</title>
<para>wpa_supplicant is copyright (c) 2003-2005,
- Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
+ Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_cli.8 b/contrib/wpa_supplicant/doc/docbook/wpa_cli.8
index ad039b548b31..6d32260e17ba 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_cli.8
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_cli.8
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_CLI" "8" "08 February 2006" "" ""
+.TH "WPA_CLI" "8" "28 May 2007" "" ""
.SH NAME
wpa_cli \- WPA command line client
@@ -113,7 +113,14 @@ Run in daemon mode executing the action file
based on events from wpa_supplicant. The specified file will
be executed with the first argument set to interface name and
second to "CONNECT" or "DISCONNECT" depending on the event.
-This can be used
+This can be used to execute networking tools required to configure
+the interface.
+
+Additionally, three environmental variables are available to
+the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR
+contains the absolute path to the ctrl_interface socket. WPA_ID
+contains the unique network_id identifier assigned to the active
+network, and WPA_ID_STR contains the content of the id_str option.
.TP
\fB-P file\fR
Set the location of the PID
@@ -177,7 +184,7 @@ configure pin for an SSID
\fBotp <network id> <password>\fR
configure one-time-password for an SSID
.TP
-\fBbssid *lt;network id> <BSSID>\fR
+\fBbssid <network id> <BSSID>\fR
set preferred BSSID for an SSID
.TP
\fBlist_networks\fR
@@ -194,7 +201,7 @@ exit wpa_cli
.SH "LEGAL"
.PP
wpa_supplicant is copyright (c) 2003-2005,
-Jouni Malinen <jkmaline@cc.hut.fi> and
+Jouni Malinen <j@w1.fi> and
contributors.
All Rights Reserved.
.PP
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml
index e8042397a7d7..140c365b9242 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -141,7 +141,15 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
based on events from wpa_supplicant. The specified file will
be executed with the first argument set to interface name and
second to "CONNECT" or "DISCONNECT" depending on the event.
- This can be used </para></listitem>
+ This can be used to execute networking tools required to configure
+ the interface.</para>
+
+ <para>Additionally, three environmental variables are available to
+ the file: WPA_CTRL_DIR, WPA_ID, and WPA_ID_STR. WPA_CTRL_DIR
+ contains the absolute path to the ctrl_interface socket. WPA_ID
+ contains the unique network_id identifier assigned to the active
+ network, and WPA_ID_STR contains the content of the id_str option.
+ </para></listitem>
</varlistentry>
<varlistentry>
@@ -282,7 +290,7 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
</varlistentry>
<varlistentry>
- <term>bssid *lt;network id&gt; &lt;BSSID&gt;</term>
+ <term>bssid &lt;network id&gt; &lt;BSSID&gt;</term>
<listitem>
<para>set preferred BSSID for an SSID</para>
</listitem>
@@ -320,7 +328,7 @@ CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
<refsect1>
<title>Legal</title>
<para>wpa_supplicant is copyright (c) 2003-2005,
- Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
+ Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8 b/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8
index 11e0f85bb863..c883777fc486 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8
@@ -3,10 +3,10 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_PASSPHRASE" "8" "08 February 2006" "" ""
+.TH "WPA_PASSPHRASE" "8" "28 May 2007" "" ""
.SH NAME
-wpa_passphrase \- Set WPA passphrase for a SSID
+wpa_passphrase \- Generate a WPA PSK from an ASCII passphrase for a SSID
.SH SYNOPSIS
\fBwpa_passphrase\fR [ \fB\fIssid\fB\fR ] [ \fB\fIpassphrase\fB\fR ]
@@ -15,7 +15,8 @@ wpa_passphrase \- Set WPA passphrase for a SSID
.PP
\fBwpa_passphrase\fR pre-computes PSK entries for
network configuration blocks of a
-\fIwpa_supplicant.conf\fR file.
+\fIwpa_supplicant.conf\fR file. An ASCII passphrase
+and SSID are used to generate a 256-bit PSK.
.SH "OPTIONS"
.TP
\fBssid\fR
@@ -31,7 +32,7 @@ passphrase will be read from standard input.
.SH "LEGAL"
.PP
wpa_supplicant is copyright (c) 2003-2005,
-Jouni Malinen <jkmaline@cc.hut.fi> and
+Jouni Malinen <j@w1.fi> and
contributors.
All Rights Reserved.
.PP
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
index 1380a74d910e..eacb119ee382 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -7,7 +7,7 @@
</refmeta>
<refnamediv>
<refname>wpa_passphrase</refname>
- <refpurpose>Set WPA passphrase for a SSID</refpurpose>
+ <refpurpose>Generate a WPA PSK from an ASCII passphrase for a SSID</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
@@ -22,7 +22,8 @@
<para><command>wpa_passphrase</command> pre-computes PSK entries for
network configuration blocks of a
- <filename>wpa_supplicant.conf</filename> file.</para>
+ <filename>wpa_supplicant.conf</filename> file. An ASCII passphrase
+ and SSID are used to generate a 256-bit PSK.</para>
</refsect1>
<refsect1>
@@ -62,7 +63,7 @@
<refsect1>
<title>Legal</title>
<para>wpa_supplicant is copyright (c) 2003-2005,
- Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
+ Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8 b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8
index fcd738b9203c..502000d3754c 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8
@@ -3,13 +3,13 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_SUPPLICANT" "8" "08 February 2006" "" ""
+.TH "WPA_SUPPLICANT" "8" "28 May 2007" "" ""
.SH NAME
wpa_supplicant \- Wi-Fi Protected Access client and IEEE 802.1X supplicant
.SH SYNOPSIS
-\fBwpa_supplicant\fR [ \fB-BddehLqqvw\fR ] [ \fB-i\fIifname\fB\fR ] [ \fB-c\fIconfig file\fB\fR ] [ \fB-D\fIdriver\fB\fR ]
+\fBwpa_supplicant\fR [ \fB-BddehLqqvw\fR ] [ \fB-i\fIifname\fB\fR ] [ \fB-c\fIconfig file\fB\fR ] [ \fB-D\fIdriver\fB\fR ] [ \fB-P\fIPID_file\fB\fR ]
.SH "OVERVIEW"
.PP
@@ -260,6 +260,15 @@ Interface to listen on.
\fB-c filename\fR
Path to configuration file.
.TP
+\fB-P PID_file\fR
+Path to PID file.
+.TP
+\fB-C ctrl_interface\fR
+Path to ctrl_interface socket (only used if -c is not).
+.TP
+\fB-g global ctrl_interface\fR
+Path to global ctrl_interface socket.
+.TP
\fB-D driver\fR
Driver to use. See the available options below.
.TP
@@ -454,7 +463,7 @@ encrypted passwords.
.PP
First, make a configuration file, e.g.
\fI/etc/wpa_supplicant.conf\fR, that describes the networks
-you are interested in. See \fBwpa_supplicant\fR(5)
+you are interested in. See \fBwpa_supplicant.conf\fR(5)
for details.
.PP
Once the configuration is ready, you can test whether the
@@ -536,7 +545,7 @@ the AP.
.SH "LEGAL"
.PP
wpa_supplicant is copyright (c) 2003-2005,
-Jouni Malinen <jkmaline@cc.hut.fi> and
+Jouni Malinen <j@w1.fi> and
contributors.
All Rights Reserved.
.PP
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
index d5e5c62b6489..c7e4c6fa744c 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_SUPPLICANT.CONF" "5" "08 February 2006" "" ""
+.TH "WPA_SUPPLICANT.CONF" "5" "28 May 2007" "" ""
.SH NAME
wpa_supplicant.conf \- configuration file for wpa_supplicant
@@ -24,13 +24,13 @@ run in the background.
Changes to configuration file can be reloaded be sending
SIGHUP signal to \fBwpa_supplicant\fR ('killall -HUP
wpa_supplicant'). Similarly, reloading can be triggered with
-'wpa_cli reconfigure' command.
+the 'wpa_cli reconfigure' command.
.PP
Configuration file can include one or more network blocks,
e.g., one for each used SSID. wpa_supplicant will automatically
-select the best betwork based on the order of network blocks in
+select the best network based on the order of network blocks in
the configuration file, network security level (WPA/WPA2 is
-prefered), and signal strength.
+preferred), and signal strength.
.SH "QUICK EXAMPLES"
.TP 3
1.
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
index dbd9e37f552f..082509cc77aa 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
@@ -26,13 +26,13 @@
<para>Changes to configuration file can be reloaded be sending
SIGHUP signal to <command>wpa_supplicant</command> ('killall -HUP
wpa_supplicant'). Similarly, reloading can be triggered with
- 'wpa_cli reconfigure' command.</para>
+ the 'wpa_cli reconfigure' command.</para>
<para>Configuration file can include one or more network blocks,
e.g., one for each used SSID. wpa_supplicant will automatically
- select the best betwork based on the order of network blocks in
+ select the best network based on the order of network blocks in
the configuration file, network security level (WPA/WPA2 is
- prefered), and signal strength.</para>
+ preferred), and signal strength.</para>
</refsect1>
<refsect1>
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index cb35abf31e47..d19e5463a930 100644
--- a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -16,6 +16,7 @@
<arg>-i<replaceable>ifname</replaceable></arg>
<arg>-c<replaceable>config file</replaceable></arg>
<arg>-D<replaceable>driver</replaceable></arg>
+ <arg>-P<replaceable>PID_file</replaceable></arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -347,6 +348,27 @@
</varlistentry>
<varlistentry>
+ <term>-P PID_file</term>
+ <listitem>
+ <para>Path to PID file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-C ctrl_interface</term>
+ <listitem>
+ <para>Path to ctrl_interface socket (only used if -c is not).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-g global ctrl_interface</term>
+ <listitem>
+ <para>Path to global ctrl_interface socket.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>-D driver</term>
<listitem>
<para>Driver to use. See the available options below.</para>
@@ -657,7 +679,7 @@ wpa_supplicant \
<para>First, make a configuration file, e.g.
<filename>/etc/wpa_supplicant.conf</filename>, that describes the networks
you are interested in. See <citerefentry>
- <refentrytitle>wpa_supplicant</refentrytitle>
+ <refentrytitle>wpa_supplicant.conf</refentrytitle>
<manvolnum>5</manvolnum>
</citerefentry>
for details.</para>
@@ -751,7 +773,7 @@ fi
<refsect1>
<title>Legal</title>
<para>wpa_supplicant is copyright (c) 2003-2005,
- Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
+ Jouni Malinen <email>j@w1.fi</email> and
contributors.
All Rights Reserved.</para>
diff --git a/contrib/wpa_supplicant/doc/doxygen.fast b/contrib/wpa_supplicant/doc/doxygen.fast
index 2eb9d27c386b..597fd372c60c 100644
--- a/contrib/wpa_supplicant/doc/doxygen.fast
+++ b/contrib/wpa_supplicant/doc/doxygen.fast
@@ -4,7 +4,7 @@
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = wpa_supplicant
-PROJECT_NUMBER = 0.4.x
+PROJECT_NUMBER = 0.5.x
OUTPUT_DIRECTORY = doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
diff --git a/contrib/wpa_supplicant/doc/doxygen.full b/contrib/wpa_supplicant/doc/doxygen.full
index 69cec656f7f0..9ed2ef845afb 100644
--- a/contrib/wpa_supplicant/doc/doxygen.full
+++ b/contrib/wpa_supplicant/doc/doxygen.full
@@ -4,7 +4,7 @@
# Project related configuration options
#---------------------------------------------------------------------------
PROJECT_NAME = wpa_supplicant
-PROJECT_NUMBER = 0.4.x
+PROJECT_NUMBER = 0.5.x
OUTPUT_DIRECTORY = doc
CREATE_SUBDIRS = NO
OUTPUT_LANGUAGE = English
@@ -187,7 +187,7 @@ EXPAND_ONLY_PREDEF = NO
SEARCH_INCLUDES = YES
INCLUDE_PATH =
INCLUDE_FILE_PATTERNS =
-PREDEFINED = IEEE8021X_EAPOL
+PREDEFINED = IEEE8021X_EAPOL CONFIG_CTRL_IFACE
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
diff --git a/contrib/wpa_supplicant/doc/eap.doxygen b/contrib/wpa_supplicant/doc/eap.doxygen
index e1ae9c047cf2..988b304c62cf 100644
--- a/contrib/wpa_supplicant/doc/eap.doxygen
+++ b/contrib/wpa_supplicant/doc/eap.doxygen
@@ -1,9 +1,10 @@
/**
\page eap_module EAP peer implementation
-%wpa_supplicant uses a separate code module for EAP peer
-implementation. This module was designed to use only a minimal set of
-direct function calls (mainly, to debug/event functions) in order for
+Extensible Authentication Protocol (EAP) is an authentication framework
+defined in RFC 3748. %wpa_supplicant uses a separate code module for EAP
+peer implementation. This module was designed to use only a minimal set
+of direct function calls (mainly, to debug/event functions) in order for
it to be usable in other programs. The design of the EAP
implementation is based loosely on RFC 4137. The state machine is
defined in this RFC and so is the interface between the peer state
@@ -25,8 +26,9 @@ methods use the same interface between the peer state machine and
method specific functions. This allows new EAP methods to be added
without modifying the core EAP state machine implementation.
-New EAP methods need to be registered by adding them into build
-(Makefile) and EAP method table in the beginning of eap.c. Each EAP
+New EAP methods need to be registered by adding them into the build
+(Makefile) and the EAP method registration list in the
+eap_peer_register_methods() function of eap_methods.c. Each EAP
method should use a build-time configuration option, e.g., EAP_TLS, in
order to make it possible to select which of the methods are included
in the build.
@@ -35,4 +37,20 @@ EAP methods must implement the interface defined in eap_i.h. struct
eap_method defines the needed function pointers that each EAP method
must provide. In addition, the EAP type and name are registered using
this structure. This interface is based on section 4.4 of RFC 4137.
+
+It is recommended that the EAP methods would use generic helper
+functions, eap_msg_alloc() and eap_hdr_validate() when processing
+messages. This allows code sharing and can avoid missing some of the
+needed validation steps for received packets. In addition, these
+functions make it easier to change between expanded and legacy EAP
+header, if needed.
+
+When adding an EAP method that uses a vendor specific EAP type
+(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
+must be registered by passing vendor id instead of EAP_VENDOR_IETF to
+eap_peer_method_alloc(). These methods must not try to emulate
+expanded types by registering a legacy EAP method for type 254. See
+eap_vendor_test.c for an example of an EAP method implementation that
+is implemented as an expanded type.
+
*/
diff --git a/contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl b/contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl
index d46f7bd07868..68835a1ddd31 100755
--- a/contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl
+++ b/contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl
@@ -20,7 +20,7 @@
#
##########################################################################
# Copyright (C) 2003 Jonathan Foster <jon@jon-foster.co.uk>
-# Copyright (C) 2005 Jouni Malinen <jkmaline@cc.hut.fi>
+# Copyright (C) 2005 Jouni Malinen <j@w1.fi>
# (modified for kerneldoc format used in wpa_supplicant)
#
# This program is free software; you can redistribute it and/or modify
@@ -34,7 +34,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# or look at http://www.gnu.org/licenses/gpl.html
##########################################################################
diff --git a/contrib/wpa_supplicant/doc/mainpage.doxygen b/contrib/wpa_supplicant/doc/mainpage.doxygen
index 56882f44fe1d..6e58af8738e0 100644
--- a/contrib/wpa_supplicant/doc/mainpage.doxygen
+++ b/contrib/wpa_supplicant/doc/mainpage.doxygen
@@ -13,7 +13,7 @@ give enough information for other developers to understand how
%wpa_supplicant has been implemented, how it can be modified, how new
drivers can be supported, and how %wpa_supplicant can be ported to
other operating systems. If any information is missing, feel free to
-contact Jouni Malinen <jkmaline@cc.hut.fi> for more
+contact Jouni Malinen <j@w1.fi> for more
information. Contributions as patch files are also very welcome at the
same address. Please note that %wpa_supplicant is licensed under dual
license, GPLv2 or BSD at user's choice. All contributions to
diff --git a/contrib/wpa_supplicant/doc/porting.doxygen b/contrib/wpa_supplicant/doc/porting.doxygen
index db64a11b536e..581da487e20f 100644
--- a/contrib/wpa_supplicant/doc/porting.doxygen
+++ b/contrib/wpa_supplicant/doc/porting.doxygen
@@ -5,14 +5,62 @@
hardware (board, CPU) and software (OS, drivers) targets. It is
already used with number of operating systems and numerous wireless
card models and drivers. The main %wpa_supplicant repository includes
-support for Linux, FreeBSD, and Windows. In addition, at least VxWorks
-and PalmOS are supported in separate repositories. On the hardware
+support for Linux, FreeBSD, and Windows. In addition, at least VxWorks,
+PalmOS, Windows CE, and Windows Mobile are supported in separate
+repositories. On the hardware
side, %wpa_supplicant is used on various systems: desktops, laptops,
PDAs, and embedded devices with CPUs including x86, PowerPC,
arm/xscale, and MIPS. Both big and little endian configurations are
supported.
+\section ansi_c_extra Extra functions on top of ANSI C
+
+%wpa_supplicant is mostly using ANSI C functions that are available on
+most targets. However, couple of additional functions that are common
+on modern UNIX systems are used. Number of these are listed with
+prototypes in common.h (the #ifdef CONFIG_ANSI_C_EXTRA block). These
+functions may need to be implemented or at least defined as macros to
+native functions in the target OS or C library.
+
+Many of the common ANSI C functions are used through a wrapper
+definitions in os.h to allow these to be replaced easily with a
+platform specific version in case standard C libraries are not
+available. In addition, os.h defines couple of common platform
+specific functions that are implemented in os_unix.c for UNIX like
+targets and in os_win32.c for Win32 API. If the target platform does
+not support either of these examples, a new os_*.c file may need to be
+added.
+
+Unless OS_NO_C_LIB_DEFINES is defined, the standard ANSI C and POSIX
+functions are used by defining the os_*() wrappers to use them
+directly in order to avoid extra cost in size and speed. If the target
+platform needs different versions of the functions, os.h can be
+modified to define the suitable macros or alternatively,
+OS_NO_C_LIB_DEFINES may be defined for the build and the wrapper
+functions can then be implemented in a new os_*.c wrapper file.
+
+common.h defines number of helper macros for handling integers of
+different size and byte order. Suitable version of these definitions
+may need to be added for the target platform.
+
+
+\section configuration_backend Configuration backend
+
+%wpa_supplicant implements a configuration interface that allows the
+backend to be easily replaced in order to read configuration data from
+a suitable source depending on the target platform. config.c
+implements the generic code that can be shared with all configuration
+backends. Each backend is implemented in its own config_*.c file.
+
+The included config_file.c backend uses a text file for configuration
+and config_winreg.c uses Windows registry. These files can be used as
+an example for a new configuration backend if the target platform uses
+different mechanism for configuration parameters. In addition,
+config_none.c can be used as an empty starting point for building a
+new configuration backend.
+
+
\section driver_iface_porting Driver interface
Unless the target OS and driver is already supported, most porting
@@ -118,4 +166,43 @@ also possible to do this when a network interface is being
enabled/disabled if it is desirable that %wpa_supplicant processing
for the interface is fully enabled/disabled at the same time.
+
+\section simple_build Simple build example
+
+One way to start a porting project is to begin with a very simple
+build of %wpa_supplicant with WPA-PSK support and once that is
+building correctly, start adding features.
+
+Following command can be used to build very simple version of
+%wpa_supplicant:
+
+\verbatim
+cc -o wpa_supplicant config.c eloop.c common.c md5.c rc4.c sha1.c \
+ config_none.c l2_packet_none.c tls_none.c wpa.c preauth.c \
+ aes_wrap.c wpa_supplicant.c events.c main_none.c drivers.c
+\endverbatim
+
+The end result is not really very useful since it uses empty functions
+for configuration parsing and layer 2 packet access and does not
+include a driver interface. However, this is a good starting point
+since the build is complete in the sense that all functions are
+present and this is easy to configure to a build system by just
+including the listed C files.
+
+Once this version can be build successfully, the end result can be
+made functional by adding a proper program entry point (main*.c),
+driver interface (driver_*.c and matching CONFIG_DRIVER_* define for
+registration in drivers.c), configuration parser/writer (config_*.c),
+and layer 2 packet access implementation (l2_packet_*.c). After these
+components have been added, the end result should be a working
+WPA/WPA2-PSK enabled supplicant.
+
+After the basic functionality has been verified to work, more features
+can be added by linking in more files and defining C pre-processor
+defines. Currently, the best source of information for what options
+are available and which files needs to be included is in the Makefile
+used for building the supplicant with make. Similar configuration will
+be needed for build systems that either use different type of make
+tool or a GUI-based project configuration.
+
*/
diff --git a/contrib/wpa_supplicant/doc/testing_tools.doxygen b/contrib/wpa_supplicant/doc/testing_tools.doxygen
index c1e24082a0f8..a2ae0c250fdd 100644
--- a/contrib/wpa_supplicant/doc/testing_tools.doxygen
+++ b/contrib/wpa_supplicant/doc/testing_tools.doxygen
@@ -47,7 +47,9 @@ The resulting eapol_test binary has following command like options:
\verbatim
usage:
-eapol_test [-nW] -c<conf> [-a<AS IP>] [-p<AS port>] [-s<AS secret>] [-r<count>]
+eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] [-s<AS secret>] \
+ [-r<count>] [-t<timeout>] [-C<Connect-Info>] \
+ [-M<client MAC address>]
eapol_test scard
eapol_test sim <PIN> <num triplets> [debug]
@@ -58,7 +60,12 @@ options:
-s<AS secret> = shared secret with the authentication server, default 'radius'
-r<count> = number of re-authentications
-W = wait for a control interface monitor before starting
+ -S = save configuration after authentiation
-n = no MPPE keys expected
+ -t<timeout> = sets timeout in seconds (default: 30 s)
+ -C<Connect-Info> = RADIUS Connect-Info (default: CONNECT 11Mbps 802.11b)
+ -M<client MAC address> = Set own MAC address (Calling-Station-Id,
+ default: 02:00:00:00:00:01)
\endverbatim
diff --git a/contrib/wpa_supplicant/driver.h b/contrib/wpa_supplicant/driver.h
index 9864e9b8ae3c..ba5c5e6e375e 100644
--- a/contrib/wpa_supplicant/driver.h
+++ b/contrib/wpa_supplicant/driver.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - driver interface definition
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -128,6 +128,30 @@ struct wpa_driver_associate_params {
* mode - Operation mode (infra/ibss) IEEE80211_MODE_*
*/
int mode;
+
+ /**
+ * wep_key - WEP keys for static WEP configuration
+ */
+ const u8 *wep_key[4];
+
+ /**
+ * wep_key_len - WEP key length for static WEP configuration
+ */
+ size_t wep_key_len[4];
+
+ /**
+ * wep_tx_keyidx - WEP TX key index for static WEP configuration
+ */
+ int wep_tx_keyidx;
+
+ /**
+ * mgmt_frame_protection - IEEE 802.11w management frame protection
+ */
+ enum {
+ NO_MGMT_FRAME_PROTECTION,
+ MGMT_FRAME_PROTECTION_OPTIONAL,
+ MGMT_FRAME_PROTECTION_REQUIRED
+ } mgmt_frame_protection;
};
/**
@@ -155,10 +179,56 @@ struct wpa_driver_capa {
/* Driver generated WPA/RSN IE */
#define WPA_DRIVER_FLAGS_DRIVER_IE 0x00000001
#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
+#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004
unsigned int flags;
};
+#define WPA_CHAN_W_SCAN 0x00000001
+#define WPA_CHAN_W_ACTIVE_SCAN 0x00000002
+#define WPA_CHAN_W_IBSS 0x00000004
+
+struct wpa_channel_data {
+ short chan; /* channel number (IEEE 802.11) */
+ short freq; /* frequency in MHz */
+ int flag; /* flag for user space use (WPA_CHAN_*) */
+};
+
+#define WPA_RATE_ERP 0x00000001
+#define WPA_RATE_BASIC 0x00000002
+#define WPA_RATE_PREAMBLE2 0x00000004
+#define WPA_RATE_SUPPORTED 0x00000010
+#define WPA_RATE_OFDM 0x00000020
+#define WPA_RATE_CCK 0x00000040
+#define WPA_RATE_MANDATORY 0x00000100
+
+struct wpa_rate_data {
+ int rate; /* rate in 100 kbps */
+ int flags; /* WPA_RATE_ flags */
+};
+
+typedef enum {
+ WPA_MODE_IEEE80211B,
+ WPA_MODE_IEEE80211G,
+ WPA_MODE_IEEE80211A,
+ NUM_WPA_MODES
+} wpa_hw_mode;
+
+struct wpa_hw_modes {
+ wpa_hw_mode mode;
+ int num_channels;
+ struct wpa_channel_data *channels;
+ int num_rates;
+ struct wpa_rate_data *rates;
+};
+
+
+struct ieee80211_rx_status {
+ int channel;
+ int ssi;
+};
+
+
/**
* struct wpa_driver_ops - Driver interface API definition
*
@@ -230,10 +300,12 @@ struct wpa_driver_ops {
* set_key - Configure encryption key
* @priv: private driver interface data
* @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
+ * %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_DHV);
+ * %WPA_ALG_NONE clears the key.
* @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
* broadcast/default keys
- * @key_idx: key index (0..3), usually 0 for unicast keys
+ * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
+ * IGTK
* @set_tx: configure this key as the default Tx key (only used when
* driver does not support separate unicast/individual key
* @seq: sequence number/packet number, seq_len octets, the next
@@ -241,11 +313,11 @@ struct wpa_driver_ops {
* for Rx keys (in most cases, this is only used with broadcast
* keys and set to zero for unicast keys)
* @seq_len: length of the seq, depends on the algorithm:
- * TKIP: 6 octets, CCMP: 6 octets
+ * TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets
* @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
* 8-byte Rx Mic Key
* @key_len: length of the key buffer in octets (WEP: 5 or 13,
- * TKIP: 32, CCMP: 16)
+ * TKIP: 32, CCMP: 16, IGTK: 16, DHV: 16)
*
* Returns: 0 on success, -1 on failure
*
@@ -554,6 +626,132 @@ struct wpa_driver_ops {
*/
int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
const u8 *data, size_t data_len);
+
+ /**
+ * set_operstate - Sets device operating state to DORMANT or UP
+ * @priv: private driver interface data
+ * @state: 0 = dormant, 1 = up
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is an optional function that can be used on operating systems
+ * that support a concept of controlling network device state from user
+ * space applications. This function, if set, gets called with
+ * state = 1 when authentication has been completed and with state = 0
+ * when connection is lost.
+ */
+ int (*set_operstate)(void *priv, int state);
+
+ /**
+ * mlme_setprotection - MLME-SETPROTECTION.request primitive
+ * @priv: Private driver interface data
+ * @addr: Address of the station for which to set protection (may be
+ * %NULL for group keys)
+ * @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_*
+ * @key_type: MLME_SETPROTECTION_KEY_TYPE_*
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is an optional function that can be used to set the driver to
+ * require protection for Tx and/or Rx frames. This uses the layer
+ * interface defined in IEEE 802.11i-2004 clause 10.3.22.1
+ * (MLME-SETPROTECTION.request). Many drivers do not use explicit
+ * set protection operation; instead, they set protection implicitly
+ * based on configured keys.
+ */
+ int (*mlme_setprotection)(void *priv, const u8 *addr, int protect_type,
+ int key_type);
+
+ /**
+ * get_hw_feature_data - Get hardware support data (channels and rates)
+ * @priv: Private driver interface data
+ * @num_modes: Variable for returning the number of returned modes
+ * flags: Variable for returning hardware feature flags
+ * Returns: Pointer to allocated hardware data on success or %NULL on
+ * failure. Caller is responsible for freeing this.
+ *
+ * This function is only needed for drivers that export MLME
+ * (management frame processing) to wpa_supplicant.
+ */
+ struct wpa_hw_modes * (*get_hw_feature_data)(void *priv,
+ u16 *num_modes,
+ u16 *flags);
+
+ /**
+ * set_channel - Set channel
+ * @priv: Private driver interface data
+ * @phymode: WPA_MODE_IEEE80211B, ..
+ * @chan: IEEE 802.11 channel number
+ * @freq: Frequency of the channel in MHz
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only needed for drivers that export MLME
+ * (management frame processing) to wpa_supplicant.
+ */
+ int (*set_channel)(void *priv, wpa_hw_mode phymode, int chan,
+ int freq);
+
+ /**
+ * set_ssid - Set SSID
+ * @priv: Private driver interface data
+ * @ssid: SSID
+ * @ssid_len: SSID length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only needed for drivers that export MLME
+ * (management frame processing) to wpa_supplicant.
+ */
+ int (*set_ssid)(void *priv, const u8 *ssid, size_t ssid_len);
+
+ /**
+ * set_bssid - Set BSSID
+ * @priv: Private driver interface data
+ * @bssid: BSSID
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only needed for drivers that export MLME
+ * (management frame processing) to wpa_supplicant.
+ */
+ int (*set_bssid)(void *priv, const u8 *bssid);
+
+ /**
+ * send_mlme - Send management frame from MLME
+ * @priv: Private driver interface data
+ * @data: IEEE 802.11 management frame with IEEE 802.11 header
+ * @data_len: Size of the management frame
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only needed for drivers that export MLME
+ * (management frame processing) to wpa_supplicant.
+ */
+ int (*send_mlme)(void *priv, const u8 *data, size_t data_len);
+
+ /**
+ * mlme_add_sta - Add a STA entry into the driver/netstack
+ * @priv: Private driver interface data
+ * @addr: MAC address of the STA (e.g., BSSID of the AP)
+ * @supp_rates: Supported rate set (from (Re)AssocResp); in IEEE 802.11
+ * format (one octet per rate, 1 = 0.5 Mbps)
+ * @supp_rates_len: Number of entries in supp_rates
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only needed for drivers that export MLME
+ * (management frame processing) to wpa_supplicant. When the MLME code
+ * completes association with an AP, this function is called to
+ * configure the driver/netstack with a STA entry for data frame
+ * processing (TX rate control, encryption/decryption).
+ */
+ int (*mlme_add_sta)(void *priv, const u8 *addr, const u8 *supp_rates,
+ size_t supp_rates_len);
+
+ /**
+ * mlme_remove_sta - Remove a STA entry from the driver/netstack
+ * @priv: Private driver interface data
+ * @addr: MAC address of the STA (e.g., BSSID of the AP)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only needed for drivers that export MLME
+ * (management frame processing) to wpa_supplicant.
+ */
+ int (*mlme_remove_sta)(void *priv, const u8 *addr);
};
#endif /* DRIVER_H */
diff --git a/contrib/wpa_supplicant/driver_hostap.h b/contrib/wpa_supplicant/driver_hostap.h
index 76791055bd31..a83322f7e237 100644
--- a/contrib/wpa_supplicant/driver_hostap.h
+++ b/contrib/wpa_supplicant/driver_hostap.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - driver interaction with Linux Host AP driver
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/contrib/wpa_supplicant/driver_ndis.c b/contrib/wpa_supplicant/driver_ndis.c
index 5ad2a31b0198..16e051e94a3e 100644
--- a/contrib/wpa_supplicant/driver_ndis.c
+++ b/contrib/wpa_supplicant/driver_ndis.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Windows/NDIS driver interface
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,13 +12,27 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
+#ifdef __CYGWIN__
+/* Avoid some header file conflicts by not including standard headers for
+ * cygwin builds when Packet32.h is included. */
+#include "build_config.h"
+int close(int fd);
+#else /* __CYGWIN__ */
+#include "includes.h"
+#endif /* __CYGWIN__ */
+#ifdef CONFIG_USE_NDISUIO
+#include <winsock2.h>
+#else /* CONFIG_USE_NDISUIO */
#include <Packet32.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/unistd.h>
+#endif /* CONFIG_USE_NDISUIO */
#include <ntddndis.h>
+#ifdef _WIN32_WCE
+#include <winioctl.h>
+#include <nuiouser.h>
+#include <devload.h>
+#endif /* _WIN32_WCE */
+
#include "common.h"
#include "driver.h"
#include "wpa_supplicant.h"
@@ -28,8 +42,14 @@
#include "driver_ndis.h"
int wpa_driver_register_event_cb(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data);
+static void wpa_driver_ndis_deinit(void *priv);
static void wpa_driver_ndis_poll(void *drv);
+static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx);
+static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv);
+static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv);
+static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv);
/* FIX: to be removed once this can be compiled with the complete NDIS
@@ -216,7 +236,7 @@ typedef struct NDIS_802_11_CAPABILITY {
ULONG Length;
ULONG Version;
ULONG NoOfPMKIDs;
- ULONG NoOfAuthEncryptPairSupported;
+ ULONG NoOfAuthEncryptPairsSupported;
NDIS_802_11_AUTHENTICATION_ENCRYPTION
AuthenticationEncryptionSupported[1];
} NDIS_802_11_CAPABILITY;
@@ -268,20 +288,173 @@ typedef struct NDIS_802_11_AUTHENTICATION_REQUEST {
#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
-#endif
+#endif /* OID_802_11_BSSID */
+
+
+#ifndef OID_802_11_PMKID
+/* Platform SDK for XP did not include WPA2, so add needed definitions */
+
+#define OID_802_11_CAPABILITY 0x0d010122
+#define OID_802_11_PMKID 0x0d010123
+
+#define Ndis802_11AuthModeWPA2 6
+#define Ndis802_11AuthModeWPA2PSK 7
+
+#define Ndis802_11StatusType_PMKID_CandidateList 2
+
+typedef struct NDIS_802_11_AUTHENTICATION_ENCRYPTION {
+ NDIS_802_11_AUTHENTICATION_MODE AuthModeSupported;
+ NDIS_802_11_ENCRYPTION_STATUS EncryptStatusSupported;
+} NDIS_802_11_AUTHENTICATION_ENCRYPTION;
+
+typedef struct NDIS_802_11_CAPABILITY {
+ ULONG Length;
+ ULONG Version;
+ ULONG NoOfPMKIDs;
+ ULONG NoOfAuthEncryptPairsSupported;
+ NDIS_802_11_AUTHENTICATION_ENCRYPTION
+ AuthenticationEncryptionSupported[1];
+} NDIS_802_11_CAPABILITY;
+
+typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
+
+typedef struct BSSID_INFO {
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ NDIS_802_11_PMKID_VALUE PMKID;
+} BSSID_INFO;
+
+typedef struct NDIS_802_11_PMKID {
+ ULONG Length;
+ ULONG BSSIDInfoCount;
+ BSSID_INFO BSSIDInfo[1];
+} NDIS_802_11_PMKID;
+
+typedef struct PMKID_CANDIDATE {
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ ULONG Flags;
+} PMKID_CANDIDATE;
+
+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
+
+typedef struct NDIS_802_11_PMKID_CANDIDATE_LIST {
+ ULONG Version;
+ ULONG NumCandidates;
+ PMKID_CANDIDATE CandidateList[1];
+} NDIS_802_11_PMKID_CANDIDATE_LIST;
+
+#endif /* OID_802_11_CAPABILITY */
+
+
+#ifdef CONFIG_USE_NDISUIO
+#ifndef _WIN32_WCE
+#ifdef __MINGW32_VERSION
+typedef ULONG NDIS_OID;
+#endif /* __MINGW32_VERSION */
+/* from nuiouser.h */
+#define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK
+
+#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
+ CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
+
+#define IOCTL_NDISUIO_OPEN_DEVICE \
+ _NDISUIO_CTL_CODE(0x200, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_QUERY_OID_VALUE \
+ _NDISUIO_CTL_CODE(0x201, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_SET_OID_VALUE \
+ _NDISUIO_CTL_CODE(0x205, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_SET_ETHER_TYPE \
+ _NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_QUERY_BINDING \
+ _NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_BIND_WAIT \
+ _NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+typedef struct _NDISUIO_QUERY_OID
+{
+ NDIS_OID Oid;
+ UCHAR Data[sizeof(ULONG)];
+} NDISUIO_QUERY_OID, *PNDISUIO_QUERY_OID;
+
+typedef struct _NDISUIO_SET_OID
+{
+ NDIS_OID Oid;
+ UCHAR Data[sizeof(ULONG)];
+} NDISUIO_SET_OID, *PNDISUIO_SET_OID;
+
+typedef struct _NDISUIO_QUERY_BINDING
+{
+ ULONG BindingIndex;
+ ULONG DeviceNameOffset;
+ ULONG DeviceNameLength;
+ ULONG DeviceDescrOffset;
+ ULONG DeviceDescrLength;
+} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING;
+#endif /* _WIN32_WCE */
+#endif /* CONFIG_USE_NDISUIO */
static int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
- char *data, int len)
+ char *data, size_t len)
{
+#ifdef CONFIG_USE_NDISUIO
+ NDISUIO_QUERY_OID *o;
+ size_t buflen = sizeof(*o) + len;
+ DWORD written;
+ int ret;
+ size_t hdrlen;
+
+ o = os_zalloc(buflen);
+ if (o == NULL)
+ return -1;
+ o->Oid = oid;
+#ifdef _WIN32_WCE
+ o->ptcDeviceName = drv->adapter_name;
+#endif /* _WIN32_WCE */
+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_OID_VALUE,
+ o, sizeof(NDISUIO_QUERY_OID), o, buflen, &written,
+ NULL)) {
+ wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_QUERY_OID_VALUE "
+ "failed (oid=%08x): %d", oid, (int) GetLastError());
+ os_free(o);
+ return -1;
+ }
+ hdrlen = sizeof(NDISUIO_QUERY_OID) - sizeof(o->Data);
+ if (written < hdrlen) {
+ wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d); "
+ "too short", oid, (unsigned int) written);
+ os_free(o);
+ return -1;
+ }
+ written -= hdrlen;
+ if (written > len) {
+ wpa_printf(MSG_DEBUG, "NDIS: query oid=%08x written (%d) > "
+ "len (%d)",oid, (unsigned int) written, len);
+ os_free(o);
+ return -1;
+ }
+ os_memcpy(data, o->Data, written);
+ ret = written;
+ os_free(o);
+ return ret;
+#else /* CONFIG_USE_NDISUIO */
char *buf;
PACKET_OID_DATA *o;
int ret;
- buf = malloc(sizeof(*o) + len);
+ buf = os_zalloc(sizeof(*o) + len);
if (buf == NULL)
return -1;
- memset(buf, 0, sizeof(*o) + len);
o = (PACKET_OID_DATA *) buf;
o->Oid = oid;
o->Length = len;
@@ -289,46 +462,81 @@ static int ndis_get_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
if (!PacketRequest(drv->adapter, FALSE, o)) {
wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
__func__, oid, len);
- free(buf);
+ os_free(buf);
return -1;
}
if (o->Length > len) {
wpa_printf(MSG_DEBUG, "%s: oid=0x%x Length (%d) > len (%d)",
__func__, oid, (unsigned int) o->Length, len);
- free(buf);
+ os_free(buf);
return -1;
}
- memcpy(data, o->Data, o->Length);
+ os_memcpy(data, o->Data, o->Length);
ret = o->Length;
- free(buf);
+ os_free(buf);
return ret;
+#endif /* CONFIG_USE_NDISUIO */
}
static int ndis_set_oid(struct wpa_driver_ndis_data *drv, unsigned int oid,
- char *data, int len)
+ const char *data, size_t len)
{
+#ifdef CONFIG_USE_NDISUIO
+ NDISUIO_SET_OID *o;
+ size_t buflen, reallen;
+ DWORD written;
+ char txt[50];
+
+ os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
+ wpa_hexdump_key(MSG_MSGDUMP, txt, data, len);
+
+ buflen = sizeof(*o) + len;
+ reallen = buflen - sizeof(o->Data);
+ o = os_zalloc(buflen);
+ if (o == NULL)
+ return -1;
+ o->Oid = oid;
+#ifdef _WIN32_WCE
+ o->ptcDeviceName = drv->adapter_name;
+#endif /* _WIN32_WCE */
+ if (data)
+ os_memcpy(o->Data, data, len);
+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_SET_OID_VALUE,
+ o, reallen, NULL, 0, &written, NULL)) {
+ wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDISUIO_SET_OID_VALUE "
+ "(oid=%08x) failed: %d", oid, (int) GetLastError());
+ os_free(o);
+ return -1;
+ }
+ os_free(o);
+ return 0;
+#else /* CONFIG_USE_NDISUIO */
char *buf;
PACKET_OID_DATA *o;
+ char txt[50];
+
+ os_snprintf(txt, sizeof(txt), "NDIS: Set OID %08x", oid);
+ wpa_hexdump_key(MSG_MSGDUMP, txt, data, len);
- buf = malloc(sizeof(*o) + len);
+ buf = os_zalloc(sizeof(*o) + len);
if (buf == NULL)
return -1;
- memset(buf, 0, sizeof(*o) + len);
o = (PACKET_OID_DATA *) buf;
o->Oid = oid;
o->Length = len;
if (data)
- memcpy(o->Data, data, len);
+ os_memcpy(o->Data, data, len);
if (!PacketRequest(drv->adapter, TRUE, o)) {
wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
__func__, oid, len);
- free(buf);
+ os_free(buf);
return -1;
}
- free(buf);
+ os_free(buf);
return 0;
+#endif /* CONFIG_USE_NDISUIO */
}
@@ -429,7 +637,7 @@ static int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid)
}
return -1;
}
- memcpy(ssid, buf.Ssid, buf.SsidLength);
+ os_memcpy(ssid, buf.Ssid, buf.SsidLength);
return buf.SsidLength;
}
@@ -439,9 +647,9 @@ static int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv,
{
NDIS_802_11_SSID buf;
- memset(&buf, 0, sizeof(buf));
+ os_memset(&buf, 0, sizeof(buf));
buf.SsidLength = ssid_len;
- memcpy(buf.Ssid, ssid, ssid_len);
+ os_memcpy(buf.Ssid, ssid, ssid_len);
/*
* Make sure radio is marked enabled here so that scan request will not
* force SSID to be changed to a random one in order to enable radio at
@@ -517,7 +725,7 @@ static int wpa_driver_ndis_scan(void *priv, const u8 *ssid, size_t ssid_len)
}
res = ndis_set_oid(drv, OID_802_11_BSSID_LIST_SCAN, " ", 4);
- eloop_register_timeout(3, 0, wpa_driver_ndis_scan_timeout, drv,
+ eloop_register_timeout(7, 0, wpa_driver_ndis_scan_timeout, drv,
drv->ctx);
return res;
}
@@ -541,11 +749,11 @@ static void wpa_driver_ndis_get_ies(struct wpa_scan_result *res, u8 *ie,
continue;
}
if (pos[0] == GENERIC_INFO_ELEM && pos[1] >= 4 &&
- memcmp(pos + 2, "\x00\x50\xf2\x01", 4) == 0) {
- memcpy(res->wpa_ie, pos, ielen);
+ os_memcmp(pos + 2, "\x00\x50\xf2\x01", 4) == 0) {
+ os_memcpy(res->wpa_ie, pos, ielen);
res->wpa_ie_len = ielen;
} else if (pos[0] == RSN_INFO_ELEM) {
- memcpy(res->rsn_ie, pos, ielen);
+ os_memcpy(res->rsn_ie, pos, ielen);
res->rsn_ie_len = ielen;
}
pos += ielen;
@@ -559,19 +767,18 @@ static int wpa_driver_ndis_get_scan_results(void *priv,
{
struct wpa_driver_ndis_data *drv = priv;
NDIS_802_11_BSSID_LIST_EX *b;
- size_t blen;
- int len, count, i, j;
+ size_t blen, count, i;
+ int len, j;
char *pos;
blen = 65535;
- b = malloc(blen);
+ b = os_zalloc(blen);
if (b == NULL)
return -1;
- memset(b, 0, blen);
len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
if (len < 0) {
wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
- free(b);
+ os_free(b);
return -1;
}
count = b->NumberOfItems;
@@ -579,15 +786,20 @@ static int wpa_driver_ndis_get_scan_results(void *priv,
if (count > max_size)
count = max_size;
- memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+ os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
pos = (char *) &b->Bssid[0];
for (i = 0; i < count; i++) {
NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
- memcpy(results[i].bssid, bss->MacAddress, ETH_ALEN);
- memcpy(results[i].ssid, bss->Ssid.Ssid, bss->Ssid.SsidLength);
+ os_memcpy(results[i].bssid, bss->MacAddress, ETH_ALEN);
+ os_memcpy(results[i].ssid, bss->Ssid.Ssid,
+ bss->Ssid.SsidLength);
results[i].ssid_len = bss->Ssid.SsidLength;
if (bss->Privacy)
results[i].caps |= IEEE80211_CAP_PRIVACY;
+ if (bss->InfrastructureMode == Ndis802_11IBSS)
+ results[i].caps |= IEEE80211_CAP_IBSS;
+ else if (bss->InfrastructureMode == Ndis802_11Infrastructure)
+ results[i].caps |= IEEE80211_CAP_ESS;
results[i].level = (int) bss->Rssi;
results[i].freq = bss->Configuration.DSConfig / 1000;
for (j = 0; j < sizeof(bss->SupportedRates); j++) {
@@ -597,14 +809,27 @@ static int wpa_driver_ndis_get_scan_results(void *priv,
bss->SupportedRates[j] & 0x7f;
}
}
+ if (((char *) bss->IEs) + bss->IELength > (char *) b + blen) {
+ /*
+ * Some NDIS drivers have been reported to include an
+ * entry with an invalid IELength in scan results and
+ * this has crashed wpa_supplicant, so validate the
+ * returned value before using it.
+ */
+ wpa_printf(MSG_DEBUG, "NDIS: skipped invalid scan "
+ "result IE (BSSID=" MACSTR ") IELength=%d",
+ MAC2STR(results[i].bssid),
+ (int) bss->IELength);
+ break;
+ }
wpa_driver_ndis_get_ies(&results[i], bss->IEs, bss->IELength);
pos += bss->Length;
if (pos > (char *) b + blen)
break;
}
- free(b);
- return count;
+ os_free(b);
+ return (int) count;
}
@@ -616,24 +841,25 @@ static int wpa_driver_ndis_remove_key(struct wpa_driver_ndis_data *drv,
NDIS_802_11_KEY_INDEX index;
int res, res2;
- memset(&rkey, 0, sizeof(rkey));
+ os_memset(&rkey, 0, sizeof(rkey));
rkey.Length = sizeof(rkey);
rkey.KeyIndex = key_idx;
if (pairwise)
rkey.KeyIndex |= 1 << 30;
- memcpy(rkey.BSSID, bssid, ETH_ALEN);
+ os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
res = ndis_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
sizeof(rkey));
if (!pairwise) {
+ index = key_idx;
res2 = ndis_set_oid(drv, OID_802_11_REMOVE_WEP,
(char *) &index, sizeof(index));
} else
res2 = 0;
if (res < 0 && res2 < 0)
- return res;
+ return -1;
return 0;
}
@@ -647,10 +873,9 @@ static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
int res;
len = 12 + key_len;
- wep = malloc(len);
+ wep = os_zalloc(len);
if (wep == NULL)
return -1;
- memset(wep, 0, len);
wep->Length = len;
wep->KeyIndex = key_idx;
if (set_tx)
@@ -660,13 +885,13 @@ static int wpa_driver_ndis_add_wep(struct wpa_driver_ndis_data *drv,
wep->KeyIndex |= 1 << 30;
#endif
wep->KeyLength = key_len;
- memcpy(wep->KeyMaterial, key, key_len);
+ os_memcpy(wep->KeyMaterial, key, key_len);
- wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OIS_802_11_ADD_WEP",
+ wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_WEP",
(char *) wep, len);
res = ndis_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
- free(wep);
+ os_free(wep);
return res;
}
@@ -677,20 +902,21 @@ static int wpa_driver_ndis_set_key(void *priv, wpa_alg alg, const u8 *addr,
const u8 *key, size_t key_len)
{
struct wpa_driver_ndis_data *drv = priv;
- size_t len;
+ size_t len, i;
NDIS_802_11_KEY *nkey;
- int i, res, pairwise;
+ int res, pairwise;
u8 bssid[ETH_ALEN];
- if (addr == NULL || memcmp(addr, "\xff\xff\xff\xff\xff\xff",
- ETH_ALEN) == 0) {
+ if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
+ ETH_ALEN) == 0) {
/* Group Key */
pairwise = 0;
- wpa_driver_ndis_get_bssid(drv, bssid);
+ if (wpa_driver_ndis_get_bssid(drv, bssid) < 0)
+ os_memset(bssid, 0xff, ETH_ALEN);
} else {
/* Pairwise Key */
pairwise = 1;
- memcpy(bssid, addr, ETH_ALEN);
+ os_memcpy(bssid, addr, ETH_ALEN);
}
if (alg == WPA_ALG_NONE || key_len == 0) {
@@ -705,10 +931,9 @@ static int wpa_driver_ndis_set_key(void *priv, wpa_alg alg, const u8 *addr,
len = 12 + 6 + 6 + 8 + key_len;
- nkey = malloc(len);
+ nkey = os_zalloc(len);
if (nkey == NULL)
return -1;
- memset(nkey, 0, len);
nkey->Length = len;
nkey->KeyIndex = key_idx;
@@ -719,23 +944,23 @@ static int wpa_driver_ndis_set_key(void *priv, wpa_alg alg, const u8 *addr,
if (seq && seq_len)
nkey->KeyIndex |= 1 << 29;
nkey->KeyLength = key_len;
- memcpy(nkey->BSSID, bssid, ETH_ALEN);
+ os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
if (seq && seq_len) {
for (i = 0; i < seq_len; i++)
- nkey->KeyRSC |= seq[i] << (i * 8);
+ nkey->KeyRSC |= (ULONGLONG) seq[i] << (i * 8);
}
if (alg == WPA_ALG_TKIP && key_len == 32) {
- memcpy(nkey->KeyMaterial, key, 16);
- memcpy(nkey->KeyMaterial + 16, key + 24, 8);
- memcpy(nkey->KeyMaterial + 24, key + 16, 8);
+ os_memcpy(nkey->KeyMaterial, key, 16);
+ os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
+ os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
} else {
- memcpy(nkey->KeyMaterial, key, key_len);
+ os_memcpy(nkey->KeyMaterial, key, key_len);
}
- wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OIS_802_11_ADD_KEY",
+ wpa_hexdump_key(MSG_MSGDUMP, "NDIS: OID_802_11_ADD_KEY",
(char *) nkey, len);
res = ndis_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
- free(nkey);
+ os_free(nkey);
return res;
}
@@ -748,11 +973,18 @@ wpa_driver_ndis_associate(void *priv,
struct wpa_driver_ndis_data *drv = priv;
u32 auth_mode, encr, priv_mode, mode;
+ drv->mode = params->mode;
+
/* Note: Setting OID_802_11_INFRASTRUCTURE_MODE clears current keys,
* so static WEP keys needs to be set again after this. */
- if (params->mode == IEEE80211_MODE_IBSS)
+ if (params->mode == IEEE80211_MODE_IBSS) {
mode = Ndis802_11IBSS;
- else
+ /* Need to make sure that BSSID polling is enabled for
+ * IBSS mode. */
+ eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
+ eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
+ drv, NULL);
+ } else
mode = Ndis802_11Infrastructure;
if (ndis_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
(char *) &mode, sizeof(mode)) < 0) {
@@ -762,6 +994,23 @@ wpa_driver_ndis_associate(void *priv,
/* Try to continue anyway */
}
+ if (params->key_mgmt_suite == KEY_MGMT_NONE ||
+ params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
+ /* Re-set WEP keys if static WEP configuration is used. */
+ u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+ int i;
+ for (i = 0; i < 4; i++) {
+ if (!params->wep_key[i])
+ continue;
+ wpa_printf(MSG_DEBUG, "NDIS: Re-setting static WEP "
+ "key %d", i);
+ wpa_driver_ndis_set_key(drv, WPA_ALG_WEP, bcast, i,
+ i == params->wep_tx_keyidx,
+ NULL, 0, params->wep_key[i],
+ params->wep_key_len[i]);
+ }
+ }
+
if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
if (params->auth_alg & AUTH_ALG_SHARED_KEY) {
if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
@@ -801,8 +1050,10 @@ wpa_driver_ndis_associate(void *priv,
case CIPHER_NONE:
if (params->group_suite == CIPHER_CCMP)
encr = Ndis802_11Encryption3Enabled;
- else
+ else if (params->group_suite == CIPHER_TKIP)
encr = Ndis802_11Encryption2Enabled;
+ else
+ encr = Ndis802_11EncryptionDisabled;
break;
default:
encr = Ndis802_11EncryptionDisabled;
@@ -819,6 +1070,15 @@ wpa_driver_ndis_associate(void *priv,
ndis_set_auth_mode(drv, auth_mode);
ndis_set_encr_status(drv, encr);
+ if (params->bssid) {
+ ndis_set_oid(drv, OID_802_11_BSSID, params->bssid, ETH_ALEN);
+ drv->oid_bssid_set = 1;
+ } else if (drv->oid_bssid_set) {
+ ndis_set_oid(drv, OID_802_11_BSSID, "\xff\xff\xff\xff\xff\xff",
+ ETH_ALEN);
+ drv->oid_bssid_set = 0;
+ }
+
return wpa_driver_ndis_set_ssid(drv, params->ssid, params->ssid_len);
}
@@ -838,21 +1098,21 @@ static int wpa_driver_ndis_set_pmkid(struct wpa_driver_ndis_data *drv)
entry = entry->next;
}
len = 8 + count * sizeof(BSSID_INFO);
- p = malloc(len);
+ p = os_zalloc(len);
if (p == NULL)
return -1;
- memset(p, 0, len);
+
p->Length = len;
p->BSSIDInfoCount = count;
entry = drv->pmkid;
for (i = 0; i < count; i++) {
- memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
- memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
+ os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
+ os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
entry = entry->next;
}
wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID", (char *) p, len);
ret = ndis_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
- free(p);
+ os_free(p);
return ret;
}
@@ -869,7 +1129,7 @@ static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid,
prev = NULL;
entry = drv->pmkid;
while (entry) {
- if (memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
break;
prev = entry;
entry = entry->next;
@@ -878,17 +1138,17 @@ static int wpa_driver_ndis_add_pmkid(void *priv, const u8 *bssid,
if (entry) {
/* Replace existing entry for this BSSID and move it into the
* beginning of the list. */
- memcpy(entry->pmkid, pmkid, 16);
+ os_memcpy(entry->pmkid, pmkid, 16);
if (prev) {
prev->next = entry->next;
entry->next = drv->pmkid;
drv->pmkid = entry;
}
} else {
- entry = malloc(sizeof(*entry));
+ entry = os_malloc(sizeof(*entry));
if (entry) {
- memcpy(entry->bssid, bssid, ETH_ALEN);
- memcpy(entry->pmkid, pmkid, 16);
+ os_memcpy(entry->bssid, bssid, ETH_ALEN);
+ os_memcpy(entry->pmkid, pmkid, 16);
entry->next = drv->pmkid;
drv->pmkid = entry;
}
@@ -911,13 +1171,13 @@ static int wpa_driver_ndis_remove_pmkid(void *priv, const u8 *bssid,
prev = NULL;
drv->pmkid = NULL;
while (entry) {
- if (memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
- memcmp(entry->pmkid, pmkid, 16) == 0) {
+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
+ os_memcmp(entry->pmkid, pmkid, 16) == 0) {
if (prev)
prev->next = entry->next;
else
drv->pmkid = entry->next;
- free(entry);
+ os_free(entry);
break;
}
prev = entry;
@@ -941,10 +1201,10 @@ static int wpa_driver_ndis_flush_pmkid(void *priv)
while (pmkid) {
prev = pmkid;
pmkid = pmkid->next;
- free(prev);
+ os_free(prev);
}
- memset(&p, 0, sizeof(p));
+ os_memset(&p, 0, sizeof(p));
p.Length = 8;
p.BSSIDInfoCount = 0;
wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
@@ -957,10 +1217,10 @@ static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
{
char buf[512], *pos;
NDIS_802_11_ASSOCIATION_INFORMATION *ai;
- int len, i;
+ int len;
union wpa_event_data data;
NDIS_802_11_BSSID_LIST_EX *b;
- size_t blen;
+ size_t blen, i;
len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf,
sizeof(buf));
@@ -1002,33 +1262,32 @@ static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
(int) ai->OffsetRequestIEs, (int) ai->OffsetResponseIEs,
(int) ai->RequestIELength, (int) ai->ResponseIELength);
- if (ai->OffsetRequestIEs + ai->RequestIELength > len ||
- ai->OffsetResponseIEs + ai->ResponseIELength > len) {
+ if (ai->OffsetRequestIEs + ai->RequestIELength > (unsigned) len ||
+ ai->OffsetResponseIEs + ai->ResponseIELength > (unsigned) len) {
wpa_printf(MSG_DEBUG, "NDIS: association information - "
"IE overflow");
return -1;
}
- wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs",
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: Request IEs",
buf + ai->OffsetRequestIEs, ai->RequestIELength);
- wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs",
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: Response IEs",
buf + ai->OffsetResponseIEs, ai->ResponseIELength);
- memset(&data, 0, sizeof(data));
+ os_memset(&data, 0, sizeof(data));
data.assoc_info.req_ies = buf + ai->OffsetRequestIEs;
data.assoc_info.req_ies_len = ai->RequestIELength;
data.assoc_info.resp_ies = buf + ai->OffsetResponseIEs;
data.assoc_info.resp_ies_len = ai->ResponseIELength;
blen = 65535;
- b = malloc(blen);
+ b = os_zalloc(blen);
if (b == NULL)
goto skip_scan_results;
- memset(b, 0, blen);
len = ndis_get_oid(drv, OID_802_11_BSSID_LIST, (char *) b, blen);
if (len < 0) {
wpa_printf(MSG_DEBUG, "NDIS: failed to get scan results");
- free(b);
+ os_free(b);
b = NULL;
goto skip_scan_results;
}
@@ -1038,7 +1297,7 @@ static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
pos = (char *) &b->Bssid[0];
for (i = 0; i < b->NumberOfItems; i++) {
NDIS_WLAN_BSSID_EX *bss = (NDIS_WLAN_BSSID_EX *) pos;
- if (memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 &&
+ if (os_memcmp(drv->bssid, bss->MacAddress, ETH_ALEN) == 0 &&
bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) {
data.assoc_info.beacon_ies =
((u8 *) bss->IEs) +
@@ -1058,7 +1317,7 @@ static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
skip_scan_results:
wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
- free(b);
+ os_free(b);
return 0;
}
@@ -1068,26 +1327,44 @@ static void wpa_driver_ndis_poll_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_driver_ndis_data *drv = eloop_ctx;
u8 bssid[ETH_ALEN];
+ int poll;
if (drv->wired)
return;
if (wpa_driver_ndis_get_bssid(drv, bssid)) {
/* Disconnected */
- if (memcmp(drv->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)
+ if (os_memcmp(drv->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)
!= 0) {
- memset(drv->bssid, 0, ETH_ALEN);
+ os_memset(drv->bssid, 0, ETH_ALEN);
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
}
} else {
/* Connected */
- if (memcmp(drv->bssid, bssid, ETH_ALEN) != 0) {
- memcpy(drv->bssid, bssid, ETH_ALEN);
+ if (os_memcmp(drv->bssid, bssid, ETH_ALEN) != 0) {
+ os_memcpy(drv->bssid, bssid, ETH_ALEN);
wpa_driver_ndis_get_associnfo(drv);
wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
}
}
- eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL);
+
+ /* When using integrated NDIS event receiver, we can skip BSSID
+ * polling when using infrastructure network. However, when using
+ * IBSS mode, many driver do not seem to generate connection event,
+ * so we need to enable BSSID polling to figure out when IBSS network
+ * has been formed.
+ */
+ poll = drv->mode == IEEE80211_MODE_IBSS;
+#ifndef CONFIG_NDIS_EVENTS_INTEGRATED
+#ifndef _WIN32_WCE
+ poll = 1;
+#endif /* _WIN32_WCE */
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+
+ if (poll) {
+ eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout,
+ drv, NULL);
+ }
}
@@ -1116,7 +1393,7 @@ void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv)
void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv)
{
wpa_printf(MSG_DEBUG, "NDIS: Media Disconnect Event");
- memset(drv->bssid, 0, ETH_ALEN);
+ os_memset(drv->bssid, 0, ETH_ALEN);
wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
}
@@ -1147,7 +1424,7 @@ static void wpa_driver_ndis_event_auth(struct wpa_driver_ndis_data *drv,
group = 1;
if (pairwise || group) {
- memset(&event, 0, sizeof(event));
+ os_memset(&event, 0, sizeof(event));
event.michael_mic_failure.unicast = pairwise;
wpa_supplicant_event(drv->ctx, EVENT_MICHAEL_MIC_FAILURE,
&event);
@@ -1159,7 +1436,7 @@ static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv,
const u8 *data, size_t data_len)
{
NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
- int i;
+ size_t i;
union wpa_event_data event;
if (data_len < 8) {
@@ -1183,12 +1460,12 @@ static void wpa_driver_ndis_event_pmkid(struct wpa_driver_ndis_data *drv,
return;
}
- memset(&event, 0, sizeof(event));
+ os_memset(&event, 0, sizeof(event));
for (i = 0; i < pmkid->NumCandidates; i++) {
PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
wpa_printf(MSG_DEBUG, "NDIS: %d: " MACSTR " Flags 0x%x",
i, MAC2STR(p->BSSID), (int) p->Flags);
- memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
+ os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
event.pmkid_candidate.index = i;
event.pmkid_candidate.preauth =
p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
@@ -1230,6 +1507,50 @@ void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
}
+/* Called when an adapter is added */
+void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv)
+{
+ union wpa_event_data event;
+ int i;
+
+ wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Arrival");
+
+ for (i = 0; i < 30; i++) {
+ /* Re-open Packet32/NDISUIO connection */
+ wpa_driver_ndis_adapter_close(drv);
+ if (wpa_driver_ndis_adapter_init(drv) < 0 ||
+ wpa_driver_ndis_adapter_open(drv) < 0) {
+ wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialization "
+ "(%d) failed", i);
+ os_sleep(1, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, "NDIS: Driver re-initialized");
+ break;
+ }
+ }
+
+ os_memset(&event, 0, sizeof(event));
+ os_snprintf(event.interface_status.ifname,
+ sizeof(event.interface_status.ifname), "%s", drv->ifname);
+ event.interface_status.ievent = EVENT_INTERFACE_ADDED;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+/* Called when an adapter is removed */
+void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv)
+{
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG, "NDIS: Notify Adapter Removal");
+ os_memset(&event, 0, sizeof(event));
+ os_snprintf(event.interface_status.ifname,
+ sizeof(event.interface_status.ifname), "%s", drv->ifname);
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
static void
wpa_driver_ndis_get_wpa_capability(struct wpa_driver_ndis_data *drv)
{
@@ -1300,11 +1621,11 @@ wpa_driver_ndis_get_wpa_capability(struct wpa_driver_ndis_data *drv)
static void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv)
{
char buf[512];
- int len, i;
+ int len;
+ size_t i;
NDIS_802_11_CAPABILITY *c;
- drv->capa.flags = WPA_DRIVER_FLAGS_DRIVER_IE |
- WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC;
+ drv->capa.flags = WPA_DRIVER_FLAGS_DRIVER_IE;
len = ndis_get_oid(drv, OID_802_11_CAPABILITY, buf, sizeof(buf));
if (len < 0) {
@@ -1321,10 +1642,11 @@ static void wpa_driver_ndis_get_capability(struct wpa_driver_ndis_data *drv)
}
wpa_printf(MSG_DEBUG, "NDIS: Driver supports OID_802_11_CAPABILITY - "
"NoOfPMKIDs %d NoOfAuthEncrPairs %d",
- (int) c->NoOfPMKIDs, (int) c->NoOfAuthEncryptPairSupported);
+ (int) c->NoOfPMKIDs,
+ (int) c->NoOfAuthEncryptPairsSupported);
drv->has_capability = 1;
drv->no_of_pmkid = c->NoOfPMKIDs;
- for (i = 0; i < c->NoOfAuthEncryptPairSupported; i++) {
+ for (i = 0; i < c->NoOfAuthEncryptPairsSupported; i++) {
NDIS_802_11_AUTHENTICATION_ENCRYPTION *ae;
ae = &c->AuthenticationEncryptionSupported[i];
if ((char *) (ae + 1) > buf + len) {
@@ -1389,7 +1711,7 @@ static int wpa_driver_ndis_get_capa(void *priv, struct wpa_driver_capa *capa)
struct wpa_driver_ndis_data *drv = priv;
if (!drv->has_capability)
return -1;
- memcpy(capa, &drv->capa, sizeof(*capa));
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
return 0;
}
@@ -1408,12 +1730,279 @@ static const u8 * wpa_driver_ndis_get_mac_addr(void *priv)
}
+#ifdef _WIN32_WCE
+
+#define NDISUIO_MSG_SIZE (sizeof(NDISUIO_DEVICE_NOTIFICATION) + 512)
+
+static void ndisuio_notification_receive(void *eloop_data, void *user_ctx)
+{
+ struct wpa_driver_ndis_data *drv = eloop_data;
+ NDISUIO_DEVICE_NOTIFICATION *hdr;
+ u8 buf[NDISUIO_MSG_SIZE];
+ DWORD len, flags;
+
+ if (!ReadMsgQueue(drv->event_queue, buf, NDISUIO_MSG_SIZE, &len, 0,
+ &flags)) {
+ wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
+ "ReadMsgQueue failed: %d", (int) GetLastError());
+ return;
+ }
+
+ if (len < sizeof(NDISUIO_DEVICE_NOTIFICATION)) {
+ wpa_printf(MSG_DEBUG, "ndisuio_notification_receive: "
+ "Too short message (len=%d)", (int) len);
+ return;
+ }
+
+ hdr = (NDISUIO_DEVICE_NOTIFICATION *) buf;
+ wpa_printf(MSG_DEBUG, "NDIS: Notification received: len=%d type=0x%x",
+ (int) len, hdr->dwNotificationType);
+
+ switch (hdr->dwNotificationType) {
+#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
+ case NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL:
+ wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_ARRIVAL");
+ wpa_driver_ndis_event_adapter_arrival(drv);
+ break;
+#endif
+#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
+ case NDISUIO_NOTIFICATION_ADAPTER_REMOVAL:
+ wpa_printf(MSG_DEBUG, "NDIS: ADAPTER_REMOVAL");
+ wpa_driver_ndis_event_adapter_removal(drv);
+ break;
+#endif
+ case NDISUIO_NOTIFICATION_MEDIA_CONNECT:
+ wpa_printf(MSG_DEBUG, "NDIS: MEDIA_CONNECT");
+ SetEvent(drv->connected_event);
+ wpa_driver_ndis_event_connect(drv);
+ break;
+ case NDISUIO_NOTIFICATION_MEDIA_DISCONNECT:
+ ResetEvent(drv->connected_event);
+ wpa_printf(MSG_DEBUG, "NDIS: MEDIA_DISCONNECT");
+ wpa_driver_ndis_event_disconnect(drv);
+ break;
+ case NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION:
+ wpa_printf(MSG_DEBUG, "NDIS: MEDIA_SPECIFIC_NOTIFICATION");
+#if _WIN32_WCE == 420 || _WIN32_WCE == 0x420
+ wpa_driver_ndis_event_media_specific(
+ drv, hdr->pvStatusBuffer, hdr->uiStatusBufferSize);
+#else
+ wpa_driver_ndis_event_media_specific(
+ drv, ((const u8 *) hdr) + hdr->uiOffsetToStatusBuffer,
+ (size_t) hdr->uiStatusBufferSize);
+#endif
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "NDIS: Unknown notification type 0x%x",
+ hdr->dwNotificationType);
+ break;
+ }
+}
+
+
+static void ndisuio_notification_deinit(struct wpa_driver_ndis_data *drv)
+{
+ NDISUIO_REQUEST_NOTIFICATION req;
+
+ memset(&req, 0, sizeof(req));
+ req.hMsgQueue = drv->event_queue;
+ req.dwNotificationTypes = 0;
+
+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
+ &req, sizeof(req), NULL, 0, NULL, NULL)) {
+ wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
+ "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
+ (int) GetLastError());
+ }
+
+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_CANCEL_NOTIFICATION,
+ NULL, 0, NULL, 0, NULL, NULL)) {
+ wpa_printf(MSG_INFO, "ndisuio_notification_deinit: "
+ "IOCTL_NDISUIO_CANCEL_NOTIFICATION failed: %d",
+ (int) GetLastError());
+ }
+
+ if (drv->event_queue) {
+ eloop_unregister_event(drv->event_queue,
+ sizeof(drv->event_queue));
+ CloseHandle(drv->event_queue);
+ drv->event_queue = NULL;
+ }
+
+ if (drv->connected_event) {
+ CloseHandle(drv->connected_event);
+ drv->connected_event = NULL;
+ }
+}
+
+
+static int ndisuio_notification_init(struct wpa_driver_ndis_data *drv)
+{
+ MSGQUEUEOPTIONS opt;
+ NDISUIO_REQUEST_NOTIFICATION req;
+
+ drv->connected_event =
+ CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
+ if (drv->connected_event == NULL) {
+ wpa_printf(MSG_INFO, "ndisuio_notification_init: "
+ "CreateEvent failed: %d",
+ (int) GetLastError());
+ return -1;
+ }
+
+ memset(&opt, 0, sizeof(opt));
+ opt.dwSize = sizeof(opt);
+ opt.dwMaxMessages = 5;
+ opt.cbMaxMessage = NDISUIO_MSG_SIZE;
+ opt.bReadAccess = TRUE;
+
+ drv->event_queue = CreateMsgQueue(NULL, &opt);
+ if (drv->event_queue == NULL) {
+ wpa_printf(MSG_INFO, "ndisuio_notification_init: "
+ "CreateMsgQueue failed: %d",
+ (int) GetLastError());
+ ndisuio_notification_deinit(drv);
+ return -1;
+ }
+
+ memset(&req, 0, sizeof(req));
+ req.hMsgQueue = drv->event_queue;
+ req.dwNotificationTypes =
+#ifdef NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL
+ NDISUIO_NOTIFICATION_ADAPTER_ARRIVAL |
+#endif
+#ifdef NDISUIO_NOTIFICATION_ADAPTER_REMOVAL
+ NDISUIO_NOTIFICATION_ADAPTER_REMOVAL |
+#endif
+ NDISUIO_NOTIFICATION_MEDIA_CONNECT |
+ NDISUIO_NOTIFICATION_MEDIA_DISCONNECT |
+ NDISUIO_NOTIFICATION_MEDIA_SPECIFIC_NOTIFICATION;
+
+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_REQUEST_NOTIFICATION,
+ &req, sizeof(req), NULL, 0, NULL, NULL)) {
+ wpa_printf(MSG_INFO, "ndisuio_notification_init: "
+ "IOCTL_NDISUIO_REQUEST_NOTIFICATION failed: %d",
+ (int) GetLastError());
+ ndisuio_notification_deinit(drv);
+ return -1;
+ }
+
+ eloop_register_event(drv->event_queue, sizeof(drv->event_queue),
+ ndisuio_notification_receive, drv, NULL);
+
+ return 0;
+}
+#endif /* _WIN32_WCE */
+
+
static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
{
- PTSTR names, pos, pos2;
+#ifdef CONFIG_USE_NDISUIO
+ NDISUIO_QUERY_BINDING *b;
+ size_t blen = sizeof(*b) + 1024;
+ int i, error, found = 0;
+ DWORD written;
+ char name[256], desc[256], *dpos;
+ WCHAR *pos;
+ size_t j, len, dlen;
+
+ b = os_malloc(blen);
+ if (b == NULL)
+ return -1;
+
+ for (i = 0; ; i++) {
+ os_memset(b, 0, blen);
+ b->BindingIndex = i;
+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
+ b, sizeof(NDISUIO_QUERY_BINDING), b, blen,
+ &written, NULL)) {
+ error = (int) GetLastError();
+ if (error == ERROR_NO_MORE_ITEMS)
+ break;
+ wpa_printf(MSG_DEBUG, "IOCTL_NDISUIO_QUERY_BINDING "
+ "failed: %d", error);
+ break;
+ }
+
+ pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
+ len = b->DeviceNameLength;
+ if (len >= sizeof(name))
+ len = sizeof(name) - 1;
+ for (j = 0; j < len; j++)
+ name[j] = (char) pos[j];
+ name[len] = '\0';
+
+ pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
+ len = b->DeviceDescrLength;
+ if (len >= sizeof(desc))
+ len = sizeof(desc) - 1;
+ for (j = 0; j < len; j++)
+ desc[j] = (char) pos[j];
+ desc[len] = '\0';
+
+ wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s", i, name, desc);
+
+ if (os_strstr(name, drv->ifname)) {
+ wpa_printf(MSG_DEBUG, "NDIS: Interface name match");
+ found = 1;
+ break;
+ }
+
+ if (os_strncmp(desc, drv->ifname, os_strlen(drv->ifname)) == 0)
+ {
+ wpa_printf(MSG_DEBUG, "NDIS: Interface description "
+ "match");
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found) {
+ wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
+ drv->ifname);
+ os_free(b);
+ return -1;
+ }
+
+ os_strncpy(drv->ifname,
+ os_strncmp(name, "\\DEVICE\\", 8) == 0 ? name + 8 : name,
+ sizeof(drv->ifname));
+#ifdef _WIN32_WCE
+ drv->adapter_name = wpa_strdup_tchar(drv->ifname);
+ if (drv->adapter_name == NULL) {
+ wpa_printf(MSG_ERROR, "NDIS: Failed to allocate memory for "
+ "adapter name");
+ os_free(b);
+ return -1;
+ }
+#endif /* _WIN32_WCE */
+
+ dpos = os_strstr(desc, " - ");
+ if (dpos)
+ dlen = dpos - desc;
+ else
+ dlen = os_strlen(desc);
+ drv->adapter_desc = os_malloc(dlen + 1);
+ if (drv->adapter_desc) {
+ os_memcpy(drv->adapter_desc, desc, dlen);
+ drv->adapter_desc[dlen] = '\0';
+ }
+
+ os_free(b);
+
+ if (drv->adapter_desc == NULL)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "NDIS: Adapter description prefix '%s'",
+ drv->adapter_desc);
+
+ return 0;
+#else /* CONFIG_USE_NDISUIO */
+ PTSTR _names;
+ char *names, *pos, *pos2;
ULONG len;
BOOLEAN res;
- const int MAX_ADAPTERS = 32;
+#define MAX_ADAPTERS 32
char *name[MAX_ADAPTERS];
char *desc[MAX_ADAPTERS];
int num_name, num_desc, i, found_name, found_desc;
@@ -1423,30 +2012,27 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
PacketGetVersion());
len = 8192;
- names = malloc(len);
- if (names == NULL)
+ _names = os_zalloc(len);
+ if (_names == NULL)
return -1;
- memset(names, 0, len);
- res = PacketGetAdapterNames(names, &len);
+ res = PacketGetAdapterNames(_names, &len);
if (!res && len > 8192) {
- free(names);
- names = malloc(len);
- if (names == NULL)
+ os_free(_names);
+ _names = os_zalloc(len);
+ if (_names == NULL)
return -1;
- memset(names, 0, len);
- res = PacketGetAdapterNames(names, &len);
+ res = PacketGetAdapterNames(_names, &len);
}
if (!res) {
wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
"(PacketGetAdapterNames)");
- free(names);
+ os_free(_names);
return -1;
}
- /* wpa_hexdump_ascii(MSG_DEBUG, "NDIS: AdapterNames", names, len); */
-
+ names = (char *) _names;
if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
"UNICODE");
@@ -1461,7 +2047,7 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
*pos++ = pos2[0];
pos2 += 2;
}
- memcpy(pos + 2, names, pos - names);
+ os_memcpy(pos + 2, names, pos - names);
pos += 2;
} else
pos = names;
@@ -1472,14 +2058,14 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
while (*pos && pos < names + len)
pos++;
if (pos + 1 >= names + len) {
- free(names);
+ os_free(names);
return -1;
}
pos++;
num_name++;
if (num_name >= MAX_ADAPTERS) {
wpa_printf(MSG_DEBUG, "NDIS: Too many adapters");
- free(names);
+ os_free(names);
return -1;
}
if (*pos == '\0') {
@@ -1496,7 +2082,7 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
while (*pos && pos < names + len)
pos++;
if (pos + 1 >= names + len) {
- free(names);
+ os_free(names);
return -1;
}
pos++;
@@ -1504,7 +2090,7 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
if (num_desc >= MAX_ADAPTERS) {
wpa_printf(MSG_DEBUG, "NDIS: Too many adapter "
"descriptions");
- free(names);
+ os_free(names);
return -1;
}
if (*pos == '\0') {
@@ -1526,7 +2112,7 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
"description counts (%d != %d)",
num_name, num_desc);
- free(names);
+ os_free(names);
return -1;
}
@@ -1534,13 +2120,12 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
for (i = 0; i < num_name; i++) {
wpa_printf(MSG_DEBUG, "NDIS: %d - %s - %s",
i, name[i], desc[i]);
- if (found_name == -1 && strcmp(name[i], drv->ifname) == 0) {
+ if (found_name == -1 && os_strstr(name[i], drv->ifname))
found_name = i;
- }
if (found_desc == -1 &&
- strncmp(desc[i], drv->ifname, strlen(drv->ifname)) == 0) {
+ os_strncmp(desc[i], drv->ifname, os_strlen(drv->ifname)) ==
+ 0)
found_desc = i;
- }
}
if (found_name < 0 && found_desc >= 0) {
@@ -1548,33 +2133,36 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
"description '%s'",
name[found_desc], desc[found_desc]);
found_name = found_desc;
- strncpy(drv->ifname, name[found_desc], sizeof(drv->ifname));
+ os_strncpy(drv->ifname,
+ os_strncmp(name[found_desc], "\\Device\\NPF_", 12)
+ == 0 ? name[found_desc] + 12 : name[found_desc],
+ sizeof(drv->ifname));
}
if (found_name < 0) {
wpa_printf(MSG_DEBUG, "NDIS: Could not find interface '%s'",
drv->ifname);
- free(names);
+ os_free(names);
return -1;
}
i = found_name;
- pos = strchr(desc[i], '(');
+ pos = os_strrchr(desc[i], '(');
if (pos) {
dlen = pos - desc[i];
pos--;
if (pos > desc[i] && *pos == ' ')
dlen--;
} else {
- dlen = strlen(desc[i]);
+ dlen = os_strlen(desc[i]);
}
- drv->adapter_desc = malloc(dlen + 1);
+ drv->adapter_desc = os_malloc(dlen + 1);
if (drv->adapter_desc) {
- memcpy(drv->adapter_desc, desc[i], dlen);
+ os_memcpy(drv->adapter_desc, desc[i], dlen);
drv->adapter_desc[dlen] = '\0';
}
- free(names);
+ os_free(names);
if (drv->adapter_desc == NULL)
return -1;
@@ -1583,6 +2171,500 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
drv->adapter_desc);
return 0;
+#endif /* CONFIG_USE_NDISUIO */
+}
+
+
+#if defined(CONFIG_NATIVE_WINDOWS) || defined(__CYGWIN__)
+#ifndef _WIN32_WCE
+/*
+ * These structures are undocumented for WinXP; only WinCE version is
+ * documented. These would be included wzcsapi.h if it were available. Some
+ * changes here have been needed to make the structures match with WinXP SP2.
+ * It is unclear whether these work with any other version.
+ */
+
+typedef struct {
+ LPWSTR wszGuid;
+} INTF_KEY_ENTRY, *PINTF_KEY_ENTRY;
+
+typedef struct {
+ DWORD dwNumIntfs;
+ PINTF_KEY_ENTRY pIntfs;
+} INTFS_KEY_TABLE, *PINTFS_KEY_TABLE;
+
+typedef struct {
+ DWORD dwDataLen;
+ LPBYTE pData;
+} RAW_DATA, *PRAW_DATA;
+
+typedef struct {
+ LPWSTR wszGuid;
+ LPWSTR wszDescr;
+ ULONG ulMediaState;
+ ULONG ulMediaType;
+ ULONG ulPhysicalMediaType;
+ INT nInfraMode;
+ INT nAuthMode;
+ INT nWepStatus;
+#ifndef _WIN32_WCE
+ u8 pad[2]; /* why is this needed? */
+#endif /* _WIN32_WCE */
+ DWORD dwCtlFlags;
+ DWORD dwCapabilities; /* something added for WinXP SP2(?) */
+ RAW_DATA rdSSID;
+ RAW_DATA rdBSSID;
+ RAW_DATA rdBSSIDList;
+ RAW_DATA rdStSSIDList;
+ RAW_DATA rdCtrlData;
+#ifdef UNDER_CE
+ BOOL bInitialized;
+#endif
+ DWORD nWPAMCastCipher;
+ /* add some extra buffer for later additions since this interface is
+ * far from stable */
+ u8 later_additions[100];
+} INTF_ENTRY, *PINTF_ENTRY;
+
+#define INTF_ALL 0xffffffff
+#define INTF_ALL_FLAGS 0x0000ffff
+#define INTF_CTLFLAGS 0x00000010
+#define INTFCTL_ENABLED 0x8000
+#endif /* _WIN32_WCE */
+
+
+#ifdef _WIN32_WCE
+static int wpa_driver_ndis_rebind_adapter(struct wpa_driver_ndis_data *drv)
+{
+ HANDLE ndis;
+ TCHAR multi[100];
+ int len;
+
+ len = _tcslen(drv->adapter_name);
+ if (len > 80)
+ return -1;
+
+ ndis = CreateFile(DD_NDIS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
+ 0, NULL, OPEN_EXISTING, 0, NULL);
+ if (ndis == INVALID_HANDLE_VALUE) {
+ wpa_printf(MSG_DEBUG, "NDIS: Failed to open file to NDIS "
+ "device: %d", (int) GetLastError());
+ return -1;
+ }
+
+ len++;
+ memcpy(multi, drv->adapter_name, len * sizeof(TCHAR));
+ memcpy(&multi[len], TEXT("NDISUIO\0"), 9 * sizeof(TCHAR));
+ len += 9;
+
+ if (!DeviceIoControl(ndis, IOCTL_NDIS_REBIND_ADAPTER,
+ multi, len * sizeof(TCHAR), NULL, 0, NULL, NULL))
+ {
+ wpa_printf(MSG_DEBUG, "NDIS: IOCTL_NDIS_REBIND_ADAPTER "
+ "failed: 0x%x", (int) GetLastError());
+ wpa_hexdump_ascii(MSG_DEBUG, "NDIS: rebind multi_sz",
+ (u8 *) multi, len * sizeof(TCHAR));
+ CloseHandle(ndis);
+ return -1;
+ }
+
+ CloseHandle(ndis);
+
+ wpa_printf(MSG_DEBUG, "NDIS: Requested NDIS rebind of NDISUIO "
+ "protocol");
+
+ return 0;
+}
+#endif /* _WIN32_WCE */
+
+
+static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
+ int enable)
+{
+#ifdef _WIN32_WCE
+ HKEY hk, hk2;
+ LONG ret;
+ DWORD i, hnd, len;
+ TCHAR keyname[256], devname[256];
+
+#define WZC_DRIVER TEXT("Drivers\\BuiltIn\\ZeroConfig")
+
+ if (enable) {
+ HANDLE h;
+ h = ActivateDeviceEx(WZC_DRIVER, NULL, 0, NULL);
+ if (h == INVALID_HANDLE_VALUE || h == 0) {
+ wpa_printf(MSG_DEBUG, "NDIS: Failed to re-enable WZC "
+ "- ActivateDeviceEx failed: %d",
+ (int) GetLastError());
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "NDIS: WZC re-enabled");
+ return wpa_driver_ndis_rebind_adapter(drv);
+ }
+
+ /*
+ * Unfortunately, just disabling the WZC for an interface is not enough
+ * to free NDISUIO for us, so need to disable and unload WZC completely
+ * for now when using WinCE with NDISUIO. In addition, must request
+ * NDISUIO protocol to be rebound to the adapter in order to free the
+ * NDISUIO binding that WZC hold before us.
+ */
+
+ /* Enumerate HKLM\Drivers\Active\* to find a handle to WZC. */
+ ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, DEVLOAD_ACTIVE_KEY, 0, 0, &hk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(DEVLOAD_ACTIVE_KEY) "
+ "failed: %d %d", (int) ret, (int) GetLastError());
+ return -1;
+ }
+
+ for (i = 0; ; i++) {
+ len = sizeof(keyname);
+ ret = RegEnumKeyEx(hk, i, keyname, &len, NULL, NULL, NULL,
+ NULL);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "NDIS: Could not find active "
+ "WZC - assuming it is not running.");
+ RegCloseKey(hk);
+ return -1;
+ }
+
+ ret = RegOpenKeyEx(hk, keyname, 0, 0, &hk2);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "NDIS: RegOpenKeyEx(active dev) "
+ "failed: %d %d",
+ (int) ret, (int) GetLastError());
+ continue;
+ }
+
+ len = sizeof(devname);
+ ret = RegQueryValueEx(hk2, DEVLOAD_DEVKEY_VALNAME, NULL, NULL,
+ (LPBYTE) devname, &len);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx("
+ "DEVKEY_VALNAME) failed: %d %d",
+ (int) ret, (int) GetLastError());
+ RegCloseKey(hk2);
+ continue;
+ }
+
+ if (_tcscmp(devname, WZC_DRIVER) == 0)
+ break;
+
+ RegCloseKey(hk2);
+ }
+
+ RegCloseKey(hk);
+
+ /* Found WZC - get handle to it. */
+ len = sizeof(hnd);
+ ret = RegQueryValueEx(hk2, DEVLOAD_HANDLE_VALNAME, NULL, NULL,
+ (PUCHAR) &hnd, &len);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "NDIS: RegQueryValueEx(HANDLE_VALNAME) "
+ "failed: %d %d", (int) ret, (int) GetLastError());
+ RegCloseKey(hk2);
+ return -1;
+ }
+
+ RegCloseKey(hk2);
+
+ /* Deactivate WZC */
+ if (!DeactivateDevice((HANDLE) hnd)) {
+ wpa_printf(MSG_DEBUG, "NDIS: DeactivateDevice failed: %d",
+ (int) GetLastError());
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily");
+ drv->wzc_disabled = 1;
+ return wpa_driver_ndis_rebind_adapter(drv);
+
+#else /* _WIN32_WCE */
+
+ HMODULE hm;
+ DWORD (WINAPI *wzc_enum_interf)(LPWSTR pSrvAddr,
+ PINTFS_KEY_TABLE pIntfs);
+ DWORD (WINAPI *wzc_query_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
+ PINTF_ENTRY pIntf,
+ LPDWORD pdwOutFlags);
+ DWORD (WINAPI *wzc_set_interf)(LPWSTR pSrvAddr, DWORD dwInFlags,
+ PINTF_ENTRY pIntf, LPDWORD pdwOutFlags);
+ int ret = -1, j;
+ DWORD res;
+ INTFS_KEY_TABLE guids;
+ INTF_ENTRY intf;
+ char guid[128];
+ WCHAR *pos;
+ DWORD flags, i;
+
+ hm = LoadLibrary(TEXT("wzcsapi.dll"));
+ if (hm == NULL) {
+ wpa_printf(MSG_DEBUG, "NDIS: Failed to load wzcsapi.dll (%u) "
+ "- WZC probably not running",
+ (unsigned int) GetLastError());
+ return -1;
+ }
+
+#ifdef _WIN32_WCE
+ wzc_enum_interf = (void *) GetProcAddressA(hm, "WZCEnumInterfaces");
+ wzc_query_interf = (void *) GetProcAddressA(hm, "WZCQueryInterface");
+ wzc_set_interf = (void *) GetProcAddressA(hm, "WZCSetInterface");
+#else /* _WIN32_WCE */
+ wzc_enum_interf = (void *) GetProcAddress(hm, "WZCEnumInterfaces");
+ wzc_query_interf = (void *) GetProcAddress(hm, "WZCQueryInterface");
+ wzc_set_interf = (void *) GetProcAddress(hm, "WZCSetInterface");
+#endif /* _WIN32_WCE */
+
+ if (wzc_enum_interf == NULL || wzc_query_interf == NULL ||
+ wzc_set_interf == NULL) {
+ wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces, "
+ "WZCQueryInterface, or WZCSetInterface not found "
+ "in wzcsapi.dll");
+ goto fail;
+ }
+
+ os_memset(&guids, 0, sizeof(guids));
+ res = wzc_enum_interf(NULL, &guids);
+ if (res != 0) {
+ wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces failed: %d; "
+ "WZC service is apparently not running",
+ (int) res);
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "NDIS: WZCEnumInterfaces: %d interfaces",
+ (int) guids.dwNumIntfs);
+
+ for (i = 0; i < guids.dwNumIntfs; i++) {
+ pos = guids.pIntfs[i].wszGuid;
+ for (j = 0; j < sizeof(guid); j++) {
+ guid[j] = (char) *pos;
+ if (*pos == 0)
+ break;
+ pos++;
+ }
+ guid[sizeof(guid) - 1] = '\0';
+ wpa_printf(MSG_DEBUG, "NDIS: intfs %d GUID '%s'",
+ (int) i, guid);
+ if (os_strstr(drv->ifname, guid) == NULL)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "NDIS: Current interface found from "
+ "WZC");
+ break;
+ }
+
+ if (i >= guids.dwNumIntfs) {
+ wpa_printf(MSG_DEBUG, "NDIS: Current interface not found from "
+ "WZC");
+ goto fail;
+ }
+
+ os_memset(&intf, 0, sizeof(intf));
+ intf.wszGuid = guids.pIntfs[i].wszGuid;
+ /* Set flags to verify that the structure has not changed. */
+ intf.dwCtlFlags = -1;
+ flags = 0;
+ res = wzc_query_interf(NULL, INTFCTL_ENABLED, &intf, &flags);
+ if (res != 0) {
+ wpa_printf(MSG_DEBUG, "NDIS: Could not query flags for the "
+ "WZC interface: %d (0x%x)",
+ (int) res, (int) res);
+ wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
+ (unsigned int) GetLastError());
+ goto fail;
+ }
+
+ wpa_printf(MSG_DEBUG, "NDIS: WZC interface flags 0x%x dwCtlFlags 0x%x",
+ (int) flags, (int) intf.dwCtlFlags);
+
+ if (intf.dwCtlFlags == -1) {
+ wpa_printf(MSG_DEBUG, "NDIS: Looks like wzcsapi has changed "
+ "again - could not disable WZC");
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: intf",
+ (u8 *) &intf, sizeof(intf));
+ goto fail;
+ }
+
+ if (enable) {
+ if (!(intf.dwCtlFlags & INTFCTL_ENABLED)) {
+ wpa_printf(MSG_DEBUG, "NDIS: Enabling WZC for this "
+ "interface");
+ intf.dwCtlFlags |= INTFCTL_ENABLED;
+ res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
+ &flags);
+ if (res != 0) {
+ wpa_printf(MSG_DEBUG, "NDIS: Failed to enable "
+ "WZC: %d (0x%x)",
+ (int) res, (int) res);
+ wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
+ (unsigned int) GetLastError());
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "NDIS: Re-enabled WZC for this "
+ "interface");
+ drv->wzc_disabled = 0;
+ }
+ } else {
+ if (intf.dwCtlFlags & INTFCTL_ENABLED) {
+ wpa_printf(MSG_DEBUG, "NDIS: Disabling WZC for this "
+ "interface");
+ intf.dwCtlFlags &= ~INTFCTL_ENABLED;
+ res = wzc_set_interf(NULL, INTFCTL_ENABLED, &intf,
+ &flags);
+ if (res != 0) {
+ wpa_printf(MSG_DEBUG, "NDIS: Failed to "
+ "disable WZC: %d (0x%x)",
+ (int) res, (int) res);
+ wpa_printf(MSG_DEBUG, "NDIS: GetLastError: %u",
+ (unsigned int) GetLastError());
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "NDIS: Disabled WZC temporarily "
+ "for this interface");
+ drv->wzc_disabled = 1;
+ } else {
+ wpa_printf(MSG_DEBUG, "NDIS: WZC was not enabled for "
+ "this interface");
+ }
+ }
+
+ ret = 0;
+
+fail:
+ FreeLibrary(hm);
+
+ return ret;
+#endif /* _WIN32_WCE */
+}
+
+#else /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
+
+static int wpa_driver_ndis_set_wzc(struct wpa_driver_ndis_data *drv,
+ int enable)
+{
+ return 0;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS || __CYGWIN__ */
+
+
+#ifdef CONFIG_USE_NDISUIO
+/*
+ * l2_packet_ndis.c is sharing the same handle to NDISUIO, so we must be able
+ * to export this handle. This is somewhat ugly, but there is no better
+ * mechanism available to pass data from driver interface to l2_packet wrapper.
+ */
+static HANDLE driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
+
+HANDLE driver_ndis_get_ndisuio_handle(void)
+{
+ return driver_ndis_ndisuio_handle;
+}
+#endif /* CONFIG_USE_NDISUIO */
+
+
+static int wpa_driver_ndis_adapter_init(struct wpa_driver_ndis_data *drv)
+{
+#ifdef CONFIG_USE_NDISUIO
+#ifndef _WIN32_WCE
+#define NDISUIO_DEVICE_NAME TEXT("\\\\.\\\\Ndisuio")
+ DWORD written;
+#endif /* _WIN32_WCE */
+ drv->ndisuio = CreateFile(NDISUIO_DEVICE_NAME,
+ GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
+ INVALID_HANDLE_VALUE);
+ if (drv->ndisuio == INVALID_HANDLE_VALUE) {
+ wpa_printf(MSG_ERROR, "NDIS: Failed to open connection to "
+ "NDISUIO: %d", (int) GetLastError());
+ return -1;
+ }
+ driver_ndis_ndisuio_handle = drv->ndisuio;
+
+#ifndef _WIN32_WCE
+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_BIND_WAIT, NULL, 0,
+ NULL, 0, &written, NULL)) {
+ wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_BIND_WAIT failed: "
+ "%d", (int) GetLastError());
+ CloseHandle(drv->ndisuio);
+ drv->ndisuio = INVALID_HANDLE_VALUE;
+ return -1;
+ }
+#endif /* _WIN32_WCE */
+
+ return 0;
+#else /* CONFIG_USE_NDISUIO */
+ return 0;
+#endif /* CONFIG_USE_NDISUIO */
+}
+
+
+static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv)
+{
+#ifdef CONFIG_USE_NDISUIO
+ DWORD written;
+#define MAX_NDIS_DEVICE_NAME_LEN 256
+ WCHAR ifname[MAX_NDIS_DEVICE_NAME_LEN];
+ size_t len, i, pos;
+ const char *prefix = "\\DEVICE\\";
+
+#ifdef _WIN32_WCE
+ pos = 0;
+#else /* _WIN32_WCE */
+ pos = 8;
+#endif /* _WIN32_WCE */
+ len = pos + os_strlen(drv->ifname);
+ if (len >= MAX_NDIS_DEVICE_NAME_LEN)
+ return -1;
+ for (i = 0; i < pos; i++)
+ ifname[i] = (WCHAR) prefix[i];
+ for (i = pos; i < len; i++)
+ ifname[i] = (WCHAR) drv->ifname[i - pos];
+ ifname[i] = L'\0';
+
+ if (!DeviceIoControl(drv->ndisuio, IOCTL_NDISUIO_OPEN_DEVICE,
+ ifname, len * sizeof(WCHAR), NULL, 0, &written,
+ NULL)) {
+ wpa_printf(MSG_ERROR, "NDIS: IOCTL_NDISUIO_OPEN_DEVICE "
+ "failed: %d", (int) GetLastError());
+ wpa_hexdump_ascii(MSG_DEBUG, "NDIS: ifname",
+ (const u8 *) ifname, len * sizeof(WCHAR));
+ CloseHandle(drv->ndisuio);
+ drv->ndisuio = INVALID_HANDLE_VALUE;
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "NDIS: Opened NDISUIO device successfully");
+
+ return 0;
+#else /* CONFIG_USE_NDISUIO */
+ char ifname[128];
+ os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", drv->ifname);
+ drv->adapter = PacketOpenAdapter(ifname);
+ if (drv->adapter == NULL) {
+ wpa_printf(MSG_DEBUG, "NDIS: PacketOpenAdapter failed for "
+ "'%s'", ifname);
+ return -1;
+ }
+ return 0;
+#endif /* CONFIG_USE_NDISUIO */
+}
+
+
+static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv)
+{
+#ifdef CONFIG_USE_NDISUIO
+ driver_ndis_ndisuio_handle = INVALID_HANDLE_VALUE;
+ if (drv->ndisuio != INVALID_HANDLE_VALUE)
+ CloseHandle(drv->ndisuio);
+#else /* CONFIG_USE_NDISUIO */
+ if (drv->adapter)
+ PacketCloseAdapter(drv->adapter);
+#endif /* CONFIG_USE_NDISUIO */
}
@@ -1591,24 +2673,38 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
struct wpa_driver_ndis_data *drv;
u32 mode;
- drv = malloc(sizeof(*drv));
+ drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
- memset(drv, 0, sizeof(*drv));
drv->ctx = ctx;
- strncpy(drv->ifname, ifname, sizeof(drv->ifname));
- drv->event_sock = -1;
+ /*
+ * Compatibility code to strip possible prefix from the GUID. Previous
+ * versions include \Device\NPF_ prefix for all names, but the internal
+ * interface name is now only the GUI. Both Packet32 and NDISUIO
+ * prefixes are supported.
+ */
+ if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
+ ifname += 12;
+ else if (os_strncmp(ifname, "\\DEVICE\\", 8) == 0)
+ ifname += 8;
+ os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ if (wpa_driver_ndis_adapter_init(drv) < 0) {
+ os_free(drv);
+ return NULL;
+ }
if (wpa_driver_ndis_get_names(drv) < 0) {
- free(drv);
+ wpa_driver_ndis_adapter_close(drv);
+ os_free(drv);
return NULL;
}
- drv->adapter = PacketOpenAdapter(drv->ifname);
- if (drv->adapter == NULL) {
- wpa_printf(MSG_DEBUG, "NDIS: PacketOpenAdapter failed for "
- "'%s'", drv->ifname);
- free(drv);
+ wpa_driver_ndis_set_wzc(drv, 0);
+
+ if (wpa_driver_ndis_adapter_open(drv) < 0) {
+ wpa_driver_ndis_adapter_close(drv);
+ os_free(drv);
return NULL;
}
@@ -1616,8 +2712,8 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
drv->own_addr, ETH_ALEN) < 0) {
wpa_printf(MSG_DEBUG, "NDIS: Get OID_802_3_CURRENT_ADDRESS "
"failed");
- PacketCloseAdapter(drv->adapter);
- free(drv);
+ wpa_driver_ndis_adapter_close(drv);
+ os_free(drv);
return NULL;
}
wpa_driver_ndis_get_capability(drv);
@@ -1628,7 +2724,23 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
eloop_register_timeout(1, 0, wpa_driver_ndis_poll_timeout, drv, NULL);
- wpa_driver_register_event_cb(drv);
+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+ drv->events = ndis_events_init(&drv->events_pipe, &drv->event_avail,
+ drv->ifname, drv->adapter_desc);
+ if (drv->events == NULL) {
+ wpa_driver_ndis_deinit(drv);
+ return NULL;
+ }
+ eloop_register_event(drv->event_avail, sizeof(drv->event_avail),
+ wpa_driver_ndis_event_pipe_cb, drv, NULL);
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+
+#ifdef _WIN32_WCE
+ if (ndisuio_notification_init(drv) < 0) {
+ wpa_driver_ndis_deinit(drv);
+ return NULL;
+ }
+#endif /* _WIN32_WCE */
/* Set mode here in case card was configured for ad-hoc mode
* previously. */
@@ -1655,6 +2767,20 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
static void wpa_driver_ndis_deinit(void *priv)
{
struct wpa_driver_ndis_data *drv = priv;
+
+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+ if (drv->events) {
+ eloop_unregister_event(drv->event_avail,
+ sizeof(drv->event_avail));
+ ndis_events_deinit(drv->events);
+ }
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+
+#ifdef _WIN32_WCE
+ ndisuio_notification_deinit(drv);
+#endif /* _WIN32_WCE */
+
+ eloop_cancel_timeout(wpa_driver_ndis_scan_timeout, drv, drv->ctx);
eloop_cancel_timeout(wpa_driver_ndis_poll_timeout, drv, NULL);
wpa_driver_ndis_flush_pmkid(drv);
wpa_driver_ndis_disconnect(drv);
@@ -1662,37 +2788,53 @@ static void wpa_driver_ndis_deinit(void *priv)
wpa_printf(MSG_DEBUG, "NDIS: failed to disassociate and turn "
"radio off");
}
- if (drv->event_sock >= 0) {
- eloop_unregister_read_sock(drv->event_sock);
- close(drv->event_sock);
- }
- if (drv->adapter)
- PacketCloseAdapter(drv->adapter);
- free(drv->adapter_desc);
- free(drv);
+ wpa_driver_ndis_adapter_close(drv);
+
+ if (drv->wzc_disabled)
+ wpa_driver_ndis_set_wzc(drv, 1);
+
+#ifdef _WIN32_WCE
+ os_free(drv->adapter_name);
+#endif /* _WIN32_WCE */
+ os_free(drv->adapter_desc);
+ os_free(drv);
}
const struct wpa_driver_ops wpa_driver_ndis_ops = {
- .name = "ndis",
- .desc = "Windows NDIS driver",
- .init = wpa_driver_ndis_init,
- .deinit = wpa_driver_ndis_deinit,
- .set_wpa = wpa_driver_ndis_set_wpa,
- .scan = wpa_driver_ndis_scan,
- .get_scan_results = wpa_driver_ndis_get_scan_results,
- .get_bssid = wpa_driver_ndis_get_bssid,
- .get_ssid = wpa_driver_ndis_get_ssid,
- .set_key = wpa_driver_ndis_set_key,
- .associate = wpa_driver_ndis_associate,
- .deauthenticate = wpa_driver_ndis_deauthenticate,
- .disassociate = wpa_driver_ndis_disassociate,
- .poll = wpa_driver_ndis_poll,
- .add_pmkid = wpa_driver_ndis_add_pmkid,
- .remove_pmkid = wpa_driver_ndis_remove_pmkid,
- .flush_pmkid = wpa_driver_ndis_flush_pmkid,
- .get_capa = wpa_driver_ndis_get_capa,
- .get_ifname = wpa_driver_ndis_get_ifname,
- .get_mac_addr = wpa_driver_ndis_get_mac_addr,
+ "ndis",
+ "Windows NDIS driver",
+ wpa_driver_ndis_get_bssid,
+ wpa_driver_ndis_get_ssid,
+ wpa_driver_ndis_set_wpa,
+ wpa_driver_ndis_set_key,
+ wpa_driver_ndis_init,
+ wpa_driver_ndis_deinit,
+ NULL /* set_param */,
+ NULL /* set_countermeasures */,
+ NULL /* set_drop_unencrypted */,
+ wpa_driver_ndis_scan,
+ wpa_driver_ndis_get_scan_results,
+ wpa_driver_ndis_deauthenticate,
+ wpa_driver_ndis_disassociate,
+ wpa_driver_ndis_associate,
+ NULL /* set_auth_alg */,
+ wpa_driver_ndis_add_pmkid,
+ wpa_driver_ndis_remove_pmkid,
+ wpa_driver_ndis_flush_pmkid,
+ wpa_driver_ndis_get_capa,
+ wpa_driver_ndis_poll,
+ wpa_driver_ndis_get_ifname,
+ wpa_driver_ndis_get_mac_addr,
+ NULL /* send_eapol */,
+ NULL /* set_operstate */,
+ NULL /* mlme_setprotection */,
+ NULL /* get_hw_feature_data */,
+ NULL /* set_channel */,
+ NULL /* set_ssid */,
+ NULL /* set_bssid */,
+ NULL /* send_mlme */,
+ NULL /* mlme_add_sta */,
+ NULL /* mlme_remove_sta */
};
diff --git a/contrib/wpa_supplicant/driver_ndis.h b/contrib/wpa_supplicant/driver_ndis.h
index 7906fdc5b04e..cdce4bac85ab 100644
--- a/contrib/wpa_supplicant/driver_ndis.h
+++ b/contrib/wpa_supplicant/driver_ndis.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Windows/NDIS driver interface
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,14 @@
#ifndef DRIVER_NDIS_H
#define DRIVER_NDIS_H
+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+struct ndis_events_data;
+struct ndis_events_data * ndis_events_init(HANDLE *read_pipe, HANDLE *event,
+ const char *ifname,
+ const char *desc);
+void ndis_events_deinit(struct ndis_events_data *events);
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
+
struct ndis_pmkid_entry {
struct ndis_pmkid_entry *next;
u8 bssid[ETH_ALEN];
@@ -23,9 +31,18 @@ struct ndis_pmkid_entry {
struct wpa_driver_ndis_data {
void *ctx;
- char ifname[100];
+ char ifname[100]; /* GUID: {7EE3EFE5-C165-472F-986D-F6FBEDFE8C8D} */
+#ifdef _WIN32_WCE
+ TCHAR *adapter_name;
+ HANDLE event_queue; /* NDISUIO notifier MsgQueue */
+ HANDLE connected_event; /* WpaSupplicantConnected event */
+#endif /* _WIN32_WCE */
u8 own_addr[ETH_ALEN];
+#ifdef CONFIG_USE_NDISUIO
+ HANDLE ndisuio;
+#else /* CONFIG_USE_NDISUIO */
LPADAPTER adapter;
+#endif /* CONFIG_USE_NDISUIO */
u8 bssid[ETH_ALEN];
int has_capability;
@@ -33,9 +50,15 @@ struct wpa_driver_ndis_data {
int radio_enabled;
struct wpa_driver_capa capa;
struct ndis_pmkid_entry *pmkid;
- int event_sock;
char *adapter_desc;
int wired;
+ int mode;
+ int wzc_disabled;
+ int oid_bssid_set;
+#ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+ HANDLE events_pipe, event_avail;
+ struct ndis_events_data *events;
+#endif /* CONFIG_NDIS_EVENTS_INTEGRATED */
};
#endif /* DRIVER_NDIS_H */
diff --git a/contrib/wpa_supplicant/driver_wired.c b/contrib/wpa_supplicant/driver_wired.c
index 359a21b481bd..f987d3d73f54 100644
--- a/contrib/wpa_supplicant/driver_wired.c
+++ b/contrib/wpa_supplicant/driver_wired.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - wired Ethernet driver interface
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,15 +12,15 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
+#include "includes.h"
#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netpacket/packet.h>
#include <net/if.h>
+#ifdef __linux__
+#include <netpacket/packet.h>
+#endif /* __linux__ */
+#ifdef __FreeBSD__
+#include <net/if_dl.h>
+#endif /* __FreeBSD__ */
#include "common.h"
#include "driver.h"
@@ -39,12 +39,6 @@ struct wpa_driver_wired_data {
};
-static int wpa_driver_wired_set_wpa(void *priv, int enabled)
-{
- return 0;
-}
-
-
static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
{
ssid[0] = 0;
@@ -55,7 +49,7 @@ static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
{
/* Report PAE group address as the "BSSID" for wired connection. */
- memcpy(bssid, pae_group_addr, ETH_ALEN);
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
return 0;
}
@@ -71,8 +65,8 @@ static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
return -1;
}
- memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
perror("ioctl[SIOCGIFFLAGS]");
close(s);
@@ -95,8 +89,8 @@ static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
return -1;
}
- memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
ifr.ifr_flags = flags & 0xffff;
if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
perror("ioctl[SIOCSIFFLAGS]");
@@ -119,10 +113,25 @@ static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
return -1;
}
- memset(&ifr, 0, sizeof(ifr));
- strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+#ifdef __linux__
ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
- memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+#endif /* __linux__ */
+#ifdef __FreeBSD__
+ {
+ struct sockaddr_dl *dlp;
+ dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
+ dlp->sdl_len = sizeof(struct sockaddr_dl);
+ dlp->sdl_family = AF_LINK;
+ dlp->sdl_index = 0;
+ dlp->sdl_nlen = 0;
+ dlp->sdl_alen = ETH_ALEN;
+ dlp->sdl_slen = 0;
+ os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
+ }
+#endif /* __FreeBSD__ */
if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
perror("ioctl[SIOC{ADD/DEL}MULTI]");
@@ -143,11 +152,11 @@ static int wpa_driver_wired_membership(struct wpa_driver_wired_data *drv,
if (drv->pf_sock == -1)
return -1;
- memset(&mreq, 0, sizeof(mreq));
+ os_memset(&mreq, 0, sizeof(mreq));
mreq.mr_ifindex = if_nametoindex(drv->ifname);
mreq.mr_type = PACKET_MR_MULTICAST;
mreq.mr_alen = ETH_ALEN;
- memcpy(mreq.mr_address, addr, ETH_ALEN);
+ os_memcpy(mreq.mr_address, addr, ETH_ALEN);
if (setsockopt(drv->pf_sock, SOL_PACKET,
add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
@@ -167,20 +176,19 @@ static void * wpa_driver_wired_init(void *ctx, const char *ifname)
struct wpa_driver_wired_data *drv;
int flags;
- drv = malloc(sizeof(*drv));
+ drv = os_zalloc(sizeof(*drv));
if (drv == NULL)
return NULL;
- memset(drv, 0, sizeof(*drv));
- strncpy(drv->ifname, ifname, sizeof(drv->ifname));
+ os_strncpy(drv->ifname, ifname, sizeof(drv->ifname));
drv->ctx = ctx;
#ifdef __linux__
drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
if (drv->pf_sock < 0)
perror("socket(PF_PACKET)");
-#else
+#else /* __linux__ */
drv->pf_sock = -1;
-#endif
+#endif /* __linux__ */
if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
!(flags & IFF_UP) &&
@@ -199,7 +207,7 @@ static void * wpa_driver_wired_init(void *ctx, const char *ifname)
} else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
wpa_printf(MSG_INFO, "%s: Could not get interface "
"flags", __func__);
- free(drv);
+ os_free(drv);
return NULL;
} else if (flags & IFF_ALLMULTI) {
wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
@@ -208,7 +216,7 @@ static void * wpa_driver_wired_init(void *ctx, const char *ifname)
flags | IFF_ALLMULTI) < 0) {
wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
__func__);
- free(drv);
+ os_free(drv);
return NULL;
} else {
wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
@@ -256,14 +264,13 @@ static void wpa_driver_wired_deinit(void *priv)
if (drv->pf_sock != -1)
close(drv->pf_sock);
- free(drv);
+ os_free(drv);
}
const struct wpa_driver_ops wpa_driver_wired_ops = {
.name = "wired",
.desc = "wpa_supplicant wired Ethernet driver",
- .set_wpa = wpa_driver_wired_set_wpa,
.get_ssid = wpa_driver_wired_get_ssid,
.get_bssid = wpa_driver_wired_get_bssid,
.init = wpa_driver_wired_init,
diff --git a/contrib/wpa_supplicant/drivers.c b/contrib/wpa_supplicant/drivers.c
index 4fd0509129a5..d7cbbbdc32b9 100644
--- a/contrib/wpa_supplicant/drivers.c
+++ b/contrib/wpa_supplicant/drivers.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / driver interface list
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,12 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
+#include "includes.h"
+#ifdef CONFIG_DRIVER_WEXT
+extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
+#endif /* CONFIG_DRIVER_WEXT */
#ifdef CONFIG_DRIVER_HOSTAP
extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
#endif /* CONFIG_DRIVER_HOSTAP */
@@ -30,9 +33,6 @@ extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
#ifdef CONFIG_DRIVER_ATMEL
extern struct wpa_driver_ops wpa_driver_atmel_ops; /* driver_atmel.c */
#endif /* CONFIG_DRIVER_ATMEL */
-#ifdef CONFIG_DRIVER_WEXT
-extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
-#endif /* CONFIG_DRIVER_WEXT */
#ifdef CONFIG_DRIVER_NDISWRAPPER
/* driver_ndiswrapper.c */
extern struct wpa_driver_ops wpa_driver_ndiswrapper_ops;
@@ -59,6 +59,9 @@ extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
struct wpa_driver_ops *wpa_supplicant_drivers[] =
{
+#ifdef CONFIG_DRIVER_WEXT
+ &wpa_driver_wext_ops,
+#endif /* CONFIG_DRIVER_WEXT */
#ifdef CONFIG_DRIVER_HOSTAP
&wpa_driver_hostap_ops,
#endif /* CONFIG_DRIVER_HOSTAP */
@@ -74,9 +77,6 @@ struct wpa_driver_ops *wpa_supplicant_drivers[] =
#ifdef CONFIG_DRIVER_ATMEL
&wpa_driver_atmel_ops,
#endif /* CONFIG_DRIVER_ATMEL */
-#ifdef CONFIG_DRIVER_WEXT
- &wpa_driver_wext_ops,
-#endif /* CONFIG_DRIVER_WEXT */
#ifdef CONFIG_DRIVER_NDISWRAPPER
&wpa_driver_ndiswrapper_ops,
#endif /* CONFIG_DRIVER_NDISWRAPPER */
diff --git a/contrib/wpa_supplicant/eap.c b/contrib/wpa_supplicant/eap.c
index 5d81870271bd..a5cd9824fc62 100644
--- a/contrib/wpa_supplicant/eap.c
+++ b/contrib/wpa_supplicant/eap.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP state machines (RFC 4137)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer state machines (RFC 4137)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -10,159 +10,46 @@
* license.
*
* See README and COPYING for more details.
+ *
+ * This file implements the Peer State Machine as defined in RFC 4137. The used
+ * states and state transitions match mostly with the RFC. However, there are
+ * couple of additional transitions for working around small issues noticed
+ * during testing. These exceptions are explained in comments within the
+ * functions in this file. The method functions, m.func(), are similar to the
+ * ones used in RFC 4137, but some small changes have used here to optimize
+ * operations and to add functionality needed for fast re-authentication
+ * (session resumption).
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "tls.h"
#include "crypto.h"
#include "pcsc_funcs.h"
#include "wpa_ctrl.h"
+#include "state_machine.h"
+#define STATE_MACHINE_DATA struct eap_sm
+#define STATE_MACHINE_DEBUG_PREFIX "EAP"
#define EAP_MAX_AUTH_ROUNDS 50
-#ifdef EAP_MD5
-extern const struct eap_method eap_method_md5;
-#endif
-#ifdef EAP_TLS
-extern const struct eap_method eap_method_tls;
-#endif
-#ifdef EAP_MSCHAPv2
-extern const struct eap_method eap_method_mschapv2;
-#endif
-#ifdef EAP_PEAP
-extern const struct eap_method eap_method_peap;
-#endif
-#ifdef EAP_TTLS
-extern const struct eap_method eap_method_ttls;
-#endif
-#ifdef EAP_GTC
-extern const struct eap_method eap_method_gtc;
-#endif
-#ifdef EAP_OTP
-extern const struct eap_method eap_method_otp;
-#endif
-#ifdef EAP_SIM
-extern const struct eap_method eap_method_sim;
-#endif
-#ifdef EAP_LEAP
-extern const struct eap_method eap_method_leap;
-#endif
-#ifdef EAP_PSK
-extern const struct eap_method eap_method_psk;
-#endif
-#ifdef EAP_AKA
-extern const struct eap_method eap_method_aka;
-#endif
-#ifdef EAP_FAST
-extern const struct eap_method eap_method_fast;
-#endif
-#ifdef EAP_PAX
-extern const struct eap_method eap_method_pax;
-#endif
-
-static const struct eap_method *eap_methods[] =
-{
-#ifdef EAP_MD5
- &eap_method_md5,
-#endif
-#ifdef EAP_TLS
- &eap_method_tls,
-#endif
-#ifdef EAP_MSCHAPv2
- &eap_method_mschapv2,
-#endif
-#ifdef EAP_PEAP
- &eap_method_peap,
-#endif
-#ifdef EAP_TTLS
- &eap_method_ttls,
-#endif
-#ifdef EAP_GTC
- &eap_method_gtc,
-#endif
-#ifdef EAP_OTP
- &eap_method_otp,
-#endif
-#ifdef EAP_SIM
- &eap_method_sim,
-#endif
-#ifdef EAP_LEAP
- &eap_method_leap,
-#endif
-#ifdef EAP_PSK
- &eap_method_psk,
-#endif
-#ifdef EAP_AKA
- &eap_method_aka,
-#endif
-#ifdef EAP_FAST
- &eap_method_fast,
-#endif
-#ifdef EAP_PAX
- &eap_method_pax,
-#endif
-};
-#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
-
-
-/**
- * eap_sm_get_eap_methods - Get EAP method based on type number
- * @method: EAP type number
- * Returns: Pointer to EAP method of %NULL if not found
- */
-const struct eap_method * eap_sm_get_eap_methods(int method)
-{
- int i;
- for (i = 0; i < NUM_EAP_METHODS; i++) {
- if (eap_methods[i]->method == method)
- return eap_methods[i];
- }
- return NULL;
-}
-
-
-static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method);
+static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+ EapType method);
static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len);
-static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
- size_t len);
-static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len);
-static u8 * eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len);
+static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req);
+static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req);
+static u8 * eap_sm_buildNotify(int id, size_t *len);
static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len);
-static const char * eap_sm_method_state_txt(int state);
-static const char * eap_sm_decision_txt(int decision);
-
-
-/* Definitions for clarifying state machine implementation */
-#define SM_STATE(machine, state) \
-static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
- int global)
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static const char * eap_sm_method_state_txt(EapMethodState state);
+static const char * eap_sm_decision_txt(EapDecision decision);
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
-#define SM_ENTRY(machine, state) \
-if (!global || sm->machine ## _state != machine ## _ ## state) { \
- sm->changed = TRUE; \
- wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
-} \
-sm->machine ## _state = machine ## _ ## state;
-
-#define SM_ENTER(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 0)
-#define SM_ENTER_GLOBAL(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 1)
-
-#define SM_STEP(machine) \
-static void sm_ ## machine ## _Step(struct eap_sm *sm)
-
-#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
@@ -210,6 +97,11 @@ static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
}
+/*
+ * This state initializes state machine variables when the machine is
+ * activated (portEnabled = TRUE). This is also used when re-starting
+ * authentication (eapRestart == TRUE).
+ */
SM_STATE(EAP, INITIALIZE)
{
SM_ENTRY(EAP, INITIALIZE);
@@ -228,7 +120,7 @@ SM_STATE(EAP, INITIALIZE)
eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
eapol_set_bool(sm, EAPOL_eapFail, FALSE);
- free(sm->eapKeyData);
+ os_free(sm->eapKeyData);
sm->eapKeyData = NULL;
sm->eapKeyAvailable = FALSE;
eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
@@ -248,6 +140,11 @@ SM_STATE(EAP, INITIALIZE)
}
+/*
+ * This state is reached whenever service from the lower layer is interrupted
+ * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
+ * occurs when the port becomes enabled.
+ */
SM_STATE(EAP, DISABLED)
{
SM_ENTRY(EAP, DISABLED);
@@ -255,12 +152,21 @@ SM_STATE(EAP, DISABLED)
}
+/*
+ * The state machine spends most of its time here, waiting for something to
+ * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and
+ * SEND_RESPONSE states.
+ */
SM_STATE(EAP, IDLE)
{
SM_ENTRY(EAP, IDLE);
}
+/*
+ * This state is entered when an EAP packet is received (eapReq == TRUE) to
+ * parse the packet header.
+ */
SM_STATE(EAP, RECEIVED)
{
const u8 *eapReqData;
@@ -274,72 +180,110 @@ SM_STATE(EAP, RECEIVED)
}
+/*
+ * This state is entered when a request for a new type comes in. Either the
+ * correct method is started, or a Nak response is built.
+ */
SM_STATE(EAP, GET_METHOD)
{
+ int reinit;
+ EapType method;
+
SM_ENTRY(EAP, GET_METHOD);
- if (eap_sm_allowMethod(sm, sm->reqMethod)) {
- int reinit = 0;
- if (sm->fast_reauth &&
- sm->m && sm->m->method == sm->reqMethod &&
- sm->m->has_reauth_data &&
- sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
- wpa_printf(MSG_DEBUG, "EAP: using previous method data"
- " for fast re-authentication");
- reinit = 1;
- } else
- eap_deinit_prev_method(sm, "GET_METHOD");
- sm->selectedMethod = sm->reqMethod;
- if (sm->m == NULL)
- sm->m = eap_sm_get_eap_methods(sm->selectedMethod);
- if (sm->m) {
- wpa_printf(MSG_DEBUG, "EAP: initialize selected EAP "
- "method (%d, %s)",
- sm->selectedMethod, sm->m->name);
- if (reinit)
- sm->eap_method_priv = sm->m->init_for_reauth(
- sm, sm->eap_method_priv);
- else
- sm->eap_method_priv = sm->m->init(sm);
- if (sm->eap_method_priv == NULL) {
- struct wpa_ssid *config = eap_get_config(sm);
- wpa_msg(sm->msg_ctx, MSG_INFO,
- "EAP: Failed to initialize EAP method "
- "%d (%s)",
- sm->selectedMethod, sm->m->name);
- sm->m = NULL;
- sm->methodState = METHOD_NONE;
- sm->selectedMethod = EAP_TYPE_NONE;
- if (sm->reqMethod == EAP_TYPE_TLS &&
- config &&
- (config->pending_req_pin ||
- config->pending_req_passphrase)) {
- /*
- * Return without generating Nak in
- * order to allow entering of PIN code
- * or passphrase to retry the current
- * EAP packet.
- */
- wpa_printf(MSG_DEBUG, "EAP: Pending "
- "PIN/passphrase request - "
- "skip Nak");
- return;
- }
- } else {
- sm->methodState = METHOD_INIT;
- wpa_msg(sm->msg_ctx, MSG_INFO,
- WPA_EVENT_EAP_METHOD
- "EAP method %d (%s) selected",
- sm->selectedMethod, sm->m->name);
- return;
- }
+
+ if (sm->reqMethod == EAP_TYPE_EXPANDED)
+ method = sm->reqVendorMethod;
+ else
+ method = sm->reqMethod;
+
+ if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
+ wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
+ sm->reqVendor, method);
+ goto nak;
+ }
+
+ /*
+ * RFC 4137 does not define specific operation for fast
+ * re-authentication (session resumption). The design here is to allow
+ * the previously used method data to be maintained for
+ * re-authentication if the method support session resumption.
+ * Otherwise, the previously used method data is freed and a new method
+ * is allocated here.
+ */
+ if (sm->fast_reauth &&
+ sm->m && sm->m->vendor == sm->reqVendor &&
+ sm->m->method == method &&
+ sm->m->has_reauth_data &&
+ sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
+ wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
+ " for fast re-authentication");
+ reinit = 1;
+ } else {
+ eap_deinit_prev_method(sm, "GET_METHOD");
+ reinit = 0;
+ }
+
+ sm->selectedMethod = sm->reqMethod;
+ if (sm->m == NULL)
+ sm->m = eap_sm_get_eap_methods(sm->reqVendor, method);
+ if (!sm->m) {
+ wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
+ "vendor %d method %d",
+ sm->reqVendor, method);
+ goto nak;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
+ "vendor %u method %u (%s)",
+ sm->reqVendor, method, sm->m->name);
+ if (reinit)
+ sm->eap_method_priv = sm->m->init_for_reauth(
+ sm, sm->eap_method_priv);
+ else
+ sm->eap_method_priv = sm->m->init(sm);
+
+ if (sm->eap_method_priv == NULL) {
+ struct wpa_ssid *config = eap_get_config(sm);
+ wpa_msg(sm->msg_ctx, MSG_INFO,
+ "EAP: Failed to initialize EAP method: vendor %u "
+ "method %u (%s)",
+ sm->reqVendor, method, sm->m->name);
+ sm->m = NULL;
+ sm->methodState = METHOD_NONE;
+ sm->selectedMethod = EAP_TYPE_NONE;
+ if (sm->reqMethod == EAP_TYPE_TLS && config &&
+ (config->pending_req_pin ||
+ config->pending_req_passphrase)) {
+ /*
+ * Return without generating Nak in order to allow
+ * entering of PIN code or passphrase to retry the
+ * current EAP packet.
+ */
+ wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase "
+ "request - skip Nak");
+ return;
}
+
+ goto nak;
}
- free(sm->eapRespData);
+ sm->methodState = METHOD_INIT;
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD
+ "EAP vendor %u method %u (%s) selected",
+ sm->reqVendor, method, sm->m->name);
+ return;
+
+nak:
+ os_free(sm->eapRespData);
+ sm->eapRespData = NULL;
sm->eapRespData = eap_sm_buildNak(sm, sm->reqId, &sm->eapRespDataLen);
}
+/*
+ * The method processing happens here. The request from the authenticator is
+ * processed, and an appropriate response packet is built.
+ */
SM_STATE(EAP, METHOD)
{
u8 *eapReqData;
@@ -354,14 +298,27 @@ SM_STATE(EAP, METHOD)
eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
- /* Get ignore, methodState, decision, allowNotifications, and
- * eapRespData. */
- memset(&ret, 0, sizeof(ret));
+ /*
+ * Get ignore, methodState, decision, allowNotifications, and
+ * eapRespData. RFC 4137 uses three separate method procedure (check,
+ * process, and buildResp) in this state. These have been combined into
+ * a single function call to m->process() in order to optimize EAP
+ * method implementation interface a bit. These procedures are only
+ * used from within this METHOD state, so there is no need to keep
+ * these as separate C functions.
+ *
+ * The RFC 4137 procedures return values as follows:
+ * ignore = m.check(eapReqData)
+ * (methodState, decision, allowNotifications) = m.process(eapReqData)
+ * eapRespData = m.buildResp(reqId)
+ */
+ os_memset(&ret, 0, sizeof(ret));
ret.ignore = sm->ignore;
ret.methodState = sm->methodState;
ret.decision = sm->decision;
ret.allowNotifications = sm->allowNotifications;
- free(sm->eapRespData);
+ os_free(sm->eapRespData);
+ sm->eapRespData = NULL;
sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
eapReqData, eapReqDataLen,
&sm->eapRespDataLen);
@@ -380,25 +337,29 @@ SM_STATE(EAP, METHOD)
if (sm->m->isKeyAvailable && sm->m->getKey &&
sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
- free(sm->eapKeyData);
+ os_free(sm->eapKeyData);
sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
&sm->eapKeyDataLen);
}
}
+/*
+ * This state signals the lower layer that a response packet is ready to be
+ * sent.
+ */
SM_STATE(EAP, SEND_RESPONSE)
{
SM_ENTRY(EAP, SEND_RESPONSE);
- free(sm->lastRespData);
+ os_free(sm->lastRespData);
if (sm->eapRespData) {
if (sm->workaround)
- memcpy(sm->last_md5, sm->req_md5, 16);
+ os_memcpy(sm->last_md5, sm->req_md5, 16);
sm->lastId = sm->reqId;
- sm->lastRespData = malloc(sm->eapRespDataLen);
+ sm->lastRespData = os_malloc(sm->eapRespDataLen);
if (sm->lastRespData) {
- memcpy(sm->lastRespData, sm->eapRespData,
- sm->eapRespDataLen);
+ os_memcpy(sm->lastRespData, sm->eapRespData,
+ sm->eapRespDataLen);
sm->lastRespDataLen = sm->eapRespDataLen;
}
eapol_set_bool(sm, EAPOL_eapResp, TRUE);
@@ -409,6 +370,10 @@ SM_STATE(EAP, SEND_RESPONSE)
}
+/*
+ * This state signals the lower layer that the request was discarded, and no
+ * response packet will be sent at this time.
+ */
SM_STATE(EAP, DISCARD)
{
SM_ENTRY(EAP, DISCARD);
@@ -417,6 +382,9 @@ SM_STATE(EAP, DISCARD)
}
+/*
+ * Handles requests for Identity method and builds a response.
+ */
SM_STATE(EAP, IDENTITY)
{
const u8 *eapReqData;
@@ -424,13 +392,17 @@ SM_STATE(EAP, IDENTITY)
SM_ENTRY(EAP, IDENTITY);
eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
- eap_sm_processIdentity(sm, eapReqData, eapReqDataLen);
- free(sm->eapRespData);
+ eap_sm_processIdentity(sm, eapReqData);
+ os_free(sm->eapRespData);
+ sm->eapRespData = NULL;
sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId,
&sm->eapRespDataLen, 0);
}
+/*
+ * Handles requests for Notification method and builds a response.
+ */
SM_STATE(EAP, NOTIFICATION)
{
const u8 *eapReqData;
@@ -438,22 +410,25 @@ SM_STATE(EAP, NOTIFICATION)
SM_ENTRY(EAP, NOTIFICATION);
eapReqData = eapol_get_eapReqData(sm, &eapReqDataLen);
- eap_sm_processNotify(sm, eapReqData, eapReqDataLen);
- free(sm->eapRespData);
- sm->eapRespData = eap_sm_buildNotify(sm, sm->reqId,
- &sm->eapRespDataLen);
+ eap_sm_processNotify(sm, eapReqData);
+ os_free(sm->eapRespData);
+ sm->eapRespData = NULL;
+ sm->eapRespData = eap_sm_buildNotify(sm->reqId, &sm->eapRespDataLen);
}
+/*
+ * This state retransmits the previous response packet.
+ */
SM_STATE(EAP, RETRANSMIT)
{
SM_ENTRY(EAP, RETRANSMIT);
- free(sm->eapRespData);
+ os_free(sm->eapRespData);
if (sm->lastRespData) {
- sm->eapRespData = malloc(sm->lastRespDataLen);
+ sm->eapRespData = os_malloc(sm->lastRespDataLen);
if (sm->eapRespData) {
- memcpy(sm->eapRespData, sm->lastRespData,
- sm->lastRespDataLen);
+ os_memcpy(sm->eapRespData, sm->lastRespData,
+ sm->lastRespDataLen);
sm->eapRespDataLen = sm->lastRespDataLen;
}
} else
@@ -461,6 +436,11 @@ SM_STATE(EAP, RETRANSMIT)
}
+/*
+ * This state is entered in case of a successful completion of authentication
+ * and state machine waits here until port is disabled or EAP authentication is
+ * restarted.
+ */
SM_STATE(EAP, SUCCESS)
{
SM_ENTRY(EAP, SUCCESS);
@@ -488,6 +468,10 @@ SM_STATE(EAP, SUCCESS)
}
+/*
+ * This state is entered in case of a failure and state machine waits here
+ * until port is disabled or EAP authentication is restarted.
+ */
SM_STATE(EAP, FAILURE)
{
SM_ENTRY(EAP, FAILURE);
@@ -538,6 +522,9 @@ static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
}
+/*
+ * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions
+ */
SM_STEP(EAP)
{
int duplicate;
@@ -548,6 +535,14 @@ SM_STEP(EAP)
else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
SM_ENTER_GLOBAL(EAP, DISABLED);
else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
+ /* RFC 4137 does not place any limit on number of EAP messages
+ * in an authentication session. However, some error cases have
+ * ended up in a state were EAP messages were sent between the
+ * peer and server in a loop (e.g., TLS ACK frame in both
+ * direction). Since this is quite undesired outcome, limit the
+ * total number of EAP round-trips and abort authentication if
+ * this limit is exceeded.
+ */
if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
"authentication rounds - abort",
@@ -565,6 +560,11 @@ SM_STEP(EAP)
SM_ENTER(EAP, INITIALIZE);
break;
case EAP_IDLE:
+ /*
+ * The first three transitions are from RFC 4137. The last two
+ * are local additions to handle special cases with LEAP and
+ * PEAP server not sending EAP-Success in some cases.
+ */
if (eapol_get_bool(sm, EAPOL_eapReq))
SM_ENTER(EAP, RECEIVED);
else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
@@ -591,7 +591,7 @@ SM_STEP(EAP)
case EAP_RECEIVED:
duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
if (sm->workaround && duplicate &&
- memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
+ os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
/*
* RFC 4137 uses (reqId == lastId) as the only
* verification for duplicate EAP requests. However,
@@ -608,10 +608,15 @@ SM_STEP(EAP)
duplicate = 0;
}
- if (sm->rxSuccess &&
+ /*
+ * Two special cases below for LEAP are local additions to work
+ * around odd LEAP behavior (EAP-Success in the middle of
+ * authentication and then swapped roles). Other transitions
+ * are based on RFC 4137.
+ */
+ if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
(sm->reqId == sm->lastId ||
- eap_success_workaround(sm, sm->reqId, sm->lastId)) &&
- sm->decision != DECISION_FAIL)
+ eap_success_workaround(sm, sm->reqId, sm->lastId)))
SM_ENTER(EAP, SUCCESS);
else if (sm->methodState != METHOD_CONT &&
((sm->rxFailure &&
@@ -682,32 +687,108 @@ SM_STEP(EAP)
}
-static Boolean eap_sm_allowMethod(struct eap_sm *sm, EapType method)
+static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+ EapType method)
{
struct wpa_ssid *config = eap_get_config(sm);
- int i;
- if (!wpa_config_allowed_eap_method(config, method))
+ if (!wpa_config_allowed_eap_method(config, vendor, method)) {
+ wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
+ "vendor %u method %u", vendor, method);
return FALSE;
- for (i = 0; i < NUM_EAP_METHODS; i++) {
- if (eap_methods[i]->method == method)
- return TRUE;
}
+ if (eap_sm_get_eap_methods(vendor, method))
+ return TRUE;
+ wpa_printf(MSG_DEBUG, "EAP: not included in build: "
+ "vendor %u method %u", vendor, method);
return FALSE;
}
-static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
+static u8 * eap_sm_build_expanded_nak(struct eap_sm *sm, int id, size_t *len,
+ const struct eap_method *methods,
+ size_t count)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_hdr *resp;
+ u8 *pos;
+ int found = 0;
+ const struct eap_method *m;
+
+ wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak");
+
+ /* RFC 3748 - 5.3.2: Expanded Nak */
+ *len = sizeof(struct eap_hdr) + 8;
+ resp = os_malloc(*len + 8 * (count + 1));
+ if (resp == NULL)
+ return NULL;
+
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = id;
+ pos = (u8 *) (resp + 1);
+ *pos++ = EAP_TYPE_EXPANDED;
+ WPA_PUT_BE24(pos, EAP_VENDOR_IETF);
+ pos += 3;
+ WPA_PUT_BE32(pos, EAP_TYPE_NAK);
+ pos += 4;
+
+ for (m = methods; m; m = m->next) {
+ if (sm->reqVendor == m->vendor &&
+ sm->reqVendorMethod == m->method)
+ continue; /* do not allow the current method again */
+ if (wpa_config_allowed_eap_method(config, m->vendor,
+ m->method)) {
+ wpa_printf(MSG_DEBUG, "EAP: allowed type: "
+ "vendor=%u method=%u",
+ m->vendor, m->method);
+ *pos++ = EAP_TYPE_EXPANDED;
+ WPA_PUT_BE24(pos, m->vendor);
+ pos += 3;
+ WPA_PUT_BE32(pos, m->method);
+ pos += 4;
+
+ (*len) += 8;
+ found++;
+ }
+ }
+ if (!found) {
+ wpa_printf(MSG_DEBUG, "EAP: no more allowed methods");
+ *pos++ = EAP_TYPE_EXPANDED;
+ WPA_PUT_BE24(pos, EAP_VENDOR_IETF);
+ pos += 3;
+ WPA_PUT_BE32(pos, EAP_TYPE_NONE);
+ pos += 4;
+
+ (*len) += 8;
+ }
+
+ resp->length = host_to_be16(*len);
+
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
{
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *resp;
u8 *pos;
- int i, found = 0;
+ int found = 0, expanded_found = 0;
+ size_t count;
+ const struct eap_method *methods, *m;
+
+ wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u "
+ "vendor=%u method=%u not allowed)", sm->reqMethod,
+ sm->reqVendor, sm->reqVendorMethod);
+ methods = eap_peer_get_methods(&count);
+ if (methods == NULL)
+ return NULL;
+ if (sm->reqMethod == EAP_TYPE_EXPANDED)
+ return eap_sm_build_expanded_nak(sm, id, len, methods, count);
- wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %d not "
- "allowed)", sm->reqMethod);
+ /* RFC 3748 - 5.3.1: Legacy Nak */
*len = sizeof(struct eap_hdr) + 1;
- resp = malloc(*len + NUM_EAP_METHODS);
+ resp = os_malloc(*len + count + 1);
if (resp == NULL)
return NULL;
@@ -716,11 +797,18 @@ static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
pos = (u8 *) (resp + 1);
*pos++ = EAP_TYPE_NAK;
- for (i = 0; i < NUM_EAP_METHODS; i++) {
- if (eap_methods[i]->method != sm->reqMethod &&
- wpa_config_allowed_eap_method(config,
- eap_methods[i]->method)) {
- *pos++ = eap_methods[i]->method;
+ for (m = methods; m; m = m->next) {
+ if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod)
+ continue; /* do not allow the current method again */
+ if (wpa_config_allowed_eap_method(config, m->vendor,
+ m->method)) {
+ if (m->vendor != EAP_VENDOR_IETF) {
+ if (expanded_found)
+ continue;
+ expanded_found = 1;
+ *pos++ = EAP_TYPE_EXPANDED;
+ } else
+ *pos++ = m->method;
(*len)++;
found++;
}
@@ -738,8 +826,7 @@ static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
}
-static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
- size_t len)
+static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req)
{
const struct eap_hdr *hdr = (const struct eap_hdr *) req;
const u8 *pos = (const u8 *) (hdr + 1);
@@ -748,6 +835,13 @@ static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
"EAP authentication started");
+ /*
+ * RFC 3748 - 5.1: Identity
+ * Data field may contain a displayable message in UTF-8. If this
+ * includes NUL-character, only the data before that should be
+ * displayed. Some EAP implementasitons may piggy-back additional
+ * options after the NUL.
+ */
/* TODO: could save displayable message so that it can be shown to the
* user in case of interaction is required */
wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
@@ -755,12 +849,14 @@ static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
}
+#ifdef PCSC_FUNCS
static int eap_sm_imsi_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
{
int aka = 0;
char imsi[100];
size_t imsi_len;
- u8 *pos = ssid->eap_methods;
+ struct eap_method_type *m = ssid->eap_methods;
+ int i;
imsi_len = sizeof(imsi);
if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
@@ -770,16 +866,17 @@ static int eap_sm_imsi_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
- while (pos && *pos != EAP_TYPE_NONE) {
- if (*pos == EAP_TYPE_AKA) {
+ for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
+ m[i].method != EAP_TYPE_NONE); i++) {
+ if (m[i].vendor == EAP_VENDOR_IETF &&
+ m[i].method == EAP_TYPE_AKA) {
aka = 1;
break;
}
- pos++;
}
- free(ssid->identity);
- ssid->identity = malloc(1 + imsi_len);
+ os_free(ssid->identity);
+ ssid->identity = os_malloc(1 + imsi_len);
if (ssid->identity == NULL) {
wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
"IMSI-based identity");
@@ -787,28 +884,34 @@ static int eap_sm_imsi_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
}
ssid->identity[0] = aka ? '0' : '1';
- memcpy(ssid->identity + 1, imsi, imsi_len);
+ os_memcpy(ssid->identity + 1, imsi, imsi_len);
ssid->identity_len = 1 + imsi_len;
+
return 0;
}
+#endif /* PCSC_FUNCS */
static int eap_sm_get_scard_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
{
+#ifdef PCSC_FUNCS
if (scard_set_pin(sm->scard_ctx, ssid->pin)) {
/*
* Make sure the same PIN is not tried again in order to avoid
* blocking SIM.
*/
- free(ssid->pin);
+ os_free(ssid->pin);
ssid->pin = NULL;
wpa_printf(MSG_WARNING, "PIN validation failed");
- eap_sm_request_pin(sm, ssid);
+ eap_sm_request_pin(sm);
return -1;
}
return eap_sm_imsi_identity(sm, ssid);
+#else /* PCSC_FUNCS */
+ return -1;
+#endif /* PCSC_FUNCS */
}
@@ -816,8 +919,8 @@ static int eap_sm_get_scard_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
* eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* @id: EAP identifier for the packet
- * @len: Pointer to variable that will be set to the length of the response
- * @encrypted: Whether the packet is for enrypted tunnel (EAP phase 2)
+ * @len: Pointer to a variable that will be set to the length of the response
+ * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2)
* Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
* failure
*
@@ -867,14 +970,13 @@ u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
"IMSI", identity, identity_len);
} else {
- eap_sm_request_identity(sm, config);
+ eap_sm_request_identity(sm);
return NULL;
}
}
-
*len = sizeof(struct eap_hdr) + 1 + identity_len;
- resp = malloc(*len);
+ resp = os_malloc(*len);
if (resp == NULL)
return NULL;
@@ -883,19 +985,18 @@ u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
resp->length = host_to_be16(*len);
pos = (u8 *) (resp + 1);
*pos++ = EAP_TYPE_IDENTITY;
- memcpy(pos, identity, identity_len);
+ os_memcpy(pos, identity, identity_len);
return (u8 *) resp;
}
-static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len)
+static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req)
{
const struct eap_hdr *hdr = (const struct eap_hdr *) req;
const u8 *pos;
char *msg;
- size_t msg_len;
- int i;
+ size_t i, msg_len;
pos = (const u8 *) (hdr + 1);
pos++;
@@ -907,7 +1008,7 @@ static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len)
wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
pos, msg_len);
- msg = malloc(msg_len + 1);
+ msg = os_malloc(msg_len + 1);
if (msg == NULL)
return;
for (i = 0; i < msg_len; i++)
@@ -915,18 +1016,18 @@ static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len)
msg[msg_len] = '\0';
wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
WPA_EVENT_EAP_NOTIFICATION, msg);
- free(msg);
+ os_free(msg);
}
-static u8 *eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len)
+static u8 * eap_sm_buildNotify(int id, size_t *len)
{
struct eap_hdr *resp;
u8 *pos;
wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
*len = sizeof(struct eap_hdr) + 1;
- resp = malloc(*len);
+ resp = os_malloc(*len);
if (resp == NULL)
return NULL;
@@ -944,10 +1045,13 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len)
{
const struct eap_hdr *hdr;
size_t plen;
+ const u8 *pos;
- sm->rxReq = sm->rxSuccess = sm->rxFailure = FALSE;
+ sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
sm->reqId = 0;
sm->reqMethod = EAP_TYPE_NONE;
+ sm->reqVendor = EAP_VENDOR_IETF;
+ sm->reqVendorMethod = EAP_TYPE_NONE;
if (req == NULL || len < sizeof(*hdr))
return;
@@ -964,22 +1068,50 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len)
sm->reqId = hdr->identifier;
if (sm->workaround) {
- md5_vector(1, (const u8 **) &req, &len, sm->req_md5);
+ md5_vector(1, (const u8 **) &req, &plen, sm->req_md5);
}
switch (hdr->code) {
case EAP_CODE_REQUEST:
+ if (plen < sizeof(*hdr) + 1) {
+ wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - "
+ "no Type field");
+ return;
+ }
sm->rxReq = TRUE;
- if (plen > sizeof(*hdr))
- sm->reqMethod = *((u8 *) (hdr + 1));
- wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request method=%d "
- "id=%d", sm->reqMethod, sm->reqId);
+ pos = (const u8 *) (hdr + 1);
+ sm->reqMethod = *pos++;
+ if (sm->reqMethod == EAP_TYPE_EXPANDED) {
+ if (plen < sizeof(*hdr) + 8) {
+ wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
+ "expanded EAP-Packet (plen=%lu)",
+ (unsigned long) plen);
+ return;
+ }
+ sm->reqVendor = WPA_GET_BE24(pos);
+ pos += 3;
+ sm->reqVendorMethod = WPA_GET_BE32(pos);
+ }
+ wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d "
+ "method=%u vendor=%u vendorMethod=%u",
+ sm->reqId, sm->reqMethod, sm->reqVendor,
+ sm->reqVendorMethod);
break;
case EAP_CODE_RESPONSE:
if (sm->selectedMethod == EAP_TYPE_LEAP) {
+ /*
+ * LEAP differs from RFC 4137 by using reversed roles
+ * for mutual authentication and because of this, we
+ * need to accept EAP-Response frames if LEAP is used.
+ */
+ if (plen < sizeof(*hdr) + 1) {
+ wpa_printf(MSG_DEBUG, "EAP: Too short "
+ "EAP-Response - no Type field");
+ return;
+ }
sm->rxResp = TRUE;
- if (plen > sizeof(*hdr))
- sm->reqMethod = *((u8 *) (hdr + 1));
+ pos = (const u8 *) (hdr + 1);
+ sm->reqMethod = *pos;
wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
"LEAP method=%d id=%d",
sm->reqMethod, sm->reqId);
@@ -1012,7 +1144,10 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len)
* Returns: Pointer to the allocated EAP state machine or %NULL on failure
*
* This function allocates and initializes an EAP state machine. In addition,
- * this initializes TLS library for the new EAP state machine.
+ * this initializes TLS library for the new EAP state machine. eapol_cb pointer
+ * will be in use until eap_sm_deinit() is used to deinitialize this EAP state
+ * machine. Consequently, the caller must make sure that this data structure
+ * remains alive while the EAP state machine is active.
*/
struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
void *msg_ctx, struct eap_config *conf)
@@ -1020,16 +1155,15 @@ struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
struct eap_sm *sm;
struct tls_config tlsconf;
- sm = malloc(sizeof(*sm));
+ sm = os_zalloc(sizeof(*sm));
if (sm == NULL)
return NULL;
- memset(sm, 0, sizeof(*sm));
sm->eapol_ctx = eapol_ctx;
sm->eapol_cb = eapol_cb;
sm->msg_ctx = msg_ctx;
sm->ClientTimeout = 60;
- memset(&tlsconf, 0, sizeof(tlsconf));
+ os_memset(&tlsconf, 0, sizeof(tlsconf));
tlsconf.opensc_engine_path = conf->opensc_engine_path;
tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
@@ -1037,7 +1171,7 @@ struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
if (sm->ssl_ctx == NULL) {
wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
"context.");
- free(sm);
+ os_free(sm);
return NULL;
}
@@ -1057,11 +1191,9 @@ void eap_sm_deinit(struct eap_sm *sm)
if (sm == NULL)
return;
eap_deinit_prev_method(sm, "EAP deinit");
- free(sm->lastRespData);
- free(sm->eapRespData);
- free(sm->eapKeyData);
+ eap_sm_abort(sm);
tls_deinit(sm->ssl_ctx);
- free(sm);
+ os_free(sm);
}
@@ -1096,13 +1228,21 @@ int eap_sm_step(struct eap_sm *sm)
*/
void eap_sm_abort(struct eap_sm *sm)
{
- free(sm->eapRespData);
+ os_free(sm->lastRespData);
+ sm->lastRespData = NULL;
+ os_free(sm->eapRespData);
sm->eapRespData = NULL;
- free(sm->eapKeyData);
+ os_free(sm->eapKeyData);
sm->eapKeyData = NULL;
+
+ /* This is not clearly specified in the EAP statemachines draft, but
+ * it seems necessary to make sure that some of the EAPOL variables get
+ * cleared for the next authentication. */
+ eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
}
+#ifdef CONFIG_CTRL_IFACE
static const char * eap_sm_state_txt(int state)
{
switch (state) {
@@ -1136,9 +1276,11 @@ static const char * eap_sm_state_txt(int state)
return "UNKNOWN";
}
}
+#endif /* CONFIG_CTRL_IFACE */
-static const char * eap_sm_method_state_txt(int state)
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static const char * eap_sm_method_state_txt(EapMethodState state)
{
switch (state) {
case METHOD_NONE:
@@ -1157,7 +1299,7 @@ static const char * eap_sm_method_state_txt(int state)
}
-static const char * eap_sm_decision_txt(int decision)
+static const char * eap_sm_decision_txt(EapDecision decision)
{
switch (decision) {
case DECISION_FAIL:
@@ -1170,15 +1312,18 @@ static const char * eap_sm_decision_txt(int decision)
return "UNKNOWN";
}
}
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#ifdef CONFIG_CTRL_IFACE
+
/**
* eap_sm_get_status - Get EAP state machine status
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
- * @buf: buffer for status information
- * @buflen: maximum buffer length
- * @verbose: whether to include verbose status information
- * Returns: number of bytes written to buf.
+ * @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 state machine for status information. This function fills in a
* text area with current status information from the EAPOL state machine. If
@@ -1187,14 +1332,16 @@ static const char * eap_sm_decision_txt(int decision)
*/
int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
{
- int len;
+ int len, ret;
if (sm == NULL)
return 0;
- len = snprintf(buf, buflen,
- "EAP state=%s\n",
- eap_sm_state_txt(sm->EAP_state));
+ len = os_snprintf(buf, buflen,
+ "EAP state=%s\n",
+ eap_sm_state_txt(sm->EAP_state));
+ if (len < 0 || (size_t) len >= buflen)
+ return 0;
if (sm->selectedMethod != EAP_TYPE_NONE) {
const char *name;
@@ -1202,15 +1349,19 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
name = sm->m->name;
} else {
const struct eap_method *m =
- eap_sm_get_eap_methods(sm->selectedMethod);
+ eap_sm_get_eap_methods(EAP_VENDOR_IETF,
+ sm->selectedMethod);
if (m)
name = m->name;
else
name = "?";
}
- len += snprintf(buf + len, buflen - len,
- "selectedMethod=%d (EAP-%s)\n",
- sm->selectedMethod, name);
+ ret = os_snprintf(buf + len, buflen - len,
+ "selectedMethod=%d (EAP-%s)\n",
+ sm->selectedMethod, name);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
if (sm->m && sm->m->get_status) {
len += sm->m->get_status(sm, sm->eap_method_priv,
@@ -1220,37 +1371,45 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
}
if (verbose) {
- len += snprintf(buf + len, buflen - len,
- "reqMethod=%d\n"
- "methodState=%s\n"
- "decision=%s\n"
- "ClientTimeout=%d\n",
- sm->reqMethod,
- eap_sm_method_state_txt(sm->methodState),
- eap_sm_decision_txt(sm->decision),
- sm->ClientTimeout);
+ ret = os_snprintf(buf + len, buflen - len,
+ "reqMethod=%d\n"
+ "methodState=%s\n"
+ "decision=%s\n"
+ "ClientTimeout=%d\n",
+ sm->reqMethod,
+ eap_sm_method_state_txt(sm->methodState),
+ eap_sm_decision_txt(sm->decision),
+ sm->ClientTimeout);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
}
return len;
}
+#endif /* CONFIG_CTRL_IFACE */
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
typedef enum {
TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
TYPE_PASSPHRASE
} eap_ctrl_req_type;
-static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
- eap_ctrl_req_type type, const char *msg,
- size_t msglen)
+static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
+ const char *msg, size_t msglen)
{
+ struct wpa_ssid *config;
char *buf;
size_t buflen;
int len;
char *field;
char *txt, *tmp;
- if (config == NULL || sm == NULL)
+ if (sm == NULL)
+ return;
+ config = eap_get_config(sm);
+ if (config == NULL)
return;
switch (type) {
@@ -1277,15 +1436,15 @@ static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
case TYPE_OTP:
field = "OTP";
if (msg) {
- tmp = malloc(msglen + 3);
+ tmp = os_malloc(msglen + 3);
if (tmp == NULL)
return;
tmp[0] = '[';
- memcpy(tmp + 1, msg, msglen);
+ os_memcpy(tmp + 1, msg, msglen);
tmp[msglen + 1] = ']';
tmp[msglen + 2] = '\0';
txt = tmp;
- free(config->pending_req_otp);
+ os_free(config->pending_req_otp);
config->pending_req_otp = tmp;
config->pending_req_otp_len = msglen + 3;
} else {
@@ -1303,90 +1462,94 @@ static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
return;
}
- buflen = 100 + strlen(txt) + config->ssid_len;
- buf = malloc(buflen);
+ buflen = 100 + os_strlen(txt) + config->ssid_len;
+ buf = os_malloc(buflen);
if (buf == NULL)
return;
- len = snprintf(buf, buflen, WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
- field, config->id, txt);
+ len = os_snprintf(buf, buflen,
+ WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
+ field, config->id, txt);
+ if (len < 0 || (size_t) len >= buflen) {
+ os_free(buf);
+ return;
+ }
if (config->ssid && buflen > len + config->ssid_len) {
- memcpy(buf + len, config->ssid, config->ssid_len);
+ os_memcpy(buf + len, config->ssid, config->ssid_len);
len += config->ssid_len;
buf[len] = '\0';
}
+ buf[buflen - 1] = '\0';
wpa_msg(sm->msg_ctx, MSG_INFO, "%s", buf);
- free(buf);
+ os_free(buf);
}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
/**
* eap_sm_request_identity - Request identity from user (ctrl_iface)
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
- * @config: Pointer to the current network configuration
*
* EAP methods can call this function to request identity information for the
* current network. This is normally called when the identity is not included
* in the network configuration. The request will be sent to monitor programs
* through the control interface.
*/
-void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config)
+void eap_sm_request_identity(struct eap_sm *sm)
{
- eap_sm_request(sm, config, TYPE_IDENTITY, NULL, 0);
+ eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);
}
/**
* eap_sm_request_password - Request password from user (ctrl_iface)
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
- * @config: Pointer to the current network configuration
*
* EAP methods can call this function to request password information for the
* current network. This is normally called when the password is not included
* in the network configuration. The request will be sent to monitor programs
* through the control interface.
*/
-void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config)
+void eap_sm_request_password(struct eap_sm *sm)
{
- eap_sm_request(sm, config, TYPE_PASSWORD, NULL, 0);
+ eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);
}
/**
* eap_sm_request_new_password - Request new password from user (ctrl_iface)
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
- * @config: Pointer to the current network configuration
*
* EAP methods can call this function to request new password information for
* the current network. This is normally called when the EAP method indicates
* that the current password has expired and password change is required. The
* request will be sent to monitor programs through the control interface.
*/
-void eap_sm_request_new_password(struct eap_sm *sm, struct wpa_ssid *config)
+void eap_sm_request_new_password(struct eap_sm *sm)
{
- eap_sm_request(sm, config, TYPE_NEW_PASSWORD, NULL, 0);
+ eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);
}
/**
* eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface)
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
- * @config: Pointer to the current network configuration
*
* EAP methods can call this function to request SIM or smart card PIN
* information for the current network. This is normally called when the PIN is
* not included in the network configuration. The request will be sent to
* monitor programs through the control interface.
*/
-void eap_sm_request_pin(struct eap_sm *sm, struct wpa_ssid *config)
+void eap_sm_request_pin(struct eap_sm *sm)
{
- eap_sm_request(sm, config, TYPE_PIN, NULL, 0);
+ eap_sm_request(sm, TYPE_PIN, NULL, 0);
}
/**
* eap_sm_request_otp - Request one time password from user (ctrl_iface)
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
- * @config: Pointer to the current network configuration
* @msg: Message to be displayed to the user when asking for OTP
* @msg_len: Length of the user displayable message
*
@@ -1394,26 +1557,24 @@ void eap_sm_request_pin(struct eap_sm *sm, struct wpa_ssid *config)
* the current network. The request will be sent to monitor programs through
* the control interface.
*/
-void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
- const char *msg, size_t msg_len)
+void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
{
- eap_sm_request(sm, config, TYPE_OTP, msg, msg_len);
+ eap_sm_request(sm, TYPE_OTP, msg, msg_len);
}
/**
* eap_sm_request_passphrase - Request passphrase from user (ctrl_iface)
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
- * @config: Pointer to the current network configuration
*
* EAP methods can call this function to request passphrase for a private key
* for the current network. This is normally called when the passphrase is not
* included in the network configuration. The request will be sent to monitor
* programs through the control interface.
*/
-void eap_sm_request_passphrase(struct eap_sm *sm, struct wpa_ssid *config)
+void eap_sm_request_passphrase(struct eap_sm *sm)
{
- eap_sm_request(sm, config, TYPE_PASSPHRASE, NULL, 0);
+ eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0);
}
@@ -1436,84 +1597,24 @@ void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
* starts immediately after system startup when the user interface is
* not yet running. */
if (config->pending_req_identity)
- eap_sm_request_identity(sm, config);
+ eap_sm_request_identity(sm);
if (config->pending_req_password)
- eap_sm_request_password(sm, config);
+ eap_sm_request_password(sm);
if (config->pending_req_new_password)
- eap_sm_request_new_password(sm, config);
+ eap_sm_request_new_password(sm);
if (config->pending_req_otp)
- eap_sm_request_otp(sm, config, NULL, 0);
+ eap_sm_request_otp(sm, NULL, 0);
if (config->pending_req_pin)
- eap_sm_request_pin(sm, config);
+ eap_sm_request_pin(sm);
if (config->pending_req_passphrase)
- eap_sm_request_passphrase(sm, config);
+ eap_sm_request_passphrase(sm);
}
-/**
- * eap_get_type - Get EAP type for the given EAP method name
- * @name: EAP method name, e.g., TLS
- * Returns: EAP method type or %EAP_TYPE_NONE if not found
- *
- * This function maps EAP type names into EAP type numbers based on the list of
- * EAP methods included in the build.
- */
-u8 eap_get_type(const char *name)
-{
- int i;
- for (i = 0; i < NUM_EAP_METHODS; i++) {
- if (strcmp(eap_methods[i]->name, name) == 0)
- return eap_methods[i]->method;
- }
- return EAP_TYPE_NONE;
-}
-
-
-/**
- * eap_get_name - Get EAP method name for the given EAP type
- * @type: EAP method type
- * Returns: EAP method name, e.g., TLS, or %NULL if not found
- *
- * This function maps EAP type numbers into EAP type names based on the list of
- * EAP methods included in the build.
- */
-const char * eap_get_name(EapType type)
-{
- int i;
- for (i = 0; i < NUM_EAP_METHODS; i++) {
- if (eap_methods[i]->method == type)
- return eap_methods[i]->name;
- }
- return NULL;
-}
-
-
-/**
- * eap_get_names - Get space separated list of names for supported EAP methods
- * @buf: Buffer for names
- * @buflen: Buffer length
- * Returns: Number of characters written into buf (not including nul
- * termination)
- */
-size_t eap_get_names(char *buf, size_t buflen)
-{
- char *pos, *end;
- int i;
-
- pos = buf;
- end = pos + buflen;
-
- for (i = 0; i < NUM_EAP_METHODS; i++) {
- pos += snprintf(pos, end - pos, "%s%s",
- i == 0 ? "" : " ", eap_methods[i]->name);
- }
-
- return pos - buf;
-}
-
-
-static int eap_allowed_phase2_type(int type)
+static int eap_allowed_phase2_type(int vendor, int type)
{
+ if (vendor != EAP_VENDOR_IETF)
+ return 0;
return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
type != EAP_TYPE_FAST;
}
@@ -1522,17 +1623,22 @@ static int eap_allowed_phase2_type(int type)
/**
* eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name
* @name: EAP method name, e.g., MD5
+ * @vendor: Buffer for returning EAP Vendor-Id
* Returns: EAP method type or %EAP_TYPE_NONE if not found
*
* This function maps EAP type names into EAP type numbers that are allowed for
* Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with
* EAP-PEAP, EAP-TTLS, and EAP-FAST.
*/
-u8 eap_get_phase2_type(const char *name)
+u32 eap_get_phase2_type(const char *name, int *vendor)
{
- u8 type = eap_get_type(name);
- if (eap_allowed_phase2_type(type))
+ int v;
+ u8 type = eap_get_type(name, &v);
+ if (eap_allowed_phase2_type(v, type)) {
+ *vendor = v;
return type;
+ }
+ *vendor = EAP_VENDOR_IETF;
return EAP_TYPE_NONE;
}
@@ -1540,29 +1646,39 @@ u8 eap_get_phase2_type(const char *name)
/**
* eap_get_phase2_types - Get list of allowed EAP phase 2 types
* @config: Pointer to a network configuration
- * @count: Pointer to variable filled with number of returned EAP types
+ * @count: Pointer to a variable to be filled with number of returned EAP types
* Returns: Pointer to allocated type list or %NULL on failure
*
* This function generates an array of allowed EAP phase 2 (tunneled) types for
* the given network configuration.
*/
-u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count)
+struct eap_method_type * eap_get_phase2_types(struct wpa_ssid *config,
+ size_t *count)
{
- u8 *buf, method;
- int i;
+ struct eap_method_type *buf;
+ u32 method;
+ int vendor;
+ size_t mcount;
+ const struct eap_method *methods, *m;
+ methods = eap_peer_get_methods(&mcount);
+ if (methods == NULL)
+ return NULL;
*count = 0;
- buf = malloc(NUM_EAP_METHODS);
+ buf = os_malloc(mcount * sizeof(struct eap_method_type));
if (buf == NULL)
return NULL;
- for (i = 0; i < NUM_EAP_METHODS; i++) {
- method = eap_methods[i]->method;
- if (eap_allowed_phase2_type(method)) {
- if (method == EAP_TYPE_TLS && config &&
+ for (m = methods; m; m = m->next) {
+ vendor = m->vendor;
+ method = m->method;
+ if (eap_allowed_phase2_type(vendor, method)) {
+ if (vendor == EAP_VENDOR_IETF &&
+ method == EAP_TYPE_TLS && config &&
config->private_key2 == NULL)
continue;
- buf[*count] = method;
+ buf[*count].vendor = vendor;
+ buf[*count].method = method;
(*count)++;
}
}
@@ -1574,7 +1690,7 @@ u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count)
/**
* eap_set_fast_reauth - Update fast_reauth setting
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
- * @enabled: 1 = fast reauthentication is enabled, 0 = disabled
+ * @enabled: 1 = Fast reauthentication is enabled, 0 = Disabled
*/
void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
{
@@ -1597,6 +1713,11 @@ void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
* eap_get_config - Get current network configuration
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* Returns: Pointer to the current network configuration or %NULL if not found
+ *
+ * EAP peer methods should avoid using this function if they can use other
+ * access functions, like eap_get_config_identity() and
+ * eap_get_config_password(), that do not require direct access to
+ * struct wpa_ssid.
*/
struct wpa_ssid * eap_get_config(struct eap_sm *sm)
{
@@ -1605,6 +1726,90 @@ struct wpa_ssid * eap_get_config(struct eap_sm *sm)
/**
+ * eap_get_config_password - Get identity from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @len: Buffer for the length of the identity
+ * Returns: Pointer to the identity or %NULL if not found
+ */
+const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config == NULL)
+ return NULL;
+ *len = config->identity_len;
+ return config->identity;
+}
+
+
+/**
+ * eap_get_config_password - Get password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @len: Buffer for the length of the password
+ * Returns: Pointer to the password or %NULL if not found
+ */
+const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config == NULL)
+ return NULL;
+ *len = config->password_len;
+ return config->password;
+}
+
+
+/**
+ * eap_get_config_new_password - Get new password from network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @len: Buffer for the length of the new password
+ * Returns: Pointer to the new password or %NULL if not found
+ */
+const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config == NULL)
+ return NULL;
+ *len = config->new_password_len;
+ return config->new_password;
+}
+
+
+/**
+ * eap_get_config_otp - Get one-time password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @len: Buffer for the length of the one-time password
+ * Returns: Pointer to the one-time password or %NULL if not found
+ */
+const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config == NULL)
+ return NULL;
+ *len = config->otp_len;
+ return config->otp;
+}
+
+
+/**
+ * eap_clear_config_otp - Clear used one-time password
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function clears a used one-time password (OTP) from the current network
+ * configuration. This should be called when the OTP has been used and is not
+ * needed anymore.
+ */
+void eap_clear_config_otp(struct eap_sm *sm)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config == NULL)
+ return;
+ os_memset(config->otp, 0, config->otp_len);
+ os_free(config->otp);
+ config->otp = NULL;
+ config->otp_len = 0;
+}
+
+
+/**
* eap_key_available - Get key availability (eapKeyAvailable variable)
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
* Returns: 1 if EAP keying material is available, 0 if not
@@ -1631,6 +1836,8 @@ void eap_notify_success(struct eap_sm *sm)
sm->EAP_state = EAP_SUCCESS;
}
}
+
+
/**
* eap_notify_lower_layer_success - Notification of lower layer success
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
@@ -1713,7 +1920,7 @@ u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len)
/**
* eap_sm_register_scard_ctx - Notification of smart card context
* @sm: Pointer to EAP state machine allocated with eap_sm_init()
- * @ctx: context data for smart card operations
+ * @ctx: Context data for smart card operations
*
* Notify EAP state machines of context data for smart card operations. This
* context data will be used as a parameter for scard_*() functions.
@@ -1727,35 +1934,72 @@ void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
/**
* eap_hdr_validate - Validate EAP header
+ * @vendor: Expected EAP Vendor-Id (0 = IETF)
* @eap_type: Expected EAP type number
* @msg: EAP frame (starting with EAP header)
* @msglen: Length of msg
- * @plen: Pointer for return payload length
+ * @plen: Pointer to variable to contain the returned payload length
* Returns: Pointer to EAP payload (after type field), or %NULL on failure
*
* This is a helper function for EAP method implementations. This is usually
- * called in the beginning of struct eap_method::process() function.
+ * called in the beginning of struct eap_method::process() function to verify
+ * that the received EAP request packet has a valid header. This function is
+ * able to process both legacy and expanded EAP headers and in most cases, the
+ * caller can just use the returned payload pointer (into *plen) for processing
+ * the payload regardless of whether the packet used the expanded EAP header or
+ * not.
*/
-const u8 * eap_hdr_validate(EapType eap_type, const u8 *msg, size_t msglen,
- size_t *plen)
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+ const u8 *msg, size_t msglen, size_t *plen)
{
const struct eap_hdr *hdr;
const u8 *pos;
size_t len;
hdr = (const struct eap_hdr *) msg;
- pos = (const u8 *) (hdr + 1);
- if (msglen < sizeof(*hdr) + 1 || *pos != eap_type) {
- wpa_printf(MSG_INFO, "EAP: Invalid frame type");
+
+ if (msglen < sizeof(*hdr)) {
+ wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
return NULL;
}
+
len = be_to_host16(hdr->length);
if (len < sizeof(*hdr) + 1 || len > msglen) {
wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
return NULL;
}
- *plen = len - sizeof(*hdr) - 1;
- return pos + 1;
+
+ pos = (const u8 *) (hdr + 1);
+
+ if (*pos == EAP_TYPE_EXPANDED) {
+ int exp_vendor;
+ u32 exp_type;
+ if (len < sizeof(*hdr) + 8) {
+ wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
+ "length");
+ return NULL;
+ }
+ pos++;
+ exp_vendor = WPA_GET_BE24(pos);
+ pos += 3;
+ exp_type = WPA_GET_BE32(pos);
+ pos += 4;
+ if (exp_vendor != vendor || exp_type != (u32) eap_type) {
+ wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
+ "type");
+ return NULL;
+ }
+
+ *plen = len - sizeof(*hdr) - 8;
+ return pos;
+ } else {
+ if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
+ wpa_printf(MSG_INFO, "EAP: Invalid frame type");
+ return NULL;
+ }
+ *plen = len - sizeof(*hdr) - 1;
+ return pos + 1;
+ }
}
@@ -1798,3 +2042,79 @@ void eap_set_force_disabled(struct eap_sm *sm, int disabled)
{
sm->force_disabled = disabled;
}
+
+
+/**
+ * eap_msg_alloc - Allocate a buffer for an EAP message
+ * @vendor: Vendor-Id (0 = IETF)
+ * @type: EAP type
+ * @len: Buffer for returning message length
+ * @payload_len: Payload length in bytes (data after Type)
+ * @code: Message Code (EAP_CODE_*)
+ * @identifier: Identifier
+ * @payload: Pointer to payload pointer that will be set to point to the
+ * beginning of the payload or %NULL if payload pointer is not needed
+ * Returns: Pointer to the allocated message buffer or %NULL on error
+ *
+ * This function can be used to allocate a buffer for an EAP message and fill
+ * in the EAP header. This function is automatically using expanded EAP header
+ * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
+ * not need to separately select which header type to use when using this
+ * function to allocate the message buffers.
+ */
+struct eap_hdr * eap_msg_alloc(int vendor, EapType type, size_t *len,
+ size_t payload_len, u8 code, u8 identifier,
+ u8 **payload)
+{
+ struct eap_hdr *hdr;
+ u8 *pos;
+
+ *len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
+ payload_len;
+ hdr = os_malloc(*len);
+ if (hdr) {
+ hdr->code = code;
+ hdr->identifier = identifier;
+ hdr->length = host_to_be16(*len);
+ pos = (u8 *) (hdr + 1);
+ if (vendor == EAP_VENDOR_IETF) {
+ *pos++ = type;
+ } else {
+ *pos++ = EAP_TYPE_EXPANDED;
+ WPA_PUT_BE24(pos, vendor);
+ pos += 3;
+ WPA_PUT_BE32(pos, type);
+ pos += 4;
+ }
+ if (payload)
+ *payload = pos;
+ }
+
+ return hdr;
+}
+
+
+ /**
+ * eap_notify_pending - Notify that EAP method is ready to re-process a request
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * An EAP method can perform a pending operation (e.g., to get a response from
+ * an external process). Once the response is available, this 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 eap_notify_pending(struct eap_sm *sm)
+{
+ sm->eapol_cb->notify_pending(sm->eapol_ctx);
+}
+
+
+/**
+ * eap_invalidate_cached_session - Mark cached session data invalid
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ */
+void eap_invalidate_cached_session(struct eap_sm *sm)
+{
+ if (sm)
+ eap_deinit_prev_method(sm, "invalidate");
+}
diff --git a/contrib/wpa_supplicant/eap.h b/contrib/wpa_supplicant/eap.h
index e00e29bd9678..f1f78c2997f6 100644
--- a/contrib/wpa_supplicant/eap.h
+++ b/contrib/wpa_supplicant/eap.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP state machine functions (RFC 4137)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer state machine functions (RFC 4137)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,11 +17,16 @@
#include "defs.h"
#include "eap_defs.h"
+#include "eap_methods.h"
struct eap_sm;
struct wpa_ssid;
struct wpa_config_blob;
+struct eap_method_type {
+ int vendor;
+ u32 method;
+};
#ifdef IEEE8021X_EAPOL
@@ -194,6 +199,18 @@ struct eapol_callbacks {
*/
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_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);
};
/**
@@ -229,47 +246,26 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen,
int verbose);
u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
int encrypted);
-const struct eap_method * eap_sm_get_eap_methods(int method);
-void eap_sm_request_identity(struct eap_sm *sm, struct wpa_ssid *config);
-void eap_sm_request_password(struct eap_sm *sm, struct wpa_ssid *config);
-void eap_sm_request_new_password(struct eap_sm *sm, struct wpa_ssid *config);
-void eap_sm_request_pin(struct eap_sm *sm, struct wpa_ssid *config);
-void eap_sm_request_otp(struct eap_sm *sm, struct wpa_ssid *config,
- const char *msg, size_t msg_len);
-void eap_sm_request_passphrase(struct eap_sm *sm, struct wpa_ssid *config);
+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_notify_ctrl_attached(struct eap_sm *sm);
-u8 eap_get_type(const char *name);
-const char * eap_get_name(EapType type);
-size_t eap_get_names(char *buf, size_t buflen);
-u8 eap_get_phase2_type(const char *name);
-u8 *eap_get_phase2_types(struct wpa_ssid *config, size_t *count);
+u32 eap_get_phase2_type(const char *name, int *vendor);
+struct eap_method_type * eap_get_phase2_types(struct wpa_ssid *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);
-struct wpa_ssid * eap_get_config(struct eap_sm *sm);
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_eapKeyData(struct eap_sm *sm, size_t *len);
u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len);
void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
-
-#else /* IEEE8021X_EAPOL */
-
-static inline u8 eap_get_type(const char *name)
-{
- return EAP_TYPE_NONE;
-}
-
-static inline const char * eap_get_name(EapType type)
-{
- return NULL;
-}
-
-static inline size_t eap_get_names(char *buf, size_t buflen)
-{
- return 0;
-}
+void eap_invalidate_cached_session(struct eap_sm *sm);
#endif /* IEEE8021X_EAPOL */
diff --git a/contrib/wpa_supplicant/eap_aka.c b/contrib/wpa_supplicant/eap_aka.c
index b05cc72a9aa9..a8b56ca67302 100644
--- a/contrib/wpa_supplicant/eap_aka.c
+++ b/contrib/wpa_supplicant/eap_aka.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-AKA (draft-arkko-pppext-eap-aka-12.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-AKA (RFC 4187)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,46 +12,26 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
-#include "config_ssid.h"
#include "crypto.h"
#include "pcsc_funcs.h"
#include "eap_sim_common.h"
-/* 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 AKA_AUTS_LEN 14
-#define RES_MAX_LEN 16
-#define IK_LEN 16
-#define CK_LEN 16
-#define EAP_AKA_MAX_FAST_REAUTHS 1000
struct eap_aka_data {
- u8 ik[IK_LEN], ck[CK_LEN], res[RES_MAX_LEN];
+ u8 ik[EAP_AKA_IK_LEN], ck[EAP_AKA_CK_LEN], res[EAP_AKA_RES_MAX_LEN];
size_t res_len;
u8 nonce_s[EAP_SIM_NONCE_S_LEN];
u8 mk[EAP_SIM_MK_LEN];
u8 k_aut[EAP_SIM_K_AUT_LEN];
u8 k_encr[EAP_SIM_K_ENCR_LEN];
u8 msk[EAP_SIM_KEYING_DATA_LEN];
- u8 rand[AKA_RAND_LEN], autn[AKA_AUTN_LEN];
- u8 auts[AKA_AUTS_LEN];
+ u8 emsk[EAP_EMSK_LEN];
+ u8 rand[EAP_AKA_RAND_LEN], autn[EAP_AKA_AUTN_LEN];
+ u8 auts[EAP_AKA_AUTS_LEN];
int num_id_req, num_notification;
u8 *pseudonym;
@@ -69,10 +49,9 @@ struct eap_aka_data {
static void * eap_aka_init(struct eap_sm *sm)
{
struct eap_aka_data *data;
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
data->state = CONTINUE;
@@ -84,10 +63,10 @@ static void eap_aka_deinit(struct eap_sm *sm, void *priv)
{
struct eap_aka_data *data = priv;
if (data) {
- free(data->pseudonym);
- free(data->reauth_id);
- free(data->last_eap_identity);
- free(data);
+ os_free(data->pseudonym);
+ os_free(data->reauth_id);
+ os_free(data->last_eap_identity);
+ os_free(data);
}
}
@@ -102,45 +81,34 @@ static int eap_aka_umts_auth(struct eap_sm *sm, struct eap_aka_data *data)
#else /* PCSC_FUNCS */
/* These hardcoded Kc and SRES values are used for testing.
* Could consider making them configurable. */
- memset(data->res, '2', RES_MAX_LEN);
- data->res_len = 16;
- memset(data->ik, '3', IK_LEN);
- memset(data->ck, '4', CK_LEN);
+ os_memset(data->res, '2', EAP_AKA_RES_MAX_LEN);
+ data->res_len = EAP_AKA_RES_MAX_LEN;
+ os_memset(data->ik, '3', EAP_AKA_IK_LEN);
+ os_memset(data->ck, '4', EAP_AKA_CK_LEN);
{
- u8 autn[AKA_AUTN_LEN];
- memset(autn, '1', AKA_AUTN_LEN);
- if (memcmp(autn, data->autn, AKA_AUTN_LEN) != 0) {
+ u8 autn[EAP_AKA_AUTN_LEN];
+ os_memset(autn, '1', EAP_AKA_AUTN_LEN);
+ if (os_memcmp(autn, data->autn, EAP_AKA_AUTN_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-AKA: AUTN did not match "
"with expected value");
return -1;
}
}
+#if 0
+ {
+ static int test_resync = 1;
+ if (test_resync) {
+ /* Test Resynchronization */
+ test_resync = 0;
+ return -2;
+ }
+ }
+#endif
return 0;
#endif /* PCSC_FUNCS */
}
-static void eap_aka_derive_mk(struct eap_aka_data *data,
- const u8 *identity, size_t identity_len)
-{
- const u8 *addr[3];
- size_t len[3];
-
- addr[0] = identity;
- len[0] = identity_len;
- addr[1] = data->ik;
- len[1] = IK_LEN;
- addr[2] = data->ck;
- len[2] = CK_LEN;
-
- /* MK = SHA1(Identity|IK|CK) */
- sha1_vector(3, addr, len, data->mk);
- wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", data->ik, IK_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", data->ck, CK_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", data->mk, EAP_SIM_MK_LEN);
-}
-
-
#define CLEAR_PSEUDONYM 0x01
#define CLEAR_REAUTH_ID 0x02
#define CLEAR_EAP_ID 0x04
@@ -152,17 +120,17 @@ static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
id & CLEAR_REAUTH_ID ? " reauth_id" : "",
id & CLEAR_EAP_ID ? " eap_id" : "");
if (id & CLEAR_PSEUDONYM) {
- free(data->pseudonym);
+ os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
}
if (id & CLEAR_REAUTH_ID) {
- free(data->reauth_id);
+ os_free(data->reauth_id);
data->reauth_id = NULL;
data->reauth_id_len = 0;
}
if (id & CLEAR_EAP_ID) {
- free(data->last_eap_identity);
+ os_free(data->last_eap_identity);
data->last_eap_identity = NULL;
data->last_eap_identity_len = 0;
}
@@ -173,15 +141,15 @@ static int eap_aka_learn_ids(struct eap_aka_data *data,
struct eap_sim_attrs *attr)
{
if (attr->next_pseudonym) {
- free(data->pseudonym);
- data->pseudonym = malloc(attr->next_pseudonym_len);
+ os_free(data->pseudonym);
+ data->pseudonym = os_malloc(attr->next_pseudonym_len);
if (data->pseudonym == NULL) {
wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
"next pseudonym");
return -1;
}
- memcpy(data->pseudonym, attr->next_pseudonym,
- attr->next_pseudonym_len);
+ os_memcpy(data->pseudonym, attr->next_pseudonym,
+ attr->next_pseudonym_len);
data->pseudonym_len = attr->next_pseudonym_len;
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-AKA: (encr) AT_NEXT_PSEUDONYM",
@@ -190,15 +158,15 @@ static int eap_aka_learn_ids(struct eap_aka_data *data,
}
if (attr->next_reauth_id) {
- free(data->reauth_id);
- data->reauth_id = malloc(attr->next_reauth_id_len);
+ os_free(data->reauth_id);
+ data->reauth_id = os_malloc(attr->next_reauth_id_len);
if (data->reauth_id == NULL) {
wpa_printf(MSG_INFO, "EAP-AKA: (encr) No memory for "
"next reauth_id");
return -1;
}
- memcpy(data->reauth_id, attr->next_reauth_id,
- attr->next_reauth_id_len);
+ os_memcpy(data->reauth_id, attr->next_reauth_id,
+ attr->next_reauth_id_len);
data->reauth_id_len = attr->next_reauth_id_len;
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-AKA: (encr) AT_NEXT_REAUTH_ID",
@@ -210,7 +178,7 @@ static int eap_aka_learn_ids(struct eap_aka_data *data,
}
-static u8 * eap_aka_client_error(struct eap_sm *sm, struct eap_aka_data *data,
+static u8 * eap_aka_client_error(struct eap_aka_data *data,
const struct eap_hdr *req,
size_t *respDataLen, int err)
{
@@ -227,8 +195,7 @@ static u8 * eap_aka_client_error(struct eap_sm *sm, struct eap_aka_data *data,
}
-static u8 * eap_aka_authentication_reject(struct eap_sm *sm,
- struct eap_aka_data *data,
+static u8 * eap_aka_authentication_reject(struct eap_aka_data *data,
const struct eap_hdr *req,
size_t *respDataLen)
{
@@ -247,14 +214,12 @@ static u8 * eap_aka_authentication_reject(struct eap_sm *sm,
}
-static u8 * eap_aka_synchronization_failure(struct eap_sm *sm,
- struct eap_aka_data *data,
+static u8 * eap_aka_synchronization_failure(struct eap_aka_data *data,
const struct eap_hdr *req,
size_t *respDataLen)
{
struct eap_sim_msg *msg;
- data->state = FAILURE;
data->num_id_req = 0;
data->num_notification = 0;
@@ -264,7 +229,8 @@ static u8 * eap_aka_synchronization_failure(struct eap_sm *sm,
EAP_TYPE_AKA,
EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE);
wpa_printf(MSG_DEBUG, " AT_AUTS");
- eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts, AKA_AUTS_LEN);
+ eap_sim_msg_add_full(msg, EAP_SIM_AT_AUTS, data->auts,
+ EAP_AKA_AUTS_LEN);
return eap_sim_msg_finish(msg, respDataLen, NULL, NULL, 0);
}
@@ -275,8 +241,7 @@ static u8 * eap_aka_response_identity(struct eap_sm *sm,
size_t *respDataLen,
enum eap_sim_id_req id_req)
{
- struct wpa_ssid *config = eap_get_config(sm);
- u8 *identity = NULL;
+ const u8 *identity = NULL;
size_t identity_len = 0;
struct eap_sim_msg *msg;
@@ -290,11 +255,12 @@ static u8 * eap_aka_response_identity(struct eap_sm *sm,
identity = data->pseudonym;
identity_len = data->pseudonym_len;
eap_aka_clear_identities(data, CLEAR_REAUTH_ID);
- } else if (id_req != NO_ID_REQ && config && config->identity) {
- identity = config->identity;
- identity_len = config->identity_len;
- eap_aka_clear_identities(data,
- CLEAR_PSEUDONYM | CLEAR_REAUTH_ID);
+ } else if (id_req != NO_ID_REQ) {
+ identity = eap_get_config_identity(sm, &identity_len);
+ if (identity) {
+ eap_aka_clear_identities(data, CLEAR_PSEUDONYM |
+ CLEAR_REAUTH_ID);
+ }
}
if (id_req != NO_ID_REQ)
eap_aka_clear_identities(data, CLEAR_EAP_ID);
@@ -315,8 +281,7 @@ static u8 * eap_aka_response_identity(struct eap_sm *sm,
}
-static u8 * eap_aka_response_challenge(struct eap_sm *sm,
- struct eap_aka_data *data,
+static u8 * eap_aka_response_challenge(struct eap_aka_data *data,
const struct eap_hdr *req,
size_t *respDataLen)
{
@@ -335,10 +300,10 @@ static u8 * eap_aka_response_challenge(struct eap_sm *sm,
}
-static u8 * eap_aka_response_reauth(struct eap_sm *sm,
- struct eap_aka_data *data,
+static u8 * eap_aka_response_reauth(struct eap_aka_data *data,
const struct eap_hdr *req,
- size_t *respDataLen, int counter_too_small)
+ size_t *respDataLen, int counter_too_small,
+ const u8 *nonce_s)
{
struct eap_sim_msg *msg;
unsigned int counter;
@@ -370,13 +335,12 @@ static u8 * eap_aka_response_reauth(struct eap_sm *sm,
}
wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
- return eap_sim_msg_finish(msg, respDataLen, data->k_aut, data->nonce_s,
+ return eap_sim_msg_finish(msg, respDataLen, data->k_aut, nonce_s,
EAP_SIM_NONCE_S_LEN);
}
-static u8 * eap_aka_response_notification(struct eap_sm *sm,
- struct eap_aka_data *data,
+static u8 * eap_aka_response_notification(struct eap_aka_data *data,
const struct eap_hdr *req,
size_t *respDataLen,
u16 notification)
@@ -388,8 +352,6 @@ static u8 * eap_aka_response_notification(struct eap_sm *sm,
req->identifier);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
EAP_TYPE_AKA, EAP_AKA_SUBTYPE_NOTIFICATION);
- wpa_printf(MSG_DEBUG, " AT_NOTIFICATION");
- eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, notification, NULL, 0);
if (k_aut && data->reauth) {
wpa_printf(MSG_DEBUG, " AT_IV");
wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
@@ -417,7 +379,6 @@ static u8 * eap_aka_response_notification(struct eap_sm *sm,
static u8 * eap_aka_process_identity(struct eap_sm *sm,
struct eap_aka_data *data,
const struct eap_hdr *req,
- size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
@@ -448,7 +409,7 @@ static u8 * eap_aka_process_identity(struct eap_sm *sm,
if (id_error) {
wpa_printf(MSG_INFO, "EAP-AKA: Too many ID requests "
"used within one authentication");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
@@ -464,8 +425,7 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
- struct wpa_ssid *config = eap_get_config(sm);
- u8 *identity;
+ const u8 *identity;
size_t identity_len;
int res;
struct eap_sim_attrs eattr;
@@ -478,26 +438,24 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
!attr->mac ? " AT_MAC" : "",
!attr->rand ? " AT_RAND" : "",
!attr->autn ? " AT_AUTN" : "");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
- memcpy(data->rand, attr->rand, AKA_RAND_LEN);
- memcpy(data->autn, attr->autn, AKA_AUTN_LEN);
+ os_memcpy(data->rand, attr->rand, EAP_AKA_RAND_LEN);
+ os_memcpy(data->autn, attr->autn, EAP_AKA_AUTN_LEN);
res = eap_aka_umts_auth(sm, data);
if (res == -1) {
wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
"failed (AUTN)");
- return eap_aka_authentication_reject(sm, data, req,
- respDataLen);
+ return eap_aka_authentication_reject(data, req, respDataLen);
} else if (res == -2) {
wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication "
"failed (AUTN seq# -> AUTS)");
- return eap_aka_synchronization_failure(sm, data, req,
- respDataLen);
+ return eap_aka_synchronization_failure(data, req, respDataLen);
} else if (res) {
wpa_printf(MSG_WARNING, "EAP-AKA: UMTS authentication failed");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
if (data->last_eap_identity) {
@@ -506,19 +464,19 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
} else if (data->pseudonym) {
identity = data->pseudonym;
identity_len = data->pseudonym_len;
- } else {
- identity = config->identity;
- identity_len = config->identity_len;
- }
+ } else
+ identity = eap_get_config_identity(sm, &identity_len);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Selected identity for MK "
"derivation", identity, identity_len);
- eap_aka_derive_mk(data, identity, identity_len);
- eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
+ eap_aka_derive_mk(identity, identity_len, data->ik, data->ck,
+ data->mk);
+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+ data->emsk);
if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
"used invalid AT_MAC");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
@@ -535,11 +493,11 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
&eattr, 0);
if (decrypted == NULL) {
return eap_aka_client_error(
- sm, data, req, respDataLen,
+ data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
eap_aka_learn_ids(data, &eattr);
- free(decrypted);
+ os_free(decrypted);
}
if (data->state != FAILURE)
@@ -547,17 +505,15 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
data->num_id_req = 0;
data->num_notification = 0;
- /* draft-arkko-pppext-eap-aka-12.txt specifies that counter
- * is initialized to one after fullauth, but initializing it to
- * zero makes it easier to implement reauth verification. */
+ /* RFC 4187 specifies that counter is initialized to one after
+ * fullauth, but initializing it to zero makes it easier to implement
+ * reauth verification. */
data->counter = 0;
- return eap_aka_response_challenge(sm, data, req, respDataLen);
+ return eap_aka_response_challenge(data, req, respDataLen);
}
static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
- const struct eap_hdr *req,
- size_t reqDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
@@ -578,15 +534,15 @@ static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
return -1;
}
- if (eattr.counter != data->counter) {
+ if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
"message does not match with counter in reauth "
"message");
- free(decrypted);
+ os_free(decrypted);
return -1;
}
- free(decrypted);
+ os_free(decrypted);
return 0;
}
@@ -610,7 +566,7 @@ static int eap_aka_process_notification_auth(struct eap_aka_data *data,
}
if (data->reauth &&
- eap_aka_process_notification_reauth(data, req, reqDataLen, attr)) {
+ eap_aka_process_notification_reauth(data, attr)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Invalid notification "
"message after reauth");
return -1;
@@ -631,20 +587,20 @@ static u8 * eap_aka_process_notification(struct eap_sm *sm,
if (data->num_notification > 0) {
wpa_printf(MSG_INFO, "EAP-AKA: too many notification "
"rounds (only one allowed)");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
data->num_notification++;
if (attr->notification == -1) {
wpa_printf(MSG_INFO, "EAP-AKA: no AT_NOTIFICATION in "
"Notification message");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
if ((attr->notification & 0x4000) == 0 &&
eap_aka_process_notification_auth(data, req, reqDataLen, attr)) {
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
@@ -652,7 +608,7 @@ static u8 * eap_aka_process_notification(struct eap_sm *sm,
if (attr->notification >= 0 && attr->notification < 32768) {
data->state = FAILURE;
}
- return eap_aka_response_notification(sm, data, req, respDataLen,
+ return eap_aka_response_notification(data, req, respDataLen,
attr->notification);
}
@@ -672,7 +628,7 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
if (data->reauth_id == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: Server is trying "
"reauthentication, but no reauth_id available");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
@@ -681,14 +637,14 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
"did not have valid AT_MAC");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
if (attr->encr_data == NULL || attr->iv == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
"message did not include encrypted data");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
@@ -698,7 +654,7 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
if (decrypted == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
"data from reauthentication message");
- return eap_aka_client_error(sm, data, req, respDataLen,
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
@@ -706,37 +662,48 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
wpa_printf(MSG_INFO, "EAP-AKA: (encr) No%s%s in reauth packet",
!eattr.nonce_s ? " AT_NONCE_S" : "",
eattr.counter < 0 ? " AT_COUNTER" : "");
- free(decrypted);
- return eap_aka_client_error(sm, data, req, respDataLen,
+ os_free(decrypted);
+ return eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
- if (eattr.counter <= data->counter) {
+ if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
+ u8 *res;
wpa_printf(MSG_INFO, "EAP-AKA: (encr) Invalid counter "
"(%d <= %d)", eattr.counter, data->counter);
data->counter_too_small = eattr.counter;
+
+ eap_sim_derive_keys_reauth(eattr.counter, data->reauth_id,
+ data->reauth_id_len, eattr.nonce_s,
+ data->mk, NULL, NULL);
+
/* Reply using Re-auth w/ AT_COUNTER_TOO_SMALL. The current
* reauth_id must not be used to start a new reauthentication.
* However, since it was used in the last EAP-Response-Identity
* packet, it has to saved for the following fullauth to be
* used in MK derivation. */
- free(data->last_eap_identity);
+ os_free(data->last_eap_identity);
data->last_eap_identity = data->reauth_id;
data->last_eap_identity_len = data->reauth_id_len;
data->reauth_id = NULL;
data->reauth_id_len = 0;
- free(decrypted);
- return eap_aka_response_reauth(sm, data, req, respDataLen, 1);
+
+ res = eap_aka_response_reauth(data, req, respDataLen, 1,
+ eattr.nonce_s);
+ os_free(decrypted);
+
+ return res;
}
data->counter = eattr.counter;
- memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
+ os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-AKA: (encr) AT_NONCE_S",
data->nonce_s, EAP_SIM_NONCE_S_LEN);
eap_sim_derive_keys_reauth(data->counter,
data->reauth_id, data->reauth_id_len,
- data->nonce_s, data->mk, data->msk);
+ data->nonce_s, data->mk, data->msk,
+ data->emsk);
eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
eap_aka_learn_ids(data, &eattr);
@@ -750,8 +717,9 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
"fast reauths performed - force fullauth");
eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
}
- free(decrypted);
- return eap_aka_response_reauth(sm, data, req, respDataLen, 0);
+ os_free(decrypted);
+ return eap_aka_response_reauth(data, req, respDataLen, 0,
+ data->nonce_s);
}
@@ -761,7 +729,6 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
size_t *respDataLen)
{
struct eap_aka_data *data = priv;
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *req;
u8 subtype, *res;
const u8 *pos;
@@ -769,14 +736,15 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
size_t len;
wpa_hexdump(MSG_DEBUG, "EAP-AKA: EAP data", reqData, reqDataLen);
- if (config == NULL || config->identity == NULL) {
+ if (eap_get_config_identity(sm, &len) == NULL) {
wpa_printf(MSG_INFO, "EAP-AKA: Identity not configured");
- eap_sm_request_identity(sm, config);
+ eap_sm_request_identity(sm);
ret->ignore = TRUE;
return NULL;
}
- pos = eap_hdr_validate(EAP_TYPE_AKA, reqData, reqDataLen, &len);
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_AKA,
+ reqData, reqDataLen, &len);
if (pos == NULL || len < 1) {
ret->ignore = TRUE;
return NULL;
@@ -794,14 +762,14 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
pos += 2; /* Reserved */
if (eap_sim_parse_attr(pos, reqData + len, &attr, 1, 0)) {
- res = eap_aka_client_error(sm, data, req, respDataLen,
+ res = eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
goto done;
}
switch (subtype) {
case EAP_AKA_SUBTYPE_IDENTITY:
- res = eap_aka_process_identity(sm, data, req, len,
+ res = eap_aka_process_identity(sm, data, req,
respDataLen, &attr);
break;
case EAP_AKA_SUBTYPE_CHALLENGE:
@@ -818,12 +786,12 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
break;
case EAP_AKA_SUBTYPE_CLIENT_ERROR:
wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Client-Error");
- res = eap_aka_client_error(sm, data, req, respDataLen,
+ res = eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
break;
default:
wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown subtype=%d", subtype);
- res = eap_aka_client_error(sm, data, req, respDataLen,
+ res = eap_aka_client_error(data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
break;
}
@@ -834,7 +802,12 @@ done:
ret->methodState = METHOD_DONE;
} else if (data->state == SUCCESS) {
ret->decision = DECISION_COND_SUCC;
- ret->methodState = METHOD_DONE;
+ /*
+ * It is possible for the server to reply with AKA
+ * Notification, so we must allow the method to continue and
+ * not only accept EAP-Success at this point.
+ */
+ ret->methodState = METHOD_MAY_CONT;
}
if (ret->methodState == METHOD_DONE) {
@@ -903,28 +876,59 @@ static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = malloc(EAP_SIM_KEYING_DATA_LEN);
+ key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
if (key == NULL)
return NULL;
*len = EAP_SIM_KEYING_DATA_LEN;
- memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+ os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
return key;
}
-const struct eap_method eap_method_aka =
+static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
- .method = EAP_TYPE_AKA,
- .name = "AKA",
- .init = eap_aka_init,
- .deinit = eap_aka_deinit,
- .process = eap_aka_process,
- .isKeyAvailable = eap_aka_isKeyAvailable,
- .getKey = eap_aka_getKey,
- .has_reauth_data = eap_aka_has_reauth_data,
- .deinit_for_reauth = eap_aka_deinit_for_reauth,
- .init_for_reauth = eap_aka_init_for_reauth,
- .get_identity = eap_aka_get_identity,
-};
+ struct eap_aka_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+
+ return key;
+}
+
+
+int eap_peer_aka_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_aka_init;
+ eap->deinit = eap_aka_deinit;
+ eap->process = eap_aka_process;
+ eap->isKeyAvailable = eap_aka_isKeyAvailable;
+ eap->getKey = eap_aka_getKey;
+ eap->has_reauth_data = eap_aka_has_reauth_data;
+ eap->deinit_for_reauth = eap_aka_deinit_for_reauth;
+ eap->init_for_reauth = eap_aka_init_for_reauth;
+ eap->get_identity = eap_aka_get_identity;
+ eap->get_emsk = eap_aka_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_defs.h b/contrib/wpa_supplicant/eap_defs.h
index 9cd44905153d..8ea923a8f9d0 100644
--- a/contrib/wpa_supplicant/eap_defs.h
+++ b/contrib/wpa_supplicant/eap_defs.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant/hostapd / Shared EAP definitions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: Shared EAP definitions
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -17,12 +17,20 @@
/* RFC 3748 - Extensible Authentication Protocol (EAP) */
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct eap_hdr {
u8 code;
u8 identifier;
u16 length; /* including code and identifier; network byte order */
/* followed by length-4 octets of data */
-} __attribute__ ((packed));
+} 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 };
@@ -40,17 +48,28 @@ typedef enum {
EAP_TYPE_GTC = 6, /* RFC 3748 */
EAP_TYPE_TLS = 13 /* RFC 2716 */,
EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
- EAP_TYPE_SIM = 18 /* draft-haverinen-pppext-eap-sim-12.txt */,
+ EAP_TYPE_SIM = 18 /* RFC 4186 */,
EAP_TYPE_TTLS = 21 /* draft-ietf-pppext-eap-ttls-02.txt */,
- EAP_TYPE_AKA = 23 /* draft-arkko-pppext-eap-aka-12.txt */,
+ 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_FAST = 43 /* draft-cam-winget-eap-fast-00.txt */,
- EAP_TYPE_PAX = 46, /* draft-clancy-eap-pax-04.txt */
- EAP_TYPE_EXPANDED_NAK = 254 /* RFC 3748 */,
- EAP_TYPE_PSK = 255 /* EXPERIMENTAL - type not yet allocated
- * draft-bersani-eap-psk-09 */
+ EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-05.txt */,
+ EAP_TYPE_PAX = 46 /* RFC 4746 */,
+ EAP_TYPE_PSK = 47 /* RFC 4764 */,
+ EAP_TYPE_SAKE = 48 /* RFC 4763 */,
+ EAP_TYPE_EXPANDED = 254 /* RFC 3748 */,
+ EAP_TYPE_GPSK = 255 /* EXPERIMENTAL - type not yet allocated
+ * draft-ietf-emu-eap-gpsk-01.txt */
} EapType;
+
+/* SMI Network Management Private Enterprise Code for vendor specific types */
+enum {
+ EAP_VENDOR_IETF = 0
+};
+
+#define EAP_MSK_LEN 64
+#define EAP_EMSK_LEN 64
+
#endif /* EAP_DEFS_H */
diff --git a/contrib/wpa_supplicant/eap_fast.c b/contrib/wpa_supplicant/eap_fast.c
index ff8f76c69e73..d9347a986d9d 100644
--- a/contrib/wpa_supplicant/eap_fast.c
+++ b/contrib/wpa_supplicant/eap_fast.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-FAST (draft-cam-winget-eap-fast-00.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-FAST (draft-cam-winget-eap-fast-03.txt)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,14 +12,11 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
#include "eap_tls_common.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "tls.h"
#include "eap_tlv.h"
@@ -35,6 +32,8 @@
#define EAP_FAST_VERSION 1
#define EAP_FAST_KEY_LEN 64
#define EAP_FAST_PAC_KEY_LEN 32
+#define EAP_FAST_SIMCK_LEN 40
+#define EAP_FAST_SKS_LEN 40
#define TLS_EXT_PAC_OPAQUE 35
@@ -61,19 +60,11 @@ struct pac_tlv_hdr {
};
-/* draft-cam-winget-eap-fast-02.txt:
- * 6.2 EAP-FAST Authentication Phase 1: Key Derivations */
-struct eap_fast_key_block_auth {
- /* Extra key material after TLS key_block */
- u8 session_key_seed[40];
-};
-
-
/* draft-cam-winget-eap-fast-provisioning-01.txt:
* 3.4 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[40];
+ u8 session_key_seed[EAP_FAST_SKS_LEN];
u8 server_challenge[16];
u8 client_challenge[16];
};
@@ -105,33 +96,36 @@ struct eap_fast_data {
void *phase2_priv;
int phase2_success;
- u8 phase2_type;
- u8 *phase2_types;
+ struct eap_method_type phase2_type;
+ struct eap_method_type *phase2_types;
size_t num_phase2_types;
int resuming; /* starting a resumed session */
- struct eap_fast_key_block_auth *key_block_a;
struct eap_fast_key_block_provisioning *key_block_p;
int provisioning_allowed; /* is PAC provisioning allowed */
int provisioning; /* doing PAC provisioning (not the normal auth) */
u8 key_data[EAP_FAST_KEY_LEN];
+ u8 emsk[EAP_EMSK_LEN];
int success;
struct eap_fast_pac *pac;
struct eap_fast_pac *current_pac;
int tls_master_secret_set;
+
+ u8 simck[EAP_FAST_SIMCK_LEN];
+ int simck_idx;
};
static void eap_fast_free_pac(struct eap_fast_pac *pac)
{
- free(pac->pac_opaque);
- free(pac->pac_info);
- free(pac->a_id);
- free(pac->i_id);
- free(pac->a_id_info);
- free(pac);
+ os_free(pac->pac_opaque);
+ os_free(pac->pac_info);
+ os_free(pac->a_id);
+ os_free(pac->i_id);
+ os_free(pac->a_id_info);
+ os_free(pac);
}
@@ -142,7 +136,7 @@ static struct eap_fast_pac * eap_fast_get_pac(struct eap_fast_data *data,
while (pac) {
if (pac->a_id_len == a_id_len &&
- memcmp(pac->a_id, a_id, a_id_len) == 0) {
+ os_memcmp(pac->a_id, a_id, a_id_len) == 0) {
return pac;
}
pac = pac->next;
@@ -164,7 +158,7 @@ static int eap_fast_add_pac(struct eap_fast_data *data,
prev = NULL;
while (pac) {
if (pac->a_id_len == entry->a_id_len &&
- memcmp(pac->a_id, entry->a_id, pac->a_id_len) == 0) {
+ os_memcmp(pac->a_id, entry->a_id, pac->a_id_len) == 0) {
if (prev == NULL) {
data->pac = pac->next;
} else {
@@ -180,60 +174,59 @@ static int eap_fast_add_pac(struct eap_fast_data *data,
}
/* Allocate a new entry and add it to the list of PACs. */
- pac = malloc(sizeof(*pac));
+ pac = os_zalloc(sizeof(*pac));
if (pac == NULL)
return -1;
- memset(pac, 0, sizeof(*pac));
- memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
+ os_memcpy(pac->pac_key, entry->pac_key, EAP_FAST_PAC_KEY_LEN);
if (entry->pac_opaque) {
- pac->pac_opaque = malloc(entry->pac_opaque_len);
+ pac->pac_opaque = os_malloc(entry->pac_opaque_len);
if (pac->pac_opaque == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->pac_opaque, entry->pac_opaque,
- entry->pac_opaque_len);
+ os_memcpy(pac->pac_opaque, entry->pac_opaque,
+ entry->pac_opaque_len);
pac->pac_opaque_len = entry->pac_opaque_len;
}
if (entry->pac_info) {
- pac->pac_info = malloc(entry->pac_info_len);
+ pac->pac_info = os_malloc(entry->pac_info_len);
if (pac->pac_info == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->pac_info, entry->pac_info,
- entry->pac_info_len);
+ os_memcpy(pac->pac_info, entry->pac_info,
+ entry->pac_info_len);
pac->pac_info_len = entry->pac_info_len;
}
if (entry->a_id) {
- pac->a_id = malloc(entry->a_id_len);
+ pac->a_id = os_malloc(entry->a_id_len);
if (pac->a_id == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->a_id, entry->a_id,
- entry->a_id_len);
+ os_memcpy(pac->a_id, entry->a_id,
+ entry->a_id_len);
pac->a_id_len = entry->a_id_len;
}
if (entry->i_id) {
- pac->i_id = malloc(entry->i_id_len);
+ pac->i_id = os_malloc(entry->i_id_len);
if (pac->i_id == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->i_id, entry->i_id,
- entry->i_id_len);
+ os_memcpy(pac->i_id, entry->i_id,
+ entry->i_id_len);
pac->i_id_len = entry->i_id_len;
}
if (entry->a_id_info) {
- pac->a_id_info = malloc(entry->a_id_info_len);
+ pac->a_id_info = os_malloc(entry->a_id_info_len);
if (pac->a_id_info == NULL) {
eap_fast_free_pac(pac);
return -1;
}
- memcpy(pac->a_id_info, entry->a_id_info,
- entry->a_id_info_len);
+ os_memcpy(pac->a_id_info, entry->a_id_info,
+ entry->a_id_info_len);
pac->a_id_info_len = entry->a_id_info_len;
}
pac->next = data->pac;
@@ -267,7 +260,7 @@ static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char *buf,
len = l_end - rc->pos;
if (len >= buf_len)
len = buf_len - 1;
- memcpy(buf, rc->pos, len);
+ os_memcpy(buf, rc->pos, len);
buf[len] = '\0';
rc->pos = l_end + 1;
}
@@ -293,15 +286,15 @@ static u8 * eap_fast_parse_hex(const char *value, size_t *len)
if (value == NULL)
return NULL;
- hlen = strlen(value);
+ hlen = os_strlen(value);
if (hlen & 1)
return NULL;
*len = hlen / 2;
- buf = malloc(*len);
+ buf = os_malloc(*len);
if (buf == NULL)
return NULL;
if (hexstr2bin(value, buf, *len)) {
- free(buf);
+ os_free(buf);
return NULL;
}
return buf;
@@ -321,9 +314,9 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
if (pac_file == NULL)
return -1;
- memset(&rc, 0, sizeof(rc));
+ os_memset(&rc, 0, sizeof(rc));
- if (strncmp(pac_file, "blob://", 7) == 0) {
+ if (os_strncmp(pac_file, "blob://", 7) == 0) {
const struct wpa_config_blob *blob;
blob = eap_get_config_blob(sm, pac_file + 7);
if (blob == NULL) {
@@ -344,17 +337,17 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
}
}
- buf = malloc(buf_len);
+ buf = os_malloc(buf_len);
if (buf == NULL) {
return -1;
}
line++;
if (eap_fast_read_line(&rc, buf, buf_len) < 0 ||
- strcmp(pac_file_hdr, buf) != 0) {
+ os_strcmp(pac_file_hdr, buf) != 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Unrecognized header line in "
"PAC file '%s'", pac_file);
- free(buf);
+ os_free(buf);
if (rc.f)
fclose(rc.f);
return -1;
@@ -362,12 +355,12 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
while (eap_fast_read_line(&rc, buf, buf_len) == 0) {
line++;
- pos = strchr(buf, '=');
+ pos = os_strchr(buf, '=');
if (pos) {
*pos++ = '\0';
}
- if (strcmp(buf, "START") == 0) {
+ if (os_strcmp(buf, "START") == 0) {
if (pac) {
wpa_printf(MSG_INFO, "EAP-FAST: START line "
"without END in '%s:%d'",
@@ -375,15 +368,14 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
break;
}
- pac = malloc(sizeof(*pac));
+ pac = os_zalloc(sizeof(*pac));
if (pac == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: No memory for "
"PAC entry");
ret = -1;
break;
}
- memset(pac, 0, sizeof(*pac));
- } else if (strcmp(buf, "END") == 0) {
+ } else if (os_strcmp(buf, "END") == 0) {
if (pac == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: END line "
"without START in '%s:%d'",
@@ -395,7 +387,7 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
data->pac = pac;
pac = NULL;
count++;
- } else if (pac && strcmp(buf, "PAC-Key") == 0) {
+ } else if (pac && os_strcmp(buf, "PAC-Key") == 0) {
u8 *key;
size_t key_len;
key = eap_fast_parse_hex(pos, &key_len);
@@ -403,13 +395,14 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
"PAC-Key '%s:%d'", pac_file, line);
ret = -1;
- free(key);
+ os_free(key);
break;
}
- memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
- free(key);
- } else if (pac && strcmp(buf, "PAC-Opaque") == 0) {
+ os_memcpy(pac->pac_key, key, EAP_FAST_PAC_KEY_LEN);
+ os_free(key);
+ } else if (pac && os_strcmp(buf, "PAC-Opaque") == 0) {
+ os_free(pac->pac_opaque);
pac->pac_opaque =
eap_fast_parse_hex(pos, &pac->pac_opaque_len);
if (pac->pac_opaque == NULL) {
@@ -419,7 +412,8 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
break;
}
- } else if (pac && strcmp(buf, "A-ID") == 0) {
+ } else if (pac && os_strcmp(buf, "A-ID") == 0) {
+ os_free(pac->a_id);
pac->a_id = eap_fast_parse_hex(pos, &pac->a_id_len);
if (pac->a_id == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
@@ -427,7 +421,8 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
break;
}
- } else if (pac && strcmp(buf, "I-ID") == 0) {
+ } else if (pac && os_strcmp(buf, "I-ID") == 0) {
+ os_free(pac->i_id);
pac->i_id = eap_fast_parse_hex(pos, &pac->i_id_len);
if (pac->i_id == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid "
@@ -435,7 +430,8 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
break;
}
- } else if (pac && strcmp(buf, "A-ID-Info") == 0) {
+ } else if (pac && os_strcmp(buf, "A-ID-Info") == 0) {
+ os_free(pac->a_id_info);
pac->a_id_info =
eap_fast_parse_hex(pos, &pac->a_id_info_len);
if (pac->a_id_info == NULL) {
@@ -455,7 +451,7 @@ static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
ret = -1;
}
- free(buf);
+ os_free(buf);
if (rc.f)
fclose(rc.f);
@@ -472,20 +468,20 @@ static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
const char *field, const u8 *data,
size_t len, int txt)
{
- int i;
- size_t need;
+ size_t i, need;
+ int ret;
if (data == NULL || *buf == NULL)
return;
- need = strlen(field) + len * 2 + 30;
+ need = os_strlen(field) + len * 2 + 30;
if (txt)
- need += strlen(field) + len + 20;
+ need += os_strlen(field) + len + 20;
if (*pos - *buf + need > *buf_len) {
- char *nbuf = realloc(*buf, *buf_len + need);
+ char *nbuf = os_realloc(*buf, *buf_len + need);
if (nbuf == NULL) {
- free(*buf);
+ os_free(*buf);
*buf = NULL;
return;
}
@@ -493,21 +489,33 @@ static void eap_fast_write(char **buf, char **pos, size_t *buf_len,
*buf_len += need;
}
- *pos += snprintf(*pos, *buf + *buf_len - *pos, "%s=", field);
- for (i = 0; i < len; i++) {
- *pos += snprintf(*pos, *buf + *buf_len - *pos,
- "%02x", data[i]);
- }
- *pos += snprintf(*pos, *buf + *buf_len - *pos, "\n");
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos, "%s=", field);
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
+ *pos += wpa_snprintf_hex(*pos, *buf + *buf_len - *pos, data, len);
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n");
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
if (txt) {
- *pos += snprintf(*pos, *buf + *buf_len - *pos,
- "%s-txt=", field);
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos,
+ "%s-txt=", field);
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
for (i = 0; i < len; i++) {
- *pos += snprintf(*pos, *buf + *buf_len - *pos,
- "%c", data[i]);
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos,
+ "%c", data[i]);
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
}
- *pos += snprintf(*pos, *buf + *buf_len - *pos, "\n");
+ ret = os_snprintf(*pos, *buf + *buf_len - *pos, "\n");
+ if (ret < 0 || ret >= *buf + *buf_len - *pos)
+ return;
+ *pos += ret;
}
}
@@ -517,7 +525,7 @@ static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
{
FILE *f;
struct eap_fast_pac *pac;
- int count = 0;
+ int count = 0, ret;
char *buf, *pos;
size_t buf_len;
@@ -525,15 +533,25 @@ static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
return -1;
buf_len = 1024;
- pos = buf = malloc(buf_len);
+ pos = buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
- pos += snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
+ ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
+ if (ret < 0 || ret >= buf + buf_len - pos) {
+ os_free(buf);
+ return -1;
+ }
+ pos += ret;
pac = data->pac;
while (pac) {
- pos += snprintf(pos, buf + buf_len - pos, "START\n");
+ ret = os_snprintf(pos, buf + buf_len - pos, "START\n");
+ if (ret < 0 || ret >= buf + buf_len - pos) {
+ os_free(buf);
+ return -1;
+ }
+ pos += ret;
eap_fast_write(&buf, &pos, &buf_len, "PAC-Key", pac->pac_key,
EAP_FAST_PAC_KEY_LEN, 0);
eap_fast_write(&buf, &pos, &buf_len, "PAC-Opaque",
@@ -546,31 +564,35 @@ static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
pac->i_id_len, 1);
eap_fast_write(&buf, &pos, &buf_len, "A-ID-Info",
pac->a_id_info, pac->a_id_info_len, 1);
- pos += snprintf(pos, buf + buf_len - pos, "END\n");
- count++;
- pac = pac->next;
-
if (buf == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No memory for PAC "
"data");
return -1;
}
+ ret = os_snprintf(pos, buf + buf_len - pos, "END\n");
+ if (ret < 0 || ret >= buf + buf_len - pos) {
+ os_free(buf);
+ return -1;
+ }
+ pos += ret;
+ count++;
+ pac = pac->next;
}
- if (strncmp(pac_file, "blob://", 7) == 0) {
+ if (os_strncmp(pac_file, "blob://", 7) == 0) {
struct wpa_config_blob *blob;
- blob = malloc(sizeof(*blob));
+ blob = os_zalloc(sizeof(*blob));
if (blob == NULL) {
- free(buf);
+ os_free(buf);
return -1;
}
- memset(blob, 0, sizeof(*blob));
blob->data = (u8 *) buf;
blob->len = pos - buf;
buf = NULL;
- blob->name = strdup(pac_file + 7);
+ blob->name = os_strdup(pac_file + 7);
if (blob->name == NULL) {
- wpa_config_free_blob(blob);
+ os_free(blob->data);
+ os_free(blob);
return -1;
}
eap_set_config_blob(sm, blob);
@@ -579,11 +601,11 @@ static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
if (f == NULL) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
"file '%s' for writing", pac_file);
- free(buf);
+ os_free(buf);
return -1;
}
fprintf(f, "%s", buf);
- free(buf);
+ os_free(buf);
fclose(f);
}
@@ -599,14 +621,13 @@ static void * eap_fast_init(struct eap_sm *sm)
struct eap_fast_data *data;
struct wpa_ssid *config = eap_get_config(sm);
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
data->fast_version = EAP_FAST_VERSION;
if (config && config->phase1) {
- if (strstr(config->phase1, "fast_provisioning=1")) {
+ if (os_strstr(config->phase1, "fast_provisioning=1")) {
data->provisioning_allowed = 1;
wpa_printf(MSG_DEBUG, "EAP-FAST: Automatic PAC "
"provisioning is allowed");
@@ -615,15 +636,17 @@ static void * eap_fast_init(struct eap_sm *sm)
if (config && config->phase2) {
char *start, *pos, *buf;
- u8 method, *methods = NULL, *_methods;
+ struct eap_method_type *methods = NULL, *_methods;
+ u8 method;
size_t num_methods = 0;
- start = buf = strdup(config->phase2);
+ start = buf = os_strdup(config->phase2);
if (buf == NULL) {
eap_fast_deinit(sm, data);
return NULL;
}
while (start && *start != '\0') {
- pos = strstr(start, "auth=");
+ int vendor;
+ pos = os_strstr(start, "auth=");
if (pos == NULL)
break;
if (start != pos && *(pos - 1) != ' ') {
@@ -632,28 +655,33 @@ static void * eap_fast_init(struct eap_sm *sm)
}
start = pos + 5;
- pos = strchr(start, ' ');
+ pos = os_strchr(start, ' ');
if (pos)
*pos++ = '\0';
- method = eap_get_phase2_type(start);
- if (method == EAP_TYPE_NONE) {
+ method = eap_get_phase2_type(start, &vendor);
+ if (vendor == EAP_VENDOR_IETF &&
+ method == EAP_TYPE_NONE) {
wpa_printf(MSG_ERROR, "EAP-FAST: Unsupported "
"Phase2 method '%s'", start);
} else {
num_methods++;
- _methods = realloc(methods, num_methods);
+ _methods = os_realloc(
+ methods,
+ num_methods * sizeof(*methods));
if (_methods == NULL) {
- free(methods);
+ os_free(methods);
+ os_free(buf);
eap_fast_deinit(sm, data);
return NULL;
}
methods = _methods;
- methods[num_methods - 1] = method;
+ methods[num_methods - 1].vendor = vendor;
+ methods[num_methods - 1].method = method;
}
start = pos;
}
- free(buf);
+ os_free(buf);
data->phase2_types = methods;
data->num_phase2_types = num_methods;
}
@@ -667,8 +695,10 @@ static void * eap_fast_init(struct eap_sm *sm)
return NULL;
}
wpa_hexdump(MSG_DEBUG, "EAP-FAST: Phase2 EAP types",
- data->phase2_types, data->num_phase2_types);
- data->phase2_type = EAP_TYPE_NONE;
+ (u8 *) data->phase2_types,
+ data->num_phase2_types * sizeof(struct eap_method_type));
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_NONE;
if (eap_tls_ssl_init(sm, &data->ssl, config)) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize SSL.");
@@ -706,9 +736,8 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
return;
if (data->phase2_priv && data->phase2_method)
data->phase2_method->deinit(sm, data->phase2_priv);
- free(data->phase2_types);
- free(data->key_block_a);
- free(data->key_block_p);
+ os_free(data->phase2_types);
+ os_free(data->key_block_p);
eap_tls_ssl_deinit(sm, &data->ssl);
pac = data->pac;
@@ -718,7 +747,7 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
pac = pac->next;
eap_fast_free_pac(prev);
}
- free(data);
+ os_free(data);
}
@@ -732,7 +761,7 @@ static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
/* TODO: add support for fragmentation, if needed. This will need to
* add TLS Message Length field, if the frame is fragmented. */
- resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
if (resp == NULL)
return 0;
@@ -749,7 +778,7 @@ static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
if (res < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt Phase 2 "
"data");
- free(resp);
+ os_free(resp);
return 0;
}
@@ -760,53 +789,57 @@ static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
}
-static int eap_fast_phase2_nak(struct eap_sm *sm,
- struct eap_fast_data *data,
+static int eap_fast_phase2_nak(struct eap_fast_data *data,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
struct eap_hdr *resp_hdr;
u8 *pos = (u8 *) (hdr + 1);
+ size_t i;
+ /* TODO: add support for expanded Nak */
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: Nak type=%d", *pos);
wpa_hexdump(MSG_DEBUG, "EAP-FAST: Allowed Phase2 EAP types",
- data->phase2_types, data->num_phase2_types);
- *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_types;
- *resp = malloc(*resp_len);
+ (u8 *) data->phase2_types,
+ data->num_phase2_types * sizeof(struct eap_method_type));
+ *resp_len = sizeof(struct eap_hdr) + 1;
+ *resp = os_malloc(*resp_len + data->num_phase2_types);
if (*resp == NULL)
return -1;
resp_hdr = (struct eap_hdr *) (*resp);
resp_hdr->code = EAP_CODE_RESPONSE;
resp_hdr->identifier = hdr->identifier;
- resp_hdr->length = host_to_be16(*resp_len);
pos = (u8 *) (resp_hdr + 1);
*pos++ = EAP_TYPE_NAK;
- memcpy(pos, data->phase2_types, data->num_phase2_types);
+ for (i = 0; i < data->num_phase2_types; i++) {
+ if (data->phase2_types[i].vendor == EAP_VENDOR_IETF &&
+ data->phase2_types[i].method < 256) {
+ (*resp_len)++;
+ *pos++ = data->phase2_types[i].method;
+ }
+ }
+ resp_hdr->length = host_to_be16(*resp_len);
return 0;
}
-static int eap_fast_derive_msk(struct eap_sm *sm, struct eap_fast_data *data)
+static int eap_fast_derive_msk(struct eap_fast_data *data)
{
- u8 isk[32];
- u8 imck[60];
-
- if (data->key_block_a == NULL)
- return -1;
-
- memset(isk, 0, sizeof(isk));
- sha1_t_prf(data->key_block_a->session_key_seed,
- sizeof(data->key_block_a->session_key_seed),
- "Inner Methods Compound Keys",
- isk, sizeof(isk), imck, sizeof(imck));
- sha1_t_prf(imck, 40, "Session Key Generating Function", (u8 *) "", 0,
+ /* Derive EAP Master Session Keys (section 5.4) */
+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Session Key Generating Function", (u8 *) "", 0,
data->key_data, EAP_FAST_KEY_LEN);
-
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (MSK)",
data->key_data, EAP_FAST_KEY_LEN);
+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Extended Session Key Generating Function",
+ (u8 *) "", 0, data->emsk, EAP_EMSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: Derived key (EMSK)",
+ data->emsk, EAP_EMSK_LEN);
+
data->success = 1;
return 0;
@@ -823,7 +856,8 @@ static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
size_t seed_len, server_random_len;
if (data->tls_master_secret_set || !data->current_pac ||
- tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys)) {
+ tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
+ keys.client_random == NULL) {
return 0;
}
@@ -857,14 +891,13 @@ static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
wpa_hexdump(MSG_DEBUG, "EAP-FAST: server_random",
server_random, server_random_len);
-
seed_len = keys.client_random_len + server_random_len;
- seed = malloc(seed_len);
+ seed = os_malloc(seed_len);
if (seed == NULL)
return -1;
- memcpy(seed, server_random, server_random_len);
- memcpy(seed + server_random_len,
- keys.client_random, keys.client_random_len);
+ os_memcpy(seed, server_random, server_random_len);
+ os_memcpy(seed + server_random_len,
+ keys.client_random, keys.client_random_len);
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: T-PRF seed", seed, seed_len);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: PAC-Key",
@@ -874,7 +907,7 @@ static int eap_fast_set_tls_master_secret(struct eap_sm *sm,
sha1_t_prf(data->current_pac->pac_key, EAP_FAST_PAC_KEY_LEN,
"PAC to master secret label hash",
seed, seed_len, master_secret, sizeof(master_secret));
- free(seed);
+ os_free(seed);
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: TLS pre-master-secret",
master_secret, sizeof(master_secret));
@@ -890,63 +923,86 @@ static u8 * eap_fast_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len)
{
struct tls_keys keys;
- u8 *rnd;
- u8 *out;
+ u8 *rnd = NULL, *out;
int block_size;
- if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
- return NULL;
block_size = tls_connection_get_keyblock_size(sm->ssl_ctx, data->conn);
if (block_size < 0)
return NULL;
- out = malloc(block_size + len);
- rnd = malloc(keys.client_random_len + keys.server_random_len);
- if (out == NULL || rnd == NULL) {
- free(out);
- free(rnd);
+
+ out = os_malloc(block_size + len);
+ if (out == NULL)
return NULL;
+
+ if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 1, out,
+ block_size + len) == 0) {
+ os_memmove(out, out + block_size, len);
+ return out;
}
- memcpy(rnd, keys.server_random, keys.server_random_len);
- memcpy(rnd + keys.server_random_len, keys.client_random,
- keys.client_random_len);
+
+ if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ goto fail;
+
+ rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+ if (rnd == NULL)
+ goto fail;
+
+ os_memcpy(rnd, keys.server_random, keys.server_random_len);
+ os_memcpy(rnd + keys.server_random_len, keys.client_random,
+ keys.client_random_len);
wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
"expansion", keys.master_key, keys.master_key_len);
if (tls_prf(keys.master_key, keys.master_key_len,
label, rnd, keys.client_random_len +
- keys.server_random_len, out, block_size + len)) {
- free(rnd);
- free(out);
- return NULL;
- }
- free(rnd);
- memmove(out, out + block_size, len);
+ keys.server_random_len, out, block_size + len))
+ goto fail;
+ os_free(rnd);
+ os_memmove(out, out + block_size, len);
return out;
+
+fail:
+ os_free(rnd);
+ os_free(out);
+ return NULL;
}
static void eap_fast_derive_key_auth(struct eap_sm *sm,
struct eap_fast_data *data)
{
- free(data->key_block_a);
- data->key_block_a = (struct eap_fast_key_block_auth *)
- eap_fast_derive_key(sm, &data->ssl, "key expansion",
- sizeof(*data->key_block_a));
- if (data->key_block_a == NULL) {
+ u8 *sks;
+
+ /* draft-cam-winget-eap-fast-05.txt:
+ * 5.1 EAP-FAST Authentication Phase 1: Key Derivations
+ * Extra key material after TLS key_block: session_ket_seed[40]
+ */
+
+ sks = eap_fast_derive_key(sm, &data->ssl, "key expansion",
+ EAP_FAST_SKS_LEN);
+ if (sks == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive "
"session_key_seed");
return;
}
- wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed",
- data->key_block_a->session_key_seed,
- sizeof(data->key_block_a->session_key_seed));
+
+ /*
+ * draft-cam-winget-eap-fast-05.txt, 5.2:
+ * S-IMCK[0] = session_key_seed
+ */
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
+ sks, EAP_FAST_SKS_LEN);
+ data->simck_idx = 0;
+ os_memcpy(data->simck, sks, EAP_FAST_SIMCK_LEN);
+ os_free(sks);
}
static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
struct eap_fast_data *data)
{
- free(data->key_block_p);
+ os_free(data->key_block_p);
data->key_block_p = (struct eap_fast_key_block_provisioning *)
eap_fast_derive_key(sm, &data->ssl, "key expansion",
sizeof(*data->key_block_p));
@@ -954,9 +1010,17 @@ static void eap_fast_derive_key_provisioning(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to derive key block");
return;
}
- wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: session_key_seed",
+ /*
+ * draft-cam-winget-eap-fast-05.txt, 5.2:
+ * S-IMCK[0] = session_key_seed
+ */
+ wpa_hexdump_key(MSG_DEBUG,
+ "EAP-FAST: session_key_seed (SKS = S-IMCK[0])",
data->key_block_p->session_key_seed,
sizeof(data->key_block_p->session_key_seed));
+ data->simck_idx = 0;
+ os_memcpy(data->simck, data->key_block_p->session_key_seed,
+ EAP_FAST_SIMCK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-FAST: server_challenge",
data->key_block_p->server_challenge,
sizeof(data->key_block_p->server_challenge));
@@ -979,7 +1043,6 @@ static void eap_fast_derive_keys(struct eap_sm *sm, struct eap_fast_data *data)
static int eap_fast_phase2_request(struct eap_sm *sm,
struct eap_fast_data *data,
struct eap_method_ret *ret,
- const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -996,30 +1059,40 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 Request: type=%d", *pos);
switch (*pos) {
case EAP_TYPE_IDENTITY:
- *resp = eap_sm_buildIdentity(sm, req->identifier, resp_len, 1);
+ *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1);
break;
default:
- if (data->phase2_type == EAP_TYPE_NONE) {
- int i;
+ if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
+ data->phase2_type.method == EAP_TYPE_NONE) {
+ size_t i;
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i] != *pos)
+ if (data->phase2_types[i].vendor !=
+ EAP_VENDOR_IETF ||
+ data->phase2_types[i].method != *pos)
continue;
- data->phase2_type = *pos;
+ data->phase2_type.vendor =
+ data->phase2_types[i].vendor;
+ data->phase2_type.method =
+ data->phase2_types[i].method;
wpa_printf(MSG_DEBUG, "EAP-FAST: Selected "
- "Phase 2 EAP method %d",
- data->phase2_type);
+ "Phase 2 EAP vendor %d method %d",
+ data->phase2_type.vendor,
+ data->phase2_type.method);
break;
}
}
- if (*pos != data->phase2_type || *pos == EAP_TYPE_NONE) {
- if (eap_fast_phase2_nak(sm, data, hdr, resp, resp_len))
+ if (*pos != data->phase2_type.method ||
+ *pos == EAP_TYPE_NONE) {
+ if (eap_fast_phase2_nak(data, hdr, resp, resp_len))
return -1;
return 0;
}
if (data->phase2_priv == NULL) {
- data->phase2_method = eap_sm_get_eap_methods(*pos);
+ data->phase2_method = eap_sm_get_eap_methods(
+ data->phase2_type.vendor,
+ data->phase2_type.method);
if (data->phase2_method) {
if (data->key_block_p) {
sm->auth_challenge =
@@ -1030,9 +1103,11 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
client_challenge;
}
sm->init_phase2 = 1;
+ sm->mschapv2_full_key = 1;
data->phase2_priv =
data->phase2_method->init(sm);
sm->init_phase2 = 0;
+ sm->mschapv2_full_key = 0;
sm->auth_challenge = NULL;
sm->peer_challenge = NULL;
}
@@ -1044,7 +1119,7 @@ static int eap_fast_phase2_request(struct eap_sm *sm,
ret->decision = DECISION_FAIL;
return -1;
}
- memset(&iret, 0, sizeof(iret));
+ os_memset(&iret, 0, sizeof(iret));
*resp = data->phase2_method->process(sm, data->phase2_priv,
&iret, (u8 *) hdr, len,
resp_len);
@@ -1071,7 +1146,7 @@ static u8 * eap_fast_tlv_nak(int vendor_id, int tlv_type, size_t *len)
{
struct eap_tlv_nak_tlv *nak;
*len = sizeof(*nak);
- nak = malloc(*len);
+ nak = os_malloc(*len);
if (nak == NULL)
return NULL;
nak->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY | EAP_TLV_NAK_TLV);
@@ -1086,7 +1161,7 @@ static u8 * eap_fast_tlv_result(int status, int intermediate, size_t *len)
{
struct eap_tlv_intermediate_result_tlv *result;
*len = sizeof(*result);
- result = malloc(*len);
+ result = os_malloc(*len);
if (result == NULL)
return NULL;
result->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
@@ -1105,11 +1180,10 @@ static u8 * eap_fast_tlv_pac_ack(size_t *len)
struct eap_tlv_pac_ack_tlv *ack;
*len = sizeof(*res) + sizeof(*ack);
- res = malloc(*len);
+ res = os_zalloc(*len);
if (res == NULL)
return NULL;
- memset(res, 0, *len);
res->tlv_type = host_to_be16(EAP_TLV_RESULT_TLV |
EAP_TLV_TYPE_MANDATORY);
res->length = host_to_be16(sizeof(*res) - sizeof(struct eap_tlv_hdr));
@@ -1132,19 +1206,19 @@ static u8 * eap_fast_tlv_eap_payload(u8 *buf, size_t *len)
struct eap_tlv_hdr *tlv;
/* Encapsulate EAP packet in EAP Payload TLV */
- tlv = malloc(sizeof(*tlv) + *len);
+ tlv = os_malloc(sizeof(*tlv) + *len);
if (tlv == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
"allocate memory for TLV "
"encapsulation");
- free(buf);
+ os_free(buf);
return NULL;
}
tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
EAP_TLV_EAP_PAYLOAD_TLV);
tlv->length = host_to_be16(*len);
- memcpy(tlv + 1, buf, *len);
- free(buf);
+ os_memcpy(tlv + 1, buf, *len);
+ os_free(buf);
*len += sizeof(*tlv);
return (u8 *) tlv;
}
@@ -1153,10 +1227,10 @@ static u8 * eap_fast_tlv_eap_payload(u8 *buf, size_t *len)
static u8 * eap_fast_process_crypto_binding(
struct eap_sm *sm, struct eap_fast_data *data,
struct eap_method_ret *ret,
- struct eap_tlv_crypto_binding__tlv *bind, size_t bind_len,
+ struct eap_tlv_crypto_binding__tlv *_bind, size_t bind_len,
size_t *resp_len, int final)
{
- u8 *resp, *sks = NULL;
+ u8 *resp;
struct eap_tlv_intermediate_result_tlv *rresult;
struct eap_tlv_crypto_binding__tlv *rbind;
u8 isk[32], imck[60], *cmk, cmac[20], *key;
@@ -1165,46 +1239,37 @@ static u8 * eap_fast_process_crypto_binding(
wpa_printf(MSG_DEBUG, "EAP-FAST: Crypto-Binding TLV: Version %d "
"Received Version %d SubType %d",
- bind->version, bind->received_version, bind->subtype);
+ _bind->version, _bind->received_version, _bind->subtype);
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: NONCE",
- bind->nonce, sizeof(bind->nonce));
+ _bind->nonce, sizeof(_bind->nonce));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Compound MAC",
- bind->compound_mac, sizeof(bind->compound_mac));
+ _bind->compound_mac, sizeof(_bind->compound_mac));
- if (bind->version != EAP_FAST_VERSION ||
- bind->received_version != EAP_FAST_VERSION ||
- bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
+ if (_bind->version != EAP_FAST_VERSION ||
+ _bind->received_version != EAP_FAST_VERSION ||
+ _bind->subtype != EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid version/subtype in "
"Crypto-Binding TLV: Version %d "
"Received Version %d SubType %d",
- bind->version, bind->received_version,
- bind->subtype);
+ _bind->version, _bind->received_version,
+ _bind->subtype);
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
resp_len);
return resp;
}
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK[%d] for Compound MIC "
+ "calculation", data->simck_idx + 1);
- if (data->provisioning) {
- if (data->key_block_p) {
- sks = data->key_block_p->session_key_seed;
- }
- } else {
- if (data->key_block_a) {
- sks = data->key_block_a->session_key_seed;
- }
- }
- if (sks == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: No Session Key Seed available "
- "for processing Crypto-Binding TLV");
- return NULL;
- }
-
- wpa_printf(MSG_DEBUG, "EAP-FAST: Determining CMK for Compound MIC "
- "calculation");
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[0] = SKS", sks, 40);
+ /*
+ * draft-cam-winget-eap-fast-05.txt, 5.2:
+ * IMCK[j] = T-PRF(S-IMCK[j-1], "Inner Methods Compound Keys",
+ * MSK[j], 60)
+ * S-IMCK[j] = first 40 octets of IMCK[j]
+ * CMK[j] = last 20 octets of IMCK[j]
+ */
- memset(isk, 0, sizeof(isk));
+ os_memset(isk, 0, sizeof(isk));
if (data->phase2_method == NULL || data->phase2_priv == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Phase 2 method not "
"available");
@@ -1222,45 +1287,42 @@ static u8 * eap_fast_process_crypto_binding(
}
if (key_len > sizeof(isk))
key_len = sizeof(isk);
- /* FIX: which end is being padded? */
-#if 0
- memcpy(isk + (sizeof(isk) - key_len), key, key_len);
-#else
- memcpy(isk, key, key_len);
-#endif
- free(key);
+ os_memcpy(isk, key, key_len);
+ os_free(key);
}
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[0]", isk, sizeof(isk));
- sha1_t_prf(sks, 40, "Inner Methods Compound Keys",
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: ISK[j]", isk, sizeof(isk));
+ sha1_t_prf(data->simck, EAP_FAST_SIMCK_LEN,
+ "Inner Methods Compound Keys",
isk, sizeof(isk), imck, sizeof(imck));
- /* S-IMCK[1] = imkc[0..39] */
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[1]", imck, 40);
- cmk = imck + 40;
- wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK", cmk, 20);
-
- memcpy(cmac, bind->compound_mac, sizeof(cmac));
- memset(bind->compound_mac, 0, sizeof(cmac));
+ data->simck_idx++;
+ os_memcpy(data->simck, imck, EAP_FAST_SIMCK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: S-IMCK[j]",
+ data->simck, EAP_FAST_SIMCK_LEN);
+ cmk = imck + EAP_FAST_SIMCK_LEN;
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: CMK[j]", cmk, 20);
+
+ os_memcpy(cmac, _bind->compound_mac, sizeof(cmac));
+ os_memset(_bind->compound_mac, 0, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Crypto-Binding TLV for Compound "
- "MAC calculation", (u8 *) bind, bind_len);
- hmac_sha1(cmk, 20, (u8 *) bind, bind_len, bind->compound_mac);
- res = memcmp(cmac, bind->compound_mac, sizeof(cmac));
+ "MAC calculation", (u8 *) _bind, bind_len);
+ hmac_sha1(cmk, 20, (u8 *) _bind, bind_len, _bind->compound_mac);
+ res = os_memcmp(cmac, _bind->compound_mac, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Received Compound MAC",
cmac, sizeof(cmac));
wpa_hexdump(MSG_MSGDUMP, "EAP-FAST: Calculated Compound MAC",
- bind->compound_mac, sizeof(cmac));
+ _bind->compound_mac, sizeof(cmac));
if (res != 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Compound MAC did not match");
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
resp_len);
- memcpy(bind->compound_mac, cmac, sizeof(cmac));
+ os_memcpy(_bind->compound_mac, cmac, sizeof(cmac));
return resp;
}
*resp_len = sizeof(*rresult) + sizeof(*rbind);
- resp = malloc(*resp_len);
+ resp = os_zalloc(*resp_len);
if (resp == NULL)
return NULL;
- memset(resp, 0, *resp_len);
/* Both intermediate and final Result TLVs are identical, so ok to use
* the same structure definition for them. */
@@ -1272,7 +1334,7 @@ static u8 * eap_fast_process_crypto_binding(
rresult->status = host_to_be16(EAP_TLV_RESULT_SUCCESS);
if (!data->provisioning && data->phase2_success &&
- eap_fast_derive_msk(sm, data) < 0) {
+ eap_fast_derive_msk(data) < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to generate MSK");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
@@ -1286,10 +1348,10 @@ static u8 * eap_fast_process_crypto_binding(
rbind->length = host_to_be16(sizeof(*rbind) -
sizeof(struct eap_tlv_hdr));
rbind->version = EAP_FAST_VERSION;
- rbind->received_version = bind->version;
+ rbind->received_version = _bind->version;
rbind->subtype = EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE;
- memcpy(rbind->nonce, bind->nonce, sizeof(bind->nonce));
- inc_byte_array(rbind->nonce, sizeof(bind->nonce));
+ os_memcpy(rbind->nonce, _bind->nonce, sizeof(_bind->nonce));
+ inc_byte_array(rbind->nonce, sizeof(rbind->nonce));
hmac_sha1(cmk, 20, (u8 *) rbind, sizeof(*rbind), rbind->compound_mac);
wpa_printf(MSG_DEBUG, "EAP-FAST: Reply Crypto-Binding TLV: Version %d "
@@ -1322,7 +1384,7 @@ static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
int type, pac_key_found = 0;
struct eap_fast_pac entry;
- memset(&entry, 0, sizeof(entry));
+ os_memset(&entry, 0, sizeof(entry));
pos = pac;
left = pac_len;
while (left > sizeof(*hdr)) {
@@ -1350,7 +1412,7 @@ static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
break;
}
pac_key_found = 1;
- memcpy(entry.pac_key, pos, len);
+ os_memcpy(entry.pac_key, pos, len);
break;
case PAC_TYPE_PAC_OPAQUE:
wpa_hexdump(MSG_DEBUG, "EAP-FAST: PAC-Opaque",
@@ -1463,10 +1525,10 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted, *pos, *end;
- int buf_len, len_decrypted, len;
+ int len_decrypted, len;
struct eap_hdr *hdr;
u8 *resp = NULL;
- size_t resp_len;
+ size_t buf_len, resp_len;
int mandatory, tlv_type;
u8 *eap_payload_tlv = NULL, *pac = NULL;
size_t eap_payload_tlv_len = 0, pac_len = 0;
@@ -1475,7 +1537,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
size_t crypto_binding_len = 0;
const u8 *msg;
size_t msg_len;
- int need_more_input;
+ int need_more_input, stop;
wpa_printf(MSG_DEBUG, "EAP-FAST: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -1488,9 +1550,9 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
buf_len = in_len;
if (data->ssl.tls_in_total > buf_len)
buf_len = data->ssl.tls_in_total;
- in_decrypted = malloc(buf_len);
+ in_decrypted = os_malloc(buf_len);
if (in_decrypted == NULL) {
- free(data->ssl.tls_in);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
wpa_printf(MSG_WARNING, "EAP-FAST: failed to allocate memory "
@@ -1501,13 +1563,13 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
msg, msg_len,
in_decrypted, buf_len);
- free(data->ssl.tls_in);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
if (len_decrypted < 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Failed to decrypt Phase 2 "
"data");
- free(in_decrypted);
+ os_free(in_decrypted);
return -1;
}
@@ -1515,7 +1577,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
in_decrypted, len_decrypted);
if (len_decrypted < 4) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-FAST: Too short Phase 2 "
"TLV frame (len=%d)", len_decrypted);
return -1;
@@ -1523,14 +1585,15 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
pos = in_decrypted;
end = in_decrypted + len_decrypted;
- while (pos + 4 < end) {
+ stop = 0;
+ while (pos + 4 < end && !stop) {
mandatory = pos[0] & 0x80;
tlv_type = WPA_GET_BE16(pos) & 0x3fff;
pos += 2;
len = WPA_GET_BE16(pos);
pos += 2;
if (pos + len > end) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
return 0;
}
@@ -1613,7 +1676,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
"mandatory TLV type %d", tlv_type);
resp = eap_fast_tlv_nak(0, tlv_type,
&resp_len);
- pos = end;
+ stop = 1;
} else {
wpa_printf(MSG_DEBUG, "EAP-FAST: ignored "
"unknown optional TLV type %d",
@@ -1629,7 +1692,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
&resp_len);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1638,7 +1701,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 1,
&resp_len);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1648,31 +1711,33 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
wpa_printf(MSG_DEBUG, "EAP-FAST: too short EAP "
"Payload TLV (len=%lu)",
(unsigned long) eap_payload_tlv_len);
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
hdr = (struct eap_hdr *) eap_payload_tlv;
if (be_to_host16(hdr->length) > eap_payload_tlv_len) {
wpa_printf(MSG_DEBUG, "EAP-FAST: EAP packet overflow "
"in EAP Payload TLV");
+ os_free(in_decrypted);
+ return 0;
}
if (hdr->code == EAP_CODE_REQUEST) {
- if (eap_fast_phase2_request(sm, data, ret, req, hdr,
+ if (eap_fast_phase2_request(sm, data, ret, hdr,
&resp, &resp_len)) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-FAST: Phase2 "
"Request processing failed");
return 0;
}
resp = eap_fast_tlv_eap_payload(resp, &resp_len);
if (resp == NULL) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
} else {
wpa_printf(MSG_INFO, "EAP-FAST: Unexpected code=%d in "
"Phase 2 EAP header", hdr->code);
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1684,7 +1749,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
crypto_binding_len,
&resp_len, final);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1695,7 +1760,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
&resp_len);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
@@ -1704,17 +1769,17 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
resp = eap_fast_process_pac(sm, data, ret, pac, pac_len,
&resp_len);
if (!resp) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
}
- free(in_decrypted);
+ os_free(in_decrypted);
if (resp == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
"empty response packet");
- resp = malloc(1);
+ resp = os_malloc(1);
if (resp == NULL)
return 0;
resp_len = 0;
@@ -1727,7 +1792,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
wpa_printf(MSG_INFO, "EAP-FAST: Failed to encrypt a Phase 2 "
"frame");
}
- free(resp);
+ os_free(resp);
return 0;
}
@@ -1803,17 +1868,17 @@ static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
} else if (data->current_pac) {
u8 *tlv;
size_t tlv_len, olen;
- struct eap_tlv_hdr *hdr;
+ struct eap_tlv_hdr *ehdr;
olen = data->current_pac->pac_opaque_len;
- tlv_len = sizeof(*hdr) + olen;
- tlv = malloc(tlv_len);
+ tlv_len = sizeof(*ehdr) + olen;
+ tlv = os_malloc(tlv_len);
if (tlv) {
- hdr = (struct eap_tlv_hdr *) tlv;
- hdr->tlv_type =
+ ehdr = (struct eap_tlv_hdr *) tlv;
+ ehdr->tlv_type =
host_to_be16(PAC_TYPE_PAC_OPAQUE);
- hdr->length = host_to_be16(olen);
- memcpy(hdr + 1, data->current_pac->pac_opaque,
- olen);
+ ehdr->length = host_to_be16(olen);
+ os_memcpy(ehdr + 1,
+ data->current_pac->pac_opaque, olen);
}
if (tlv == NULL ||
tls_connection_client_hello_ext(
@@ -1821,11 +1886,12 @@ static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
TLS_EXT_PAC_OPAQUE, tlv, tlv_len) < 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Failed to "
"add PAC-Opaque TLS extension");
- free(tlv);
+ os_free(tlv);
return NULL;
}
- free(tlv);
+ os_free(tlv);
} else {
+ u8 ciphers[2];
if (!data->provisioning_allowed) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found "
"and provisioning disabled");
@@ -1833,8 +1899,11 @@ static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
}
wpa_printf(MSG_DEBUG, "EAP-FAST: No PAC found - "
"starting provisioning");
- if (tls_connection_set_anon_dh(sm->ssl_ctx,
- data->ssl.conn)) {
+ ciphers[0] = TLS_CIPHER_ANON_DH_AES128_SHA;
+ ciphers[1] = TLS_CIPHER_NONE;
+ if (tls_connection_set_cipher_list(sm->ssl_ctx,
+ data->ssl.conn,
+ ciphers)) {
wpa_printf(MSG_INFO, "EAP-FAST: Could not "
"configure anonymous DH for TLS "
"connection");
@@ -1903,6 +1972,9 @@ static Boolean eap_fast_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_fast_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
+ struct eap_fast_data *data = priv;
+ os_free(data->key_block_p);
+ data->key_block_p = NULL;
}
@@ -1910,12 +1982,16 @@ static void * eap_fast_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_fast_data *data = priv;
if (eap_tls_reauth_init(sm, &data->ssl)) {
- free(data);
+ 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_success = 0;
data->resuming = 1;
data->provisioning = 0;
+ data->simck_idx = 0;
return priv;
}
#endif
@@ -1925,7 +2001,18 @@ static int eap_fast_get_status(struct eap_sm *sm, void *priv, char *buf,
size_t buflen, int verbose)
{
struct eap_fast_data *data = priv;
- return eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
+ int len, ret;
+
+ len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
+ if (data->phase2_method) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "EAP-FAST Phase2 method=%s\n",
+ data->phase2_method->name);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+ }
+ return len;
}
@@ -1944,30 +2031,61 @@ static u8 * eap_fast_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (!data->success)
return NULL;
- key = malloc(EAP_FAST_KEY_LEN);
+ key = os_malloc(EAP_FAST_KEY_LEN);
if (key == NULL)
return NULL;
*len = EAP_FAST_KEY_LEN;
- memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
+ os_memcpy(key, data->key_data, EAP_FAST_KEY_LEN);
return key;
}
-const struct eap_method eap_method_fast =
+static u8 * eap_fast_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
- .method = EAP_TYPE_FAST,
- .name = "FAST",
- .init = eap_fast_init,
- .deinit = eap_fast_deinit,
- .process = eap_fast_process,
- .isKeyAvailable = eap_fast_isKeyAvailable,
- .getKey = eap_fast_getKey,
- .get_status = eap_fast_get_status,
+ struct eap_fast_data *data = priv;
+ u8 *key;
+
+ if (!data->success)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+
+ return key;
+}
+
+
+int eap_peer_fast_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_FAST, "FAST");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_fast_init;
+ eap->deinit = eap_fast_deinit;
+ eap->process = eap_fast_process;
+ eap->isKeyAvailable = eap_fast_isKeyAvailable;
+ eap->getKey = eap_fast_getKey;
+ eap->get_status = eap_fast_get_status;
#if 0
- .has_reauth_data = eap_fast_has_reauth_data,
- .deinit_for_reauth = eap_fast_deinit_for_reauth,
- .init_for_reauth = eap_fast_init_for_reauth,
+ eap->has_reauth_data = eap_fast_has_reauth_data;
+ eap->deinit_for_reauth = eap_fast_deinit_for_reauth;
+ eap->init_for_reauth = eap_fast_init_for_reauth;
#endif
-};
+ eap->get_emsk = eap_fast_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_gpsk.c b/contrib/wpa_supplicant/eap_gpsk.c
new file mode 100644
index 000000000000..1366d4335986
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_gpsk.c
@@ -0,0 +1,583 @@
+/*
+ * EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-03.txt)
+ * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_i.h"
+#include "config_ssid.h"
+#include "eap_gpsk_common.h"
+
+struct eap_gpsk_data {
+ enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
+ u8 rand_server[EAP_GPSK_RAND_LEN];
+ u8 rand_client[EAP_GPSK_RAND_LEN];
+ u8 msk[EAP_MSK_LEN];
+ u8 emsk[EAP_EMSK_LEN];
+ u8 sk[EAP_GPSK_MAX_SK_LEN];
+ size_t sk_len;
+ u8 pk[EAP_GPSK_MAX_PK_LEN];
+ size_t pk_len;
+ u8 session_id;
+ int session_id_set;
+ u8 *id_client;
+ size_t id_client_len;
+ u8 *id_server;
+ size_t id_server_len;
+ int vendor; /* CSuite/Specifier */
+ int specifier; /* CSuite/Specifier */
+ u8 *psk;
+ size_t psk_len;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char * eap_gpsk_state_txt(int state)
+{
+ switch (state) {
+ case GPSK_1:
+ return "GPSK-1";
+ case GPSK_3:
+ return "GPSK-3";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "?";
+ }
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
+ eap_gpsk_state_txt(data->state),
+ eap_gpsk_state_txt(state));
+ data->state = state;
+}
+
+
+static void eap_gpsk_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_gpsk_init(struct eap_sm *sm)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_gpsk_data *data;
+
+ if (config == NULL) {
+ wpa_printf(MSG_INFO, "EAP-GPSK: No configuration found");
+ return NULL;
+ }
+
+ if (config->eappsk == NULL) {
+ wpa_printf(MSG_INFO, "EAP-GPSK: No key (eappsk) configured");
+ return NULL;
+ }
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = GPSK_1;
+
+ if (config->nai) {
+ data->id_client = os_malloc(config->nai_len);
+ if (data->id_client == NULL) {
+ eap_gpsk_deinit(sm, data);
+ return NULL;
+ }
+ os_memcpy(data->id_client, config->nai, config->nai_len);
+ data->id_client_len = config->nai_len;
+ }
+
+ data->psk = os_malloc(config->eappsk_len);
+ if (data->psk == NULL) {
+ eap_gpsk_deinit(sm, data);
+ return NULL;
+ }
+ os_memcpy(data->psk, config->eappsk, config->eappsk_len);
+ data->psk_len = config->eappsk_len;
+
+ return data;
+}
+
+
+static void eap_gpsk_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_gpsk_data *data = priv;
+ os_free(data->id_server);
+ os_free(data->id_client);
+ os_free(data->psk);
+ os_free(data);
+}
+
+
+static u8 * eap_gpsk_process_gpsk_1(struct eap_sm *sm,
+ struct eap_gpsk_data *data,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ const u8 *payload, size_t payload_len,
+ size_t *respDataLen)
+{
+ size_t len, csuite_list_len, miclen;
+ struct eap_hdr *resp;
+ u8 *rpos, *start;
+ const u8 *csuite_list, *pos, *end;
+ const struct eap_hdr *req;
+ struct eap_gpsk_csuite *csuite;
+ u16 alen;
+ int i, count;
+
+ if (data->state != GPSK_1) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-1");
+
+ req = (const struct eap_hdr *) reqData;
+ pos = payload;
+ end = payload + payload_len;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
+ return NULL;
+ }
+ alen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < alen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server overflow");
+ return NULL;
+ }
+ os_free(data->id_server);
+ data->id_server = os_malloc(alen);
+ if (data->id_server == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: No memory for ID_Server");
+ return NULL;
+ }
+ os_memcpy(data->id_server, pos, alen);
+ data->id_server_len = alen;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Server",
+ data->id_server, data->id_server_len);
+ pos += alen;
+
+ if (end - pos < EAP_GPSK_RAND_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server overflow");
+ return NULL;
+ }
+ os_memcpy(data->rand_server, pos, EAP_GPSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server",
+ data->rand_server, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short GPSK-1 packet");
+ return NULL;
+ }
+ csuite_list_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < (int) csuite_list_len) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List overflow");
+ return NULL;
+ }
+ csuite_list = pos;
+
+ if (csuite_list_len == 0 ||
+ csuite_list_len % sizeof(struct eap_gpsk_csuite)) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid CSuite_List len %d",
+ csuite_list_len);
+ return NULL;
+ }
+ count = csuite_list_len / sizeof(struct eap_gpsk_csuite);
+ data->vendor = EAP_GPSK_VENDOR_IETF;
+ data->specifier = EAP_GPSK_CIPHER_RESERVED;
+ csuite = (struct eap_gpsk_csuite *) csuite_list;
+ for (i = 0; i < count; i++) {
+ int vendor, specifier;
+ vendor = WPA_GET_BE24(csuite->vendor);
+ specifier = WPA_GET_BE24(csuite->specifier);
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite[%d]: %d:%d",
+ i, vendor, specifier);
+ if (data->vendor == EAP_GPSK_VENDOR_IETF &&
+ data->specifier == EAP_GPSK_CIPHER_RESERVED &&
+ eap_gpsk_supported_ciphersuite(vendor, specifier)) {
+ data->vendor = vendor;
+ data->specifier = specifier;
+ }
+ csuite++;
+ }
+ if (data->vendor == EAP_GPSK_VENDOR_IETF &&
+ data->specifier == EAP_GPSK_CIPHER_RESERVED) {
+ wpa_msg(sm->msg_ctx, MSG_INFO, "EAP-GPSK: No supported "
+ "ciphersuite found");
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Selected ciphersuite %d:%d",
+ data->vendor, data->specifier);
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-2");
+
+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+ len = 1 + 2 + data->id_client_len + 2 + data->id_server_len +
+ 2 * EAP_GPSK_RAND_LEN + 2 + csuite_list_len +
+ sizeof(struct eap_gpsk_csuite) + 2 + miclen;
+
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respDataLen, len,
+ EAP_CODE_RESPONSE, req->identifier, &rpos);
+ if (resp == NULL)
+ return NULL;
+
+ *rpos++ = EAP_GPSK_OPCODE_GPSK_2;
+ start = rpos;
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Client",
+ data->id_client, data->id_client_len);
+ WPA_PUT_BE16(rpos, data->id_client_len);
+ rpos += 2;
+ if (data->id_client)
+ os_memcpy(rpos, data->id_client, data->id_client_len);
+ rpos += data->id_client_len;
+
+ WPA_PUT_BE16(rpos, data->id_server_len);
+ rpos += 2;
+ if (data->id_server)
+ os_memcpy(rpos, data->id_server, data->id_server_len);
+ rpos += data->id_server_len;
+
+ if (os_get_random(data->rand_client, EAP_GPSK_RAND_LEN)) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to get random data "
+ "for RAND_Client");
+ eap_gpsk_state(data, FAILURE);
+ os_free(resp);
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client",
+ data->rand_client, EAP_GPSK_RAND_LEN);
+ os_memcpy(rpos, data->rand_client, EAP_GPSK_RAND_LEN);
+ rpos += EAP_GPSK_RAND_LEN;
+
+ os_memcpy(rpos, data->rand_server, EAP_GPSK_RAND_LEN);
+ rpos += EAP_GPSK_RAND_LEN;
+
+ WPA_PUT_BE16(rpos, csuite_list_len);
+ rpos += 2;
+ os_memcpy(rpos, csuite_list, csuite_list_len);
+ rpos += csuite_list_len;
+
+ csuite = (struct eap_gpsk_csuite *) rpos;
+ WPA_PUT_BE24(csuite->vendor, data->vendor);
+ WPA_PUT_BE24(csuite->specifier, data->specifier);
+ rpos = (u8 *) (csuite + 1);
+
+ if (eap_gpsk_derive_keys(data->psk, data->psk_len,
+ data->vendor, data->specifier,
+ data->rand_client, data->rand_server,
+ data->id_client, data->id_client_len,
+ data->id_server, data->id_server_len,
+ data->msk, data->emsk,
+ data->sk, &data->sk_len,
+ data->pk, &data->pk_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
+ eap_gpsk_state(data, FAILURE);
+ os_free(resp);
+ return NULL;
+ }
+
+ /* No PD_Payload_1 */
+ WPA_PUT_BE16(rpos, 0);
+ rpos += 2;
+
+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+ data->specifier, start, rpos - start, rpos) <
+ 0) {
+ eap_gpsk_state(data, FAILURE);
+ os_free(resp);
+ return NULL;
+ }
+
+ eap_gpsk_state(data, GPSK_3);
+
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_gpsk_process_gpsk_3(struct eap_sm *sm,
+ struct eap_gpsk_data *data,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ const u8 *payload, size_t payload_len,
+ size_t *respDataLen)
+{
+ size_t len, miclen;
+ struct eap_hdr *resp;
+ u8 *rpos, *start;
+ const struct eap_hdr *req;
+ const u8 *pos, *end;
+ u16 alen;
+ int vendor, specifier;
+ const struct eap_gpsk_csuite *csuite;
+ u8 mic[EAP_GPSK_MAX_MIC_LEN];
+
+ if (data->state != GPSK_3) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Request/GPSK-3");
+
+ req = (const struct eap_hdr *) reqData;
+ pos = payload;
+ end = payload + payload_len;
+
+ if (end - pos < EAP_GPSK_RAND_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+ "RAND_Client");
+ return NULL;
+ }
+ if (os_memcmp(pos, data->rand_client, EAP_GPSK_RAND_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-2 and "
+ "GPSK-3 did not match");
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-2",
+ data->rand_client, EAP_GPSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client in GPSK-3",
+ pos, EAP_GPSK_RAND_LEN);
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+ pos += EAP_GPSK_RAND_LEN;
+
+ if (end - pos < EAP_GPSK_RAND_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+ "RAND_Server");
+ return NULL;
+ }
+ if (os_memcmp(pos, data->rand_server, EAP_GPSK_RAND_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
+ "GPSK-3 did not match");
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
+ data->rand_server, EAP_GPSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-3",
+ pos, EAP_GPSK_RAND_LEN);
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+ pos += EAP_GPSK_RAND_LEN;
+
+ if (end - pos < (int) sizeof(*csuite)) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+ "CSuite_Sel");
+ return NULL;
+ }
+ csuite = (const struct eap_gpsk_csuite *) pos;
+ vendor = WPA_GET_BE24(csuite->vendor);
+ specifier = WPA_GET_BE24(csuite->specifier);
+ pos += sizeof(*csuite);
+ if (vendor != data->vendor || specifier != data->specifier) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel (%d:%d) does not "
+ "match with the one sent in GPSK-2 (%d:%d)",
+ vendor, specifier, data->vendor, data->specifier);
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+ "PD_Payload_2 length");
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+ alen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < alen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for "
+ "%d-octet PD_Payload_2", alen);
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_2", pos, alen);
+ pos += alen;
+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+ if (end - pos < (int) miclen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
+ "(left=%d miclen=%d)", end - pos, miclen);
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+ data->specifier, payload, pos - payload, mic)
+ < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+ if (os_memcmp(mic, pos, miclen) != 0) {
+ wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-3");
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+ pos += miclen;
+
+ if (pos != end) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
+ "data in the end of GPSK-2", end - pos);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Sending Response/GPSK-4");
+
+ len = 1 + 2 + miclen;
+
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, respDataLen, len,
+ EAP_CODE_RESPONSE, req->identifier, &rpos);
+ if (resp == NULL)
+ return NULL;
+
+ *rpos++ = EAP_GPSK_OPCODE_GPSK_4;
+ start = rpos;
+
+ /* No PD_Payload_3 */
+ WPA_PUT_BE16(rpos, 0);
+ rpos += 2;
+
+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+ data->specifier, start, rpos - start, rpos) <
+ 0) {
+ eap_gpsk_state(data, FAILURE);
+ os_free(resp);
+ return NULL;
+ }
+
+ eap_gpsk_state(data, SUCCESS);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_gpsk_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *resp;
+ const u8 *pos;
+ size_t len;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK,
+ reqData, reqDataLen, &len);
+ if (pos == NULL || len < 1) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode %d", *pos);
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = FALSE;
+
+ switch (*pos) {
+ case EAP_GPSK_OPCODE_GPSK_1:
+ resp = eap_gpsk_process_gpsk_1(sm, data, ret, reqData,
+ reqDataLen, pos + 1, len - 1,
+ respDataLen);
+ break;
+ case EAP_GPSK_OPCODE_GPSK_3:
+ resp = eap_gpsk_process_gpsk_3(sm, data, ret, reqData,
+ reqDataLen, pos + 1, len - 1,
+ respDataLen);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignoring message with "
+ "unknown opcode %d", *pos);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ return resp;
+}
+
+
+static Boolean eap_gpsk_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_gpsk_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_MSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->msk, EAP_MSK_LEN);
+ *len = EAP_MSK_LEN;
+
+ return key;
+}
+
+
+static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
+int eap_peer_gpsk_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_gpsk_init;
+ eap->deinit = eap_gpsk_deinit;
+ eap->process = eap_gpsk_process;
+ eap->isKeyAvailable = eap_gpsk_isKeyAvailable;
+ eap->getKey = eap_gpsk_getKey;
+ eap->get_emsk = eap_gpsk_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_gpsk_common.c b/contrib/wpa_supplicant/eap_gpsk_common.c
new file mode 100644
index 000000000000..a72b5f3da15f
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_gpsk_common.c
@@ -0,0 +1,441 @@
+/*
+ * EAP server/peer: EAP-GPSK shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_defs.h"
+#include "aes_wrap.h"
+#include "crypto.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "eap_gpsk_common.h"
+
+
+/**
+ * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * Returns: 1 if ciphersuite is support, or 0 if not
+ */
+int eap_gpsk_supported_ciphersuite(int vendor, int specifier)
+{
+ if (vendor == EAP_GPSK_VENDOR_IETF &&
+ specifier == EAP_GPSK_CIPHER_AES)
+ return 1;
+#ifdef EAP_GPSK_SHA256
+ if (vendor == EAP_GPSK_VENDOR_IETF &&
+ specifier == EAP_GPSK_CIPHER_SHA256)
+ return 1;
+#endif /* EAP_GPSK_SHA256 */
+ return 0;
+}
+
+
+static int eap_gpsk_gkdf(const u8 *psk /* Y */, size_t psk_len,
+ const u8 *data /* Z */, size_t data_len,
+ u8 *buf, size_t len /* X */)
+{
+ u8 *opos;
+ size_t i, n, hashlen, left, clen;
+ u8 ibuf[2], hash[SHA1_MAC_LEN];
+ const u8 *addr[3];
+ size_t vlen[3];
+
+ hashlen = SHA1_MAC_LEN;
+ /* M_i = Hash-Function (i || Y || Z); */
+ addr[0] = ibuf;
+ vlen[0] = sizeof(ibuf);
+ addr[1] = psk;
+ vlen[1] = psk_len;
+ addr[2] = data;
+ vlen[2] = data_len;
+
+ opos = buf;
+ left = len;
+ n = (len + hashlen - 1) / hashlen;
+ for (i = 1; i <= n; i++) {
+ WPA_PUT_BE16(ibuf, i);
+ sha1_vector(3, addr, vlen, hash);
+ clen = left > hashlen ? hashlen : left;
+ os_memcpy(opos, hash, clen);
+ opos += clen;
+ left -= clen;
+ }
+
+ return 0;
+}
+
+
+static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len,
+ const u8 *seed, size_t seed_len,
+ u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+ u8 *pk, size_t *pk_len)
+{
+#define EAP_GPSK_SK_LEN_AES 16
+#define EAP_GPSK_PK_LEN_AES 16
+ u8 zero_string[1], mk[32], *pos, *data;
+ u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES +
+ EAP_GPSK_PK_LEN_AES];
+ size_t data_len;
+
+ /*
+ * inputString = RAND_Client || ID_Client || RAND_Server || ID_Server
+ * (= seed)
+ * KS = 16, PL = psk_len, CSuite_Sel = 0x000000 0x000001
+ * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
+ * MSK = GKDF-160 (MK, inputString)[0..63]
+ * EMSK = GKDF-160 (MK, inputString)[64..127]
+ * SK = GKDF-160 (MK, inputString)[128..143]
+ * PK = GKDF-160 (MK, inputString)[144..159]
+ * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
+ * inputString)
+ * Hash-Function = SHA-1 (see [RFC3174])
+ * hashlen = 20 octets (160 bits)
+ */
+
+ os_memset(zero_string, 0, sizeof(zero_string));
+
+ data_len = 2 + psk_len + 6 + seed_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ WPA_PUT_BE16(pos, psk_len);
+ pos += 2;
+ os_memcpy(pos, psk, psk_len);
+ pos += psk_len;
+ WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
+ pos += 3;
+ WPA_PUT_BE24(pos, EAP_GPSK_CIPHER_AES); /* CSuite/Specifier */
+ pos += 3;
+ os_memcpy(pos, seed, seed_len); /* inputString */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation (AES)",
+ data, data_len);
+
+ if (eap_gpsk_gkdf(zero_string, sizeof(zero_string), data, data_len,
+ mk, sizeof(mk)) < 0) {
+ os_free(data);
+ return -1;
+ }
+ os_free(data);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
+
+ if (eap_gpsk_gkdf(mk, sizeof(mk), seed, seed_len,
+ kdf_out, sizeof(kdf_out)) < 0)
+ return -1;
+
+ pos = kdf_out;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
+ os_memcpy(msk, pos, EAP_MSK_LEN);
+ pos += EAP_MSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
+ os_memcpy(emsk, pos, EAP_EMSK_LEN);
+ pos += EAP_EMSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, EAP_GPSK_SK_LEN_AES);
+ os_memcpy(sk, pos, EAP_GPSK_SK_LEN_AES);
+ *sk_len = EAP_GPSK_SK_LEN_AES;
+ pos += EAP_GPSK_SK_LEN_AES;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, EAP_GPSK_PK_LEN_AES);
+ os_memcpy(pk, pos, EAP_GPSK_PK_LEN_AES);
+ *pk_len = EAP_GPSK_PK_LEN_AES;
+
+ return 0;
+}
+
+
+#ifdef EAP_GPSK_SHA256
+static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */, size_t psk_len,
+ const u8 *data /* Z */, size_t data_len,
+ u8 *buf, size_t len /* X */)
+{
+ u8 *opos;
+ size_t i, n, hashlen, left, clen;
+ u8 ibuf[2], hash[SHA256_MAC_LEN];
+ const u8 *addr[3];
+ size_t vlen[3];
+
+ hashlen = SHA256_MAC_LEN;
+ /* M_i = Hash-Function (i || Y || Z); */
+ addr[0] = ibuf;
+ vlen[0] = sizeof(ibuf);
+ addr[1] = psk;
+ vlen[1] = psk_len;
+ addr[2] = data;
+ vlen[2] = data_len;
+
+ opos = buf;
+ left = len;
+ n = (len + hashlen - 1) / hashlen;
+ for (i = 1; i <= n; i++) {
+ WPA_PUT_BE16(ibuf, i);
+ sha256_vector(3, addr, vlen, hash);
+ clen = left > hashlen ? hashlen : left;
+ os_memcpy(opos, hash, clen);
+ opos += clen;
+ left -= clen;
+ }
+
+ return 0;
+}
+
+
+static int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len,
+ const u8 *seed, size_t seed_len,
+ u8 *msk, u8 *emsk,
+ u8 *sk, size_t *sk_len,
+ u8 *pk, size_t *pk_len)
+{
+#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN
+#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN
+ u8 mk[SHA256_MAC_LEN], zero_string[1], *pos, *data;
+ u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 +
+ EAP_GPSK_PK_LEN_SHA256];
+ size_t data_len;
+
+ /*
+ * inputString = RAND_Client || ID_Client || RAND_Server || ID_Server
+ * (= seed)
+ * KS = 32, PL = psk_len, CSuite_Sel = 0x000000 0x000002
+ * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
+ * MSK = GKDF-192 (MK, inputString)[0..63]
+ * EMSK = GKDF-192 (MK, inputString)[64..127]
+ * SK = GKDF-192 (MK, inputString)[128..159]
+ * PK = GKDF-192 (MK, inputString)[160..191]
+ * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
+ * inputString)
+ * Hash-Function = SHA256 (see [RFC4634])
+ * hashlen = 32 octets (256 bits)
+ */
+
+ os_memset(zero_string, 0, sizeof(zero_string));
+
+ data_len = 2 + psk_len + 6 + seed_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ WPA_PUT_BE16(pos, psk_len);
+ pos += 2;
+ os_memcpy(pos, psk, psk_len);
+ pos += psk_len;
+ WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
+ pos += 3;
+ WPA_PUT_BE24(pos, EAP_GPSK_CIPHER_SHA256); /* CSuite/Specifier */
+ pos += 3;
+ os_memcpy(pos, seed, seed_len); /* inputString */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation (SHA256)",
+ data, data_len);
+
+ if (eap_gpsk_gkdf_sha256(zero_string, sizeof(zero_string),
+ data, data_len, mk, sizeof(mk)) < 0) {
+ os_free(data);
+ return -1;
+ }
+ os_free(data);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
+
+ if (eap_gpsk_gkdf_sha256(mk, sizeof(mk), seed, seed_len,
+ kdf_out, sizeof(kdf_out)) < 0)
+ return -1;
+
+ pos = kdf_out;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
+ os_memcpy(msk, pos, EAP_MSK_LEN);
+ pos += EAP_MSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
+ os_memcpy(emsk, pos, EAP_EMSK_LEN);
+ pos += EAP_EMSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK",
+ pos, EAP_GPSK_SK_LEN_SHA256);
+ os_memcpy(sk, pos, EAP_GPSK_SK_LEN_SHA256);
+ *sk_len = EAP_GPSK_SK_LEN_AES;
+ pos += EAP_GPSK_SK_LEN_AES;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK",
+ pos, EAP_GPSK_PK_LEN_SHA256);
+ os_memcpy(pk, pos, EAP_GPSK_PK_LEN_SHA256);
+ *pk_len = EAP_GPSK_PK_LEN_SHA256;
+
+ return 0;
+}
+#endif /* EAP_GPSK_SHA256 */
+
+
+/**
+ * eap_gpsk_derive_keys - Derive EAP-GPSK keys
+ * @psk: Pre-shared key (at least 16 bytes if AES is used)
+ * @psk_len: Length of psk in bytes
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @rand_client: 32-byte RAND_Client
+ * @rand_server: 32-byte RAND_Server
+ * @id_client: ID_Client
+ * @id_client_len: Length of ID_Client
+ * @id_server: ID_Server
+ * @id_server_len: Length of ID_Server
+ * @msk: Buffer for 64-byte MSK
+ * @emsk: Buffer for 64-byte EMSK
+ * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes)
+ * @sk_len: Buffer for returning length of SK
+ * @pk: Buffer for SK (at least EAP_GPSK_MAX_PK_LEN bytes)
+ * @pk_len: Buffer for returning length of PK
+ * Returns: 0 on success, -1 on failure
+ */
+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)
+{
+ u8 *seed, *pos;
+ size_t seed_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)",
+ vendor, specifier);
+
+ if (vendor != EAP_GPSK_VENDOR_IETF)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
+
+ /* Seed = RAND_Client || ID_Client || RAND_Server || ID_Server */
+ seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_client_len;
+ seed = os_malloc(seed_len);
+ if (seed == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
+ "for key derivation");
+ return -1;
+ }
+
+ pos = seed;
+ os_memcpy(pos, rand_client, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_client, id_client_len);
+ pos += id_client_len;
+ os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_server, id_server_len);
+ pos += id_server_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+
+ switch (specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len,
+ msk, emsk, sk, sk_len,
+ pk, pk_len);
+ break;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len,
+ msk, emsk, sk, sk_len,
+ pk, pk_len);
+ break;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
+ "key derivation", vendor, specifier);
+ ret = -1;
+ break;
+ }
+
+ os_free(seed);
+
+ return ret;
+}
+
+
+/**
+ * eap_gpsk_mic_len - Get the length of the MIC
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * Returns: MIC length in bytes
+ */
+size_t eap_gpsk_mic_len(int vendor, int specifier)
+{
+ if (vendor != EAP_GPSK_VENDOR_IETF)
+ return 0;
+
+ switch (specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ return 16;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ return 32;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ return 0;
+ }
+}
+
+
+static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len,
+ const u8 *data, size_t len, u8 *mic)
+{
+ if (sk_len != 16) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %d for "
+ "AES-CMAC MIC", sk_len);
+ return -1;
+ }
+
+ return omac1_aes_128(sk, data, len, mic);
+}
+
+
+/**
+ * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet
+ * @sk: Session key SK from eap_gpsk_derive_keys()
+ * @sk_len: SK length in bytes from eap_gpsk_derive_keys()
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @data: Input data to MIC
+ * @len: Input data length in bytes
+ * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
+ int specifier, const u8 *data, size_t len, u8 *mic)
+{
+ int ret;
+
+ if (vendor != EAP_GPSK_VENDOR_IETF)
+ return -1;
+
+ switch (specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic);
+ break;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ hmac_sha256(sk, sk_len, data, len, mic);
+ ret = 0;
+ break;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
+ "MIC computation", vendor, specifier);
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_gpsk_common.h b/contrib/wpa_supplicant/eap_gpsk_common.h
new file mode 100644
index 000000000000..c806b7f85217
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_gpsk_common.h
@@ -0,0 +1,66 @@
+/*
+ * EAP server/peer: EAP-GPSK shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EAP_GPSK_COMMON_H
+#define EAP_GPSK_COMMON_H
+
+#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 0x000000
+#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[3];
+ u8 specifier[3];
+} 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);
+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);
+
+#endif /* EAP_GPSK_COMMON_H */
diff --git a/contrib/wpa_supplicant/eap_gtc.c b/contrib/wpa_supplicant/eap_gtc.c
index 3665746e6fd1..ed4f8f32f629 100644
--- a/contrib/wpa_supplicant/eap_gtc.c
+++ b/contrib/wpa_supplicant/eap_gtc.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-GTC (RFC 2284)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-GTC (RFC 3748)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,14 +12,10 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
-#include "config_ssid.h"
struct eap_gtc_data {
@@ -30,10 +26,9 @@ struct eap_gtc_data {
static void * eap_gtc_init(struct eap_sm *sm)
{
struct eap_gtc_data *data;
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
if (sm->m && sm->m->method == EAP_TYPE_FAST) {
wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
@@ -47,7 +42,7 @@ static void * eap_gtc_init(struct eap_sm *sm)
static void eap_gtc_deinit(struct eap_sm *sm, void *priv)
{
struct eap_gtc_data *data = priv;
- free(data);
+ os_free(data);
}
@@ -57,14 +52,15 @@ static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
size_t *respDataLen)
{
struct eap_gtc_data *data = priv;
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *req;
struct eap_hdr *resp;
- const u8 *pos, *password;
+ const u8 *pos, *password, *identity;
u8 *rpos;
- size_t password_len, len;
+ size_t password_len, identity_len, len, plen;
+ int otp;
- pos = eap_hdr_validate(EAP_TYPE_GTC, reqData, reqDataLen, &len);
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+ reqData, reqDataLen, &len);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
@@ -73,7 +69,7 @@ static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len);
if (data->prefix &&
- (len < 10 || memcmp(pos, "CHALLENGE=", 10) != 0)) {
+ (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) {
wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with "
"expected prefix");
@@ -81,81 +77,79 @@ static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
* acknowledgement of the failure. This will also cover the
* error case which seems to use EAP-MSCHAPv2 like error
* reporting with EAP-GTC inside EAP-FAST tunnel. */
- *respDataLen = sizeof(struct eap_hdr) + 1;
- resp = malloc(*respDataLen);
- if (resp == NULL)
- return NULL;
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(*respDataLen);
- rpos = (u8 *) (resp + 1);
- *rpos++ = EAP_TYPE_GTC;
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+ respDataLen, 0, EAP_CODE_RESPONSE,
+ req->identifier, NULL);
return (u8 *) resp;
}
- if (config == NULL ||
- (config->password == NULL && config->otp == NULL)) {
+ password = eap_get_config_otp(sm, &password_len);
+ if (password)
+ otp = 1;
+ else {
+ password = eap_get_config_password(sm, &password_len);
+ otp = 0;
+ }
+
+ if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
- eap_sm_request_otp(sm, config, (const char *) pos, len);
+ eap_sm_request_otp(sm, (const char *) pos, len);
ret->ignore = TRUE;
return NULL;
}
- if (config->otp) {
- password = config->otp;
- password_len = config->otp_len;
- } else {
- password = config->password;
- password_len = config->password_len;
- }
-
ret->ignore = FALSE;
ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE;
ret->decision = DECISION_COND_SUCC;
ret->allowNotifications = FALSE;
- *respDataLen = sizeof(struct eap_hdr) + 1 + password_len;
- if (data->prefix) {
- *respDataLen += 9 + config->identity_len + 1;
- }
- resp = malloc(*respDataLen);
+ plen = password_len;
+ identity = eap_get_config_identity(sm, &identity_len);
+ if (identity == NULL)
+ return NULL;
+ if (data->prefix)
+ plen += 9 + identity_len + 1;
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, respDataLen,
+ plen, EAP_CODE_RESPONSE, req->identifier, &rpos);
if (resp == NULL)
return NULL;
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(*respDataLen);
- rpos = (u8 *) (resp + 1);
- *rpos++ = EAP_TYPE_GTC;
if (data->prefix) {
- memcpy(rpos, "RESPONSE=", 9);
+ os_memcpy(rpos, "RESPONSE=", 9);
rpos += 9;
- memcpy(rpos, config->identity, config->identity_len);
- rpos += config->identity_len;
+ os_memcpy(rpos, identity, identity_len);
+ rpos += identity_len;
*rpos++ = '\0';
}
- memcpy(rpos, password, password_len);
+ os_memcpy(rpos, password, password_len);
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response",
- (u8 *) (resp + 1) + 1,
- *respDataLen - sizeof(struct eap_hdr) - 1);
+ (u8 *) (resp + 1) + 1, plen);
- if (config->otp) {
+ if (otp) {
wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password");
- memset(config->otp, 0, config->otp_len);
- free(config->otp);
- config->otp = NULL;
- config->otp_len = 0;
+ eap_clear_config_otp(sm);
}
return (u8 *) resp;
}
-const struct eap_method eap_method_gtc =
+int eap_peer_gtc_register(void)
{
- .method = EAP_TYPE_GTC,
- .name = "GTC",
- .init = eap_gtc_init,
- .deinit = eap_gtc_deinit,
- .process = eap_gtc_process,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_gtc_init;
+ eap->deinit = eap_gtc_deinit;
+ eap->process = eap_gtc_process;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_i.h b/contrib/wpa_supplicant/eap_i.h
index d1345489339e..ad7a1dd496d9 100644
--- a/contrib/wpa_supplicant/eap_i.h
+++ b/contrib/wpa_supplicant/eap_i.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP state machines internal structures (RFC 4137)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer state machines internal structures (RFC 4137)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -66,6 +66,11 @@ struct eap_method_ret {
*/
struct eap_method {
/**
+ * vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
+ */
+ int vendor;
+
+ /**
* method - EAP type number (EAP_TYPE_*)
*/
EapType method;
@@ -205,6 +210,64 @@ struct eap_method {
* 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_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);
};
@@ -231,6 +294,8 @@ struct eap_sm {
Boolean rxFailure;
int reqId;
EapType reqMethod;
+ int reqVendor;
+ u32 reqVendorMethod;
Boolean ignore;
/* Constants */
int ClientTimeout;
@@ -266,15 +331,26 @@ struct eap_sm {
/* Optional challenges generated in Phase 1 (EAP-FAST) */
u8 *peer_challenge, *auth_challenge;
+ int mschapv2_full_key; /* Request full MSCHAPv2 key */
int num_rounds;
int force_disabled;
};
-const u8 * eap_hdr_validate(EapType eap_type, const u8 *msg, size_t msglen,
- size_t *plen);
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+ const u8 *msg, size_t msglen, size_t *plen);
+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_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);
+struct wpa_ssid * 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);
+struct eap_hdr * eap_msg_alloc(int vendor, EapType type, size_t *len,
+ size_t payload_len, u8 code, u8 identifier,
+ u8 **payload);
+void eap_notify_pending(struct eap_sm *sm);
#endif /* EAP_I_H */
diff --git a/contrib/wpa_supplicant/eap_leap.c b/contrib/wpa_supplicant/eap_leap.c
index d0e5aab1d70f..aa6e05707d41 100644
--- a/contrib/wpa_supplicant/eap_leap.c
+++ b/contrib/wpa_supplicant/eap_leap.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-LEAP
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: LEAP
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,14 +12,10 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
-#include "config_ssid.h"
#include "ms_funcs.h"
#include "crypto.h"
@@ -49,10 +45,9 @@ static void * eap_leap_init(struct eap_sm *sm)
{
struct eap_leap_data *data;
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
data->state = LEAP_WAIT_CHALLENGE;
sm->leap_done = FALSE;
@@ -62,7 +57,7 @@ static void * eap_leap_init(struct eap_sm *sm)
static void eap_leap_deinit(struct eap_sm *sm, void *priv)
{
- free(priv);
+ os_free(priv);
}
@@ -72,14 +67,19 @@ static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
size_t *respDataLen)
{
struct eap_leap_data *data = priv;
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *req;
struct eap_hdr *resp;
- const u8 *pos, *challenge;
+ const u8 *pos, *challenge, *identity, *password;
u8 challenge_len, *rpos;
+ size_t identity_len, password_len;
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
+ identity = eap_get_config_identity(sm, &identity_len);
+ password = eap_get_config_password(sm, &password_len);
+ if (identity == NULL || password == NULL)
+ return NULL;
+
req = (const struct eap_hdr *) reqData;
pos = (const u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_LEAP) {
@@ -103,38 +103,32 @@ static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
if (challenge_len != LEAP_CHALLENGE_LEN ||
challenge_len > reqDataLen - sizeof(*req) - 4) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid challenge "
- "(challenge_len=%d reqDataLen=%lu",
+ "(challenge_len=%d reqDataLen=%lu)",
challenge_len, (unsigned long) reqDataLen);
ret->ignore = TRUE;
return NULL;
}
challenge = pos;
- memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
+ os_memcpy(data->peer_challenge, challenge, LEAP_CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge from AP",
challenge, LEAP_CHALLENGE_LEN);
wpa_printf(MSG_DEBUG, "EAP-LEAP: Generating Challenge Response");
- *respDataLen = sizeof(struct eap_hdr) + 1 + 3 + LEAP_RESPONSE_LEN +
- config->identity_len;
- resp = malloc(*respDataLen);
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, respDataLen,
+ 3 + LEAP_RESPONSE_LEN + identity_len,
+ EAP_CODE_RESPONSE, req->identifier, &rpos);
if (resp == NULL)
return NULL;
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(*respDataLen);
- rpos = (u8 *) (resp + 1);
- *rpos++ = EAP_TYPE_LEAP;
*rpos++ = LEAP_VERSION;
*rpos++ = 0; /* unused */
*rpos++ = LEAP_RESPONSE_LEN;
- nt_challenge_response(challenge,
- config->password, config->password_len, rpos);
- memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
+ nt_challenge_response(challenge, password, password_len, rpos);
+ os_memcpy(data->peer_response, rpos, LEAP_RESPONSE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response",
rpos, LEAP_RESPONSE_LEN);
rpos += LEAP_RESPONSE_LEN;
- memcpy(rpos, config->identity, config->identity_len);
+ os_memcpy(rpos, identity, identity_len);
data->state = LEAP_WAIT_SUCCESS;
@@ -144,17 +138,21 @@ static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- const u8 *reqData, size_t reqDataLen,
- size_t *respDataLen)
+ const u8 *reqData, size_t *respDataLen)
{
struct eap_leap_data *data = priv;
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *req;
struct eap_hdr *resp;
u8 *pos;
+ const u8 *identity;
+ size_t identity_len;
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
+ identity = eap_get_config_identity(sm, &identity_len);
+ if (identity == NULL)
+ return NULL;
+
if (data->state != LEAP_WAIT_SUCCESS) {
wpa_printf(MSG_INFO, "EAP-LEAP: EAP-Success received in "
"unexpected state (%d) - ignored", data->state);
@@ -164,31 +162,26 @@ static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
req = (const struct eap_hdr *) reqData;
- *respDataLen = sizeof(struct eap_hdr) + 1 + 3 + LEAP_CHALLENGE_LEN +
- config->identity_len;
- resp = malloc(*respDataLen);
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_LEAP, respDataLen,
+ 3 + LEAP_CHALLENGE_LEN + identity_len,
+ EAP_CODE_REQUEST, req->identifier, &pos);
if (resp == NULL)
return NULL;
- resp->code = EAP_CODE_REQUEST;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(*respDataLen);
- pos = (u8 *) (resp + 1);
- *pos++ = EAP_TYPE_LEAP;
*pos++ = LEAP_VERSION;
*pos++ = 0; /* unused */
*pos++ = LEAP_CHALLENGE_LEN;
if (hostapd_get_rand(pos, LEAP_CHALLENGE_LEN)) {
wpa_printf(MSG_WARNING, "EAP-LEAP: Failed to read random data "
"for challenge");
- free(resp);
+ os_free(resp);
ret->ignore = TRUE;
return NULL;
}
- memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
+ os_memcpy(data->ap_challenge, pos, LEAP_CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Challenge to AP/AS", pos,
LEAP_CHALLENGE_LEN);
pos += LEAP_CHALLENGE_LEN;
- memcpy(pos, config->identity, config->identity_len);
+ os_memcpy(pos, identity, identity_len);
data->state = LEAP_WAIT_RESPONSE;
@@ -198,18 +191,21 @@ static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
static u8 * eap_leap_process_response(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- const u8 *reqData, size_t reqDataLen,
- size_t *respDataLen)
+ const u8 *reqData, size_t reqDataLen)
{
struct eap_leap_data *data = priv;
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *resp;
- const u8 *pos;
+ const u8 *pos, *password;
u8 response_len, pw_hash[16], pw_hash_hash[16],
expected[LEAP_RESPONSE_LEN];
+ size_t password_len;
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
+ password = eap_get_config_password(sm, &password_len);
+ if (password == NULL)
+ return NULL;
+
resp = (const struct eap_hdr *) reqData;
pos = (const u8 *) (resp + 1);
if (reqDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_LEAP) {
@@ -233,7 +229,7 @@ static u8 * eap_leap_process_response(struct eap_sm *sm, void *priv,
if (response_len != LEAP_RESPONSE_LEN ||
response_len > reqDataLen - sizeof(*resp) - 4) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid response "
- "(response_len=%d reqDataLen=%lu",
+ "(response_len=%d reqDataLen=%lu)",
response_len, (unsigned long) reqDataLen);
ret->ignore = TRUE;
return NULL;
@@ -241,16 +237,16 @@ static u8 * eap_leap_process_response(struct eap_sm *sm, void *priv,
wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Response from AP",
pos, LEAP_RESPONSE_LEN);
- memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
+ os_memcpy(data->ap_response, pos, LEAP_RESPONSE_LEN);
- nt_password_hash(config->password, config->password_len, pw_hash);
+ nt_password_hash(password, password_len, pw_hash);
hash_nt_password_hash(pw_hash, pw_hash_hash);
challenge_response(data->ap_challenge, pw_hash_hash, expected);
ret->methodState = METHOD_DONE;
ret->allowNotifications = FALSE;
- if (memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
+ if (os_memcmp(pos, expected, LEAP_RESPONSE_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-LEAP: AP sent an invalid "
"response - authentication failed");
wpa_hexdump(MSG_DEBUG, "EAP-LEAP: Expected response from AP",
@@ -278,13 +274,14 @@ static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *eap;
- size_t len;
+ size_t len, password_len;
+ const u8 *password;
- if (config == NULL || config->password == NULL) {
+ password = eap_get_config_password(sm, &password_len);
+ if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-LEAP: Password not configured");
- eap_sm_request_password(sm, config);
+ eap_sm_request_password(sm);
ret->ignore = TRUE;
return NULL;
}
@@ -310,11 +307,10 @@ static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
return eap_leap_process_request(sm, priv, ret, reqData, len,
respDataLen);
case EAP_CODE_SUCCESS:
- return eap_leap_process_success(sm, priv, ret, reqData, len,
+ return eap_leap_process_success(sm, priv, ret, reqData,
respDataLen);
case EAP_CODE_RESPONSE:
- return eap_leap_process_response(sm, priv, ret, reqData, len,
- respDataLen);
+ return eap_leap_process_response(sm, priv, ret, reqData, len);
default:
wpa_printf(MSG_INFO, "EAP-LEAP: Unexpected EAP code (%d) - "
"ignored", eap->code);
@@ -334,19 +330,22 @@ static Boolean eap_leap_isKeyAvailable(struct eap_sm *sm, void *priv)
static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
{
struct eap_leap_data *data = priv;
- struct wpa_ssid *config = eap_get_config(sm);
u8 *key, pw_hash_hash[16], pw_hash[16];
- const u8 *addr[5];
- size_t elen[5];
+ const u8 *addr[5], *password;
+ size_t elen[5], password_len;
if (data->state != LEAP_DONE)
return NULL;
- key = malloc(LEAP_KEY_LEN);
+ password = eap_get_config_password(sm, &password_len);
+ if (password == NULL)
+ return NULL;
+
+ key = os_malloc(LEAP_KEY_LEN);
if (key == NULL)
return NULL;
- nt_password_hash(config->password, config->password_len, pw_hash);
+ nt_password_hash(password, password_len, pw_hash);
hash_nt_password_hash(pw_hash, pw_hash_hash);
wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: pw_hash_hash",
pw_hash_hash, 16);
@@ -377,13 +376,24 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
-const struct eap_method eap_method_leap =
+int eap_peer_leap_register(void)
{
- .method = EAP_TYPE_LEAP,
- .name = "LEAP",
- .init = eap_leap_init,
- .deinit = eap_leap_deinit,
- .process = eap_leap_process,
- .isKeyAvailable = eap_leap_isKeyAvailable,
- .getKey = eap_leap_getKey,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_LEAP, "LEAP");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_leap_init;
+ eap->deinit = eap_leap_deinit;
+ eap->process = eap_leap_process;
+ eap->isKeyAvailable = eap_leap_isKeyAvailable;
+ eap->getKey = eap_leap_getKey;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_md5.c b/contrib/wpa_supplicant/eap_md5.c
index 46a5f55fe17e..5dc16854c938 100644
--- a/contrib/wpa_supplicant/eap_md5.c
+++ b/contrib/wpa_supplicant/eap_md5.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-MD5
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,19 +12,18 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
-#include "config_ssid.h"
#include "md5.h"
#include "crypto.h"
static void * eap_md5_init(struct eap_sm *sm)
{
+ /* No need for private data. However, must return non-NULL to indicate
+ * success. */
return (void *) 1;
}
@@ -39,35 +38,41 @@ static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *req;
struct eap_hdr *resp;
- const u8 *pos, *challenge;
+ const u8 *pos, *challenge, *password;
u8 *rpos;
- int challenge_len;
- size_t len;
+ size_t len, challenge_len, password_len;
const u8 *addr[3];
size_t elen[3];
- if (config == NULL || config->password == NULL) {
+ password = eap_get_config_password(sm, &password_len);
+ if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
- eap_sm_request_password(sm, config);
+ eap_sm_request_password(sm);
ret->ignore = TRUE;
return NULL;
}
- pos = eap_hdr_validate(EAP_TYPE_MD5, reqData, reqDataLen, &len);
- if (pos == NULL) {
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5,
+ reqData, reqDataLen, &len);
+ if (pos == NULL || len == 0) {
+ wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)",
+ pos, (unsigned long) len);
ret->ignore = TRUE;
return NULL;
}
+
+ /*
+ * CHAP Challenge:
+ * Value-Size (1 octet) | Value(Challenge) | Name(optional)
+ */
req = (const struct eap_hdr *) reqData;
challenge_len = *pos++;
- if (challenge_len == 0 ||
- challenge_len > len - 1) {
+ if (challenge_len == 0 || challenge_len > len - 1) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
- "(challenge_len=%d len=%lu",
- challenge_len, (unsigned long) len);
+ "(challenge_len=%lu len=%lu)",
+ (unsigned long) challenge_len, (unsigned long) len);
ret->ignore = TRUE;
return NULL;
}
@@ -76,26 +81,27 @@ static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
challenge, challenge_len);
- wpa_printf(MSG_DEBUG, "EAP-MD5: generating Challenge Response");
+ wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response");
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
ret->allowNotifications = TRUE;
- *respDataLen = sizeof(struct eap_hdr) + 1 + 1 + MD5_MAC_LEN;
- resp = malloc(*respDataLen);
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, respDataLen,
+ 1 + MD5_MAC_LEN, EAP_CODE_RESPONSE,
+ req->identifier, &rpos);
if (resp == NULL)
return NULL;
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(*respDataLen);
- rpos = (u8 *) (resp + 1);
- *rpos++ = EAP_TYPE_MD5;
- *rpos++ = MD5_MAC_LEN; /* Value-Size */
+
+ /*
+ * CHAP Response:
+ * Value-Size (1 octet) | Value(Response) | Name(optional)
+ */
+ *rpos++ = MD5_MAC_LEN;
addr[0] = &resp->identifier;
elen[0] = 1;
- addr[1] = config->password;
- elen[1] = config->password_len;
+ addr[1] = password;
+ elen[1] = password_len;
addr[2] = challenge;
elen[2] = challenge_len;
md5_vector(3, addr, elen, rpos);
@@ -105,11 +111,22 @@ static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
}
-const struct eap_method eap_method_md5 =
+int eap_peer_md5_register(void)
{
- .method = EAP_TYPE_MD5,
- .name = "MD5",
- .init = eap_md5_init,
- .deinit = eap_md5_deinit,
- .process = eap_md5_process,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_md5_init;
+ eap->deinit = eap_md5_deinit;
+ eap->process = eap_md5_process;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_methods.c b/contrib/wpa_supplicant/eap_methods.c
new file mode 100644
index 000000000000..53c7e629d0b7
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_methods.c
@@ -0,0 +1,500 @@
+/*
+ * EAP peer: Method registration
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+#include <dlfcn.h>
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+#include "common.h"
+#include "eap_i.h"
+#include "eap_methods.h"
+
+
+static struct eap_method *eap_methods = NULL;
+
+
+/**
+ * eap_sm_get_eap_methods - Get EAP method based on type number
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @method: EAP type number
+ * Returns: Pointer to EAP method or %NULL if not found
+ */
+const struct eap_method * eap_sm_get_eap_methods(int vendor, EapType method)
+{
+ struct eap_method *m;
+ for (m = eap_methods; m; m = m->next) {
+ if (m->vendor == vendor && m->method == method)
+ return m;
+ }
+ return NULL;
+}
+
+
+/**
+ * eap_get_type - Get EAP type for the given EAP method name
+ * @name: EAP method name, e.g., TLS
+ * @vendor: Buffer for returning EAP Vendor-Id
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers based on the list of
+ * EAP methods included in the build.
+ */
+EapType eap_get_type(const char *name, int *vendor)
+{
+ struct eap_method *m;
+ for (m = eap_methods; m; m = m->next) {
+ if (os_strcmp(m->name, name) == 0) {
+ *vendor = m->vendor;
+ return m->method;
+ }
+ }
+ *vendor = EAP_VENDOR_IETF;
+ return EAP_TYPE_NONE;
+}
+
+
+/**
+ * eap_get_name - Get EAP method name for the given EAP type
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @type: EAP method type
+ * Returns: EAP method name, e.g., TLS, or %NULL if not found
+ *
+ * This function maps EAP type numbers into EAP type names based on the list of
+ * EAP methods included in the build.
+ */
+const char * eap_get_name(int vendor, EapType type)
+{
+ struct eap_method *m;
+ for (m = eap_methods; m; m = m->next) {
+ if (m->vendor == vendor && m->method == type)
+ return m->name;
+ }
+ return NULL;
+}
+
+
+/**
+ * eap_get_names - Get space separated list of names for supported EAP methods
+ * @buf: Buffer for names
+ * @buflen: Buffer length
+ * Returns: Number of characters written into buf (not including nul
+ * termination)
+ */
+size_t eap_get_names(char *buf, size_t buflen)
+{
+ char *pos, *end;
+ struct eap_method *m;
+ int ret;
+
+ if (buflen == 0)
+ return 0;
+
+ pos = buf;
+ end = pos + buflen;
+
+ for (m = eap_methods; m; m = m->next) {
+ ret = os_snprintf(pos, end - pos, "%s%s",
+ m == eap_methods ? "" : " ", m->name);
+ if (ret < 0 || ret >= end - pos)
+ break;
+ pos += ret;
+ }
+ buf[buflen - 1] = '\0';
+
+ return pos - buf;
+}
+
+
+/**
+ * eap_get_names_as_string_array - Get supported EAP methods as string array
+ * @num: Buffer for returning the number of items in array, not including %NULL
+ * terminator. This parameter can be %NULL if the length is not needed.
+ * Returns: A %NULL-terminated array of strings, or %NULL on error.
+ *
+ * This function returns the list of names for all supported EAP methods as an
+ * array of strings. The caller must free the returned array items and the
+ * array.
+ */
+char ** eap_get_names_as_string_array(size_t *num)
+{
+ struct eap_method *m;
+ size_t array_len = 0;
+ char **array;
+ int i = 0, j;
+
+ for (m = eap_methods; m; m = m->next)
+ array_len++;
+
+ array = os_zalloc(sizeof(char *) * (array_len + 1));
+ if (array == NULL)
+ return NULL;
+
+ for (m = eap_methods; m; m = m->next) {
+ array[i++] = os_strdup(m->name);
+ if (array[i - 1] == NULL) {
+ for (j = 0; j < i; j++)
+ os_free(array[j]);
+ os_free(array);
+ return NULL;
+ }
+ }
+ array[i] = NULL;
+
+ if (num)
+ *num = array_len;
+
+ return array;
+}
+
+
+/**
+ * eap_peer_get_methods - Get a list of enabled EAP peer methods
+ * @count: Set to number of available methods
+ * Returns: List of enabled EAP peer methods
+ */
+const struct eap_method * eap_peer_get_methods(size_t *count)
+{
+ int c = 0;
+ struct eap_method *m;
+
+ for (m = eap_methods; m; m = m->next)
+ c++;
+
+ *count = c;
+ return eap_methods;
+}
+
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+/**
+ * eap_peer_method_load - Load a dynamic EAP method library (shared object)
+ * @so: File path for the shared object file to load
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_peer_method_load(const char *so)
+{
+ void *handle;
+ int (*dyn_init)(void);
+ int ret;
+
+ handle = dlopen(so, RTLD_LAZY);
+ if (handle == NULL) {
+ wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method "
+ "'%s': %s", so, dlerror());
+ return -1;
+ }
+
+ dyn_init = dlsym(handle, "eap_peer_method_dynamic_init");
+ if (dyn_init == NULL) {
+ dlclose(handle);
+ wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no "
+ "eap_peer_method_dynamic_init()", so);
+ return -1;
+ }
+
+ ret = dyn_init();
+ if (ret) {
+ dlclose(handle);
+ wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - "
+ "ret %d", so, ret);
+ return ret;
+ }
+
+ /* Store the handle for this shared object. It will be freed with
+ * dlclose() when the EAP method is unregistered. */
+ eap_methods->dl_handle = handle;
+
+ wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so);
+
+ return 0;
+}
+
+
+/**
+ * eap_peer_method_unload - Unload a dynamic EAP method library (shared object)
+ * @method: Pointer to the dynamically loaded EAP method
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to unload EAP methods that have been previously
+ * loaded with eap_peer_method_load(). Before unloading the method, all
+ * references to the method must be removed to make sure that no dereferences
+ * of freed memory will occur after unloading.
+ */
+int eap_peer_method_unload(struct eap_method *method)
+{
+ struct eap_method *m, *prev;
+ void *handle;
+
+ m = eap_methods;
+ prev = NULL;
+ while (m) {
+ if (m == method)
+ break;
+ prev = m;
+ m = m->next;
+ }
+
+ if (m == NULL || m->dl_handle == NULL)
+ return -1;
+
+ if (prev)
+ prev->next = m->next;
+ else
+ eap_methods = m->next;
+
+ handle = m->dl_handle;
+
+ if (m->free)
+ m->free(m);
+ else
+ eap_peer_method_free(m);
+
+ dlclose(handle);
+
+ return 0;
+}
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+
+/**
+ * eap_peer_method_alloc - Allocate EAP peer method structure
+ * @version: Version of the EAP peer method interface (set to
+ * EAP_PEER_METHOD_INTERFACE_VERSION)
+ * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
+ * @method: EAP type number (EAP_TYPE_*)
+ * @name: Name of the method (e.g., "TLS")
+ * Returns: Allocated EAP method structure or %NULL on failure
+ *
+ * The returned structure should be freed with eap_peer_method_free() when it
+ * is not needed anymore.
+ */
+struct eap_method * eap_peer_method_alloc(int version, int vendor,
+ EapType method, const char *name)
+{
+ struct eap_method *eap;
+ eap = os_zalloc(sizeof(*eap));
+ if (eap == NULL)
+ return NULL;
+ eap->version = version;
+ eap->vendor = vendor;
+ eap->method = method;
+ eap->name = name;
+ return eap;
+}
+
+
+/**
+ * eap_peer_method_free - Free EAP peer method structure
+ * @method: Method structure allocated with eap_peer_method_alloc()
+ */
+void eap_peer_method_free(struct eap_method *method)
+{
+ os_free(method);
+}
+
+
+/**
+ * eap_peer_method_register - Register an EAP peer method
+ * @method: EAP method to register
+ * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
+ * has already been registered
+ *
+ * Each EAP peer method needs to call this function to register itself as a
+ * supported EAP method.
+ */
+int eap_peer_method_register(struct eap_method *method)
+{
+ struct eap_method *m, *last = NULL;
+
+ if (method == NULL || method->name == NULL ||
+ method->version != EAP_PEER_METHOD_INTERFACE_VERSION)
+ return -1;
+
+ for (m = eap_methods; m; m = m->next) {
+ if ((m->vendor == method->vendor &&
+ m->method == method->method) ||
+ os_strcmp(m->name, method->name) == 0)
+ return -2;
+ last = m;
+ }
+
+ if (last)
+ last->next = method;
+ else
+ eap_methods = method;
+
+ return 0;
+}
+
+
+/**
+ * eap_peer_register_methods - Register statically linked EAP peer methods
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called at program initialization to register all EAP peer
+ * methods that were linked in statically.
+ */
+int eap_peer_register_methods(void)
+{
+ int ret = 0;
+
+#ifdef EAP_MD5
+ if (ret == 0) {
+ int eap_peer_md5_register(void);
+ ret = eap_peer_md5_register();
+ }
+#endif /* EAP_MD5 */
+
+#ifdef EAP_TLS
+ if (ret == 0) {
+ int eap_peer_tls_register(void);
+ ret = eap_peer_tls_register();
+ }
+#endif /* EAP_TLS */
+
+#ifdef EAP_MSCHAPv2
+ if (ret == 0) {
+ int eap_peer_mschapv2_register(void);
+ ret = eap_peer_mschapv2_register();
+ }
+#endif /* EAP_MSCHAPv2 */
+
+#ifdef EAP_PEAP
+ if (ret == 0) {
+ int eap_peer_peap_register(void);
+ ret = eap_peer_peap_register();
+ }
+#endif /* EAP_PEAP */
+
+#ifdef EAP_TTLS
+ if (ret == 0) {
+ int eap_peer_ttls_register(void);
+ ret = eap_peer_ttls_register();
+ }
+#endif /* EAP_TTLS */
+
+#ifdef EAP_GTC
+ if (ret == 0) {
+ int eap_peer_gtc_register(void);
+ ret = eap_peer_gtc_register();
+ }
+#endif /* EAP_GTC */
+
+#ifdef EAP_OTP
+ if (ret == 0) {
+ int eap_peer_otp_register(void);
+ ret = eap_peer_otp_register();
+ }
+#endif /* EAP_OTP */
+
+#ifdef EAP_SIM
+ if (ret == 0) {
+ int eap_peer_sim_register(void);
+ ret = eap_peer_sim_register();
+ }
+#endif /* EAP_SIM */
+
+#ifdef EAP_LEAP
+ if (ret == 0) {
+ int eap_peer_leap_register(void);
+ ret = eap_peer_leap_register();
+ }
+#endif /* EAP_LEAP */
+
+#ifdef EAP_PSK
+ if (ret == 0) {
+ int eap_peer_psk_register(void);
+ ret = eap_peer_psk_register();
+ }
+#endif /* EAP_PSK */
+
+#ifdef EAP_AKA
+ if (ret == 0) {
+ int eap_peer_aka_register(void);
+ ret = eap_peer_aka_register();
+ }
+#endif /* EAP_AKA */
+
+#ifdef EAP_FAST
+ if (ret == 0) {
+ int eap_peer_fast_register(void);
+ ret = eap_peer_fast_register();
+ }
+#endif /* EAP_FAST */
+
+#ifdef EAP_PAX
+ if (ret == 0) {
+ int eap_peer_pax_register(void);
+ ret = eap_peer_pax_register();
+ }
+#endif /* EAP_PAX */
+
+#ifdef EAP_SAKE
+ if (ret == 0) {
+ int eap_peer_sake_register(void);
+ ret = eap_peer_sake_register();
+ }
+#endif /* EAP_SAKE */
+
+#ifdef EAP_GPSK
+ if (ret == 0) {
+ int eap_peer_gpsk_register(void);
+ ret = eap_peer_gpsk_register();
+ }
+#endif /* EAP_GPSK */
+
+#ifdef EAP_VENDOR_TEST
+ if (ret == 0) {
+ int eap_peer_vendor_test_register(void);
+ ret = eap_peer_vendor_test_register();
+ }
+#endif /* EAP_VENDOR_TEST */
+
+ return ret;
+}
+
+
+/**
+ * eap_peer_unregister_methods - Unregister EAP peer methods
+ *
+ * This function is called at program termination to unregister all EAP peer
+ * methods.
+ */
+void eap_peer_unregister_methods(void)
+{
+ struct eap_method *m;
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+ void *handle;
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+ while (eap_methods) {
+ m = eap_methods;
+ eap_methods = eap_methods->next;
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+ handle = m->dl_handle;
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+ if (m->free)
+ m->free(m);
+ else
+ eap_peer_method_free(m);
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+ if (handle)
+ dlclose(handle);
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+ }
+}
diff --git a/contrib/wpa_supplicant/eap_methods.h b/contrib/wpa_supplicant/eap_methods.h
new file mode 100644
index 000000000000..625c4d16b8dc
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_methods.h
@@ -0,0 +1,87 @@
+/*
+ * EAP peer: Method registration
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EAP_METHODS_H
+#define EAP_METHODS_H
+
+#include "eap_defs.h"
+
+const struct eap_method * eap_sm_get_eap_methods(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_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);
+int eap_peer_register_methods(void);
+void eap_peer_unregister_methods(void);
+
+#else /* IEEE8021X_EAPOL */
+
+static inline EapType eap_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)
+{
+}
+
+#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)
+{
+ return 0;
+}
+
+static inline int eap_peer_method_unload(struct eap_method *method)
+{
+ return 0;
+}
+
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+#endif /* EAP_METHODS_H */
diff --git a/contrib/wpa_supplicant/eap_mschapv2.c b/contrib/wpa_supplicant/eap_mschapv2.c
index 9fcd480b856d..26c835148980 100644
--- a/contrib/wpa_supplicant/eap_mschapv2.c
+++ b/contrib/wpa_supplicant/eap_mschapv2.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -10,30 +10,60 @@
* license.
*
* See README and COPYING for more details.
+ *
+ * This file implements EAP peer part of EAP-MSCHAPV2 method (EAP type 26).
+ * draft-kamath-pppext-eap-mschapv2-00.txt defines the Microsoft EAP CHAP
+ * Extensions Protocol, Version 2, for mutual authentication and key
+ * derivation. This encapsulates MS-CHAP-v2 protocol which is defined in
+ * RFC 2759. Use of EAP-MSCHAPV2 derived keys with MPPE cipher is described in
+ * RFC 3079.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "ms_funcs.h"
#include "wpa_ctrl.h"
+#define MSCHAPV2_CHAL_LEN 16
+#define MSCHAPV2_NT_RESPONSE_LEN 24
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct eap_mschapv2_hdr {
- u8 code;
- u8 identifier;
- u16 length; /* including code, identifier, and length */
- u8 type; /* EAP_TYPE_MSCHAPV2 */
u8 op_code; /* MSCHAPV2_OP_* */
- u8 mschapv2_id; /* usually same as identifier */
+ u8 mschapv2_id; /* usually same as EAP identifier; must be changed
+ * for challenges, but not for success/failure */
u8 ms_length[2]; /* Note: misaligned; length - 5 */
/* followed by data */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+/* Response Data field */
+struct ms_response {
+ u8 peer_challenge[MSCHAPV2_CHAL_LEN];
+ u8 reserved[8];
+ u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
+ u8 flags;
+} STRUCT_PACKED;
+
+/* Change-Password Data field */
+struct ms_change_password {
+ u8 encr_password[516];
+ u8 encr_hash[16];
+ u8 peer_challenge[MSCHAPV2_CHAL_LEN];
+ u8 reserved[8];
+ u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
+ u8 flags[2];
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
#define MSCHAPV2_OP_CHALLENGE 1
#define MSCHAPV2_OP_RESPONSE 2
@@ -41,8 +71,6 @@ struct eap_mschapv2_hdr {
#define MSCHAPV2_OP_FAILURE 4
#define MSCHAPV2_OP_CHANGE_PASSWORD 7
-#define MSCHAPV2_RESP_LEN 49
-
#define ERROR_RESTRICTED_LOGON_HOURS 646
#define ERROR_ACCT_DISABLED 647
#define ERROR_PASSWD_EXPIRED 648
@@ -67,6 +95,7 @@ struct eap_mschapv2_data {
*/
u8 *peer_challenge;
u8 *auth_challenge;
+ int full_key;
int phase2;
u8 master_key[16];
@@ -84,27 +113,31 @@ static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv);
static void * eap_mschapv2_init(struct eap_sm *sm)
{
struct eap_mschapv2_data *data;
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
+
+ data->full_key = sm->mschapv2_full_key;
if (sm->peer_challenge) {
- data->peer_challenge = malloc(16);
+ data->full_key = 1;
+ data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
if (data->peer_challenge == NULL) {
eap_mschapv2_deinit(sm, data);
return NULL;
}
- memcpy(data->peer_challenge, sm->peer_challenge, 16);
+ os_memcpy(data->peer_challenge, sm->peer_challenge,
+ MSCHAPV2_CHAL_LEN);
}
if (sm->auth_challenge) {
- data->auth_challenge = malloc(16);
+ data->auth_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
if (data->auth_challenge == NULL) {
eap_mschapv2_deinit(sm, data);
return NULL;
}
- memcpy(data->auth_challenge, sm->auth_challenge, 16);
+ os_memcpy(data->auth_challenge, sm->auth_challenge,
+ MSCHAPV2_CHAL_LEN);
}
data->phase2 = sm->init_phase2;
@@ -116,54 +149,194 @@ static void * eap_mschapv2_init(struct eap_sm *sm)
static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
{
struct eap_mschapv2_data *data = priv;
- free(data->peer_challenge);
- free(data->auth_challenge);
- free(data->prev_challenge);
- free(data);
+ os_free(data->peer_challenge);
+ os_free(data->auth_challenge);
+ os_free(data->prev_challenge);
+ os_free(data);
+}
+
+
+static const u8 * eap_mschapv2_remove_domain(const u8 *username, size_t *len)
+{
+ size_t i;
+
+ /*
+ * MSCHAPv2 does not include optional domain name in the
+ * challenge-response calculation, so remove domain prefix
+ * (if present).
+ */
+
+ for (i = 0; i < *len; i++) {
+ if (username[i] == '\\') {
+ *len -= i + 1;
+ return username + i + 1;
+ }
+ }
+
+ return username;
+}
+
+
+static void eap_mschapv2_derive_response(
+ struct eap_mschapv2_data *data,
+ const u8 *username, size_t username_len,
+ const u8 *password, size_t password_len,
+ const u8 *auth_challenge, const u8 *peer_challenge,
+ u8 *nt_response)
+{
+ u8 password_hash[16], password_hash_hash[16];
+
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge",
+ auth_challenge, MSCHAPV2_CHAL_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
+ peer_challenge, MSCHAPV2_CHAL_LEN);
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
+ username, username_len);
+ wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password",
+ password, password_len);
+ generate_nt_response(auth_challenge, peer_challenge,
+ username, username_len,
+ password, password_len, nt_response);
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: response", nt_response,
+ MSCHAPV2_NT_RESPONSE_LEN);
+ /* Authenticator response is not really needed yet, but calculate it
+ * here so that challenges need not be saved. */
+ generate_authenticator_response(password, password_len,
+ peer_challenge, auth_challenge,
+ username, username_len, nt_response,
+ data->auth_response);
+ data->auth_response_valid = 1;
+
+ /* Likewise, generate master_key here since we have the needed data
+ * available. */
+ nt_password_hash(password, password_len, password_hash);
+ hash_nt_password_hash(password_hash, password_hash_hash);
+ get_master_key(password_hash_hash, nt_response, data->master_key);
+ data->master_key_valid = 1;
+}
+
+
+static u8 * eap_mschapv2_challenge_reply(struct eap_sm *sm,
+ struct eap_mschapv2_data *data, u8 id,
+ u8 mschapv2_id,
+ const u8 *auth_challenge,
+ size_t *respDataLen)
+{
+ struct eap_hdr *resp;
+ struct eap_mschapv2_hdr *ms;
+ u8 *rpos, *peer_challenge;
+ int ms_len;
+ struct ms_response *r;
+ size_t username_len, identity_len, password_len;
+ const u8 *username, *identity, *password;
+
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
+
+ identity = eap_get_config_identity(sm, &identity_len);
+ password = eap_get_config_password(sm, &password_len);
+ if (identity == NULL || password == NULL)
+ return NULL;
+
+ username_len = identity_len;
+ username = eap_mschapv2_remove_domain(identity, &username_len);
+
+ ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len;
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respDataLen,
+ ms_len, EAP_CODE_RESPONSE, id, &rpos);
+ if (resp == NULL)
+ return NULL;
+
+ ms = (struct eap_mschapv2_hdr *) rpos;
+ ms->op_code = MSCHAPV2_OP_RESPONSE;
+ ms->mschapv2_id = mschapv2_id;
+ if (data->prev_error) {
+ /*
+ * TODO: this does not seem to be enough when processing two
+ * or more failure messages. IAS did not increment mschapv2_id
+ * in its own packets, but it seemed to expect the peer to
+ * increment this for all packets(?).
+ */
+ ms->mschapv2_id++;
+ }
+ WPA_PUT_BE16(ms->ms_length, ms_len);
+ rpos = (u8 *) (ms + 1);
+ *rpos++ = sizeof(*r); /* Value-Size */
+
+ /* Response */
+ r = (struct ms_response *) rpos;
+ peer_challenge = r->peer_challenge;
+ if (data->peer_challenge) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
+ "in Phase 1");
+ peer_challenge = data->peer_challenge;
+ os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
+ } else if (os_get_random(peer_challenge, MSCHAPV2_CHAL_LEN)) {
+ os_free(resp);
+ return NULL;
+ }
+ os_memset(r->reserved, 0, 8);
+ if (data->auth_challenge) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
+ "in Phase 1");
+ auth_challenge = data->auth_challenge;
+ }
+ eap_mschapv2_derive_response(data, username, username_len,
+ password, password_len,
+ auth_challenge, peer_challenge,
+ r->nt_response);
+
+ r->flags = 0; /* reserved, must be zero */
+
+ os_memcpy((u8 *) (r + 1), identity, identity_len);
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
+ "(response)", resp->identifier, ms->mschapv2_id);
+ return (u8 *) resp;
}
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @data: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: Pointer to EAP-MSCHAPv2 header from the request
+ * @req_len: Length of the EAP-MSCHAPv2 data
+ * @id: EAP identifier used in th erequest
+ * @respDataLen: Length of the returned EAP response
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
const struct eap_mschapv2_hdr *req,
- size_t *respDataLen)
+ size_t req_len, u8 id, size_t *respDataLen)
{
- struct wpa_ssid *config = eap_get_config(sm);
- u8 *challenge, *peer_challenge, *username, *pos;
- int i, ms_len;
- size_t len, challenge_len, username_len;
- struct eap_mschapv2_hdr *resp;
- u8 password_hash[16], password_hash_hash[16];
+ size_t len, challenge_len;
+ const u8 *pos, *challenge;
- if (config == NULL)
+ if (eap_get_config_identity(sm, &len) == NULL ||
+ eap_get_config_password(sm, &len) == NULL)
return NULL;
- /* MSCHAPv2 does not include optional domain name in the
- * challenge-response calculation, so remove domain prefix
- * (if present). */
- username = config->identity;
- username_len = config->identity_len;
- for (i = 0; i < username_len; i++) {
- if (username[i] == '\\') {
- username_len -= i + 1;
- username += i + 1;
- break;
- }
- }
-
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
- len = be_to_host16(req->length);
- pos = (u8 *) (req + 1);
+ if (req_len < sizeof(*req) + 1) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
+ "(len %lu)", (unsigned long) req_len);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ pos = (const u8 *) (req + 1);
challenge_len = *pos++;
- if (challenge_len != 16) {
+ len = req_len - sizeof(*req) - 1;
+ if (challenge_len != MSCHAPV2_CHAL_LEN) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
"%lu", (unsigned long) challenge_len);
ret->ignore = TRUE;
return NULL;
}
- if (len < 10 || len - 10 < challenge_len) {
+ if (len < challenge_len) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
" packet: len=%lu challenge_len=%lu",
(unsigned long) len, (unsigned long) challenge_len);
@@ -178,116 +351,70 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
} else
challenge = pos;
pos += challenge_len;
+ len -= challenge_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
- pos, len - challenge_len - 10);
+ pos, len);
ret->ignore = FALSE;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
+ return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
+ challenge, respDataLen);
+}
- *respDataLen = sizeof(*resp) + 1 + MSCHAPV2_RESP_LEN +
- config->identity_len;
- resp = malloc(*respDataLen);
- if (resp == NULL)
- return NULL;
- memset(resp, 0, *respDataLen);
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(*respDataLen);
- resp->type = EAP_TYPE_MSCHAPV2;
- resp->op_code = MSCHAPV2_OP_RESPONSE;
- resp->mschapv2_id = req->mschapv2_id;
- if (data->prev_error) {
- /*
- * TODO: this does not seem to be enough when processing two
- * or more failure messages. IAS did not increment mschapv2_id
- * in its own packets, but it seemed to expect the peer to
- * increment this for all packets(?).
- */
- resp->mschapv2_id++;
- }
- ms_len = *respDataLen - 5;
- WPA_PUT_BE16(resp->ms_length, ms_len);
- pos = (u8 *) (resp + 1);
- *pos++ = MSCHAPV2_RESP_LEN; /* Value-Size */
- /* Response */
- peer_challenge = pos;
- if (data->peer_challenge) {
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
- "in Phase 1");
- peer_challenge = data->peer_challenge;
- } else if (hostapd_get_rand(peer_challenge, 16)) {
- free(resp);
- return NULL;
- }
- pos += 16;
- pos += 8; /* Reserved, must be zero */
- if (data->auth_challenge) {
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
- "in Phase 1");
- challenge = data->auth_challenge;
+static void eap_mschapv2_password_changed(struct eap_sm *sm,
+ struct eap_mschapv2_data *data)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config && config->new_password) {
+ wpa_msg(sm->msg_ctx, MSG_INFO,
+ WPA_EVENT_PASSWORD_CHANGED
+ "EAP-MSCHAPV2: Password changed successfully");
+ data->prev_error = 0;
+ os_free(config->password);
+ config->password = config->new_password;
+ config->new_password = NULL;
+ config->password_len = config->new_password_len;
+ config->new_password_len = 0;
}
- wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge", challenge, 16);
- wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
- peer_challenge, 16);
- wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
- username, username_len);
- wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: password",
- config->password, config->password_len);
- generate_nt_response(challenge, peer_challenge,
- username, username_len,
- config->password, config->password_len,
- pos);
- wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: response", pos, 24);
- /* Authenticator response is not really needed yet, but calculate it
- * here so that challenges need not be saved. */
- generate_authenticator_response(config->password, config->password_len,
- peer_challenge, challenge,
- username, username_len, pos,
- data->auth_response);
- data->auth_response_valid = 1;
-
- /* Likewise, generate master_key here since we have the needed data
- * available. */
- nt_password_hash(config->password, config->password_len,
- password_hash);
- hash_nt_password_hash(password_hash, password_hash_hash);
- get_master_key(password_hash_hash, pos /* nt_response */,
- data->master_key);
- data->master_key_valid = 1;
-
- pos += 24;
- pos++; /* Flag / reserved, must be zero */
-
- memcpy(pos, config->identity, config->identity_len);
- wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
- "(response)", resp->identifier, resp->mschapv2_id);
- return (u8 *) resp;
}
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 success message
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @data: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: Pointer to EAP-MSCHAPv2 header from the request
+ * @req_len: Length of the EAP-MSCHAPv2 data
+ * @id: EAP identifier used in th erequest
+ * @respDataLen: Length of the returned EAP response
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
static u8 * eap_mschapv2_success(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
const struct eap_mschapv2_hdr *req,
- size_t *respDataLen)
+ size_t req_len, u8 id, size_t *respDataLen)
{
- struct eap_mschapv2_hdr *resp;
+ struct eap_hdr *resp;
+ struct eap_mschapv2_hdr *ms;
const u8 *pos;
u8 recv_response[20];
- int len, left;
+ size_t len;
+ u8 *rpos;
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
- len = be_to_host16(req->length);
+ len = req_len - sizeof(*req);
pos = (const u8 *) (req + 1);
- if (!data->auth_response_valid || len < sizeof(*req) + 42 ||
+ if (!data->auth_response_valid || len < 42 ||
pos[0] != 'S' || pos[1] != '=' ||
hexstr2bin((char *) (pos + 2), recv_response, 20) ||
- memcmp(data->auth_response, recv_response, 20) != 0) {
+ os_memcmp(data->auth_response, recv_response, 20) != 0) {
wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
"response in success request");
ret->methodState = METHOD_DONE;
@@ -295,16 +422,19 @@ static u8 * eap_mschapv2_success(struct eap_sm *sm,
return NULL;
}
pos += 42;
- left = len - sizeof(*req) - 42;
- while (left > 0 && *pos == ' ') {
+ len -= 42;
+ while (len > 0 && *pos == ' ') {
pos++;
- left--;
+ len--;
}
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
- pos, left);
+ pos, len);
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
- *respDataLen = 6;
- resp = malloc(6);
+
+ /* Note: Only op_code of the EAP-MSCHAPV2 header is included in success
+ * message. */
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respDataLen,
+ 1, EAP_CODE_RESPONSE, id, &rpos);
if (resp == NULL) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
"buffer for success response");
@@ -312,31 +442,16 @@ static u8 * eap_mschapv2_success(struct eap_sm *sm,
return NULL;
}
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(6);
- resp->type = EAP_TYPE_MSCHAPV2;
- resp->op_code = MSCHAPV2_OP_SUCCESS;
+ ms = (struct eap_mschapv2_hdr *) rpos;
+ ms->op_code = MSCHAPV2_OP_SUCCESS;
ret->methodState = METHOD_DONE;
ret->decision = DECISION_UNCOND_SUCC;
ret->allowNotifications = FALSE;
data->success = 1;
- if (data->prev_error == ERROR_PASSWD_EXPIRED) {
- struct wpa_ssid *config = eap_get_config(sm);
- if (config && config->new_password) {
- wpa_msg(sm->msg_ctx, MSG_INFO,
- WPA_EVENT_PASSWORD_CHANGED
- "EAP-MSCHAPV2: Password changed successfully");
- data->prev_error = 0;
- free(config->password);
- config->password = config->new_password;
- config->new_password = NULL;
- config->password_len = config->new_password_len;
- config->new_password_len = 0;
- }
- }
+ if (data->prev_error == ERROR_PASSWD_EXPIRED)
+ eap_mschapv2_password_changed(sm, data);
return (u8 *) resp;
}
@@ -355,30 +470,30 @@ static int eap_mschapv2_failure_txt(struct eap_sm *sm,
pos = txt;
- if (pos && strncmp(pos, "E=", 2) == 0) {
+ if (pos && os_strncmp(pos, "E=", 2) == 0) {
pos += 2;
data->prev_error = atoi(pos);
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d",
data->prev_error);
- pos = strchr(pos, ' ');
+ pos = os_strchr(pos, ' ');
if (pos)
pos++;
}
- if (pos && strncmp(pos, "R=", 2) == 0) {
+ if (pos && os_strncmp(pos, "R=", 2) == 0) {
pos += 2;
retry = atoi(pos);
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed",
retry == 1 ? "" : "not ");
- pos = strchr(pos, ' ');
+ pos = os_strchr(pos, ' ');
if (pos)
pos++;
}
- if (pos && strncmp(pos, "C=", 2) == 0) {
+ if (pos && os_strncmp(pos, "C=", 2) == 0) {
int hex_len;
pos += 2;
- hex_len = strchr(pos, ' ') - (char *) pos;
+ hex_len = os_strchr(pos, ' ') - (char *) pos;
if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
if (hexstr2bin(pos, data->passwd_change_challenge,
PASSWD_CHANGE_CHAL_LEN)) {
@@ -395,7 +510,7 @@ static int eap_mschapv2_failure_txt(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure "
"challenge len %d", hex_len);
}
- pos = strchr(pos, ' ');
+ pos = os_strchr(pos, ' ');
if (pos)
pos++;
} else {
@@ -403,17 +518,17 @@ static int eap_mschapv2_failure_txt(struct eap_sm *sm,
"was not present in failure message");
}
- if (pos && strncmp(pos, "V=", 2) == 0) {
+ if (pos && os_strncmp(pos, "V=", 2) == 0) {
pos += 2;
data->passwd_change_version = atoi(pos);
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing "
"protocol version %d", data->passwd_change_version);
- pos = strchr(pos, ' ');
+ pos = os_strchr(pos, ' ');
if (pos)
pos++;
}
- if (pos && strncmp(pos, "M=", 2) == 0) {
+ if (pos && os_strncmp(pos, "M=", 2) == 0) {
pos += 2;
msg = pos;
}
@@ -427,14 +542,14 @@ static int eap_mschapv2_failure_txt(struct eap_sm *sm,
wpa_msg(sm->msg_ctx, MSG_INFO,
"EAP-MSCHAPV2: Password expired - password "
"change required");
- eap_sm_request_new_password(sm, config);
+ eap_sm_request_new_password(sm);
}
} else if (retry == 1 && config) {
/* TODO: could prevent the current password from being used
* again at least for some period of time */
if (!config->mschapv2_retry)
- eap_sm_request_identity(sm, config);
- eap_sm_request_password(sm, config);
+ eap_sm_request_identity(sm);
+ eap_sm_request_password(sm);
config->mschapv2_retry = 1;
} else if (config) {
/* TODO: prevent retries using same username/password */
@@ -449,137 +564,135 @@ static u8 * eap_mschapv2_change_password(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
const struct eap_mschapv2_hdr *req,
- size_t *respDataLen)
+ u8 id, size_t *respDataLen)
{
- struct eap_mschapv2_hdr *resp;
- int ms_len, i;
- u8 *peer_challenge, *username, *pos;
- size_t username_len;
- struct wpa_ssid *config = eap_get_config(sm);
-
- if (config == NULL || config->identity == NULL ||
- config->new_password == NULL || config->password == NULL)
+ struct eap_hdr *resp;
+ int ms_len;
+ const u8 *username, *password, *new_password;
+ u8 *pos;
+ size_t username_len, password_len, new_password_len;
+ struct eap_mschapv2_hdr *ms;
+ struct ms_change_password *cp;
+
+ username = eap_get_config_identity(sm, &username_len);
+ password = eap_get_config_password(sm, &password_len);
+ new_password = eap_get_config_new_password(sm, &new_password_len);
+ if (username == NULL || password == NULL || new_password == NULL)
return NULL;
- /*
- * MSCHAPv2 does not include optional domain name in the
- * challenge-response calculation, so remove domain prefix
- * (if present).
- */
- username = config->identity;
- username_len = config->identity_len;
- for (i = 0; i < username_len; i++) {
- if (username[i] == '\\') {
- username_len -= i + 1;
- username += i + 1;
- break;
- }
- }
+ username = eap_mschapv2_remove_domain(username, &username_len);
ret->ignore = FALSE;
ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_COND_SUCC;
ret->allowNotifications = TRUE;
- *respDataLen = 591;
- resp = malloc(*respDataLen);
- if (resp == NULL) {
+ ms_len = sizeof(*ms) + sizeof(*cp);
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respDataLen,
+ ms_len, EAP_CODE_RESPONSE, id, &pos);
+ if (resp == NULL)
return NULL;
- }
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16((u16) *respDataLen);
- resp->type = EAP_TYPE_MSCHAPV2;
- resp->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
- resp->mschapv2_id = req->mschapv2_id + 1;
- ms_len = *respDataLen - 5;
- WPA_PUT_BE16(resp->ms_length, ms_len);
- pos = (u8 *) (resp + 1);
+ ms = (struct eap_mschapv2_hdr *) pos;
+ ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
+ ms->mschapv2_id = req->mschapv2_id + 1;
+ WPA_PUT_BE16(ms->ms_length, ms_len);
+ cp = (struct ms_change_password *) (ms + 1);
/* Encrypted-Password */
new_password_encrypted_with_old_nt_password_hash(
- config->new_password, config->new_password_len,
- config->password, config->password_len, pos);
- pos += 516;
+ new_password, new_password_len,
+ password, password_len, cp->encr_password);
/* Encrypted-Hash */
old_nt_password_hash_encrypted_with_new_nt_password_hash(
- config->new_password, config->new_password_len,
- config->password, config->password_len, pos);
- pos += 16;
+ new_password, new_password_len,
+ password, password_len, cp->encr_hash);
/* Peer-Challenge */
- peer_challenge = pos;
- if (hostapd_get_rand(peer_challenge, 16)) {
- free(resp);
+ if (os_get_random(cp->peer_challenge, MSCHAPV2_CHAL_LEN)) {
+ os_free(resp);
return NULL;
}
- pos += 16;
/* Reserved, must be zero */
- memset(pos, 0, 8);
- pos += 8;
+ os_memset(cp->reserved, 0, 8);
/* NT-Response */
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge",
data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
- peer_challenge, 16);
+ cp->peer_challenge, MSCHAPV2_CHAL_LEN);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
username, username_len);
wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password",
- config->new_password, config->new_password_len);
- generate_nt_response(data->passwd_change_challenge, peer_challenge,
+ new_password, new_password_len);
+ generate_nt_response(data->passwd_change_challenge, cp->peer_challenge,
username, username_len,
- config->new_password, config->new_password_len,
- pos);
- wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response", pos, 24);
+ new_password, new_password_len,
+ cp->nt_response);
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response",
+ cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN);
/* Authenticator response is not really needed yet, but calculate it
* here so that challenges need not be saved. */
- generate_authenticator_response(config->new_password,
- config->new_password_len,
- peer_challenge,
+ generate_authenticator_response(new_password, new_password_len,
+ cp->peer_challenge,
data->passwd_change_challenge,
- username, username_len, pos,
- data->auth_response);
+ username, username_len,
+ cp->nt_response, data->auth_response);
data->auth_response_valid = 1;
- pos += 24;
-
/* Flags */
- *pos++ = 0;
- *pos++ = 0;
+ os_memset(cp->flags, 0, 2);
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
- "(change pw)", resp->identifier, resp->mschapv2_id);
+ "(change pw)", resp->identifier, ms->mschapv2_id);
return (u8 *) resp;
}
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 failure message
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @data: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: Pointer to EAP-MSCHAPv2 header from the request
+ * @req_len: Length of the EAP-MSCHAPv2 data
+ * @id: EAP identifier used in th erequest
+ * @respDataLen: Length of the returned EAP response
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
static u8 * eap_mschapv2_failure(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
const struct eap_mschapv2_hdr *req,
- size_t *respDataLen)
+ size_t req_len, u8 id, size_t *respDataLen)
{
- struct eap_mschapv2_hdr *resp;
+ struct eap_hdr *resp;
const u8 *msdata = (const u8 *) (req + 1);
char *buf;
- int len = be_to_host16(req->length) - sizeof(*req);
+ size_t len = req_len - sizeof(*req);
int retry = 0;
+ struct eap_mschapv2_hdr *ms;
+ u8 *pos;
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
msdata, len);
- buf = malloc(len + 1);
+ /*
+ * eap_mschapv2_failure_txt() expects a nul terminated string, so we
+ * must allocate a large enough temporary buffer to create that since
+ * the received message does not include nul termination.
+ */
+ buf = os_malloc(len + 1);
if (buf) {
- memcpy(buf, msdata, len);
+ os_memcpy(buf, msdata, len);
buf[len] = '\0';
retry = eap_mschapv2_failure_txt(sm, data, buf);
- free(buf);
+ os_free(buf);
}
ret->ignore = FALSE;
@@ -592,7 +705,7 @@ static u8 * eap_mschapv2_failure(struct eap_sm *sm,
struct wpa_ssid *config = eap_get_config(sm);
if (config && config->new_password)
return eap_mschapv2_change_password(sm, data, ret, req,
- respDataLen);
+ id, respDataLen);
if (config && config->pending_req_new_password)
return NULL;
} else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
@@ -602,22 +715,91 @@ static u8 * eap_mschapv2_failure(struct eap_sm *sm,
return NULL;
}
- *respDataLen = 6;
- resp = malloc(6);
- if (resp == NULL) {
+ /* Note: Only op_code of the EAP-MSCHAPV2 header is included in failure
+ * message. */
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, respDataLen,
+ 1, EAP_CODE_RESPONSE, id, &pos);
+ if (resp == NULL)
return NULL;
- }
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(6);
- resp->type = EAP_TYPE_MSCHAPV2;
- resp->op_code = MSCHAPV2_OP_FAILURE;
+ ms = (struct eap_mschapv2_hdr *) pos;
+ ms->op_code = MSCHAPV2_OP_FAILURE;
return (u8 *) resp;
}
+static int eap_mschapv2_check_config(struct eap_sm *sm)
+{
+ size_t len;
+
+ if (eap_get_config_identity(sm, &len) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
+ eap_sm_request_identity(sm);
+ return -1;
+ }
+
+ if (eap_get_config_password(sm, &len) == NULL) {
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+ eap_sm_request_password(sm);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
+ const struct eap_mschapv2_hdr *ms)
+{
+ size_t ms_len = WPA_GET_BE16(ms->ms_length);
+
+ if (ms_len == len)
+ return 0;
+
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
+ "ms_len=%lu", (unsigned long) len, (unsigned long) ms_len);
+ if (sm->workaround) {
+ /* Some authentication servers use invalid ms_len,
+ * ignore it for interoperability. */
+ wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
+ " invalid ms_len %lu (len %lu)",
+ (unsigned long) ms_len,
+ (unsigned long) len);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static void eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,
+ const u8 *reqData, size_t reqDataLen)
+{
+ /*
+ * Store a copy of the challenge message, so that it can be processed
+ * again in case retry is allowed after a possible failure.
+ */
+ os_free(data->prev_challenge);
+ data->prev_challenge = os_malloc(reqDataLen);
+ if (data->prev_challenge) {
+ data->prev_challenge_len = reqDataLen;
+ os_memcpy(data->prev_challenge, reqData, reqDataLen);
+ }
+}
+
+
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 request
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @reqData: EAP request to be processed (eapReqData)
+ * @reqDataLen: Length of the EAP request
+ * @respDataLen: Length of the returned EAP response
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
@@ -625,21 +807,13 @@ static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
{
struct eap_mschapv2_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
- const struct eap_mschapv2_hdr *req;
- int ms_len, using_prev_challenge = 0;
+ const struct eap_hdr *req;
+ const struct eap_mschapv2_hdr *ms;
+ int using_prev_challenge = 0;
const u8 *pos;
size_t len;
- if (config == NULL || config->identity == NULL) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
- eap_sm_request_identity(sm, config);
- ret->ignore = TRUE;
- return NULL;
- }
-
- if (config->password == NULL) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
- eap_sm_request_password(sm, config);
+ if (eap_mschapv2_check_config(sm)) {
ret->ignore = TRUE;
return NULL;
}
@@ -655,49 +829,38 @@ static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
config->mschapv2_retry = 0;
}
- pos = eap_hdr_validate(EAP_TYPE_MSCHAPV2, reqData, reqDataLen, &len);
- if (pos == NULL || len < 5) {
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+ reqData, reqDataLen, &len);
+ if (pos == NULL || len < sizeof(*ms) + 1) {
ret->ignore = TRUE;
return NULL;
}
- req = (const struct eap_mschapv2_hdr *) reqData;
- len = be_to_host16(req->length);
- ms_len = WPA_GET_BE16(req->ms_length);
- if (ms_len != len - 5) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
- "ms_len=%d", (unsigned long) len, ms_len);
- if (sm->workaround) {
- /* Some authentication servers use invalid ms_len,
- * ignore it for interoperability. */
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
- " invalid ms_len");
- } else {
- ret->ignore = TRUE;
- return NULL;
- }
+
+ ms = (const struct eap_mschapv2_hdr *) pos;
+ if (eap_mschapv2_check_mslen(sm, len, ms)) {
+ ret->ignore = TRUE;
+ return NULL;
}
+ req = (const struct eap_hdr *) reqData;
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
- req->identifier, req->mschapv2_id);
+ req->identifier, ms->mschapv2_id);
- switch (req->op_code) {
+ switch (ms->op_code) {
case MSCHAPV2_OP_CHALLENGE:
- if (!using_prev_challenge) {
- free(data->prev_challenge);
- data->prev_challenge = malloc(len);
- if (data->prev_challenge) {
- data->prev_challenge_len = len;
- memcpy(data->prev_challenge, reqData, len);
- }
- }
- return eap_mschapv2_challenge(sm, data, ret, req, respDataLen);
+ if (!using_prev_challenge)
+ eap_mschapv2_copy_challenge(data, reqData, reqDataLen);
+ return eap_mschapv2_challenge(sm, data, ret, ms, len,
+ req->identifier, respDataLen);
case MSCHAPV2_OP_SUCCESS:
- return eap_mschapv2_success(sm, data, ret, req, respDataLen);
+ return eap_mschapv2_success(sm, data, ret, ms, len,
+ req->identifier, respDataLen);
case MSCHAPV2_OP_FAILURE:
- return eap_mschapv2_failure(sm, data, ret, req, respDataLen);
+ return eap_mschapv2_failure(sm, data, ret, ms, len,
+ req->identifier, respDataLen);
default:
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
- req->op_code);
+ ms->op_code);
ret->ignore = TRUE;
return NULL;
}
@@ -720,18 +883,18 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (!data->master_key_valid || !data->success)
return NULL;
- if (data->peer_challenge) {
+ if (data->full_key) {
/* EAP-FAST needs both send and receive keys */
key_len = 2 * MSCHAPV2_KEY_LEN;
} else {
key_len = MSCHAPV2_KEY_LEN;
}
- key = malloc(key_len);
+ key = os_malloc(key_len);
if (key == NULL)
return NULL;
- if (data->peer_challenge) {
+ if (data->full_key) {
get_asymetric_start_key(data->master_key, key,
MSCHAPV2_KEY_LEN, 0, 0);
get_asymetric_start_key(data->master_key,
@@ -750,13 +913,32 @@ static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
-const struct eap_method eap_method_mschapv2 =
+/**
+ * eap_peer_mschapv2_register - Register EAP-MSCHAPv2 peer method
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to register EAP-MSCHAPv2 peer method into the EAP
+ * method list.
+ */
+int eap_peer_mschapv2_register(void)
{
- .method = EAP_TYPE_MSCHAPV2,
- .name = "MSCHAPV2",
- .init = eap_mschapv2_init,
- .deinit = eap_mschapv2_deinit,
- .process = eap_mschapv2_process,
- .isKeyAvailable = eap_mschapv2_isKeyAvailable,
- .getKey = eap_mschapv2_getKey,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+ "MSCHAPV2");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_mschapv2_init;
+ eap->deinit = eap_mschapv2_deinit;
+ eap->process = eap_mschapv2_process;
+ eap->isKeyAvailable = eap_mschapv2_isKeyAvailable;
+ eap->getKey = eap_mschapv2_getKey;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_otp.c b/contrib/wpa_supplicant/eap_otp.c
index e7ec44c4340b..4cb131f30b4e 100644
--- a/contrib/wpa_supplicant/eap_otp.c
+++ b/contrib/wpa_supplicant/eap_otp.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-OTP (RFC 3748)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-OTP (RFC 3748)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,18 +12,17 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
static void * eap_otp_init(struct eap_sm *sm)
{
+ /* No need for private data. However, must return non-NULL to indicate
+ * success. */
return (void *) 1;
}
@@ -38,14 +37,15 @@ static u8 * eap_otp_process(struct eap_sm *sm, void *priv,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *req;
struct eap_hdr *resp;
const u8 *pos, *password;
u8 *rpos;
size_t password_len, len;
+ int otp;
- pos = eap_hdr_validate(EAP_TYPE_OTP, reqData, reqDataLen, &len);
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_OTP,
+ reqData, reqDataLen, &len);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
@@ -54,58 +54,61 @@ static u8 * eap_otp_process(struct eap_sm *sm, void *priv,
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message",
pos, len);
- if (config == NULL ||
- (config->password == NULL && config->otp == NULL)) {
+ password = eap_get_config_otp(sm, &password_len);
+ if (password)
+ otp = 1;
+ else {
+ password = eap_get_config_password(sm, &password_len);
+ otp = 0;
+ }
+
+ if (password == NULL) {
wpa_printf(MSG_INFO, "EAP-OTP: Password not configured");
- eap_sm_request_otp(sm, config, (const char *) pos, len);
+ eap_sm_request_otp(sm, (const char *) pos, len);
ret->ignore = TRUE;
return NULL;
}
- if (config->otp) {
- password = config->otp;
- password_len = config->otp_len;
- } else {
- password = config->password;
- password_len = config->password_len;
- }
-
ret->ignore = FALSE;
ret->methodState = METHOD_DONE;
ret->decision = DECISION_COND_SUCC;
ret->allowNotifications = FALSE;
- *respDataLen = sizeof(struct eap_hdr) + 1 + password_len;
- resp = malloc(*respDataLen);
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_OTP, respDataLen,
+ password_len, EAP_CODE_RESPONSE, req->identifier,
+ &rpos);
if (resp == NULL)
return NULL;
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = req->identifier;
- resp->length = host_to_be16(*respDataLen);
- rpos = (u8 *) (resp + 1);
- *rpos++ = EAP_TYPE_OTP;
- memcpy(rpos, password, password_len);
+ os_memcpy(rpos, password, password_len);
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-OTP: Response",
password, password_len);
- if (config->otp) {
+ if (otp) {
wpa_printf(MSG_DEBUG, "EAP-OTP: Forgetting used password");
- memset(config->otp, 0, config->otp_len);
- free(config->otp);
- config->otp = NULL;
- config->otp_len = 0;
+ eap_clear_config_otp(sm);
}
return (u8 *) resp;
}
-const struct eap_method eap_method_otp =
+int eap_peer_otp_register(void)
{
- .method = EAP_TYPE_OTP,
- .name = "OTP",
- .init = eap_otp_init,
- .deinit = eap_otp_deinit,
- .process = eap_otp_process,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_OTP, "OTP");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_otp_init;
+ eap->deinit = eap_otp_deinit;
+ eap->process = eap_otp_process;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_pax.c b/contrib/wpa_supplicant/eap_pax.c
index b590b90da06c..d9d937dc1fbc 100644
--- a/contrib/wpa_supplicant/eap_pax.c
+++ b/contrib/wpa_supplicant/eap_pax.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PAX (draft-clancy-eap-pax-04.txt)
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-PAX (RFC 4746)
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,13 +12,10 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "eap_pax_common.h"
#include "sha1.h"
@@ -26,6 +23,11 @@
/*
* Note: only PAX_STD subprotocol is currently supported
+ *
+ * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite
+ * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and
+ * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits),
+ * RSAES-OAEP).
*/
struct eap_pax_data {
@@ -68,22 +70,21 @@ static void * eap_pax_init(struct eap_sm *sm)
return NULL;
}
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
data->state = PAX_INIT;
- data->cid = malloc(config->nai_len);
+ data->cid = os_malloc(config->nai_len);
if (data->cid == NULL) {
eap_pax_deinit(sm, data);
return NULL;
}
- memcpy(data->cid, config->nai, config->nai_len);
+ os_memcpy(data->cid, config->nai, config->nai_len);
data->cid_len = config->nai_len;
if (config->eappsk) {
- memcpy(data->ak, config->eappsk, EAP_PAX_AK_LEN);
+ os_memcpy(data->ak, config->eappsk, EAP_PAX_AK_LEN);
} else {
u8 hash[SHA1_MAC_LEN];
const unsigned char *addr[1];
@@ -91,7 +92,7 @@ static void * eap_pax_init(struct eap_sm *sm)
addr[0] = config->password;
len[0] = config->password_len;
sha1_vector(1, addr, len, hash);
- memcpy(data->ak, hash, EAP_PAX_AK_LEN);
+ os_memcpy(data->ak, hash, EAP_PAX_AK_LEN);
}
return data;
@@ -101,8 +102,8 @@ static void * eap_pax_init(struct eap_sm *sm)
static void eap_pax_deinit(struct eap_sm *sm, void *priv)
{
struct eap_pax_data *data = priv;
- free(data->cid);
- free(data);
+ os_free(data->cid);
+ os_free(data);
}
@@ -111,7 +112,7 @@ static struct eap_pax_hdr * eap_pax_alloc_resp(const struct eap_pax_hdr *req,
{
struct eap_pax_hdr *resp;
- resp = malloc(resp_len);
+ resp = os_malloc(resp_len);
if (resp == NULL)
return NULL;
resp->code = EAP_CODE_RESPONSE;
@@ -127,7 +128,7 @@ static struct eap_pax_hdr * eap_pax_alloc_resp(const struct eap_pax_hdr *req,
}
-static u8 * eap_pax_process_std_1(struct eap_sm *sm, struct eap_pax_data *data,
+static u8 * eap_pax_process_std_1(struct eap_pax_data *data,
struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
@@ -175,7 +176,7 @@ static u8 * eap_pax_process_std_1(struct eap_sm *sm, struct eap_pax_data *data,
pos += 2;
left -= 2;
- memcpy(data->rand.r.x, pos, EAP_PAX_RAND_LEN);
+ os_memcpy(data->rand.r.x, pos, EAP_PAX_RAND_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: X (server rand)",
data->rand.r.x, EAP_PAX_RAND_LEN);
pos += EAP_PAX_RAND_LEN;
@@ -212,14 +213,14 @@ static u8 * eap_pax_process_std_1(struct eap_sm *sm, struct eap_pax_data *data,
rpos = (u8 *) (resp + 1);
*rpos++ = 0;
*rpos++ = EAP_PAX_RAND_LEN;
- memcpy(rpos, data->rand.r.y, EAP_PAX_RAND_LEN);
+ os_memcpy(rpos, data->rand.r.y, EAP_PAX_RAND_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: B = Y (client rand)",
rpos, EAP_PAX_RAND_LEN);
rpos += EAP_PAX_RAND_LEN;
WPA_PUT_BE16(rpos, data->cid_len);
rpos += 2;
- memcpy(rpos, data->cid, data->cid_len);
+ os_memcpy(rpos, data->cid, data->cid_len);
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID", rpos, data->cid_len);
rpos += data->cid_len;
@@ -233,6 +234,8 @@ static u8 * eap_pax_process_std_1(struct eap_sm *sm, struct eap_pax_data *data,
rpos, EAP_PAX_MAC_LEN);
rpos += EAP_PAX_MAC_LEN;
+ /* Optional ADE could be added here, if needed */
+
eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
(u8 *) resp, *respDataLen - EAP_PAX_ICV_LEN,
NULL, 0, NULL, 0, rpos);
@@ -248,7 +251,7 @@ static u8 * eap_pax_process_std_1(struct eap_sm *sm, struct eap_pax_data *data,
}
-static u8 * eap_pax_process_std_3(struct eap_sm *sm, struct eap_pax_data *data,
+static u8 * eap_pax_process_std_3(struct eap_pax_data *data,
struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
@@ -300,7 +303,7 @@ static u8 * eap_pax_process_std_3(struct eap_sm *sm, struct eap_pax_data *data,
eap_pax_mac(data->mac_id, data->ck, EAP_PAX_CK_LEN,
data->rand.r.y, EAP_PAX_RAND_LEN,
(u8 *) data->cid, data->cid_len, NULL, 0, mac);
- if (memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) {
+ if (os_memcmp(pos, mac, EAP_PAX_MAC_LEN) != 0) {
wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
"received");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)",
@@ -326,6 +329,9 @@ static u8 * eap_pax_process_std_3(struct eap_sm *sm, struct eap_pax_data *data,
return NULL;
rpos = (u8 *) (resp + 1);
+
+ /* Optional ADE could be added here, if needed */
+
eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
(u8 *) resp, *respDataLen - EAP_PAX_ICV_LEN,
NULL, 0, NULL, 0, rpos);
@@ -352,7 +358,8 @@ static u8 * eap_pax_process(struct eap_sm *sm, void *priv,
size_t len;
u16 flen;
- pos = eap_hdr_validate(EAP_TYPE_PAX, reqData, reqDataLen, &len);
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PAX,
+ reqData, reqDataLen, &len);
if (pos == NULL || len < EAP_PAX_ICV_LEN) {
ret->ignore = TRUE;
return NULL;
@@ -393,7 +400,7 @@ static u8 * eap_pax_process(struct eap_sm *sm, void *priv,
return NULL;
}
- /* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
+ /* TODO: add support EAP_PAX_HMAC_SHA256_128 */
if (req->mac_id != EAP_PAX_MAC_HMAC_SHA1_128) {
wpa_printf(MSG_INFO, "EAP-PAX: Unsupported MAC ID 0x%x",
req->mac_id);
@@ -432,7 +439,7 @@ static u8 * eap_pax_process(struct eap_sm *sm, void *priv,
eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
reqData, flen, NULL, 0, NULL, 0, icvbuf);
}
- if (memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
+ if (os_memcmp(icv, icvbuf, EAP_PAX_ICV_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the "
"message");
wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
@@ -448,11 +455,11 @@ static u8 * eap_pax_process(struct eap_sm *sm, void *priv,
switch (req->op_code) {
case EAP_PAX_OP_STD_1:
- resp = eap_pax_process_std_1(sm, data, ret, reqData, flen,
+ resp = eap_pax_process_std_1(data, ret, reqData, flen,
respDataLen);
break;
case EAP_PAX_OP_STD_3:
- resp = eap_pax_process_std_3(sm, data, ret, reqData, flen,
+ resp = eap_pax_process_std_3(data, ret, reqData, flen,
respDataLen);
break;
default:
@@ -485,26 +492,60 @@ static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != PAX_DONE)
return NULL;
- key = malloc(EAP_PAX_MSK_LEN);
+ key = os_malloc(EAP_MSK_LEN);
if (key == NULL)
return NULL;
- *len = EAP_PAX_MSK_LEN;
+ *len = EAP_MSK_LEN;
eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
"Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN,
- EAP_PAX_MSK_LEN, key);
+ EAP_MSK_LEN, key);
return key;
}
-const struct eap_method eap_method_pax =
+static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
- .method = EAP_TYPE_PAX,
- .name = "PAX",
- .init = eap_pax_init,
- .deinit = eap_pax_deinit,
- .process = eap_pax_process,
- .isKeyAvailable = eap_pax_isKeyAvailable,
- .getKey = eap_pax_getKey,
-};
+ struct eap_pax_data *data = priv;
+ u8 *key;
+
+ if (data->state != PAX_DONE)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+ eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
+ "Extended Master Session Key",
+ data->rand.e, 2 * EAP_PAX_RAND_LEN,
+ EAP_EMSK_LEN, key);
+
+ return key;
+}
+
+
+int eap_peer_pax_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_pax_init;
+ eap->deinit = eap_pax_deinit;
+ eap->process = eap_pax_process;
+ eap->isKeyAvailable = eap_pax_isKeyAvailable;
+ eap->getKey = eap_pax_getKey;
+ eap->get_emsk = eap_pax_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_pax_common.c b/contrib/wpa_supplicant/eap_pax_common.c
index d8f4016a6a09..80110469dcc3 100644
--- a/contrib/wpa_supplicant/eap_pax_common.c
+++ b/contrib/wpa_supplicant/eap_pax_common.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PAX shared routines
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: EAP-PAX shared routines
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "sha1.h"
@@ -33,7 +31,7 @@
* @output: Buffer for the derived key
* Returns: 0 on success, -1 failed
*
- * draft-clancy-eap-pax-04.txt, chap. 2.5: PAX-KDF-W(X, Y, Z)
+ * RFC 4746, Section 2.6: PAX-KDF-W(X, Y, Z)
*/
int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
const char *identifier,
@@ -50,12 +48,12 @@ int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
if (identifier == NULL || num_blocks >= 255)
return -1;
- /* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
+ /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
return -1;
addr[0] = (const u8 *) identifier;
- len[0] = strlen(identifier);
+ len[0] = os_strlen(identifier);
addr[1] = entropy;
len[1] = entropy_len;
addr[2] = &counter;
@@ -66,7 +64,7 @@ int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
for (counter = 1; counter <= (u8) num_blocks; counter++) {
size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left;
hmac_sha1_vector(key, key_len, 3, addr, len, mac);
- memcpy(pos, mac, clen);
+ os_memcpy(pos, mac, clen);
pos += clen;
left -= clen;
}
@@ -102,7 +100,7 @@ int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
size_t len[3];
size_t count;
- /* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
+ /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
return -1;
@@ -115,7 +113,7 @@ int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0);
hmac_sha1_vector(key, key_len, count, addr, len, hash);
- memcpy(mac, hash, EAP_PAX_MAC_LEN);
+ os_memcpy(mac, hash, EAP_PAX_MAC_LEN);
return 0;
}
diff --git a/contrib/wpa_supplicant/eap_pax_common.h b/contrib/wpa_supplicant/eap_pax_common.h
index b5ad6af1f2b9..bbad5e4052ff 100644
--- a/contrib/wpa_supplicant/eap_pax_common.h
+++ b/contrib/wpa_supplicant/eap_pax_common.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PAX shared routines
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: EAP-PAX shared routines
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,10 @@
#ifndef EAP_PAX_COMMON_H
#define EAP_PAX_COMMON_H
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct eap_pax_hdr {
u8 code;
u8 identifier;
@@ -26,7 +30,11 @@ struct eap_pax_hdr {
u8 dh_group_id;
u8 public_key_id;
/* Followed by variable length payload and ICV */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
/* op_code: */
@@ -45,22 +53,31 @@ enum {
/* 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_MAC_AES_CBC_MAC_128 0x02
+#define EAP_PAX_HMAC_SHA256_128 0x02
/* dh_group_id: */
#define EAP_PAX_DH_GROUP_NONE 0x00
-#define EAP_PAX_DH_GROUP_3072_MODP 0x01
+#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_RSA_OAEP_2048 0x01
+#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_MSK_LEN 64
#define EAP_PAX_MAC_LEN 16
#define EAP_PAX_ICV_LEN 16
#define EAP_PAX_AK_LEN 16
diff --git a/contrib/wpa_supplicant/eap_peap.c b/contrib/wpa_supplicant/eap_peap.c
index efbb867a9c90..7f23e5be2ed6 100644
--- a/contrib/wpa_supplicant/eap_peap.c
+++ b/contrib/wpa_supplicant/eap_peap.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,14 +12,11 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
#include "eap_tls_common.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "tls.h"
#include "eap_tlv.h"
@@ -45,8 +42,8 @@ struct eap_peap_data {
void *phase2_priv;
int phase2_success;
- u8 phase2_type;
- u8 *phase2_types;
+ struct eap_method_type phase2_type;
+ struct eap_method_type *phase2_types;
size_t num_phase2_types;
int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
@@ -70,17 +67,16 @@ static void * eap_peap_init(struct eap_sm *sm)
struct eap_peap_data *data;
struct wpa_ssid *config = eap_get_config(sm);
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
sm->peap_done = FALSE;
- memset(data, 0, sizeof(*data));
data->peap_version = EAP_PEAP_VERSION;
data->force_peap_version = -1;
data->peap_outer_success = 2;
if (config && config->phase1) {
- char *pos = strstr(config->phase1, "peapver=");
+ char *pos = os_strstr(config->phase1, "peapver=");
if (pos) {
data->force_peap_version = atoi(pos + 8);
data->peap_version = data->force_peap_version;
@@ -88,22 +84,22 @@ static void * eap_peap_init(struct eap_sm *sm)
"%d", data->force_peap_version);
}
- if (strstr(config->phase1, "peaplabel=1")) {
+ if (os_strstr(config->phase1, "peaplabel=1")) {
data->force_new_label = 1;
wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for "
"key derivation");
}
- if (strstr(config->phase1, "peap_outer_success=0")) {
+ if (os_strstr(config->phase1, "peap_outer_success=0")) {
data->peap_outer_success = 0;
wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate "
"authentication on tunneled EAP-Success");
- } else if (strstr(config->phase1, "peap_outer_success=1")) {
+ } else if (os_strstr(config->phase1, "peap_outer_success=1")) {
data->peap_outer_success = 1;
wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled "
"EAP-Success after receiving tunneled "
"EAP-Success");
- } else if (strstr(config->phase1, "peap_outer_success=2")) {
+ } else if (os_strstr(config->phase1, "peap_outer_success=2")) {
data->peap_outer_success = 2;
wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK "
"after receiving tunneled EAP-Success");
@@ -112,15 +108,17 @@ static void * eap_peap_init(struct eap_sm *sm)
if (config && config->phase2) {
char *start, *pos, *buf;
- u8 method, *methods = NULL, *_methods;
+ struct eap_method_type *methods = NULL, *_methods;
+ u8 method;
size_t num_methods = 0;
- start = buf = strdup(config->phase2);
+ start = buf = os_strdup(config->phase2);
if (buf == NULL) {
eap_peap_deinit(sm, data);
return NULL;
}
while (start && *start != '\0') {
- pos = strstr(start, "auth=");
+ int vendor;
+ pos = os_strstr(start, "auth=");
if (pos == NULL)
break;
if (start != pos && *(pos - 1) != ' ') {
@@ -129,28 +127,33 @@ static void * eap_peap_init(struct eap_sm *sm)
}
start = pos + 5;
- pos = strchr(start, ' ');
+ pos = os_strchr(start, ' ');
if (pos)
*pos++ = '\0';
- method = eap_get_phase2_type(start);
- if (method == EAP_TYPE_NONE) {
+ method = eap_get_phase2_type(start, &vendor);
+ if (vendor == EAP_VENDOR_IETF &&
+ method == EAP_TYPE_NONE) {
wpa_printf(MSG_ERROR, "EAP-PEAP: Unsupported "
"Phase2 method '%s'", start);
} else {
num_methods++;
- _methods = realloc(methods, num_methods);
+ _methods = os_realloc(
+ methods,
+ num_methods * sizeof(*methods));
if (_methods == NULL) {
- free(methods);
+ os_free(methods);
+ os_free(buf);
eap_peap_deinit(sm, data);
return NULL;
}
methods = _methods;
- methods[num_methods - 1] = method;
+ methods[num_methods - 1].vendor = vendor;
+ methods[num_methods - 1].method = method;
}
start = pos;
}
- free(buf);
+ os_free(buf);
data->phase2_types = methods;
data->num_phase2_types = num_methods;
}
@@ -164,8 +167,10 @@ static void * eap_peap_init(struct eap_sm *sm)
return NULL;
}
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 EAP types",
- data->phase2_types, data->num_phase2_types);
- data->phase2_type = EAP_TYPE_NONE;
+ (u8 *) data->phase2_types,
+ data->num_phase2_types * sizeof(struct eap_method_type));
+ data->phase2_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_type.method = EAP_TYPE_NONE;
if (eap_tls_ssl_init(sm, &data->ssl, config)) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
@@ -184,11 +189,11 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
return;
if (data->phase2_priv && data->phase2_method)
data->phase2_method->deinit(sm, data->phase2_priv);
- free(data->phase2_types);
+ os_free(data->phase2_types);
eap_tls_ssl_deinit(sm, &data->ssl);
- free(data->key_data);
- free(data->pending_phase2_req);
- free(data);
+ os_free(data->key_data);
+ os_free(data->pending_phase2_req);
+ os_free(data);
}
@@ -204,7 +209,7 @@ static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
* add TLS Message Length field, if the frame is fragmented.
* Note: Microsoft IAS did not seem to like TLS Message Length with
* PEAP/MSCHAPv2. */
- resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
if (resp == NULL)
return -1;
@@ -221,7 +226,7 @@ static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
if (res < 0) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt Phase 2 "
"data");
- free(resp);
+ os_free(resp);
return -1;
}
@@ -232,29 +237,36 @@ static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
}
-static int eap_peap_phase2_nak(struct eap_sm *sm,
- struct eap_peap_data *data,
- struct eap_hdr *hdr,
+static int eap_peap_phase2_nak(struct eap_peap_data *data, struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
struct eap_hdr *resp_hdr;
u8 *pos = (u8 *) (hdr + 1);
+ size_t i;
+ /* TODO: add support for expanded Nak */
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: Nak type=%d", *pos);
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Allowed Phase2 EAP types",
- data->phase2_types, data->num_phase2_types);
- *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_types;
- *resp = malloc(*resp_len);
+ (u8 *) data->phase2_types,
+ data->num_phase2_types * sizeof(struct eap_method_type));
+ *resp_len = sizeof(struct eap_hdr) + 1;
+ *resp = os_malloc(*resp_len + data->num_phase2_types);
if (*resp == NULL)
return -1;
resp_hdr = (struct eap_hdr *) (*resp);
resp_hdr->code = EAP_CODE_RESPONSE;
resp_hdr->identifier = hdr->identifier;
- resp_hdr->length = host_to_be16(*resp_len);
pos = (u8 *) (resp_hdr + 1);
*pos++ = EAP_TYPE_NAK;
- memcpy(pos, data->phase2_types, data->num_phase2_types);
+ for (i = 0; i < data->num_phase2_types; i++) {
+ if (data->phase2_types[i].vendor == EAP_VENDOR_IETF &&
+ data->phase2_types[i].method < 256) {
+ (*resp_len)++;
+ *pos++ = data->phase2_types[i].method;
+ }
+ }
+ resp_hdr->length = host_to_be16(*resp_len);
return 0;
}
@@ -263,7 +275,6 @@ static int eap_peap_phase2_nak(struct eap_sm *sm,
static int eap_peap_phase2_request(struct eap_sm *sm,
struct eap_peap_data *data,
struct eap_method_ret *ret,
- const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -281,10 +292,10 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
switch (*pos) {
case EAP_TYPE_IDENTITY:
- *resp = eap_sm_buildIdentity(sm, req->identifier, resp_len, 1);
+ *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1);
break;
case EAP_TYPE_TLV:
- memset(&iret, 0, sizeof(iret));
+ os_memset(&iret, 0, sizeof(iret));
if (eap_tlv_process(sm, &iret, hdr, resp, resp_len)) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
@@ -298,27 +309,37 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
}
break;
default:
- if (data->phase2_type == EAP_TYPE_NONE) {
- int i;
+ if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
+ data->phase2_type.method == EAP_TYPE_NONE) {
+ size_t i;
for (i = 0; i < data->num_phase2_types; i++) {
- if (data->phase2_types[i] != *pos)
+ if (data->phase2_types[i].vendor !=
+ EAP_VENDOR_IETF ||
+ data->phase2_types[i].method != *pos)
continue;
- data->phase2_type = *pos;
+ data->phase2_type.vendor =
+ data->phase2_types[i].vendor;
+ data->phase2_type.method =
+ data->phase2_types[i].method;
wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
- "Phase 2 EAP method %d",
- data->phase2_type);
+ "Phase 2 EAP vendor %d method %d",
+ data->phase2_type.vendor,
+ data->phase2_type.method);
break;
}
}
- if (*pos != data->phase2_type || *pos == EAP_TYPE_NONE) {
- if (eap_peap_phase2_nak(sm, data, hdr, resp, resp_len))
+ if (*pos != data->phase2_type.method ||
+ *pos == EAP_TYPE_NONE) {
+ if (eap_peap_phase2_nak(data, hdr, resp, resp_len))
return -1;
return 0;
}
if (data->phase2_priv == NULL) {
- data->phase2_method = eap_sm_get_eap_methods(*pos);
+ data->phase2_method = eap_sm_get_eap_methods(
+ data->phase2_type.vendor,
+ data->phase2_type.method);
if (data->phase2_method) {
sm->init_phase2 = 1;
data->phase2_priv =
@@ -333,7 +354,7 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
ret->decision = DECISION_FAIL;
return -1;
}
- memset(&iret, 0, sizeof(iret));
+ os_memset(&iret, 0, sizeof(iret));
*resp = data->phase2_method->process(sm, data->phase2_priv,
&iret, (u8 *) hdr, len,
resp_len);
@@ -349,10 +370,10 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
if (*resp == NULL &&
(config->pending_req_identity || config->pending_req_password ||
config->pending_req_otp || config->pending_req_new_password)) {
- free(data->pending_phase2_req);
- data->pending_phase2_req = malloc(len);
+ os_free(data->pending_phase2_req);
+ data->pending_phase2_req = os_malloc(len);
if (data->pending_phase2_req) {
- memcpy(data->pending_phase2_req, hdr, len);
+ os_memcpy(data->pending_phase2_req, hdr, len);
data->pending_phase2_req_len = len;
}
}
@@ -368,10 +389,10 @@ static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted;
- int buf_len, len_decrypted, len, skip_change = 0;
+ int res, skip_change = 0;
struct eap_hdr *hdr, *rhdr;
u8 *resp = NULL;
- size_t resp_len;
+ size_t resp_len, len_decrypted, len, buf_len;
const u8 *msg;
size_t msg_len;
int need_more_input;
@@ -383,7 +404,7 @@ static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
"skip decryption and use old data");
/* Clear TLS reassembly state. */
- free(data->ssl.tls_in);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
data->ssl.tls_in_left = 0;
@@ -416,9 +437,9 @@ static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
buf_len = in_len;
if (data->ssl.tls_in_total > buf_len)
buf_len = data->ssl.tls_in_total;
- in_decrypted = malloc(buf_len);
+ in_decrypted = os_malloc(buf_len);
if (in_decrypted == NULL) {
- free(data->ssl.tls_in);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
wpa_printf(MSG_WARNING, "EAP-PEAP: failed to allocate memory "
@@ -426,18 +447,18 @@ static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
return -1;
}
- len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
- msg, msg_len,
- in_decrypted, buf_len);
- free(data->ssl.tls_in);
+ res = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ msg, msg_len, in_decrypted, buf_len);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
- if (len_decrypted < 0) {
+ if (res < 0) {
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to decrypt Phase 2 "
"data");
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
+ len_decrypted = res;
continue_req:
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP", in_decrypted,
@@ -457,14 +478,14 @@ continue_req:
}
if (data->peap_version == 0 && !skip_change) {
- struct eap_hdr *nhdr = malloc(sizeof(struct eap_hdr) +
- len_decrypted);
+ struct eap_hdr *nhdr = os_malloc(sizeof(struct eap_hdr) +
+ len_decrypted);
if (nhdr == NULL) {
- free(in_decrypted);
+ os_free(in_decrypted);
return 0;
}
- memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted);
- free(in_decrypted);
+ os_memcpy((u8 *) (nhdr + 1), in_decrypted, len_decrypted);
+ os_free(in_decrypted);
nhdr->code = req->code;
nhdr->identifier = req->identifier;
nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
@@ -475,23 +496,25 @@ continue_req:
}
hdr = (struct eap_hdr *) in_decrypted;
if (len_decrypted < sizeof(*hdr)) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
- "EAP frame (len=%d)", len_decrypted);
+ "EAP frame (len=%lu)",
+ (unsigned long) len_decrypted);
return 0;
}
len = be_to_host16(hdr->length);
if (len > len_decrypted) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
- "Phase 2 EAP frame (len=%d hdr->length=%d)",
- len_decrypted, len);
+ "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
+ (unsigned long) len_decrypted, (unsigned long) len);
return 0;
}
if (len < len_decrypted) {
wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
- "shorter length than full decrypted data (%d < %d)",
- len, len_decrypted);
+ "shorter length than full decrypted data "
+ "(%lu < %lu)",
+ (unsigned long) len, (unsigned long) len_decrypted);
if (sm->workaround && len == 4 && len_decrypted == 5 &&
in_decrypted[4] == EAP_TYPE_IDENTITY) {
/* Radiator 3.9 seems to set Phase 2 EAP header to use
@@ -500,19 +523,22 @@ continue_req:
* This was fixed in 2004-06-23 patch for Radiator and
* this workaround can be removed at some point. */
wpa_printf(MSG_INFO, "EAP-PEAP: workaround -> replace "
- "Phase 2 EAP header len (%d) with real "
- "decrypted len (%d)", len, len_decrypted);
+ "Phase 2 EAP header len (%lu) with real "
+ "decrypted len (%lu)",
+ (unsigned long) len,
+ (unsigned long) len_decrypted);
len = len_decrypted;
hdr->length = host_to_be16(len);
}
}
wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
- "identifier=%d length=%d", hdr->code, hdr->identifier, len);
+ "identifier=%d length=%lu", hdr->code, hdr->identifier,
+ (unsigned long) len);
switch (hdr->code) {
case EAP_CODE_REQUEST:
- if (eap_peap_phase2_request(sm, data, ret, req, hdr,
+ if (eap_peap_phase2_request(sm, data, ret, hdr,
&resp, &resp_len)) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
"processing failed");
return 0;
@@ -531,7 +557,7 @@ continue_req:
ret->methodState = METHOD_DONE;
data->phase2_success = 1;
if (data->peap_outer_success == 2) {
- free(in_decrypted);
+ os_free(in_decrypted);
wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
"to finish authentication");
return 1;
@@ -539,9 +565,8 @@ continue_req:
/* Reply with EAP-Success within the TLS
* channel to complete the authentication. */
resp_len = sizeof(struct eap_hdr);
- resp = malloc(resp_len);
+ resp = os_zalloc(resp_len);
if (resp) {
- memset(resp, 0, resp_len);
rhdr = (struct eap_hdr *) resp;
rhdr->code = EAP_CODE_SUCCESS;
rhdr->identifier = hdr->identifier;
@@ -565,9 +590,8 @@ continue_req:
/* Reply with EAP-Failure within the TLS channel to complete
* failure reporting. */
resp_len = sizeof(struct eap_hdr);
- resp = malloc(resp_len);
+ resp = os_zalloc(resp_len);
if (resp) {
- memset(resp, 0, resp_len);
rhdr = (struct eap_hdr *) resp;
rhdr->code = EAP_CODE_FAILURE;
rhdr->identifier = hdr->identifier;
@@ -580,20 +604,20 @@ continue_req:
break;
}
- free(in_decrypted);
+ os_free(in_decrypted);
if (resp) {
u8 *resp_pos;
size_t resp_send_len;
- int skip_change = 0;
+ int skip_change2 = 0;
wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: Encrypting Phase 2 data",
resp, resp_len);
/* PEAP version changes */
if (resp_len >= 5 && resp[0] == EAP_CODE_RESPONSE &&
resp[4] == EAP_TYPE_TLV)
- skip_change = 1;
- if (data->peap_version == 0 && !skip_change) {
+ skip_change2 = 1;
+ if (data->peap_version == 0 && !skip_change2) {
resp_pos = resp + sizeof(struct eap_hdr);
resp_send_len = resp_len - sizeof(struct eap_hdr);
} else {
@@ -607,7 +631,7 @@ continue_req:
wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
"a Phase 2 frame");
}
- free(resp);
+ os_free(resp);
}
return 0;
@@ -669,7 +693,7 @@ static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
char *label;
wpa_printf(MSG_DEBUG,
"EAP-PEAP: TLS done, proceed to Phase 2");
- free(data->key_data);
+ os_free(data->key_data);
/* draft-josefsson-ppext-eap-tls-eap-05.txt
* specifies that PEAPv1 would use "client PEAP
* encryption" as the label. However, most existing
@@ -716,6 +740,19 @@ static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
data->resuming = 0;
}
+
+ if (res == 2) {
+ /*
+ * Application data included in the handshake message.
+ */
+ os_free(data->pending_phase2_req);
+ data->pending_phase2_req = resp;
+ data->pending_phase2_req_len = *respDataLen;
+ resp = NULL;
+ *respDataLen = 0;
+ res = eap_peap_decrypt(sm, data, ret, req, pos, left,
+ &resp, respDataLen);
+ }
}
if (ret->methodState == METHOD_DONE) {
@@ -742,7 +779,7 @@ static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
- free(data->pending_phase2_req);
+ os_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
}
@@ -750,12 +787,15 @@ static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_peap_data *data = priv;
- free(data->key_data);
+ os_free(data->key_data);
data->key_data = NULL;
if (eap_tls_reauth_init(sm, &data->ssl)) {
- free(data);
+ 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_success = 0;
data->resuming = 1;
sm->peap_done = FALSE;
@@ -767,13 +807,17 @@ static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
size_t buflen, int verbose)
{
struct eap_peap_data *data = priv;
- int len;
+ int len, ret;
len = eap_tls_status(sm, &data->ssl, buf, buflen, verbose);
if (data->phase2_method) {
- len += snprintf(buf + len, buflen - len,
- "EAP-PEAPv%d Phase2 method=%s\n",
- data->peap_version, data->phase2_method->name);
+ ret = os_snprintf(buf + len, buflen - len,
+ "EAP-PEAPv%d Phase2 method=%s\n",
+ data->peap_version,
+ data->phase2_method->name);
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
}
return len;
}
@@ -794,28 +838,39 @@ static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->key_data == NULL || !data->phase2_success)
return NULL;
- key = malloc(EAP_TLS_KEY_LEN);
+ key = os_malloc(EAP_TLS_KEY_LEN);
if (key == NULL)
return NULL;
*len = EAP_TLS_KEY_LEN;
- memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+ os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
return key;
}
-const struct eap_method eap_method_peap =
+int eap_peer_peap_register(void)
{
- .method = EAP_TYPE_PEAP,
- .name = "PEAP",
- .init = eap_peap_init,
- .deinit = eap_peap_deinit,
- .process = eap_peap_process,
- .isKeyAvailable = eap_peap_isKeyAvailable,
- .getKey = eap_peap_getKey,
- .get_status = eap_peap_get_status,
- .has_reauth_data = eap_peap_has_reauth_data,
- .deinit_for_reauth = eap_peap_deinit_for_reauth,
- .init_for_reauth = eap_peap_init_for_reauth,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_peap_init;
+ eap->deinit = eap_peap_deinit;
+ eap->process = eap_peap_process;
+ eap->isKeyAvailable = eap_peap_isKeyAvailable;
+ eap->getKey = eap_peap_getKey;
+ eap->get_status = eap_peap_get_status;
+ eap->has_reauth_data = eap_peap_has_reauth_data;
+ eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
+ eap->init_for_reauth = eap_peap_init_for_reauth;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_psk.c b/contrib/wpa_supplicant/eap_psk.c
index 853c79a5e89a..e07b25b026a9 100644
--- a/contrib/wpa_supplicant/eap_psk.c
+++ b/contrib/wpa_supplicant/eap_psk.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-09.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-PSK (RFC 4764)
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,13 +15,10 @@
* different from WPA-PSK. This file is not needed for WPA-PSK functionality.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "md5.h"
#include "aes_wrap.h"
@@ -34,7 +31,8 @@ struct eap_psk_data {
u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
u8 *id_s, *id_p;
size_t id_s_len, id_p_len;
- u8 key_data[EAP_PSK_MSK_LEN];
+ u8 msk[EAP_MSK_LEN];
+ u8 emsk[EAP_EMSK_LEN];
};
@@ -48,24 +46,23 @@ static void * eap_psk_init(struct eap_sm *sm)
return NULL;
}
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
eap_psk_key_setup(config->eappsk, data->ak, data->kdk);
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: AK", data->ak, EAP_PSK_AK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, EAP_PSK_KDK_LEN);
data->state = PSK_INIT;
if (config->nai) {
- data->id_p = malloc(config->nai_len);
+ data->id_p = os_malloc(config->nai_len);
if (data->id_p)
- memcpy(data->id_p, config->nai, config->nai_len);
+ os_memcpy(data->id_p, config->nai, config->nai_len);
data->id_p_len = config->nai_len;
}
if (data->id_p == NULL) {
wpa_printf(MSG_INFO, "EAP-PSK: could not get own identity");
- free(data);
+ os_free(data);
return NULL;
}
@@ -76,13 +73,13 @@ static void * eap_psk_init(struct eap_sm *sm)
static void eap_psk_deinit(struct eap_sm *sm, void *priv)
{
struct eap_psk_data *data = priv;
- free(data->id_s);
- free(data->id_p);
- free(data);
+ os_free(data->id_s);
+ os_free(data->id_p);
+ os_free(data);
}
-static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
+static u8 * eap_psk_process_1(struct eap_psk_data *data,
struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
@@ -107,25 +104,25 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
- if ((hdr1->flags & 0x03) != 0) {
+ if (EAP_PSK_FLAGS_GET_T(hdr1->flags) != 0) {
wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
- hdr1->flags & 0x03);
+ EAP_PSK_FLAGS_GET_T(hdr1->flags));
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return NULL;
}
wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
EAP_PSK_RAND_LEN);
- free(data->id_s);
+ os_free(data->id_s);
data->id_s_len = be_to_host16(hdr1->length) - sizeof(*hdr1);
- data->id_s = malloc(data->id_s_len);
+ data->id_s = os_malloc(data->id_s_len);
if (data->id_s == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
"ID_S (len=%lu)", (unsigned long) data->id_s_len);
ret->ignore = TRUE;
return NULL;
}
- memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
+ os_memcpy(data->id_s, (u8 *) (hdr1 + 1), data->id_s_len);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
data->id_s, data->id_s_len);
@@ -136,7 +133,7 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
}
*respDataLen = sizeof(*hdr2) + data->id_p_len;
- resp = malloc(*respDataLen);
+ resp = os_malloc(*respDataLen);
if (resp == NULL)
return NULL;
hdr2 = (struct eap_psk_hdr_2 *) resp;
@@ -144,26 +141,26 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
hdr2->identifier = hdr1->identifier;
hdr2->length = host_to_be16(*respDataLen);
hdr2->type = EAP_TYPE_PSK;
- hdr2->flags = 1; /* T=1 */
- memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
- memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
- memcpy((u8 *) (hdr2 + 1), data->id_p, data->id_p_len);
+ hdr2->flags = EAP_PSK_FLAGS_SET_T(1); /* T=1 */
+ os_memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
+ os_memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy((u8 *) (hdr2 + 1), data->id_p, data->id_p_len);
/* MAC_P = OMAC1-AES-128(AK, ID_P||ID_S||RAND_S||RAND_P) */
buflen = data->id_p_len + data->id_s_len + 2 * EAP_PSK_RAND_LEN;
- buf = malloc(buflen);
+ buf = os_malloc(buflen);
if (buf == NULL) {
- free(resp);
+ os_free(resp);
return NULL;
}
- memcpy(buf, data->id_p, data->id_p_len);
+ os_memcpy(buf, data->id_p, data->id_p_len);
pos = buf + data->id_p_len;
- memcpy(pos, data->id_s, data->id_s_len);
+ os_memcpy(pos, data->id_s, data->id_s_len);
pos += data->id_s_len;
- memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
+ os_memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
pos += EAP_PSK_RAND_LEN;
- memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p);
- free(buf);
+ os_free(buf);
wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_P", hdr2->rand_p,
EAP_PSK_RAND_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_P", hdr2->mac_p, EAP_PSK_MAC_LEN);
@@ -176,7 +173,7 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
}
-static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
+static u8 * eap_psk_process_3(struct eap_psk_data *data,
struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
@@ -205,9 +202,9 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
left -= sizeof(*hdr3);
pchannel = (const u8 *) (hdr3 + 1);
wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
- if ((hdr3->flags & 0x03) != 2) {
+ if (EAP_PSK_FLAGS_GET_T(hdr3->flags) != 2) {
wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
- hdr3->flags & 0x03);
+ EAP_PSK_FLAGS_GET_T(hdr3->flags));
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return NULL;
@@ -227,14 +224,14 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
buflen = data->id_s_len + EAP_PSK_RAND_LEN;
- buf = malloc(buflen);
+ buf = os_malloc(buflen);
if (buf == NULL)
return NULL;
- memcpy(buf, data->id_s, data->id_s_len);
- memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
+ os_memcpy(buf, data->id_s, data->id_s_len);
+ os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
omac1_aes_128(data->ak, buf, buflen, mac);
- free(buf);
- if (memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
+ os_free(buf);
+ if (os_memcmp(mac, hdr3->mac_s, EAP_PSK_MAC_LEN) != 0) {
wpa_printf(MSG_WARNING, "EAP-PSK: Invalid MAC_S in third "
"message");
ret->methodState = METHOD_DONE;
@@ -244,13 +241,13 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
wpa_printf(MSG_DEBUG, "EAP-PSK: MAC_S verified successfully");
eap_psk_derive_keys(data->kdk, data->rand_p, data->tek,
- data->key_data);
+ data->msk, data->emsk);
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->key_data,
- EAP_PSK_MSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
- memset(nonce, 0, 12);
- memcpy(nonce + 12, pchannel, 4);
+ os_memset(nonce, 0, 12);
+ os_memcpy(nonce + 12, pchannel, 4);
pchannel += 4;
left -= 4;
@@ -265,18 +262,18 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - hdr", reqData, 5);
wpa_hexdump(MSG_MSGDUMP, "EAP-PSK: PCHANNEL - cipher msg", msg, left);
- decrypted = malloc(left);
+ decrypted = os_malloc(left);
if (decrypted == NULL) {
ret->methodState = METHOD_DONE;
ret->decision = DECISION_FAIL;
return NULL;
}
- memcpy(decrypted, msg, left);
+ os_memcpy(decrypted, msg, left);
if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
reqData, 22, decrypted, left, tag)) {
wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
- free(decrypted);
+ os_free(decrypted);
return NULL;
}
wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
@@ -300,9 +297,9 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
}
*respDataLen = sizeof(*hdr4) + 4 + 16 + 1;
- resp = malloc(*respDataLen + 1);
+ resp = os_malloc(*respDataLen + 1);
if (resp == NULL) {
- free(decrypted);
+ os_free(decrypted);
return NULL;
}
hdr4 = (struct eap_psk_hdr_4 *) resp;
@@ -310,13 +307,13 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
hdr4->identifier = hdr3->identifier;
hdr4->length = host_to_be16(*respDataLen);
hdr4->type = EAP_TYPE_PSK;
- hdr4->flags = 3; /* T=3 */
- memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
+ hdr4->flags = EAP_PSK_FLAGS_SET_T(3); /* T=3 */
+ os_memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
rpchannel = (u8 *) (hdr4 + 1);
/* nonce++ */
inc_byte_array(nonce, sizeof(nonce));
- memcpy(rpchannel, nonce + 12, 4);
+ os_memcpy(rpchannel, nonce + 12, 4);
data_len = 1;
if (decrypted[0] & EAP_PSK_E_FLAG) {
@@ -349,7 +346,7 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
ret->methodState = METHOD_DONE;
ret->decision = failed ? DECISION_FAIL : DECISION_UNCOND_SUCC;
- free(decrypted);
+ os_free(decrypted);
return resp;
}
@@ -365,7 +362,8 @@ static u8 * eap_psk_process(struct eap_sm *sm, void *priv,
u8 *resp = NULL;
size_t len;
- pos = eap_hdr_validate(EAP_TYPE_PSK, reqData, reqDataLen, &len);
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_PSK,
+ reqData, reqDataLen, &len);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
@@ -379,11 +377,11 @@ static u8 * eap_psk_process(struct eap_sm *sm, void *priv,
switch (data->state) {
case PSK_INIT:
- resp = eap_psk_process_1(sm, data, ret, reqData, len,
+ resp = eap_psk_process_1(data, ret, reqData, len,
respDataLen);
break;
case PSK_MAC_SENT:
- resp = eap_psk_process_3(sm, data, ret, reqData, len,
+ resp = eap_psk_process_3(data, ret, reqData, len,
respDataLen);
break;
case PSK_DONE:
@@ -416,24 +414,55 @@ static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != PSK_DONE)
return NULL;
- key = malloc(EAP_PSK_MSK_LEN);
+ key = os_malloc(EAP_MSK_LEN);
if (key == NULL)
return NULL;
- *len = EAP_PSK_MSK_LEN;
- memcpy(key, data->key_data, EAP_PSK_MSK_LEN);
+ *len = EAP_MSK_LEN;
+ os_memcpy(key, data->msk, EAP_MSK_LEN);
return key;
}
-const struct eap_method eap_method_psk =
+static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
- .method = EAP_TYPE_PSK,
- .name = "PSK",
- .init = eap_psk_init,
- .deinit = eap_psk_deinit,
- .process = eap_psk_process,
- .isKeyAvailable = eap_psk_isKeyAvailable,
- .getKey = eap_psk_getKey,
-};
+ struct eap_psk_data *data = priv;
+ u8 *key;
+
+ if (data->state != PSK_DONE)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+
+ return key;
+}
+
+
+int eap_peer_psk_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_psk_init;
+ eap->deinit = eap_psk_deinit;
+ eap->process = eap_psk_process;
+ eap->isKeyAvailable = eap_psk_isKeyAvailable;
+ eap->getKey = eap_psk_getKey;
+ eap->get_emsk = eap_psk_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_psk_common.c b/contrib/wpa_supplicant/eap_psk_common.c
index 24de66cf0cb7..8d896ae639d5 100644
--- a/contrib/wpa_supplicant/eap_psk_common.c
+++ b/contrib/wpa_supplicant/eap_psk_common.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PSK shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: EAP-PSK shared routines
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,12 +12,11 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "aes_wrap.h"
+#include "eap_defs.h"
#include "eap_psk_common.h"
#define aes_block_size 16
@@ -25,9 +24,9 @@
void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
{
- memset(ak, 0, aes_block_size);
+ os_memset(ak, 0, aes_block_size);
aes_128_encrypt_block(psk, ak, ak);
- memcpy(kdk, ak, aes_block_size);
+ os_memcpy(kdk, ak, aes_block_size);
ak[aes_block_size - 1] ^= 0x01;
kdk[aes_block_size - 1] ^= 0x02;
aes_128_encrypt_block(psk, ak, ak);
@@ -35,7 +34,8 @@ void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
}
-void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk)
+void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk,
+ u8 *emsk)
{
u8 hash[aes_block_size];
u8 counter = 1;
@@ -48,10 +48,17 @@ void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk)
hash[aes_block_size - 1] ^= counter;
counter++;
- for (i = 0; i < EAP_PSK_MSK_LEN / aes_block_size; i++) {
+ for (i = 0; i < EAP_MSK_LEN / aes_block_size; i++) {
hash[aes_block_size - 1] ^= counter;
aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]);
hash[aes_block_size - 1] ^= counter;
counter++;
}
+
+ for (i = 0; i < EAP_EMSK_LEN / aes_block_size; i++) {
+ hash[aes_block_size - 1] ^= counter;
+ aes_128_encrypt_block(kdk, hash, &emsk[i * aes_block_size]);
+ hash[aes_block_size - 1] ^= counter;
+ counter++;
+ }
}
diff --git a/contrib/wpa_supplicant/eap_psk_common.h b/contrib/wpa_supplicant/eap_psk_common.h
index 5dd3a1042da3..e1bdccf5916a 100644
--- a/contrib/wpa_supplicant/eap_psk_common.h
+++ b/contrib/wpa_supplicant/eap_psk_common.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PSK shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: EAP-PSK shared routines
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,7 +19,6 @@
#define EAP_PSK_RAND_LEN 16
#define EAP_PSK_MAC_LEN 16
#define EAP_PSK_TEK_LEN 16
-#define EAP_PSK_MSK_LEN 64
#define EAP_PSK_PSK_LEN 16
#define EAP_PSK_AK_LEN 16
#define EAP_PSK_KDK_LEN 16
@@ -29,6 +28,13 @@
#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 */
+
/* Shared prefix for all EAP-PSK frames */
struct eap_psk_hdr {
u8 code;
@@ -36,7 +42,7 @@ struct eap_psk_hdr {
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
u8 flags;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
/* EAP-PSK First Message (AS -> Supplicant) */
struct eap_psk_hdr_1 {
@@ -47,7 +53,7 @@ struct eap_psk_hdr_1 {
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
/* Followed by variable length ID_S */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
/* EAP-PSK Second Message (Supplicant -> AS) */
struct eap_psk_hdr_2 {
@@ -60,7 +66,7 @@ struct eap_psk_hdr_2 {
u8 rand_p[EAP_PSK_RAND_LEN];
u8 mac_p[EAP_PSK_MAC_LEN];
/* Followed by variable length ID_P */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
/* EAP-PSK Third Message (AS -> Supplicant) */
struct eap_psk_hdr_3 {
@@ -72,7 +78,7 @@ struct eap_psk_hdr_3 {
u8 rand_s[EAP_PSK_RAND_LEN];
u8 mac_s[EAP_PSK_MAC_LEN];
/* Followed by variable length PCHANNEL */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
/* EAP-PSK Fourth Message (Supplicant -> AS) */
struct eap_psk_hdr_4 {
@@ -83,10 +89,15 @@ struct eap_psk_hdr_4 {
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
/* Followed by variable length PCHANNEL */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk);
-void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk);
+void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk,
+ u8 *emsk);
#endif /* EAP_PSK_COMMON_H */
diff --git a/contrib/wpa_supplicant/eap_sake.c b/contrib/wpa_supplicant/eap_sake.c
new file mode 100644
index 000000000000..85ca4a41d88a
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_sake.c
@@ -0,0 +1,515 @@
+/*
+ * EAP peer method: EAP-SAKE (RFC 4763)
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_i.h"
+#include "config_ssid.h"
+#include "eap_sake_common.h"
+
+struct eap_sake_data {
+ enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
+ u8 root_secret_a[EAP_SAKE_ROOT_SECRET_LEN];
+ u8 root_secret_b[EAP_SAKE_ROOT_SECRET_LEN];
+ u8 rand_s[EAP_SAKE_RAND_LEN];
+ u8 rand_p[EAP_SAKE_RAND_LEN];
+ struct {
+ u8 auth[EAP_SAKE_TEK_AUTH_LEN];
+ u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
+ } tek;
+ u8 msk[EAP_MSK_LEN];
+ u8 emsk[EAP_EMSK_LEN];
+ u8 session_id;
+ int session_id_set;
+ u8 *peerid;
+ size_t peerid_len;
+ u8 *serverid;
+ size_t serverid_len;
+};
+
+
+static const char * eap_sake_state_txt(int state)
+{
+ switch (state) {
+ case IDENTITY:
+ return "IDENTITY";
+ case CHALLENGE:
+ return "CHALLENGE";
+ case CONFIRM:
+ return "CONFIRM";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "?";
+ }
+}
+
+
+static void eap_sake_state(struct eap_sake_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
+ eap_sake_state_txt(data->state),
+ eap_sake_state_txt(state));
+ data->state = state;
+}
+
+
+static void eap_sake_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_sake_init(struct eap_sm *sm)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_sake_data *data;
+
+ if (config == NULL) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: No configuration found");
+ return NULL;
+ }
+
+ if (!config->eappsk ||
+ config->eappsk_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: No key (eappsk) of correct "
+ "length configured");
+ return NULL;
+ }
+
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = IDENTITY;
+
+ if (config->nai) {
+ data->peerid = os_malloc(config->nai_len);
+ if (data->peerid == NULL) {
+ eap_sake_deinit(sm, data);
+ return NULL;
+ }
+ os_memcpy(data->peerid, config->nai, config->nai_len);
+ data->peerid_len = config->nai_len;
+ }
+
+ os_memcpy(data->root_secret_a, config->eappsk,
+ EAP_SAKE_ROOT_SECRET_LEN);
+ os_memcpy(data->root_secret_b,
+ config->eappsk + EAP_SAKE_ROOT_SECRET_LEN,
+ EAP_SAKE_ROOT_SECRET_LEN);
+
+ return data;
+}
+
+
+static void eap_sake_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_sake_data *data = priv;
+ os_free(data->serverid);
+ os_free(data->peerid);
+ os_free(data);
+}
+
+
+static u8 * eap_sake_build_msg(struct eap_sake_data *data, u8 **payload,
+ int id, size_t *length, u8 subtype)
+{
+ struct eap_sake_hdr *req;
+ u8 *msg;
+
+ *length += sizeof(struct eap_sake_hdr);
+
+ msg = os_zalloc(*length);
+ if (msg == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
+ "request");
+ return NULL;
+ }
+
+ req = (struct eap_sake_hdr *) msg;
+ req->code = EAP_CODE_RESPONSE;
+ req->identifier = id;
+ req->length = htons((u16) *length);
+ req->type = EAP_TYPE_SAKE;
+ req->version = EAP_SAKE_VERSION;
+ req->session_id = data->session_id;
+ req->subtype = subtype;
+ *payload = (u8 *) (req + 1);
+
+ return msg;
+}
+
+
+static u8 * eap_sake_process_identity(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ const u8 *payload, size_t payload_len,
+ size_t *respDataLen)
+{
+ struct eap_sake_parse_attr attr;
+ u8 *resp, *rpos;
+ const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
+
+ if (data->state != IDENTITY) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Identity");
+
+ if (eap_sake_parse_attributes(payload, payload_len, &attr))
+ return NULL;
+
+ if (!attr.perm_id_req && !attr.any_id_req) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: No AT_PERM_ID_REQ or "
+ "AT_ANY_ID_REQ in Request/Identity");
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Identity");
+
+ *respDataLen = 2 + data->peerid_len;
+ resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
+ EAP_SAKE_SUBTYPE_IDENTITY);
+ if (resp == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
+ *rpos++ = EAP_SAKE_AT_PEERID;
+ *rpos++ = 2 + data->peerid_len;
+ if (data->peerid)
+ os_memcpy(rpos, data->peerid, data->peerid_len);
+
+ eap_sake_state(data, CHALLENGE);
+
+ return resp;
+}
+
+
+static u8 * eap_sake_process_challenge(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ const u8 *payload, size_t payload_len,
+ size_t *respDataLen)
+{
+ struct eap_sake_parse_attr attr;
+ u8 *resp, *rpos;
+ const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
+
+ if (data->state != IDENTITY && data->state != CHALLENGE) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge received "
+ "in unexpected state (%d)", data->state);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ if (data->state == IDENTITY)
+ eap_sake_state(data, CHALLENGE);
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Challenge");
+
+ if (eap_sake_parse_attributes(payload, payload_len, &attr))
+ return NULL;
+
+ if (!attr.rand_s) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Request/Challenge did not "
+ "include AT_RAND_S");
+ return NULL;
+ }
+
+ os_memcpy(data->rand_s, attr.rand_s, EAP_SAKE_RAND_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
+ data->rand_s, EAP_SAKE_RAND_LEN);
+
+ if (hostapd_get_rand(data->rand_p, EAP_SAKE_RAND_LEN)) {
+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_P (peer rand)",
+ data->rand_p, EAP_SAKE_RAND_LEN);
+
+ os_free(data->serverid);
+ data->serverid = NULL;
+ data->serverid_len = 0;
+ if (attr.serverid) {
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-SAKE: SERVERID",
+ attr.serverid, attr.serverid_len);
+ data->serverid = os_malloc(attr.serverid_len);
+ if (data->serverid == NULL)
+ return NULL;
+ os_memcpy(data->serverid, attr.serverid, attr.serverid_len);
+ data->serverid_len = attr.serverid_len;
+ }
+
+ eap_sake_derive_keys(data->root_secret_a, data->root_secret_b,
+ data->rand_s, data->rand_p,
+ (u8 *) &data->tek, data->msk, data->emsk);
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Challenge");
+
+ *respDataLen = 2 + EAP_SAKE_RAND_LEN + 2 + EAP_SAKE_MIC_LEN;
+ if (data->peerid)
+ *respDataLen += 2 + data->peerid_len;
+ resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
+ EAP_SAKE_SUBTYPE_CHALLENGE);
+ if (resp == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_P");
+ *rpos++ = EAP_SAKE_AT_RAND_P;
+ *rpos++ = 2 + EAP_SAKE_RAND_LEN;
+ os_memcpy(rpos, data->rand_p, EAP_SAKE_RAND_LEN);
+ rpos += EAP_SAKE_RAND_LEN;
+
+ if (data->peerid) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PEERID");
+ *rpos++ = EAP_SAKE_AT_PEERID;
+ *rpos++ = 2 + data->peerid_len;
+ os_memcpy(rpos, data->peerid, data->peerid_len);
+ rpos += data->peerid_len;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
+ *rpos++ = EAP_SAKE_AT_MIC_P;
+ *rpos++ = 2 + EAP_SAKE_MIC_LEN;
+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len, 1,
+ resp, *respDataLen, rpos, rpos)) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+ os_free(resp);
+ return NULL;
+ }
+
+ eap_sake_state(data, CONFIRM);
+
+ return resp;
+}
+
+
+static u8 * eap_sake_process_confirm(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ const u8 *payload, size_t payload_len,
+ size_t *respDataLen)
+{
+ struct eap_sake_parse_attr attr;
+ u8 mic_s[EAP_SAKE_MIC_LEN];
+ u8 *resp, *rpos;
+ const struct eap_hdr *hdr = (const struct eap_hdr *) reqData;
+
+ if (data->state != CONFIRM) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Request/Confirm");
+
+ if (eap_sake_parse_attributes(payload, payload_len, &attr))
+ return NULL;
+
+ if (!attr.mic_s) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Request/Confirm did not "
+ "include AT_MIC_S");
+ return NULL;
+ }
+
+ eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len, 0,
+ reqData, reqDataLen, attr.mic_s, mic_s);
+ if (os_memcmp(attr.mic_s, mic_s, EAP_SAKE_MIC_LEN) != 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_S");
+ eap_sake_state(data, FAILURE);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = FALSE;
+ *respDataLen = 0;
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending "
+ "Response/Auth-Reject");
+ return eap_sake_build_msg(data, &rpos, hdr->identifier,
+ respDataLen,
+ EAP_SAKE_SUBTYPE_AUTH_REJECT);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Sending Response/Confirm");
+
+ *respDataLen = 2 + EAP_SAKE_MIC_LEN;
+ resp = eap_sake_build_msg(data, &rpos, hdr->identifier, respDataLen,
+ EAP_SAKE_SUBTYPE_CONFIRM);
+ if (resp == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_P");
+ *rpos++ = EAP_SAKE_AT_MIC_P;
+ *rpos++ = 2 + EAP_SAKE_MIC_LEN;
+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len, 1,
+ resp, *respDataLen, rpos, rpos)) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+ os_free(resp);
+ return NULL;
+ }
+
+ eap_sake_state(data, SUCCESS);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ ret->allowNotifications = FALSE;
+
+ return resp;
+}
+
+
+static u8 * eap_sake_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_sake_data *data = priv;
+ const struct eap_sake_hdr *req;
+ u8 *resp;
+ const u8 *pos, *end;
+ size_t len;
+ u8 subtype, session_id;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SAKE,
+ reqData, reqDataLen, &len);
+ if (pos == NULL || len < 3) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ req = (const struct eap_sake_hdr *) reqData;
+ subtype = req->subtype;
+ session_id = req->session_id;
+ pos = (const u8 *) (req + 1);
+ end = reqData + be_to_host16(req->length);
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype %d "
+ "session_id %d", subtype, session_id);
+ wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
+ pos, end - pos);
+
+ if (data->session_id_set && data->session_id != session_id) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
+ session_id, data->session_id);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ data->session_id = session_id;
+ data->session_id_set = 1;
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ switch (subtype) {
+ case EAP_SAKE_SUBTYPE_IDENTITY:
+ resp = eap_sake_process_identity(sm, data, ret, reqData,
+ reqDataLen, pos, end - pos,
+ respDataLen);
+ break;
+ case EAP_SAKE_SUBTYPE_CHALLENGE:
+ resp = eap_sake_process_challenge(sm, data, ret, reqData,
+ reqDataLen, pos, end - pos,
+ respDataLen);
+ break;
+ case EAP_SAKE_SUBTYPE_CONFIRM:
+ resp = eap_sake_process_confirm(sm, data, ret, reqData,
+ reqDataLen, pos, end - pos,
+ respDataLen);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring message with "
+ "unknown subtype %d", subtype);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (ret->methodState == METHOD_DONE)
+ ret->allowNotifications = FALSE;
+
+ return resp;
+}
+
+
+static Boolean eap_sake_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_sake_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sake_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_MSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->msk, EAP_MSK_LEN);
+ *len = EAP_MSK_LEN;
+
+ return key;
+}
+
+
+static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sake_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
+int eap_peer_sake_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_sake_init;
+ eap->deinit = eap_sake_deinit;
+ eap->process = eap_sake_process;
+ eap->isKeyAvailable = eap_sake_isKeyAvailable;
+ eap->getKey = eap_sake_getKey;
+ eap->get_emsk = eap_sake_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_sake_common.c b/contrib/wpa_supplicant/eap_sake_common.c
new file mode 100644
index 000000000000..4b5476f101c8
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_sake_common.c
@@ -0,0 +1,380 @@
+/*
+ * EAP server/peer: EAP-SAKE shared routines
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "eap_defs.h"
+#include "eap_sake_common.h"
+
+
+static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr,
+ const u8 *pos)
+{
+ size_t i;
+
+ switch (pos[0]) {
+ case EAP_SAKE_AT_RAND_S:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_S");
+ if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_S with "
+ "invalid length %d", pos[1]);
+ return -1;
+ }
+ attr->rand_s = pos + 2;
+ break;
+ case EAP_SAKE_AT_RAND_P:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_P");
+ if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_P with "
+ "invalid length %d", pos[1]);
+ return -1;
+ }
+ attr->rand_p = pos + 2;
+ break;
+ case EAP_SAKE_AT_MIC_S:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_S");
+ if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_S with "
+ "invalid length %d", pos[1]);
+ return -1;
+ }
+ attr->mic_s = pos + 2;
+ break;
+ case EAP_SAKE_AT_MIC_P:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_P");
+ if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_P with "
+ "invalid length %d", pos[1]);
+ return -1;
+ }
+ attr->mic_p = pos + 2;
+ break;
+ case EAP_SAKE_AT_SERVERID:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SERVERID");
+ attr->serverid = pos + 2;
+ attr->serverid_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_PEERID:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PEERID");
+ attr->peerid = pos + 2;
+ attr->peerid_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_SPI_S:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_S");
+ attr->spi_s = pos + 2;
+ attr->spi_s_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_SPI_P:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_P");
+ attr->spi_p = pos + 2;
+ attr->spi_p_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_ANY_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ANY_ID_REQ");
+ if (pos[1] != 4) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid AT_ANY_ID_REQ"
+ " length %d", pos[1]);
+ return -1;
+ }
+ attr->any_id_req = pos + 2;
+ break;
+ case EAP_SAKE_AT_PERM_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PERM_ID_REQ");
+ if (pos[1] != 4) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
+ "AT_PERM_ID_REQ length %d", pos[1]);
+ return -1;
+ }
+ attr->perm_id_req = pos + 2;
+ break;
+ case EAP_SAKE_AT_ENCR_DATA:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ENCR_DATA");
+ attr->encr_data = pos + 2;
+ attr->encr_data_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_IV:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+ attr->iv = pos + 2;
+ attr->iv_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_PADDING:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PADDING");
+ for (i = 2; i < pos[1]; i++) {
+ if (pos[i]) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_PADDING "
+ "with non-zero pad byte");
+ return -1;
+ }
+ }
+ break;
+ case EAP_SAKE_AT_NEXT_TMPID:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_NEXT_TMPID");
+ attr->next_tmpid = pos + 2;
+ attr->next_tmpid_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_MSK_LIFE:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+ if (pos[1] != 6) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
+ "AT_MSK_LIFE length %d", pos[1]);
+ return -1;
+ }
+ attr->msk_life = pos + 2;
+ break;
+ default:
+ if (pos[0] < 128) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown non-skippable"
+ " attribute %d", pos[0]);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring unknown skippable "
+ "attribute %d", pos[0]);
+ break;
+ }
+
+ if (attr->iv && !attr->encr_data) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_IV included without "
+ "AT_ENCR_DATA");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * eap_sake_parse_attributes - Parse EAP-SAKE attributes
+ * @buf: Packet payload (starting with the first attribute)
+ * @len: Payload length
+ * @attr: Structure to be filled with found attributes
+ * Returns: 0 on success or -1 on failure
+ */
+int eap_sake_parse_attributes(const u8 *buf, size_t len,
+ struct eap_sake_parse_attr *attr)
+{
+ const u8 *pos = buf, *end = buf + len;
+
+ os_memset(attr, 0, sizeof(*attr));
+ while (pos < end) {
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute");
+ return -1;
+ }
+
+ if (pos[1] < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute "
+ "length (%d)", pos[1]);
+ return -1;
+ }
+
+ if (pos + pos[1] > end) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow");
+ return -1;
+ }
+
+ if (eap_sake_parse_add_attr(attr, pos))
+ return -1;
+
+ pos += pos[1];
+ }
+
+ return 0;
+}
+
+
+/**
+ * eap_sake_kdf - EAP-SAKE Key Derivation Function (KDF)
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF
+ * @data: Extra data (start) to bind into the key
+ * @data_len: Length of the data
+ * @data2: Extra data (end) to bind into the key
+ * @data2_len: Length of the data2
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i.
+ */
+static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len,
+ const u8 *data2, size_t data2_len,
+ u8 *buf, size_t buf_len)
+{
+ u8 counter = 0;
+ size_t pos, plen;
+ u8 hash[SHA1_MAC_LEN];
+ size_t label_len = os_strlen(label) + 1;
+ const unsigned char *addr[4];
+ size_t len[4];
+
+ addr[0] = (u8 *) label; /* Label | Y */
+ len[0] = label_len;
+ addr[1] = data; /* Msg[start] */
+ len[1] = data_len;
+ addr[2] = data2; /* Msg[end] */
+ len[2] = data2_len;
+ addr[3] = &counter; /* Length */
+ len[3] = 1;
+
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ if (plen >= SHA1_MAC_LEN) {
+ hmac_sha1_vector(key, key_len, 4, addr, len,
+ &buf[pos]);
+ pos += SHA1_MAC_LEN;
+ } else {
+ hmac_sha1_vector(key, key_len, 4, addr, len,
+ hash);
+ os_memcpy(&buf[pos], hash, plen);
+ break;
+ }
+ counter++;
+ }
+}
+
+
+/**
+ * eap_sake_derive_keys - Derive EAP-SAKE keys
+ * @root_secret_a: 16-byte Root-Secret-A
+ * @root_secret_b: 16-byte Root-Secret-B
+ * @rand_s: 16-byte RAND_S
+ * @rand_p: 16-byte RAND_P
+ * @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16])
+ * @msk: Buffer for 64-byte MSK
+ * @emsk: Buffer for 64-byte EMSK
+ *
+ * This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6.
+ */
+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)
+{
+ u8 sms_a[EAP_SAKE_SMS_LEN];
+ u8 sms_b[EAP_SAKE_SMS_LEN];
+ u8 key_buf[EAP_MSK_LEN + EAP_EMSK_LEN];
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Deriving keys");
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A",
+ root_secret_a, EAP_SAKE_ROOT_SECRET_LEN);
+ eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
+ "SAKE Master Secret A",
+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+ sms_a, EAP_SAKE_SMS_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN);
+ eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+ tek, EAP_SAKE_TEK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth",
+ tek, EAP_SAKE_TEK_AUTH_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher",
+ tek + EAP_SAKE_TEK_AUTH_LEN, EAP_SAKE_TEK_CIPHER_LEN);
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B",
+ root_secret_b, EAP_SAKE_ROOT_SECRET_LEN);
+ eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
+ "SAKE Master Secret B",
+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+ sms_b, EAP_SAKE_SMS_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN);
+ eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+ key_buf, sizeof(key_buf));
+ os_memcpy(msk, key_buf, EAP_MSK_LEN);
+ os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN);
+}
+
+
+/**
+ * eap_sake_compute_mic - Compute EAP-SAKE MIC for an EAP packet
+ * @tek_auth: 16-byte TEK-Auth
+ * @rand_s: 16-byte RAND_S
+ * @rand_p: 16-byte RAND_P
+ * @serverid: SERVERID
+ * @serverid_len: SERVERID length
+ * @peerid: PEERID
+ * @peerid_len: PEERID length
+ * @peer: MIC calculation for 0 = Server, 1 = Peer message
+ * @eap: EAP packet
+ * @eap_len: EAP packet length
+ * @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len])
+ * @mic: Buffer for the computed 16-byte MIC
+ */
+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)
+{
+ u8 _rand[2 * EAP_SAKE_RAND_LEN];
+ u8 *tmp, *pos;
+ size_t tmplen;
+
+ tmplen = serverid_len + 1 + peerid_len + 1 + eap_len;
+ tmp = os_malloc(tmplen);
+ if (tmp == NULL)
+ return -1;
+ pos = tmp;
+ if (peer) {
+ if (peerid) {
+ os_memcpy(pos, peerid, peerid_len);
+ pos += peerid_len;
+ }
+ *pos++ = 0x00;
+ if (serverid) {
+ os_memcpy(pos, serverid, serverid_len);
+ pos += serverid_len;
+ }
+ *pos++ = 0x00;
+
+ os_memcpy(_rand, rand_s, EAP_SAKE_RAND_LEN);
+ os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_p,
+ EAP_SAKE_RAND_LEN);
+ } else {
+ if (serverid) {
+ os_memcpy(pos, serverid, serverid_len);
+ pos += serverid_len;
+ }
+ *pos++ = 0x00;
+ if (peerid) {
+ os_memcpy(pos, peerid, peerid_len);
+ pos += peerid_len;
+ }
+ *pos++ = 0x00;
+
+ os_memcpy(_rand, rand_p, EAP_SAKE_RAND_LEN);
+ os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_s,
+ EAP_SAKE_RAND_LEN);
+ }
+
+ os_memcpy(pos, eap, eap_len);
+ os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN);
+
+ eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
+ peer ? "Peer MIC" : "Server MIC",
+ _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
+ mic, EAP_SAKE_MIC_LEN);
+
+ os_free(tmp);
+
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/eap_sake_common.h b/contrib/wpa_supplicant/eap_sake_common.h
new file mode 100644
index 000000000000..ac6e8199d66b
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_sake_common.h
@@ -0,0 +1,104 @@
+/*
+ * EAP server/peer: EAP-SAKE shared routines
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EAP_SAKE_COMMON_H
+#define EAP_SAKE_COMMON_H
+
+#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 code;
+ u8 identifier;
+ u16 length;
+ u8 type; /* EAP_TYPE_SAKE */
+ 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);
+
+#endif /* EAP_SAKE_COMMON_H */
diff --git a/contrib/wpa_supplicant/eap_sim.c b/contrib/wpa_supplicant/eap_sim.c
index ca9d7376eaa3..545f0ae31d66 100644
--- a/contrib/wpa_supplicant/eap_sim.c
+++ b/contrib/wpa_supplicant/eap_sim.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-SIM (draft-haverinen-pppext-eap-sim-13.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-SIM (RFC 4186)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,50 +12,30 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "crypto.h"
#include "pcsc_funcs.h"
#include "eap_sim_common.h"
-#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 KC_LEN 8
-#define SRES_LEN 4
-#define EAP_SIM_MAX_FAST_REAUTHS 1000
struct eap_sim_data {
u8 *ver_list;
size_t ver_list_len;
int selected_version;
- int min_num_chal, num_chal;
+ size_t min_num_chal, num_chal;
- u8 kc[3][KC_LEN];
- u8 sres[3][SRES_LEN];
+ u8 kc[3][EAP_SIM_KC_LEN];
+ u8 sres[3][EAP_SIM_SRES_LEN];
u8 nonce_mt[EAP_SIM_NONCE_MT_LEN], nonce_s[EAP_SIM_NONCE_S_LEN];
u8 mk[EAP_SIM_MK_LEN];
u8 k_aut[EAP_SIM_K_AUT_LEN];
u8 k_encr[EAP_SIM_K_ENCR_LEN];
u8 msk[EAP_SIM_KEYING_DATA_LEN];
+ u8 emsk[EAP_EMSK_LEN];
u8 rand[3][GSM_RAND_LEN];
int num_id_req, num_notification;
@@ -76,33 +56,33 @@ static void * eap_sim_init(struct eap_sm *sm)
struct eap_sim_data *data;
struct wpa_ssid *config = eap_get_config(sm);
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
if (hostapd_get_rand(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
"for NONCE_MT");
- free(data);
+ os_free(data);
return NULL;
}
data->min_num_chal = 2;
if (config && config->phase1) {
- char *pos = strstr(config->phase1, "sim_min_num_chal=");
+ char *pos = os_strstr(config->phase1, "sim_min_num_chal=");
if (pos) {
data->min_num_chal = atoi(pos + 17);
if (data->min_num_chal < 2 || data->min_num_chal > 3) {
wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
"sim_min_num_chal configuration "
- "(%d, expected 2 or 3)",
- data->min_num_chal);
- free(data);
+ "(%lu, expected 2 or 3)",
+ (unsigned long) data->min_num_chal);
+ os_free(data);
return NULL;
}
wpa_printf(MSG_DEBUG, "EAP-SIM: Set minimum number of "
- "challenges to %d", data->min_num_chal);
+ "challenges to %lu",
+ (unsigned long) data->min_num_chal);
}
}
@@ -116,11 +96,11 @@ static void eap_sim_deinit(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
if (data) {
- free(data->ver_list);
- free(data->pseudonym);
- free(data->reauth_id);
- free(data->last_eap_identity);
- free(data);
+ os_free(data->ver_list);
+ os_free(data->pseudonym);
+ os_free(data->reauth_id);
+ os_free(data->last_eap_identity);
+ os_free(data);
}
}
@@ -146,26 +126,26 @@ static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
* concerned, but it is quite useful for cases where the AS is rotating
* the order of pre-configured values. */
{
- int i;
+ size_t i;
for (i = 0; i < data->num_chal; i++) {
if (data->rand[i][0] == 0xaa) {
- memcpy(data->kc[i],
- "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
- KC_LEN);
- memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
- SRES_LEN);
+ os_memcpy(data->kc[i],
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7",
+ EAP_SIM_KC_LEN);
+ os_memcpy(data->sres[i], "\xd1\xd2\xd3\xd4",
+ EAP_SIM_SRES_LEN);
} else if (data->rand[i][0] == 0xbb) {
- memcpy(data->kc[i],
- "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
- KC_LEN);
- memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
- SRES_LEN);
+ os_memcpy(data->kc[i],
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7",
+ EAP_SIM_KC_LEN);
+ os_memcpy(data->sres[i], "\xe1\xe2\xe3\xe4",
+ EAP_SIM_SRES_LEN);
} else {
- memcpy(data->kc[i],
- "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
- KC_LEN);
- memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
- SRES_LEN);
+ os_memcpy(data->kc[i],
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7",
+ EAP_SIM_KC_LEN);
+ os_memcpy(data->sres[i], "\xf1\xf2\xf3\xf4",
+ EAP_SIM_SRES_LEN);
}
}
}
@@ -174,38 +154,12 @@ static int eap_sim_gsm_auth(struct eap_sm *sm, struct eap_sim_data *data)
}
-static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
+static int eap_sim_supported_ver(int version)
{
return version == EAP_SIM_VERSION;
}
-static void eap_sim_derive_mk(struct eap_sim_data *data,
- const u8 *identity, size_t identity_len)
-{
- u8 sel_ver[2];
- const unsigned char *addr[5];
- size_t len[5];
-
- addr[0] = identity;
- len[0] = identity_len;
- addr[1] = (u8 *) data->kc;
- len[1] = data->num_chal * KC_LEN;
- addr[2] = data->nonce_mt;
- len[2] = EAP_SIM_NONCE_MT_LEN;
- addr[3] = data->ver_list;
- len[3] = data->ver_list_len;
- addr[4] = sel_ver;
- len[4] = 2;
-
- WPA_PUT_BE16(sel_ver, data->selected_version);
-
- /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
- sha1_vector(5, addr, len, data->mk);
- wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", data->mk, EAP_SIM_MK_LEN);
-}
-
-
#define CLEAR_PSEUDONYM 0x01
#define CLEAR_REAUTH_ID 0x02
#define CLEAR_EAP_ID 0x04
@@ -217,17 +171,17 @@ static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
id & CLEAR_REAUTH_ID ? " reauth_id" : "",
id & CLEAR_EAP_ID ? " eap_id" : "");
if (id & CLEAR_PSEUDONYM) {
- free(data->pseudonym);
+ os_free(data->pseudonym);
data->pseudonym = NULL;
data->pseudonym_len = 0;
}
if (id & CLEAR_REAUTH_ID) {
- free(data->reauth_id);
+ os_free(data->reauth_id);
data->reauth_id = NULL;
data->reauth_id_len = 0;
}
if (id & CLEAR_EAP_ID) {
- free(data->last_eap_identity);
+ os_free(data->last_eap_identity);
data->last_eap_identity = NULL;
data->last_eap_identity_len = 0;
}
@@ -238,15 +192,15 @@ static int eap_sim_learn_ids(struct eap_sim_data *data,
struct eap_sim_attrs *attr)
{
if (attr->next_pseudonym) {
- free(data->pseudonym);
- data->pseudonym = malloc(attr->next_pseudonym_len);
+ os_free(data->pseudonym);
+ data->pseudonym = os_malloc(attr->next_pseudonym_len);
if (data->pseudonym == NULL) {
wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
"next pseudonym");
return -1;
}
- memcpy(data->pseudonym, attr->next_pseudonym,
- attr->next_pseudonym_len);
+ os_memcpy(data->pseudonym, attr->next_pseudonym,
+ attr->next_pseudonym_len);
data->pseudonym_len = attr->next_pseudonym_len;
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-SIM: (encr) AT_NEXT_PSEUDONYM",
@@ -255,15 +209,15 @@ static int eap_sim_learn_ids(struct eap_sim_data *data,
}
if (attr->next_reauth_id) {
- free(data->reauth_id);
- data->reauth_id = malloc(attr->next_reauth_id_len);
+ os_free(data->reauth_id);
+ data->reauth_id = os_malloc(attr->next_reauth_id_len);
if (data->reauth_id == NULL) {
wpa_printf(MSG_INFO, "EAP-SIM: (encr) No memory for "
"next reauth_id");
return -1;
}
- memcpy(data->reauth_id, attr->next_reauth_id,
- attr->next_reauth_id_len);
+ os_memcpy(data->reauth_id, attr->next_reauth_id,
+ attr->next_reauth_id_len);
data->reauth_id_len = attr->next_reauth_id_len;
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-SIM: (encr) AT_NEXT_REAUTH_ID",
@@ -275,7 +229,7 @@ static int eap_sim_learn_ids(struct eap_sim_data *data,
}
-static u8 * eap_sim_client_error(struct eap_sm *sm, struct eap_sim_data *data,
+static u8 * eap_sim_client_error(struct eap_sim_data *data,
const struct eap_hdr *req,
size_t *respDataLen, int err)
{
@@ -298,8 +252,7 @@ static u8 * eap_sim_response_start(struct eap_sm *sm,
size_t *respDataLen,
enum eap_sim_id_req id_req)
{
- struct wpa_ssid *config = eap_get_config(sm);
- u8 *identity = NULL;
+ const u8 *identity = NULL;
size_t identity_len = 0;
struct eap_sim_msg *msg;
@@ -313,11 +266,12 @@ static u8 * eap_sim_response_start(struct eap_sm *sm,
identity = data->pseudonym;
identity_len = data->pseudonym_len;
eap_sim_clear_identities(data, CLEAR_REAUTH_ID);
- } else if (id_req != NO_ID_REQ && config && config->identity) {
- identity = config->identity;
- identity_len = config->identity_len;
- eap_sim_clear_identities(data,
- CLEAR_PSEUDONYM | CLEAR_REAUTH_ID);
+ } else if (id_req != NO_ID_REQ) {
+ identity = eap_get_config_identity(sm, &identity_len);
+ if (identity) {
+ eap_sim_clear_identities(data, CLEAR_PSEUDONYM |
+ CLEAR_REAUTH_ID);
+ }
}
if (id_req != NO_ID_REQ)
eap_sim_clear_identities(data, CLEAR_EAP_ID);
@@ -346,8 +300,7 @@ static u8 * eap_sim_response_start(struct eap_sm *sm,
}
-static u8 * eap_sim_response_challenge(struct eap_sm *sm,
- struct eap_sim_data *data,
+static u8 * eap_sim_response_challenge(struct eap_sim_data *data,
const struct eap_hdr *req,
size_t *respDataLen)
{
@@ -361,12 +314,11 @@ static u8 * eap_sim_response_challenge(struct eap_sm *sm,
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
return eap_sim_msg_finish(msg, respDataLen, data->k_aut,
(u8 *) data->sres,
- data->num_chal * SRES_LEN);
+ data->num_chal * EAP_SIM_SRES_LEN);
}
-static u8 * eap_sim_response_reauth(struct eap_sm *sm,
- struct eap_sim_data *data,
+static u8 * eap_sim_response_reauth(struct eap_sim_data *data,
const struct eap_hdr *req,
size_t *respDataLen, int counter_too_small)
{
@@ -405,8 +357,7 @@ static u8 * eap_sim_response_reauth(struct eap_sm *sm,
}
-static u8 * eap_sim_response_notification(struct eap_sm *sm,
- struct eap_sim_data *data,
+static u8 * eap_sim_response_notification(struct eap_sim_data *data,
const struct eap_hdr *req,
size_t *respDataLen,
u16 notification)
@@ -445,36 +396,37 @@ static u8 * eap_sim_response_notification(struct eap_sm *sm,
static u8 * eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data,
- const struct eap_hdr *req, size_t reqDataLen,
+ const struct eap_hdr *req,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
- int i, selected_version = -1, id_error;
+ int selected_version = -1, id_error;
+ size_t i;
u8 *pos;
wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Start");
if (attr->version_list == NULL) {
wpa_printf(MSG_INFO, "EAP-SIM: No AT_VERSION_LIST in "
"SIM/Start");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNSUPPORTED_VERSION);
}
- free(data->ver_list);
- data->ver_list = malloc(attr->version_list_len);
+ os_free(data->ver_list);
+ data->ver_list = os_malloc(attr->version_list_len);
if (data->ver_list == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Failed to allocate "
"memory for version list");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
- memcpy(data->ver_list, attr->version_list, attr->version_list_len);
+ os_memcpy(data->ver_list, attr->version_list, attr->version_list_len);
data->ver_list_len = attr->version_list_len;
pos = data->ver_list;
for (i = 0; i < data->ver_list_len / 2; i++) {
int ver = pos[0] * 256 + pos[1];
pos += 2;
- if (eap_sim_supported_ver(data, ver)) {
+ if (eap_sim_supported_ver(ver)) {
selected_version = ver;
break;
}
@@ -482,7 +434,7 @@ static u8 * eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data,
if (selected_version < 0) {
wpa_printf(MSG_INFO, "EAP-SIM: Could not find a supported "
"version");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNSUPPORTED_VERSION);
}
wpa_printf(MSG_DEBUG, "EAP-SIM: Selected Version %d",
@@ -512,7 +464,7 @@ static u8 * eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data,
if (id_error) {
wpa_printf(MSG_INFO, "EAP-SIM: Too many ID requests "
"used within one authentication");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
@@ -528,8 +480,7 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
- struct wpa_ssid *config = eap_get_config(sm);
- u8 *identity;
+ const u8 *identity;
size_t identity_len;
struct eap_sim_attrs eattr;
@@ -540,7 +491,7 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
"did not include%s%s",
!attr->mac ? " AT_MAC" : "",
!attr->rand ? " AT_RAND" : "");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
@@ -549,36 +500,36 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
if (attr->num_chal < data->min_num_chal) {
wpa_printf(MSG_INFO, "EAP-SIM: Insufficient number of "
"challenges (%lu)", (unsigned long) attr->num_chal);
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_INSUFFICIENT_NUM_OF_CHAL);
}
if (attr->num_chal > 3) {
wpa_printf(MSG_INFO, "EAP-SIM: Too many challenges "
"(%lu)", (unsigned long) attr->num_chal);
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
/* Verify that RANDs are different */
- if (memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
+ if (os_memcmp(attr->rand, attr->rand + GSM_RAND_LEN,
GSM_RAND_LEN) == 0 ||
(attr->num_chal > 2 &&
- (memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
- GSM_RAND_LEN) == 0 ||
- memcmp(attr->rand + GSM_RAND_LEN,
- attr->rand + 2 * GSM_RAND_LEN,
- GSM_RAND_LEN) == 0))) {
+ (os_memcmp(attr->rand, attr->rand + 2 * GSM_RAND_LEN,
+ GSM_RAND_LEN) == 0 ||
+ os_memcmp(attr->rand + GSM_RAND_LEN,
+ attr->rand + 2 * GSM_RAND_LEN,
+ GSM_RAND_LEN) == 0))) {
wpa_printf(MSG_INFO, "EAP-SIM: Same RAND used multiple times");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_RAND_NOT_FRESH);
}
- memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
+ os_memcpy(data->rand, attr->rand, attr->num_chal * GSM_RAND_LEN);
data->num_chal = attr->num_chal;
if (eap_sim_gsm_auth(sm, data)) {
wpa_printf(MSG_WARNING, "EAP-SIM: GSM authentication failed");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
if (data->last_eap_identity) {
@@ -587,20 +538,22 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
} else if (data->pseudonym) {
identity = data->pseudonym;
identity_len = data->pseudonym_len;
- } else {
- identity = config->identity;
- identity_len = config->identity_len;
- }
+ } else
+ identity = eap_get_config_identity(sm, &identity_len);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Selected identity for MK "
"derivation", identity, identity_len);
- eap_sim_derive_mk(data, identity, identity_len);
- eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
+ eap_sim_derive_mk(identity, identity_len, data->nonce_mt,
+ data->selected_version, data->ver_list,
+ data->ver_list_len, data->num_chal,
+ (const u8 *) data->kc, data->mk);
+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+ data->emsk);
if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
attr->mac, data->nonce_mt,
EAP_SIM_NONCE_MT_LEN)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
"used invalid AT_MAC");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
@@ -617,11 +570,11 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
&eattr, 0);
if (decrypted == NULL) {
return eap_sim_client_error(
- sm, data, req, respDataLen,
+ data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
eap_sim_learn_ids(data, &eattr);
- free(decrypted);
+ os_free(decrypted);
}
if (data->state != FAILURE)
@@ -629,17 +582,15 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
data->num_id_req = 0;
data->num_notification = 0;
- /* draft-haverinen-pppext-eap-sim-13.txt specifies that counter
- * is initialized to one after fullauth, but initializing it to
- * zero makes it easier to implement reauth verification. */
+ /* RFC 4186 specifies that counter is initialized to one after
+ * fullauth, but initializing it to zero makes it easier to implement
+ * reauth verification. */
data->counter = 0;
- return eap_sim_response_challenge(sm, data, req, respDataLen);
+ return eap_sim_response_challenge(data, req, respDataLen);
}
static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
- const struct eap_hdr *req,
- size_t reqDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
@@ -660,15 +611,15 @@ static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
return -1;
}
- if (eattr.counter != data->counter) {
+ if (eattr.counter < 0 || (size_t) eattr.counter != data->counter) {
wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
"message does not match with counter in reauth "
"message");
- free(decrypted);
+ os_free(decrypted);
return -1;
}
- free(decrypted);
+ os_free(decrypted);
return 0;
}
@@ -692,7 +643,7 @@ static int eap_sim_process_notification_auth(struct eap_sim_data *data,
}
if (data->reauth &&
- eap_sim_process_notification_reauth(data, req, reqDataLen, attr)) {
+ eap_sim_process_notification_reauth(data, attr)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Invalid notification "
"message after reauth");
return -1;
@@ -713,20 +664,20 @@ static u8 * eap_sim_process_notification(struct eap_sm *sm,
if (data->num_notification > 0) {
wpa_printf(MSG_INFO, "EAP-SIM: too many notification "
"rounds (only one allowed)");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
data->num_notification++;
if (attr->notification == -1) {
wpa_printf(MSG_INFO, "EAP-SIM: no AT_NOTIFICATION in "
"Notification message");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
if ((attr->notification & 0x4000) == 0 &&
eap_sim_process_notification_auth(data, req, reqDataLen, attr)) {
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
@@ -734,7 +685,7 @@ static u8 * eap_sim_process_notification(struct eap_sm *sm,
if (attr->notification >= 0 && attr->notification < 32768) {
data->state = FAILURE;
}
- return eap_sim_response_notification(sm, data, req, respDataLen,
+ return eap_sim_response_notification(data, req, respDataLen,
attr->notification);
}
@@ -754,7 +705,7 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
if (data->reauth_id == NULL) {
wpa_printf(MSG_WARNING, "EAP-SIM: Server is trying "
"reauthentication, but no reauth_id available");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
@@ -763,14 +714,14 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
"did not have valid AT_MAC");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
if (attr->encr_data == NULL || attr->iv == NULL) {
wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
"message did not include encrypted data");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
@@ -780,7 +731,7 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
if (decrypted == NULL) {
wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
"data from reauthentication message");
- return eap_sim_client_error(sm, data, req, respDataLen,
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
@@ -788,12 +739,12 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
wpa_printf(MSG_INFO, "EAP-SIM: (encr) No%s%s in reauth packet",
!eattr.nonce_s ? " AT_NONCE_S" : "",
eattr.counter < 0 ? " AT_COUNTER" : "");
- free(decrypted);
- return eap_sim_client_error(sm, data, req, respDataLen,
+ os_free(decrypted);
+ return eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
- if (eattr.counter <= data->counter) {
+ if (eattr.counter < 0 || (size_t) eattr.counter <= data->counter) {
wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid counter "
"(%d <= %d)", eattr.counter, data->counter);
data->counter_too_small = eattr.counter;
@@ -802,23 +753,24 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
* However, since it was used in the last EAP-Response-Identity
* packet, it has to saved for the following fullauth to be
* used in MK derivation. */
- free(data->last_eap_identity);
+ os_free(data->last_eap_identity);
data->last_eap_identity = data->reauth_id;
data->last_eap_identity_len = data->reauth_id_len;
data->reauth_id = NULL;
data->reauth_id_len = 0;
- free(decrypted);
- return eap_sim_response_reauth(sm, data, req, respDataLen, 1);
+ os_free(decrypted);
+ return eap_sim_response_reauth(data, req, respDataLen, 1);
}
data->counter = eattr.counter;
- memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
+ os_memcpy(data->nonce_s, eattr.nonce_s, EAP_SIM_NONCE_S_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-SIM: (encr) AT_NONCE_S",
data->nonce_s, EAP_SIM_NONCE_S_LEN);
eap_sim_derive_keys_reauth(data->counter,
data->reauth_id, data->reauth_id_len,
- data->nonce_s, data->mk, data->msk);
+ data->nonce_s, data->mk, data->msk,
+ data->emsk);
eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
eap_sim_learn_ids(data, &eattr);
@@ -832,8 +784,8 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
"fast reauths performed - force fullauth");
eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
}
- free(decrypted);
- return eap_sim_response_reauth(sm, data, req, respDataLen, 0);
+ os_free(decrypted);
+ return eap_sim_response_reauth(data, req, respDataLen, 0);
}
@@ -843,7 +795,6 @@ static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
size_t *respDataLen)
{
struct eap_sim_data *data = priv;
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *req;
u8 subtype, *res;
const u8 *pos;
@@ -851,14 +802,15 @@ static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
size_t len;
wpa_hexdump(MSG_DEBUG, "EAP-SIM: EAP data", reqData, reqDataLen);
- if (config == NULL || config->identity == NULL) {
+ if (eap_get_config_identity(sm, &len) == NULL) {
wpa_printf(MSG_INFO, "EAP-SIM: Identity not configured");
- eap_sm_request_identity(sm, config);
+ eap_sm_request_identity(sm);
ret->ignore = TRUE;
return NULL;
}
- pos = eap_hdr_validate(EAP_TYPE_SIM, reqData, reqDataLen, &len);
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_SIM,
+ reqData, reqDataLen, &len);
if (pos == NULL || len < 1) {
ret->ignore = TRUE;
return NULL;
@@ -876,14 +828,14 @@ static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
pos += 2; /* Reserved */
if (eap_sim_parse_attr(pos, reqData + len, &attr, 0, 0)) {
- res = eap_sim_client_error(sm, data, req, respDataLen,
+ res = eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
goto done;
}
switch (subtype) {
case EAP_SIM_SUBTYPE_START:
- res = eap_sim_process_start(sm, data, req, len,
+ res = eap_sim_process_start(sm, data, req,
respDataLen, &attr);
break;
case EAP_SIM_SUBTYPE_CHALLENGE:
@@ -900,12 +852,12 @@ static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
break;
case EAP_SIM_SUBTYPE_CLIENT_ERROR:
wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Client-Error");
- res = eap_sim_client_error(sm, data, req, respDataLen,
+ res = eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
break;
default:
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown subtype=%d", subtype);
- res = eap_sim_client_error(sm, data, req, respDataLen,
+ res = eap_sim_client_error(data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
break;
}
@@ -947,7 +899,7 @@ static void * eap_sim_init_for_reauth(struct eap_sm *sm, void *priv)
if (hostapd_get_rand(data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Failed to get random data "
"for NONCE_MT");
- free(data);
+ os_free(data);
return NULL;
}
data->num_id_req = 0;
@@ -991,28 +943,59 @@ static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = malloc(EAP_SIM_KEYING_DATA_LEN);
+ key = os_malloc(EAP_SIM_KEYING_DATA_LEN);
if (key == NULL)
return NULL;
*len = EAP_SIM_KEYING_DATA_LEN;
- memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+ os_memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
return key;
}
-const struct eap_method eap_method_sim =
+static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
- .method = EAP_TYPE_SIM,
- .name = "SIM",
- .init = eap_sim_init,
- .deinit = eap_sim_deinit,
- .process = eap_sim_process,
- .isKeyAvailable = eap_sim_isKeyAvailable,
- .getKey = eap_sim_getKey,
- .has_reauth_data = eap_sim_has_reauth_data,
- .deinit_for_reauth = eap_sim_deinit_for_reauth,
- .init_for_reauth = eap_sim_init_for_reauth,
- .get_identity = eap_sim_get_identity,
-};
+ struct eap_sim_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+
+ return key;
+}
+
+
+int eap_peer_sim_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_sim_init;
+ eap->deinit = eap_sim_deinit;
+ eap->process = eap_sim_process;
+ eap->isKeyAvailable = eap_sim_isKeyAvailable;
+ eap->getKey = eap_sim_getKey;
+ eap->has_reauth_data = eap_sim_has_reauth_data;
+ eap->deinit_for_reauth = eap_sim_deinit_for_reauth;
+ eap->init_for_reauth = eap_sim_init_for_reauth;
+ eap->get_identity = eap_sim_get_identity;
+ eap->get_emsk = eap_sim_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_sim_common.c b/contrib/wpa_supplicant/eap_sim_common.c
index 75947b7995a0..dc8b2f6f4b10 100644
--- a/contrib/wpa_supplicant/eap_sim_common.c
+++ b/contrib/wpa_supplicant/eap_sim_common.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-SIM/AKA shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer: EAP-SIM/AKA shared routines
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
@@ -24,80 +22,98 @@
#include "eap_sim_common.h"
-static void eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
+static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
{
- u8 xkey[64];
- u32 t[5], _t[5];
- int i, j, m, k;
- u8 *xpos = x;
- u32 carry;
-
- /* FIPS 186-2 + change notice 1 */
-
- memcpy(xkey, key, EAP_SIM_MK_LEN);
- memset(xkey + EAP_SIM_MK_LEN, 0, 64 - EAP_SIM_MK_LEN);
- t[0] = 0x67452301;
- t[1] = 0xEFCDAB89;
- t[2] = 0x98BADCFE;
- t[3] = 0x10325476;
- t[4] = 0xC3D2E1F0;
-
- m = xlen / 40;
- for (j = 0; j < m; j++) {
- /* XSEED_j = 0 */
- for (i = 0; i < 2; i++) {
- /* XVAL = (XKEY + XSEED_j) mod 2^b */
-
- /* w_i = G(t, XVAL) */
- memcpy(_t, t, 20);
- sha1_transform((u8 *) _t, xkey);
- _t[0] = host_to_be32(_t[0]);
- _t[1] = host_to_be32(_t[1]);
- _t[2] = host_to_be32(_t[2]);
- _t[3] = host_to_be32(_t[3]);
- _t[4] = host_to_be32(_t[4]);
- memcpy(xpos, _t, 20);
-
- /* XKEY = (1 + XKEY + w_i) mod 2^b */
- carry = 1;
- for (k = 19; k >= 0; k--) {
- carry += xkey[k] + xpos[k];
- xkey[k] = carry & 0xff;
- carry >>= 8;
- }
+ return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
+}
- xpos += SHA1_MAC_LEN;
- }
- /* x_j = w_0|w_1 */
- }
+
+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)
+{
+ u8 sel_ver[2];
+ const unsigned char *addr[5];
+ size_t len[5];
+
+ addr[0] = identity;
+ len[0] = identity_len;
+ addr[1] = kc;
+ len[1] = num_chal * EAP_SIM_KC_LEN;
+ addr[2] = nonce_mt;
+ len[2] = EAP_SIM_NONCE_MT_LEN;
+ addr[3] = ver_list;
+ len[3] = ver_list_len;
+ addr[4] = sel_ver;
+ len[4] = 2;
+
+ WPA_PUT_BE16(sel_ver, selected_version);
+
+ /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
+ sha1_vector(5, addr, len, mk);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
+}
+
+
+void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
+ const u8 *ik, const u8 *ck, u8 *mk)
+{
+ const u8 *addr[3];
+ size_t len[3];
+
+ addr[0] = identity;
+ len[0] = identity_len;
+ addr[1] = ik;
+ len[1] = EAP_AKA_IK_LEN;
+ addr[2] = ck;
+ len[2] = EAP_AKA_CK_LEN;
+
+ /* MK = SHA1(Identity|IK|CK) */
+ sha1_vector(3, addr, len, mk);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
}
-void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk)
+int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
{
- u8 buf[120], *pos;
- eap_sim_prf(mk, buf, 120);
+ u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
+ EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
+ if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
+ return -1;
+ }
pos = buf;
- memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
+ os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
pos += EAP_SIM_K_ENCR_LEN;
- memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
+ os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
pos += EAP_SIM_K_AUT_LEN;
- memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
+ os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
+ pos += EAP_SIM_KEYING_DATA_LEN;
+ os_memcpy(emsk, pos, EAP_EMSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
k_encr, EAP_SIM_K_ENCR_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
- k_aut, EAP_SIM_K_ENCR_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material",
+ k_aut, EAP_SIM_K_AUT_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
msk, EAP_SIM_KEYING_DATA_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
+ os_memset(buf, 0, sizeof(buf));
+
+ return 0;
}
-void eap_sim_derive_keys_reauth(u16 _counter,
- const u8 *identity, size_t identity_len,
- const u8 *nonce_s, const u8 *mk, u8 *msk)
+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)
{
u8 xkey[SHA1_MAC_LEN];
+ u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
u8 counter[2];
const u8 *addr[4];
size_t len[4];
@@ -125,9 +141,22 @@ void eap_sim_derive_keys_reauth(u16 _counter,
sha1_vector(4, addr, len, xkey);
wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
- eap_sim_prf(xkey, msk, EAP_SIM_KEYING_DATA_LEN);
- wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material",
- msk, EAP_SIM_KEYING_DATA_LEN);
+ if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
+ return -1;
+ }
+ if (msk) {
+ os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
+ msk, EAP_SIM_KEYING_DATA_LEN);
+ }
+ if (emsk) {
+ os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
+ }
+ os_memset(buf, 0, sizeof(buf));
+
+ return 0;
}
@@ -143,7 +172,7 @@ int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
mac > req + req_len - EAP_SIM_MAC_LEN)
return -1;
- tmp = malloc(req_len);
+ tmp = os_malloc(req_len);
if (tmp == NULL)
return -1;
@@ -153,12 +182,19 @@ int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
len[1] = extra_len;
/* HMAC-SHA1-128 */
- memcpy(tmp, req, req_len);
- memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
+ os_memcpy(tmp, req, req_len);
+ os_memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", tmp, req_len);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
+ extra, extra_len);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
+ k_aut, EAP_SIM_K_AUT_LEN);
hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
- free(tmp);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
+ hmac, EAP_SIM_MAC_LEN);
+ os_free(tmp);
- return (memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+ return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
}
@@ -175,9 +211,16 @@ void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
len[1] = extra_len;
/* HMAC-SHA1-128 */
- memset(mac, 0, EAP_SIM_MAC_LEN);
+ os_memset(mac, 0, EAP_SIM_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
+ extra, extra_len);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
+ k_aut, EAP_SIM_K_AUT_LEN);
hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
- memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+ os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
+ mac, EAP_SIM_MAC_LEN);
}
@@ -185,10 +228,9 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
struct eap_sim_attrs *attr, int aka, int encr)
{
const u8 *pos = start, *apos;
- size_t alen, plen;
- int list_len, i;
+ size_t alen, plen, i, list_len;
- memset(attr, 0, sizeof(*attr));
+ os_memset(attr, 0, sizeof(*attr));
attr->id_req = NO_ID_REQ;
attr->notification = -1;
attr->counter = -1;
@@ -219,7 +261,7 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
apos += 2;
alen -= 2;
if ((!aka && (alen % GSM_RAND_LEN)) ||
- (aka && alen != AKA_RAND_LEN)) {
+ (aka && alen != EAP_AKA_RAND_LEN)) {
wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
" (len %lu)",
(unsigned long) alen);
@@ -237,7 +279,7 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
}
apos += 2;
alen -= 2;
- if (alen != AKA_AUTN_LEN) {
+ if (alen != EAP_AKA_AUTN_LEN) {
wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
" (len %lu)",
(unsigned long) alen);
@@ -316,8 +358,9 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
if (list_len < 2 || list_len > alen - 2) {
wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
- "AT_VERSION_LIST (list_len=%d "
- "attr_len=%lu)", list_len,
+ "AT_VERSION_LIST (list_len=%lu "
+ "attr_len=%lu)",
+ (unsigned long) list_len,
(unsigned long) alen);
return -1;
}
@@ -356,6 +399,22 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
attr->counter);
break;
+ case EAP_SIM_AT_COUNTER_TOO_SMALL:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_COUNTER_TOO_SMALL");
+ return -1;
+ }
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+ "AT_COUNTER_TOO_SMALL (alen=%lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+ "AT_COUNTER_TOO_SMALL");
+ attr->counter_too_small = 1;
+ break;
case EAP_SIM_AT_NONCE_S:
if (!encr) {
wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
@@ -444,6 +503,35 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
attr->next_reauth_id = pos + 4;
attr->next_reauth_id_len = plen;
break;
+ case EAP_SIM_AT_RES:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
+ apos += 2;
+ alen -= 2;
+ if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
+ alen > EAP_AKA_MAX_RES_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
+ "(len %lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->res = apos;
+ attr->res_len = alen;
+ break;
+ case EAP_SIM_AT_AUTS:
+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
+ if (!aka) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: "
+ "Unexpected AT_AUTS");
+ return -1;
+ }
+ if (alen != EAP_AKA_AUTS_LEN) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
+ " (len %lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->auts = apos;
+ break;
default:
if (pos[0] < 128) {
wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
@@ -478,10 +566,10 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
return NULL;
}
- decrypted = malloc(encr_data_len);
+ decrypted = os_malloc(encr_data_len);
if (decrypted == NULL)
return NULL;
- memcpy(decrypted, encr_data, encr_data_len);
+ os_memcpy(decrypted, encr_data, encr_data_len);
aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len);
wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
@@ -491,7 +579,7 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
aka, 1)) {
wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
"decrypted AT_ENCR_DATA");
- free(decrypted);
+ os_free(decrypted);
return NULL;
}
@@ -514,17 +602,15 @@ struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
struct eap_hdr *eap;
u8 *pos;
- msg = malloc(sizeof(*msg));
+ msg = os_zalloc(sizeof(*msg));
if (msg == NULL)
return NULL;
- memset(msg, 0, sizeof(*msg));
- msg->buf = malloc(EAP_SIM_INIT_LEN);
+ msg->buf = os_zalloc(EAP_SIM_INIT_LEN);
if (msg->buf == NULL) {
- free(msg);
+ os_free(msg);
return NULL;
}
- memset(msg->buf, 0, EAP_SIM_INIT_LEN);
msg->buf_len = EAP_SIM_INIT_LEN;
eap = (struct eap_hdr *) msg->buf;
eap->code = code;
@@ -561,7 +647,7 @@ u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
*len = msg->used;
buf = msg->buf;
- free(msg);
+ os_free(msg);
return buf;
}
@@ -569,8 +655,8 @@ u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
void eap_sim_msg_free(struct eap_sim_msg *msg)
{
if (msg) {
- free(msg->buf);
- free(msg);
+ os_free(msg->buf);
+ os_free(msg);
}
}
@@ -578,7 +664,7 @@ void eap_sim_msg_free(struct eap_sim_msg *msg)
static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
{
if (msg->used + add_len > msg->buf_len) {
- u8 *nbuf = realloc(msg->buf, msg->used + add_len);
+ u8 *nbuf = os_realloc(msg->buf, msg->used + add_len);
if (nbuf == NULL)
return -1;
msg->buf = nbuf;
@@ -605,10 +691,10 @@ u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
start = pos = msg->buf + msg->used;
*pos++ = attr;
*pos++ = attr_len / 4;
- memcpy(pos, data, len);
+ os_memcpy(pos, data, len);
if (pad_len) {
pos += len;
- memset(pos, 0, pad_len);
+ os_memset(pos, 0, pad_len);
}
msg->used += attr_len;
return start;
@@ -635,10 +721,10 @@ u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
WPA_PUT_BE16(pos, value);
pos += 2;
if (data)
- memcpy(pos, data, len);
+ os_memcpy(pos, data, len);
if (pad_len) {
pos += len;
- memset(pos, 0, pad_len);
+ os_memset(pos, 0, pad_len);
}
msg->used += attr_len;
return start;
@@ -681,7 +767,7 @@ int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
{
size_t encr_len;
- if (k_encr == NULL || msg->iv == 0 || msg->encr == 0)
+ if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
return -1;
encr_len = msg->used - msg->encr - 4;
@@ -698,7 +784,7 @@ int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
if (pos == NULL)
return -1;
- memset(pos + 4, 0, pad_len - 4);
+ os_memset(pos + 4, 0, pad_len - 4);
encr_len += pad_len;
}
wpa_printf(MSG_DEBUG, " (AT_ENCR_DATA data len %lu)",
@@ -752,43 +838,3 @@ void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
}
}
}
-
-
-#ifdef TEST_MAIN_EAP_SIM_COMMON
-static int test_eap_sim_prf(void)
-{
- /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
- u8 xkey[] = {
- 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
- 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
- 0xeb, 0x5a, 0x38, 0xb6
- };
- u8 w[] = {
- 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
- 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
- 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
- 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
- 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
- };
- u8 buf[40];
-
- printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
- eap_sim_prf(xkey, buf, sizeof(buf));
- if (memcmp(w, buf, sizeof(w) != 0)) {
- printf("eap_sim_prf failed\n");
- return 1;
- }
-
- return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
- int errors = 0;
-
- errors += test_eap_sim_prf();
-
- return errors;
-}
-#endif /* TEST_MAIN_EAP_SIM_COMMON */
diff --git a/contrib/wpa_supplicant/eap_sim_common.h b/contrib/wpa_supplicant/eap_sim_common.h
index 6715c369c0b6..9c983a864e3e 100644
--- a/contrib/wpa_supplicant/eap_sim_common.h
+++ b/contrib/wpa_supplicant/eap_sim_common.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-SIM/AKA shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer: EAP-SIM/AKA shared routines
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,16 +23,65 @@
#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 AKA_RAND_LEN 16
-#define AKA_AUTN_LEN 16
-
-void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk);
-void eap_sim_derive_keys_reauth(u16 _counter,
- const u8 *identity, size_t identity_len,
- const u8 *nonce_s, const u8 *mk, u8 *msk);
+#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
+
+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 u8 *req, size_t req_len,
const u8 *mac, const u8 *extra, size_t extra_len);
void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
@@ -42,8 +91,8 @@ void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
/* 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 send */
-#define EAP_SIM_AT_AUTS 4 /* only AKA, only send */
+#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
@@ -81,11 +130,12 @@ enum eap_sim_id_req {
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;
+ const u8 *nonce_mt, *identity, *res, *auts;
size_t num_chal, version_list_len, encr_data_len;
- size_t next_pseudonym_len, next_reauth_id_len, identity_len;
+ size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len;
enum eap_sim_id_req id_req;
int notification, counter, selected_version, client_error_code;
+ int counter_too_small;
};
int eap_sim_parse_attr(const u8 *start, const u8 *end,
diff --git a/contrib/wpa_supplicant/eap_testing.txt b/contrib/wpa_supplicant/eap_testing.txt
index a4d1e0a6a009..18c5c3f936b2 100644
--- a/contrib/wpa_supplicant/eap_testing.txt
+++ b/contrib/wpa_supplicant/eap_testing.txt
@@ -25,7 +25,7 @@ certificates, and private keys for testing use. Other alternative
would be to get an evaluation version of the server so that I can
install it on my own test setup. If you are interested in providing
either server access or evaluation version, please contact me
-(jkmaline@cc.hut.fi).
+(j@w1.fi).
Test matrix
@@ -38,7 +38,7 @@ F) failed
Cisco ACS ----------------------------------------------------------.
hostapd --------------------------------------------------------. |
Cisco Aironet 1200 AP (local RADIUS server) ----------------. | |
-Corriente Elektron -------------------------------------. | | |
+Periodik Labs Elektron ---------------------------------. | | |
Lucent NavisRadius ---------------------------------. | | | |
Interlink RAD-Series ---------------------------. | | | | |
Radiator -----------------------------------. | | | | | |
@@ -60,7 +60,7 @@ EAP-PEAPv0/OTP - - - - - + - - - - - -
EAP-PEAPv0/MD5 + - - + + + + + - - + -
EAP-PEAPv0/TLS - + - + + + F + - - - -
EAP-PEAPv1/MSCHAPv2 - - + + + +1 + +5 +8 - + +
-EAP-PEAPv1/GTC - - + + + +1 + +5 - - + +
+EAP-PEAPv1/GTC - - + + + +1 + +5 +8 - + +
EAP-PEAPv1/OTP - - - - - +1 - - - - - -
EAP-PEAPv1/MD5 - - - + + +1 + +5 - - + -
EAP-PEAPv1/TLS - - - + + +1 F +5 - - - -
@@ -68,16 +68,18 @@ EAP-TTLS/CHAP + - +2 + + + + + + - + -
EAP-TTLS/MSCHAP + - + + + + + + + - + -
EAP-TTLS/MSCHAPv2 + - + + + + + + + - + -
EAP-TTLS/PAP + - + + + + + + + - + -
-EAP-TTLS/EAP-MD5 + - +2 + + + + + - - + -
+EAP-TTLS/EAP-MD5 + - +2 + + + + + + - + -
EAP-TTLS/EAP-GTC + - +2 ? + + + + - - + -
EAP-TTLS/EAP-OTP - - - - - + - - - - - -
EAP-TTLS/EAP-MSCHAPv2 + - +2 + + + + + + - + -
EAP-TTLS/EAP-TLS - - +2 + F + + + - - - -
EAP-SIM +3 - - ? - + - ? - - + -
-EAP-AKA - - - - - + - - - - - -
+EAP-AKA - - - - - + - - - - + -
EAP-PSK +7 - - - - - - - - - + -
EAP-PAX - - - - - - - - - - + -
-EAP-FAST - - - - - - - - - + - +
+EAP-SAKE - - - - - - - - - - + -
+EAP-GPSK - - - - - - - - - - + -
+EAP-FAST - - - + - - - - - + - +
LEAP + - + + + + F +6 - + - +
1) PEAPv1 required new label, "client PEAP encryption" instead of "client EAP
diff --git a/contrib/wpa_supplicant/eap_tls.c b/contrib/wpa_supplicant/eap_tls.c
index d1452dfe3370..03fcd89aed56 100644
--- a/contrib/wpa_supplicant/eap_tls.c
+++ b/contrib/wpa_supplicant/eap_tls.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-TLS (RFC 2716)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-TLS (RFC 2716)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,14 +12,11 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
#include "eap_tls_common.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "tls.h"
@@ -44,10 +41,9 @@ static void * eap_tls_init(struct eap_sm *sm)
return NULL;
}
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
if (eap_tls_ssl_init(sm, &data->ssl, config)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
@@ -55,13 +51,13 @@ static void * eap_tls_init(struct eap_sm *sm)
if (config->engine) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
"PIN");
- eap_sm_request_pin(sm, config);
+ eap_sm_request_pin(sm);
sm->ignore = TRUE;
} else if (config->private_key && !config->private_key_passwd)
{
wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
"key passphrase");
- eap_sm_request_passphrase(sm, config);
+ eap_sm_request_passphrase(sm);
sm->ignore = TRUE;
}
return NULL;
@@ -77,8 +73,67 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
if (data == NULL)
return;
eap_tls_ssl_deinit(sm, &data->ssl);
- free(data->key_data);
- free(data);
+ os_free(data->key_data);
+ os_free(data);
+}
+
+
+static u8 * eap_tls_failure(struct eap_sm *sm, struct eap_tls_data *data,
+ struct eap_method_ret *ret, int res, u8 *resp,
+ u8 id, size_t *respDataLen)
+{
+ wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
+
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+
+ if (res == -1) {
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config) {
+ /*
+ * The TLS handshake failed. So better forget the old
+ * PIN. It may be wrong, we cannot be sure but trying
+ * the wrong one again might block it on the card--so
+ * better ask the user again.
+ */
+ os_free(config->pin);
+ config->pin = NULL;
+ }
+ }
+
+ if (resp) {
+ /*
+ * This is likely an alert message, so send it instead of just
+ * ACKing the error.
+ */
+ return resp;
+ }
+
+ return eap_tls_build_ack(&data->ssl, respDataLen, id, EAP_TYPE_TLS, 0);
+}
+
+
+static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
+ struct eap_method_ret *ret)
+{
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
+
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+
+ os_free(data->key_data);
+ data->key_data = eap_tls_derive_key(sm, &data->ssl,
+ "client EAP encryption",
+ EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+ if (data->key_data) {
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
+ data->key_data, EAP_TLS_KEY_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK",
+ data->key_data + EAP_TLS_KEY_LEN,
+ EAP_EMSK_LEN);
+ } else {
+ wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
+ }
}
@@ -87,7 +142,6 @@ static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct wpa_ssid *config = eap_get_config(sm);
const struct eap_hdr *req;
size_t left;
int res;
@@ -113,48 +167,18 @@ static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
left, &resp, respDataLen);
if (res < 0) {
- wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
- ret->methodState = METHOD_MAY_CONT;
- ret->decision = DECISION_FAIL;
- if (resp) {
- /* This is likely an alert message, so send it instead
- * of just ACKing the error. */
- return resp;
- }
- return eap_tls_build_ack(&data->ssl, respDataLen, id,
- EAP_TYPE_TLS, 0);
+ return eap_tls_failure(sm, data, ret, res, resp, id,
+ respDataLen);
}
- if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
- wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_UNCOND_SUCC;
- free(data->key_data);
- data->key_data = eap_tls_derive_key(sm, &data->ssl,
- "client EAP encryption",
- EAP_TLS_KEY_LEN);
- if (data->key_data) {
- wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
- data->key_data, EAP_TLS_KEY_LEN);
- } else {
- wpa_printf(MSG_DEBUG, "EAP-TLS: Failed to derive key");
- }
- }
+ if (tls_connection_established(sm->ssl_ctx, data->ssl.conn))
+ eap_tls_success(sm, data, ret);
if (res == 1) {
return eap_tls_build_ack(&data->ssl, respDataLen, id,
EAP_TYPE_TLS, 0);
}
- if (res == -1) {
- /* The TLS handshake failed. So better forget the old PIN.
- * It may be wrong, we can't be sure but trying the wrong one
- * again might block it on the card - so better ask the user
- * again */
- free(config->pin);
- config->pin = NULL;
- }
-
return resp;
}
@@ -174,10 +198,10 @@ static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_tls_data *data = priv;
- free(data->key_data);
+ os_free(data->key_data);
data->key_data = NULL;
if (eap_tls_reauth_init(sm, &data->ssl)) {
- free(data);
+ os_free(data);
return NULL;
}
return priv;
@@ -207,28 +231,59 @@ static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->key_data == NULL)
return NULL;
- key = malloc(EAP_TLS_KEY_LEN);
+ key = os_malloc(EAP_TLS_KEY_LEN);
if (key == NULL)
return NULL;
*len = EAP_TLS_KEY_LEN;
- memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+ os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
return key;
}
-const struct eap_method eap_method_tls =
+static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
{
- .method = EAP_TYPE_TLS,
- .name = "TLS",
- .init = eap_tls_init,
- .deinit = eap_tls_deinit,
- .process = eap_tls_process,
- .isKeyAvailable = eap_tls_isKeyAvailable,
- .getKey = eap_tls_getKey,
- .get_status = eap_tls_get_status,
- .has_reauth_data = eap_tls_has_reauth_data,
- .deinit_for_reauth = eap_tls_deinit_for_reauth,
- .init_for_reauth = eap_tls_init_for_reauth,
-};
+ struct eap_tls_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_tls_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_tls_init;
+ eap->deinit = eap_tls_deinit;
+ eap->process = eap_tls_process;
+ eap->isKeyAvailable = eap_tls_isKeyAvailable;
+ eap->getKey = eap_tls_getKey;
+ eap->get_status = eap_tls_get_status;
+ eap->has_reauth_data = eap_tls_has_reauth_data;
+ eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
+ eap->init_for_reauth = eap_tls_init_for_reauth;
+ eap->get_emsk = eap_tls_get_emsk;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_tls_common.c b/contrib/wpa_supplicant/eap_tls_common.c
index cb3fb28d13ed..95ae0622d4eb 100644
--- a/contrib/wpa_supplicant/eap_tls_common.c
+++ b/contrib/wpa_supplicant/eap_tls_common.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,14 +12,11 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
#include "eap_tls_common.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "md5.h"
#include "sha1.h"
@@ -32,7 +29,7 @@ static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
{
const struct wpa_config_blob *blob;
- if (*name == NULL || strncmp(*name, "blob://", 7) != 0)
+ if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)
return 0;
blob = eap_get_config_blob(sm, *name + 7);
@@ -50,87 +47,138 @@ static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
}
-int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
- struct wpa_ssid *config)
+static void eap_tls_params_from_conf1(struct tls_connection_params *params,
+ struct wpa_ssid *config)
{
- int ret = -1, res;
- struct tls_connection_params params;
+ 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->engine_id = config->engine_id;
+ params->pin = config->pin;
+ params->key_id = config->key_id;
+}
- data->eap = sm;
- data->phase2 = sm->init_phase2;
- memset(&params, 0, sizeof(params));
- params.engine = config->engine;
- if (config == NULL) {
- } else if (data->phase2) {
- 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;
- } else {
- 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.engine_id = config->engine_id;
- params.pin = config->pin;
- params.key_id = config->key_id;
- }
- if (eap_tls_check_blob(sm, &params.ca_cert, &params.ca_cert_blob,
- &params.ca_cert_blob_len) ||
- eap_tls_check_blob(sm, &params.client_cert,
- &params.client_cert_blob,
- &params.client_cert_blob_len) ||
- eap_tls_check_blob(sm, &params.private_key,
- &params.private_key_blob,
- &params.private_key_blob_len) ||
- eap_tls_check_blob(sm, &params.dh_file, &params.dh_blob,
- &params.dh_blob_len)) {
+static void eap_tls_params_from_conf2(struct tls_connection_params *params,
+ struct wpa_ssid *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;
+}
+
+
+static int eap_tls_params_from_conf(struct eap_sm *sm,
+ struct eap_ssl_data *data,
+ struct tls_connection_params *params,
+ struct wpa_ssid *config, int phase2)
+{
+ os_memset(params, 0, sizeof(*params));
+ params->engine = config->engine;
+ if (phase2)
+ eap_tls_params_from_conf2(params, config);
+ else
+ eap_tls_params_from_conf1(params, config);
+ params->tls_ia = data->tls_ia;
+
+
+ if (eap_tls_check_blob(sm, &params->ca_cert, &params->ca_cert_blob,
+ &params->ca_cert_blob_len) ||
+ eap_tls_check_blob(sm, &params->client_cert,
+ &params->client_cert_blob,
+ &params->client_cert_blob_len) ||
+ eap_tls_check_blob(sm, &params->private_key,
+ &params->private_key_blob,
+ &params->private_key_blob_len) ||
+ eap_tls_check_blob(sm, &params->dh_file, &params->dh_blob,
+ &params->dh_blob_len)) {
wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
- goto done;
+ return -1;
}
+ return 0;
+}
+
+
+static int eap_tls_init_connection(struct eap_sm *sm,
+ struct eap_ssl_data *data,
+ struct wpa_ssid *config,
+ struct tls_connection_params *params)
+{
+ int res;
+
data->conn = tls_connection_init(sm->ssl_ctx);
if (data->conn == NULL) {
wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
"connection");
- goto done;
+ return -1;
}
- res = tls_connection_set_params(sm->ssl_ctx, data->conn, &params);
+ res = tls_connection_set_params(sm->ssl_ctx, data->conn, params);
if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
/* 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 */
- free(config->pin);
+ os_free(config->pin);
config->pin = NULL;
} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
- wpa_printf(MSG_INFO,"TLS: Failed to load private key");
+ wpa_printf(MSG_INFO, "TLS: Failed to load private key");
/* We don't know exactly but maybe the PIN was wrong,
* so ask for a new one. */
- free(config->pin);
+ os_free(config->pin);
config->pin = NULL;
- eap_sm_request_pin(sm, config);
+ eap_sm_request_pin(sm);
sm->ignore = TRUE;
- goto done;
+ return -1;
} else if (res) {
wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
"parameters");
- goto done;
+ return -1;
}
- /* TODO: make this configurable */
- data->tls_out_limit = 1398;
+ return 0;
+}
+
+
+/**
+ * eap_tls_ssl_init - Initialize shared TLS functionality
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @data: Data for TLS processing
+ * @config: Pointer to the network configuration
+ * 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_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+ struct wpa_ssid *config)
+{
+ int ret = -1;
+ struct tls_connection_params params;
+
+ if (config == NULL)
+ return -1;
+
+ data->eap = sm;
+ data->phase2 = sm->init_phase2;
+ if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
+ 0)
+ goto done;
+
+ if (eap_tls_init_connection(sm, data, config, &params) < 0)
+ goto done;
+
+ 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
@@ -139,8 +187,8 @@ int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
data->tls_out_limit -= 100;
}
- if (config && config->phase1 &&
- strstr(config->phase1, "include_tls_length=1")) {
+ 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;
@@ -153,58 +201,82 @@ done:
}
+/**
+ * eap_tls_ssl_deinit - Deinitialize shared TLS functionality
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @data: Data for TLS processing
+ *
+ * This function deinitializes shared TLS functionality that was initialized
+ * with eap_tls_ssl_init().
+ */
void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
{
tls_connection_deinit(sm->ssl_ctx, data->conn);
- free(data->tls_in);
- free(data->tls_out);
+ os_free(data->tls_in);
+ os_free(data->tls_out);
}
+/**
+ * eap_tls_derive_key - Derive a key based on TLS session data
+ * @sm: Pointer to EAP state machine allocated with eap_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_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- char *label, size_t len)
+ const char *label, size_t len)
{
struct tls_keys keys;
- u8 *rnd;
- u8 *out;
+ u8 *rnd = NULL, *out;
- if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+ out = os_malloc(len);
+ if (out == NULL)
return NULL;
- if (keys.eap_tls_prf && strcmp(label, "client EAP encryption") == 0) {
- if (len > keys.eap_tls_prf_len)
- return NULL;
- out = malloc(len);
- if (out == NULL)
- return NULL;
- memcpy(out, keys.eap_tls_prf, len);
+ /* First, try to use TLS library function for PRF, if available. */
+ if (tls_connection_prf(sm->ssl_ctx, data->conn, label, 0, out, len) ==
+ 0)
return out;
- }
+
+ /*
+ * 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)
- return NULL;
+ goto fail;
- out = malloc(len);
- rnd = malloc(keys.client_random_len + keys.server_random_len);
- if (out == NULL || rnd == NULL) {
- free(out);
- free(rnd);
- return NULL;
- }
- memcpy(rnd, keys.client_random, keys.client_random_len);
- memcpy(rnd + keys.client_random_len, keys.server_random,
- keys.server_random_len);
+ rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+ if (rnd == NULL)
+ goto fail;
+ os_memcpy(rnd, keys.client_random, keys.client_random_len);
+ os_memcpy(rnd + keys.client_random_len, keys.server_random,
+ keys.server_random_len);
if (tls_prf(keys.master_key, keys.master_key_len,
label, rnd, keys.client_random_len +
- keys.server_random_len, out, len)) {
- free(rnd);
- free(out);
- return NULL;
- }
- free(rnd);
+ keys.server_random_len, out, len))
+ goto fail;
+
+ os_free(rnd);
return out;
+
+fail:
+ os_free(out);
+ os_free(rnd);
+ return NULL;
}
@@ -217,9 +289,11 @@ u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
* @out_len: Variable for returning output data length
* @need_more_input: Variable for returning whether more input data is needed
* to reassemble this TLS packet
- * Returns: Pointer to output data or %NULL on error
+ * 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.
+ * This function reassembles TLS fragments. Caller must not free the returned
+ * data buffer since an internal pointer to it is maintained.
*/
const u8 * eap_tls_data_reassemble(
struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data,
@@ -231,7 +305,7 @@ const u8 * eap_tls_data_reassemble(
if (data->tls_in_left > in_len || data->tls_in) {
if (data->tls_in_len + in_len == 0) {
- free(data->tls_in);
+ os_free(data->tls_in);
data->tls_in = NULL;
data->tls_in_len = 0;
wpa_printf(MSG_WARNING, "SSL: Invalid reassembly "
@@ -242,16 +316,26 @@ const u8 * eap_tls_data_reassemble(
(unsigned long) in_len);
return NULL;
}
- buf = realloc(data->tls_in, data->tls_in_len + in_len);
+ if (data->tls_in_len + in_len > 65536) {
+ /* Limit length to avoid rogue servers from causing
+ * large memory allocations. */
+ os_free(data->tls_in);
+ data->tls_in = NULL;
+ data->tls_in_len = 0;
+ wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size"
+ " over 64 kB)");
+ return NULL;
+ }
+ buf = os_realloc(data->tls_in, data->tls_in_len + in_len);
if (buf == NULL) {
- free(data->tls_in);
+ os_free(data->tls_in);
data->tls_in = NULL;
data->tls_in_len = 0;
wpa_printf(MSG_INFO, "SSL: Could not allocate memory "
"for TLS data");
return NULL;
}
- memcpy(buf + data->tls_in_len, in_data, in_len);
+ os_memcpy(buf + data->tls_in_len, in_data, in_len);
data->tls_in = buf;
data->tls_in_len += in_len;
if (in_len > data->tls_in_left) {
@@ -269,10 +353,10 @@ const u8 * eap_tls_data_reassemble(
}
} else {
data->tls_in_left = 0;
- data->tls_in = malloc(in_len);
+ data->tls_in = os_malloc(in_len ? in_len : 1);
if (data->tls_in == NULL)
return NULL;
- memcpy(data->tls_in, in_data, in_len);
+ os_memcpy(data->tls_in, in_data, in_len);
data->tls_in_len = in_len;
}
@@ -281,56 +365,161 @@ const u8 * eap_tls_data_reassemble(
}
+static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
+ const u8 *in_data, size_t in_len,
+ u8 **out_data, size_t *out_len)
+{
+ const u8 *msg;
+ size_t msg_len;
+ int need_more_input;
+ u8 *appl_data;
+ size_t appl_data_len;
+
+ msg = eap_tls_data_reassemble(sm, data, in_data, in_len,
+ &msg_len, &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_helper - pending "
+ "tls_out data even though tls_out_len = 0");
+ os_free(data->tls_out);
+ WPA_ASSERT(data->tls_out == NULL);
+ }
+ appl_data = NULL;
+ data->tls_out = tls_connection_handshake(sm->ssl_ctx, data->conn,
+ msg, msg_len,
+ &data->tls_out_len,
+ &appl_data, &appl_data_len);
+
+ /* Clear reassembled input data (if the buffer was needed). */
+ data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
+ os_free(data->tls_in);
+ data->tls_in = NULL;
+
+ if (appl_data &&
+ tls_connection_established(sm->ssl_ctx, data->conn) &&
+ !tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
+ wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application data",
+ appl_data, appl_data_len);
+ *out_data = appl_data;
+ *out_len = appl_data_len;
+ return 2;
+ }
+
+ os_free(appl_data);
+
+ return 0;
+}
+
+
+static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
+ int peap_version, u8 id, int ret,
+ u8 **out_data, size_t *out_len)
+{
+ size_t len;
+ u8 *pos, *flags;
+ int more_fragments, length_included;
+
+ wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
+ "%lu bytes)",
+ (unsigned long) data->tls_out_len - data->tls_out_pos,
+ (unsigned long) data->tls_out_len);
+
+ len = data->tls_out_len - data->tls_out_pos;
+ 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 &&
+ (data->tls_out_len > data->tls_out_limit ||
+ data->include_tls_length);
+
+ *out_data = (u8 *)
+ eap_msg_alloc(EAP_VENDOR_IETF, eap_type, out_len,
+ 1 + length_included * 4 + len, EAP_CODE_RESPONSE,
+ id, &pos);
+ if (*out_data == NULL)
+ return -1;
+
+ flags = pos++;
+ *flags = peap_version;
+ if (more_fragments)
+ *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
+ if (length_included) {
+ *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
+ WPA_PUT_BE32(pos, data->tls_out_len);
+ pos += 4;
+ }
+
+ os_memcpy(pos, &data->tls_out[data->tls_out_pos], len);
+ data->tls_out_pos += len;
+
+ if (!more_fragments) {
+ data->tls_out_len = 0;
+ data->tls_out_pos = 0;
+ os_free(data->tls_out);
+ data->tls_out = NULL;
+ }
+
+ return ret;
+}
+
+
+/**
+ * eap_tls_process_helper - Process TLS handshake message
+ * @sm: Pointer to EAP state machine allocated with eap_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
+ * @out_len: Buffer for returning the length of the response message
+ * Returns: 0 on success, 1 if more input data is needed, 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 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.
+ */
int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- int eap_type, int peap_version,
+ EapType eap_type, int peap_version,
u8 id, const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len)
{
- size_t len;
- u8 *pos, *flags;
- struct eap_hdr *resp;
int ret = 0;
WPA_ASSERT(data->tls_out_len == 0 || in_len == 0);
*out_len = 0;
+ *out_data = NULL;
if (data->tls_out_len == 0) {
/* No more data to send out - expect to receive more data from
* the AS. */
- const u8 *msg;
- size_t msg_len;
- int need_more_input;
-
- msg = eap_tls_data_reassemble(sm, data, in_data, in_len,
- &msg_len, &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_helper - "
- "pending tls_out data even though "
- "tls_out_len = 0");
- free(data->tls_out);
- WPA_ASSERT(data->tls_out == NULL);
- }
- data->tls_out = tls_connection_handshake(sm->ssl_ctx,
- data->conn,
- msg, msg_len,
- &data->tls_out_len);
-
- /* Clear reassembled input data (if the buffer was needed). */
- data->tls_in_left = data->tls_in_total = data->tls_in_len = 0;
- free(data->tls_in);
- data->tls_in = NULL;
+ int res = eap_tls_process_input(sm, data, in_data, in_len,
+ out_data, out_len);
+ if (res)
+ return res;
}
if (data->tls_out == NULL) {
data->tls_out_len = 0;
return -1;
}
+
if (tls_connection_get_failed(sm->ssl_ctx, data->conn)) {
wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
"report error");
@@ -340,90 +529,56 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
if (data->tls_out_len == 0) {
/* TLS negotiation should now be complete since all other cases
- * needing more that should have been catched above based on
+ * 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");
- free(data->tls_out);
+ os_free(data->tls_out);
data->tls_out = NULL;
return 1;
}
- wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
- "%lu bytes)",
- (unsigned long) data->tls_out_len - data->tls_out_pos,
- (unsigned long) data->tls_out_len);
- resp = malloc(sizeof(struct eap_hdr) + 2 + 4 + data->tls_out_limit);
- if (resp == NULL) {
- *out_data = NULL;
- return -1;
- }
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = id;
- pos = (u8 *) (resp + 1);
- *pos++ = eap_type;
- flags = pos++;
- *flags = peap_version;
- if (data->tls_out_pos == 0 &&
- (data->tls_out_len > data->tls_out_limit ||
- data->include_tls_length)) {
- *flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
- *pos++ = (data->tls_out_len >> 24) & 0xff;
- *pos++ = (data->tls_out_len >> 16) & 0xff;
- *pos++ = (data->tls_out_len >> 8) & 0xff;
- *pos++ = data->tls_out_len & 0xff;
- }
-
- len = data->tls_out_len - data->tls_out_pos;
- if (len > data->tls_out_limit) {
- *flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
- len = data->tls_out_limit;
- wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
- "will follow", (unsigned long) len);
- }
- memcpy(pos, &data->tls_out[data->tls_out_pos], len);
- data->tls_out_pos += len;
- *out_len = (pos - (u8 *) resp) + len;
- resp->length = host_to_be16(*out_len);
- *out_data = (u8 *) resp;
-
- if (!(*flags & EAP_TLS_FLAGS_MORE_FRAGMENTS)) {
- data->tls_out_len = 0;
- data->tls_out_pos = 0;
- free(data->tls_out);
- data->tls_out = NULL;
- }
-
- return ret;
+ return eap_tls_process_output(data, eap_type, peap_version, id, ret,
+ out_data, out_len);
}
+/**
+ * eap_tls_build_ack - Build a TLS ACK frames
+ * @data: Data for TLS processing
+ * @respDataLen: Buffer for returning the length of the response message
+ * @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 allocated ACK frames or %NULL on failure
+ */
u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
- int eap_type, int peap_version)
+ EapType eap_type, int peap_version)
{
struct eap_hdr *resp;
u8 *pos;
- *respDataLen = sizeof(struct eap_hdr) + 2;
- resp = malloc(*respDataLen);
+ resp = eap_msg_alloc(EAP_VENDOR_IETF, eap_type, respDataLen,
+ 1, EAP_CODE_RESPONSE, id, &pos);
if (resp == NULL)
return NULL;
wpa_printf(MSG_DEBUG, "SSL: Building ACK");
- resp->code = EAP_CODE_RESPONSE;
- resp->identifier = id;
- resp->length = host_to_be16(*respDataLen);
- pos = (u8 *) (resp + 1);
- *pos++ = eap_type; /* Type */
*pos = peap_version; /* Flags */
return (u8 *) resp;
}
+/**
+ * eap_tls_reauth_init - Re-initialize shared TLS for session resumption
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @data: Data for TLS processing
+ * Returns: 0 on success, -1 on failure
+ */
int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
{
- free(data->tls_in);
+ os_free(data->tls_in);
data->tls_in = NULL;
data->tls_in_len = data->tls_in_left = data->tls_in_total = 0;
- free(data->tls_out);
+ os_free(data->tls_out);
data->tls_out = NULL;
data->tls_out_len = data->tls_out_pos = 0;
@@ -431,27 +586,50 @@ int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
}
+/**
+ * eap_tls_status - Get TLS status
+ * @sm: Pointer to EAP state machine allocated with eap_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_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
size_t buflen, int verbose)
{
char name[128];
- int len = 0;
+ int len = 0, ret;
if (tls_get_cipher(sm->ssl_ctx, data->conn, name, sizeof(name)) == 0) {
- len += snprintf(buf + len, buflen - len,
- "EAP TLS cipher=%s\n", name);
+ 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;
}
return len;
}
+/**
+ * eap_tls_process_init - Initial validation and processing of EAP requests
+ * @sm: Pointer to EAP state machine allocated with eap_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)
+ * @reqDataLen: Length of the EAP request
+ * @len: Buffer for returning length of the remaining payload
+ * @flags: Buffer for returning TLS flags
+ * Returns: Buffer to payload after TLS flags and length or %NULL on failure
+ */
const u8 * eap_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data,
EapType eap_type, struct eap_method_ret *ret,
const u8 *reqData, size_t reqDataLen,
size_t *len, u8 *flags)
{
- const struct eap_hdr *req;
const u8 *pos;
size_t left;
unsigned int tls_msg_len;
@@ -462,12 +640,12 @@ const u8 * eap_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data,
return NULL;
}
- pos = eap_hdr_validate(eap_type, reqData, reqDataLen, &left);
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData, reqDataLen,
+ &left);
if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
- req = (const struct eap_hdr *) reqData;
*flags = *pos++;
left--;
wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
@@ -479,14 +657,13 @@ const u8 * eap_tls_process_init(struct eap_sm *sm, struct eap_ssl_data *data,
ret->ignore = TRUE;
return NULL;
}
- tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
- pos[3];
+ 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;
- free(data->tls_in);
+ os_free(data->tls_in);
data->tls_in = NULL;
data->tls_in_len = 0;
}
diff --git a/contrib/wpa_supplicant/eap_tls_common.h b/contrib/wpa_supplicant/eap_tls_common.h
index d1dfff5e220b..59de922c0ecb 100644
--- a/contrib/wpa_supplicant/eap_tls_common.h
+++ b/contrib/wpa_supplicant/eap_tls_common.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-TLS/PEAP/TTLS/FAST common functions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -30,6 +30,7 @@ struct eap_ssl_data {
int phase2;
int include_tls_length; /* include TLS length field even if the TLS
* data is not fragmented */
+ int tls_ia; /* Enable TLS/IA */
struct eap_sm *eap;
};
@@ -49,16 +50,16 @@ int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
struct wpa_ssid *config);
void eap_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
- char *label, size_t len);
+ const char *label, size_t len);
const u8 * eap_tls_data_reassemble(
struct eap_sm *sm, struct eap_ssl_data *data, const u8 *in_data,
size_t in_len, size_t *out_len, int *need_more_input);
int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
- int eap_type, int peap_version,
+ EapType eap_type, int peap_version,
u8 id, const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len);
u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
- int eap_type, int peap_version);
+ EapType eap_type, int peap_version);
int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
size_t buflen, int verbose);
diff --git a/contrib/wpa_supplicant/eap_tlv.c b/contrib/wpa_supplicant/eap_tlv.c
index 4070c6f70691..df328de6b487 100644
--- a/contrib/wpa_supplicant/eap_tlv.c
+++ b/contrib/wpa_supplicant/eap_tlv.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,31 +12,33 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
-#include "wpa_supplicant.h"
#include "eap_i.h"
#include "eap_tlv.h"
+/**
+ * eap_tlv_build_nak - Build EAP-TLV NAK message
+ * @id: EAP identifier for the header
+ * @nak_type: TLV type (EAP_TLV_*)
+ * @resp_len: Buffer for returning the response length
+ * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
+ *
+ * This funtion builds an EAP-TLV NAK message. The caller is responsible for
+ * freeing the returned buffer.
+ */
u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len)
{
struct eap_hdr *hdr;
u8 *pos;
- *resp_len = sizeof(struct eap_hdr) + 1 + 10;
- hdr = malloc(*resp_len);
+ hdr = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, resp_len,
+ 10, EAP_CODE_RESPONSE, id, &pos);
if (hdr == NULL)
return NULL;
- hdr->code = EAP_CODE_RESPONSE;
- hdr->identifier = id;
- hdr->length = host_to_be16(*resp_len);
- pos = (u8 *) (hdr + 1);
- *pos++ = EAP_TYPE_TLV;
*pos++ = 0x80; /* Mandatory */
*pos++ = EAP_TLV_NAK_TLV;
/* Length */
@@ -54,21 +56,26 @@ u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len)
}
+/**
+ * eap_tlv_build_result - Build EAP-TLV Result message
+ * @id: EAP identifier for the header
+ * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
+ * @resp_len: Buffer for returning the response length
+ * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
+ *
+ * This funtion builds an EAP-TLV Result message. The caller is responsible for
+ * freeing the returned buffer.
+ */
u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len)
{
struct eap_hdr *hdr;
u8 *pos;
- *resp_len = sizeof(struct eap_hdr) + 1 + 6;
- hdr = malloc(*resp_len);
+ hdr = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, resp_len,
+ 6, EAP_CODE_RESPONSE, id, &pos);
if (hdr == NULL)
return NULL;
- hdr->code = EAP_CODE_RESPONSE;
- hdr->identifier = id;
- hdr->length = host_to_be16(*resp_len);
- pos = (u8 *) (hdr + 1);
- *pos++ = EAP_TYPE_TLV;
*pos++ = 0x80; /* Mandatory */
*pos++ = EAP_TLV_RESULT_TLV;
/* Length */
@@ -81,14 +88,28 @@ u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len)
}
+/**
+ * eap_tlv_process - Process a received EAP-TLV message and generate a response
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @ret: Return values from EAP request validation and processing
+ * @hdr: EAP-TLV request to be processed. The caller must have validated that
+ * the buffer is large enough to contain full request (hdr->length bytes) and
+ * that the EAP type is EAP_TYPE_TLV.
+ * @resp: Buffer to return a pointer to the allocated response message. This
+ * field should be initialized to %NULL before the call. The value will be
+ * updated if a response message is generated. The caller is responsible for
+ * freeing the allocated message.
+ * @resp_len: Buffer for returning the response length
+ * Returns: 0 on success, -1 on failure
+ */
int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
const struct eap_hdr *hdr, u8 **resp, size_t *resp_len)
{
- size_t left;
+ size_t left, tlv_len;
const u8 *pos;
const u8 *result_tlv = NULL;
size_t result_tlv_len = 0;
- int tlv_type, mandatory, tlv_len;
+ int tlv_type, mandatory;
/* Parse TLVs */
left = be_to_host16(hdr->length) - sizeof(struct eap_hdr) - 1;
@@ -104,7 +125,8 @@ int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
left -= 4;
if (tlv_len > left) {
wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
- "(tlv_len=%d left=%lu)", tlv_len,
+ "(tlv_len=%lu left=%lu)",
+ (unsigned long) tlv_len,
(unsigned long) left);
return -1;
}
diff --git a/contrib/wpa_supplicant/eap_tlv.h b/contrib/wpa_supplicant/eap_tlv.h
index 6a5afe0ad888..0525a60b183e 100644
--- a/contrib/wpa_supplicant/eap_tlv.h
+++ b/contrib/wpa_supplicant/eap_tlv.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -32,29 +32,33 @@
#define EAP_TLV_TYPE_MANDATORY 0x8000
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct eap_tlv_hdr {
u16 tlv_type;
u16 length;
-};
+} STRUCT_PACKED;
struct eap_tlv_nak_tlv {
u16 tlv_type;
u16 length;
u32 vendor_id;
u16 nak_type;
-} __attribute__((packed));
+} STRUCT_PACKED;
struct eap_tlv_result_tlv {
u16 tlv_type;
u16 length;
u16 status;
-} __attribute__((packed));
+} STRUCT_PACKED;
struct eap_tlv_intermediate_result_tlv {
u16 tlv_type;
u16 length;
u16 status;
-} __attribute__((packed));
+} STRUCT_PACKED;
struct eap_tlv_crypto_binding__tlv {
u16 tlv_type;
@@ -65,7 +69,7 @@ struct eap_tlv_crypto_binding__tlv {
u8 subtype;
u8 nonce[32];
u8 compound_mac[20];
-} __attribute__((packed));
+} STRUCT_PACKED;
struct eap_tlv_pac_ack_tlv {
u16 tlv_type;
@@ -73,7 +77,11 @@ struct eap_tlv_pac_ack_tlv {
u16 pac_type;
u16 pac_len;
u16 result;
-} __attribute__((packed));
+} 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
diff --git a/contrib/wpa_supplicant/eap_ttls.c b/contrib/wpa_supplicant/eap_ttls.c
index 0b1ff8f67658..ca0069439ac4 100644
--- a/contrib/wpa_supplicant/eap_ttls.c
+++ b/contrib/wpa_supplicant/eap_ttls.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-TTLS (draft-ietf-pppext-eap-ttls-03.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer method: EAP-TTLS (draft-ietf-pppext-eap-ttls-03.txt)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,26 +12,37 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
#include "eap_tls_common.h"
-#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "ms_funcs.h"
+#include "sha1.h"
#include "crypto.h"
#include "tls.h"
#include "eap_ttls.h"
+/* Maximum supported PEAP version
+ * 0 = draft-ietf-pppext-eap-ttls-03.txt / draft-funk-eap-ttls-v0-00.txt
+ * 1 = draft-funk-eap-ttls-v1-00.txt
+ */
+#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
+
+
+#define MSCHAPV2_KEY_LEN 16
+
+
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;
const struct eap_method *phase2_method;
void *phase2_priv;
@@ -45,8 +56,8 @@ struct eap_ttls_data {
EAP_TTLS_PHASE2_PAP,
EAP_TTLS_PHASE2_CHAP
} phase2_type;
- u8 phase2_eap_type;
- u8 *phase2_eap_types;
+ struct eap_method_type phase2_eap_type;
+ struct eap_method_type *phase2_eap_types;
size_t num_phase2_eap_types;
u8 auth_response[20];
@@ -67,26 +78,38 @@ static void * eap_ttls_init(struct eap_sm *sm)
struct wpa_ssid *config = eap_get_config(sm);
char *selected;
- data = malloc(sizeof(*data));
+ data = os_zalloc(sizeof(*data));
if (data == NULL)
return NULL;
- memset(data, 0, sizeof(*data));
+ data->ttls_version = EAP_TTLS_VERSION;
+ data->force_ttls_version = -1;
selected = "EAP";
data->phase2_type = EAP_TTLS_PHASE2_EAP;
+
+ if (config && config->phase1) {
+ 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);
+ }
+ }
+
if (config && config->phase2) {
- if (strstr(config->phase2, "autheap=")) {
+ if (os_strstr(config->phase2, "autheap=")) {
selected = "EAP";
data->phase2_type = EAP_TTLS_PHASE2_EAP;
- } else if (strstr(config->phase2, "auth=MSCHAPV2")) {
+ } else if (os_strstr(config->phase2, "auth=MSCHAPV2")) {
selected = "MSCHAPV2";
data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
- } else if (strstr(config->phase2, "auth=MSCHAP")) {
+ } else if (os_strstr(config->phase2, "auth=MSCHAP")) {
selected = "MSCHAP";
data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
- } else if (strstr(config->phase2, "auth=PAP")) {
+ } else if (os_strstr(config->phase2, "auth=PAP")) {
selected = "PAP";
data->phase2_type = EAP_TTLS_PHASE2_PAP;
- } else if (strstr(config->phase2, "auth=CHAP")) {
+ } else if (os_strstr(config->phase2, "auth=CHAP")) {
selected = "CHAP";
data->phase2_type = EAP_TTLS_PHASE2_CHAP;
}
@@ -96,15 +119,17 @@ static void * eap_ttls_init(struct eap_sm *sm)
if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
if (config && config->phase2) {
char *start, *pos, *buf;
- u8 method, *methods = NULL, *_methods;
+ struct eap_method_type *methods = NULL, *_methods;
+ u8 method;
size_t num_methods = 0;
- start = buf = strdup(config->phase2);
+ start = buf = os_strdup(config->phase2);
if (buf == NULL) {
eap_ttls_deinit(sm, data);
return NULL;
}
while (start && *start != '\0') {
- pos = strstr(start, "autheap=");
+ int vendor;
+ pos = os_strstr(start, "autheap=");
if (pos == NULL)
break;
if (start != pos && *(pos - 1) != ' ') {
@@ -113,30 +138,36 @@ static void * eap_ttls_init(struct eap_sm *sm)
}
start = pos + 8;
- pos = strchr(start, ' ');
+ pos = os_strchr(start, ' ');
if (pos)
*pos++ = '\0';
- method = eap_get_phase2_type(start);
- if (method == EAP_TYPE_NONE) {
+ method = eap_get_phase2_type(start, &vendor);
+ if (vendor == EAP_VENDOR_IETF &&
+ method == EAP_TYPE_NONE) {
wpa_printf(MSG_ERROR, "EAP-TTLS: "
"Unsupported Phase2 EAP "
"method '%s'", start);
} else {
num_methods++;
- _methods = realloc(methods,
- num_methods);
+ _methods = os_realloc(
+ methods, num_methods *
+ sizeof(*methods));
if (_methods == NULL) {
- free(methods);
+ os_free(methods);
+ os_free(buf);
eap_ttls_deinit(sm, data);
return NULL;
}
methods = _methods;
- methods[num_methods - 1] = method;
+ methods[num_methods - 1].vendor =
+ vendor;
+ methods[num_methods - 1].method =
+ method;
}
start = pos;
}
- free(buf);
+ os_free(buf);
data->phase2_eap_types = methods;
data->num_phase2_eap_types = num_methods;
}
@@ -151,16 +182,23 @@ static void * eap_ttls_init(struct eap_sm *sm)
return NULL;
}
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase2 EAP types",
- data->phase2_eap_types,
- data->num_phase2_eap_types);
- data->phase2_eap_type = EAP_TYPE_NONE;
+ (u8 *) data->phase2_eap_types,
+ data->num_phase2_eap_types *
+ sizeof(struct eap_method_type));
+ data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
+ data->phase2_eap_type.method = EAP_TYPE_NONE;
}
-
- if (eap_tls_ssl_init(sm, &data->ssl, config)) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
- eap_ttls_deinit(sm, data);
- return NULL;
+ 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;
}
return data;
@@ -174,11 +212,12 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
return;
if (data->phase2_priv && data->phase2_method)
data->phase2_method->deinit(sm, data->phase2_priv);
- free(data->phase2_eap_types);
- eap_tls_ssl_deinit(sm, &data->ssl);
- free(data->key_data);
- free(data->pending_phase2_req);
- free(data);
+ os_free(data->phase2_eap_types);
+ if (data->ssl_initialized)
+ eap_tls_ssl_deinit(sm, &data->ssl);
+ os_free(data->key_data);
+ os_free(data->pending_phase2_req);
+ os_free(data);
}
@@ -192,7 +231,7 @@ static int eap_ttls_encrypt(struct eap_sm *sm, struct eap_ttls_data *data,
/* TODO: add support for fragmentation, if needed. This will need to
* add TLS Message Length field, if the frame is fragmented. */
- resp = malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
+ resp = os_malloc(sizeof(struct eap_hdr) + 2 + data->ssl.tls_out_limit);
if (resp == NULL)
return -1;
@@ -201,7 +240,7 @@ static int eap_ttls_encrypt(struct eap_sm *sm, struct eap_ttls_data *data,
pos = (u8 *) (resp + 1);
*pos++ = EAP_TYPE_TTLS;
- *pos++ = 0;
+ *pos++ = data->ttls_version;
res = tls_connection_encrypt(sm->ssl_ctx, data->ssl.conn,
plain, plain_len,
@@ -209,7 +248,7 @@ static int eap_ttls_encrypt(struct eap_sm *sm, struct eap_ttls_data *data,
if (res < 0) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt Phase 2 "
"data");
- free(resp);
+ os_free(resp);
return -1;
}
@@ -250,7 +289,7 @@ static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
{
u8 *pos;
pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len);
- memcpy(pos, data, len);
+ os_memcpy(pos, data, len);
pos += len;
AVP_PAD(start, pos);
return pos;
@@ -262,48 +301,215 @@ static int eap_ttls_avp_encapsulate(u8 **resp, size_t *resp_len, u32 avp_code,
{
u8 *avp, *pos;
- avp = malloc(sizeof(struct ttls_avp) + *resp_len + 4);
+ avp = os_malloc(sizeof(struct ttls_avp) + *resp_len + 4);
if (avp == NULL) {
- free(*resp);
+ os_free(*resp);
*resp = NULL;
*resp_len = 0;
return -1;
}
pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, *resp_len);
- memcpy(pos, *resp, *resp_len);
+ os_memcpy(pos, *resp, *resp_len);
pos += *resp_len;
AVP_PAD(avp, pos);
- free(*resp);
+ os_free(*resp);
*resp = avp;
*resp_len = pos - avp;
return 0;
}
-static int eap_ttls_phase2_nak(struct eap_sm *sm,
- struct eap_ttls_data *data,
- struct eap_hdr *hdr,
+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;
+}
+
+
+static int eap_ttls_v0_derive_key(struct eap_sm *sm,
+ struct eap_ttls_data *data)
+{
+ os_free(data->key_data);
+ data->key_data = eap_tls_derive_key(sm, &data->ssl,
+ "ttls keying material",
+ EAP_TLS_KEY_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;
+}
+
+
+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(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;
+}
+
+
+static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
+ struct eap_ttls_data *data, size_t len)
+{
+ struct tls_keys keys;
+ u8 *challenge, *rnd;
+
+ if (data->ttls_version == 0) {
+ return eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
+ len);
+ }
+
+ 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;
+}
+
+
+static int eap_ttls_phase2_nak(struct eap_ttls_data *data, struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
struct eap_hdr *resp_hdr;
u8 *pos = (u8 *) (hdr + 1);
+ size_t i;
+ /* TODO: add support for expanded Nak */
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 Request: Nak type=%d", *pos);
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Allowed Phase2 EAP types",
- data->phase2_eap_types, data->num_phase2_eap_types);
- *resp_len = sizeof(struct eap_hdr) + 1 + data->num_phase2_eap_types;
- *resp = malloc(*resp_len);
+ (u8 *) data->phase2_eap_types, data->num_phase2_eap_types *
+ sizeof(struct eap_method_type));
+ *resp_len = sizeof(struct eap_hdr) + 1;
+ *resp = os_malloc(*resp_len + data->num_phase2_eap_types);
if (*resp == NULL)
return -1;
resp_hdr = (struct eap_hdr *) (*resp);
resp_hdr->code = EAP_CODE_RESPONSE;
resp_hdr->identifier = hdr->identifier;
- resp_hdr->length = host_to_be16(*resp_len);
pos = (u8 *) (resp_hdr + 1);
*pos++ = EAP_TYPE_NAK;
- memcpy(pos, data->phase2_eap_types, data->num_phase2_eap_types);
+ 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 < 256) {
+ (*resp_len)++;
+ *pos++ = data->phase2_eap_types[i].method;
+ }
+ }
+ resp_hdr->length = host_to_be16(*resp_len);
return 0;
}
@@ -312,7 +518,6 @@ static int eap_ttls_phase2_nak(struct eap_sm *sm,
static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
- const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -330,35 +535,46 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos);
switch (*pos) {
case EAP_TYPE_IDENTITY:
- *resp = eap_sm_buildIdentity(sm, req->identifier, resp_len, 1);
+ *resp = eap_sm_buildIdentity(sm, hdr->identifier, resp_len, 1);
break;
default:
- if (data->phase2_eap_type == EAP_TYPE_NONE) {
- int i;
+ if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
+ data->phase2_eap_type.method == EAP_TYPE_NONE) {
+ size_t i;
for (i = 0; i < data->num_phase2_eap_types; i++) {
- if (data->phase2_eap_types[i] != *pos)
+ if (data->phase2_eap_types[i].vendor !=
+ EAP_VENDOR_IETF ||
+ data->phase2_eap_types[i].method != *pos)
continue;
- data->phase2_eap_type = *pos;
+ 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 method %d",
- data->phase2_eap_type);
+ "Phase 2 EAP vendor %d method %d",
+ data->phase2_eap_type.vendor,
+ data->phase2_eap_type.method);
break;
}
}
- if (*pos != data->phase2_eap_type || *pos == EAP_TYPE_NONE) {
- if (eap_ttls_phase2_nak(sm, data, hdr, resp, resp_len))
+ if (*pos != data->phase2_eap_type.method ||
+ *pos == EAP_TYPE_NONE) {
+ if (eap_ttls_phase2_nak(data, hdr, resp, resp_len))
return -1;
break;
}
if (data->phase2_priv == NULL) {
- data->phase2_method = eap_sm_get_eap_methods(*pos);
+ data->phase2_method = eap_sm_get_eap_methods(
+ EAP_VENDOR_IETF, *pos);
if (data->phase2_method) {
sm->init_phase2 = 1;
+ sm->mschapv2_full_key = 1;
data->phase2_priv =
data->phase2_method->init(sm);
sm->init_phase2 = 0;
+ sm->mschapv2_full_key = 0;
}
}
if (data->phase2_priv == NULL || data->phase2_method == NULL) {
@@ -366,7 +582,7 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
"Phase 2 EAP method %d", *pos);
return -1;
}
- memset(&iret, 0, sizeof(iret));
+ os_memset(&iret, 0, sizeof(iret));
*resp = data->phase2_method->process(sm, data->phase2_priv,
&iret, (u8 *) hdr, len,
resp_len);
@@ -378,6 +594,28 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
ret->methodState = iret.methodState;
ret->decision = iret.decision;
}
+ 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);
+ }
+ }
+ }
break;
}
@@ -400,14 +638,11 @@ static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
- const struct eap_hdr *req,
- struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
struct wpa_ssid *config = eap_get_config(sm);
u8 *buf, *pos, *challenge, *username, *peer_challenge;
- size_t username_len;
- int i;
+ size_t username_len, i;
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request");
@@ -425,7 +660,7 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
}
}
- pos = buf = malloc(config->identity_len + 1000);
+ pos = buf = os_malloc(config->identity_len + 1000);
if (buf == NULL) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/MSCHAPV2: Failed to allocate memory");
@@ -437,11 +672,10 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
config->identity, config->identity_len);
/* MS-CHAP-Challenge */
- challenge = eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
- EAP_TTLS_MSCHAPV2_CHALLENGE_LEN * 2 +
- 1);
+ challenge = eap_ttls_implicit_challenge(
+ sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN * 2 + 1);
if (challenge == NULL) {
- free(buf);
+ os_free(buf);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
"implicit challenge");
return -1;
@@ -459,9 +693,9 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
*pos++ = data->ident;
*pos++ = 0; /* Flags */
- memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+ os_memcpy(pos, peer_challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
- memset(pos, 0, 8); /* Reserved, must be zero */
+ os_memset(pos, 0, 8); /* Reserved, must be zero */
pos += 8;
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAPV2: implicit auth_challenge",
challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
@@ -482,14 +716,32 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
pos, data->auth_response);
data->auth_response_valid = 1;
+ if (data->ttls_version > 0) {
+ u8 pw_hash[16], pw_hash_hash[16], master_key[16];
+ u8 session_key[2 * MSCHAPV2_KEY_LEN];
+ nt_password_hash(config->password, config->password_len,
+ pw_hash);
+ hash_nt_password_hash(pw_hash, pw_hash_hash);
+ get_master_key(pw_hash_hash, pos /* nt_response */,
+ master_key);
+ get_asymetric_start_key(master_key, session_key,
+ MSCHAPV2_KEY_LEN, 0, 0);
+ get_asymetric_start_key(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));
+ }
+
pos += 24;
- free(challenge);
+ os_free(challenge);
AVP_PAD(buf, pos);
*resp = buf;
*resp_len = pos - buf;
- if (sm->workaround) {
+ 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. */
@@ -506,8 +758,6 @@ static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
- const struct eap_hdr *req,
- struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
struct wpa_ssid *config = eap_get_config(sm);
@@ -515,7 +765,7 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request");
- pos = buf = malloc(config->identity_len + 1000);
+ pos = buf = os_malloc(config->identity_len + 1000);
if (buf == NULL) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/MSCHAP: Failed to allocate memory");
@@ -527,10 +777,9 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
config->identity, config->identity_len);
/* MS-CHAP-Challenge */
- challenge = eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
- EAP_TLS_KEY_LEN);
+ challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
if (challenge == NULL) {
- free(buf);
+ os_free(buf);
wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
"implicit challenge");
return -1;
@@ -547,7 +796,7 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN];
*pos++ = data->ident;
*pos++ = 1; /* Flags: Use NT style passwords */
- memset(pos, 0, 24); /* LM-Response */
+ os_memset(pos, 0, 24); /* LM-Response */
pos += 24;
nt_challenge_response(challenge,
config->password, config->password_len,
@@ -558,16 +807,23 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24);
pos += 24;
- free(challenge);
+ os_free(challenge);
AVP_PAD(buf, pos);
*resp = buf;
*resp_len = pos - buf;
- /* EAP-TTLS/MSCHAP does not provide tunneled success notification, so
- * assume that Phase2 succeeds. */
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_COND_SUCC;
+ if (data->ttls_version > 0) {
+ /* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
+ * so do not allow connection to be terminated yet. */
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_COND_SUCC;
+ } else {
+ /* EAP-TTLS/MSCHAP does not provide tunneled success
+ * notification, so assume that Phase2 succeeds. */
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_COND_SUCC;
+ }
return 0;
}
@@ -576,8 +832,6 @@ static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
- const struct eap_hdr *req,
- struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
struct wpa_ssid *config = eap_get_config(sm);
@@ -586,7 +840,8 @@ static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request");
- pos = buf = malloc(config->identity_len + config->password_len + 100);
+ pos = buf = os_malloc(config->identity_len + config->password_len +
+ 100);
if (buf == NULL) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/PAP: Failed to allocate memory");
@@ -603,19 +858,26 @@ static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
pad = (16 - (config->password_len & 15)) & 15;
pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1,
config->password_len + pad);
- memcpy(pos, config->password, config->password_len);
+ os_memcpy(pos, config->password, config->password_len);
pos += config->password_len;
- memset(pos, 0, pad);
+ os_memset(pos, 0, pad);
pos += pad;
AVP_PAD(buf, pos);
*resp = buf;
*resp_len = pos - buf;
- /* EAP-TTLS/PAP does not provide tunneled success notification, so
- * assume that Phase2 succeeds. */
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_COND_SUCC;
+ 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;
+ }
return 0;
}
@@ -624,8 +886,6 @@ static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
- const struct eap_hdr *req,
- struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
struct wpa_ssid *config = eap_get_config(sm);
@@ -635,7 +895,7 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
- pos = buf = malloc(config->identity_len + 1000);
+ pos = buf = os_malloc(config->identity_len + 1000);
if (buf == NULL) {
wpa_printf(MSG_ERROR,
"EAP-TTLS/CHAP: Failed to allocate memory");
@@ -647,10 +907,9 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
config->identity, config->identity_len);
/* CHAP-Challenge */
- challenge = eap_tls_derive_key(sm, &data->ssl, "ttls challenge",
- EAP_TLS_KEY_LEN);
+ challenge = eap_ttls_implicit_challenge(sm, data, EAP_TLS_KEY_LEN);
if (challenge == NULL) {
- free(buf);
+ os_free(buf);
wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
"implicit challenge");
return -1;
@@ -683,16 +942,23 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password",
pos, EAP_TTLS_CHAP_PASSWORD_LEN);
pos += EAP_TTLS_CHAP_PASSWORD_LEN;
- free(challenge);
+ os_free(challenge);
AVP_PAD(buf, pos);
*resp = buf;
*resp_len = pos - buf;
- /* EAP-TTLS/CHAP does not provide tunneled success notification, so
- * assume that Phase2 succeeds. */
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_COND_SUCC;
+ 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;
+ }
return 0;
}
@@ -705,49 +971,49 @@ static int eap_ttls_phase2_request(struct eap_sm *sm,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
- struct wpa_ssid *config = eap_get_config(sm);
int res = 0;
+ size_t len;
if (data->phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 ||
data->phase2_type == EAP_TTLS_PHASE2_MSCHAP ||
data->phase2_type == EAP_TTLS_PHASE2_PAP ||
data->phase2_type == EAP_TTLS_PHASE2_CHAP) {
- if (config == NULL || config->identity == NULL) {
+ if (eap_get_config_identity(sm, &len) == NULL) {
wpa_printf(MSG_INFO,
"EAP-TTLS: Identity not configured");
- eap_sm_request_identity(sm, config);
- if (config->password == NULL)
- eap_sm_request_password(sm, config);
+ eap_sm_request_identity(sm);
+ if (eap_get_config_password(sm, &len) == NULL)
+ eap_sm_request_password(sm);
return 0;
}
- if (config->password == NULL) {
+ if (eap_get_config_password(sm, &len) == NULL) {
wpa_printf(MSG_INFO,
"EAP-TTLS: Password not configured");
- eap_sm_request_password(sm, config);
+ eap_sm_request_password(sm);
return 0;
}
}
switch (data->phase2_type) {
case EAP_TTLS_PHASE2_EAP:
- res = eap_ttls_phase2_request_eap(sm, data, ret, req, hdr,
+ res = eap_ttls_phase2_request_eap(sm, data, ret, hdr,
resp, resp_len);
break;
case EAP_TTLS_PHASE2_MSCHAPV2:
- res = eap_ttls_phase2_request_mschapv2(sm, data, ret, req, hdr,
+ res = eap_ttls_phase2_request_mschapv2(sm, data, ret,
resp, resp_len);
break;
case EAP_TTLS_PHASE2_MSCHAP:
- res = eap_ttls_phase2_request_mschap(sm, data, ret, req, hdr,
+ res = eap_ttls_phase2_request_mschap(sm, data, ret,
resp, resp_len);
break;
case EAP_TTLS_PHASE2_PAP:
- res = eap_ttls_phase2_request_pap(sm, data, ret, req, hdr,
+ res = eap_ttls_phase2_request_pap(sm, data, ret,
resp, resp_len);
break;
case EAP_TTLS_PHASE2_CHAP:
- res = eap_ttls_phase2_request_chap(sm, data, ret, req, hdr,
+ res = eap_ttls_phase2_request_chap(sm, data, ret,
resp, resp_len);
break;
default:
@@ -765,6 +1031,43 @@ static int eap_ttls_phase2_request(struct eap_sm *sm,
}
+static u8 * eap_ttls_build_phase_finished(struct eap_sm *sm,
+ struct eap_ttls_data *data,
+ int id, int final,
+ size_t *reqDataLen)
+{
+ int len;
+ struct eap_hdr *req;
+ u8 *pos;
+ const int max_len = 300;
+
+ len = sizeof(struct eap_hdr) + 2 + max_len;
+ req = os_malloc(len);
+ if (req == NULL)
+ return NULL;
+
+ req->code = EAP_CODE_RESPONSE;
+ req->identifier = id;
+
+ pos = (u8 *) (req + 1);
+ *pos++ = EAP_TYPE_TTLS;
+ *pos++ = data->ttls_version;
+
+ len = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
+ data->ssl.conn,
+ final, pos, max_len);
+ if (len < 0) {
+ os_free(req);
+ return NULL;
+ }
+
+ *reqDataLen = sizeof(struct eap_hdr) + 2 + len;
+ req->length = host_to_be16(*reqDataLen);
+
+ return (u8 *) req;
+}
+
+
static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
struct eap_method_ret *ret,
const struct eap_hdr *req,
@@ -772,10 +1075,10 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted = NULL, *pos;
- int buf_len, len_decrypted = 0, len, left, retval = 0;
+ int res, retval = 0;
struct eap_hdr *hdr = NULL;
u8 *resp = NULL, *mschapv2 = NULL, *eapdata = NULL;
- size_t resp_len, eap_len = 0;
+ size_t resp_len, eap_len = 0, len_decrypted = 0, len, buf_len, left;
struct ttls_avp *avp;
u8 recv_response[20];
int mschapv2_error = 0;
@@ -791,7 +1094,7 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - "
"skip decryption and use old data");
/* Clear TLS reassembly state. */
- free(data->ssl.tls_in);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
data->ssl.tls_in_left = 0;
@@ -801,7 +1104,7 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
data->pending_phase2_req = NULL;
len_decrypted = data->pending_phase2_req_len;
if (data->pending_phase2_req_len == 0) {
- free(in_decrypted);
+ os_free(in_decrypted);
in_decrypted = NULL;
goto fake_req_identity;
}
@@ -831,7 +1134,7 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of "
"Phase 2 - use fake EAP-Request Identity");
buf_len = sizeof(*hdr) + 1;
- in_decrypted = malloc(buf_len);
+ in_decrypted = os_malloc(buf_len);
if (in_decrypted == NULL) {
wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate "
"memory for fake EAP-Identity Request");
@@ -854,9 +1157,9 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
buf_len = in_len;
if (data->ssl.tls_in_total > buf_len)
buf_len = data->ssl.tls_in_total;
- in_decrypted = malloc(buf_len);
+ in_decrypted = os_malloc(buf_len);
if (in_decrypted == NULL) {
- free(data->ssl.tls_in);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate memory "
@@ -865,18 +1168,34 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
goto done;
}
- len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
- msg, msg_len,
- in_decrypted, buf_len);
- free(data->ssl.tls_in);
+ res = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
+ msg, msg_len, in_decrypted, buf_len);
+ os_free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
data->ssl.tls_in_len = 0;
- if (len_decrypted < 0) {
+ if (res < 0) {
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to decrypt Phase 2 "
"data");
retval = -1;
goto done;
}
+ len_decrypted = res;
+
+ if (data->ttls_version > 0 && len_decrypted == 0 &&
+ tls_connection_ia_final_phase_finished(sm->ssl_ctx,
+ data->ssl.conn)) {
+ 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,
+ req->identifier, 1,
+ out_len);
+ eap_ttls_v1_derive_key(sm, data);
+ goto done;
+ }
continue_req:
data->phase2_start = 0;
@@ -885,8 +1204,8 @@ continue_req:
in_decrypted, len_decrypted);
if (len_decrypted < sizeof(struct ttls_avp)) {
wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame"
- " len=%d expected %lu or more - dropped",
- len_decrypted,
+ " len=%lu expected %lu or more - dropped",
+ (unsigned long) len_decrypted,
(unsigned long) sizeof(struct ttls_avp));
retval = -1;
goto done;
@@ -911,8 +1230,14 @@ continue_req:
(int) avp_length);
if (avp_length > left) {
wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
- "(len=%d, left=%d) - dropped",
- (int) avp_length, left);
+ "(len=%d, left=%lu) - dropped",
+ (int) avp_length, (unsigned long) left);
+ retval = -1;
+ goto done;
+ }
+ if (avp_length < sizeof(*avp)) {
+ wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length "
+ "%d", avp_length);
retval = -1;
goto done;
}
@@ -937,7 +1262,7 @@ continue_req:
if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
if (eapdata == NULL) {
- eapdata = malloc(dlen);
+ eapdata = os_malloc(dlen);
if (eapdata == NULL) {
retval = -1;
wpa_printf(MSG_WARNING, "EAP-TTLS: "
@@ -945,10 +1270,11 @@ continue_req:
"for Phase 2 EAP data");
goto done;
}
- memcpy(eapdata, dpos, dlen);
+ os_memcpy(eapdata, dpos, dlen);
eap_len = dlen;
} else {
- u8 *neweap = realloc(eapdata, eap_len + dlen);
+ u8 *neweap = os_realloc(eapdata,
+ eap_len + dlen);
if (neweap == NULL) {
retval = -1;
wpa_printf(MSG_WARNING, "EAP-TTLS: "
@@ -956,7 +1282,7 @@ continue_req:
"for Phase 2 EAP data");
goto done;
}
- memcpy(neweap + eap_len, dpos, dlen);
+ os_memcpy(neweap + eap_len, dpos, dlen);
eapdata = neweap;
eap_len += dlen;
}
@@ -999,7 +1325,10 @@ continue_req:
pad = (4 - (avp_length & 3)) & 3;
pos += avp_length + pad;
- left -= avp_length + pad;
+ if (left < avp_length + pad)
+ left = 0;
+ else
+ left -= avp_length + pad;
}
switch (data->phase2_type) {
@@ -1026,15 +1355,16 @@ continue_req:
len = be_to_host16(hdr->length);
if (len > eap_len) {
wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in "
- "Phase 2 EAP frame (EAP hdr len=%d, EAP "
- "data len in AVP=%lu)", len,
+ "Phase 2 EAP frame (EAP hdr len=%lu, EAP "
+ "data len in AVP=%lu)",
+ (unsigned long) len,
(unsigned long) eap_len);
retval = -1;
goto done;
}
wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d "
- "identifier=%d length=%d",
- hdr->code, hdr->identifier, len);
+ "identifier=%d length=%lu",
+ hdr->code, hdr->identifier, (unsigned long) len);
process_eap:
switch (hdr->code) {
case EAP_CODE_REQUEST:
@@ -1082,7 +1412,7 @@ continue_req:
if (!data->auth_response_valid ||
mschapv2[1] != 'S' || mschapv2[2] != '=' ||
hexstr2bin((char *) (mschapv2 + 3), recv_response, 20) ||
- memcmp(data->auth_response, recv_response, 20) != 0) {
+ os_memcmp(data->auth_response, recv_response, 20) != 0) {
wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid "
"authenticator response in Phase 2 "
"MSCHAPV2 success request");
@@ -1092,9 +1422,17 @@ continue_req:
wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
"authentication succeeded");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_UNCOND_SUCC;
- data->phase2_success = 1;
+ 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;
+ }
/* Reply with empty data; authentication server will reply
* with EAP-Success after this. */
@@ -1120,23 +1458,23 @@ continue_req:
wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt "
"a Phase 2 frame");
}
- free(resp);
+ os_free(resp);
} else if (config->pending_req_identity ||
config->pending_req_password ||
config->pending_req_otp ||
config->pending_req_new_password) {
- free(data->pending_phase2_req);
- data->pending_phase2_req = malloc(len_decrypted);
+ os_free(data->pending_phase2_req);
+ data->pending_phase2_req = os_malloc(len_decrypted);
if (data->pending_phase2_req) {
- memcpy(data->pending_phase2_req, in_decrypted,
- len_decrypted);
+ os_memcpy(data->pending_phase2_req, in_decrypted,
+ len_decrypted);
data->pending_phase2_req_len = len_decrypted;
}
}
done:
- free(in_decrypted);
- free(eapdata);
+ os_free(in_decrypted);
+ os_free(eapdata);
if (retval < 0) {
ret->methodState = METHOD_DONE;
@@ -1158,6 +1496,7 @@ static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
u8 flags, *resp, id;
const u8 *pos;
struct eap_ttls_data *data = priv;
+ struct wpa_ssid *config = eap_get_config(sm);
pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret,
reqData, reqDataLen, &left, &flags);
@@ -1167,6 +1506,34 @@ static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
id = req->identifier;
if (flags & EAP_TLS_FLAGS_START) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
+ "ver=%d)", flags & EAP_PEAP_VERSION_MASK,
+ data->ttls_version);
+ if ((flags & EAP_PEAP_VERSION_MASK) < data->ttls_version)
+ data->ttls_version = flags & EAP_PEAP_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 NULL;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d",
+ data->ttls_version);
+
+ if (data->ttls_version > 0)
+ data->ssl.tls_ia = 1;
+ if (!data->ssl_initialized &&
+ eap_tls_ssl_init(sm, &data->ssl, config)) {
+ wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize "
+ "SSL.");
+ return NULL;
+ }
+ data->ssl_initialized = 1;
+
wpa_printf(MSG_DEBUG, "EAP-TTLS: Start");
/* draft-ietf-pppext-eap-ttls-03.txt, Ch. 8.1:
* EAP-TTLS Start packet may, in a future specification, be
@@ -1174,6 +1541,13 @@ static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
* must ignore such data but must not reject the Start packet.
*/
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;
}
resp = NULL;
@@ -1182,8 +1556,8 @@ static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
res = eap_ttls_decrypt(sm, data, ret, req, pos, left,
&resp, respDataLen);
} else {
- res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS, 0,
- id, pos, left,
+ res = eap_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
+ data->ttls_version, id, pos, left,
&resp, respDataLen);
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
@@ -1196,20 +1570,8 @@ static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
ret->methodState = METHOD_MAY_CONT;
}
data->phase2_start = 1;
- free(data->key_data);
- data->key_data =
- eap_tls_derive_key(sm, &data->ssl,
- "ttls keying material",
- EAP_TLS_KEY_LEN);
- if (data->key_data) {
- wpa_hexdump_key(MSG_DEBUG,
- "EAP-TTLS: Derived key",
- data->key_data,
- EAP_TLS_KEY_LEN);
- } else {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to "
- "derive key");
- }
+ if (data->ttls_version == 0)
+ eap_ttls_v0_derive_key(sm, data);
if (*respDataLen == 0) {
if (eap_ttls_decrypt(sm, data, ret, req, NULL,
@@ -1222,9 +1584,22 @@ static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
}
data->resuming = 0;
}
+
+ if (res == 2) {
+ /*
+ * Application data included in the handshake message.
+ */
+ os_free(data->pending_phase2_req);
+ data->pending_phase2_req = resp;
+ data->pending_phase2_req_len = *respDataLen;
+ resp = NULL;
+ *respDataLen = 0;
+ res = eap_ttls_decrypt(sm, data, ret, req, pos, left,
+ &resp, respDataLen);
+ }
}
- if (ret->methodState == METHOD_DONE) {
+ if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) {
ret->allowNotifications = FALSE;
if (ret->decision == DECISION_UNCOND_SUCC ||
ret->decision == DECISION_COND_SUCC) {
@@ -1232,7 +1607,8 @@ static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
"completed successfully");
data->phase2_success = 1;
}
- } else if (sm->workaround && ret->methodState == METHOD_MAY_CONT &&
+ } else if (data->ttls_version == 0 && sm->workaround &&
+ ret->methodState == METHOD_MAY_CONT &&
(ret->decision == DECISION_UNCOND_SUCC ||
ret->decision == DECISION_COND_SUCC)) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
@@ -1242,7 +1618,7 @@ static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
if (res == 1) {
return eap_tls_build_ack(&data->ssl, respDataLen, id,
- EAP_TYPE_TTLS, 0);
+ EAP_TYPE_TTLS, data->ttls_version);
}
return resp;
}
@@ -1259,7 +1635,7 @@ static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
- free(data->pending_phase2_req);
+ os_free(data->pending_phase2_req);
data->pending_phase2_req = NULL;
}
@@ -1267,12 +1643,15 @@ static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
{
struct eap_ttls_data *data = priv;
- free(data->key_data);
+ os_free(data->key_data);
data->key_data = NULL;
if (eap_tls_reauth_init(sm, &data->ssl)) {
- free(data);
+ 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;
@@ -1285,33 +1664,40 @@ 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;
+ int len, ret;
len = eap_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)
+ return len;
+ len += ret;
switch (data->phase2_type) {
case EAP_TTLS_PHASE2_EAP:
- len += snprintf(buf + len, buflen - len,
- "EAP-TTLS Phase2 method=EAP-%s\n",
- data->phase2_method ? data->phase2_method->name
- : "?");
+ ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n",
+ data->phase2_method ?
+ data->phase2_method->name : "?");
break;
case EAP_TTLS_PHASE2_MSCHAPV2:
- len += snprintf(buf + len, buflen - len,
- "EAP-TTLS Phase2 method=MSCHAPV2\n");
+ ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n");
break;
case EAP_TTLS_PHASE2_MSCHAP:
- len += snprintf(buf + len, buflen - len,
- "EAP-TTLS Phase2 method=MSCHAP\n");
+ ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n");
break;
case EAP_TTLS_PHASE2_PAP:
- len += snprintf(buf + len, buflen - len,
- "EAP-TTLS Phase2 method=PAP\n");
+ ret = os_snprintf(buf + len, buflen - len, "PAP\n");
break;
case EAP_TTLS_PHASE2_CHAP:
- len += snprintf(buf + len, buflen - len,
- "EAP-TTLS Phase2 method=CHAP\n");
+ ret = os_snprintf(buf + len, buflen - len, "CHAP\n");
+ break;
+ default:
+ ret = 0;
break;
}
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
return len;
}
@@ -1332,28 +1718,39 @@ static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->key_data == NULL || !data->phase2_success)
return NULL;
- key = malloc(EAP_TLS_KEY_LEN);
+ key = os_malloc(EAP_TLS_KEY_LEN);
if (key == NULL)
return NULL;
*len = EAP_TLS_KEY_LEN;
- memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+ os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
return key;
}
-const struct eap_method eap_method_ttls =
+int eap_peer_ttls_register(void)
{
- .method = EAP_TYPE_TTLS,
- .name = "TTLS",
- .init = eap_ttls_init,
- .deinit = eap_ttls_deinit,
- .process = eap_ttls_process,
- .isKeyAvailable = eap_ttls_isKeyAvailable,
- .getKey = eap_ttls_getKey,
- .get_status = eap_ttls_get_status,
- .has_reauth_data = eap_ttls_has_reauth_data,
- .deinit_for_reauth = eap_ttls_deinit_for_reauth,
- .init_for_reauth = eap_ttls_init_for_reauth,
-};
+ 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->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;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eap_ttls.h b/contrib/wpa_supplicant/eap_ttls.h
index f35f5a905997..e0b2cbf45488 100644
--- a/contrib/wpa_supplicant/eap_ttls.h
+++ b/contrib/wpa_supplicant/eap_ttls.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-TTLS (draft-ietf-pppext-eap-ttls-03.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: EAP-TTLS (draft-ietf-pppext-eap-ttls-03.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -36,11 +36,11 @@ struct ttls_avp_vendor {
#define AVP_PAD(start, pos) \
do { \
- int pad; \
- pad = (4 - (((pos) - (start)) & 3)) & 3; \
- memset((pos), 0, pad); \
- pos += pad; \
-} while(0)
+ int __pad; \
+ __pad = (4 - (((pos) - (start)) & 3)) & 3; \
+ os_memset((pos), 0, __pad); \
+ pos += __pad; \
+} while (0)
/* RFC 2865 */
diff --git a/contrib/wpa_supplicant/eap_vendor_test.c b/contrib/wpa_supplicant/eap_vendor_test.c
new file mode 100644
index 000000000000..7db76be25f9d
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_vendor_test.c
@@ -0,0 +1,198 @@
+/*
+ * EAP peer method: Test method for vendor specific (expanded) EAP type
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file implements a vendor specific test method using EAP expanded types.
+ * This is only for test use and must not be used for authentication since no
+ * security is provided.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_i.h"
+#include "eloop.h"
+
+
+#define EAP_VENDOR_ID 0xfffefd
+#define EAP_VENDOR_TYPE 0xfcfbfaf9
+
+
+/* #define TEST_PENDING_REQUEST */
+
+struct eap_vendor_test_data {
+ enum { INIT, CONFIRM, SUCCESS } state;
+ int first_try;
+};
+
+
+static void * eap_vendor_test_init(struct eap_sm *sm)
+{
+ struct eap_vendor_test_data *data;
+ data = os_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = INIT;
+ data->first_try = 1;
+ return data;
+}
+
+
+static void eap_vendor_test_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_vendor_test_data *data = priv;
+ os_free(data);
+}
+
+
+#ifdef TEST_PENDING_REQUEST
+static void eap_vendor_ready(void *eloop_ctx, void *timeout_ctx)
+{
+ struct eap_sm *sm = eloop_ctx;
+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Ready to re-process pending "
+ "request");
+ eap_notify_pending(sm);
+}
+#endif /* TEST_PENDING_REQUEST */
+
+
+static u8 * eap_vendor_test_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_vendor_test_data *data = priv;
+ const struct eap_hdr *req;
+ struct eap_hdr *resp;
+ const u8 *pos;
+ u8 *rpos;
+ size_t len;
+
+ pos = eap_hdr_validate(EAP_VENDOR_ID, EAP_VENDOR_TYPE,
+ reqData, reqDataLen, &len);
+ if (pos == NULL || len < 1) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (data->state == INIT && *pos != 1) {
+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
+ "%d in INIT state", *pos);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (data->state == CONFIRM && *pos != 3) {
+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
+ "%d in CONFIRM state", *pos);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (data->state == SUCCESS) {
+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Unexpected message "
+ "in SUCCESS state");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (data->state == CONFIRM) {
+#ifdef TEST_PENDING_REQUEST
+ if (data->first_try) {
+ data->first_try = 0;
+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Testing "
+ "pending request");
+ ret->ignore = TRUE;
+ eloop_register_timeout(1, 0, eap_vendor_ready, sm,
+ NULL);
+ return NULL;
+ }
+#endif /* TEST_PENDING_REQUEST */
+ }
+
+ ret->ignore = FALSE;
+ req = (const struct eap_hdr *) reqData;
+
+ wpa_printf(MSG_DEBUG, "EAP-VENDOR-TEST: Generating Response");
+ ret->allowNotifications = TRUE;
+
+ resp = eap_msg_alloc(EAP_VENDOR_ID, EAP_VENDOR_TYPE, respDataLen, 1,
+ EAP_CODE_RESPONSE, req->identifier, &rpos);
+ if (resp == NULL)
+ return NULL;
+
+ if (data->state == INIT) {
+ *rpos = 2;
+ data->state = CONFIRM;
+ ret->methodState = METHOD_CONT;
+ ret->decision = DECISION_FAIL;
+ } else {
+ *rpos = 4;
+ data->state = SUCCESS;
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ }
+
+ return (u8 *) resp;
+}
+
+
+static Boolean eap_vendor_test_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_vendor_test_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+static u8 * eap_vendor_test_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_vendor_test_data *data = priv;
+ u8 *key;
+ const int key_len = 64;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(key_len);
+ if (key == NULL)
+ return NULL;
+
+ os_memset(key, 0x11, key_len / 2);
+ os_memset(key + key_len / 2, 0x22, key_len / 2);
+ *len = key_len;
+
+ return key;
+}
+
+
+int eap_peer_vendor_test_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_ID, EAP_VENDOR_TYPE,
+ "VENDOR-TEST");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_vendor_test_init;
+ eap->deinit = eap_vendor_test_deinit;
+ eap->process = eap_vendor_test_process;
+ eap->isKeyAvailable = eap_vendor_test_isKeyAvailable;
+ eap->getKey = eap_vendor_test_getKey;
+
+ ret = eap_peer_method_register(eap);
+ if (ret)
+ eap_peer_method_free(eap);
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/eapol_sm.c b/contrib/wpa_supplicant/eapol_sm.c
index 95a6031015e3..899e2ce096a9 100644
--- a/contrib/wpa_supplicant/eapol_sm.c
+++ b/contrib/wpa_supplicant/eapol_sm.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / EAPOL state machines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eapol_sm.h"
@@ -24,6 +22,10 @@
#include "wpa.h"
#include "md5.h"
#include "rc4.h"
+#include "state_machine.h"
+
+#define STATE_MACHINE_DATA struct eapol_sm
+#define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
@@ -150,6 +152,10 @@ struct eapol_sm {
#define IEEE8021X_KEY_INDEX_FLAG 0x80
#define IEEE8021X_KEY_INDEX_MASK 0x03
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct ieee802_1x_eapol_key {
u8 type;
/* Note: key_length is unaligned */
@@ -172,7 +178,11 @@ struct ieee802_1x_eapol_key {
* represents the number of least significant octets from
* MS-MPPE-Send-Key attribute to be used as the keying material;
* RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
static void eapol_sm_txLogoff(struct eapol_sm *sm);
@@ -185,29 +195,6 @@ static void eapol_sm_abort_cached(struct eapol_sm *sm);
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
-/* Definitions for clarifying state machine implementation */
-#define SM_STATE(machine, state) \
-static void sm_ ## machine ## _ ## state ## _Enter(struct eapol_sm *sm, \
- int global)
-
-#define SM_ENTRY(machine, state) \
-if (!global || sm->machine ## _state != machine ## _ ## state) { \
- sm->changed = TRUE; \
- wpa_printf(MSG_DEBUG, "EAPOL: " #machine " entering state " #state); \
-} \
-sm->machine ## _state = machine ## _ ## state;
-
-#define SM_ENTER(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 0)
-#define SM_ENTER_GLOBAL(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 1)
-
-#define SM_STEP(machine) \
-static void sm_ ## machine ## _Step(struct eapol_sm *sm)
-
-#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
-
-
/* Port Timers state machine - implemented as a function that will be called
* once a second as a registered event loop timeout */
static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
@@ -537,6 +524,20 @@ SM_STEP(SUPP_BE)
case SUPP_BE_UNKNOWN:
break;
case SUPP_BE_REQUEST:
+ /*
+ * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
+ * and SUCCESS based on eapFail and eapSuccess, respectively.
+ * However, IEEE Std 802.1X-2004 is also specifying that
+ * eapNoResp should be set in conjuction with eapSuccess and
+ * eapFail which would mean that more than one of the
+ * transitions here would be activated at the same time.
+ * Skipping RESPONSE and/or RECEIVE states in these cases can
+ * cause problems and the direct transitions to do not seem
+ * correct. Because of this, the conditions for these
+ * transitions are verified only after eapNoResp. They are
+ * unlikely to be used since eapNoResp should always be set if
+ * either of eapSuccess or eapFail is set.
+ */
if (sm->eapResp && sm->eapNoResp) {
wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
"eapResp and eapNoResp set?!");
@@ -545,6 +546,10 @@ SM_STEP(SUPP_BE)
SM_ENTER(SUPP_BE, RESPONSE);
else if (sm->eapNoResp)
SM_ENTER(SUPP_BE, RECEIVE);
+ else if (sm->eapFail)
+ SM_ENTER(SUPP_BE, FAIL);
+ else if (sm->eapSuccess)
+ SM_ENTER(SUPP_BE, SUCCESS);
break;
case SUPP_BE_RESPONSE:
SM_ENTER(SUPP_BE, RECEIVE);
@@ -664,7 +669,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
}
sign_key_len = 16;
encr_key_len = 16;
- memcpy(keydata.sign_key, keydata.encr_key, 16);
+ os_memcpy(keydata.sign_key, keydata.encr_key, 16);
} else if (res) {
wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
"data for decrypting EAPOL-Key keys (res=%d)", res);
@@ -673,8 +678,8 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
/* The key replay_counter must increase when same master key */
if (sm->replay_counter_valid &&
- memcmp(sm->last_replay_counter, key->replay_counter,
- IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
+ os_memcmp(sm->last_replay_counter, key->replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
"not increase - ignoring key");
wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
@@ -686,17 +691,17 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
}
/* Verify key signature (HMAC-MD5) */
- memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
- memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
+ os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
+ os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
hmac_md5(keydata.sign_key, sign_key_len,
sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
key->key_signature);
- if (memcmp(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN)
- != 0) {
+ if (os_memcmp(orig_key_sign, key->key_signature,
+ IEEE8021X_KEY_SIGN_LEN) != 0) {
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
"EAPOL-Key packet");
- memcpy(key->key_signature, orig_key_sign,
- IEEE8021X_KEY_SIGN_LEN);
+ os_memcpy(key->key_signature, orig_key_sign,
+ IEEE8021X_KEY_SIGN_LEN);
return;
}
wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
@@ -708,10 +713,10 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
return;
}
if (key_len == rx_key_length) {
- memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
- memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
- encr_key_len);
- memcpy(datakey, key + 1, key_len);
+ os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
+ os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
+ encr_key_len);
+ os_memcpy(datakey, key + 1, key_len);
rc4(datakey, key_len, ekey,
IEEE8021X_KEY_IV_LEN + encr_key_len);
wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
@@ -727,7 +732,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
* seems to interoperate with Authenticators.
*/
key_len = rx_key_length;
- memcpy(datakey, keydata.encr_key, key_len);
+ os_memcpy(datakey, keydata.encr_key, key_len);
wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
"material data encryption key",
datakey, key_len);
@@ -738,8 +743,8 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
}
sm->replay_counter_valid = TRUE;
- memcpy(sm->last_replay_counter, key->replay_counter,
- IEEE8021X_REPLAY_COUNTER_LEN);
+ os_memcpy(sm->last_replay_counter, key->replay_counter,
+ IEEE8021X_REPLAY_COUNTER_LEN);
wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
"len %d",
@@ -803,7 +808,7 @@ static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
IEEE802_1X_TYPE_EAP_PACKET, resp, resp_len);
/* eapRespData is not used anymore, so free it here */
- free(resp);
+ os_free(resp);
if (sm->initial_req)
sm->dot1xSuppEapolReqIdFramesRx++;
@@ -818,9 +823,9 @@ static void eapol_sm_abortSupp(struct eapol_sm *sm)
{
/* release system resources that may have been allocated for the
* authentication session */
- free(sm->last_rx_key);
+ os_free(sm->last_rx_key);
sm->last_rx_key = NULL;
- free(sm->eapReqData);
+ os_free(sm->eapReqData);
sm->eapReqData = NULL;
eap_sm_abort(sm->eap);
}
@@ -855,6 +860,8 @@ void eapol_sm_step(struct eapol_sm *sm)
SM_STEP_RUN(SUPP_BE);
if (eap_sm_step(sm->eap))
sm->changed = TRUE;
+ if (!sm->changed)
+ break;
}
if (sm->changed) {
@@ -872,6 +879,7 @@ void eapol_sm_step(struct eapol_sm *sm)
}
+#ifdef CONFIG_CTRL_IFACE
static const char *eapol_supp_pae_state(int state)
{
switch (state) {
@@ -927,8 +935,10 @@ static const char * eapol_port_status(PortStatus status)
else
return "Unauthorized";
}
+#endif /* CONFIG_CTRL_IFACE */
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
static const char * eapol_port_control(PortControl ctrl)
{
switch (ctrl) {
@@ -942,6 +952,7 @@ static const char * eapol_port_control(PortControl ctrl)
return "Unknown";
}
}
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
/**
@@ -971,6 +982,7 @@ void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
}
+#ifdef CONFIG_CTRL_IFACE
/**
* eapol_sm_get_status - Get EAPOL state machine status
* @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
@@ -987,30 +999,35 @@ void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
int verbose)
{
- int len;
+ int len, ret;
if (sm == NULL)
return 0;
- len = snprintf(buf, buflen,
- "Supplicant PAE state=%s\n"
- "suppPortStatus=%s\n",
- eapol_supp_pae_state(sm->SUPP_PAE_state),
- eapol_port_status(sm->suppPortStatus));
+ len = os_snprintf(buf, buflen,
+ "Supplicant PAE state=%s\n"
+ "suppPortStatus=%s\n",
+ eapol_supp_pae_state(sm->SUPP_PAE_state),
+ eapol_port_status(sm->suppPortStatus));
+ if (len < 0 || (size_t) len >= buflen)
+ return 0;
if (verbose) {
- len += snprintf(buf + len, buflen - len,
- "heldPeriod=%u\n"
- "authPeriod=%u\n"
- "startPeriod=%u\n"
- "maxStart=%u\n"
- "portControl=%s\n"
- "Supplicant Backend state=%s\n",
- sm->heldPeriod,
- sm->authPeriod,
- sm->startPeriod,
- sm->maxStart,
- eapol_port_control(sm->portControl),
- eapol_supp_be_state(sm->SUPP_BE_state));
+ ret = os_snprintf(buf + len, buflen - len,
+ "heldPeriod=%u\n"
+ "authPeriod=%u\n"
+ "startPeriod=%u\n"
+ "maxStart=%u\n"
+ "portControl=%s\n"
+ "Supplicant Backend state=%s\n",
+ sm->heldPeriod,
+ sm->authPeriod,
+ sm->startPeriod,
+ sm->maxStart,
+ eapol_port_control(sm->portControl),
+ eapol_supp_be_state(sm->SUPP_BE_state));
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
}
len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
@@ -1033,49 +1050,63 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
*/
int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
{
- int len;
+ size_t len;
+ int ret;
+
if (sm == NULL)
return 0;
- len = snprintf(buf, buflen,
- "dot1xSuppPaeState=%d\n"
- "dot1xSuppHeldPeriod=%u\n"
- "dot1xSuppAuthPeriod=%u\n"
- "dot1xSuppStartPeriod=%u\n"
- "dot1xSuppMaxStart=%u\n"
- "dot1xSuppSuppControlledPortStatus=%s\n"
- "dot1xSuppBackendPaeState=%d\n"
- "dot1xSuppEapolFramesRx=%u\n"
- "dot1xSuppEapolFramesTx=%u\n"
- "dot1xSuppEapolStartFramesTx=%u\n"
- "dot1xSuppEapolLogoffFramesTx=%u\n"
- "dot1xSuppEapolRespFramesTx=%u\n"
- "dot1xSuppEapolReqIdFramesRx=%u\n"
- "dot1xSuppEapolReqFramesRx=%u\n"
- "dot1xSuppInvalidEapolFramesRx=%u\n"
- "dot1xSuppEapLengthErrorFramesRx=%u\n"
- "dot1xSuppLastEapolFrameVersion=%u\n"
- "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
- sm->SUPP_PAE_state,
- sm->heldPeriod,
- sm->authPeriod,
- sm->startPeriod,
- sm->maxStart,
- sm->suppPortStatus == Authorized ?
- "Authorized" : "Unauthorized",
- sm->SUPP_BE_state,
- sm->dot1xSuppEapolFramesRx,
- sm->dot1xSuppEapolFramesTx,
- sm->dot1xSuppEapolStartFramesTx,
- sm->dot1xSuppEapolLogoffFramesTx,
- sm->dot1xSuppEapolRespFramesTx,
- sm->dot1xSuppEapolReqIdFramesRx,
- sm->dot1xSuppEapolReqFramesRx,
- sm->dot1xSuppInvalidEapolFramesRx,
- sm->dot1xSuppEapLengthErrorFramesRx,
- sm->dot1xSuppLastEapolFrameVersion,
- MAC2STR(sm->dot1xSuppLastEapolFrameSource));
+ ret = os_snprintf(buf, buflen,
+ "dot1xSuppPaeState=%d\n"
+ "dot1xSuppHeldPeriod=%u\n"
+ "dot1xSuppAuthPeriod=%u\n"
+ "dot1xSuppStartPeriod=%u\n"
+ "dot1xSuppMaxStart=%u\n"
+ "dot1xSuppSuppControlledPortStatus=%s\n"
+ "dot1xSuppBackendPaeState=%d\n",
+ sm->SUPP_PAE_state,
+ sm->heldPeriod,
+ sm->authPeriod,
+ sm->startPeriod,
+ sm->maxStart,
+ sm->suppPortStatus == Authorized ?
+ "Authorized" : "Unauthorized",
+ sm->SUPP_BE_state);
+
+ if (ret < 0 || (size_t) ret >= buflen)
+ return 0;
+ len = ret;
+
+ ret = os_snprintf(buf + len, buflen - len,
+ "dot1xSuppEapolFramesRx=%u\n"
+ "dot1xSuppEapolFramesTx=%u\n"
+ "dot1xSuppEapolStartFramesTx=%u\n"
+ "dot1xSuppEapolLogoffFramesTx=%u\n"
+ "dot1xSuppEapolRespFramesTx=%u\n"
+ "dot1xSuppEapolReqIdFramesRx=%u\n"
+ "dot1xSuppEapolReqFramesRx=%u\n"
+ "dot1xSuppInvalidEapolFramesRx=%u\n"
+ "dot1xSuppEapLengthErrorFramesRx=%u\n"
+ "dot1xSuppLastEapolFrameVersion=%u\n"
+ "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
+ sm->dot1xSuppEapolFramesRx,
+ sm->dot1xSuppEapolFramesTx,
+ sm->dot1xSuppEapolStartFramesTx,
+ sm->dot1xSuppEapolLogoffFramesTx,
+ sm->dot1xSuppEapolRespFramesTx,
+ sm->dot1xSuppEapolReqIdFramesRx,
+ sm->dot1xSuppEapolReqFramesRx,
+ sm->dot1xSuppInvalidEapolFramesRx,
+ sm->dot1xSuppEapLengthErrorFramesRx,
+ sm->dot1xSuppLastEapolFrameVersion,
+ MAC2STR(sm->dot1xSuppLastEapolFrameSource));
+
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
+
return len;
}
+#endif /* CONFIG_CTRL_IFACE */
/**
@@ -1092,8 +1123,9 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
{
const struct ieee802_1x_hdr *hdr;
const struct ieee802_1x_eapol_key *key;
- int plen, data_len;
+ int data_len;
int res = 1;
+ size_t plen;
if (sm == NULL)
return 0;
@@ -1104,7 +1136,7 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
}
hdr = (const struct ieee802_1x_hdr *) buf;
sm->dot1xSuppLastEapolFrameVersion = hdr->version;
- memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
+ os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
if (hdr->version < EAPOL_VERSION) {
/* TODO: backwards compatibility */
}
@@ -1124,14 +1156,14 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
*/
eapol_sm_abort_cached(sm);
}
- free(sm->eapReqData);
+ os_free(sm->eapReqData);
sm->eapReqDataLen = plen;
- sm->eapReqData = malloc(sm->eapReqDataLen);
+ sm->eapReqData = os_malloc(sm->eapReqDataLen);
if (sm->eapReqData) {
wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
"frame");
- memcpy(sm->eapReqData, (u8 *) (hdr + 1),
- sm->eapReqDataLen);
+ os_memcpy(sm->eapReqData, (u8 *) (hdr + 1),
+ sm->eapReqDataLen);
sm->eapolEap = TRUE;
eapol_sm_step(sm);
}
@@ -1156,12 +1188,12 @@ int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
"EAPOL-Key type %d", key->type);
break;
}
- free(sm->last_rx_key);
- sm->last_rx_key = malloc(data_len);
+ os_free(sm->last_rx_key);
+ sm->last_rx_key = os_malloc(data_len);
if (sm->last_rx_key) {
wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
"frame");
- memcpy(sm->last_rx_key, buf, data_len);
+ os_memcpy(sm->last_rx_key, buf, data_len);
sm->last_rx_key_len = data_len;
sm->rxKey = TRUE;
eapol_sm_step(sm);
@@ -1330,7 +1362,7 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
return -1;
if (len > eap_len)
return eap_len;
- memcpy(key, eap_key, len);
+ os_memcpy(key, eap_key, len);
return 0;
}
@@ -1398,7 +1430,13 @@ static void eapol_sm_abort_cached(struct eapol_sm *sm)
sm->cached_pmk = FALSE;
sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
sm->suppPortStatus = Unauthorized;
- sm->eapRestart= TRUE;
+
+ /* Make sure we do not start sending EAPOL-Start frames first, but
+ * instead move to RESTART state to start EAPOL authentication. */
+ sm->startWhen = 3;
+
+ if (sm->ctx->aborted_cached)
+ sm->ctx->aborted_cached(sm->ctx->ctx);
}
@@ -1505,6 +1543,17 @@ void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
}
+/**
+ * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ */
+void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
+{
+ if (sm)
+ eap_invalidate_cached_session(sm->eap);
+}
+
+
static struct wpa_ssid * eapol_sm_get_config(void *ctx)
{
struct eapol_sm *sm = ctx;
@@ -1638,16 +1687,32 @@ eapol_sm_get_config_blob(void *ctx, const char *name)
}
+static void eapol_sm_notify_pending(void *ctx)
+{
+ struct eapol_sm *sm = ctx;
+ if (sm == NULL)
+ return;
+ if (sm->eapReqData && !sm->eapReq) {
+ wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
+ "state machine - retrying pending EAP Request");
+ sm->eapolEap = TRUE;
+ sm->eapReq = TRUE;
+ eapol_sm_step(sm);
+ }
+}
+
+
static struct eapol_callbacks eapol_cb =
{
- .get_config = eapol_sm_get_config,
- .get_bool = eapol_sm_get_bool,
- .set_bool = eapol_sm_set_bool,
- .get_int = eapol_sm_get_int,
- .set_int = eapol_sm_set_int,
- .get_eapReqData = eapol_sm_get_eapReqData,
- .set_config_blob = eapol_sm_set_config_blob,
- .get_config_blob = eapol_sm_get_config_blob,
+ eapol_sm_get_config,
+ eapol_sm_get_bool,
+ eapol_sm_set_bool,
+ eapol_sm_get_int,
+ eapol_sm_set_int,
+ eapol_sm_get_eapReqData,
+ eapol_sm_set_config_blob,
+ eapol_sm_get_config_blob,
+ eapol_sm_notify_pending
};
@@ -1663,10 +1728,9 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
struct eapol_sm *sm;
struct eap_config conf;
- sm = malloc(sizeof(*sm));
+ sm = os_zalloc(sizeof(*sm));
if (sm == NULL)
return NULL;
- memset(sm, 0, sizeof(*sm));
sm->ctx = ctx;
sm->portControl = Auto;
@@ -1679,14 +1743,14 @@ struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
/* Supplicant Backend state machine */
sm->authPeriod = 30;
- memset(&conf, 0, sizeof(conf));
+ os_memset(&conf, 0, sizeof(conf));
conf.opensc_engine_path = ctx->opensc_engine_path;
conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
conf.pkcs11_module_path = ctx->pkcs11_module_path;
sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
if (sm->eap == NULL) {
- free(sm);
+ os_free(sm);
return NULL;
}
@@ -1715,8 +1779,8 @@ void eapol_sm_deinit(struct eapol_sm *sm)
eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
eap_sm_deinit(sm->eap);
- free(sm->last_rx_key);
- free(sm->eapReqData);
- free(sm->ctx);
- free(sm);
+ os_free(sm->last_rx_key);
+ os_free(sm->eapReqData);
+ os_free(sm->ctx);
+ os_free(sm);
}
diff --git a/contrib/wpa_supplicant/eapol_sm.h b/contrib/wpa_supplicant/eapol_sm.h
index 1d44a54130d4..927bfcb6595b 100644
--- a/contrib/wpa_supplicant/eapol_sm.h
+++ b/contrib/wpa_supplicant/eapol_sm.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / EAPOL state machines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -168,6 +168,12 @@ struct eapol_ctx {
const char *name);
/**
+ * aborted_cached - Notify that cached PMK attempt was aborted
+ * @ctx: Callback context (ctx)
+ */
+ void (*aborted_cached)(void *ctx);
+
+ /**
* opensc_engine_path - Path to the OpenSSL engine for opensc
*
* This is an OpenSSL specific configuration option for loading OpenSC
@@ -224,6 +230,7 @@ void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm);
void eapol_sm_notify_ctrl_response(struct eapol_sm *sm);
void eapol_sm_request_reauth(struct eapol_sm *sm);
void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm);
+void eapol_sm_invalidate_cached_session(struct eapol_sm *sm);
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
@@ -307,6 +314,9 @@ static inline void eapol_sm_request_reauth(struct eapol_sm *sm)
static inline void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
{
}
+static inline void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
+{
+}
#endif /* IEEE8021X_EAPOL */
#endif /* EAPOL_SM_H */
diff --git a/contrib/wpa_supplicant/eapol_test.c b/contrib/wpa_supplicant/eapol_test.c
index 1bc34a3fcd4f..ac3213b19274 100644
--- a/contrib/wpa_supplicant/eapol_test.c
+++ b/contrib/wpa_supplicant/eapol_test.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - test code
- * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,22 +15,13 @@
* Not used in production version.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <string.h>
-#include <signal.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
#include <assert.h>
#include "common.h"
#include "config.h"
#include "eapol_sm.h"
+#include "eap.h"
#include "eloop.h"
#include "wpa.h"
#include "eap_i.h"
@@ -46,7 +37,7 @@
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
-struct wpa_driver_ops *wpa_supplicant_drivers[] = { };
+struct wpa_driver_ops *wpa_supplicant_drivers[] = { NULL };
struct eapol_test_data {
@@ -74,6 +65,9 @@ struct eapol_test_data {
u8 *eap_identity;
size_t eap_identity_len;
+
+ char *connect_info;
+ u8 own_addr[ETH_ALEN];
};
static struct eapol_test_data eapol_test;
@@ -82,15 +76,15 @@ static struct eapol_test_data eapol_test;
static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx);
-void hostapd_logger(void *ctx, u8 *addr, unsigned int module, int level,
+void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
char *fmt, ...)
{
char *format;
int maxlen;
va_list ap;
- maxlen = strlen(fmt) + 100;
- format = malloc(maxlen);
+ maxlen = os_strlen(fmt) + 100;
+ format = os_malloc(maxlen);
if (!format)
return;
@@ -98,15 +92,15 @@ void hostapd_logger(void *ctx, u8 *addr, unsigned int module, int level,
if (addr)
- snprintf(format, maxlen, "STA " MACSTR ": %s",
- MAC2STR(addr), fmt);
+ os_snprintf(format, maxlen, "STA " MACSTR ": %s",
+ MAC2STR(addr), fmt);
else
- snprintf(format, maxlen, "%s", fmt);
+ os_snprintf(format, maxlen, "%s", fmt);
vprintf(format, ap);
printf("\n");
- free(format);
+ os_free(format);
va_end(ap);
}
@@ -119,7 +113,7 @@ const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
return NULL;
if (addr->af == AF_INET) {
- snprintf(buf, buflen, "%s", inet_ntoa(addr->u.v4));
+ os_snprintf(buf, buflen, "%s", inet_ntoa(addr->u.v4));
} else {
buf[0] = '\0';
}
@@ -134,6 +128,12 @@ const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
}
+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b)
+{
+ return 0;
+}
+
+
static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
const u8 *eap, size_t len)
{
@@ -160,11 +160,11 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE &&
pos[0] == EAP_TYPE_IDENTITY) {
pos++;
- free(e->eap_identity);
+ os_free(e->eap_identity);
e->eap_identity_len = len - sizeof(*hdr) - 1;
- e->eap_identity = malloc(e->eap_identity_len);
+ e->eap_identity = os_malloc(e->eap_identity_len);
if (e->eap_identity) {
- memcpy(e->eap_identity, pos, e->eap_identity_len);
+ os_memcpy(e->eap_identity, pos, e->eap_identity_len);
wpa_hexdump(MSG_DEBUG, "Learned identity from "
"EAP-Response-Identity",
e->eap_identity, e->eap_identity_len);
@@ -184,10 +184,10 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
goto fail;
}
- snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
- MAC2STR(e->wpa_s->own_addr));
+ os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+ MAC2STR(e->wpa_s->own_addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
- (u8 *) buf, strlen(buf))) {
+ (u8 *) buf, os_strlen(buf))) {
printf("Could not add Calling-Station-Id\n");
goto fail;
}
@@ -206,9 +206,9 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
goto fail;
}
- snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
+ os_snprintf(buf, sizeof(buf), "%s", e->connect_info);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
- (u8 *) buf, strlen(buf))) {
+ (u8 *) buf, os_strlen(buf))) {
printf("Could not add Connect-Info\n");
goto fail;
}
@@ -240,7 +240,7 @@ static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
fail:
radius_msg_free(msg);
- free(msg);
+ os_free(msg);
}
@@ -295,23 +295,27 @@ static int eapol_test_compare_pmk(struct eapol_test_data *e)
if (eapol_sm_get_key(e->wpa_s->eapol, pmk, PMK_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "PMK from EAPOL", pmk, PMK_LEN);
- if (memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0)
+ if (os_memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0) {
printf("WARNING: PMK mismatch\n");
- else if (e->radius_access_accept_received)
+ wpa_hexdump(MSG_DEBUG, "PMK from AS",
+ e->authenticator_pmk, PMK_LEN);
+ } else if (e->radius_access_accept_received)
ret = 0;
} else if (e->authenticator_pmk_len == 16 &&
eapol_sm_get_key(e->wpa_s->eapol, pmk, 16) == 0) {
wpa_hexdump(MSG_DEBUG, "LEAP PMK from EAPOL", pmk, 16);
- if (memcmp(pmk, e->authenticator_pmk, 16) != 0)
+ if (os_memcmp(pmk, e->authenticator_pmk, 16) != 0) {
printf("WARNING: PMK mismatch\n");
- else if (e->radius_access_accept_received)
+ wpa_hexdump(MSG_DEBUG, "PMK from AS",
+ e->authenticator_pmk, 16);
+ } else if (e->radius_access_accept_received)
ret = 0;
} else if (e->radius_access_accept_received && e->no_mppe_keys) {
/* No keying material expected */
ret = 0;
}
- if (ret)
+ if (ret && !e->no_mppe_keys)
e->num_mppe_mismatch++;
else if (!e->no_mppe_keys)
e->num_mppe_ok++;
@@ -340,12 +344,11 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
struct eapol_config eapol_conf;
struct eapol_ctx *ctx;
- ctx = malloc(sizeof(*ctx));
+ ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL) {
printf("Failed to allocate EAPOL context.\n");
return -1;
}
- memset(ctx, 0, sizeof(*ctx));
ctx->ctx = wpa_s;
ctx->msg_ctx = wpa_s;
ctx->scard_ctx = wpa_s->scard;
@@ -363,13 +366,13 @@ static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
- free(ctx);
+ os_free(ctx);
printf("Failed to initialize EAPOL state machines.\n");
return -1;
}
wpa_s->current_ssid = ssid;
- memset(&eapol_conf, 0, sizeof(eapol_conf));
+ os_memset(&eapol_conf, 0, sizeof(eapol_conf));
eapol_conf.accept_802_1x_keys = 1;
eapol_conf.required_keys = 0;
eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
@@ -390,23 +393,26 @@ static void test_eapol_clean(struct eapol_test_data *e,
struct wpa_supplicant *wpa_s)
{
radius_client_deinit(e->radius);
- free(e->last_eap_radius);
+ os_free(e->last_eap_radius);
if (e->last_recv_radius) {
radius_msg_free(e->last_recv_radius);
- free(e->last_recv_radius);
+ os_free(e->last_recv_radius);
}
- free(e->eap_identity);
+ os_free(e->eap_identity);
e->eap_identity = NULL;
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
if (e->radius_conf && e->radius_conf->auth_server) {
- free(e->radius_conf->auth_server->shared_secret);
- free(e->radius_conf->auth_server);
+ os_free(e->radius_conf->auth_server->shared_secret);
+ os_free(e->radius_conf->auth_server);
}
- free(e->radius_conf);
+ os_free(e->radius_conf);
e->radius_conf = NULL;
scard_deinit(wpa_s->scard);
- wpa_supplicant_ctrl_iface_deinit(wpa_s);
+ if (wpa_s->ctrl_iface) {
+ wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
+ }
wpa_config_free(wpa_s->conf);
}
@@ -458,6 +464,9 @@ static char *eap_type_text(u8 type)
case EAP_TYPE_GTC: return "GTC";
case EAP_TYPE_MD5: return "MD5";
case EAP_TYPE_OTP: return "OTP";
+ case EAP_TYPE_FAST: return "FAST";
+ case EAP_TYPE_SAKE: return "SAKE";
+ case EAP_TYPE_PSK: return "PSK";
default: return "Unknown";
}
}
@@ -484,7 +493,7 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
* attribute */
wpa_printf(MSG_DEBUG, "could not extract "
"EAP-Message from RADIUS message");
- free(e->last_eap_radius);
+ os_free(e->last_eap_radius);
e->last_eap_radius = NULL;
e->last_eap_radius_len = 0;
return;
@@ -493,7 +502,7 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
if (len < sizeof(*hdr)) {
wpa_printf(MSG_DEBUG, "too short EAP packet "
"received from authentication server");
- free(eap);
+ os_free(eap);
return;
}
@@ -503,26 +512,26 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
hdr = (struct eap_hdr *) eap;
switch (hdr->code) {
case EAP_CODE_REQUEST:
- snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
- eap_type >= 0 ? eap_type_text(eap_type) : "??",
- eap_type);
+ os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
+ eap_type >= 0 ? eap_type_text(eap_type) : "??",
+ eap_type);
break;
case EAP_CODE_RESPONSE:
- snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
- eap_type >= 0 ? eap_type_text(eap_type) : "??",
- eap_type);
+ os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
+ eap_type >= 0 ? eap_type_text(eap_type) : "??",
+ eap_type);
break;
case EAP_CODE_SUCCESS:
- snprintf(buf, sizeof(buf), "EAP Success");
+ os_snprintf(buf, sizeof(buf), "EAP Success");
/* LEAP uses EAP Success within an authentication, so must not
* stop here with eloop_terminate(); */
break;
case EAP_CODE_FAILURE:
- snprintf(buf, sizeof(buf), "EAP Failure");
+ os_snprintf(buf, sizeof(buf), "EAP Failure");
eloop_terminate();
break;
default:
- snprintf(buf, sizeof(buf), "unknown EAP code");
+ os_snprintf(buf, sizeof(buf), "unknown EAP code");
wpa_hexdump(MSG_DEBUG, "Decapsulated EAP packet", eap, len);
break;
}
@@ -532,21 +541,21 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
/* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
- free(e->last_eap_radius);
+ os_free(e->last_eap_radius);
e->last_eap_radius = eap;
e->last_eap_radius_len = len;
{
- struct ieee802_1x_hdr *hdr;
- hdr = malloc(sizeof(*hdr) + len);
- assert(hdr != NULL);
- hdr->version = EAPOL_VERSION;
- hdr->type = IEEE802_1X_TYPE_EAP_PACKET;
- hdr->length = htons(len);
- memcpy((u8 *) (hdr + 1), eap, len);
+ struct ieee802_1x_hdr *dot1x;
+ dot1x = os_malloc(sizeof(*dot1x) + len);
+ assert(dot1x != NULL);
+ dot1x->version = EAPOL_VERSION;
+ dot1x->type = IEEE802_1X_TYPE_EAP_PACKET;
+ dot1x->length = htons(len);
+ os_memcpy((u8 *) (dot1x + 1), eap, len);
eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
- (u8 *) hdr, sizeof(*hdr) + len);
- free(hdr);
+ (u8 *) dot1x, sizeof(*dot1x) + len);
+ os_free(dot1x);
}
}
@@ -560,7 +569,7 @@ static void ieee802_1x_get_keys(struct eapol_test_data *e,
keys = radius_msg_get_ms_keys(msg, req, shared_secret,
shared_secret_len);
if (keys && keys->send == NULL && keys->recv == NULL) {
- free(keys);
+ os_free(keys);
keys = radius_msg_get_cisco_keys(msg, req, shared_secret,
shared_secret_len);
}
@@ -576,13 +585,13 @@ static void ieee802_1x_get_keys(struct eapol_test_data *e,
e->authenticator_pmk_len =
keys->recv_len > PMK_LEN ? PMK_LEN :
keys->recv_len;
- memcpy(e->authenticator_pmk, keys->recv,
- e->authenticator_pmk_len);
+ os_memcpy(e->authenticator_pmk, keys->recv,
+ e->authenticator_pmk_len);
}
- free(keys->send);
- free(keys->recv);
- free(keys);
+ os_free(keys->send);
+ os_free(keys->recv);
+ os_free(keys);
}
}
@@ -623,7 +632,7 @@ ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
if (e->last_recv_radius) {
radius_msg_free(e->last_recv_radius);
- free(e->last_recv_radius);
+ os_free(e->last_recv_radius);
}
e->last_recv_radius = msg;
@@ -659,18 +668,16 @@ static void wpa_init_conf(struct eapol_test_data *e,
int res;
wpa_s->bssid[5] = 1;
- wpa_s->own_addr[5] = 2;
+ os_memcpy(wpa_s->own_addr, e->own_addr, ETH_ALEN);
e->own_ip_addr.s_addr = htonl((127 << 24) | 1);
- strncpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname));
+ os_strncpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname));
- e->radius_conf = malloc(sizeof(struct hostapd_radius_servers));
+ e->radius_conf = os_zalloc(sizeof(struct hostapd_radius_servers));
assert(e->radius_conf != NULL);
- memset(e->radius_conf, 0, sizeof(struct hostapd_radius_servers));
e->radius_conf->num_auth_servers = 1;
- as = malloc(sizeof(struct hostapd_radius_server));
+ as = os_zalloc(sizeof(struct hostapd_radius_server));
assert(as != NULL);
- memset(as, 0, sizeof(*as));
-#ifdef CONFIG_NATIVE_WINDOWS
+#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
{
int a[4];
u8 *pos;
@@ -681,13 +688,13 @@ static void wpa_init_conf(struct eapol_test_data *e,
*pos++ = a[2];
*pos++ = a[3];
}
-#else /* CONFIG_NATIVE_WINDOWS */
+#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
inet_aton(authsrv, &as->addr.u.v4);
-#endif /* CONFIG_NATIVE_WINDOWS */
+#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
as->addr.af = AF_INET;
as->port = port;
- as->shared_secret = (u8 *) strdup(secret);
- as->shared_secret_len = strlen(secret);
+ as->shared_secret = (u8 *) os_strdup(secret);
+ as->shared_secret_len = os_strlen(secret);
e->radius_conf->auth_server = as;
e->radius_conf->auth_servers = as;
e->radius_conf->msg_dumps = 1;
@@ -706,7 +713,7 @@ static int scard_test(void)
struct scard_data *scard;
size_t len;
char imsi[20];
- unsigned char rand[16];
+ unsigned char _rand[16];
#ifdef PCSC_FUNCS
unsigned char sres[4];
unsigned char kc[8];
@@ -715,7 +722,8 @@ static int scard_test(void)
unsigned char rand_[num_triplets][16];
unsigned char sres_[num_triplets][4];
unsigned char kc_[num_triplets][8];
- int i, j, res;
+ int i, res;
+ size_t j;
#define AKA_RAND_LEN 16
#define AKA_AUTN_LEN 16
@@ -746,16 +754,16 @@ static int scard_test(void)
wpa_hexdump_ascii(MSG_DEBUG, "SCARD: IMSI", (u8 *) imsi, len);
/* NOTE: Permanent Username: 1 | IMSI */
- memset(rand, 0, sizeof(rand));
- if (scard_gsm_auth(scard, rand, sres, kc))
+ os_memset(_rand, 0, sizeof(_rand));
+ if (scard_gsm_auth(scard, _rand, sres, kc))
goto failed;
- memset(rand, 0xff, sizeof(rand));
- if (scard_gsm_auth(scard, rand, sres, kc))
+ os_memset(_rand, 0xff, sizeof(_rand));
+ if (scard_gsm_auth(scard, _rand, sres, kc))
goto failed;
for (i = 0; i < num_triplets; i++) {
- memset(rand_[i], i, sizeof(rand_[i]));
+ os_memset(rand_[i], i, sizeof(rand_[i]));
if (scard_gsm_auth(scard, rand_[i], sres_[i], kc_[i]))
goto failed;
}
@@ -779,9 +787,9 @@ static int scard_test(void)
wpa_printf(MSG_DEBUG, "Trying to use UMTS authentication");
/* seq 39 (0x28) */
- memset(aka_rand, 0xaa, 16);
- memcpy(aka_autn, "\x86\x71\x31\xcb\xa2\xfc\x61\xdf"
- "\xa3\xb3\x97\x9d\x07\x32\xa2\x12", 16);
+ os_memset(aka_rand, 0xaa, 16);
+ os_memcpy(aka_autn, "\x86\x71\x31\xcb\xa2\xfc\x61\xdf"
+ "\xa3\xb3\x97\x9d\x07\x32\xa2\x12", 16);
res = scard_umts_auth(scard, aka_rand, aka_autn, aka_res, &aka_res_len,
aka_ik, aka_ck, aka_auts);
@@ -811,18 +819,19 @@ static int scard_get_triplets(int argc, char *argv[])
struct scard_data *scard;
size_t len;
char imsi[20];
- unsigned char rand[16];
+ unsigned char _rand[16];
unsigned char sres[4];
unsigned char kc[8];
int num_triplets;
- int i, j;
+ int i;
+ size_t j;
if (argc < 2 || ((num_triplets = atoi(argv[1])) <= 0)) {
printf("invalid parameters for sim command\n");
return -1;
}
- if (argc <= 2 || strcmp(argv[2], "debug") != 0) {
+ if (argc <= 2 || os_strcmp(argv[2], "debug") != 0) {
/* disable debug output */
wpa_debug_level = 99;
}
@@ -845,8 +854,8 @@ static int scard_get_triplets(int argc, char *argv[])
}
for (i = 0; i < num_triplets; i++) {
- memset(rand, i, sizeof(rand));
- if (scard_gsm_auth(scard, rand, sres, kc))
+ os_memset(_rand, i, sizeof(_rand));
+ if (scard_gsm_auth(scard, _rand, sres, kc))
break;
/* IMSI:Kc:SRES:RAND */
@@ -860,7 +869,7 @@ static int scard_get_triplets(int argc, char *argv[])
printf("%02X", sres[j]);
printf(":");
for (j = 0; j < 16; j++)
- printf("%02X", rand[j]);
+ printf("%02X", _rand[j]);
printf("\n");
}
@@ -883,11 +892,13 @@ static void usage(void)
{
printf("usage:\n"
"eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
- "[-s<AS secret>] [-r<count>]\n"
+ "[-s<AS secret>] \\\n"
+ " [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
+ " [-M<client MAC address>]\n"
"eapol_test scard\n"
"eapol_test sim <PIN> <num triplets> [debug]\n"
- "\n"
- "options:\n"
+ "\n");
+ printf("options:\n"
" -c<conf> = configuration file\n"
" -a<AS IP> = IP address of the authentication server, "
"default 127.0.0.1\n"
@@ -898,7 +909,13 @@ static void usage(void)
" -r<count> = number of re-authentications\n"
" -W = wait for a control interface monitor before starting\n"
" -S = save configuration after authentiation\n"
- " -n = no MPPE keys expected\n");
+ " -n = no MPPE keys expected\n"
+ " -t<timeout> = sets timeout in seconds (default: 30 s)\n"
+ " -C<Connect-Info> = RADIUS Connect-Info (default: "
+ "CONNECT 11Mbps 802.11b)\n"
+ " -M<client MAC address> = Set own MAC address "
+ "(Calling-Station-Id,\n"
+ " default: 02:00:00:00:00:01)\n");
}
@@ -910,22 +927,20 @@ int main(int argc, char *argv[])
int as_port = 1812;
char *as_secret = "radius";
char *conf = NULL;
+ int timeout = 30;
-#ifdef CONFIG_NATIVE_WINDOWS
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
- printf("Could not find a usable WinSock.dll\n");
+ if (os_program_init())
return -1;
- }
-#endif /* CONFIG_NATIVE_WINDOWS */
- memset(&eapol_test, 0, sizeof(eapol_test));
+ os_memset(&eapol_test, 0, sizeof(eapol_test));
+ eapol_test.connect_info = "CONNECT 11Mbps 802.11b";
+ os_memcpy(eapol_test.own_addr, "\x02\x00\x00\x00\x00\x01", ETH_ALEN);
wpa_debug_level = 0;
wpa_debug_show_keys = 1;
for (;;) {
- c = getopt(argc, argv, "a:c:np:r:s:SW");
+ c = getopt(argc, argv, "a:c:C:M:np:r:s:St:W");
if (c < 0)
break;
switch (c) {
@@ -935,6 +950,15 @@ int main(int argc, char *argv[])
case 'c':
conf = optarg;
break;
+ case 'C':
+ eapol_test.connect_info = optarg;
+ break;
+ case 'M':
+ if (hwaddr_aton(optarg, eapol_test.own_addr)) {
+ usage();
+ return -1;
+ }
+ break;
case 'n':
eapol_test.no_mppe_keys++;
break;
@@ -950,6 +974,9 @@ int main(int argc, char *argv[])
case 'S':
save_config++;
break;
+ case 't':
+ timeout = atoi(optarg);
+ break;
case 'W':
wait_for_monitor++;
break;
@@ -959,11 +986,11 @@ int main(int argc, char *argv[])
}
}
- if (argc > optind && strcmp(argv[optind], "scard") == 0) {
+ if (argc > optind && os_strcmp(argv[optind], "scard") == 0) {
return scard_test();
}
- if (argc > optind && strcmp(argv[optind], "sim") == 0) {
+ if (argc > optind && os_strcmp(argv[optind], "sim") == 0) {
return scard_get_triplets(argc - optind - 1,
&argv[optind + 1]);
}
@@ -974,9 +1001,17 @@ int main(int argc, char *argv[])
return -1;
}
- eloop_init(&wpa_s);
+ if (eap_peer_register_methods()) {
+ wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+ return -1;
+ }
- memset(&wpa_s, 0, sizeof(wpa_s));
+ if (eloop_init(&wpa_s)) {
+ wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+ return -1;
+ }
+
+ os_memset(&wpa_s, 0, sizeof(wpa_s));
eapol_test.wpa_s = &wpa_s;
wpa_s.conf = wpa_config_read(conf);
if (wpa_s.conf == NULL) {
@@ -989,7 +1024,8 @@ int main(int argc, char *argv[])
}
wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret);
- if (wpa_supplicant_ctrl_iface_init(&wpa_s)) {
+ wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
+ if (wpa_s.ctrl_iface == NULL) {
printf("Failed to initialize control interface '%s'.\n"
"You may have another eapol_test process already "
"running or the file was\n"
@@ -1007,18 +1043,17 @@ int main(int argc, char *argv[])
return -1;
if (wait_for_monitor)
- wpa_supplicant_ctrl_iface_wait(&wpa_s);
+ wpa_supplicant_ctrl_iface_wait(wpa_s.ctrl_iface);
- eloop_register_timeout(30, 0, eapol_test_timeout, &eapol_test, NULL);
+ eloop_register_timeout(timeout, 0, eapol_test_timeout, &eapol_test,
+ NULL);
eloop_register_timeout(0, 0, send_eap_request_identity, &wpa_s, NULL);
- eloop_register_signal(SIGINT, eapol_test_terminate, NULL);
- eloop_register_signal(SIGTERM, eapol_test_terminate, NULL);
-#ifndef CONFIG_NATIVE_WINDOWS
- eloop_register_signal(SIGHUP, eapol_test_terminate, NULL);
-#endif /* CONFIG_NATIVE_WINDOWS */
+ eloop_register_signal_terminate(eapol_test_terminate, NULL);
+ eloop_register_signal_reconfig(eapol_test_terminate, NULL);
eloop_run();
- if (eapol_test_compare_pmk(&eapol_test) == 0)
+ if (eapol_test_compare_pmk(&eapol_test) == 0 ||
+ eapol_test.no_mppe_keys)
ret = 0;
if (eapol_test.auth_timed_out)
ret = -2;
@@ -1030,6 +1065,8 @@ int main(int argc, char *argv[])
test_eapol_clean(&eapol_test, &wpa_s);
+ eap_peer_unregister_methods();
+
eloop_destroy();
printf("MPPE keys OK: %d mismatch: %d\n",
@@ -1041,9 +1078,7 @@ int main(int argc, char *argv[])
else
printf("SUCCESS\n");
-#ifdef CONFIG_NATIVE_WINDOWS
- WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
+ os_program_deinit();
return ret;
}
diff --git a/contrib/wpa_supplicant/eloop.c b/contrib/wpa_supplicant/eloop.c
index 39fccb8cfc59..232e7533cab2 100644
--- a/contrib/wpa_supplicant/eloop.c
+++ b/contrib/wpa_supplicant/eloop.c
@@ -1,6 +1,6 @@
/*
* Event loop based on select() loop
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,19 +12,9 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
+#include "includes.h"
-#ifdef CONFIG_NATIVE_WINDOWS
#include "common.h"
-#endif /* CONFIG_NATIVE_WINDOWS */
-
#include "eloop.h"
@@ -32,29 +22,38 @@ struct eloop_sock {
int sock;
void *eloop_data;
void *user_data;
- void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+ eloop_sock_handler handler;
};
struct eloop_timeout {
- struct timeval time;
+ struct os_time time;
void *eloop_data;
void *user_data;
- void (*handler)(void *eloop_ctx, void *sock_ctx);
+ eloop_timeout_handler handler;
struct eloop_timeout *next;
};
struct eloop_signal {
int sig;
void *user_data;
- void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+ eloop_signal_handler handler;
int signaled;
};
+struct eloop_sock_table {
+ int count;
+ struct eloop_sock *table;
+ int changed;
+};
+
struct eloop_data {
void *user_data;
- int max_sock, reader_count;
- struct eloop_sock *readers;
+ int max_sock;
+
+ struct eloop_sock_table readers;
+ struct eloop_sock_table writers;
+ struct eloop_sock_table exceptions;
struct eloop_timeout *timeout;
@@ -64,81 +63,181 @@ struct eloop_data {
int pending_terminate;
int terminate;
+ int reader_table_changed;
};
static struct eloop_data eloop;
-void eloop_init(void *user_data)
+int eloop_init(void *user_data)
{
- memset(&eloop, 0, sizeof(eloop));
+ os_memset(&eloop, 0, sizeof(eloop));
eloop.user_data = user_data;
+ return 0;
}
-int eloop_register_read_sock(int sock,
- void (*handler)(int sock, void *eloop_ctx,
- void *sock_ctx),
- void *eloop_data, void *user_data)
+static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
+ int sock, eloop_sock_handler handler,
+ void *eloop_data, void *user_data)
{
struct eloop_sock *tmp;
+ if (table == NULL)
+ return -1;
+
tmp = (struct eloop_sock *)
- realloc(eloop.readers,
- (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ os_realloc(table->table,
+ (table->count + 1) * sizeof(struct eloop_sock));
if (tmp == NULL)
return -1;
- tmp[eloop.reader_count].sock = sock;
- tmp[eloop.reader_count].eloop_data = eloop_data;
- tmp[eloop.reader_count].user_data = user_data;
- tmp[eloop.reader_count].handler = handler;
- eloop.reader_count++;
- eloop.readers = tmp;
+ tmp[table->count].sock = sock;
+ tmp[table->count].eloop_data = eloop_data;
+ tmp[table->count].user_data = user_data;
+ tmp[table->count].handler = handler;
+ table->count++;
+ table->table = tmp;
if (sock > eloop.max_sock)
eloop.max_sock = sock;
+ table->changed = 1;
return 0;
}
-void eloop_unregister_read_sock(int sock)
+static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
+ int sock)
{
int i;
- if (eloop.readers == NULL || eloop.reader_count == 0)
+ if (table == NULL || table->table == NULL || table->count == 0)
return;
- for (i = 0; i < eloop.reader_count; i++) {
- if (eloop.readers[i].sock == sock)
+ for (i = 0; i < table->count; i++) {
+ if (table->table[i].sock == sock)
break;
}
- if (i == eloop.reader_count)
+ if (i == table->count)
return;
- if (i != eloop.reader_count - 1) {
- memmove(&eloop.readers[i], &eloop.readers[i + 1],
- (eloop.reader_count - i - 1) *
- sizeof(struct eloop_sock));
+ if (i != table->count - 1) {
+ os_memmove(&table->table[i], &table->table[i + 1],
+ (table->count - i - 1) *
+ sizeof(struct eloop_sock));
+ }
+ table->count--;
+ table->changed = 1;
+}
+
+
+static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
+ fd_set *fds)
+{
+ int i;
+
+ FD_ZERO(fds);
+
+ if (table->table == NULL)
+ return;
+
+ for (i = 0; i < table->count; i++)
+ FD_SET(table->table[i].sock, fds);
+}
+
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
+ fd_set *fds)
+{
+ int i;
+
+ if (table == NULL || table->table == NULL)
+ return;
+
+ table->changed = 0;
+ for (i = 0; i < table->count; i++) {
+ if (FD_ISSET(table->table[i].sock, fds)) {
+ table->table[i].handler(table->table[i].sock,
+ table->table[i].eloop_data,
+ table->table[i].user_data);
+ if (table->changed)
+ break;
+ }
+ }
+}
+
+
+static void eloop_sock_table_destroy(struct eloop_sock_table *table)
+{
+ if (table)
+ os_free(table->table);
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+ void *eloop_data, void *user_data)
+{
+ return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
+ eloop_data, user_data);
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+ eloop_unregister_sock(sock, EVENT_TYPE_READ);
+}
+
+
+static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
+{
+ switch (type) {
+ case EVENT_TYPE_READ:
+ return &eloop.readers;
+ case EVENT_TYPE_WRITE:
+ return &eloop.writers;
+ case EVENT_TYPE_EXCEPTION:
+ return &eloop.exceptions;
}
- eloop.reader_count--;
+
+ return NULL;
+}
+
+
+int eloop_register_sock(int sock, eloop_event_type type,
+ eloop_sock_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_sock_table *table;
+
+ table = eloop_get_sock_table(type);
+ return eloop_sock_table_add_sock(table, sock, handler,
+ eloop_data, user_data);
+}
+
+
+void eloop_unregister_sock(int sock, eloop_event_type type)
+{
+ struct eloop_sock_table *table;
+
+ table = eloop_get_sock_table(type);
+ eloop_sock_table_remove_sock(table, sock);
}
int eloop_register_timeout(unsigned int secs, unsigned int usecs,
- void (*handler)(void *eloop_ctx, void *timeout_ctx),
+ eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
struct eloop_timeout *timeout, *tmp, *prev;
- timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+ timeout = os_malloc(sizeof(*timeout));
if (timeout == NULL)
return -1;
- gettimeofday(&timeout->time, NULL);
- timeout->time.tv_sec += secs;
- timeout->time.tv_usec += usecs;
- while (timeout->time.tv_usec >= 1000000) {
- timeout->time.tv_sec++;
- timeout->time.tv_usec -= 1000000;
+ os_get_time(&timeout->time);
+ timeout->time.sec += secs;
+ timeout->time.usec += usecs;
+ while (timeout->time.usec >= 1000000) {
+ timeout->time.sec++;
+ timeout->time.usec -= 1000000;
}
timeout->eloop_data = eloop_data;
timeout->user_data = user_data;
@@ -153,7 +252,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
prev = NULL;
tmp = eloop.timeout;
while (tmp != NULL) {
- if (timercmp(&timeout->time, &tmp->time, <))
+ if (os_time_before(&timeout->time, &tmp->time))
break;
prev = tmp;
tmp = tmp->next;
@@ -171,7 +270,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
}
-int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+int eloop_cancel_timeout(eloop_timeout_handler handler,
void *eloop_data, void *user_data)
{
struct eloop_timeout *timeout, *prev, *next;
@@ -191,7 +290,7 @@ int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
eloop.timeout = next;
else
prev->next = next;
- free(timeout);
+ os_free(timeout);
removed++;
} else
prev = timeout;
@@ -266,17 +365,15 @@ static void eloop_process_pending_signals(void)
}
-int eloop_register_signal(int sig,
- void (*handler)(int sig, void *eloop_ctx,
- void *signal_ctx),
+int eloop_register_signal(int sig, eloop_signal_handler handler,
void *user_data)
{
struct eloop_signal *tmp;
tmp = (struct eloop_signal *)
- realloc(eloop.signals,
- (eloop.signal_count + 1) *
- sizeof(struct eloop_signal));
+ os_realloc(eloop.signals,
+ (eloop.signal_count + 1) *
+ sizeof(struct eloop_signal));
if (tmp == NULL)
return -1;
@@ -292,41 +389,67 @@ int eloop_register_signal(int sig,
}
-void eloop_run(void)
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+ void *user_data)
{
- fd_set *rfds;
- int i, res;
- struct timeval tv, now;
+ int ret = eloop_register_signal(SIGINT, handler, user_data);
+ if (ret == 0)
+ ret = eloop_register_signal(SIGTERM, handler, user_data);
+ return ret;
+}
+
- rfds = malloc(sizeof(*rfds));
- if (rfds == NULL) {
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+ void *user_data)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ return 0;
+#else /* CONFIG_NATIVE_WINDOWS */
+ return eloop_register_signal(SIGHUP, handler, user_data);
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+void eloop_run(void)
+{
+ fd_set *rfds, *wfds, *efds;
+ int res;
+ struct timeval _tv;
+ struct os_time tv, now;
+
+ rfds = os_malloc(sizeof(*rfds));
+ wfds = os_malloc(sizeof(*wfds));
+ efds = os_malloc(sizeof(*efds));
+ if (rfds == NULL || wfds == NULL || efds == NULL) {
printf("eloop_run - malloc failed\n");
- return;
+ goto out;
}
while (!eloop.terminate &&
- (eloop.timeout || eloop.reader_count > 0)) {
+ (eloop.timeout || eloop.readers.count > 0 ||
+ eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
if (eloop.timeout) {
- gettimeofday(&now, NULL);
- if (timercmp(&now, &eloop.timeout->time, <))
- timersub(&eloop.timeout->time, &now, &tv);
+ os_get_time(&now);
+ if (os_time_before(&now, &eloop.timeout->time))
+ os_time_sub(&eloop.timeout->time, &now, &tv);
else
- tv.tv_sec = tv.tv_usec = 0;
+ tv.sec = tv.usec = 0;
#if 0
printf("next timeout in %lu.%06lu sec\n",
- tv.tv_sec, tv.tv_usec);
+ tv.sec, tv.usec);
#endif
+ _tv.tv_sec = tv.sec;
+ _tv.tv_usec = tv.usec;
}
- FD_ZERO(rfds);
- for (i = 0; i < eloop.reader_count; i++)
- FD_SET(eloop.readers[i].sock, rfds);
- res = select(eloop.max_sock + 1, rfds, NULL, NULL,
- eloop.timeout ? &tv : NULL);
- if (res < 0 && errno != EINTR) {
+ eloop_sock_table_set_fds(&eloop.readers, rfds);
+ eloop_sock_table_set_fds(&eloop.writers, wfds);
+ eloop_sock_table_set_fds(&eloop.exceptions, efds);
+ res = select(eloop.max_sock + 1, rfds, wfds, efds,
+ eloop.timeout ? &_tv : NULL);
+ if (res < 0 && errno != EINTR && errno != 0) {
perror("select");
- free(rfds);
- return;
+ goto out;
}
eloop_process_pending_signals();
@@ -334,13 +457,13 @@ void eloop_run(void)
if (eloop.timeout) {
struct eloop_timeout *tmp;
- gettimeofday(&now, NULL);
- if (!timercmp(&now, &eloop.timeout->time, <)) {
+ os_get_time(&now);
+ if (!os_time_before(&now, &eloop.timeout->time)) {
tmp = eloop.timeout;
eloop.timeout = eloop.timeout->next;
tmp->handler(tmp->eloop_data,
tmp->user_data);
- free(tmp);
+ os_free(tmp);
}
}
@@ -348,17 +471,15 @@ void eloop_run(void)
if (res <= 0)
continue;
- for (i = 0; i < eloop.reader_count; i++) {
- if (FD_ISSET(eloop.readers[i].sock, rfds)) {
- eloop.readers[i].handler(
- eloop.readers[i].sock,
- eloop.readers[i].eloop_data,
- eloop.readers[i].user_data);
- }
- }
+ eloop_sock_table_dispatch(&eloop.readers, rfds);
+ eloop_sock_table_dispatch(&eloop.writers, wfds);
+ eloop_sock_table_dispatch(&eloop.exceptions, efds);
}
- free(rfds);
+out:
+ os_free(rfds);
+ os_free(wfds);
+ os_free(efds);
}
@@ -376,10 +497,12 @@ void eloop_destroy(void)
while (timeout != NULL) {
prev = timeout;
timeout = timeout->next;
- free(prev);
+ os_free(prev);
}
- free(eloop.readers);
- free(eloop.signals);
+ eloop_sock_table_destroy(&eloop.readers);
+ eloop_sock_table_destroy(&eloop.writers);
+ eloop_sock_table_destroy(&eloop.exceptions);
+ os_free(eloop.signals);
}
@@ -387,3 +510,22 @@ int eloop_terminated(void)
{
return eloop.terminate;
}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+ fd_set rfds;
+
+ if (sock < 0)
+ return;
+
+ FD_ZERO(&rfds);
+ FD_SET(sock, &rfds);
+ select(sock + 1, &rfds, NULL, NULL, NULL);
+}
+
+
+void * eloop_get_user_data(void)
+{
+ return eloop.user_data;
+}
diff --git a/contrib/wpa_supplicant/eloop.h b/contrib/wpa_supplicant/eloop.h
index c57e68266ff0..4dd2871760df 100644
--- a/contrib/wpa_supplicant/eloop.h
+++ b/contrib/wpa_supplicant/eloop.h
@@ -1,6 +1,6 @@
/*
* Event loop
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,18 +23,67 @@
#ifndef ELOOP_H
#define ELOOP_H
-/* Magic number for eloop_cancel_timeout() */
+/**
+ * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts
+ */
#define ELOOP_ALL_CTX (void *) -1
/**
+ * eloop_event_type - eloop socket event type for eloop_register_sock()
+ * @EVENT_TYPE_READ: Socket has data available for reading
+ * @EVENT_TYPE_WRITE: Socket has room for new data to be written
+ * @EVENT_TYPE_EXCEPTION: An exception has been reported
+ */
+typedef enum {
+ EVENT_TYPE_READ = 0,
+ EVENT_TYPE_WRITE,
+ EVENT_TYPE_EXCEPTION
+} eloop_event_type;
+
+/**
+ * eloop_sock_handler - eloop socket event callback type
+ * @sock: File descriptor number for the socket
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx);
+
+/**
+ * eloop_event_handler - eloop generic event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_timeout_handler - eloop timeout event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_signal_handler - eloop signal event callback type
+ * @sig: Signal number
+ * @eloop_ctx: Registered callback context data (global user_data from
+ * eloop_init() call)
+ * @signal_ctx: Registered callback context data (user_data from
+ * eloop_register_signal(), eloop_register_signal_terminate(), or
+ * eloop_register_signal_reconfig() call)
+ */
+typedef void (*eloop_signal_handler)(int sig, void *eloop_ctx,
+ void *signal_ctx);
+
+/**
* eloop_init() - Initialize global event loop data
* @user_data: Pointer to global data passed as eloop_ctx to signal handlers
+ * Returns: 0 on success, -1 on failure
*
* This function must be called before any other eloop_* function. user_data
* can be used to configure a global (to the process) pointer that will be
* passed as eloop_ctx parameter to signal handlers.
*/
-void eloop_init(void *user_data);
+int eloop_init(void *user_data);
/**
* eloop_register_read_sock - Register handler for read events
@@ -46,11 +95,11 @@ void eloop_init(void *user_data);
*
* Register a read socket notifier for the given file descriptor. The handler
* function will be called whenever data is available for reading from the
- * socket.
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
*/
-int eloop_register_read_sock(int sock,
- void (*handler)(int sock, void *eloop_ctx,
- void *sock_ctx),
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
void *eloop_data, void *user_data);
/**
@@ -63,6 +112,71 @@ int eloop_register_read_sock(int sock,
void eloop_unregister_read_sock(int sock);
/**
+ * eloop_register_sock - Register handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event to wait for
+ * @handler: Callback function to be called when the event is triggered
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event notifier for the given socket's file descriptor. The
+ * handler function will be called whenever the that event is triggered for the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_sock(int sock, eloop_event_type type,
+ eloop_sock_handler handler,
+ void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_sock - Unregister handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event for which sock was registered
+ *
+ * Unregister a socket event notifier that was previously registered with
+ * eloop_register_sock().
+ */
+void eloop_unregister_sock(int sock, eloop_event_type type);
+
+/**
+ * eloop_register_event - Register handler for generic events
+ * @event: Event to wait (eloop implementation specific)
+ * @event_size: Size of event data
+ * @handler: Callback function to be called when event is triggered
+ * @eloop_data: Callback context data (eloop_data)
+ * @user_data: Callback context data (user_data)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event handler for the given event. This function is used to
+ * register eloop implementation specific events which are mainly targetted for
+ * operating system specific code (driver interface and l2_packet) since the
+ * portable code will not be able to use such an OS-specific call. The handler
+ * function will be called whenever the event is triggered. The handler
+ * function is responsible for clearing the event after having processed it in
+ * order to avoid eloop from calling the handler again for the same event.
+ *
+ * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE
+ * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable,
+ * and they would call this function with eloop_register_event(h, sizeof(h),
+ * ...).
+ */
+int eloop_register_event(void *event, size_t event_size,
+ eloop_event_handler handler,
+ void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_event - Unregister handler for a generic event
+ * @event: Event to cancel (eloop implementation specific)
+ * @event_size: Size of event data
+ *
+ * Unregister a generic event notifier that was previously registered with
+ * eloop_register_event().
+ */
+void eloop_unregister_event(void *event, size_t event_size);
+
+/**
* eloop_register_timeout - Register timeout
* @secs: Number of seconds to the timeout
* @usecs: Number of microseconds to the timeout
@@ -75,7 +189,7 @@ void eloop_unregister_read_sock(int sock);
* given time.
*/
int eloop_register_timeout(unsigned int secs, unsigned int usecs,
- void (*handler)(void *eloop_ctx, void *timeout_ctx),
+ eloop_timeout_handler handler,
void *eloop_data, void *user_data);
/**
@@ -89,7 +203,7 @@ int eloop_register_timeout(unsigned int secs, unsigned int usecs,
* eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
* cancelling all timeouts regardless of eloop_data/user_data.
*/
-int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+int eloop_cancel_timeout(eloop_timeout_handler handler,
void *eloop_data, void *user_data);
/**
@@ -100,20 +214,67 @@ int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
* Returns: 0 on success, -1 on failure
*
* Register a callback function that will be called when a signal is received.
- * The calback function is actually called only after the system signal handler
- * has returned. This means that the normal limits for sighandlers (i.e., only
- * "safe functions" allowed) do not apply for the registered callback.
+ * The callback function is actually called only after the system signal
+ * handler has returned. This means that the normal limits for sighandlers
+ * (i.e., only "safe functions" allowed) do not apply for the registered
+ * callback.
*
* Signals are 'global' events and there is no local eloop_data pointer like
* with other handlers. The global user_data pointer registered with
* eloop_init() will be used as eloop_ctx for signal handlers.
*/
-int eloop_register_signal(int sig,
- void (*handler)(int sig, void *eloop_ctx,
- void *signal_ctx),
+int eloop_register_signal(int sig, eloop_signal_handler handler,
void *user_data);
/**
+ * eloop_register_signal_terminate - Register handler for terminate signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a process termination
+ * signal is received. The callback function is actually called only after the
+ * system signal handler has returned. This means that the normal limits for
+ * sighandlers (i.e., only "safe functions" allowed) do not apply for the
+ * registered callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers handlers for SIGINT and SIGTERM.
+ */
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+ void *user_data);
+
+/**
+ * eloop_register_signal_reconfig - Register handler for reconfig signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a reconfiguration /
+ * hangup signal is received. The callback function is actually called only
+ * after the system signal handler has returned. This means that the normal
+ * limits for sighandlers (i.e., only "safe functions" allowed) do not apply
+ * for the registered callback.
+ *
+ * Signals are 'global' events and there is no local eloop_data pointer like
+ * with other handlers. The global user_data pointer registered with
+ * eloop_init() will be used as eloop_ctx for signal handlers.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers a handler for SIGHUP.
+ */
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+ void *user_data);
+
+/**
* eloop_run - Start the event loop
*
* Start the event loop and continue running as long as there are any
@@ -133,7 +294,7 @@ void eloop_terminate(void);
/**
* eloop_destroy - Free any resources allocated for the event loop
*
- * After calling eloop_destoy(), other eloop_* functions must not be called
+ * After calling eloop_destroy(), other eloop_* functions must not be called
* before re-running eloop_init().
*/
void eloop_destroy(void);
@@ -149,4 +310,18 @@ void eloop_destroy(void);
*/
int eloop_terminated(void);
+/**
+ * eloop_wait_for_read_sock - Wait for a single reader
+ * @sock: File descriptor number for the socket
+ *
+ * Do a blocking wait for a single read socket.
+ */
+void eloop_wait_for_read_sock(int sock);
+
+/**
+ * eloop_get_user_data - Get global user data
+ * Returns: user_data pointer that was registered with eloop_init()
+ */
+void * eloop_get_user_data(void);
+
#endif /* ELOOP_H */
diff --git a/contrib/wpa_supplicant/eloop_none.c b/contrib/wpa_supplicant/eloop_none.c
new file mode 100644
index 000000000000..6943109d955f
--- /dev/null
+++ b/contrib/wpa_supplicant/eloop_none.c
@@ -0,0 +1,390 @@
+/*
+ * Event loop - empty template (basic structure, but no OS specific operations)
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+ int sock;
+ void *eloop_data;
+ void *user_data;
+ void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+};
+
+struct eloop_timeout {
+ struct os_time time;
+ void *eloop_data;
+ void *user_data;
+ void (*handler)(void *eloop_ctx, void *sock_ctx);
+ struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+ int sig;
+ void *user_data;
+ void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+ int signaled;
+};
+
+struct eloop_data {
+ void *user_data;
+
+ int max_sock, reader_count;
+ struct eloop_sock *readers;
+
+ struct eloop_timeout *timeout;
+
+ int signal_count;
+ struct eloop_signal *signals;
+ int signaled;
+ int pending_terminate;
+
+ int terminate;
+ int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void *user_data)
+{
+ memset(&eloop, 0, sizeof(eloop));
+ eloop.user_data = user_data;
+ return 0;
+}
+
+
+int eloop_register_read_sock(int sock,
+ void (*handler)(int sock, void *eloop_ctx,
+ void *sock_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_sock *tmp;
+
+ tmp = (struct eloop_sock *)
+ realloc(eloop.readers,
+ (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.reader_count].sock = sock;
+ tmp[eloop.reader_count].eloop_data = eloop_data;
+ tmp[eloop.reader_count].user_data = user_data;
+ tmp[eloop.reader_count].handler = handler;
+ eloop.reader_count++;
+ eloop.readers = tmp;
+ if (sock > eloop.max_sock)
+ eloop.max_sock = sock;
+ eloop.reader_table_changed = 1;
+
+ return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+ int i;
+
+ if (eloop.readers == NULL || eloop.reader_count == 0)
+ return;
+
+ for (i = 0; i < eloop.reader_count; i++) {
+ if (eloop.readers[i].sock == sock)
+ break;
+ }
+ if (i == eloop.reader_count)
+ return;
+ if (i != eloop.reader_count - 1) {
+ memmove(&eloop.readers[i], &eloop.readers[i + 1],
+ (eloop.reader_count - i - 1) *
+ sizeof(struct eloop_sock));
+ }
+ eloop.reader_count--;
+ eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ void (*handler)(void *eloop_ctx, void *timeout_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *tmp, *prev;
+
+ timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+ if (timeout == NULL)
+ return -1;
+ os_get_time(&timeout->time);
+ timeout->time.sec += secs;
+ timeout->time.usec += usecs;
+ while (timeout->time.usec >= 1000000) {
+ timeout->time.sec++;
+ timeout->time.usec -= 1000000;
+ }
+ timeout->eloop_data = eloop_data;
+ timeout->user_data = user_data;
+ timeout->handler = handler;
+ timeout->next = NULL;
+
+ if (eloop.timeout == NULL) {
+ eloop.timeout = timeout;
+ return 0;
+ }
+
+ prev = NULL;
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (os_time_before(&timeout->time, &tmp->time))
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (prev == NULL) {
+ timeout->next = eloop.timeout;
+ eloop.timeout = timeout;
+ } else {
+ timeout->next = prev->next;
+ prev->next = timeout;
+ }
+
+ return 0;
+}
+
+
+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *prev, *next;
+ int removed = 0;
+
+ prev = NULL;
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ next = timeout->next;
+
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data ||
+ eloop_data == ELOOP_ALL_CTX) &&
+ (timeout->user_data == user_data ||
+ user_data == ELOOP_ALL_CTX)) {
+ if (prev == NULL)
+ eloop.timeout = next;
+ else
+ prev->next = next;
+ free(timeout);
+ removed++;
+ } else
+ prev = timeout;
+
+ timeout = next;
+ }
+
+ return removed;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+ int i;
+
+ eloop.signaled++;
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].sig == sig) {
+ eloop.signals[i].signaled++;
+ break;
+ }
+ }
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+ int i;
+
+ if (eloop.signaled == 0)
+ return;
+ eloop.signaled = 0;
+
+ if (eloop.pending_terminate) {
+ eloop.pending_terminate = 0;
+ }
+
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].signaled) {
+ eloop.signals[i].signaled = 0;
+ eloop.signals[i].handler(eloop.signals[i].sig,
+ eloop.user_data,
+ eloop.signals[i].user_data);
+ }
+ }
+}
+
+
+int eloop_register_signal(int sig,
+ void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+ struct eloop_signal *tmp;
+
+ tmp = (struct eloop_signal *)
+ realloc(eloop.signals,
+ (eloop.signal_count + 1) *
+ sizeof(struct eloop_signal));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.signal_count].sig = sig;
+ tmp[eloop.signal_count].user_data = user_data;
+ tmp[eloop.signal_count].handler = handler;
+ tmp[eloop.signal_count].signaled = 0;
+ eloop.signal_count++;
+ eloop.signals = tmp;
+
+ /* TODO: register signal handler */
+
+ return 0;
+}
+
+
+int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+#if 0
+ /* TODO: for example */
+ int ret = eloop_register_signal(SIGINT, handler, user_data);
+ if (ret == 0)
+ ret = eloop_register_signal(SIGTERM, handler, user_data);
+ return ret;
+#endif
+ return 0;
+}
+
+
+int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+#if 0
+ /* TODO: for example */
+ return eloop_register_signal(SIGHUP, handler, user_data);
+#endif
+ return 0;
+}
+
+
+void eloop_run(void)
+{
+ int i;
+ struct os_time tv, now;
+
+ while (!eloop.terminate &&
+ (eloop.timeout || eloop.reader_count > 0)) {
+ if (eloop.timeout) {
+ os_get_time(&now);
+ if (os_time_before(&now, &eloop.timeout->time))
+ os_time_sub(&eloop.timeout->time, &now, &tv);
+ else
+ tv.sec = tv.usec = 0;
+ }
+
+ /*
+ * TODO: wait for any event (read socket ready, timeout (tv),
+ * signal
+ */
+ os_sleep(1, 0); /* just a dummy wait for testing */
+
+ eloop_process_pending_signals();
+
+ /* check if some registered timeouts have occurred */
+ if (eloop.timeout) {
+ struct eloop_timeout *tmp;
+
+ os_get_time(&now);
+ if (!os_time_before(&now, &eloop.timeout->time)) {
+ tmp = eloop.timeout;
+ eloop.timeout = eloop.timeout->next;
+ tmp->handler(tmp->eloop_data,
+ tmp->user_data);
+ free(tmp);
+ }
+
+ }
+
+ eloop.reader_table_changed = 0;
+ for (i = 0; i < eloop.reader_count; i++) {
+ /*
+ * TODO: call each handler that has pending data to
+ * read
+ */
+ if (0 /* TODO: eloop.readers[i].sock ready */) {
+ eloop.readers[i].handler(
+ eloop.readers[i].sock,
+ eloop.readers[i].eloop_data,
+ eloop.readers[i].user_data);
+ if (eloop.reader_table_changed)
+ break;
+ }
+ }
+ }
+}
+
+
+void eloop_terminate(void)
+{
+ eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+ struct eloop_timeout *timeout, *prev;
+
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ prev = timeout;
+ timeout = timeout->next;
+ free(prev);
+ }
+ free(eloop.readers);
+ free(eloop.signals);
+}
+
+
+int eloop_terminated(void)
+{
+ return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+ /*
+ * TODO: wait for the file descriptor to have something available for
+ * reading
+ */
+}
+
+
+void * eloop_get_user_data(void)
+{
+ return eloop.user_data;
+}
diff --git a/contrib/wpa_supplicant/eloop_win.c b/contrib/wpa_supplicant/eloop_win.c
new file mode 100644
index 000000000000..73f0eafeeb8b
--- /dev/null
+++ b/contrib/wpa_supplicant/eloop_win.c
@@ -0,0 +1,604 @@
+/*
+ * Event loop based on Windows events and WaitForMultipleObjects
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <winsock2.h>
+
+#include "common.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+ int sock;
+ void *eloop_data;
+ void *user_data;
+ eloop_sock_handler handler;
+ WSAEVENT event;
+};
+
+struct eloop_event {
+ void *eloop_data;
+ void *user_data;
+ eloop_event_handler handler;
+ HANDLE event;
+};
+
+struct eloop_timeout {
+ struct os_time time;
+ void *eloop_data;
+ void *user_data;
+ eloop_timeout_handler handler;
+ struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+ int sig;
+ void *user_data;
+ eloop_signal_handler handler;
+ int signaled;
+};
+
+struct eloop_data {
+ void *user_data;
+
+ int max_sock;
+ size_t reader_count;
+ struct eloop_sock *readers;
+
+ size_t event_count;
+ struct eloop_event *events;
+
+ struct eloop_timeout *timeout;
+
+ int signal_count;
+ struct eloop_signal *signals;
+ int signaled;
+ int pending_terminate;
+
+ int terminate;
+ int reader_table_changed;
+
+ struct eloop_signal term_signal;
+ HANDLE term_event;
+
+ HANDLE *handles;
+ size_t num_handles;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void *user_data)
+{
+ os_memset(&eloop, 0, sizeof(eloop));
+ eloop.user_data = user_data;
+ eloop.num_handles = 1;
+ eloop.handles = os_malloc(eloop.num_handles *
+ sizeof(eloop.handles[0]));
+ if (eloop.handles == NULL)
+ return -1;
+
+ eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (eloop.term_event == NULL) {
+ printf("CreateEvent() failed: %d\n",
+ (int) GetLastError());
+ os_free(eloop.handles);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eloop_prepare_handles(void)
+{
+ HANDLE *n;
+
+ if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
+ return 0;
+ n = os_realloc(eloop.handles,
+ eloop.num_handles * 2 * sizeof(eloop.handles[0]));
+ if (n == NULL)
+ return -1;
+ eloop.handles = n;
+ eloop.num_handles *= 2;
+ return 0;
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+ void *eloop_data, void *user_data)
+{
+ WSAEVENT event;
+ struct eloop_sock *tmp;
+
+ if (eloop_prepare_handles())
+ return -1;
+
+ event = WSACreateEvent();
+ if (event == WSA_INVALID_EVENT) {
+ printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+ return -1;
+ }
+
+ if (WSAEventSelect(sock, event, FD_READ)) {
+ printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+ WSACloseEvent(event);
+ return -1;
+ }
+ tmp = os_realloc(eloop.readers,
+ (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ if (tmp == NULL) {
+ WSAEventSelect(sock, event, 0);
+ WSACloseEvent(event);
+ return -1;
+ }
+
+ tmp[eloop.reader_count].sock = sock;
+ tmp[eloop.reader_count].eloop_data = eloop_data;
+ tmp[eloop.reader_count].user_data = user_data;
+ tmp[eloop.reader_count].handler = handler;
+ tmp[eloop.reader_count].event = event;
+ eloop.reader_count++;
+ eloop.readers = tmp;
+ if (sock > eloop.max_sock)
+ eloop.max_sock = sock;
+ eloop.reader_table_changed = 1;
+
+ return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+ size_t i;
+
+ if (eloop.readers == NULL || eloop.reader_count == 0)
+ return;
+
+ for (i = 0; i < eloop.reader_count; i++) {
+ if (eloop.readers[i].sock == sock)
+ break;
+ }
+ if (i == eloop.reader_count)
+ return;
+
+ WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0);
+ WSACloseEvent(eloop.readers[i].event);
+
+ if (i != eloop.reader_count - 1) {
+ os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
+ (eloop.reader_count - i - 1) *
+ sizeof(struct eloop_sock));
+ }
+ eloop.reader_count--;
+ eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_event(void *event, size_t event_size,
+ eloop_event_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_event *tmp;
+ HANDLE h = event;
+
+ if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE)
+ return -1;
+
+ if (eloop_prepare_handles())
+ return -1;
+
+ tmp = os_realloc(eloop.events,
+ (eloop.event_count + 1) * sizeof(struct eloop_event));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.event_count].eloop_data = eloop_data;
+ tmp[eloop.event_count].user_data = user_data;
+ tmp[eloop.event_count].handler = handler;
+ tmp[eloop.event_count].event = h;
+ eloop.event_count++;
+ eloop.events = tmp;
+
+ return 0;
+}
+
+
+void eloop_unregister_event(void *event, size_t event_size)
+{
+ size_t i;
+ HANDLE h = event;
+
+ if (eloop.events == NULL || eloop.event_count == 0 ||
+ event_size != sizeof(HANDLE))
+ return;
+
+ for (i = 0; i < eloop.event_count; i++) {
+ if (eloop.events[i].event == h)
+ break;
+ }
+ if (i == eloop.event_count)
+ return;
+
+ if (i != eloop.event_count - 1) {
+ os_memmove(&eloop.events[i], &eloop.events[i + 1],
+ (eloop.event_count - i - 1) *
+ sizeof(struct eloop_event));
+ }
+ eloop.event_count--;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *tmp, *prev;
+
+ timeout = os_malloc(sizeof(*timeout));
+ if (timeout == NULL)
+ return -1;
+ os_get_time(&timeout->time);
+ timeout->time.sec += secs;
+ timeout->time.usec += usecs;
+ while (timeout->time.usec >= 1000000) {
+ timeout->time.sec++;
+ timeout->time.usec -= 1000000;
+ }
+ timeout->eloop_data = eloop_data;
+ timeout->user_data = user_data;
+ timeout->handler = handler;
+ timeout->next = NULL;
+
+ if (eloop.timeout == NULL) {
+ eloop.timeout = timeout;
+ return 0;
+ }
+
+ prev = NULL;
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (os_time_before(&timeout->time, &tmp->time))
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (prev == NULL) {
+ timeout->next = eloop.timeout;
+ eloop.timeout = timeout;
+ } else {
+ timeout->next = prev->next;
+ prev->next = timeout;
+ }
+
+ return 0;
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *prev, *next;
+ int removed = 0;
+
+ prev = NULL;
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ next = timeout->next;
+
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data ||
+ eloop_data == ELOOP_ALL_CTX) &&
+ (timeout->user_data == user_data ||
+ user_data == ELOOP_ALL_CTX)) {
+ if (prev == NULL)
+ eloop.timeout = next;
+ else
+ prev->next = next;
+ os_free(timeout);
+ removed++;
+ } else
+ prev = timeout;
+
+ timeout = next;
+ }
+
+ return removed;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+ int i;
+
+ eloop.signaled++;
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].sig == sig) {
+ eloop.signals[i].signaled++;
+ break;
+ }
+ }
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+ int i;
+
+ if (eloop.signaled == 0)
+ return;
+ eloop.signaled = 0;
+
+ if (eloop.pending_terminate) {
+ eloop.pending_terminate = 0;
+ }
+
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].signaled) {
+ eloop.signals[i].signaled = 0;
+ eloop.signals[i].handler(eloop.signals[i].sig,
+ eloop.user_data,
+ eloop.signals[i].user_data);
+ }
+ }
+
+ if (eloop.term_signal.signaled) {
+ eloop.term_signal.signaled = 0;
+ eloop.term_signal.handler(eloop.term_signal.sig,
+ eloop.user_data,
+ eloop.term_signal.user_data);
+ }
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+ void *user_data)
+{
+ struct eloop_signal *tmp;
+
+ tmp = os_realloc(eloop.signals,
+ (eloop.signal_count + 1) *
+ sizeof(struct eloop_signal));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.signal_count].sig = sig;
+ tmp[eloop.signal_count].user_data = user_data;
+ tmp[eloop.signal_count].handler = handler;
+ tmp[eloop.signal_count].signaled = 0;
+ eloop.signal_count++;
+ eloop.signals = tmp;
+
+ /* TODO: register signal handler */
+
+ return 0;
+}
+
+
+#ifndef _WIN32_WCE
+static BOOL eloop_handle_console_ctrl(DWORD type)
+{
+ switch (type) {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ eloop.signaled++;
+ eloop.term_signal.signaled++;
+ SetEvent(eloop.term_event);
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+#endif /* _WIN32_WCE */
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+ void *user_data)
+{
+#ifndef _WIN32_WCE
+ if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
+ TRUE) == 0) {
+ printf("SetConsoleCtrlHandler() failed: %d\n",
+ (int) GetLastError());
+ return -1;
+ }
+#endif /* _WIN32_WCE */
+
+ eloop.term_signal.handler = handler;
+ eloop.term_signal.user_data = user_data;
+
+ return 0;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+ void *user_data)
+{
+ /* TODO */
+ return 0;
+}
+
+
+void eloop_run(void)
+{
+ struct os_time tv, now;
+ DWORD count, ret, timeout, err;
+ size_t i;
+
+ while (!eloop.terminate &&
+ (eloop.timeout || eloop.reader_count > 0 ||
+ eloop.event_count > 0)) {
+ if (eloop.timeout) {
+ os_get_time(&now);
+ if (os_time_before(&now, &eloop.timeout->time))
+ os_time_sub(&eloop.timeout->time, &now, &tv);
+ else
+ tv.sec = tv.usec = 0;
+ }
+
+ count = 0;
+ for (i = 0; i < eloop.event_count; i++)
+ eloop.handles[count++] = eloop.events[i].event;
+
+ for (i = 0; i < eloop.reader_count; i++)
+ eloop.handles[count++] = eloop.readers[i].event;
+
+ if (eloop.term_event)
+ eloop.handles[count++] = eloop.term_event;
+
+ if (eloop.timeout)
+ timeout = tv.sec * 1000 + tv.usec / 1000;
+ else
+ timeout = INFINITE;
+
+ if (count > MAXIMUM_WAIT_OBJECTS) {
+ printf("WaitForMultipleObjects: Too many events: "
+ "%d > %d (ignoring extra events)\n",
+ (int) count, MAXIMUM_WAIT_OBJECTS);
+ count = MAXIMUM_WAIT_OBJECTS;
+ }
+#ifdef _WIN32_WCE
+ ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
+ timeout);
+#else /* _WIN32_WCE */
+ ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
+ timeout, TRUE);
+#endif /* _WIN32_WCE */
+ err = GetLastError();
+
+ eloop_process_pending_signals();
+
+ /* check if some registered timeouts have occurred */
+ if (eloop.timeout) {
+ struct eloop_timeout *tmp;
+
+ os_get_time(&now);
+ if (!os_time_before(&now, &eloop.timeout->time)) {
+ tmp = eloop.timeout;
+ eloop.timeout = eloop.timeout->next;
+ tmp->handler(tmp->eloop_data,
+ tmp->user_data);
+ os_free(tmp);
+ }
+
+ }
+
+ if (ret == WAIT_FAILED) {
+ printf("WaitForMultipleObjects(count=%d) failed: %d\n",
+ (int) count, (int) err);
+ os_sleep(1, 0);
+ continue;
+ }
+
+#ifndef _WIN32_WCE
+ if (ret == WAIT_IO_COMPLETION)
+ continue;
+#endif /* _WIN32_WCE */
+
+ if (ret == WAIT_TIMEOUT)
+ continue;
+
+ while (ret >= WAIT_OBJECT_0 &&
+ ret < WAIT_OBJECT_0 + eloop.event_count) {
+ eloop.events[ret].handler(
+ eloop.events[ret].eloop_data,
+ eloop.events[ret].user_data);
+ ret = WaitForMultipleObjects(eloop.event_count,
+ eloop.handles, FALSE, 0);
+ }
+
+ eloop.reader_table_changed = 0;
+ for (i = 0; i < eloop.reader_count; i++) {
+ WSANETWORKEVENTS events;
+ if (WSAEnumNetworkEvents(eloop.readers[i].sock,
+ eloop.readers[i].event,
+ &events) == 0 &&
+ (events.lNetworkEvents & FD_READ)) {
+ eloop.readers[i].handler(
+ eloop.readers[i].sock,
+ eloop.readers[i].eloop_data,
+ eloop.readers[i].user_data);
+ if (eloop.reader_table_changed)
+ break;
+ }
+ }
+ }
+}
+
+
+void eloop_terminate(void)
+{
+ eloop.terminate = 1;
+ SetEvent(eloop.term_event);
+}
+
+
+void eloop_destroy(void)
+{
+ struct eloop_timeout *timeout, *prev;
+
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ prev = timeout;
+ timeout = timeout->next;
+ os_free(prev);
+ }
+ os_free(eloop.readers);
+ os_free(eloop.signals);
+ if (eloop.term_event)
+ CloseHandle(eloop.term_event);
+ os_free(eloop.handles);
+ eloop.handles = NULL;
+ os_free(eloop.events);
+ eloop.events = NULL;
+}
+
+
+int eloop_terminated(void)
+{
+ return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+ WSAEVENT event;
+
+ event = WSACreateEvent();
+ if (event == WSA_INVALID_EVENT) {
+ printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+ return;
+ }
+
+ if (WSAEventSelect(sock, event, FD_READ)) {
+ printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+ WSACloseEvent(event);
+ return ;
+ }
+
+ WaitForSingleObject(event, INFINITE);
+ WSAEventSelect(sock, event, 0);
+ WSACloseEvent(event);
+}
+
+
+void * eloop_get_user_data(void)
+{
+ return eloop.user_data;
+}
diff --git a/contrib/wpa_supplicant/events.c b/contrib/wpa_supplicant/events.c
index d8762e978a41..c0f4210afa0f 100644
--- a/contrib/wpa_supplicant/events.c
+++ b/contrib/wpa_supplicant/events.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Driver event processing
- * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,11 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
+#include "includes.h"
#include "common.h"
#include "eapol_sm.h"
@@ -28,8 +24,10 @@
#include "wpa_supplicant_i.h"
#include "pcsc_funcs.h"
#include "preauth.h"
+#include "pmksa_cache.h"
#include "wpa_ctrl.h"
#include "eap.h"
+#include "ctrl_iface_dbus.h"
static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
@@ -63,6 +61,8 @@ static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
}
+ if (wpa_s->current_ssid && wpa_s->current_ssid != ssid)
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
wpa_s->current_ssid = ssid;
wpa_sm_set_config(wpa_s->wpa, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
@@ -85,10 +85,11 @@ static void wpa_supplicant_stop_countermeasures(void *eloop_ctx,
}
-static void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
+void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
{
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
- memset(wpa_s->bssid, 0, ETH_ALEN);
+ os_memset(wpa_s->bssid, 0, ETH_ALEN);
+ os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK)
@@ -145,6 +146,7 @@ static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
return 0;
+#ifdef IEEE8021X_EAPOL
if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
wpa_s->current_ssid &&
!(wpa_s->current_ssid->eapol_flags &
@@ -154,6 +156,7 @@ static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
* plaintext or static WEP keys). */
return 0;
}
+#endif /* IEEE8021X_EAPOL */
return 1;
}
@@ -171,6 +174,7 @@ static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
+#ifdef IEEE8021X_EAPOL
int aka = 0, sim = 0, type;
if (ssid->pcsc == NULL || wpa_s->scard != NULL)
@@ -180,22 +184,23 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
sim = 1;
aka = 1;
} else {
- u8 *eap = ssid->eap_methods;
- while (*eap != EAP_TYPE_NONE) {
- if (*eap == EAP_TYPE_SIM)
- sim = 1;
- else if (*eap == EAP_TYPE_AKA)
- aka = 1;
+ struct eap_method_type *eap = ssid->eap_methods;
+ while (eap->vendor != EAP_VENDOR_IETF ||
+ eap->method != EAP_TYPE_NONE) {
+ if (eap->vendor == EAP_VENDOR_IETF) {
+ if (eap->method == EAP_TYPE_SIM)
+ sim = 1;
+ else if (eap->method == EAP_TYPE_AKA)
+ aka = 1;
+ }
eap++;
}
}
-#ifndef EAP_SIM
- sim = 0;
-#endif /* EAP_SIM */
-#ifndef EAP_AKA
- aka = 0;
-#endif /* EAP_AKA */
+ if (eap_sm_get_eap_methods(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL)
+ sim = 0;
+ if (eap_sm_get_eap_methods(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL)
+ aka = 0;
if (!sim && !aka) {
wpa_printf(MSG_DEBUG, "Selected network is configured to use "
@@ -220,6 +225,7 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
}
wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* IEEE8021X_EAPOL */
return 0;
}
@@ -230,16 +236,21 @@ static int wpa_supplicant_match_privacy(struct wpa_scan_result *bss,
{
int i, privacy = 0;
+ if (ssid->mixed_cell)
+ return 1;
+
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i]) {
privacy = 1;
break;
}
}
+#ifdef IEEE8021X_EAPOL
if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
EAPOL_FLAG_REQUIRE_KEY_BROADCAST))
privacy = 1;
+#endif /* IEEE8021X_EAPOL */
if (bss->caps & IEEE80211_CAP_PRIVACY)
return privacy;
@@ -284,6 +295,15 @@ static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid,
break;
}
+#ifdef CONFIG_IEEE80211W
+ if (!(ie.capabilities & WPA_CAPABILITY_MGMT_FRAME_PROTECTION)
+ && ssid->ieee80211w == IEEE80211W_REQUIRED) {
+ wpa_printf(MSG_DEBUG, " skip RSN IE - no mgmt frame "
+ "protection");
+ break;
+ }
+#endif /* CONFIG_IEEE80211W */
+
wpa_printf(MSG_DEBUG, " selected based on RSN IE");
return 1;
}
@@ -346,6 +366,7 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
bss = NULL;
ssid = NULL;
/* First, try to find WPA-enabled AP */
+ wpa_printf(MSG_DEBUG, "Try to find WPA-enabled AP");
for (i = 0; i < num && !selected; i++) {
bss = &results[i];
wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
@@ -354,8 +375,8 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
wpa_ssid_txt(bss->ssid, bss->ssid_len),
(unsigned long) bss->wpa_ie_len,
(unsigned long) bss->rsn_ie_len, bss->caps);
- if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
- e->count > 1) {
+ e = wpa_blacklist_get(wpa_s, bss->bssid);
+ if (e && e->count > 1) {
wpa_printf(MSG_DEBUG, " skip - blacklisted");
continue;
}
@@ -366,17 +387,20 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
}
for (ssid = group; ssid; ssid = ssid->pnext) {
- if (ssid->disabled)
+ if (ssid->disabled) {
+ wpa_printf(MSG_DEBUG, " skip - disabled");
continue;
+ }
if (bss->ssid_len != ssid->ssid_len ||
- memcmp(bss->ssid, ssid->ssid,
- bss->ssid_len) != 0) {
+ os_memcmp(bss->ssid, ssid->ssid,
+ bss->ssid_len) != 0) {
wpa_printf(MSG_DEBUG, " skip - "
"SSID mismatch");
continue;
}
if (ssid->bssid_set &&
- memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0)
+ {
wpa_printf(MSG_DEBUG, " skip - "
"BSSID mismatch");
continue;
@@ -384,6 +408,11 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
if (wpa_supplicant_ssid_bss_match(ssid, bss)) {
selected = bss;
*selected_ssid = ssid;
+ wpa_printf(MSG_DEBUG, " selected WPA AP "
+ MACSTR " ssid='%s'",
+ MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid,
+ bss->ssid_len));
break;
}
}
@@ -391,35 +420,76 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
/* If no WPA-enabled AP found, try to find non-WPA AP, if configuration
* allows this. */
+ wpa_printf(MSG_DEBUG, "Try to find non-WPA AP");
for (i = 0; i < num && !selected; i++) {
bss = &results[i];
- if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
- e->count > 1) {
+ wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
+ "wpa_ie_len=%lu rsn_ie_len=%lu caps=0x%x",
+ i, MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len),
+ (unsigned long) bss->wpa_ie_len,
+ (unsigned long) bss->rsn_ie_len, bss->caps);
+ e = wpa_blacklist_get(wpa_s, bss->bssid);
+ if (e && e->count > 1) {
+ wpa_printf(MSG_DEBUG, " skip - blacklisted");
continue;
}
for (ssid = group; ssid; ssid = ssid->pnext) {
- if (!ssid->disabled &&
- (ssid->ssid_len == 0 ||
- (bss->ssid_len == ssid->ssid_len &&
- memcmp(bss->ssid, ssid->ssid, bss->ssid_len) ==
- 0)) &&
- (!ssid->bssid_set ||
- memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0) &&
- ((ssid->key_mgmt & WPA_KEY_MGMT_NONE) ||
- (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA))
- && bss->wpa_ie_len == 0 && bss->rsn_ie_len == 0 &&
- wpa_supplicant_match_privacy(bss, ssid) &&
- !(bss->caps & IEEE80211_CAP_IBSS))
+ if (ssid->disabled) {
+ wpa_printf(MSG_DEBUG, " skip - disabled");
+ continue;
+ }
+ if (bss->ssid_len != ssid->ssid_len ||
+ os_memcmp(bss->ssid, ssid->ssid,
+ bss->ssid_len) != 0) {
+ wpa_printf(MSG_DEBUG, " skip - "
+ "SSID mismatch");
+ continue;
+ }
+
+ if (ssid->bssid_set &&
+ os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0)
{
- selected = bss;
- *selected_ssid = ssid;
- wpa_printf(MSG_DEBUG, " selected non-WPA AP "
- MACSTR " ssid='%s'",
- MAC2STR(bss->bssid),
- wpa_ssid_txt(bss->ssid,
- bss->ssid_len));
- break;
+ wpa_printf(MSG_DEBUG, " skip - "
+ "BSSID mismatch");
+ continue;
+ }
+
+ if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+ !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA))
+ {
+ wpa_printf(MSG_DEBUG, " skip - "
+ "non-WPA network not allowed");
+ continue;
}
+
+ if ((ssid->key_mgmt &
+ (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK)) ||
+ bss->wpa_ie_len != 0 || bss->rsn_ie_len != 0) {
+ wpa_printf(MSG_DEBUG, " skip - "
+ "WPA network");
+ continue;
+ }
+
+ if (!wpa_supplicant_match_privacy(bss, ssid)) {
+ wpa_printf(MSG_DEBUG, " skip - "
+ "privacy mismatch");
+ continue;
+ }
+
+ if (bss->caps & IEEE80211_CAP_IBSS) {
+ wpa_printf(MSG_DEBUG, " skip - "
+ "IBSS (adhoc) network");
+ continue;
+ }
+
+ selected = bss;
+ *selected_ssid = ssid;
+ wpa_printf(MSG_DEBUG, " selected non-WPA AP "
+ MACSTR " ssid='%s'",
+ MAC2STR(bss->bssid),
+ wpa_ssid_txt(bss->ssid, bss->ssid_len));
+ break;
}
}
@@ -429,7 +499,7 @@ wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
{
- int num, prio;
+ int num, prio, timeout;
struct wpa_scan_result *selected = NULL;
struct wpa_ssid *ssid = NULL;
struct wpa_scan_result *results;
@@ -439,9 +509,12 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
return;
wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
"scanning again");
- wpa_supplicant_req_scan(wpa_s, 1, 0);
- return;
+ timeout = 1;
+ goto req_scan;
}
+
+ wpa_supplicant_dbus_notify_scan_results(wpa_s);
+
if (wpa_s->conf->ap_scan == 2)
return;
results = wpa_s->scan_results;
@@ -466,8 +539,15 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
}
if (selected) {
+ /* Do not trigger new association unless the BSSID has changed
+ * or if reassociation is requested. If we are in process of
+ * associating with the selected BSSID, do not trigger new
+ * attempt. */
if (wpa_s->reassociate ||
- memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+ (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
+ (wpa_s->wpa_state != WPA_ASSOCIATING ||
+ os_memcmp(selected->bssid, wpa_s->pending_bssid,
+ ETH_ALEN) != 0))) {
if (wpa_supplicant_scard_init(wpa_s, ssid)) {
wpa_supplicant_req_scan(wpa_s, 10, 0);
return;
@@ -480,8 +560,22 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
rsn_preauth_scan_results(wpa_s->wpa, results, num);
} else {
wpa_printf(MSG_DEBUG, "No suitable AP found.");
- wpa_supplicant_req_scan(wpa_s, 5, 0);
+ timeout = 5;
+ goto req_scan;
}
+
+ return;
+
+req_scan:
+ if (wpa_s->scan_res_tried == 1 && wpa_s->conf->ap_scan == 1) {
+ /*
+ * Quick recovery if the initial scan results were not
+ * complete when fetched before the first scan request.
+ */
+ wpa_s->scan_res_tried++;
+ timeout = 0;
+ }
+ wpa_supplicant_req_scan(wpa_s, timeout, 0);
}
@@ -515,7 +609,7 @@ static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
break;
}
if ((p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
- (memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+ (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
(p[0] == RSN_INFO_ELEM && p[1] >= 2)) {
if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
break;
@@ -545,7 +639,7 @@ static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
}
if (!wpa_found &&
p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
- memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
+ os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
wpa_found = 1;
wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len);
}
@@ -576,11 +670,15 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
wpa_supplicant_event_associnfo(wpa_s, data);
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
- if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
- memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+ if (wpa_s->use_client_mlme)
+ os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
+ if (wpa_s->use_client_mlme ||
+ (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
+ os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)) {
wpa_msg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
MACSTR, MAC2STR(bssid));
- memcpy(wpa_s->bssid, bssid, ETH_ALEN);
+ os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
+ os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
if (wpa_supplicant_dynamic_keys(wpa_s)) {
wpa_clear_keys(wpa_s, bssid);
}
@@ -625,11 +723,14 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
/* Timeout for receiving the first EAPOL packet */
wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
}
+ wpa_supplicant_cancel_scan(wpa_s);
}
static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s)
{
+ const u8 *bssid;
+
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
/*
* At least Host AP driver and a Prism3 card seemed to be
@@ -648,15 +749,18 @@ static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s)
}
if (wpa_s->wpa_state >= WPA_ASSOCIATED)
wpa_supplicant_req_scan(wpa_s, 0, 100000);
- wpa_blacklist_add(wpa_s, wpa_s->bssid);
+ bssid = wpa_s->bssid;
+ if (os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+ bssid = wpa_s->pending_bssid;
+ wpa_blacklist_add(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
- wpa_supplicant_mark_disassoc(wpa_s);
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "- Disconnect event - "
"remove keys");
if (wpa_supplicant_dynamic_keys(wpa_s)) {
wpa_s->keys_cleared = 0;
wpa_clear_keys(wpa_s, wpa_s->bssid);
}
+ wpa_supplicant_mark_disassoc(wpa_s);
}
@@ -665,14 +769,14 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
int pairwise;
- time_t now;
+ struct os_time t;
wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
pairwise = (data && data->michael_mic_failure.unicast);
wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
- time(&now);
+ os_get_time(&t);
if (wpa_s->last_michael_mic_error &&
- now - wpa_s->last_michael_mic_error <= 60) {
+ t.sec - wpa_s->last_michael_mic_error <= 60) {
/* initialize countermeasures */
wpa_s->countermeasures = 1;
wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
@@ -681,7 +785,7 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
* Need to wait for completion of request frame. We do not get
* any callback for the message completion, so just wait a
* short while and hope for the best. */
- usleep(10000);
+ os_sleep(0, 10000);
wpa_drv_set_countermeasures(wpa_s, 1);
wpa_supplicant_deauthenticate(wpa_s,
@@ -694,7 +798,7 @@ wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
/* TODO: mark the AP rejected for 60 second. STA is
* allowed to associate with another AP.. */
}
- wpa_s->last_michael_mic_error = now;
+ wpa_s->last_michael_mic_error = t.sec;
}
@@ -702,7 +806,7 @@ static void
wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
union wpa_event_data *data)
{
- if (strcmp(wpa_s->ifname, data->interface_status.ifname) != 0)
+ if (os_strcmp(wpa_s->ifname, data->interface_status.ifname) != 0)
return;
switch (data->interface_status.ievent) {
@@ -727,6 +831,18 @@ wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
}
+#ifdef CONFIG_PEERKEY
+static void
+wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ if (data == NULL)
+ return;
+ wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer);
+}
+#endif /* CONFIG_PEERKEY */
+
+
void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
union wpa_event_data *data)
{
@@ -752,6 +868,11 @@ void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
case EVENT_PMKID_CANDIDATE:
wpa_supplicant_event_pmkid_candidate(wpa_s, data);
break;
+#ifdef CONFIG_PEERKEY
+ case EVENT_STKSTART:
+ wpa_supplicant_event_stkstart(wpa_s, data);
+ break;
+#endif /* CONFIG_PEERKEY */
default:
wpa_printf(MSG_INFO, "Unknown event %d", event);
break;
diff --git a/contrib/wpa_supplicant/hostapd.h b/contrib/wpa_supplicant/hostapd.h
index ce1fae94edb9..5ae9c8cc4f9e 100644
--- a/contrib/wpa_supplicant/hostapd.h
+++ b/contrib/wpa_supplicant/hostapd.h
@@ -3,18 +3,19 @@
/*
* Minimal version of hostapd header files for eapol_test to build
- * radiusclient.c.
+ * radius_client.c.
*/
#include "common.h"
-void hostapd_logger(void *ctx, u8 *addr, unsigned int module, int level,
- char *fmt, ...) __attribute__ ((format (printf, 5, 6)));
+void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
+ char *fmt, ...) PRINTF_FORMAT(5, 6);
struct hostapd_ip_addr;
const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
- size_t buflen);;
+ size_t buflen);
+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b);
enum {
HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
diff --git a/contrib/wpa_supplicant/includes.h b/contrib/wpa_supplicant/includes.h
new file mode 100644
index 000000000000..84308c3a37a2
--- /dev/null
+++ b/contrib/wpa_supplicant/includes.h
@@ -0,0 +1,57 @@
+/*
+ * wpa_supplicant/hostapd - Default include files
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This header file is included into all C files so that commonly used header
+ * files can be selected with OS specific #ifdefs in one place instead of
+ * having to have OS/C library specific selection in many files.
+ */
+
+#ifndef INCLUDES_H
+#define INCLUDES_H
+
+/* Include possible build time configuration before including anything else */
+#include "build_config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+#ifndef CONFIG_TI_COMPILER
+#include <signal.h>
+#include <sys/types.h>
+#endif /* CONFIG_TI_COMPILER */
+#include <errno.h>
+#endif /* _WIN32_WCE */
+#include <ctype.h>
+#include <time.h>
+
+#ifndef CONFIG_TI_COMPILER
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif /* _MSC_VER */
+#endif /* CONFIG_TI_COMPILER */
+
+#ifndef CONFIG_NATIVE_WINDOWS
+#ifndef CONFIG_TI_COMPILER
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifndef __vxworks
+#include <sys/uio.h>
+#include <sys/time.h>
+#endif /* __vxworks */
+#endif /* CONFIG_TI_COMPILER */
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#endif /* INCLUDES_H */
diff --git a/contrib/wpa_supplicant/l2_packet.h b/contrib/wpa_supplicant/l2_packet.h
index eb966d39ed69..540f0a116b56 100644
--- a/contrib/wpa_supplicant/l2_packet.h
+++ b/contrib/wpa_supplicant/l2_packet.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Layer2 packet interface definition
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -42,11 +42,19 @@
*/
struct l2_packet_data;
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct l2_ethhdr {
u8 h_dest[ETH_ALEN];
u8 h_source[ETH_ALEN];
u16 h_proto;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
/**
* l2_packet_init - Initialize l2_packet interface
diff --git a/contrib/wpa_supplicant/libtommath.c b/contrib/wpa_supplicant/libtommath.c
new file mode 100644
index 000000000000..b637707f31a8
--- /dev/null
+++ b/contrib/wpa_supplicant/libtommath.c
@@ -0,0 +1,2370 @@
+/*
+ * Minimal code for RSA support from LibTomMath 0.3.9
+ * http://math.libtomcrypt.com/
+ * http://math.libtomcrypt.com/files/ltm-0.39.tar.bz2
+ * This library was released in public domain by Tom St Denis.
+ *
+ * The combination in this file is not using many of the optimized algorithms
+ * (e.g., Montgomery reduction) and is considerable slower than the LibTomMath
+ * with its default of SC_RSA_1 settins. The main purpose of having this
+ * version here is to make it easier to build bignum.c wrapper without having
+ * to install and build an external library. However, it is likely worth the
+ * effort to use the full library with SC_RSA_1 instead of this minimized copy.
+ * Including the optimized algorithms may increase the size requirements by
+ * 15 kB or so (measured with x86 build).
+ *
+ * If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
+ * libtommath.c file instead of using the external LibTomMath library.
+ */
+
+#ifndef CHAR_BIT
+#define CHAR_BIT 8
+#endif
+
+#define BN_MP_INVMOD_C
+#define BN_S_MP_EXPTMOD_C /* Note: #undef in tommath_superclass.h; this would
+ * require BN_MP_EXPTMOD_FAST_C instead */
+#define BN_S_MP_MUL_DIGS_C
+#define BN_MP_INVMOD_SLOW_C
+#define BN_S_MP_SQR_C
+#define BN_S_MP_MUL_HIGH_DIGS_C /* Note: #undef in tommath_superclass.h; this
+ * would require other than mp_reduce */
+
+
+/* from tommath.h */
+
+#ifndef MIN
+ #define MIN(x,y) ((x)<(y)?(x):(y))
+#endif
+
+#ifndef MAX
+ #define MAX(x,y) ((x)>(y)?(x):(y))
+#endif
+
+#define OPT_CAST(x)
+
+typedef unsigned long mp_digit;
+typedef u64 mp_word;
+
+#define DIGIT_BIT 28
+#define MP_28BIT
+
+
+#define XMALLOC os_malloc
+#define XFREE os_free
+#define XREALLOC os_realloc
+
+
+#define MP_MASK ((((mp_digit)1)<<((mp_digit)DIGIT_BIT))-((mp_digit)1))
+
+#define MP_LT -1 /* less than */
+#define MP_EQ 0 /* equal to */
+#define MP_GT 1 /* greater than */
+
+#define MP_ZPOS 0 /* positive integer */
+#define MP_NEG 1 /* negative */
+
+#define MP_OKAY 0 /* ok result */
+#define MP_MEM -2 /* out of mem */
+#define MP_VAL -3 /* invalid input */
+
+#define MP_YES 1 /* yes response */
+#define MP_NO 0 /* no response */
+
+typedef int mp_err;
+
+/* define this to use lower memory usage routines (exptmods mostly) */
+#define MP_LOW_MEM
+
+/* default precision */
+#ifndef MP_PREC
+ #ifndef MP_LOW_MEM
+ #define MP_PREC 32 /* default digits of precision */
+ #else
+ #define MP_PREC 8 /* default digits of precision */
+ #endif
+#endif
+
+/* size of comba arrays, should be at least 2 * 2**(BITS_PER_WORD - BITS_PER_DIGIT*2) */
+#define MP_WARRAY (1 << (sizeof(mp_word) * CHAR_BIT - 2 * DIGIT_BIT + 1))
+
+/* the infamous mp_int structure */
+typedef struct {
+ int used, alloc, sign;
+ mp_digit *dp;
+} mp_int;
+
+
+/* ---> Basic Manipulations <--- */
+#define mp_iszero(a) (((a)->used == 0) ? MP_YES : MP_NO)
+#define mp_iseven(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 0)) ? MP_YES : MP_NO)
+#define mp_isodd(a) (((a)->used > 0 && (((a)->dp[0] & 1) == 1)) ? MP_YES : MP_NO)
+
+
+/* prototypes for copied functions */
+#define s_mp_mul(a, b, c) s_mp_mul_digs(a, b, c, (a)->used + (b)->used + 1)
+static int s_mp_exptmod(mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode);
+static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+static int s_mp_sqr(mp_int * a, mp_int * b);
+static int s_mp_mul_high_digs(mp_int * a, mp_int * b, mp_int * c, int digs);
+
+static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs);
+
+static int mp_init_multi(mp_int *mp, ...);
+static void mp_clear_multi(mp_int *mp, ...);
+static int mp_lshd(mp_int * a, int b);
+static void mp_set(mp_int * a, mp_digit b);
+static void mp_clamp(mp_int * a);
+static void mp_exch(mp_int * a, mp_int * b);
+static void mp_rshd(mp_int * a, int b);
+static void mp_zero(mp_int * a);
+static int mp_mod_2d(mp_int * a, int b, mp_int * c);
+static int mp_div_2d(mp_int * a, int b, mp_int * c, mp_int * d);
+static int mp_init_copy(mp_int * a, mp_int * b);
+static int mp_mul_2d(mp_int * a, int b, mp_int * c);
+static int mp_div_2(mp_int * a, mp_int * b);
+static int mp_copy(mp_int * a, mp_int * b);
+static int mp_count_bits(mp_int * a);
+static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d);
+static int mp_mod(mp_int * a, mp_int * b, mp_int * c);
+static int mp_grow(mp_int * a, int size);
+static int mp_cmp_mag(mp_int * a, mp_int * b);
+static int mp_invmod(mp_int * a, mp_int * b, mp_int * c);
+static int mp_abs(mp_int * a, mp_int * b);
+static int mp_invmod_slow(mp_int * a, mp_int * b, mp_int * c);
+static int mp_sqr(mp_int * a, mp_int * b);
+static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d);
+static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d);
+static int mp_2expt(mp_int * a, int b);
+static int mp_reduce_setup(mp_int * a, mp_int * b);
+static int mp_reduce(mp_int * x, mp_int * m, mp_int * mu);
+static int mp_init_size(mp_int * a, int size);
+
+
+
+/* functions from bn_<func name>.c */
+
+
+/* reverse an array, used for radix code */
+static void bn_reverse (unsigned char *s, int len)
+{
+ int ix, iy;
+ unsigned char t;
+
+ ix = 0;
+ iy = len - 1;
+ while (ix < iy) {
+ t = s[ix];
+ s[ix] = s[iy];
+ s[iy] = t;
+ ++ix;
+ --iy;
+ }
+}
+
+
+/* low level addition, based on HAC pp.594, Algorithm 14.7 */
+static int s_mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int *x;
+ int olduse, res, min, max;
+
+ /* find sizes, we let |a| <= |b| which means we have to sort
+ * them. "x" will point to the input with the most digits
+ */
+ if (a->used > b->used) {
+ min = b->used;
+ max = a->used;
+ x = a;
+ } else {
+ min = a->used;
+ max = b->used;
+ x = b;
+ }
+
+ /* init result */
+ if (c->alloc < max + 1) {
+ if ((res = mp_grow (c, max + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* get old used digit count and set new one */
+ olduse = c->used;
+ c->used = max + 1;
+
+ {
+ register mp_digit u, *tmpa, *tmpb, *tmpc;
+ register int i;
+
+ /* alias for digit pointers */
+
+ /* first input */
+ tmpa = a->dp;
+
+ /* second input */
+ tmpb = b->dp;
+
+ /* destination */
+ tmpc = c->dp;
+
+ /* zero the carry */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* Compute the sum at one digit, T[i] = A[i] + B[i] + U */
+ *tmpc = *tmpa++ + *tmpb++ + u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+ /* take away carry bit from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* now copy higher words if any, that is in A+B
+ * if A or B has more digits add those in
+ */
+ if (min != max) {
+ for (; i < max; i++) {
+ /* T[i] = X[i] + U */
+ *tmpc = x->dp[i] + u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)DIGIT_BIT);
+
+ /* take away carry bit from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+ }
+
+ /* add carry */
+ *tmpc++ = u;
+
+ /* clear digits above oldused */
+ for (i = c->used; i < olduse; i++) {
+ *tmpc++ = 0;
+ }
+ }
+
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+
+/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
+static int s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+ int olduse, res, min, max;
+
+ /* find sizes */
+ min = b->used;
+ max = a->used;
+
+ /* init result */
+ if (c->alloc < max) {
+ if ((res = mp_grow (c, max)) != MP_OKAY) {
+ return res;
+ }
+ }
+ olduse = c->used;
+ c->used = max;
+
+ {
+ register mp_digit u, *tmpa, *tmpb, *tmpc;
+ register int i;
+
+ /* alias for digit pointers */
+ tmpa = a->dp;
+ tmpb = b->dp;
+ tmpc = c->dp;
+
+ /* set carry to zero */
+ u = 0;
+ for (i = 0; i < min; i++) {
+ /* T[i] = A[i] - B[i] - U */
+ *tmpc = *tmpa++ - *tmpb++ - u;
+
+ /* U = carry bit of T[i]
+ * Note this saves performing an AND operation since
+ * if a carry does occur it will propagate all the way to the
+ * MSB. As a result a single shift is enough to get the carry
+ */
+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* now copy higher words if any, e.g. if A has more digits than B */
+ for (; i < max; i++) {
+ /* T[i] = A[i] - U */
+ *tmpc = *tmpa++ - u;
+
+ /* U = carry bit of T[i] */
+ u = *tmpc >> ((mp_digit)(CHAR_BIT * sizeof (mp_digit) - 1));
+
+ /* Clear carry from T[i] */
+ *tmpc++ &= MP_MASK;
+ }
+
+ /* clear digits above used (since we may not have grown result above) */
+ for (i = c->used; i < olduse; i++) {
+ *tmpc++ = 0;
+ }
+ }
+
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+
+/* init a new mp_int */
+static int mp_init (mp_int * a)
+{
+ int i;
+
+ /* allocate memory required and clear it */
+ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * MP_PREC);
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the digits to zero */
+ for (i = 0; i < MP_PREC; i++) {
+ a->dp[i] = 0;
+ }
+
+ /* set the used to zero, allocated digits to the default precision
+ * and sign to positive */
+ a->used = 0;
+ a->alloc = MP_PREC;
+ a->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+
+
+/* clear one (frees) */
+static void mp_clear (mp_int * a)
+{
+ int i;
+
+ /* only do anything if a hasn't been freed previously */
+ if (a->dp != NULL) {
+ /* first zero the digits */
+ for (i = 0; i < a->used; i++) {
+ a->dp[i] = 0;
+ }
+
+ /* free ram */
+ XFREE(a->dp);
+
+ /* reset members to make debugging easier */
+ a->dp = NULL;
+ a->alloc = a->used = 0;
+ a->sign = MP_ZPOS;
+ }
+}
+
+
+/* high level addition (handles signs) */
+static int mp_add (mp_int * a, mp_int * b, mp_int * c)
+{
+ int sa, sb, res;
+
+ /* get sign of both inputs */
+ sa = a->sign;
+ sb = b->sign;
+
+ /* handle two cases, not four */
+ if (sa == sb) {
+ /* both positive or both negative */
+ /* add their magnitudes, copy the sign */
+ c->sign = sa;
+ res = s_mp_add (a, b, c);
+ } else {
+ /* one positive, the other negative */
+ /* subtract the one with the greater magnitude from */
+ /* the one of the lesser magnitude. The result gets */
+ /* the sign of the one with the greater magnitude. */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ c->sign = sb;
+ res = s_mp_sub (b, a, c);
+ } else {
+ c->sign = sa;
+ res = s_mp_sub (a, b, c);
+ }
+ }
+ return res;
+}
+
+
+/* high level subtraction (handles signs) */
+static int mp_sub (mp_int * a, mp_int * b, mp_int * c)
+{
+ int sa, sb, res;
+
+ sa = a->sign;
+ sb = b->sign;
+
+ if (sa != sb) {
+ /* subtract a negative from a positive, OR */
+ /* subtract a positive from a negative. */
+ /* In either case, ADD their magnitudes, */
+ /* and use the sign of the first number. */
+ c->sign = sa;
+ res = s_mp_add (a, b, c);
+ } else {
+ /* subtract a positive from a positive, OR */
+ /* subtract a negative from a negative. */
+ /* First, take the difference between their */
+ /* magnitudes, then... */
+ if (mp_cmp_mag (a, b) != MP_LT) {
+ /* Copy the sign from the first */
+ c->sign = sa;
+ /* The first has a larger or equal magnitude */
+ res = s_mp_sub (a, b, c);
+ } else {
+ /* The result has the *opposite* sign from */
+ /* the first number. */
+ c->sign = (sa == MP_ZPOS) ? MP_NEG : MP_ZPOS;
+ /* The second has a larger magnitude */
+ res = s_mp_sub (b, a, c);
+ }
+ }
+ return res;
+}
+
+
+/* high level multiplication (handles sign) */
+static int mp_mul (mp_int * a, mp_int * b, mp_int * c)
+{
+ int res, neg;
+ neg = (a->sign == b->sign) ? MP_ZPOS : MP_NEG;
+
+ /* use Toom-Cook? */
+#ifdef BN_MP_TOOM_MUL_C
+ if (MIN (a->used, b->used) >= TOOM_MUL_CUTOFF) {
+ res = mp_toom_mul(a, b, c);
+ } else
+#endif
+#ifdef BN_MP_KARATSUBA_MUL_C
+ /* use Karatsuba? */
+ if (MIN (a->used, b->used) >= KARATSUBA_MUL_CUTOFF) {
+ res = mp_karatsuba_mul (a, b, c);
+ } else
+#endif
+ {
+ /* can we use the fast multiplier?
+ *
+ * The fast multiplier can be used if the output will
+ * have less than MP_WARRAY digits and the number of
+ * digits won't affect carry propagation
+ */
+#ifdef BN_FAST_S_MP_MUL_DIGS_C
+ int digs = a->used + b->used + 1;
+
+ if ((digs < MP_WARRAY) &&
+ MIN(a->used, b->used) <=
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ res = fast_s_mp_mul_digs (a, b, c, digs);
+ } else
+#endif
+#ifdef BN_S_MP_MUL_DIGS_C
+ res = s_mp_mul (a, b, c); /* uses s_mp_mul_digs */
+#else
+#error mp_mul could fail
+ res = MP_VAL;
+#endif
+
+ }
+ c->sign = (c->used > 0) ? neg : MP_ZPOS;
+ return res;
+}
+
+
+/* d = a * b (mod c) */
+static int mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ int res;
+ mp_int t;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_mul (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ res = mp_mod (&t, c, d);
+ mp_clear (&t);
+ return res;
+}
+
+
+/* c = a mod b, 0 <= c < b */
+static int mp_mod (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int t;
+ int res;
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_div (a, b, NULL, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+
+ if (t.sign != b->sign) {
+ res = mp_add (b, &t, c);
+ } else {
+ res = MP_OKAY;
+ mp_exch (&t, c);
+ }
+
+ mp_clear (&t);
+ return res;
+}
+
+
+/* this is a shell function that calls either the normal or Montgomery
+ * exptmod functions. Originally the call to the montgomery code was
+ * embedded in the normal function but that wasted alot of stack space
+ * for nothing (since 99% of the time the Montgomery code would be called)
+ */
+static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
+{
+ int dr;
+
+ /* modulus P must be positive */
+ if (P->sign == MP_NEG) {
+ return MP_VAL;
+ }
+
+ /* if exponent X is negative we have to recurse */
+ if (X->sign == MP_NEG) {
+#ifdef BN_MP_INVMOD_C
+ mp_int tmpG, tmpX;
+ int err;
+
+ /* first compute 1/G mod P */
+ if ((err = mp_init(&tmpG)) != MP_OKAY) {
+ return err;
+ }
+ if ((err = mp_invmod(G, P, &tmpG)) != MP_OKAY) {
+ mp_clear(&tmpG);
+ return err;
+ }
+
+ /* now get |X| */
+ if ((err = mp_init(&tmpX)) != MP_OKAY) {
+ mp_clear(&tmpG);
+ return err;
+ }
+ if ((err = mp_abs(X, &tmpX)) != MP_OKAY) {
+ mp_clear_multi(&tmpG, &tmpX, NULL);
+ return err;
+ }
+
+ /* and now compute (1/G)**|X| instead of G**X [X < 0] */
+ err = mp_exptmod(&tmpG, &tmpX, P, Y);
+ mp_clear_multi(&tmpG, &tmpX, NULL);
+ return err;
+#else
+#error mp_exptmod would always fail
+ /* no invmod */
+ return MP_VAL;
+#endif
+ }
+
+/* modified diminished radix reduction */
+#if defined(BN_MP_REDUCE_IS_2K_L_C) && defined(BN_MP_REDUCE_2K_L_C) && defined(BN_S_MP_EXPTMOD_C)
+ if (mp_reduce_is_2k_l(P) == MP_YES) {
+ return s_mp_exptmod(G, X, P, Y, 1);
+ }
+#endif
+
+#ifdef BN_MP_DR_IS_MODULUS_C
+ /* is it a DR modulus? */
+ dr = mp_dr_is_modulus(P);
+#else
+ /* default to no */
+ dr = 0;
+#endif
+
+#ifdef BN_MP_REDUCE_IS_2K_C
+ /* if not, is it a unrestricted DR modulus? */
+ if (dr == 0) {
+ dr = mp_reduce_is_2k(P) << 1;
+ }
+#endif
+
+ /* if the modulus is odd or dr != 0 use the montgomery method */
+#ifdef BN_MP_EXPTMOD_FAST_C
+ if (mp_isodd (P) == 1 || dr != 0) {
+ return mp_exptmod_fast (G, X, P, Y, dr);
+ } else {
+#endif
+#ifdef BN_S_MP_EXPTMOD_C
+ /* otherwise use the generic Barrett reduction technique */
+ return s_mp_exptmod (G, X, P, Y, 0);
+#else
+#error mp_exptmod could fail
+ /* no exptmod for evens */
+ return MP_VAL;
+#endif
+#ifdef BN_MP_EXPTMOD_FAST_C
+ }
+#endif
+}
+
+
+/* compare two ints (signed)*/
+static int mp_cmp (mp_int * a, mp_int * b)
+{
+ /* compare based on sign */
+ if (a->sign != b->sign) {
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ } else {
+ return MP_GT;
+ }
+ }
+
+ /* compare digits */
+ if (a->sign == MP_NEG) {
+ /* if negative compare opposite direction */
+ return mp_cmp_mag(b, a);
+ } else {
+ return mp_cmp_mag(a, b);
+ }
+}
+
+
+/* compare a digit */
+static int mp_cmp_d(mp_int * a, mp_digit b)
+{
+ /* compare based on sign */
+ if (a->sign == MP_NEG) {
+ return MP_LT;
+ }
+
+ /* compare based on magnitude */
+ if (a->used > 1) {
+ return MP_GT;
+ }
+
+ /* compare the only digit of a to b */
+ if (a->dp[0] > b) {
+ return MP_GT;
+ } else if (a->dp[0] < b) {
+ return MP_LT;
+ } else {
+ return MP_EQ;
+ }
+}
+
+
+/* hac 14.61, pp608 */
+static int mp_invmod (mp_int * a, mp_int * b, mp_int * c)
+{
+ /* b cannot be negative */
+ if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+ return MP_VAL;
+ }
+
+#ifdef BN_FAST_MP_INVMOD_C
+ /* if the modulus is odd we can use a faster routine instead */
+ if (mp_isodd (b) == 1) {
+ return fast_mp_invmod (a, b, c);
+ }
+#endif
+
+#ifdef BN_MP_INVMOD_SLOW_C
+ return mp_invmod_slow(a, b, c);
+#endif
+
+#ifndef BN_FAST_MP_INVMOD_C
+#ifndef BN_MP_INVMOD_SLOW_C
+#error mp_invmod would always fail
+#endif
+#endif
+ return MP_VAL;
+}
+
+
+/* get the size for an unsigned equivalent */
+static int mp_unsigned_bin_size (mp_int * a)
+{
+ int size = mp_count_bits (a);
+ return (size / 8 + ((size & 7) != 0 ? 1 : 0));
+}
+
+
+/* hac 14.61, pp608 */
+static int mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
+{
+ mp_int x, y, u, v, A, B, C, D;
+ int res;
+
+ /* b cannot be negative */
+ if (b->sign == MP_NEG || mp_iszero(b) == 1) {
+ return MP_VAL;
+ }
+
+ /* init temps */
+ if ((res = mp_init_multi(&x, &y, &u, &v,
+ &A, &B, &C, &D, NULL)) != MP_OKAY) {
+ return res;
+ }
+
+ /* x = a, y = b */
+ if ((res = mp_mod(a, b, &x)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy (b, &y)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ /* 2. [modified] if x,y are both even then return an error! */
+ if (mp_iseven (&x) == 1 && mp_iseven (&y) == 1) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
+ if ((res = mp_copy (&x, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_copy (&y, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ mp_set (&A, 1);
+ mp_set (&D, 1);
+
+top:
+ /* 4. while u is even do */
+ while (mp_iseven (&u) == 1) {
+ /* 4.1 u = u/2 */
+ if ((res = mp_div_2 (&u, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 4.2 if A or B is odd then */
+ if (mp_isodd (&A) == 1 || mp_isodd (&B) == 1) {
+ /* A = (A+y)/2, B = (B-x)/2 */
+ if ((res = mp_add (&A, &y, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_sub (&B, &x, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* A = A/2, B = B/2 */
+ if ((res = mp_div_2 (&A, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_div_2 (&B, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 5. while v is even do */
+ while (mp_iseven (&v) == 1) {
+ /* 5.1 v = v/2 */
+ if ((res = mp_div_2 (&v, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ /* 5.2 if C or D is odd then */
+ if (mp_isodd (&C) == 1 || mp_isodd (&D) == 1) {
+ /* C = (C+y)/2, D = (D-x)/2 */
+ if ((res = mp_add (&C, &y, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_sub (&D, &x, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+ /* C = C/2, D = D/2 */
+ if ((res = mp_div_2 (&C, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ if ((res = mp_div_2 (&D, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* 6. if u >= v then */
+ if (mp_cmp (&u, &v) != MP_LT) {
+ /* u = u - v, A = A - C, B = B - D */
+ if ((res = mp_sub (&u, &v, &u)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&A, &C, &A)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&B, &D, &B)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ } else {
+ /* v - v - u, C = C - A, D = D - B */
+ if ((res = mp_sub (&v, &u, &v)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&C, &A, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+
+ if ((res = mp_sub (&D, &B, &D)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* if not zero goto step 4 */
+ if (mp_iszero (&u) == 0)
+ goto top;
+
+ /* now a = C, b = D, gcd == g*v */
+
+ /* if v != 1 then there is no inverse */
+ if (mp_cmp_d (&v, 1) != MP_EQ) {
+ res = MP_VAL;
+ goto LBL_ERR;
+ }
+
+ /* if its too low */
+ while (mp_cmp_d(&C, 0) == MP_LT) {
+ if ((res = mp_add(&C, b, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* too big */
+ while (mp_cmp_mag(&C, b) != MP_LT) {
+ if ((res = mp_sub(&C, b, &C)) != MP_OKAY) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* C is now the inverse */
+ mp_exch (&C, c);
+ res = MP_OKAY;
+LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
+ return res;
+}
+
+
+/* compare maginitude of two ints (unsigned) */
+static int mp_cmp_mag (mp_int * a, mp_int * b)
+{
+ int n;
+ mp_digit *tmpa, *tmpb;
+
+ /* compare based on # of non-zero digits */
+ if (a->used > b->used) {
+ return MP_GT;
+ }
+
+ if (a->used < b->used) {
+ return MP_LT;
+ }
+
+ /* alias for a */
+ tmpa = a->dp + (a->used - 1);
+
+ /* alias for b */
+ tmpb = b->dp + (a->used - 1);
+
+ /* compare based on digits */
+ for (n = 0; n < a->used; ++n, --tmpa, --tmpb) {
+ if (*tmpa > *tmpb) {
+ return MP_GT;
+ }
+
+ if (*tmpa < *tmpb) {
+ return MP_LT;
+ }
+ }
+ return MP_EQ;
+}
+
+
+/* reads a unsigned char array, assumes the msb is stored first [big endian] */
+static int mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
+{
+ int res;
+
+ /* make sure there are at least two digits */
+ if (a->alloc < 2) {
+ if ((res = mp_grow(a, 2)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* zero the int */
+ mp_zero (a);
+
+ /* read the bytes in */
+ while (c-- > 0) {
+ if ((res = mp_mul_2d (a, 8, a)) != MP_OKAY) {
+ return res;
+ }
+
+#ifndef MP_8BIT
+ a->dp[0] |= *b++;
+ a->used += 1;
+#else
+ a->dp[0] = (*b & MP_MASK);
+ a->dp[1] |= ((*b++ >> 7U) & 1);
+ a->used += 2;
+#endif
+ }
+ mp_clamp (a);
+ return MP_OKAY;
+}
+
+
+/* store in unsigned [big endian] format */
+static int mp_to_unsigned_bin (mp_int * a, unsigned char *b)
+{
+ int x, res;
+ mp_int t;
+
+ if ((res = mp_init_copy (&t, a)) != MP_OKAY) {
+ return res;
+ }
+
+ x = 0;
+ while (mp_iszero (&t) == 0) {
+#ifndef MP_8BIT
+ b[x++] = (unsigned char) (t.dp[0] & 255);
+#else
+ b[x++] = (unsigned char) (t.dp[0] | ((t.dp[1] & 0x01) << 7));
+#endif
+ if ((res = mp_div_2d (&t, 8, &t, NULL)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ }
+ bn_reverse (b, x);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+
+
+/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
+static int mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
+{
+ mp_digit D, r, rr;
+ int x, res;
+ mp_int t;
+
+
+ /* if the shift count is <= 0 then we do no work */
+ if (b <= 0) {
+ res = mp_copy (a, c);
+ if (d != NULL) {
+ mp_zero (d);
+ }
+ return res;
+ }
+
+ if ((res = mp_init (&t)) != MP_OKAY) {
+ return res;
+ }
+
+ /* get the remainder */
+ if (d != NULL) {
+ if ((res = mp_mod_2d (a, b, &t)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+ }
+
+ /* copy */
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ mp_clear (&t);
+ return res;
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= (int)DIGIT_BIT) {
+ mp_rshd (c, b / DIGIT_BIT);
+ }
+
+ /* shift any bit count < DIGIT_BIT */
+ D = (mp_digit) (b % DIGIT_BIT);
+ if (D != 0) {
+ register mp_digit *tmpc, mask, shift;
+
+ /* mask */
+ mask = (((mp_digit)1) << D) - 1;
+
+ /* shift for lsb */
+ shift = DIGIT_BIT - D;
+
+ /* alias */
+ tmpc = c->dp + (c->used - 1);
+
+ /* carry */
+ r = 0;
+ for (x = c->used - 1; x >= 0; x--) {
+ /* get the lower bits of this word in a temp */
+ rr = *tmpc & mask;
+
+ /* shift the current word and mix in the carry bits from the previous word */
+ *tmpc = (*tmpc >> D) | (r << shift);
+ --tmpc;
+
+ /* set the carry to the carry bits of the current word found above */
+ r = rr;
+ }
+ }
+ mp_clamp (c);
+ if (d != NULL) {
+ mp_exch (&t, d);
+ }
+ mp_clear (&t);
+ return MP_OKAY;
+}
+
+
+static int mp_init_copy (mp_int * a, mp_int * b)
+{
+ int res;
+
+ if ((res = mp_init (a)) != MP_OKAY) {
+ return res;
+ }
+ return mp_copy (b, a);
+}
+
+
+/* set to zero */
+static void mp_zero (mp_int * a)
+{
+ int n;
+ mp_digit *tmp;
+
+ a->sign = MP_ZPOS;
+ a->used = 0;
+
+ tmp = a->dp;
+ for (n = 0; n < a->alloc; n++) {
+ *tmp++ = 0;
+ }
+}
+
+
+/* copy, b = a */
+static int mp_copy (mp_int * a, mp_int * b)
+{
+ int res, n;
+
+ /* if dst == src do nothing */
+ if (a == b) {
+ return MP_OKAY;
+ }
+
+ /* grow dest */
+ if (b->alloc < a->used) {
+ if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* zero b and copy the parameters over */
+ {
+ register mp_digit *tmpa, *tmpb;
+
+ /* pointer aliases */
+
+ /* source */
+ tmpa = a->dp;
+
+ /* destination */
+ tmpb = b->dp;
+
+ /* copy all the digits */
+ for (n = 0; n < a->used; n++) {
+ *tmpb++ = *tmpa++;
+ }
+
+ /* clear high digits */
+ for (; n < b->used; n++) {
+ *tmpb++ = 0;
+ }
+ }
+
+ /* copy used count and sign */
+ b->used = a->used;
+ b->sign = a->sign;
+ return MP_OKAY;
+}
+
+
+/* shift right a certain amount of digits */
+static void mp_rshd (mp_int * a, int b)
+{
+ int x;
+
+ /* if b <= 0 then ignore it */
+ if (b <= 0) {
+ return;
+ }
+
+ /* if b > used then simply zero it and return */
+ if (a->used <= b) {
+ mp_zero (a);
+ return;
+ }
+
+ {
+ register mp_digit *bottom, *top;
+
+ /* shift the digits down */
+
+ /* bottom */
+ bottom = a->dp;
+
+ /* top [offset into digits] */
+ top = a->dp + b;
+
+ /* this is implemented as a sliding window where
+ * the window is b-digits long and digits from
+ * the top of the window are copied to the bottom
+ *
+ * e.g.
+
+ b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
+ /\ | ---->
+ \-------------------/ ---->
+ */
+ for (x = 0; x < (a->used - b); x++) {
+ *bottom++ = *top++;
+ }
+
+ /* zero the top digits */
+ for (; x < a->used; x++) {
+ *bottom++ = 0;
+ }
+ }
+
+ /* remove excess digits */
+ a->used -= b;
+}
+
+
+/* swap the elements of two integers, for cases where you can't simply swap the
+ * mp_int pointers around
+ */
+static void mp_exch (mp_int * a, mp_int * b)
+{
+ mp_int t;
+
+ t = *a;
+ *a = *b;
+ *b = t;
+}
+
+
+/* trim unused digits
+ *
+ * This is used to ensure that leading zero digits are
+ * trimed and the leading "used" digit will be non-zero
+ * Typically very fast. Also fixes the sign if there
+ * are no more leading digits
+ */
+static void mp_clamp (mp_int * a)
+{
+ /* decrease used while the most significant digit is
+ * zero.
+ */
+ while (a->used > 0 && a->dp[a->used - 1] == 0) {
+ --(a->used);
+ }
+
+ /* reset the sign flag if used == 0 */
+ if (a->used == 0) {
+ a->sign = MP_ZPOS;
+ }
+}
+
+
+/* grow as required */
+static int mp_grow (mp_int * a, int size)
+{
+ int i;
+ mp_digit *tmp;
+
+ /* if the alloc size is smaller alloc more ram */
+ if (a->alloc < size) {
+ /* ensure there are always at least MP_PREC digits extra on top */
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
+ /* reallocate the array a->dp
+ *
+ * We store the return in a temporary variable
+ * in case the operation failed we don't want
+ * to overwrite the dp member of a.
+ */
+ tmp = OPT_CAST(mp_digit) XREALLOC (a->dp, sizeof (mp_digit) * size);
+ if (tmp == NULL) {
+ /* reallocation failed but "a" is still valid [can be freed] */
+ return MP_MEM;
+ }
+
+ /* reallocation succeeded so set a->dp */
+ a->dp = tmp;
+
+ /* zero excess digits */
+ i = a->alloc;
+ a->alloc = size;
+ for (; i < a->alloc; i++) {
+ a->dp[i] = 0;
+ }
+ }
+ return MP_OKAY;
+}
+
+
+/* b = |a|
+ *
+ * Simple function copies the input and fixes the sign to positive
+ */
+static int mp_abs (mp_int * a, mp_int * b)
+{
+ int res;
+
+ /* copy a to b */
+ if (a != b) {
+ if ((res = mp_copy (a, b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* force the sign of b to positive */
+ b->sign = MP_ZPOS;
+
+ return MP_OKAY;
+}
+
+
+/* set to a digit */
+static void mp_set (mp_int * a, mp_digit b)
+{
+ mp_zero (a);
+ a->dp[0] = b & MP_MASK;
+ a->used = (a->dp[0] != 0) ? 1 : 0;
+}
+
+
+/* b = a/2 */
+static int mp_div_2(mp_int * a, mp_int * b)
+{
+ int x, res, oldused;
+
+ /* copy */
+ if (b->alloc < a->used) {
+ if ((res = mp_grow (b, a->used)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ oldused = b->used;
+ b->used = a->used;
+ {
+ register mp_digit r, rr, *tmpa, *tmpb;
+
+ /* source alias */
+ tmpa = a->dp + b->used - 1;
+
+ /* dest alias */
+ tmpb = b->dp + b->used - 1;
+
+ /* carry */
+ r = 0;
+ for (x = b->used - 1; x >= 0; x--) {
+ /* get the carry for the next iteration */
+ rr = *tmpa & 1;
+
+ /* shift the current digit, add in carry and store */
+ *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
+
+ /* forward carry to next iteration */
+ r = rr;
+ }
+
+ /* zero excess digits */
+ tmpb = b->dp + b->used;
+ for (x = b->used; x < oldused; x++) {
+ *tmpb++ = 0;
+ }
+ }
+ b->sign = a->sign;
+ mp_clamp (b);
+ return MP_OKAY;
+}
+
+
+/* shift left by a certain bit count */
+static int mp_mul_2d (mp_int * a, int b, mp_int * c)
+{
+ mp_digit d;
+ int res;
+
+ /* copy */
+ if (a != c) {
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ if (c->alloc < (int)(c->used + b/DIGIT_BIT + 1)) {
+ if ((res = mp_grow (c, c->used + b / DIGIT_BIT + 1)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* shift by as many digits in the bit count */
+ if (b >= (int)DIGIT_BIT) {
+ if ((res = mp_lshd (c, b / DIGIT_BIT)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* shift any bit count < DIGIT_BIT */
+ d = (mp_digit) (b % DIGIT_BIT);
+ if (d != 0) {
+ register mp_digit *tmpc, shift, mask, r, rr;
+ register int x;
+
+ /* bitmask for carries */
+ mask = (((mp_digit)1) << d) - 1;
+
+ /* shift for msbs */
+ shift = DIGIT_BIT - d;
+
+ /* alias */
+ tmpc = c->dp;
+
+ /* carry */
+ r = 0;
+ for (x = 0; x < c->used; x++) {
+ /* get the higher bits of the current word */
+ rr = (*tmpc >> shift) & mask;
+
+ /* shift the current word and OR in the carry */
+ *tmpc = ((*tmpc << d) | r) & MP_MASK;
+ ++tmpc;
+
+ /* set the carry to the carry bits of the current word */
+ r = rr;
+ }
+
+ /* set final carry */
+ if (r != 0) {
+ c->dp[(c->used)++] = r;
+ }
+ }
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+
+static int mp_init_multi(mp_int *mp, ...)
+{
+ mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
+ int n = 0; /* Number of ok inits */
+ mp_int* cur_arg = mp;
+ va_list args;
+
+ va_start(args, mp); /* init args to next argument from caller */
+ while (cur_arg != NULL) {
+ if (mp_init(cur_arg) != MP_OKAY) {
+ /* Oops - error! Back-track and mp_clear what we already
+ succeeded in init-ing, then return error.
+ */
+ va_list clean_args;
+
+ /* end the current list */
+ va_end(args);
+
+ /* now start cleaning up */
+ cur_arg = mp;
+ va_start(clean_args, mp);
+ while (n--) {
+ mp_clear(cur_arg);
+ cur_arg = va_arg(clean_args, mp_int*);
+ }
+ va_end(clean_args);
+ res = MP_MEM;
+ break;
+ }
+ n++;
+ cur_arg = va_arg(args, mp_int*);
+ }
+ va_end(args);
+ return res; /* Assumed ok, if error flagged above. */
+}
+
+
+static void mp_clear_multi(mp_int *mp, ...)
+{
+ mp_int* next_mp = mp;
+ va_list args;
+ va_start(args, mp);
+ while (next_mp != NULL) {
+ mp_clear(next_mp);
+ next_mp = va_arg(args, mp_int*);
+ }
+ va_end(args);
+}
+
+
+/* shift left a certain amount of digits */
+static int mp_lshd (mp_int * a, int b)
+{
+ int x, res;
+
+ /* if its less than zero return */
+ if (b <= 0) {
+ return MP_OKAY;
+ }
+
+ /* grow to fit the new digits */
+ if (a->alloc < a->used + b) {
+ if ((res = mp_grow (a, a->used + b)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ {
+ register mp_digit *top, *bottom;
+
+ /* increment the used by the shift amount then copy upwards */
+ a->used += b;
+
+ /* top */
+ top = a->dp + a->used - 1;
+
+ /* base */
+ bottom = a->dp + a->used - 1 - b;
+
+ /* much like mp_rshd this is implemented using a sliding window
+ * except the window goes the otherway around. Copying from
+ * the bottom to the top. see bn_mp_rshd.c for more info.
+ */
+ for (x = a->used - 1; x >= b; x--) {
+ *top-- = *bottom--;
+ }
+
+ /* zero the lower digits */
+ top = a->dp;
+ for (x = 0; x < b; x++) {
+ *top++ = 0;
+ }
+ }
+ return MP_OKAY;
+}
+
+
+/* returns the number of bits in an int */
+static int mp_count_bits (mp_int * a)
+{
+ int r;
+ mp_digit q;
+
+ /* shortcut */
+ if (a->used == 0) {
+ return 0;
+ }
+
+ /* get number of digits and add that */
+ r = (a->used - 1) * DIGIT_BIT;
+
+ /* take the last digit and count the bits in it */
+ q = a->dp[a->used - 1];
+ while (q > ((mp_digit) 0)) {
+ ++r;
+ q >>= ((mp_digit) 1);
+ }
+ return r;
+}
+
+
+/* calc a value mod 2**b */
+static int mp_mod_2d (mp_int * a, int b, mp_int * c)
+{
+ int x, res;
+
+ /* if b is <= 0 then zero the int */
+ if (b <= 0) {
+ mp_zero (c);
+ return MP_OKAY;
+ }
+
+ /* if the modulus is larger than the value than return */
+ if (b >= (int) (a->used * DIGIT_BIT)) {
+ res = mp_copy (a, c);
+ return res;
+ }
+
+ /* copy */
+ if ((res = mp_copy (a, c)) != MP_OKAY) {
+ return res;
+ }
+
+ /* zero digits above the last digit of the modulus */
+ for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
+ c->dp[x] = 0;
+ }
+ /* clear the digit that is not completely outside/inside the modulus */
+ c->dp[b / DIGIT_BIT] &=
+ (mp_digit) ((((mp_digit) 1) << (((mp_digit) b) % DIGIT_BIT)) - ((mp_digit) 1));
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+
+/* slower bit-bang division... also smaller */
+static int mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
+{
+ mp_int ta, tb, tq, q;
+ int res, n, n2;
+
+ /* is divisor zero ? */
+ if (mp_iszero (b) == 1) {
+ return MP_VAL;
+ }
+
+ /* if a < b then q=0, r = a */
+ if (mp_cmp_mag (a, b) == MP_LT) {
+ if (d != NULL) {
+ res = mp_copy (a, d);
+ } else {
+ res = MP_OKAY;
+ }
+ if (c != NULL) {
+ mp_zero (c);
+ }
+ return res;
+ }
+
+ /* init our temps */
+ if ((res = mp_init_multi(&ta, &tb, &tq, &q, NULL) != MP_OKAY)) {
+ return res;
+ }
+
+
+ mp_set(&tq, 1);
+ n = mp_count_bits(a) - mp_count_bits(b);
+ if (((res = mp_abs(a, &ta)) != MP_OKAY) ||
+ ((res = mp_abs(b, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tb, n, &tb)) != MP_OKAY) ||
+ ((res = mp_mul_2d(&tq, n, &tq)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+
+ while (n-- >= 0) {
+ if (mp_cmp(&tb, &ta) != MP_GT) {
+ if (((res = mp_sub(&ta, &tb, &ta)) != MP_OKAY) ||
+ ((res = mp_add(&q, &tq, &q)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+ }
+ if (((res = mp_div_2d(&tb, 1, &tb, NULL)) != MP_OKAY) ||
+ ((res = mp_div_2d(&tq, 1, &tq, NULL)) != MP_OKAY)) {
+ goto LBL_ERR;
+ }
+ }
+
+ /* now q == quotient and ta == remainder */
+ n = a->sign;
+ n2 = (a->sign == b->sign ? MP_ZPOS : MP_NEG);
+ if (c != NULL) {
+ mp_exch(c, &q);
+ c->sign = (mp_iszero(c) == MP_YES) ? MP_ZPOS : n2;
+ }
+ if (d != NULL) {
+ mp_exch(d, &ta);
+ d->sign = (mp_iszero(d) == MP_YES) ? MP_ZPOS : n;
+ }
+LBL_ERR:
+ mp_clear_multi(&ta, &tb, &tq, &q, NULL);
+ return res;
+}
+
+
+#ifdef MP_LOW_MEM
+ #define TAB_SIZE 32
+#else
+ #define TAB_SIZE 256
+#endif
+
+static int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
+{
+ mp_int M[TAB_SIZE], res, mu;
+ mp_digit buf;
+ int err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
+ int (*redux)(mp_int*,mp_int*,mp_int*);
+
+ /* find window size */
+ x = mp_count_bits (X);
+ if (x <= 7) {
+ winsize = 2;
+ } else if (x <= 36) {
+ winsize = 3;
+ } else if (x <= 140) {
+ winsize = 4;
+ } else if (x <= 450) {
+ winsize = 5;
+ } else if (x <= 1303) {
+ winsize = 6;
+ } else if (x <= 3529) {
+ winsize = 7;
+ } else {
+ winsize = 8;
+ }
+
+#ifdef MP_LOW_MEM
+ if (winsize > 5) {
+ winsize = 5;
+ }
+#endif
+
+ /* init M array */
+ /* init first cell */
+ if ((err = mp_init(&M[1])) != MP_OKAY) {
+ return err;
+ }
+
+ /* now init the second half of the array */
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ if ((err = mp_init(&M[x])) != MP_OKAY) {
+ for (y = 1<<(winsize-1); y < x; y++) {
+ mp_clear (&M[y]);
+ }
+ mp_clear(&M[1]);
+ return err;
+ }
+ }
+
+ /* create mu, used for Barrett reduction */
+ if ((err = mp_init (&mu)) != MP_OKAY) {
+ goto LBL_M;
+ }
+
+ if (redmode == 0) {
+ if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ redux = mp_reduce;
+ } else {
+ if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ redux = mp_reduce_2k_l;
+ }
+
+ /* create M table
+ *
+ * The M table contains powers of the base,
+ * e.g. M[x] = G**x mod P
+ *
+ * The first half of the table is not
+ * computed though accept for M[0] and M[1]
+ */
+ if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+
+ /* compute the value at M[1<<(winsize-1)] by squaring
+ * M[1] (winsize-1) times
+ */
+ if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+
+ for (x = 0; x < (winsize - 1); x++) {
+ /* square it */
+ if ((err = mp_sqr (&M[1 << (winsize - 1)],
+ &M[1 << (winsize - 1)])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+
+ /* reduce modulo P */
+ if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ }
+
+ /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
+ * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
+ */
+ for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
+ if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ }
+
+ /* setup result */
+ if ((err = mp_init (&res)) != MP_OKAY) {
+ goto LBL_MU;
+ }
+ mp_set (&res, 1);
+
+ /* set initial mode and bit cnt */
+ mode = 0;
+ bitcnt = 1;
+ buf = 0;
+ digidx = X->used - 1;
+ bitcpy = 0;
+ bitbuf = 0;
+
+ for (;;) {
+ /* grab next digit as required */
+ if (--bitcnt == 0) {
+ /* if digidx == -1 we are out of digits */
+ if (digidx == -1) {
+ break;
+ }
+ /* read next digit and reset the bitcnt */
+ buf = X->dp[digidx--];
+ bitcnt = (int) DIGIT_BIT;
+ }
+
+ /* grab the next msb from the exponent */
+ y = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
+ buf <<= (mp_digit)1;
+
+ /* if the bit is zero and mode == 0 then we ignore it
+ * These represent the leading zero bits before the first 1 bit
+ * in the exponent. Technically this opt is not required but it
+ * does lower the # of trivial squaring/reductions used
+ */
+ if (mode == 0 && y == 0) {
+ continue;
+ }
+
+ /* if the bit is zero and mode == 1 then we square */
+ if (mode == 1 && y == 0) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ continue;
+ }
+
+ /* else we add it to the window */
+ bitbuf |= (y << (winsize - ++bitcpy));
+ mode = 2;
+
+ if (bitcpy == winsize) {
+ /* ok window is filled so square as required and multiply */
+ /* square first */
+ for (x = 0; x < winsize; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ /* empty window and reset */
+ bitcpy = 0;
+ bitbuf = 0;
+ mode = 1;
+ }
+ }
+
+ /* if bits remain then square/multiply */
+ if (mode == 2 && bitcpy > 0) {
+ /* square then multiply if the bit is set */
+ for (x = 0; x < bitcpy; x++) {
+ if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+
+ bitbuf <<= 1;
+ if ((bitbuf & (1 << winsize)) != 0) {
+ /* then multiply */
+ if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ if ((err = redux (&res, P, &mu)) != MP_OKAY) {
+ goto LBL_RES;
+ }
+ }
+ }
+ }
+
+ mp_exch (&res, Y);
+ err = MP_OKAY;
+LBL_RES:mp_clear (&res);
+LBL_MU:mp_clear (&mu);
+LBL_M:
+ mp_clear(&M[1]);
+ for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
+ mp_clear (&M[x]);
+ }
+ return err;
+}
+
+
+/* computes b = a*a */
+static int mp_sqr (mp_int * a, mp_int * b)
+{
+ int res;
+
+#ifdef BN_MP_TOOM_SQR_C
+ /* use Toom-Cook? */
+ if (a->used >= TOOM_SQR_CUTOFF) {
+ res = mp_toom_sqr(a, b);
+ /* Karatsuba? */
+ } else
+#endif
+#ifdef BN_MP_KARATSUBA_SQR_C
+if (a->used >= KARATSUBA_SQR_CUTOFF) {
+ res = mp_karatsuba_sqr (a, b);
+ } else
+#endif
+ {
+#ifdef BN_FAST_S_MP_SQR_C
+ /* can we use the fast comba multiplier? */
+ if ((a->used * 2 + 1) < MP_WARRAY &&
+ a->used <
+ (1 << (sizeof(mp_word) * CHAR_BIT - 2*DIGIT_BIT - 1))) {
+ res = fast_s_mp_sqr (a, b);
+ } else
+#endif
+#ifdef BN_S_MP_SQR_C
+ res = s_mp_sqr (a, b);
+#else
+#error mp_sqr could fail
+ res = MP_VAL;
+#endif
+ }
+ b->sign = MP_ZPOS;
+ return res;
+}
+
+
+/* reduces a modulo n where n is of the form 2**p - d
+ This differs from reduce_2k since "d" can be larger
+ than a single digit.
+*/
+static int mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
+{
+ mp_int q;
+ int p, res;
+
+ if ((res = mp_init(&q)) != MP_OKAY) {
+ return res;
+ }
+
+ p = mp_count_bits(n);
+top:
+ /* q = a/2**p, a = a mod 2**p */
+ if ((res = mp_div_2d(a, p, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* q = q * d */
+ if ((res = mp_mul(&q, d, &q)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ /* a = a + q */
+ if ((res = s_mp_add(a, &q, a)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if (mp_cmp_mag(a, n) != MP_LT) {
+ s_mp_sub(a, n, a);
+ goto top;
+ }
+
+ERR:
+ mp_clear(&q);
+ return res;
+}
+
+
+/* determines the setup value */
+static int mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
+{
+ int res;
+ mp_int tmp;
+
+ if ((res = mp_init(&tmp)) != MP_OKAY) {
+ return res;
+ }
+
+ if ((res = mp_2expt(&tmp, mp_count_bits(a))) != MP_OKAY) {
+ goto ERR;
+ }
+
+ if ((res = s_mp_sub(&tmp, a, d)) != MP_OKAY) {
+ goto ERR;
+ }
+
+ERR:
+ mp_clear(&tmp);
+ return res;
+}
+
+
+/* computes a = 2**b
+ *
+ * Simple algorithm which zeroes the int, grows it then just sets one bit
+ * as required.
+ */
+static int mp_2expt (mp_int * a, int b)
+{
+ int res;
+
+ /* zero a as per default */
+ mp_zero (a);
+
+ /* grow a to accomodate the single bit */
+ if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
+ return res;
+ }
+
+ /* set the used count of where the bit will go */
+ a->used = b / DIGIT_BIT + 1;
+
+ /* put the single bit in its place */
+ a->dp[b / DIGIT_BIT] = ((mp_digit)1) << (b % DIGIT_BIT);
+
+ return MP_OKAY;
+}
+
+
+/* pre-calculate the value required for Barrett reduction
+ * For a given modulus "b" it calulates the value required in "a"
+ */
+static int mp_reduce_setup (mp_int * a, mp_int * b)
+{
+ int res;
+
+ if ((res = mp_2expt (a, b->used * 2 * DIGIT_BIT)) != MP_OKAY) {
+ return res;
+ }
+ return mp_div (a, b, a, NULL);
+}
+
+
+/* reduces x mod m, assumes 0 < x < m**2, mu is
+ * precomputed via mp_reduce_setup.
+ * From HAC pp.604 Algorithm 14.42
+ */
+static int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
+{
+ mp_int q;
+ int res, um = m->used;
+
+ /* q = x */
+ if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
+ return res;
+ }
+
+ /* q1 = x / b**(k-1) */
+ mp_rshd (&q, um - 1);
+
+ /* according to HAC this optimization is ok */
+ if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
+ if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ } else {
+#ifdef BN_S_MP_MUL_HIGH_DIGS_C
+ if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
+ if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+#else
+ {
+#error mp_reduce would always fail
+ res = MP_VAL;
+ goto CLEANUP;
+ }
+#endif
+ }
+
+ /* q3 = q2 / b**(k+1) */
+ mp_rshd (&q, um + 1);
+
+ /* x = x mod b**(k+1), quick (no division) */
+ if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* q = q * m mod b**(k+1), quick (no division) */
+ if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* x = x - q */
+ if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+
+ /* If x < 0, add b**(k+1) to it */
+ if (mp_cmp_d (x, 0) == MP_LT) {
+ mp_set (&q, 1);
+ if ((res = mp_lshd (&q, um + 1)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ if ((res = mp_add (x, &q, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ }
+
+ /* Back off if it's too big */
+ while (mp_cmp (x, m) != MP_LT) {
+ if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
+ goto CLEANUP;
+ }
+ }
+
+CLEANUP:
+ mp_clear (&q);
+
+ return res;
+}
+
+
+/* multiplies |a| * |b| and only computes upto digs digits of result
+ * HAC pp. 595, Algorithm 14.12 Modified so you can control how
+ * many digits of output are created.
+ */
+static int s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ mp_int t;
+ int res, pa, pb, ix, iy;
+ mp_digit u;
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
+ /* can we use the fast multiplier? */
+ if (((digs) < MP_WARRAY) &&
+ MIN (a->used, b->used) <
+ (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_s_mp_mul_digs (a, b, c, digs);
+ }
+
+ if ((res = mp_init_size (&t, digs)) != MP_OKAY) {
+ return res;
+ }
+ t.used = digs;
+
+ /* compute the digits of the product directly */
+ pa = a->used;
+ for (ix = 0; ix < pa; ix++) {
+ /* set the carry to zero */
+ u = 0;
+
+ /* limit ourselves to making digs digits of output */
+ pb = MIN (b->used, digs - ix);
+
+ /* setup some aliases */
+ /* copy of the digit from a used within the nested loop */
+ tmpx = a->dp[ix];
+
+ /* an alias for the destination shifted ix places */
+ tmpt = t.dp + ix;
+
+ /* an alias for the digits of b */
+ tmpy = b->dp;
+
+ /* compute the columns of the output and propagate the carry */
+ for (iy = 0; iy < pb; iy++) {
+ /* compute the column as a mp_word */
+ r = ((mp_word)*tmpt) +
+ ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+ ((mp_word) u);
+
+ /* the new column is the lower part of the result */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get the carry word from the result */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+ /* set carry if it is placed below digs */
+ if (ix + iy < digs) {
+ *tmpt = u;
+ }
+ }
+
+ mp_clamp (&t);
+ mp_exch (&t, c);
+
+ mp_clear (&t);
+ return MP_OKAY;
+}
+
+
+/* Fast (comba) multiplier
+ *
+ * This is the fast column-array [comba] multiplier. It is
+ * designed to compute the columns of the product first
+ * then handle the carries afterwards. This has the effect
+ * of making the nested loops that compute the columns very
+ * simple and schedulable on super-scalar processors.
+ *
+ * This has been modified to produce a variable number of
+ * digits of output so if say only a half-product is required
+ * you don't have to compute the upper half (a feature
+ * required for fast Barrett reduction).
+ *
+ * Based on Algorithm 14.12 on pp.595 of HAC.
+ *
+ */
+static int fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ int olduse, res, pa, ix, iz;
+ mp_digit W[MP_WARRAY];
+ register mp_word _W;
+
+ /* grow the destination as required */
+ if (c->alloc < digs) {
+ if ((res = mp_grow (c, digs)) != MP_OKAY) {
+ return res;
+ }
+ }
+
+ /* number of output digits to produce */
+ pa = MIN(digs, a->used + b->used);
+
+ /* clear the carry */
+ _W = 0;
+ for (ix = 0; ix < pa; ix++) {
+ int tx, ty;
+ int iy;
+ mp_digit *tmpx, *tmpy;
+
+ /* get offsets into the two bignums */
+ ty = MIN(b->used-1, ix);
+ tx = ix - ty;
+
+ /* setup temp aliases */
+ tmpx = a->dp + tx;
+ tmpy = b->dp + ty;
+
+ /* this is the number of times the loop will iterrate, essentially
+ while (tx++ < a->used && ty-- >= 0) { ... }
+ */
+ iy = MIN(a->used-tx, ty+1);
+
+ /* execute loop */
+ for (iz = 0; iz < iy; ++iz) {
+ _W += ((mp_word)*tmpx++)*((mp_word)*tmpy--);
+
+ }
+
+ /* store term */
+ W[ix] = ((mp_digit)_W) & MP_MASK;
+
+ /* make next carry */
+ _W = _W >> ((mp_word)DIGIT_BIT);
+ }
+
+ /* setup dest */
+ olduse = c->used;
+ c->used = pa;
+
+ {
+ register mp_digit *tmpc;
+ tmpc = c->dp;
+ for (ix = 0; ix < pa+1; ix++) {
+ /* now extract the previous digit [below the carry] */
+ *tmpc++ = W[ix];
+ }
+
+ /* clear unused digits [that existed in the old copy of c] */
+ for (; ix < olduse; ix++) {
+ *tmpc++ = 0;
+ }
+ }
+ mp_clamp (c);
+ return MP_OKAY;
+}
+
+
+/* init an mp_init for a given size */
+static int mp_init_size (mp_int * a, int size)
+{
+ int x;
+
+ /* pad size so there are always extra digits */
+ size += (MP_PREC * 2) - (size % MP_PREC);
+
+ /* alloc mem */
+ a->dp = OPT_CAST(mp_digit) XMALLOC (sizeof (mp_digit) * size);
+ if (a->dp == NULL) {
+ return MP_MEM;
+ }
+
+ /* set the members */
+ a->used = 0;
+ a->alloc = size;
+ a->sign = MP_ZPOS;
+
+ /* zero the digits */
+ for (x = 0; x < size; x++) {
+ a->dp[x] = 0;
+ }
+
+ return MP_OKAY;
+}
+
+
+/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
+static int s_mp_sqr (mp_int * a, mp_int * b)
+{
+ mp_int t;
+ int res, ix, iy, pa;
+ mp_word r;
+ mp_digit u, tmpx, *tmpt;
+
+ pa = a->used;
+ if ((res = mp_init_size (&t, 2*pa + 1)) != MP_OKAY) {
+ return res;
+ }
+
+ /* default used is maximum possible size */
+ t.used = 2*pa + 1;
+
+ for (ix = 0; ix < pa; ix++) {
+ /* first calculate the digit at 2*ix */
+ /* calculate double precision result */
+ r = ((mp_word) t.dp[2*ix]) +
+ ((mp_word)a->dp[ix])*((mp_word)a->dp[ix]);
+
+ /* store lower part in result */
+ t.dp[ix+ix] = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get the carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+
+ /* left hand side of A[ix] * A[iy] */
+ tmpx = a->dp[ix];
+
+ /* alias for where to store the results */
+ tmpt = t.dp + (2*ix + 1);
+
+ for (iy = ix + 1; iy < pa; iy++) {
+ /* first calculate the product */
+ r = ((mp_word)tmpx) * ((mp_word)a->dp[iy]);
+
+ /* now calculate the double precision result, note we use
+ * addition instead of *2 since it's easier to optimize
+ */
+ r = ((mp_word) *tmpt) + r + r + ((mp_word) u);
+
+ /* store lower part */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* get carry */
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+ }
+ /* propagate upwards */
+ while (u != ((mp_digit) 0)) {
+ r = ((mp_word) *tmpt) + ((mp_word) u);
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+ u = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
+ }
+ }
+
+ mp_clamp (&t);
+ mp_exch (&t, b);
+ mp_clear (&t);
+ return MP_OKAY;
+}
+
+
+/* multiplies |a| * |b| and does not compute the lower digs digits
+ * [meant to get the higher part of the product]
+ */
+static int s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
+{
+ mp_int t;
+ int res, pa, pb, ix, iy;
+ mp_digit u;
+ mp_word r;
+ mp_digit tmpx, *tmpt, *tmpy;
+
+ /* can we use the fast multiplier? */
+#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
+ if (((a->used + b->used + 1) < MP_WARRAY)
+ && MIN (a->used, b->used) < (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
+ return fast_s_mp_mul_high_digs (a, b, c, digs);
+ }
+#endif
+
+ if ((res = mp_init_size (&t, a->used + b->used + 1)) != MP_OKAY) {
+ return res;
+ }
+ t.used = a->used + b->used + 1;
+
+ pa = a->used;
+ pb = b->used;
+ for (ix = 0; ix < pa; ix++) {
+ /* clear the carry */
+ u = 0;
+
+ /* left hand side of A[ix] * B[iy] */
+ tmpx = a->dp[ix];
+
+ /* alias to the address of where the digits will be stored */
+ tmpt = &(t.dp[digs]);
+
+ /* alias for where to read the right hand side from */
+ tmpy = b->dp + (digs - ix);
+
+ for (iy = digs - ix; iy < pb; iy++) {
+ /* calculate the double precision result */
+ r = ((mp_word)*tmpt) +
+ ((mp_word)tmpx) * ((mp_word)*tmpy++) +
+ ((mp_word) u);
+
+ /* get the lower part */
+ *tmpt++ = (mp_digit) (r & ((mp_word) MP_MASK));
+
+ /* carry the carry */
+ u = (mp_digit) (r >> ((mp_word) DIGIT_BIT));
+ }
+ *tmpt = u;
+ }
+ mp_clamp (&t);
+ mp_exch (&t, c);
+ mp_clear (&t);
+ return MP_OKAY;
+}
diff --git a/contrib/wpa_supplicant/main.c b/contrib/wpa_supplicant/main.c
index 8d8266691cd9..fdce7c51452b 100644
--- a/contrib/wpa_supplicant/main.c
+++ b/contrib/wpa_supplicant/main.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / main() function for UNIX like OSes and MinGW
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,11 +12,10 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
+#include "includes.h"
+#ifdef __linux__
#include <fcntl.h>
+#endif /* __linux__ */
#include "common.h"
#include "wpa_supplicant_i.h"
@@ -25,7 +24,11 @@
extern const char *wpa_supplicant_version;
extern const char *wpa_supplicant_license;
#ifndef CONFIG_NO_STDOUT_DEBUG
-extern const char *wpa_supplicant_full_license;
+extern const char *wpa_supplicant_full_license1;
+extern const char *wpa_supplicant_full_license2;
+extern const char *wpa_supplicant_full_license3;
+extern const char *wpa_supplicant_full_license4;
+extern const char *wpa_supplicant_full_license5;
#endif /* CONFIG_NO_STDOUT_DEBUG */
extern struct wpa_driver_ops *wpa_supplicant_drivers[];
@@ -36,12 +39,13 @@ static void usage(void)
int i;
printf("%s\n\n%s\n"
"usage:\n"
- " wpa_supplicant [-BddehLqqvwW] [-P<pid file>] "
+ " wpa_supplicant [-BddehLqquvwW] [-P<pid file>] "
"[-g<global ctrl>] \\\n"
" -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
"[-p<driver_param>] \\\n"
- " [-N -i<ifname> -c<conf> [-C<ctrl>] [-D<driver>] "
- "[-p<driver_param>] ...]\n"
+ " [-b<br_ifname> [-N -i<ifname> -c<conf> [-C<ctrl>] "
+ "[-D<driver>] \\\n"
+ " [-p<driver_param>] [-b<br_ifname>] ...]\n"
"\n"
"drivers:\n",
wpa_supplicant_version, wpa_supplicant_license);
@@ -54,6 +58,7 @@ static void usage(void)
#ifndef CONFIG_NO_STDOUT_DEBUG
printf("options:\n"
+ " -b = optional bridge interface name\n"
" -B = run daemon in the background\n"
" -c = Configuration file\n"
" -C = ctrl_interface parameter (only used if -c is not)\n"
@@ -64,10 +69,13 @@ static void usage(void)
" -K = include keys (passwords, etc.) in debug output\n"
" -t = include timestamp in debug messages\n"
" -h = show this help text\n"
- " -L = show license (GPL and BSD)\n"
- " -p = driver parameters\n"
+ " -L = show license (GPL and BSD)\n");
+ printf(" -p = driver parameters\n"
" -P = PID file\n"
" -q = decrease debugging verbosity (-qq even less)\n"
+#ifdef CONFIG_CTRL_IFACE_DBUS
+ " -u = enable DBus control interface\n"
+#endif /* CONFIG_CTRL_IFACE_DBUS */
" -v = show version\n"
" -w = wait for interface to be added, if needed\n"
" -W = wait for a control interface monitor before starting\n"
@@ -82,14 +90,20 @@ static void usage(void)
static void license(void)
{
#ifndef CONFIG_NO_STDOUT_DEBUG
- printf("%s\n\n%s\n",
- wpa_supplicant_version, wpa_supplicant_full_license);
+ printf("%s\n\n%s%s%s%s%s\n",
+ wpa_supplicant_version,
+ wpa_supplicant_full_license1,
+ wpa_supplicant_full_license2,
+ wpa_supplicant_full_license3,
+ wpa_supplicant_full_license4,
+ wpa_supplicant_full_license5);
#endif /* CONFIG_NO_STDOUT_DEBUG */
}
static void wpa_supplicant_fd_workaround(void)
{
+#ifdef __linux__
int s, i;
/* When started from pcmcia-cs scripts, wpa_supplicant might start with
* fd 0, 1, and 2 closed. This will cause some issues because many
@@ -103,6 +117,7 @@ static void wpa_supplicant_fd_workaround(void)
break;
}
}
+#endif /* __linux__ */
}
@@ -110,34 +125,31 @@ int main(int argc, char *argv[])
{
int c, i;
struct wpa_interface *ifaces, *iface;
- int iface_count, exitcode;
+ int iface_count, exitcode = -1;
struct wpa_params params;
struct wpa_global *global;
-#ifdef CONFIG_NATIVE_WINDOWS
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
- printf("Could not find a usable WinSock.dll\n");
+ if (os_program_init())
return -1;
- }
-#endif /* CONFIG_NATIVE_WINDOWS */
- memset(&params, 0, sizeof(params));
+ os_memset(&params, 0, sizeof(params));
params.wpa_debug_level = MSG_INFO;
- iface = ifaces = malloc(sizeof(struct wpa_interface));
+ iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
if (ifaces == NULL)
return -1;
- memset(iface, 0, sizeof(*iface));
iface_count = 1;
wpa_supplicant_fd_workaround();
for (;;) {
- c = getopt(argc, argv, "Bc:C:D:dg:hi:KLNp:P:qtvwW");
+ c = getopt(argc, argv, "b:Bc:C:D:dg:hi:KLNp:P:qtuvwW");
if (c < 0)
break;
switch (c) {
+ case 'b':
+ iface->bridge_ifname = optarg;
+ break;
case 'B':
params.daemonize++;
break;
@@ -155,7 +167,7 @@ int main(int argc, char *argv[])
printf("Debugging disabled with "
"CONFIG_NO_STDOUT_DEBUG=y build time "
"option.\n");
- return -1;
+ goto out;
#else /* CONFIG_NO_STDOUT_DEBUG */
params.wpa_debug_level--;
break;
@@ -165,7 +177,8 @@ int main(int argc, char *argv[])
break;
case 'h':
usage();
- return -1;
+ exitcode = 0;
+ goto out;
case 'i':
iface->ifname = optarg;
break;
@@ -174,12 +187,14 @@ int main(int argc, char *argv[])
break;
case 'L':
license();
- return -1;
+ exitcode = 0;
+ goto out;
case 'p':
iface->driver_param = optarg;
break;
case 'P':
- params.pid_file = rel2abs_path(optarg);
+ os_free(params.pid_file);
+ params.pid_file = os_rel2abs_path(optarg);
break;
case 'q':
params.wpa_debug_level++;
@@ -187,9 +202,15 @@ int main(int argc, char *argv[])
case 't':
params.wpa_debug_timestamp++;
break;
+#ifdef CONFIG_CTRL_IFACE_DBUS
+ case 'u':
+ params.dbus_ctrl_interface = 1;
+ break;
+#endif /* CONFIG_CTRL_IFACE_DBUS */
case 'v':
printf("%s\n", wpa_supplicant_version);
- return -1;
+ exitcode = 0;
+ goto out;
case 'w':
params.wait_for_interface++;
break;
@@ -198,19 +219,18 @@ int main(int argc, char *argv[])
break;
case 'N':
iface_count++;
- iface = realloc(ifaces, iface_count *
- sizeof(struct wpa_interface));
- if (iface == NULL) {
- free(ifaces);
- return -1;
- }
+ iface = os_realloc(ifaces, iface_count *
+ sizeof(struct wpa_interface));
+ if (iface == NULL)
+ goto out;
ifaces = iface;
iface = &ifaces[iface_count - 1];
- memset(iface, 0, sizeof(*iface));
+ os_memset(iface, 0, sizeof(*iface));
break;
default:
usage();
- return -1;
+ exitcode = 0;
+ goto out;
}
}
@@ -219,16 +239,19 @@ int main(int argc, char *argv[])
if (global == NULL) {
printf("Failed to initialize wpa_supplicant\n");
exitcode = -1;
+ goto out;
}
for (i = 0; exitcode == 0 && i < iface_count; i++) {
if ((ifaces[i].confname == NULL &&
ifaces[i].ctrl_interface == NULL) ||
ifaces[i].ifname == NULL) {
- if (iface_count == 1 && params.ctrl_interface)
+ if (iface_count == 1 && (params.ctrl_interface ||
+ params.dbus_ctrl_interface))
break;
usage();
- return -1;
+ exitcode = -1;
+ break;
}
if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
exitcode = -1;
@@ -239,12 +262,11 @@ int main(int argc, char *argv[])
wpa_supplicant_deinit(global);
- free(ifaces);
- free(params.pid_file);
+out:
+ os_free(ifaces);
+ os_free(params.pid_file);
-#ifdef CONFIG_NATIVE_WINDOWS
- WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
+ os_program_deinit();
return exitcode;
}
diff --git a/contrib/wpa_supplicant/md4.c b/contrib/wpa_supplicant/md4.c
new file mode 100644
index 000000000000..41c84a3a7b5d
--- /dev/null
+++ b/contrib/wpa_supplicant/md4.c
@@ -0,0 +1,282 @@
+/*
+ * MD4 hash implementation
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+
+#ifdef INTERNAL_MD4
+
+#define MD4_BLOCK_LENGTH 64
+#define MD4_DIGEST_LENGTH 16
+
+typedef struct MD4Context {
+ u32 state[4]; /* state */
+ u64 count; /* number of bits, mod 2^64 */
+ u8 buffer[MD4_BLOCK_LENGTH]; /* input buffer */
+} MD4_CTX;
+
+
+static void MD4Init(MD4_CTX *ctx);
+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len);
+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx);
+
+
+void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ MD4_CTX ctx;
+ size_t i;
+
+ MD4Init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ MD4Update(&ctx, addr[i], len[i]);
+ MD4Final(mac, &ctx);
+}
+
+
+/* ===== start - public domain MD4 implementation ===== */
+/* $OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $ */
+
+/*
+ * This code implements the MD4 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD4Context structure, pass it to MD4Init, call MD4Update as
+ * needed on buffers full of bytes, and then call MD4Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#define MD4_DIGEST_STRING_LENGTH (MD4_DIGEST_LENGTH * 2 + 1)
+
+
+static void
+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
+
+#define PUT_64BIT_LE(cp, value) do { \
+ (cp)[7] = (value) >> 56; \
+ (cp)[6] = (value) >> 48; \
+ (cp)[5] = (value) >> 40; \
+ (cp)[4] = (value) >> 32; \
+ (cp)[3] = (value) >> 24; \
+ (cp)[2] = (value) >> 16; \
+ (cp)[1] = (value) >> 8; \
+ (cp)[0] = (value); } while (0)
+
+#define PUT_32BIT_LE(cp, value) do { \
+ (cp)[3] = (value) >> 24; \
+ (cp)[2] = (value) >> 16; \
+ (cp)[1] = (value) >> 8; \
+ (cp)[0] = (value); } while (0)
+
+static u8 PADDING[MD4_BLOCK_LENGTH] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Start MD4 accumulation.
+ * Set bit count to 0 and buffer to mysterious initialization constants.
+ */
+static void MD4Init(MD4_CTX *ctx)
+{
+ ctx->count = 0;
+ ctx->state[0] = 0x67452301;
+ ctx->state[1] = 0xefcdab89;
+ ctx->state[2] = 0x98badcfe;
+ ctx->state[3] = 0x10325476;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len)
+{
+ size_t have, need;
+
+ /* Check how many bytes we already have and how many more we need. */
+ have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
+ need = MD4_BLOCK_LENGTH - have;
+
+ /* Update bitcount */
+ ctx->count += (u64)len << 3;
+
+ if (len >= need) {
+ if (have != 0) {
+ os_memcpy(ctx->buffer + have, input, need);
+ MD4Transform(ctx->state, ctx->buffer);
+ input += need;
+ len -= need;
+ have = 0;
+ }
+
+ /* Process data in MD4_BLOCK_LENGTH-byte chunks. */
+ while (len >= MD4_BLOCK_LENGTH) {
+ MD4Transform(ctx->state, input);
+ input += MD4_BLOCK_LENGTH;
+ len -= MD4_BLOCK_LENGTH;
+ }
+ }
+
+ /* Handle any remaining bytes of data. */
+ if (len != 0)
+ os_memcpy(ctx->buffer + have, input, len);
+}
+
+/*
+ * Pad pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+static void MD4Pad(MD4_CTX *ctx)
+{
+ u8 count[8];
+ size_t padlen;
+
+ /* Convert count to 8 bytes in little endian order. */
+ PUT_64BIT_LE(count, ctx->count);
+
+ /* Pad out to 56 mod 64. */
+ padlen = MD4_BLOCK_LENGTH -
+ ((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
+ if (padlen < 1 + 8)
+ padlen += MD4_BLOCK_LENGTH;
+ MD4Update(ctx, PADDING, padlen - 8); /* padlen - 8 <= 64 */
+ MD4Update(ctx, count, 8);
+}
+
+/*
+ * Final wrapup--call MD4Pad, fill in digest and zero out ctx.
+ */
+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx)
+{
+ int i;
+
+ MD4Pad(ctx);
+ if (digest != NULL) {
+ for (i = 0; i < 4; i++)
+ PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+ os_memset(ctx, 0, sizeof(*ctx));
+ }
+}
+
+
+/* The three core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) ((x & y) | (x & z) | (y & z))
+#define F3(x, y, z) (x ^ y ^ z)
+
+/* This is the central step in the MD4 algorithm. */
+#define MD4STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s) )
+
+/*
+ * The core of the MD4 algorithm, this alters an existing MD4 hash to
+ * reflect the addition of 16 longwords of new data. MD4Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH])
+{
+ u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4];
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+ os_memcpy(in, block, sizeof(in));
+#else
+ for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) {
+ in[a] = (u32)(
+ (u32)(block[a * 4 + 0]) |
+ (u32)(block[a * 4 + 1]) << 8 |
+ (u32)(block[a * 4 + 2]) << 16 |
+ (u32)(block[a * 4 + 3]) << 24);
+ }
+#endif
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+
+ MD4STEP(F1, a, b, c, d, in[ 0], 3);
+ MD4STEP(F1, d, a, b, c, in[ 1], 7);
+ MD4STEP(F1, c, d, a, b, in[ 2], 11);
+ MD4STEP(F1, b, c, d, a, in[ 3], 19);
+ MD4STEP(F1, a, b, c, d, in[ 4], 3);
+ MD4STEP(F1, d, a, b, c, in[ 5], 7);
+ MD4STEP(F1, c, d, a, b, in[ 6], 11);
+ MD4STEP(F1, b, c, d, a, in[ 7], 19);
+ MD4STEP(F1, a, b, c, d, in[ 8], 3);
+ MD4STEP(F1, d, a, b, c, in[ 9], 7);
+ MD4STEP(F1, c, d, a, b, in[10], 11);
+ MD4STEP(F1, b, c, d, a, in[11], 19);
+ MD4STEP(F1, a, b, c, d, in[12], 3);
+ MD4STEP(F1, d, a, b, c, in[13], 7);
+ MD4STEP(F1, c, d, a, b, in[14], 11);
+ MD4STEP(F1, b, c, d, a, in[15], 19);
+
+ MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999, 3);
+ MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999, 5);
+ MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999, 9);
+ MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13);
+ MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999, 3);
+ MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999, 5);
+ MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999, 9);
+ MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13);
+ MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999, 3);
+ MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999, 5);
+ MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999, 9);
+ MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13);
+ MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999, 3);
+ MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999, 5);
+ MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999, 9);
+ MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13);
+
+ MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1, 3);
+ MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1, 9);
+ MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11);
+ MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15);
+ MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1, 3);
+ MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1, 9);
+ MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11);
+ MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15);
+ MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1, 3);
+ MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1, 9);
+ MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11);
+ MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15);
+ MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1, 3);
+ MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1, 9);
+ MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11);
+ MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15);
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+}
+/* ===== end - public domain MD4 implementation ===== */
+
+#endif /* INTERNAL_MD4 */
diff --git a/contrib/wpa_supplicant/md5.c b/contrib/wpa_supplicant/md5.c
index 82388e086766..a7db7aa9a771 100644
--- a/contrib/wpa_supplicant/md5.c
+++ b/contrib/wpa_supplicant/md5.c
@@ -1,6 +1,6 @@
/*
* MD5 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "md5.h"
@@ -35,9 +33,8 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
{
u8 k_pad[64]; /* padding - key XORd with ipad/opad */
u8 tk[16];
- int i;
const u8 *_addr[6];
- size_t _len[6];
+ size_t i, _len[6];
if (num_elem > 5) {
/*
@@ -64,8 +61,8 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
* and text is the data being protected */
/* start out by storing key in ipad */
- memset(k_pad, 0, sizeof(k_pad));
- memcpy(k_pad, key, key_len);
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
/* XOR key with ipad values */
for (i = 0; i < 64; i++)
@@ -80,8 +77,8 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
}
md5_vector(1 + num_elem, _addr, _len, mac);
- memset(k_pad, 0, sizeof(k_pad));
- memcpy(k_pad, key, key_len);
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
/* XOR key with opad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x5c;
@@ -110,7 +107,7 @@ void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
}
-#ifndef EAP_TLS_FUNCS
+#ifdef INTERNAL_MD5
struct MD5Context {
u32 buf[4];
@@ -118,12 +115,15 @@ struct MD5Context {
u8 in[64];
};
+#ifndef CONFIG_CRYPTO_INTERNAL
static void MD5Init(struct MD5Context *context);
static void MD5Update(struct MD5Context *context, unsigned char const *buf,
- unsigned len);
+ unsigned len);
static void MD5Final(unsigned char digest[16], struct MD5Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
static void MD5Transform(u32 buf[4], u32 const in[16]);
+
typedef struct MD5Context MD5_CTX;
@@ -137,7 +137,7 @@ typedef struct MD5Context MD5_CTX;
void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD5_CTX ctx;
- int i;
+ size_t i;
MD5Init(&ctx);
for (i = 0; i < num_elem; i++)
@@ -186,7 +186,7 @@ static void byteReverse(unsigned char *buf, unsigned longs)
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
-static void MD5Init(struct MD5Context *ctx)
+void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
@@ -201,8 +201,7 @@ static void MD5Init(struct MD5Context *ctx)
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
-static void MD5Update(struct MD5Context *ctx, unsigned char const *buf,
- unsigned len)
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
{
u32 t;
@@ -222,10 +221,10 @@ static void MD5Update(struct MD5Context *ctx, unsigned char const *buf,
t = 64 - t;
if (len < t) {
- memcpy(p, buf, len);
+ os_memcpy(p, buf, len);
return;
}
- memcpy(p, buf, t);
+ os_memcpy(p, buf, t);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
buf += t;
@@ -234,7 +233,7 @@ static void MD5Update(struct MD5Context *ctx, unsigned char const *buf,
/* Process data in 64-byte chunks */
while (len >= 64) {
- memcpy(ctx->in, buf, 64);
+ os_memcpy(ctx->in, buf, 64);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
buf += 64;
@@ -243,14 +242,14 @@ static void MD5Update(struct MD5Context *ctx, unsigned char const *buf,
/* Handle any remaining bytes of data. */
- memcpy(ctx->in, buf, len);
+ os_memcpy(ctx->in, buf, len);
}
/*
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
-static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned count;
unsigned char *p;
@@ -269,15 +268,15 @@ static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
/* Pad out to 56 mod 64 */
if (count < 8) {
/* Two lots of padding: Pad the first block to 64 bytes */
- memset(p, 0, count);
+ os_memset(p, 0, count);
byteReverse(ctx->in, 16);
MD5Transform(ctx->buf, (u32 *) ctx->in);
/* Now fill the next block with 56 bytes */
- memset(ctx->in, 0, 56);
+ os_memset(ctx->in, 0, 56);
} else {
/* Pad block to 56 bytes */
- memset(p, 0, count - 8);
+ os_memset(p, 0, count - 8);
}
byteReverse(ctx->in, 14);
@@ -287,8 +286,8 @@ static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
MD5Transform(ctx->buf, (u32 *) ctx->in);
byteReverse((unsigned char *) ctx->buf, 4);
- memcpy(digest, ctx->buf, 16);
- memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+ os_memcpy(digest, ctx->buf, 16);
+ os_memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
/* The four core functions - F1 is optimized somewhat */
@@ -392,4 +391,4 @@ static void MD5Transform(u32 buf[4], u32 const in[16])
}
/* ===== end - public domain MD5 implementation ===== */
-#endif /* !EAP_TLS_FUNCS */
+#endif /* INTERNAL_MD5 */
diff --git a/contrib/wpa_supplicant/md5.h b/contrib/wpa_supplicant/md5.h
index a724804943fc..e82f3969ed08 100644
--- a/contrib/wpa_supplicant/md5.h
+++ b/contrib/wpa_supplicant/md5.h
@@ -1,6 +1,6 @@
/*
* MD5 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -22,4 +22,13 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac);
+#ifdef CONFIG_CRYPTO_INTERNAL
+struct MD5Context;
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
+
#endif /* MD5_H */
diff --git a/contrib/wpa_supplicant/mlme.c b/contrib/wpa_supplicant/mlme.c
new file mode 100644
index 000000000000..92b59598b50e
--- /dev/null
+++ b/contrib/wpa_supplicant/mlme.c
@@ -0,0 +1,2897 @@
+/*
+ * WPA Supplicant - Client mode MLME
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ *
+ * 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.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "config.h"
+#include "wpa_supplicant.h"
+#include "wpa_supplicant_i.h"
+#include "wpa.h"
+#include "os.h"
+#include "l2_packet.h"
+#include "driver.h"
+#include "mlme.h"
+
+
+/* Timeouts and intervals in milliseconds */
+#define IEEE80211_AUTH_TIMEOUT (200)
+#define IEEE80211_AUTH_MAX_TRIES 3
+#define IEEE80211_ASSOC_TIMEOUT (200)
+#define IEEE80211_ASSOC_MAX_TRIES 3
+#define IEEE80211_MONITORING_INTERVAL (2000)
+#define IEEE80211_PROBE_INTERVAL (60000)
+#define IEEE80211_RETRY_AUTH_INTERVAL (1000)
+#define IEEE80211_SCAN_INTERVAL (2000)
+#define IEEE80211_SCAN_INTERVAL_SLOW (15000)
+#define IEEE80211_IBSS_JOIN_TIMEOUT (20000)
+
+#define IEEE80211_PROBE_DELAY (33)
+#define IEEE80211_CHANNEL_TIME (33)
+#define IEEE80211_PASSIVE_CHANNEL_TIME (200)
+#define IEEE80211_SCAN_RESULT_EXPIRE (10000)
+#define IEEE80211_IBSS_MERGE_INTERVAL (30000)
+#define IEEE80211_IBSS_INACTIVITY_LIMIT (60000)
+
+#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
+
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_CHALLENGE 16
+/* EIDs defined as part fo 11h - starts */
+#define WLAN_EID_PWR_CONSTRAINT 32
+#define WLAN_EID_PWR_CAPABILITY 33
+#define WLAN_EID_TPC_REQUEST 34
+#define WLAN_EID_TPC_REPORT 35
+#define WLAN_EID_SUPPORTED_CHANNELS 36
+#define WLAN_EID_CHANNEL_SWITCH 37
+#define WLAN_EID_MEASURE_REQUEST 38
+#define WLAN_EID_MEASURE_REPORT 39
+#define WLAN_EID_QUITE 40
+#define WLAN_EID_IBSS_DFS 41
+/* EIDs defined as part fo 11h - ends */
+#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_RSN 48
+#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_VENDOR_SPECIFIC 221
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee80211_mgmt {
+ u16 frame_control;
+ u16 duration;
+ u8 da[6];
+ u8 sa[6];
+ u8 bssid[6];
+ u16 seq_ctrl;
+ union {
+ struct {
+ u16 auth_alg;
+ u16 auth_transaction;
+ u16 status_code;
+ /* possibly followed by Challenge text */
+ u8 variable[0];
+ } STRUCT_PACKED auth;
+ struct {
+ u16 reason_code;
+ } STRUCT_PACKED deauth;
+ struct {
+ u16 capab_info;
+ u16 listen_interval;
+ /* followed by SSID and Supported rates */
+ u8 variable[0];
+ } STRUCT_PACKED assoc_req;
+ struct {
+ u16 capab_info;
+ u16 status_code;
+ u16 aid;
+ /* followed by Supported rates */
+ u8 variable[0];
+ } STRUCT_PACKED assoc_resp, reassoc_resp;
+ struct {
+ u16 capab_info;
+ u16 listen_interval;
+ u8 current_ap[6];
+ /* followed by SSID and Supported rates */
+ u8 variable[0];
+ } STRUCT_PACKED reassoc_req;
+ struct {
+ u16 reason_code;
+ } STRUCT_PACKED disassoc;
+ struct {
+ u8 timestamp[8];
+ u16 beacon_int;
+ u16 capab_info;
+ /* followed by some of SSID, Supported rates,
+ * FH Params, DS Params, CF Params, IBSS Params, TIM */
+ u8 variable[0];
+ } STRUCT_PACKED beacon;
+ struct {
+ /* only variable items: SSID, Supported rates */
+ u8 variable[0];
+ } STRUCT_PACKED probe_req;
+ struct {
+ u8 timestamp[8];
+ u16 beacon_int;
+ u16 capab_info;
+ /* followed by some of SSID, Supported rates,
+ * FH Params, DS Params, CF Params, IBSS Params */
+ u8 variable[0];
+ } STRUCT_PACKED probe_resp;
+ struct {
+ u8 category;
+ union {
+ struct {
+ u8 action_code;
+ u8 dialog_token;
+ u8 status_code;
+ u8 variable[0];
+ } STRUCT_PACKED wme_action;
+ struct{
+ u8 action_code;
+ u8 element_id;
+ u8 length;
+ u8 switch_mode;
+ u8 new_chan;
+ u8 switch_count;
+ } __attribute__((packed)) chan_switch;
+ } u;
+ } STRUCT_PACKED action;
+ } u;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN 0
+#define WLAN_AUTH_SHARED_KEY 1
+#define WLAN_AUTH_LEAP 128
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_ESS BIT(0)
+#define WLAN_CAPABILITY_IBSS BIT(1)
+#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
+#define WLAN_CAPABILITY_PRIVACY BIT(4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5)
+#define WLAN_CAPABILITY_PBCC BIT(6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
+/* 802.11h */
+#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
+#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
+
+/* Status codes */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+/* 802.11h */
+#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
+#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
+#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
+/* 802.11g */
+#define WLAN_STATUS_ASSOC_DENOED_NO_SHORT_SLOT_TIME 25
+#define WLAN_STATUS_ASSOC_DENOED_NO_ER_PBCC 26
+#define WLAN_STATUS_ASSOC_DENOED_NO_DSSS_OFDM 27
+
+
+/* Reason codes */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+/* 802.11h */
+#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
+#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
+
+#define WLAN_REASON_MIC_FAILURE 14
+
+
+#define WLAN_FC_PVER 0x0003
+#define WLAN_FC_TODS 0x0100
+#define WLAN_FC_FROMDS 0x0200
+#define WLAN_FC_MOREFRAG 0x0400
+#define WLAN_FC_RETRY 0x0800
+#define WLAN_FC_PWRMGT 0x1000
+#define WLAN_FC_MOREDATA 0x2000
+#define WLAN_FC_ISWEP 0x4000
+#define WLAN_FC_ORDER 0x8000
+
+#define WLAN_FC_GET_TYPE(fc) (((fc) & 0x000c) >> 2)
+#define WLAN_FC_GET_STYPE(fc) (((fc) & 0x00f0) >> 4)
+
+
+#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
+
+#define WLAN_FC_TYPE_MGMT 0
+#define WLAN_FC_TYPE_CTRL 1
+#define WLAN_FC_TYPE_DATA 2
+
+/* management */
+#define WLAN_FC_STYPE_ASSOC_REQ 0
+#define WLAN_FC_STYPE_ASSOC_RESP 1
+#define WLAN_FC_STYPE_REASSOC_REQ 2
+#define WLAN_FC_STYPE_REASSOC_RESP 3
+#define WLAN_FC_STYPE_PROBE_REQ 4
+#define WLAN_FC_STYPE_PROBE_RESP 5
+#define WLAN_FC_STYPE_BEACON 8
+#define WLAN_FC_STYPE_ATIM 9
+#define WLAN_FC_STYPE_DISASSOC 10
+#define WLAN_FC_STYPE_AUTH 11
+#define WLAN_FC_STYPE_DEAUTH 12
+#define WLAN_FC_STYPE_ACTION 13
+
+
+#define ERP_INFO_USE_PROTECTION BIT(1)
+
+
+struct ieee80211_sta_bss {
+ struct ieee80211_sta_bss *next;
+ struct ieee80211_sta_bss *hnext;
+
+ u8 bssid[ETH_ALEN];
+ u8 ssid[MAX_SSID_LEN];
+ size_t ssid_len;
+ u16 capability; /* host byte order */
+ int hw_mode;
+ int channel;
+ int freq;
+ int rssi;
+ u8 *wpa_ie;
+ size_t wpa_ie_len;
+ u8 *rsn_ie;
+ size_t rsn_ie_len;
+ u8 *wmm_ie;
+ size_t wmm_ie_len;
+#define IEEE80211_MAX_SUPP_RATES 32
+ u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+ size_t supp_rates_len;
+ int beacon_int;
+ u64 timestamp;
+
+ int probe_resp;
+ struct os_time last_update;
+};
+
+
+static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
+ const u8 *dst,
+ const u8 *ssid, size_t ssid_len);
+static struct ieee80211_sta_bss *
+ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid);
+static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s);
+static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s);
+static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx);
+static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx);
+
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+ u8 *ssid;
+ u8 ssid_len;
+ u8 *supp_rates;
+ u8 supp_rates_len;
+ u8 *fh_params;
+ u8 fh_params_len;
+ u8 *ds_params;
+ u8 ds_params_len;
+ u8 *cf_params;
+ u8 cf_params_len;
+ u8 *tim;
+ u8 tim_len;
+ u8 *ibss_params;
+ u8 ibss_params_len;
+ u8 *challenge;
+ u8 challenge_len;
+ u8 *wpa;
+ u8 wpa_len;
+ u8 *rsn;
+ u8 rsn_len;
+ u8 *erp_info;
+ u8 erp_info_len;
+ u8 *ext_supp_rates;
+ u8 ext_supp_rates_len;
+ u8 *wmm_info;
+ u8 wmm_info_len;
+ u8 *wmm_param;
+ u8 wmm_param_len;
+};
+
+typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
+
+
+static ParseRes ieee802_11_parse_elems(u8 *start, size_t len,
+ struct ieee802_11_elems *elems)
+{
+ size_t left = len;
+ u8 *pos = start;
+ int unknown = 0;
+
+ os_memset(elems, 0, sizeof(*elems));
+
+ while (left >= 2) {
+ u8 id, elen;
+
+ id = *pos++;
+ elen = *pos++;
+ left -= 2;
+
+ if (elen > left) {
+#if 0
+ wpa_printf(MSG_MSGDUMP, "MLME: IEEE 802.11 element "
+ "parse failed (id=%d elen=%d left=%d)",
+ id, elen, left);
+#endif
+ return ParseFailed;
+ }
+
+ switch (id) {
+ case WLAN_EID_SSID:
+ elems->ssid = pos;
+ elems->ssid_len = elen;
+ break;
+ case WLAN_EID_SUPP_RATES:
+ elems->supp_rates = pos;
+ elems->supp_rates_len = elen;
+ break;
+ case WLAN_EID_FH_PARAMS:
+ elems->fh_params = pos;
+ elems->fh_params_len = elen;
+ break;
+ case WLAN_EID_DS_PARAMS:
+ elems->ds_params = pos;
+ elems->ds_params_len = elen;
+ break;
+ case WLAN_EID_CF_PARAMS:
+ elems->cf_params = pos;
+ elems->cf_params_len = elen;
+ break;
+ case WLAN_EID_TIM:
+ elems->tim = pos;
+ elems->tim_len = elen;
+ break;
+ case WLAN_EID_IBSS_PARAMS:
+ elems->ibss_params = pos;
+ elems->ibss_params_len = elen;
+ break;
+ case WLAN_EID_CHALLENGE:
+ elems->challenge = pos;
+ elems->challenge_len = elen;
+ break;
+ case WLAN_EID_VENDOR_SPECIFIC:
+ if (elen >= 4 && pos[0] == 0x00 && pos[1] == 0x50 &&
+ pos[2] == 0xf2) {
+ /* Microsoft OUI (00:50:F2) */
+ if (pos[3] == 1) {
+ /* OUI Type 1 - WPA IE */
+ elems->wpa = pos;
+ elems->wpa_len = elen;
+ } else if (elen >= 5 && pos[3] == 2) {
+ if (pos[4] == 0) {
+ elems->wmm_info = pos;
+ elems->wmm_info_len = elen;
+ } else if (pos[4] == 1) {
+ elems->wmm_param = pos;
+ elems->wmm_param_len = elen;
+ }
+ }
+ }
+ break;
+ case WLAN_EID_RSN:
+ elems->rsn = pos;
+ elems->rsn_len = elen;
+ break;
+ case WLAN_EID_ERP_INFO:
+ elems->erp_info = pos;
+ elems->erp_info_len = elen;
+ break;
+ case WLAN_EID_EXT_SUPP_RATES:
+ elems->ext_supp_rates = pos;
+ elems->ext_supp_rates_len = elen;
+ break;
+ default:
+#if 0
+ wpa_printf(MSG_MSGDUMP "MLME: IEEE 802.11 element "
+ "parse ignored unknown element (id=%d "
+ "elen=%d)", id, elen);
+#endif
+ unknown++;
+ break;
+ }
+
+ left -= elen;
+ pos += elen;
+ }
+
+ if (left)
+ return ParseFailed;
+
+ return unknown ? ParseUnknown : ParseOK;
+}
+
+
+static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s,
+ wpa_hw_mode phymode, int chan,
+ int freq)
+{
+ size_t i;
+ struct wpa_hw_modes *mode;
+
+ for (i = 0; i < wpa_s->mlme.num_modes; i++) {
+ mode = &wpa_s->mlme.modes[i];
+ if (mode->mode == phymode) {
+ wpa_s->mlme.curr_rates = mode->rates;
+ wpa_s->mlme.num_curr_rates = mode->num_rates;
+ break;
+ }
+ }
+
+ return wpa_drv_set_channel(wpa_s, phymode, chan, freq);
+}
+
+
+
+#if 0 /* FIX */
+static int ecw2cw(int ecw)
+{
+ int cw = 1;
+ while (ecw > 0) {
+ cw <<= 1;
+ ecw--;
+ }
+ return cw - 1;
+}
+#endif
+
+
+static void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s,
+ u8 *wmm_param, size_t wmm_param_len)
+{
+ size_t left;
+ int count;
+ u8 *pos;
+
+ if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
+ return;
+ count = wmm_param[6] & 0x0f;
+ if (count == wpa_s->mlme.wmm_last_param_set)
+ return;
+ wpa_s->mlme.wmm_last_param_set = count;
+
+ pos = wmm_param + 8;
+ left = wmm_param_len - 8;
+
+#if 0 /* FIX */
+ wmm_acm = 0;
+ for (; left >= 4; left -= 4, pos += 4) {
+ int aci = (pos[0] >> 5) & 0x03;
+ int acm = (pos[0] >> 4) & 0x01;
+ int queue;
+
+ switch (aci) {
+ case 1:
+ queue = IEEE80211_TX_QUEUE_DATA3;
+ if (acm)
+ wmm_acm |= BIT(1) | BIT(2);
+ break;
+ case 2:
+ queue = IEEE80211_TX_QUEUE_DATA1;
+ if (acm)
+ wmm_acm |= BIT(4) | BIT(5);
+ break;
+ case 3:
+ queue = IEEE80211_TX_QUEUE_DATA0;
+ if (acm)
+ wmm_acm |= BIT(6) | BIT(7);
+ break;
+ case 0:
+ default:
+ queue = IEEE80211_TX_QUEUE_DATA2;
+ if (acm)
+ wpa_s->mlme.wmm_acm |= BIT(0) | BIT(3);
+ break;
+ }
+
+ params.aifs = pos[0] & 0x0f;
+ params.cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
+ params.cw_min = ecw2cw(pos[1] & 0x0f);
+ /* TXOP is in units of 32 usec; burst_time in 0.1 ms */
+ params.burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
+ wpa_printf(MSG_DEBUG, "MLME: WMM queue=%d aci=%d acm=%d "
+ "aifs=%d cWmin=%d cWmax=%d burst=%d",
+ queue, aci, acm, params.aifs, params.cw_min,
+ params.cw_max, params.burst_time);
+ /* TODO: handle ACM (block TX, fallback to next lowest allowed
+ * AC for now) */
+ if (local->hw->conf_tx(local->mdev, queue, &params)) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to set TX queue "
+ "parameters for queue %d", queue);
+ }
+ }
+#endif
+}
+
+
+static void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc)
+{
+ if (wpa_s->mlme.associated == assoc)
+ return;
+
+ wpa_s->mlme.associated = assoc;
+
+ if (assoc) {
+ union wpa_event_data data;
+ os_memset(&data, 0, sizeof(data));
+ wpa_s->mlme.prev_bssid_set = 1;
+ os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN);
+ data.assoc_info.req_ies = wpa_s->mlme.assocreq_ies;
+ data.assoc_info.req_ies_len = wpa_s->mlme.assocreq_ies_len;
+ data.assoc_info.resp_ies = wpa_s->mlme.assocresp_ies;
+ data.assoc_info.resp_ies_len = wpa_s->mlme.assocresp_ies_len;
+ wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
+ } else {
+ wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL);
+ }
+ os_get_time(&wpa_s->mlme.last_probe);
+}
+
+
+static void ieee80211_sta_tx(struct wpa_supplicant *wpa_s, const u8 *buf,
+ size_t len)
+{
+ wpa_drv_send_mlme(wpa_s, buf, len);
+}
+
+
+static void ieee80211_send_auth(struct wpa_supplicant *wpa_s,
+ int transaction, u8 *extra, size_t extra_len,
+ int encrypt)
+{
+ u8 *buf;
+ size_t len;
+ struct ieee80211_mgmt *mgmt;
+
+ buf = os_malloc(sizeof(*mgmt) + 6 + extra_len);
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
+ "auth frame");
+ return;
+ }
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ len = 24 + 6;
+ os_memset(mgmt, 0, 24 + 6);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_AUTH);
+ if (encrypt)
+ mgmt->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->u.auth.auth_alg = host_to_le16(wpa_s->mlme.auth_alg);
+ mgmt->u.auth.auth_transaction = host_to_le16(transaction);
+ wpa_s->mlme.auth_transaction = transaction + 1;
+ mgmt->u.auth.status_code = host_to_le16(0);
+ if (extra) {
+ os_memcpy(buf + len, extra, extra_len);
+ len += extra_len;
+ }
+
+ ieee80211_sta_tx(wpa_s, buf, len);
+ os_free(buf);
+}
+
+
+static void ieee80211_reschedule_timer(struct wpa_supplicant *wpa_s, int ms)
+{
+ eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL);
+ eloop_register_timeout(ms / 1000, 1000 * (ms % 1000),
+ ieee80211_sta_timer, wpa_s, NULL);
+}
+
+
+static void ieee80211_authenticate(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->mlme.auth_tries++;
+ if (wpa_s->mlme.auth_tries > IEEE80211_AUTH_MAX_TRIES) {
+ wpa_printf(MSG_DEBUG, "MLME: authentication with AP " MACSTR
+ " timed out", MAC2STR(wpa_s->bssid));
+ return;
+ }
+
+ wpa_s->mlme.state = IEEE80211_AUTHENTICATE;
+ wpa_printf(MSG_DEBUG, "MLME: authenticate with AP " MACSTR,
+ MAC2STR(wpa_s->bssid));
+
+ ieee80211_send_auth(wpa_s, 1, NULL, 0, 0);
+
+ ieee80211_reschedule_timer(wpa_s, IEEE80211_AUTH_TIMEOUT);
+}
+
+
+static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s)
+{
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos, *ies, *buf;
+ int i, len;
+ u16 capab;
+ struct ieee80211_sta_bss *bss;
+ int wmm = 0;
+ size_t blen;
+
+ if (wpa_s->mlme.curr_rates == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: curr_rates not set for assoc");
+ return;
+ }
+
+ buf = os_malloc(sizeof(*mgmt) + 200 + wpa_s->mlme.extra_ie_len +
+ wpa_s->mlme.ssid_len);
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
+ "assoc frame");
+ return;
+ }
+ blen = 0;
+
+ capab = wpa_s->mlme.capab;
+ if (wpa_s->mlme.phymode == WPA_MODE_IEEE80211G) {
+ capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
+ WLAN_CAPABILITY_SHORT_PREAMBLE;
+ }
+ bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
+ if (bss) {
+ if (bss->capability & WLAN_CAPABILITY_PRIVACY)
+ capab |= WLAN_CAPABILITY_PRIVACY;
+ if (bss->wmm_ie) {
+ wmm = 1;
+ }
+ }
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ blen += 24;
+ os_memset(mgmt, 0, 24);
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+
+ if (wpa_s->mlme.prev_bssid_set) {
+ blen += 10;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_REASSOC_REQ);
+ mgmt->u.reassoc_req.capab_info = host_to_le16(capab);
+ mgmt->u.reassoc_req.listen_interval = host_to_le16(1);
+ os_memcpy(mgmt->u.reassoc_req.current_ap,
+ wpa_s->mlme.prev_bssid,
+ ETH_ALEN);
+ } else {
+ blen += 4;
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_ASSOC_REQ);
+ mgmt->u.assoc_req.capab_info = host_to_le16(capab);
+ mgmt->u.assoc_req.listen_interval = host_to_le16(1);
+ }
+
+ /* SSID */
+ ies = pos = buf + blen;
+ blen += 2 + wpa_s->mlme.ssid_len;
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = wpa_s->mlme.ssid_len;
+ os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
+
+ len = wpa_s->mlme.num_curr_rates;
+ if (len > 8)
+ len = 8;
+ pos = buf + blen;
+ blen += len + 2;
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = len;
+ for (i = 0; i < len; i++) {
+ int rate = wpa_s->mlme.curr_rates[i].rate;
+ *pos++ = (u8) (rate / 5);
+ }
+
+ if (wpa_s->mlme.num_curr_rates > len) {
+ pos = buf + blen;
+ blen += wpa_s->mlme.num_curr_rates - len + 2;
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = wpa_s->mlme.num_curr_rates - len;
+ for (i = len; i < wpa_s->mlme.num_curr_rates; i++) {
+ int rate = wpa_s->mlme.curr_rates[i].rate;
+ *pos++ = (u8) (rate / 5);
+ }
+ }
+
+ if (wpa_s->mlme.extra_ie) {
+ pos = buf + blen;
+ blen += wpa_s->mlme.extra_ie_len;
+ os_memcpy(pos, wpa_s->mlme.extra_ie, wpa_s->mlme.extra_ie_len);
+ }
+
+ if (wmm && wpa_s->mlme.wmm_enabled) {
+ pos = buf + blen;
+ blen += 9;
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = 7; /* len */
+ *pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
+ *pos++ = 0x50;
+ *pos++ = 0xf2;
+ *pos++ = 2; /* WME */
+ *pos++ = 0; /* WME info */
+ *pos++ = 1; /* WME ver */
+ *pos++ = 0;
+ }
+
+ os_free(wpa_s->mlme.assocreq_ies);
+ wpa_s->mlme.assocreq_ies_len = (buf + blen) - ies;
+ wpa_s->mlme.assocreq_ies = os_malloc(wpa_s->mlme.assocreq_ies_len);
+ if (wpa_s->mlme.assocreq_ies) {
+ os_memcpy(wpa_s->mlme.assocreq_ies, ies,
+ wpa_s->mlme.assocreq_ies_len);
+ }
+
+ ieee80211_sta_tx(wpa_s, buf, blen);
+ os_free(buf);
+}
+
+
+static void ieee80211_send_deauth(struct wpa_supplicant *wpa_s, u16 reason)
+{
+ u8 *buf;
+ size_t len;
+ struct ieee80211_mgmt *mgmt;
+
+ buf = os_zalloc(sizeof(*mgmt));
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
+ "deauth frame");
+ return;
+ }
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ len = 24;
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ len += 2;
+ mgmt->u.deauth.reason_code = host_to_le16(reason);
+
+ ieee80211_sta_tx(wpa_s, buf, len);
+ os_free(buf);
+}
+
+
+static void ieee80211_send_disassoc(struct wpa_supplicant *wpa_s, u16 reason)
+{
+ u8 *buf;
+ size_t len;
+ struct ieee80211_mgmt *mgmt;
+
+ buf = os_zalloc(sizeof(*mgmt));
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
+ "disassoc frame");
+ return;
+ }
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ len = 24;
+ os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ len += 2;
+ mgmt->u.disassoc.reason_code = host_to_le16(reason);
+
+ ieee80211_sta_tx(wpa_s, buf, len);
+ os_free(buf);
+}
+
+
+static int ieee80211_privacy_mismatch(struct wpa_supplicant *wpa_s)
+{
+ struct ieee80211_sta_bss *bss;
+ int res = 0;
+
+ if (wpa_s->mlme.mixed_cell ||
+ wpa_s->mlme.key_mgmt != KEY_MGMT_NONE)
+ return 0;
+
+ bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
+ if (bss == NULL)
+ return 0;
+
+ if (ieee80211_sta_wep_configured(wpa_s) !=
+ !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
+ res = 1;
+
+ return res;
+}
+
+
+static void ieee80211_associate(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->mlme.assoc_tries++;
+ if (wpa_s->mlme.assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
+ wpa_printf(MSG_DEBUG, "MLME: association with AP " MACSTR
+ " timed out", MAC2STR(wpa_s->bssid));
+ return;
+ }
+
+ wpa_s->mlme.state = IEEE80211_ASSOCIATE;
+ wpa_printf(MSG_DEBUG, "MLME: associate with AP " MACSTR,
+ MAC2STR(wpa_s->bssid));
+ if (ieee80211_privacy_mismatch(wpa_s)) {
+ wpa_printf(MSG_DEBUG, "MLME: mismatch in privacy "
+ "configuration and mixed-cell disabled - abort "
+ "association");
+ return;
+ }
+
+ ieee80211_send_assoc(wpa_s);
+
+ ieee80211_reschedule_timer(wpa_s, IEEE80211_ASSOC_TIMEOUT);
+}
+
+
+static void ieee80211_associated(struct wpa_supplicant *wpa_s)
+{
+ int disassoc;
+
+ /* TODO: start monitoring current AP signal quality and number of
+ * missed beacons. Scan other channels every now and then and search
+ * for better APs. */
+ /* TODO: remove expired BSSes */
+
+ wpa_s->mlme.state = IEEE80211_ASSOCIATED;
+
+#if 0 /* FIX */
+ sta = sta_info_get(local, wpa_s->bssid);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG "MLME: No STA entry for own AP " MACSTR,
+ MAC2STR(wpa_s->bssid));
+ disassoc = 1;
+ } else {
+ disassoc = 0;
+ if (time_after(jiffies,
+ sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
+ if (wpa_s->mlme.probereq_poll) {
+ wpa_printf(MSG_DEBUG "MLME: No ProbeResp from "
+ "current AP " MACSTR " - assume "
+ "out of range",
+ MAC2STR(wpa_s->bssid));
+ disassoc = 1;
+ } else {
+ ieee80211_send_probe_req(
+ wpa_s->bssid,
+ wpa_s->mlme.scan_ssid,
+ wpa_s->mlme.scan_ssid_len);
+ wpa_s->mlme.probereq_poll = 1;
+ }
+ } else {
+ wpa_s->mlme.probereq_poll = 0;
+ if (time_after(jiffies, wpa_s->mlme.last_probe +
+ IEEE80211_PROBE_INTERVAL)) {
+ wpa_s->mlme.last_probe = jiffies;
+ ieee80211_send_probe_req(wpa_s->bssid,
+ wpa_s->mlme.ssid,
+ wpa_s->mlme.ssid_len);
+ }
+ }
+ sta_info_release(local, sta);
+ }
+#else
+ disassoc = 0;
+#endif
+ if (disassoc) {
+ wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL);
+ ieee80211_reschedule_timer(wpa_s,
+ IEEE80211_MONITORING_INTERVAL +
+ 30000);
+ } else {
+ ieee80211_reschedule_timer(wpa_s,
+ IEEE80211_MONITORING_INTERVAL);
+ }
+}
+
+
+static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
+ const u8 *dst,
+ const u8 *ssid, size_t ssid_len)
+{
+ u8 *buf;
+ size_t len;
+ struct ieee80211_mgmt *mgmt;
+ u8 *pos, *supp_rates;
+ u8 *esupp_rates = NULL;
+ int i;
+
+ buf = os_malloc(sizeof(*mgmt) + 200);
+ if (buf == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
+ "probe request");
+ return;
+ }
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ len = 24;
+ os_memset(mgmt, 0, 24);
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_PROBE_REQ);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ if (dst) {
+ os_memcpy(mgmt->da, dst, ETH_ALEN);
+ os_memcpy(mgmt->bssid, dst, ETH_ALEN);
+ } else {
+ os_memset(mgmt->da, 0xff, ETH_ALEN);
+ os_memset(mgmt->bssid, 0xff, ETH_ALEN);
+ }
+ pos = buf + len;
+ len += 2 + ssid_len;
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ssid_len;
+ os_memcpy(pos, ssid, ssid_len);
+
+ supp_rates = buf + len;
+ len += 2;
+ supp_rates[0] = WLAN_EID_SUPP_RATES;
+ supp_rates[1] = 0;
+ for (i = 0; i < wpa_s->mlme.num_curr_rates; i++) {
+ struct wpa_rate_data *rate = &wpa_s->mlme.curr_rates[i];
+ if (!(rate->flags & WPA_RATE_SUPPORTED))
+ continue;
+ if (esupp_rates) {
+ pos = buf + len;
+ len++;
+ esupp_rates[1]++;
+ } else if (supp_rates[1] == 8) {
+ esupp_rates = pos;
+ esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
+ esupp_rates[1] = 1;
+ pos = &esupp_rates[2];
+ } else {
+ pos = buf + len;
+ len++;
+ supp_rates[1]++;
+ }
+ *pos = rate->rate / 5;
+ }
+
+ ieee80211_sta_tx(wpa_s, buf, len);
+ os_free(buf);
+}
+
+
+static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s)
+{
+#if 0 /* FIX */
+ if (sdata == NULL || sdata->default_key == NULL ||
+ sdata->default_key->alg != ALG_WEP)
+ return 0;
+ return 1;
+#else
+ return 0;
+#endif
+}
+
+
+static void ieee80211_auth_completed(struct wpa_supplicant *wpa_s)
+{
+ wpa_printf(MSG_DEBUG, "MLME: authenticated");
+ wpa_s->mlme.authenticated = 1;
+ ieee80211_associate(wpa_s);
+}
+
+
+static void ieee80211_auth_challenge(struct wpa_supplicant *wpa_s,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ u8 *pos;
+ struct ieee802_11_elems elems;
+
+ wpa_printf(MSG_DEBUG, "MLME: replying to auth challenge");
+ pos = mgmt->u.auth.variable;
+ if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
+ == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to parse Auth(challenge)");
+ return;
+ }
+ if (elems.challenge == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: no challenge IE in shared key "
+ "auth frame");
+ return;
+ }
+ ieee80211_send_auth(wpa_s, 3, elems.challenge - 2,
+ elems.challenge_len + 2, 1);
+}
+
+
+static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ u16 auth_alg, auth_transaction, status_code;
+ int adhoc;
+
+ adhoc = ssid && ssid->mode == 1;
+
+ if (wpa_s->mlme.state != IEEE80211_AUTHENTICATE && !adhoc) {
+ wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
+ "from " MACSTR ", but not in authenticate state - "
+ "ignored", MAC2STR(mgmt->sa));
+ return;
+ }
+
+ if (len < 24 + 6) {
+ wpa_printf(MSG_DEBUG, "MLME: too short (%lu) authentication "
+ "frame received from " MACSTR " - ignored",
+ (unsigned long) len, MAC2STR(mgmt->sa));
+ return;
+ }
+
+ if (!adhoc && os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
+ "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
+ ") - ignored",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
+ return;
+ }
+
+ if (adhoc && os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
+ "from unknown BSSID (SA=" MACSTR " BSSID=" MACSTR
+ ") - ignored",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
+ return;
+ }
+
+ auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+ auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+ status_code = le_to_host16(mgmt->u.auth.status_code);
+
+ wpa_printf(MSG_DEBUG, "MLME: RX authentication from " MACSTR
+ " (alg=%d transaction=%d status=%d)",
+ MAC2STR(mgmt->sa), auth_alg, auth_transaction, status_code);
+
+ if (adhoc) {
+ /* IEEE 802.11 standard does not require authentication in IBSS
+ * networks and most implementations do not seem to use it.
+ * However, try to reply to authentication attempts if someone
+ * has actually implemented this.
+ * TODO: Could implement shared key authentication. */
+ if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
+ wpa_printf(MSG_DEBUG, "MLME: unexpected IBSS "
+ "authentication frame (alg=%d "
+ "transaction=%d)",
+ auth_alg, auth_transaction);
+ return;
+ }
+ ieee80211_send_auth(wpa_s, 2, NULL, 0, 0);
+ }
+
+ if (auth_alg != wpa_s->mlme.auth_alg ||
+ auth_transaction != wpa_s->mlme.auth_transaction) {
+ wpa_printf(MSG_DEBUG, "MLME: unexpected authentication frame "
+ "(alg=%d transaction=%d)",
+ auth_alg, auth_transaction);
+ return;
+ }
+
+ if (status_code != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "MLME: AP denied authentication "
+ "(auth_alg=%d code=%d)", wpa_s->mlme.auth_alg,
+ status_code);
+ if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
+ const int num_algs = 3;
+ u8 algs[num_algs];
+ int i, pos;
+ algs[0] = algs[1] = algs[2] = 0xff;
+ if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_OPEN)
+ algs[0] = WLAN_AUTH_OPEN;
+ if (wpa_s->mlme.auth_algs &
+ IEEE80211_AUTH_ALG_SHARED_KEY)
+ algs[1] = WLAN_AUTH_SHARED_KEY;
+ if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_LEAP)
+ algs[2] = WLAN_AUTH_LEAP;
+ if (wpa_s->mlme.auth_alg == WLAN_AUTH_OPEN)
+ pos = 0;
+ else if (wpa_s->mlme.auth_alg == WLAN_AUTH_SHARED_KEY)
+ pos = 1;
+ else
+ pos = 2;
+ for (i = 0; i < num_algs; i++) {
+ pos++;
+ if (pos >= num_algs)
+ pos = 0;
+ if (algs[pos] == wpa_s->mlme.auth_alg ||
+ algs[pos] == 0xff)
+ continue;
+ if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
+ !ieee80211_sta_wep_configured(wpa_s))
+ continue;
+ wpa_s->mlme.auth_alg = algs[pos];
+ wpa_printf(MSG_DEBUG, "MLME: set auth_alg=%d "
+ "for next try",
+ wpa_s->mlme.auth_alg);
+ break;
+ }
+ }
+ return;
+ }
+
+ switch (wpa_s->mlme.auth_alg) {
+ case WLAN_AUTH_OPEN:
+ case WLAN_AUTH_LEAP:
+ ieee80211_auth_completed(wpa_s);
+ break;
+ case WLAN_AUTH_SHARED_KEY:
+ if (wpa_s->mlme.auth_transaction == 4)
+ ieee80211_auth_completed(wpa_s);
+ else
+ ieee80211_auth_challenge(wpa_s, mgmt, len,
+ rx_status);
+ break;
+ }
+}
+
+
+static void ieee80211_rx_mgmt_deauth(struct wpa_supplicant *wpa_s,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ u16 reason_code;
+
+ if (len < 24 + 2) {
+ wpa_printf(MSG_DEBUG, "MLME: too short (%lu) deauthentication "
+ "frame received from " MACSTR " - ignored",
+ (unsigned long) len, MAC2STR(mgmt->sa));
+ return;
+ }
+
+ if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "MLME: deauthentication frame received "
+ "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
+ ") - ignored",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
+ return;
+ }
+
+ reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+ wpa_printf(MSG_DEBUG, "MLME: RX deauthentication from " MACSTR
+ " (reason=%d)", MAC2STR(mgmt->sa), reason_code);
+
+ if (wpa_s->mlme.authenticated)
+ wpa_printf(MSG_DEBUG, "MLME: deauthenticated");
+
+ if (wpa_s->mlme.state == IEEE80211_AUTHENTICATE ||
+ wpa_s->mlme.state == IEEE80211_ASSOCIATE ||
+ wpa_s->mlme.state == IEEE80211_ASSOCIATED) {
+ wpa_s->mlme.state = IEEE80211_AUTHENTICATE;
+ ieee80211_reschedule_timer(wpa_s,
+ IEEE80211_RETRY_AUTH_INTERVAL);
+ }
+
+ ieee80211_set_associated(wpa_s, 0);
+ wpa_s->mlme.authenticated = 0;
+}
+
+
+static void ieee80211_rx_mgmt_disassoc(struct wpa_supplicant *wpa_s,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ u16 reason_code;
+
+ if (len < 24 + 2) {
+ wpa_printf(MSG_DEBUG, "MLME: too short (%lu) disassociation "
+ "frame received from " MACSTR " - ignored",
+ (unsigned long) len, MAC2STR(mgmt->sa));
+ return;
+ }
+
+ if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "MLME: disassociation frame received "
+ "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
+ ") - ignored",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
+ return;
+ }
+
+ reason_code = le_to_host16(mgmt->u.disassoc.reason_code);
+
+ wpa_printf(MSG_DEBUG, "MLME: RX disassociation from " MACSTR
+ " (reason=%d)", MAC2STR(mgmt->sa), reason_code);
+
+ if (wpa_s->mlme.associated)
+ wpa_printf(MSG_DEBUG, "MLME: disassociated");
+
+ if (wpa_s->mlme.state == IEEE80211_ASSOCIATED) {
+ wpa_s->mlme.state = IEEE80211_ASSOCIATE;
+ ieee80211_reschedule_timer(wpa_s,
+ IEEE80211_RETRY_AUTH_INTERVAL);
+ }
+
+ ieee80211_set_associated(wpa_s, 0);
+}
+
+
+static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status,
+ int reassoc)
+{
+ u8 rates[32];
+ size_t rates_len;
+ u16 capab_info, status_code, aid;
+ struct ieee802_11_elems elems;
+ u8 *pos;
+
+ /* AssocResp and ReassocResp have identical structure, so process both
+ * of them in this function. */
+
+ if (wpa_s->mlme.state != IEEE80211_ASSOCIATE) {
+ wpa_printf(MSG_DEBUG, "MLME: association frame received from "
+ MACSTR ", but not in associate state - ignored",
+ MAC2STR(mgmt->sa));
+ return;
+ }
+
+ if (len < 24 + 6) {
+ wpa_printf(MSG_DEBUG, "MLME: too short (%lu) association "
+ "frame received from " MACSTR " - ignored",
+ (unsigned long) len, MAC2STR(mgmt->sa));
+ return;
+ }
+
+ if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
+ wpa_printf(MSG_DEBUG, "MLME: association frame received from "
+ "unknown AP (SA=" MACSTR " BSSID=" MACSTR ") - "
+ "ignored", MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
+ return;
+ }
+
+ capab_info = le_to_host16(mgmt->u.assoc_resp.capab_info);
+ status_code = le_to_host16(mgmt->u.assoc_resp.status_code);
+ aid = le_to_host16(mgmt->u.assoc_resp.aid);
+ if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
+ wpa_printf(MSG_DEBUG, "MLME: invalid aid value %d; bits 15:14 "
+ "not set", aid);
+ aid &= ~(BIT(15) | BIT(14));
+
+ wpa_printf(MSG_DEBUG, "MLME: RX %sssocResp from " MACSTR
+ " (capab=0x%x status=%d aid=%d)",
+ reassoc ? "Rea" : "A", MAC2STR(mgmt->sa),
+ capab_info, status_code, aid);
+
+ if (status_code != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "MLME: AP denied association (code=%d)",
+ status_code);
+ return;
+ }
+
+ pos = mgmt->u.assoc_resp.variable;
+ if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems)
+ == ParseFailed) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to parse AssocResp");
+ return;
+ }
+
+ if (elems.supp_rates == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: no SuppRates element in "
+ "AssocResp");
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "MLME: associated");
+ wpa_s->mlme.aid = aid;
+ wpa_s->mlme.ap_capab = capab_info;
+
+ os_free(wpa_s->mlme.assocresp_ies);
+ wpa_s->mlme.assocresp_ies_len = len - (pos - (u8 *) mgmt);
+ wpa_s->mlme.assocresp_ies = os_malloc(wpa_s->mlme.assocresp_ies_len);
+ if (wpa_s->mlme.assocresp_ies) {
+ os_memcpy(wpa_s->mlme.assocresp_ies, pos,
+ wpa_s->mlme.assocresp_ies_len);
+ }
+
+ ieee80211_set_associated(wpa_s, 1);
+
+ rates_len = elems.supp_rates_len;
+ if (rates_len > sizeof(rates))
+ rates_len = sizeof(rates);
+ os_memcpy(rates, elems.supp_rates, rates_len);
+ if (elems.ext_supp_rates) {
+ size_t _len = elems.ext_supp_rates_len;
+ if (_len > sizeof(rates) - rates_len)
+ _len = sizeof(rates) - rates_len;
+ os_memcpy(rates + rates_len, elems.ext_supp_rates, _len);
+ rates_len += _len;
+ }
+
+ if (wpa_drv_set_bssid(wpa_s, wpa_s->bssid) < 0) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to set BSSID for the "
+ "netstack");
+ }
+ if (wpa_drv_set_ssid(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to set SSID for the "
+ "netstack");
+ }
+
+ /* Remove STA entry before adding a new one just in case to avoid
+ * problems with existing configuration (e.g., keys). */
+ wpa_drv_mlme_remove_sta(wpa_s, wpa_s->bssid);
+ if (wpa_drv_mlme_add_sta(wpa_s, wpa_s->bssid, rates, rates_len) < 0) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to add STA entry to the "
+ "netstack");
+ }
+
+#if 0 /* FIX? */
+ sta->assoc_ap = 1;
+
+ if (elems.wmm_param && wpa_s->mlme.wmm_enabled) {
+ sta->flags |= WLAN_STA_WME;
+ ieee80211_sta_wmm_params(wpa_s, elems.wmm_param,
+ elems.wmm_param_len);
+ }
+#endif
+
+ ieee80211_associated(wpa_s);
+}
+
+
+/* Caller must hold local->sta_bss_lock */
+static void __ieee80211_bss_hash_add(struct wpa_supplicant *wpa_s,
+ struct ieee80211_sta_bss *bss)
+{
+ bss->hnext = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)];
+ wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] = bss;
+}
+
+
+/* Caller must hold local->sta_bss_lock */
+static void __ieee80211_bss_hash_del(struct wpa_supplicant *wpa_s,
+ struct ieee80211_sta_bss *bss)
+{
+ struct ieee80211_sta_bss *b, *prev = NULL;
+ b = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)];
+ while (b) {
+ if (b == bss) {
+ if (prev == NULL) {
+ wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]
+ = bss->hnext;
+ } else {
+ prev->hnext = bss->hnext;
+ }
+ break;
+ }
+ prev = b;
+ b = b->hnext;
+ }
+}
+
+
+static struct ieee80211_sta_bss *
+ieee80211_bss_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct ieee80211_sta_bss *bss;
+
+ bss = os_zalloc(sizeof(*bss));
+ if (bss == NULL)
+ return NULL;
+ os_memcpy(bss->bssid, bssid, ETH_ALEN);
+
+ /* TODO: order by RSSI? */
+ bss->next = wpa_s->mlme.sta_bss_list;
+ wpa_s->mlme.sta_bss_list = bss;
+ __ieee80211_bss_hash_add(wpa_s, bss);
+ return bss;
+}
+
+
+static struct ieee80211_sta_bss *
+ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+ struct ieee80211_sta_bss *bss;
+
+ bss = wpa_s->mlme.sta_bss_hash[STA_HASH(bssid)];
+ while (bss) {
+ if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+ break;
+ bss = bss->hnext;
+ }
+ return bss;
+}
+
+
+static void ieee80211_bss_free(struct wpa_supplicant *wpa_s,
+ struct ieee80211_sta_bss *bss)
+{
+ __ieee80211_bss_hash_del(wpa_s, bss);
+ os_free(bss->wpa_ie);
+ os_free(bss->rsn_ie);
+ os_free(bss->wmm_ie);
+ os_free(bss);
+}
+
+
+static void ieee80211_bss_list_deinit(struct wpa_supplicant *wpa_s)
+{
+ struct ieee80211_sta_bss *bss, *prev;
+
+ bss = wpa_s->mlme.sta_bss_list;
+ wpa_s->mlme.sta_bss_list = NULL;
+ while (bss) {
+ prev = bss;
+ bss = bss->next;
+ ieee80211_bss_free(wpa_s, prev);
+ }
+}
+
+
+static void ieee80211_bss_info(struct wpa_supplicant *wpa_s,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status,
+ int beacon)
+{
+ struct ieee802_11_elems elems;
+ size_t baselen;
+ int channel, invalid = 0, clen;
+ struct ieee80211_sta_bss *bss;
+ u64 timestamp;
+ u8 *pos;
+
+ if (!beacon && os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN))
+ return; /* ignore ProbeResp to foreign address */
+
+#if 0
+ wpa_printf(MSG_MSGDUMP, "MLME: RX %s from " MACSTR " to " MACSTR,
+ beacon ? "Beacon" : "Probe Response",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
+#endif
+
+ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+ if (baselen > len)
+ return;
+
+ pos = mgmt->u.beacon.timestamp;
+ timestamp = ((u64) pos[7] << 56) | ((u64) pos[6] << 48) |
+ ((u64) pos[5] << 40) | ((u64) pos[4] << 32) |
+ ((u64) pos[3] << 24) | ((u64) pos[2] << 16) |
+ ((u64) pos[1] << 8) | ((u64) pos[0]);
+
+#if 0 /* FIX */
+ if (local->conf.mode == IW_MODE_ADHOC && beacon &&
+ os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0) {
+#ifdef IEEE80211_IBSS_DEBUG
+ static unsigned long last_tsf_debug = 0;
+ u64 tsf;
+ if (local->hw->get_tsf)
+ tsf = local->hw->get_tsf(local->mdev);
+ else
+ tsf = -1LLU;
+ if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
+ wpa_printf(MSG_DEBUG, "RX beacon SA=" MACSTR " BSSID="
+ MACSTR " TSF=0x%llx BCN=0x%llx diff=%lld "
+ "@%ld",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid),
+ tsf, timestamp, tsf - timestamp, jiffies);
+ last_tsf_debug = jiffies;
+ }
+#endif /* IEEE80211_IBSS_DEBUG */
+ }
+#endif
+
+ if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
+ &elems) == ParseFailed)
+ invalid = 1;
+
+#if 0 /* FIX */
+ if (local->conf.mode == IW_MODE_ADHOC && elems.supp_rates &&
+ os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0 &&
+ (sta = sta_info_get(local, mgmt->sa))) {
+ struct ieee80211_rate *rates;
+ size_t num_rates;
+ u32 supp_rates, prev_rates;
+ int i, j, oper_mode;
+
+ rates = local->curr_rates;
+ num_rates = local->num_curr_rates;
+ oper_mode = wpa_s->mlme.sta_scanning ?
+ local->scan_oper_phymode : local->conf.phymode;
+ for (i = 0; i < local->hw->num_modes; i++) {
+ struct ieee80211_hw_modes *mode = &local->hw->modes[i];
+ if (oper_mode == mode->mode) {
+ rates = mode->rates;
+ num_rates = mode->num_rates;
+ break;
+ }
+ }
+
+ supp_rates = 0;
+ for (i = 0; i < elems.supp_rates_len +
+ elems.ext_supp_rates_len; i++) {
+ u8 rate = 0;
+ int own_rate;
+ if (i < elems.supp_rates_len)
+ rate = elems.supp_rates[i];
+ else if (elems.ext_supp_rates)
+ rate = elems.ext_supp_rates
+ [i - elems.supp_rates_len];
+ own_rate = 5 * (rate & 0x7f);
+ if (oper_mode == MODE_ATHEROS_TURBO)
+ own_rate *= 2;
+ for (j = 0; j < num_rates; j++)
+ if (rates[j].rate == own_rate)
+ supp_rates |= BIT(j);
+ }
+
+ prev_rates = sta->supp_rates;
+ sta->supp_rates &= supp_rates;
+ if (sta->supp_rates == 0) {
+ /* No matching rates - this should not really happen.
+ * Make sure that at least one rate is marked
+ * supported to avoid issues with TX rate ctrl. */
+ sta->supp_rates = wpa_s->mlme.supp_rates_bits;
+ }
+ if (sta->supp_rates != prev_rates) {
+ wpa_printf(MSG_DEBUG, "MLME: updated supp_rates set "
+ "for " MACSTR " based on beacon info "
+ "(0x%x & 0x%x -> 0x%x)",
+ MAC2STR(sta->addr), prev_rates,
+ supp_rates, sta->supp_rates);
+ }
+ sta_info_release(local, sta);
+ }
+#endif
+
+ if (elems.ssid == NULL)
+ return;
+
+ if (elems.ds_params && elems.ds_params_len == 1)
+ channel = elems.ds_params[0];
+ else
+ channel = rx_status->channel;
+
+ bss = ieee80211_bss_get(wpa_s, mgmt->bssid);
+ if (bss == NULL) {
+ bss = ieee80211_bss_add(wpa_s, mgmt->bssid);
+ if (bss == NULL)
+ return;
+ } else {
+#if 0
+ /* TODO: order by RSSI? */
+ spin_lock_bh(&local->sta_bss_lock);
+ list_move_tail(&bss->list, &local->sta_bss_list);
+ spin_unlock_bh(&local->sta_bss_lock);
+#endif
+ }
+
+ if (bss->probe_resp && beacon) {
+ /* Do not allow beacon to override data from Probe Response. */
+ return;
+ }
+
+ bss->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
+ bss->capability = le_to_host16(mgmt->u.beacon.capab_info);
+ if (elems.ssid && elems.ssid_len <= MAX_SSID_LEN) {
+ os_memcpy(bss->ssid, elems.ssid, elems.ssid_len);
+ bss->ssid_len = elems.ssid_len;
+ }
+
+ bss->supp_rates_len = 0;
+ if (elems.supp_rates) {
+ clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+ if (clen > elems.supp_rates_len)
+ clen = elems.supp_rates_len;
+ os_memcpy(&bss->supp_rates[bss->supp_rates_len],
+ elems.supp_rates, clen);
+ bss->supp_rates_len += clen;
+ }
+ if (elems.ext_supp_rates) {
+ clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
+ if (clen > elems.ext_supp_rates_len)
+ clen = elems.ext_supp_rates_len;
+ os_memcpy(&bss->supp_rates[bss->supp_rates_len],
+ elems.ext_supp_rates, clen);
+ bss->supp_rates_len += clen;
+ }
+
+ if (elems.wpa &&
+ (bss->wpa_ie == NULL || bss->wpa_ie_len != elems.wpa_len ||
+ os_memcmp(bss->wpa_ie, elems.wpa, elems.wpa_len))) {
+ os_free(bss->wpa_ie);
+ bss->wpa_ie = os_malloc(elems.wpa_len + 2);
+ if (bss->wpa_ie) {
+ os_memcpy(bss->wpa_ie, elems.wpa - 2,
+ elems.wpa_len + 2);
+ bss->wpa_ie_len = elems.wpa_len + 2;
+ } else
+ bss->wpa_ie_len = 0;
+ } else if (!elems.wpa && bss->wpa_ie) {
+ os_free(bss->wpa_ie);
+ bss->wpa_ie = NULL;
+ bss->wpa_ie_len = 0;
+ }
+
+ if (elems.rsn &&
+ (bss->rsn_ie == NULL || bss->rsn_ie_len != elems.rsn_len ||
+ os_memcmp(bss->rsn_ie, elems.rsn, elems.rsn_len))) {
+ os_free(bss->rsn_ie);
+ bss->rsn_ie = os_malloc(elems.rsn_len + 2);
+ if (bss->rsn_ie) {
+ os_memcpy(bss->rsn_ie, elems.rsn - 2,
+ elems.rsn_len + 2);
+ bss->rsn_ie_len = elems.rsn_len + 2;
+ } else
+ bss->rsn_ie_len = 0;
+ } else if (!elems.rsn && bss->rsn_ie) {
+ os_free(bss->rsn_ie);
+ bss->rsn_ie = NULL;
+ bss->rsn_ie_len = 0;
+ }
+
+ if (elems.wmm_param &&
+ (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wmm_param_len ||
+ os_memcmp(bss->wmm_ie, elems.wmm_param, elems.wmm_param_len))) {
+ os_free(bss->wmm_ie);
+ bss->wmm_ie = os_malloc(elems.wmm_param_len + 2);
+ if (bss->wmm_ie) {
+ os_memcpy(bss->wmm_ie, elems.wmm_param - 2,
+ elems.wmm_param_len + 2);
+ bss->wmm_ie_len = elems.wmm_param_len + 2;
+ } else
+ bss->wmm_ie_len = 0;
+ } else if (!elems.wmm_param && bss->wmm_ie) {
+ os_free(bss->wmm_ie);
+ bss->wmm_ie = NULL;
+ bss->wmm_ie_len = 0;
+ }
+
+
+ bss->hw_mode = wpa_s->mlme.phymode;
+ bss->channel = channel;
+ bss->freq = wpa_s->mlme.freq;
+ if (channel != wpa_s->mlme.channel &&
+ (wpa_s->mlme.phymode == WPA_MODE_IEEE80211G ||
+ wpa_s->mlme.phymode == WPA_MODE_IEEE80211B) &&
+ channel >= 1 && channel <= 14) {
+ static const int freq_list[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+ };
+ /* IEEE 802.11g/b mode can receive packets from neighboring
+ * channels, so map the channel into frequency. */
+ bss->freq = freq_list[channel - 1];
+ }
+ bss->timestamp = timestamp;
+ os_get_time(&bss->last_update);
+ bss->rssi = rx_status->ssi;
+ if (!beacon)
+ bss->probe_resp++;
+}
+
+
+static void ieee80211_rx_mgmt_probe_resp(struct wpa_supplicant *wpa_s,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 0);
+}
+
+
+static void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ int use_protection;
+ size_t baselen;
+ struct ieee802_11_elems elems;
+
+ ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 1);
+
+ if (!wpa_s->mlme.associated ||
+ os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0)
+ return;
+
+ /* Process beacon from the current BSS */
+ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+ if (baselen > len)
+ return;
+
+ if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
+ &elems) == ParseFailed)
+ return;
+
+ use_protection = 0;
+ if (elems.erp_info && elems.erp_info_len >= 1) {
+ use_protection =
+ (elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
+ }
+
+ if (use_protection != !!wpa_s->mlme.use_protection) {
+ wpa_printf(MSG_DEBUG, "MLME: CTS protection %s (BSSID=" MACSTR
+ ")",
+ use_protection ? "enabled" : "disabled",
+ MAC2STR(wpa_s->bssid));
+ wpa_s->mlme.use_protection = use_protection ? 1 : 0;
+ wpa_s->mlme.cts_protect_erp_frames = use_protection;
+ }
+
+ if (elems.wmm_param && wpa_s->mlme.wmm_enabled) {
+ ieee80211_sta_wmm_params(wpa_s, elems.wmm_param,
+ elems.wmm_param_len);
+ }
+}
+
+
+static void ieee80211_rx_mgmt_probe_req(struct wpa_supplicant *wpa_s,
+ struct ieee80211_mgmt *mgmt,
+ size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ int tx_last_beacon, adhoc;
+#if 0 /* FIX */
+ struct ieee80211_mgmt *resp;
+#endif
+ u8 *pos, *end;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+ adhoc = ssid && ssid->mode == 1;
+
+ if (!adhoc || wpa_s->mlme.state != IEEE80211_IBSS_JOINED ||
+ len < 24 + 2 || wpa_s->mlme.probe_resp == NULL)
+ return;
+
+#if 0 /* FIX */
+ if (local->hw->tx_last_beacon)
+ tx_last_beacon = local->hw->tx_last_beacon(local->mdev);
+ else
+#endif
+ tx_last_beacon = 1;
+
+#ifdef IEEE80211_IBSS_DEBUG
+ wpa_printf(MSG_DEBUG, "MLME: RX ProbeReq SA=" MACSTR " DA=" MACSTR
+ " BSSID=" MACSTR " (tx_last_beacon=%d)",
+ MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
+ MAC2STR(mgmt->bssid), tx_last_beacon);
+#endif /* IEEE80211_IBSS_DEBUG */
+
+ if (!tx_last_beacon)
+ return;
+
+ if (os_memcmp(mgmt->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
+ os_memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
+ return;
+
+ end = ((u8 *) mgmt) + len;
+ pos = mgmt->u.probe_req.variable;
+ if (pos[0] != WLAN_EID_SSID ||
+ pos + 2 + pos[1] > end) {
+ wpa_printf(MSG_DEBUG, "MLME: Invalid SSID IE in ProbeReq from "
+ MACSTR, MAC2STR(mgmt->sa));
+ return;
+ }
+ if (pos[1] != 0 &&
+ (pos[1] != wpa_s->mlme.ssid_len ||
+ os_memcmp(pos + 2, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) != 0))
+ {
+ /* Ignore ProbeReq for foreign SSID */
+ return;
+ }
+
+#if 0 /* FIX */
+ /* Reply with ProbeResp */
+ skb = skb_copy(wpa_s->mlme.probe_resp, GFP_ATOMIC);
+ if (skb == NULL)
+ return;
+
+ resp = (struct ieee80211_mgmt *) skb->data;
+ os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
+#ifdef IEEE80211_IBSS_DEBUG
+ wpa_printf(MSG_DEBUG, "MLME: Sending ProbeResp to " MACSTR,
+ MAC2STR(resp->da));
+#endif /* IEEE80211_IBSS_DEBUG */
+ ieee80211_sta_tx(wpa_s, skb, 0, 1);
+#endif
+}
+
+
+static void ieee80211_sta_rx_mgmt(struct wpa_supplicant *wpa_s,
+ const u8 *buf, size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ if (len < 24)
+ return;
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ fc = le_to_host16(mgmt->frame_control);
+
+ switch (WLAN_FC_GET_STYPE(fc)) {
+ case WLAN_FC_STYPE_PROBE_REQ:
+ ieee80211_rx_mgmt_probe_req(wpa_s, mgmt, len, rx_status);
+ break;
+ case WLAN_FC_STYPE_PROBE_RESP:
+ ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, len, rx_status);
+ break;
+ case WLAN_FC_STYPE_BEACON:
+ ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status);
+ break;
+ case WLAN_FC_STYPE_AUTH:
+ ieee80211_rx_mgmt_auth(wpa_s, mgmt, len, rx_status);
+ break;
+ case WLAN_FC_STYPE_ASSOC_RESP:
+ ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 0);
+ break;
+ case WLAN_FC_STYPE_REASSOC_RESP:
+ ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 1);
+ break;
+ case WLAN_FC_STYPE_DEAUTH:
+ ieee80211_rx_mgmt_deauth(wpa_s, mgmt, len, rx_status);
+ break;
+ case WLAN_FC_STYPE_DISASSOC:
+ ieee80211_rx_mgmt_disassoc(wpa_s, mgmt, len, rx_status);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "MLME: received unknown management "
+ "frame - stype=%d", WLAN_FC_GET_STYPE(fc));
+ break;
+ }
+}
+
+
+static void ieee80211_sta_rx_scan(struct wpa_supplicant *wpa_s,
+ const u8 *buf, size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_mgmt *mgmt;
+ u16 fc;
+
+ if (len < 24)
+ return;
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ fc = le_to_host16(mgmt->frame_control);
+
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) {
+ if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
+ ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt,
+ len, rx_status);
+ } else if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) {
+ ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status);
+ }
+ }
+}
+
+
+static int ieee80211_sta_active_ibss(struct wpa_supplicant *wpa_s)
+{
+ int active = 0;
+
+#if 0 /* FIX */
+ list_for_each(ptr, &local->sta_list) {
+ sta = list_entry(ptr, struct sta_info, list);
+ if (sta->dev == dev &&
+ time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
+ jiffies)) {
+ active++;
+ break;
+ }
+ }
+#endif
+
+ return active;
+}
+
+
+static void ieee80211_sta_expire(struct wpa_supplicant *wpa_s)
+{
+#if 0 /* FIX */
+ list_for_each_safe(ptr, n, &local->sta_list) {
+ sta = list_entry(ptr, struct sta_info, list);
+ if (time_after(jiffies, sta->last_rx +
+ IEEE80211_IBSS_INACTIVITY_LIMIT)) {
+ wpa_printf(MSG_DEBUG, "MLME: expiring inactive STA "
+ MACSTR, MAC2STR(sta->addr));
+ sta_info_free(local, sta, 1);
+ }
+ }
+#endif
+}
+
+
+static void ieee80211_sta_merge_ibss(struct wpa_supplicant *wpa_s)
+{
+ ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL);
+
+ ieee80211_sta_expire(wpa_s);
+ if (ieee80211_sta_active_ibss(wpa_s))
+ return;
+
+ wpa_printf(MSG_DEBUG, "MLME: No active IBSS STAs - trying to scan for "
+ "other IBSS networks with same SSID (merge)");
+ ieee80211_sta_req_scan(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
+}
+
+
+static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ switch (wpa_s->mlme.state) {
+ case IEEE80211_DISABLED:
+ break;
+ case IEEE80211_AUTHENTICATE:
+ ieee80211_authenticate(wpa_s);
+ break;
+ case IEEE80211_ASSOCIATE:
+ ieee80211_associate(wpa_s);
+ break;
+ case IEEE80211_ASSOCIATED:
+ ieee80211_associated(wpa_s);
+ break;
+ case IEEE80211_IBSS_SEARCH:
+ ieee80211_sta_find_ibss(wpa_s);
+ break;
+ case IEEE80211_IBSS_JOINED:
+ ieee80211_sta_merge_ibss(wpa_s);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "ieee80211_sta_timer: Unknown state %d",
+ wpa_s->mlme.state);
+ break;
+ }
+
+ if (ieee80211_privacy_mismatch(wpa_s)) {
+ wpa_printf(MSG_DEBUG, "MLME: privacy configuration mismatch "
+ "and mixed-cell disabled - disassociate");
+
+ ieee80211_send_disassoc(wpa_s, WLAN_REASON_UNSPECIFIED);
+ ieee80211_set_associated(wpa_s, 0);
+ }
+}
+
+
+static void ieee80211_sta_new_auth(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ if (ssid && ssid->mode != 0)
+ return;
+
+#if 0 /* FIX */
+ if (local->hw->reset_tsf) {
+ /* Reset own TSF to allow time synchronization work. */
+ local->hw->reset_tsf(local->mdev);
+ }
+#endif
+
+ wpa_s->mlme.wmm_last_param_set = -1; /* allow any WMM update */
+
+
+ if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_OPEN)
+ wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
+ else if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
+ wpa_s->mlme.auth_alg = WLAN_AUTH_SHARED_KEY;
+ else if (wpa_s->mlme.auth_algs & IEEE80211_AUTH_ALG_LEAP)
+ wpa_s->mlme.auth_alg = WLAN_AUTH_LEAP;
+ else
+ wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
+ wpa_printf(MSG_DEBUG, "MLME: Initial auth_alg=%d",
+ wpa_s->mlme.auth_alg);
+ wpa_s->mlme.auth_transaction = -1;
+ wpa_s->mlme.auth_tries = wpa_s->mlme.assoc_tries = 0;
+ ieee80211_authenticate(wpa_s);
+}
+
+
+static int ieee80211_ibss_allowed(struct wpa_supplicant *wpa_s)
+{
+#if 0 /* FIX */
+ int m, c;
+
+ for (m = 0; m < local->hw->num_modes; m++) {
+ struct ieee80211_hw_modes *mode = &local->hw->modes[m];
+ if (mode->mode != local->conf.phymode)
+ continue;
+ for (c = 0; c < mode->num_channels; c++) {
+ struct ieee80211_channel *chan = &mode->channels[c];
+ if (chan->flag & IEEE80211_CHAN_W_SCAN &&
+ chan->chan == local->conf.channel) {
+ if (chan->flag & IEEE80211_CHAN_W_IBSS)
+ return 1;
+ break;
+ }
+ }
+ }
+#endif
+
+ return 0;
+}
+
+
+static int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s,
+ struct ieee80211_sta_bss *bss)
+{
+ int res = 0, rates, done = 0;
+ struct ieee80211_mgmt *mgmt;
+#if 0 /* FIX */
+ struct ieee80211_tx_control control;
+ struct ieee80211_rate *rate;
+ struct rate_control_extra extra;
+#endif
+ u8 *pos, *buf;
+ size_t len;
+
+ /* Remove possible STA entries from other IBSS networks. */
+#if 0 /* FIX */
+ sta_info_flush(local, NULL);
+
+ if (local->hw->reset_tsf) {
+ /* Reset own TSF to allow time synchronization work. */
+ local->hw->reset_tsf(local->mdev);
+ }
+#endif
+ os_memcpy(wpa_s->bssid, bss->bssid, ETH_ALEN);
+
+#if 0 /* FIX */
+ local->conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
+
+ sdata->drop_unencrypted = bss->capability &
+ host_to_le16(WLAN_CAPABILITY_PRIVACY) ? 1 : 0;
+#endif
+
+#if 0 /* FIX */
+ os_memset(&rq, 0, sizeof(rq));
+ rq.m = bss->freq * 100000;
+ rq.e = 1;
+ res = ieee80211_ioctl_siwfreq(wpa_s, NULL, &rq, NULL);
+#endif
+
+ if (!ieee80211_ibss_allowed(wpa_s)) {
+#if 0 /* FIX */
+ wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed on channel %d "
+ "(%d MHz)", local->conf.channel,
+ local->conf.freq);
+#endif
+ return -1;
+ }
+
+ /* Set beacon template based on scan results */
+ buf = os_malloc(400);
+ len = 0;
+ do {
+ if (buf == NULL)
+ break;
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ len += 24 + sizeof(mgmt->u.beacon);
+ os_memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+ mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_BEACON);
+ os_memset(mgmt->da, 0xff, ETH_ALEN);
+ os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
+ os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
+#if 0 /* FIX */
+ mgmt->u.beacon.beacon_int =
+ host_to_le16(local->conf.beacon_int);
+#endif
+ mgmt->u.beacon.capab_info = host_to_le16(bss->capability);
+
+ pos = buf + len;
+ len += 2 + wpa_s->mlme.ssid_len;
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = wpa_s->mlme.ssid_len;
+ os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
+
+ rates = bss->supp_rates_len;
+ if (rates > 8)
+ rates = 8;
+ pos = buf + len;
+ len += 2 + rates;
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = rates;
+ os_memcpy(pos, bss->supp_rates, rates);
+
+ pos = buf + len;
+ len += 2 + 1;
+ *pos++ = WLAN_EID_DS_PARAMS;
+ *pos++ = 1;
+ *pos++ = bss->channel;
+
+ pos = buf + len;
+ len += 2 + 2;
+ *pos++ = WLAN_EID_IBSS_PARAMS;
+ *pos++ = 2;
+ /* FIX: set ATIM window based on scan results */
+ *pos++ = 0;
+ *pos++ = 0;
+
+ if (bss->supp_rates_len > 8) {
+ rates = bss->supp_rates_len - 8;
+ pos = buf + len;
+ len += 2 + rates;
+ *pos++ = WLAN_EID_EXT_SUPP_RATES;
+ *pos++ = rates;
+ os_memcpy(pos, &bss->supp_rates[8], rates);
+ }
+
+#if 0 /* FIX */
+ os_memset(&control, 0, sizeof(control));
+ control.pkt_type = PKT_PROBE_RESP;
+ os_memset(&extra, 0, sizeof(extra));
+ extra.endidx = local->num_curr_rates;
+ rate = rate_control_get_rate(wpa_s, skb, &extra);
+ if (rate == NULL) {
+ wpa_printf(MSG_DEBUG, "MLME: Failed to determine TX "
+ "rate for IBSS beacon");
+ break;
+ }
+ control.tx_rate = (wpa_s->mlme.short_preamble &&
+ (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
+ rate->val2 : rate->val;
+ control.antenna_sel = local->conf.antenna_sel;
+ control.power_level = local->conf.power_level;
+ control.no_ack = 1;
+ control.retry_limit = 1;
+ control.rts_cts_duration = 0;
+#endif
+
+#if 0 /* FIX */
+ wpa_s->mlme.probe_resp = skb_copy(skb, GFP_ATOMIC);
+ if (wpa_s->mlme.probe_resp) {
+ mgmt = (struct ieee80211_mgmt *)
+ wpa_s->mlme.probe_resp->data;
+ mgmt->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_PROBE_RESP);
+ } else {
+ wpa_printf(MSG_DEBUG, "MLME: Could not allocate "
+ "ProbeResp template for IBSS");
+ }
+
+ if (local->hw->beacon_update &&
+ local->hw->beacon_update(wpa_s, skb, &control) == 0) {
+ wpa_printf(MSG_DEBUG, "MLME: Configured IBSS beacon "
+ "template based on scan results");
+ skb = NULL;
+ }
+
+ rates = 0;
+ for (i = 0; i < bss->supp_rates_len; i++) {
+ int rate = (bss->supp_rates[i] & 0x7f) * 5;
+ if (local->conf.phymode == MODE_ATHEROS_TURBO)
+ rate *= 2;
+ for (j = 0; j < local->num_curr_rates; j++)
+ if (local->curr_rates[j].rate == rate)
+ rates |= BIT(j);
+ }
+ wpa_s->mlme.supp_rates_bits = rates;
+#endif
+ done = 1;
+ } while (0);
+
+ os_free(buf);
+ if (!done) {
+ wpa_printf(MSG_DEBUG, "MLME: Failed to configure IBSS beacon "
+ "template");
+ }
+
+ wpa_s->mlme.state = IEEE80211_IBSS_JOINED;
+ ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL);
+
+ return res;
+}
+
+
+#if 0 /* FIX */
+static int ieee80211_sta_create_ibss(struct wpa_supplicant *wpa_s)
+{
+ struct ieee80211_sta_bss *bss;
+ u8 bssid[ETH_ALEN], *pos;
+ int i;
+
+#if 0
+ /* Easier testing, use fixed BSSID. */
+ os_memset(bssid, 0xfe, ETH_ALEN);
+#else
+ /* Generate random, not broadcast, locally administered BSSID. Mix in
+ * own MAC address to make sure that devices that do not have proper
+ * random number generator get different BSSID. */
+ os_get_random(bssid, ETH_ALEN);
+ for (i = 0; i < ETH_ALEN; i++)
+ bssid[i] ^= wpa_s->own_addr[i];
+ bssid[0] &= ~0x01;
+ bssid[0] |= 0x02;
+#endif
+
+ wpa_printf(MSG_DEBUG, "MLME: Creating new IBSS network, BSSID "
+ MACSTR "", MAC2STR(bssid));
+
+ bss = ieee80211_bss_add(wpa_s, bssid);
+ if (bss == NULL)
+ return -ENOMEM;
+
+#if 0 /* FIX */
+ if (local->conf.beacon_int == 0)
+ local->conf.beacon_int = 100;
+ bss->beacon_int = local->conf.beacon_int;
+ bss->hw_mode = local->conf.phymode;
+ bss->channel = local->conf.channel;
+ bss->freq = local->conf.freq;
+#endif
+ os_get_time(&bss->last_update);
+ bss->capability = host_to_le16(WLAN_CAPABILITY_IBSS);
+#if 0 /* FIX */
+ if (sdata->default_key) {
+ bss->capability |= host_to_le16(WLAN_CAPABILITY_PRIVACY);
+ } else
+ sdata->drop_unencrypted = 0;
+ bss->supp_rates_len = local->num_curr_rates;
+#endif
+ pos = bss->supp_rates;
+#if 0 /* FIX */
+ for (i = 0; i < local->num_curr_rates; i++) {
+ int rate = local->curr_rates[i].rate;
+ if (local->conf.phymode == MODE_ATHEROS_TURBO)
+ rate /= 2;
+ *pos++ = (u8) (rate / 5);
+ }
+#endif
+
+ return ieee80211_sta_join_ibss(wpa_s, bss);
+}
+#endif
+
+
+static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s)
+{
+ struct ieee80211_sta_bss *bss;
+ int found = 0;
+ u8 bssid[ETH_ALEN];
+ int active_ibss;
+ struct os_time now;
+
+ if (wpa_s->mlme.ssid_len == 0)
+ return -EINVAL;
+
+ active_ibss = ieee80211_sta_active_ibss(wpa_s);
+#ifdef IEEE80211_IBSS_DEBUG
+ wpa_printf(MSG_DEBUG, "MLME: sta_find_ibss (active_ibss=%d)",
+ active_ibss);
+#endif /* IEEE80211_IBSS_DEBUG */
+ for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) {
+ if (wpa_s->mlme.ssid_len != bss->ssid_len ||
+ os_memcmp(wpa_s->mlme.ssid, bss->ssid, bss->ssid_len) != 0
+ || !(bss->capability & WLAN_CAPABILITY_IBSS))
+ continue;
+#ifdef IEEE80211_IBSS_DEBUG
+ wpa_printf(MSG_DEBUG, " bssid=" MACSTR " found",
+ MAC2STR(bss->bssid));
+#endif /* IEEE80211_IBSS_DEBUG */
+ os_memcpy(bssid, bss->bssid, ETH_ALEN);
+ found = 1;
+ if (active_ibss ||
+ os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)
+ break;
+ }
+
+#ifdef IEEE80211_IBSS_DEBUG
+ wpa_printf(MSG_DEBUG, " sta_find_ibss: selected " MACSTR " current "
+ MACSTR, MAC2STR(bssid), MAC2STR(wpa_s->bssid));
+#endif /* IEEE80211_IBSS_DEBUG */
+ if (found && os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) != 0 &&
+ (bss = ieee80211_bss_get(wpa_s, bssid))) {
+ wpa_printf(MSG_DEBUG, "MLME: Selected IBSS BSSID " MACSTR
+ " based on configured SSID",
+ MAC2STR(bssid));
+ return ieee80211_sta_join_ibss(wpa_s, bss);
+ }
+#ifdef IEEE80211_IBSS_DEBUG
+ wpa_printf(MSG_DEBUG, " did not try to join ibss");
+#endif /* IEEE80211_IBSS_DEBUG */
+
+ /* Selected IBSS not found in current scan results - try to scan */
+ os_get_time(&now);
+#if 0 /* FIX */
+ if (wpa_s->mlme.state == IEEE80211_IBSS_JOINED &&
+ !ieee80211_sta_active_ibss(wpa_s)) {
+ ieee80211_reschedule_timer(wpa_s,
+ IEEE80211_IBSS_MERGE_INTERVAL);
+ } else if (time_after(jiffies, wpa_s->mlme.last_scan_completed +
+ IEEE80211_SCAN_INTERVAL)) {
+ wpa_printf(MSG_DEBUG, "MLME: Trigger new scan to find an IBSS "
+ "to join");
+ return ieee80211_sta_req_scan(wpa_s->mlme.ssid,
+ wpa_s->mlme.ssid_len);
+ } else if (wpa_s->mlme.state != IEEE80211_IBSS_JOINED) {
+ int interval = IEEE80211_SCAN_INTERVAL;
+
+ if (time_after(jiffies, wpa_s->mlme.ibss_join_req +
+ IEEE80211_IBSS_JOIN_TIMEOUT)) {
+ if (wpa_s->mlme.create_ibss &&
+ ieee80211_ibss_allowed(wpa_s))
+ return ieee80211_sta_create_ibss(wpa_s);
+ if (wpa_s->mlme.create_ibss) {
+ wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed "
+ "on the configured channel %d "
+ "(%d MHz)",
+ local->conf.channel,
+ local->conf.freq);
+ }
+
+ /* No IBSS found - decrease scan interval and continue
+ * scanning. */
+ interval = IEEE80211_SCAN_INTERVAL_SLOW;
+ }
+
+ wpa_s->mlme.state = IEEE80211_IBSS_SEARCH;
+ ieee80211_reschedule_timer(wpa_s, interval);
+ return 0;
+ }
+#endif
+
+ return 0;
+}
+
+
+int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid,
+ size_t *len)
+{
+ os_memcpy(ssid, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
+ *len = wpa_s->mlme.ssid_len;
+ return 0;
+}
+
+
+int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_associate_params *params)
+{
+ struct ieee80211_sta_bss *bss;
+
+ wpa_s->mlme.bssid_set = 0;
+ wpa_s->mlme.freq = params->freq;
+ if (params->bssid) {
+ os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN);
+ if (os_memcmp(params->bssid, "\x00\x00\x00\x00\x00\x00",
+ ETH_ALEN))
+ wpa_s->mlme.bssid_set = 1;
+ bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
+ if (bss) {
+ wpa_s->mlme.phymode = bss->hw_mode;
+ wpa_s->mlme.channel = bss->channel;
+ wpa_s->mlme.freq = bss->freq;
+ }
+ }
+
+#if 0 /* FIX */
+ /* TODO: This should always be done for IBSS, even if IEEE80211_QOS is
+ * not defined. */
+ if (local->hw->conf_tx) {
+ struct ieee80211_tx_queue_params qparam;
+ int i;
+
+ os_memset(&qparam, 0, sizeof(qparam));
+ /* TODO: are these ok defaults for all hw_modes? */
+ qparam.aifs = 2;
+ qparam.cw_min =
+ local->conf.phymode == MODE_IEEE80211B ? 31 : 15;
+ qparam.cw_max = 1023;
+ qparam.burst_time = 0;
+ for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
+ {
+ local->hw->conf_tx(wpa_s, i + IEEE80211_TX_QUEUE_DATA0,
+ &qparam);
+ }
+ /* IBSS uses different parameters for Beacon sending */
+ qparam.cw_min++;
+ qparam.cw_min *= 2;
+ qparam.cw_min--;
+ local->hw->conf_tx(wpa_s, IEEE80211_TX_QUEUE_BEACON, &qparam);
+ }
+#endif
+
+ if (wpa_s->mlme.ssid_len != params->ssid_len ||
+ os_memcmp(wpa_s->mlme.ssid, params->ssid, params->ssid_len) != 0)
+ wpa_s->mlme.prev_bssid_set = 0;
+ os_memcpy(wpa_s->mlme.ssid, params->ssid, params->ssid_len);
+ os_memset(wpa_s->mlme.ssid + params->ssid_len, 0,
+ MAX_SSID_LEN - params->ssid_len);
+ wpa_s->mlme.ssid_len = params->ssid_len;
+ wpa_s->mlme.ssid_set = 1;
+
+ os_free(wpa_s->mlme.extra_ie);
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
+ wpa_s->mlme.extra_ie = NULL;
+ wpa_s->mlme.extra_ie_len = 0;
+ return 0;
+ }
+ wpa_s->mlme.extra_ie = os_malloc(params->wpa_ie_len);
+ if (wpa_s->mlme.extra_ie == NULL) {
+ wpa_s->mlme.extra_ie_len = 0;
+ return -1;
+ }
+ os_memcpy(wpa_s->mlme.extra_ie, params->wpa_ie, params->wpa_ie_len);
+ wpa_s->mlme.extra_ie_len = params->wpa_ie_len;
+
+ wpa_s->mlme.key_mgmt = params->key_mgmt_suite;
+
+ ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode,
+ wpa_s->mlme.channel, wpa_s->mlme.freq);
+
+ if (params->mode == 1 && !wpa_s->mlme.bssid_set) {
+ os_get_time(&wpa_s->mlme.ibss_join_req);
+ wpa_s->mlme.state = IEEE80211_IBSS_SEARCH;
+ return ieee80211_sta_find_ibss(wpa_s);
+ }
+
+ if (wpa_s->mlme.bssid_set)
+ ieee80211_sta_new_auth(wpa_s);
+
+ return 0;
+}
+
+
+static void ieee80211_sta_save_oper_chan(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->mlme.scan_oper_channel = wpa_s->mlme.channel;
+ wpa_s->mlme.scan_oper_freq = wpa_s->mlme.freq;
+ wpa_s->mlme.scan_oper_phymode = wpa_s->mlme.phymode;
+}
+
+
+static int ieee80211_sta_restore_oper_chan(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->mlme.channel = wpa_s->mlme.scan_oper_channel;
+ wpa_s->mlme.freq = wpa_s->mlme.scan_oper_freq;
+ wpa_s->mlme.phymode = wpa_s->mlme.scan_oper_phymode;
+ if (wpa_s->mlme.freq == 0)
+ return 0;
+ return ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode,
+ wpa_s->mlme.channel,
+ wpa_s->mlme.freq);
+}
+
+
+static int ieee80211_active_scan(struct wpa_supplicant *wpa_s)
+{
+ size_t m;
+ int c;
+
+ for (m = 0; m < wpa_s->mlme.num_modes; m++) {
+ struct wpa_hw_modes *mode = &wpa_s->mlme.modes[m];
+ if ((int) mode->mode != (int) wpa_s->mlme.phymode)
+ continue;
+ for (c = 0; c < mode->num_channels; c++) {
+ struct wpa_channel_data *chan = &mode->channels[c];
+ if (chan->flag & WPA_CHAN_W_SCAN &&
+ chan->chan == wpa_s->mlme.channel) {
+ if (chan->flag & WPA_CHAN_W_ACTIVE_SCAN)
+ return 1;
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wpa_hw_modes *mode;
+ struct wpa_channel_data *chan;
+ int skip = 0;
+ int timeout = 0;
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ int adhoc;
+
+ if (!wpa_s->mlme.sta_scanning || wpa_s->mlme.modes == NULL)
+ return;
+
+ adhoc = ssid && ssid->mode == 1;
+
+ switch (wpa_s->mlme.scan_state) {
+ case SCAN_SET_CHANNEL:
+ mode = &wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx];
+ if (wpa_s->mlme.scan_hw_mode_idx >=
+ (int) wpa_s->mlme.num_modes ||
+ (wpa_s->mlme.scan_hw_mode_idx + 1 ==
+ (int) wpa_s->mlme.num_modes
+ && wpa_s->mlme.scan_channel_idx >= mode->num_channels)) {
+ if (ieee80211_sta_restore_oper_chan(wpa_s)) {
+ wpa_printf(MSG_DEBUG, "MLME: failed to "
+ "restore operational channel after "
+ "scan");
+ }
+ wpa_printf(MSG_DEBUG, "MLME: scan completed");
+ wpa_s->mlme.sta_scanning = 0;
+ os_get_time(&wpa_s->mlme.last_scan_completed);
+ wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL);
+ if (adhoc) {
+ if (!wpa_s->mlme.bssid_set ||
+ (wpa_s->mlme.state ==
+ IEEE80211_IBSS_JOINED &&
+ !ieee80211_sta_active_ibss(wpa_s)))
+ ieee80211_sta_find_ibss(wpa_s);
+ }
+ return;
+ }
+ skip = !(wpa_s->mlme.hw_modes & (1 << mode->mode));
+ chan = &mode->channels[wpa_s->mlme.scan_channel_idx];
+ if (!(chan->flag & WPA_CHAN_W_SCAN) ||
+ (adhoc && !(chan->flag & WPA_CHAN_W_IBSS)) ||
+ (wpa_s->mlme.hw_modes & (1 << WPA_MODE_IEEE80211G) &&
+ mode->mode == WPA_MODE_IEEE80211B &&
+ wpa_s->mlme.scan_skip_11b))
+ skip = 1;
+
+ if (!skip) {
+ wpa_printf(MSG_MSGDUMP,
+ "MLME: scan channel %d (%d MHz)",
+ chan->chan, chan->freq);
+
+ wpa_s->mlme.channel = chan->chan;
+ wpa_s->mlme.freq = chan->freq;
+ wpa_s->mlme.phymode = mode->mode;
+ if (ieee80211_sta_set_channel(wpa_s, mode->mode,
+ chan->chan, chan->freq))
+ {
+ wpa_printf(MSG_DEBUG, "MLME: failed to set "
+ "channel %d (%d MHz) for scan",
+ chan->chan, chan->freq);
+ skip = 1;
+ }
+ }
+
+ wpa_s->mlme.scan_channel_idx++;
+ if (wpa_s->mlme.scan_channel_idx >=
+ wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx].
+ num_channels) {
+ wpa_s->mlme.scan_hw_mode_idx++;
+ wpa_s->mlme.scan_channel_idx = 0;
+ }
+
+ if (skip) {
+ timeout = 0;
+ break;
+ }
+
+ timeout = IEEE80211_PROBE_DELAY;
+ wpa_s->mlme.scan_state = SCAN_SEND_PROBE;
+ break;
+ case SCAN_SEND_PROBE:
+ if (ieee80211_active_scan(wpa_s)) {
+ ieee80211_send_probe_req(wpa_s, NULL,
+ wpa_s->mlme.scan_ssid,
+ wpa_s->mlme.scan_ssid_len);
+ timeout = IEEE80211_CHANNEL_TIME;
+ } else {
+ timeout = IEEE80211_PASSIVE_CHANNEL_TIME;
+ }
+ wpa_s->mlme.scan_state = SCAN_SET_CHANNEL;
+ break;
+ }
+
+ eloop_register_timeout(timeout / 1000, 1000 * (timeout % 1000),
+ ieee80211_sta_scan_timer, wpa_s, NULL);
+}
+
+
+int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s, const u8 *ssid,
+ size_t ssid_len)
+{
+ if (ssid_len > MAX_SSID_LEN)
+ return -1;
+
+ /* MLME-SCAN.request (page 118) page 144 (11.1.3.1)
+ * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
+ * BSSID: MACAddress
+ * SSID
+ * ScanType: ACTIVE, PASSIVE
+ * ProbeDelay: delay (in microseconds) to be used prior to transmitting
+ * a Probe frame during active scanning
+ * ChannelList
+ * MinChannelTime (>= ProbeDelay), in TU
+ * MaxChannelTime: (>= MinChannelTime), in TU
+ */
+
+ /* MLME-SCAN.confirm
+ * BSSDescriptionSet
+ * ResultCode: SUCCESS, INVALID_PARAMETERS
+ */
+
+ /* TODO: if assoc, move to power save mode for the duration of the
+ * scan */
+
+ if (wpa_s->mlme.sta_scanning)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "MLME: starting scan");
+
+ ieee80211_sta_save_oper_chan(wpa_s);
+
+ wpa_s->mlme.sta_scanning = 1;
+ /* TODO: stop TX queue? */
+
+ if (ssid) {
+ wpa_s->mlme.scan_ssid_len = ssid_len;
+ os_memcpy(wpa_s->mlme.scan_ssid, ssid, ssid_len);
+ } else
+ wpa_s->mlme.scan_ssid_len = 0;
+ wpa_s->mlme.scan_skip_11b = 1; /* FIX: clear this is 11g is not
+ * supported */
+ wpa_s->mlme.scan_state = SCAN_SET_CHANNEL;
+ wpa_s->mlme.scan_hw_mode_idx = 0;
+ wpa_s->mlme.scan_channel_idx = 0;
+ eloop_register_timeout(0, 1, ieee80211_sta_scan_timer, wpa_s, NULL);
+
+ return 0;
+}
+
+
+int ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ size_t ap_num = 0;
+ struct wpa_scan_result *r;
+ struct ieee80211_sta_bss *bss;
+
+ os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+ for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) {
+ r = &results[ap_num];
+ os_memcpy(r->bssid, bss->bssid, ETH_ALEN);
+ os_memcpy(r->ssid, bss->ssid, bss->ssid_len);
+ r->ssid_len = bss->ssid_len;
+ if (bss->wpa_ie && bss->wpa_ie_len < SSID_MAX_WPA_IE_LEN) {
+ os_memcpy(r->wpa_ie, bss->wpa_ie, bss->wpa_ie_len);
+ r->wpa_ie_len = bss->wpa_ie_len;
+ }
+ if (bss->rsn_ie && bss->rsn_ie_len < SSID_MAX_WPA_IE_LEN) {
+ os_memcpy(r->rsn_ie, bss->rsn_ie, bss->rsn_ie_len);
+ r->rsn_ie_len = bss->rsn_ie_len;
+ }
+ r->freq = bss->freq;
+ r->caps = bss->capability;
+ r->level = bss->rssi;
+
+ ap_num++;
+ if (ap_num >= max_size)
+ break;
+ }
+
+ return ap_num;
+}
+
+
+#if 0 /* FIX */
+struct sta_info * ieee80211_ibss_add_sta(struct wpa_supplicant *wpa_s,
+ struct sk_buff *skb, u8 *bssid,
+ u8 *addr)
+{
+ struct ieee80211_local *local = dev->priv;
+ struct list_head *ptr;
+ struct sta_info *sta;
+ struct wpa_supplicant *sta_dev = NULL;
+
+ /* TODO: Could consider removing the least recently used entry and
+ * allow new one to be added. */
+ if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
+ if (net_ratelimit()) {
+ wpa_printf(MSG_DEBUG, "MLME: No room for a new IBSS "
+ "STA entry " MACSTR, MAC2STR(addr));
+ }
+ return NULL;
+ }
+
+ spin_lock_bh(&local->sub_if_lock);
+ list_for_each(ptr, &local->sub_if_list) {
+ sdata = list_entry(ptr, struct ieee80211_sub_if_data, list);
+ if (sdata->type == IEEE80211_SUB_IF_TYPE_STA &&
+ os_memcmp(bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
+ sta_dev = sdata->dev;
+ break;
+ }
+ }
+ spin_unlock_bh(&local->sub_if_lock);
+
+ if (sta_dev == NULL)
+ return NULL;
+
+ wpa_printf(MSG_DEBUG, "MLME: Adding new IBSS station " MACSTR
+ " (dev=%s)", MAC2STR(addr), sta_dev->name);
+
+ sta = sta_info_add(wpa_s, addr);
+ if (sta == NULL) {
+ return NULL;
+ }
+
+ sta->dev = sta_dev;
+ sta->supp_rates = wpa_s->mlme.supp_rates_bits;
+
+ rate_control_rate_init(local, sta);
+
+ return sta; /* caller will call sta_info_release() */
+}
+#endif
+
+
+int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason)
+{
+ wpa_printf(MSG_DEBUG, "MLME: deauthenticate(reason=%d)", reason);
+
+ ieee80211_send_deauth(wpa_s, reason);
+ ieee80211_set_associated(wpa_s, 0);
+ return 0;
+}
+
+
+int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason)
+{
+ wpa_printf(MSG_DEBUG, "MLME: disassociate(reason=%d)", reason);
+
+ if (!wpa_s->mlme.associated)
+ return -1;
+
+ ieee80211_send_disassoc(wpa_s, reason);
+ ieee80211_set_associated(wpa_s, 0);
+ return 0;
+}
+
+
+void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+ struct ieee80211_mgmt *mgmt;
+ u16 fc;
+ const u8 *pos;
+
+ /* wpa_hexdump(MSG_MSGDUMP, "MLME: Received frame", buf, len); */
+
+ if (wpa_s->mlme.sta_scanning) {
+ ieee80211_sta_rx_scan(wpa_s, buf, len, rx_status);
+ return;
+ }
+
+ if (len < 24)
+ return;
+
+ mgmt = (struct ieee80211_mgmt *) buf;
+ fc = le_to_host16(mgmt->frame_control);
+
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
+ ieee80211_sta_rx_mgmt(wpa_s, buf, len, rx_status);
+ else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
+ if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) !=
+ WLAN_FC_FROMDS)
+ return;
+ /* mgmt->sa is actually BSSID for FromDS data frames */
+ if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0)
+ return;
+ /* Skip IEEE 802.11 and LLC headers */
+ pos = buf + 24 + 6;
+ if (WPA_GET_BE16(pos) != ETH_P_EAPOL)
+ return;
+ pos += 2;
+ /* mgmt->bssid is actually BSSID for SA data frames */
+ wpa_supplicant_rx_eapol(wpa_s, mgmt->bssid,
+ pos, buf + len - pos);
+ }
+}
+
+
+void ieee80211_sta_free_hw_features(struct wpa_hw_modes *hw_features,
+ size_t num_hw_features)
+{
+ size_t i;
+
+ if (hw_features == NULL)
+ return;
+
+ for (i = 0; i < num_hw_features; i++) {
+ os_free(hw_features[i].channels);
+ os_free(hw_features[i].rates);
+ }
+
+ os_free(hw_features);
+}
+
+
+int ieee80211_sta_init(struct wpa_supplicant *wpa_s)
+{
+ u16 num_modes, flags;
+
+ wpa_s->mlme.modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes,
+ &flags);
+ if (wpa_s->mlme.modes == NULL) {
+ wpa_printf(MSG_ERROR, "MLME: Failed to read supported "
+ "channels and rates from the driver");
+ return -1;
+ }
+
+ wpa_s->mlme.num_modes = num_modes;
+
+ wpa_s->mlme.hw_modes = 1 << WPA_MODE_IEEE80211A;
+ wpa_s->mlme.hw_modes |= 1 << WPA_MODE_IEEE80211B;
+ wpa_s->mlme.hw_modes |= 1 << WPA_MODE_IEEE80211G;
+
+ return 0;
+}
+
+
+void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s)
+{
+ eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL);
+ eloop_cancel_timeout(ieee80211_sta_scan_timer, wpa_s, NULL);
+ os_free(wpa_s->mlme.extra_ie);
+ wpa_s->mlme.extra_ie = NULL;
+ os_free(wpa_s->mlme.assocreq_ies);
+ wpa_s->mlme.assocreq_ies = NULL;
+ os_free(wpa_s->mlme.assocresp_ies);
+ wpa_s->mlme.assocresp_ies = NULL;
+ ieee80211_bss_list_deinit(wpa_s);
+ ieee80211_sta_free_hw_features(wpa_s->mlme.modes,
+ wpa_s->mlme.num_modes);
+}
diff --git a/contrib/wpa_supplicant/mlme.h b/contrib/wpa_supplicant/mlme.h
new file mode 100644
index 000000000000..9f6f5eb2acd5
--- /dev/null
+++ b/contrib/wpa_supplicant/mlme.h
@@ -0,0 +1,104 @@
+/*
+ * WPA Supplicant - Client mode MLME
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ *
+ * 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.
+ */
+
+#ifndef MLME_H
+#define MLME_H
+
+#ifdef CONFIG_CLIENT_MLME
+
+int ieee80211_sta_init(struct wpa_supplicant *wpa_s);
+void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s);
+int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s, const u8 *ssid,
+ size_t ssid_len);
+int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason);
+int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason);
+int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_associate_params *params);
+int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid,
+ size_t *len);
+void ieee80211_sta_free_hw_features(struct wpa_hw_modes *hw_features,
+ size_t num_hw_features);
+void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
+ struct ieee80211_rx_status *rx_status);
+int ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *results,
+ size_t max_size);
+
+#else /* CONFIG_CLIENT_MLME */
+
+static inline int ieee80211_sta_init(struct wpa_supplicant *wpa_s)
+{
+ return 0;
+}
+
+static inline void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
+ const u8 *ssid, size_t ssid_len)
+{
+ return -1;
+}
+
+static inline int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+ u16 reason)
+{
+ return -1;
+}
+
+static inline int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s,
+ u16 reason)
+{
+ return -1;
+}
+
+static inline int
+ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
+ struct wpa_driver_associate_params *params)
+{
+ return -1;
+}
+
+static inline int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s,
+ u8 *ssid, size_t *len)
+{
+ return -1;
+}
+
+static inline void
+ieee80211_sta_free_hw_features(struct wpa_hw_modes *hw_features,
+ size_t num_hw_features)
+{
+}
+
+static inline void
+ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
+ struct ieee80211_rx_status *rx_status)
+{
+}
+
+static inline int
+ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ return -1;
+}
+
+#endif /* CONFIG_CLIENT_MLME */
+
+#endif /* MLME_H */
diff --git a/contrib/wpa_supplicant/ms_funcs.c b/contrib/wpa_supplicant/ms_funcs.c
index c26cddfb0775..d7231799d1c7 100644
--- a/contrib/wpa_supplicant/ms_funcs.c
+++ b/contrib/wpa_supplicant/ms_funcs.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "sha1.h"
@@ -26,7 +24,7 @@
/**
* challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
* @peer_challenge: 16-octet PeerChallenge (IN)
- * @auth_challenge: 16-octet AuthChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
* @challenge: 8-octet Challenge (OUT)
@@ -47,41 +45,41 @@ static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
len[2] = username_len;
sha1_vector(3, addr, len, hash);
- memcpy(challenge, hash, 8);
+ os_memcpy(challenge, hash, 8);
}
/**
* nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
- * @password: 0-to-256-unicode-char Password (IN)
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
* @password_len: Length of password
* @password_hash: 16-octet PasswordHash (OUT)
*/
void nt_password_hash(const u8 *password, size_t password_len,
u8 *password_hash)
{
- u8 *buf;
- int i;
- size_t len;
+ u8 buf[512], *pos;
+ size_t i, len;
- /* Convert password into unicode */
- buf = malloc(password_len * 2);
- if (buf == NULL)
+ if (password_len > 256)
return;
- memset(buf, 0, password_len * 2);
- for (i = 0; i < password_len; i++)
+
+ /* Convert password into unicode */
+ for (i = 0; i < password_len; i++) {
buf[2 * i] = password[i];
+ buf[2 * i + 1] = 0;
+ }
len = password_len * 2;
- md4_vector(1, (const u8 **) &buf, &len, password_hash);
- free(buf);
+ pos = buf;
+ md4_vector(1, (const u8 **) &pos, &len, password_hash);
}
/**
* hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
* @password_hash: 16-octet PasswordHash (IN)
- * @password_hash_hash: 16-octet PaswordHashHash (OUT)
+ * @password_hash_hash: 16-octet PasswordHashHash (OUT)
*/
void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
{
@@ -104,7 +102,7 @@ void challenge_response(const u8 *challenge, const u8 *password_hash,
des_encrypt(challenge, password_hash + 7, response + 8);
zpwd[0] = password_hash[14];
zpwd[1] = password_hash[15];
- memset(zpwd + 2, 0, 5);
+ os_memset(zpwd + 2, 0, 5);
des_encrypt(challenge, zpwd, response + 16);
}
@@ -115,7 +113,7 @@ void challenge_response(const u8 *challenge, const u8 *password_hash,
* @peer_hallenge: 16-octet PeerChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
- * @password: 0-to-256-unicode-char Password (IN)
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
* @password_len: Length of password
* @response: 24-octet Response (OUT)
*/
@@ -135,21 +133,44 @@ void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
/**
- * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
- * @password: 0-to-256-unicode-char Password (IN)
- * @password_len: Length of password
+ * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @peer_hallenge: 16-octet PeerChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @response: 24-octet Response (OUT)
+ */
+void generate_nt_response_pwhash(const u8 *auth_challenge,
+ const u8 *peer_challenge,
+ const u8 *username, size_t username_len,
+ const u8 *password_hash,
+ u8 *response)
+{
+ u8 challenge[8];
+
+ challenge_hash(peer_challenge, auth_challenge, username, username_len,
+ challenge);
+ challenge_response(challenge, password_hash, response);
+}
+
+
+/**
+ * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password_hash: 16-octet PasswordHash (IN)
* @nt_response: 24-octet NT-Response (IN)
* @peer_challenge: 16-octet PeerChallenge (IN)
* @auth_challenge: 16-octet AuthenticatorChallenge (IN)
* @username: 0-to-256-char UserName (IN)
* @username_len: Length of username
- * @response: 42-octet AuthenticatorResponse (OUT)
+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
+ * encoded as a 42-octet ASCII string (S=<hexdump of response>)
*/
-void generate_authenticator_response(const u8 *password, size_t password_len,
- const u8 *peer_challenge,
- const u8 *auth_challenge,
- const u8 *username, size_t username_len,
- const u8 *nt_response, u8 *response)
+void generate_authenticator_response_pwhash(
+ const u8 *password_hash,
+ const u8 *peer_challenge, const u8 *auth_challenge,
+ const u8 *username, size_t username_len,
+ const u8 *nt_response, u8 *response)
{
static const u8 magic1[39] = {
0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
@@ -165,7 +186,7 @@ void generate_authenticator_response(const u8 *password, size_t password_len,
0x6E
};
- u8 password_hash[16], password_hash_hash[16], challenge[8];
+ u8 password_hash_hash[16], challenge[8];
const unsigned char *addr1[3];
const size_t len1[3] = { 16, 24, sizeof(magic1) };
const unsigned char *addr2[3];
@@ -179,7 +200,6 @@ void generate_authenticator_response(const u8 *password, size_t password_len,
addr2[1] = challenge;
addr2[2] = magic2;
- nt_password_hash(password, password_len, password_hash);
hash_nt_password_hash(password_hash, password_hash_hash);
sha1_vector(3, addr1, len1, response);
@@ -190,9 +210,36 @@ void generate_authenticator_response(const u8 *password, size_t password_len,
/**
+ * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password_len: Length of password
+ * @nt_response: 24-octet NT-Response (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
+ * encoded as a 42-octet ASCII string (S=<hexdump of response>)
+ */
+void generate_authenticator_response(const u8 *password, size_t password_len,
+ const u8 *peer_challenge,
+ const u8 *auth_challenge,
+ const u8 *username, size_t username_len,
+ const u8 *nt_response, u8 *response)
+{
+ u8 password_hash[16];
+ nt_password_hash(password, password_len, password_hash);
+ generate_authenticator_response_pwhash(password_hash,
+ peer_challenge, auth_challenge,
+ username, username_len,
+ nt_response, response);
+}
+
+
+/**
* nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
* @challenge: 8-octet Challenge (IN)
- * @password: 0-to-256-unicode-char Password (IN)
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
* @password_len: Length of password
* @response: 24-octet Response (OUT)
*/
@@ -228,7 +275,7 @@ void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
addr[2] = magic1;
sha1_vector(3, addr, len, hash);
- memcpy(master_key, hash, 16);
+ os_memcpy(master_key, hash, 16);
}
@@ -236,7 +283,7 @@ void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
* get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
* @master_key: 16-octet MasterKey (IN)
* @session_key: 8-to-16 octet SessionKey (OUT)
- * @session_key_len: SessionKeyLength (Length of session_key)
+ * @session_key_len: SessionKeyLength (Length of session_key) (IN)
* @is_send: IsSend (IN, BOOLEAN)
* @is_server: IsServer (IN, BOOLEAN)
*/
@@ -296,15 +343,15 @@ void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
if (session_key_len > SHA1_MAC_LEN)
session_key_len = SHA1_MAC_LEN;
- memcpy(session_key, digest, session_key_len);
+ os_memcpy(session_key, digest, session_key_len);
}
#define PWBLOCK_LEN 516
/**
- * encrypt_pw_block_with_password_hash - EncryptPwBlobkWithPasswordHash() - RFC 2759, Sect. 8.10
- * @password: 0-to-256-unicode-char Password (IN)
+ * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
+ * @password: 0-to-256-unicode-char Password (IN; ASCII)
* @password_len: Length of password
* @password_hash: 16-octet PasswordHash (IN)
* @pw_block: 516-byte PwBlock (OUT)
@@ -319,10 +366,15 @@ static void encrypt_pw_block_with_password_hash(
if (password_len > 256)
return;
- memset(pw_block, 0, PWBLOCK_LEN);
+ os_memset(pw_block, 0, PWBLOCK_LEN);
offset = (256 - password_len) * 2;
+ os_get_random(pw_block, offset);
for (i = 0; i < password_len; i++)
pw_block[offset + i * 2] = password[i];
+ /*
+ * PasswordLength is 4 octets, but since the maximum password length is
+ * 256, only first two (in little endian byte order) can be non-zero.
+ */
pos = &pw_block[2 * 256];
WPA_PUT_LE16(pos, password_len * 2);
rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
@@ -331,9 +383,9 @@ static void encrypt_pw_block_with_password_hash(
/**
* new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
- * @new_password: 0-to-256-unicode-char NewPassword (IN)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
* @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
* @old_password_len: Length of old_password
* @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
*/
@@ -367,9 +419,9 @@ static void nt_password_hash_encrypted_with_block(const u8 *password_hash,
/**
* old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
- * @new_password: 0-to-256-unicode-char NewPassword (IN)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
* @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
* @old_password_len: Length of old_password
* @encrypted_password_ash: 16-octet EncryptedPasswordHash (OUT)
*/
@@ -386,112 +438,3 @@ void old_nt_password_hash_encrypted_with_new_nt_password_hash(
new_password_hash,
encrypted_password_hash);
}
-
-
-#ifdef TEST_MAIN_MS_FUNCS
-
-#include "rc4.c"
-
-int main(int argc, char *argv[])
-{
- /* Test vector from RFC2759 example */
- u8 *username = "User";
- u8 *password = "clientPass";
- u8 auth_challenge[] = {
- 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
- 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
- };
- u8 peer_challenge[] = {
- 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
- 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
- };
- u8 challenge[] = { 0xD0, 0x2E, 0x43, 0x86, 0xBC, 0xE9, 0x12, 0x26 };
- u8 password_hash[] = {
- 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
- 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
- };
- u8 nt_response[] = {
- 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
- 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
- 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
- };
- u8 password_hash_hash[] = {
- 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
- 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
- };
- u8 authenticator_response[] = {
- 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
- 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
- 0x93, 0x2C, 0xDA, 0x56
- };
- u8 master_key[] = {
- 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
- 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
- };
- u8 send_start_key[] = {
- 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
- 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
- };
- u8 buf[32];
-
- int errors = 0;
-
- printf("Testing ms_funcs.c\n");
-
- challenge_hash(peer_challenge, auth_challenge,
- username, strlen(username),
- buf);
- if (memcmp(challenge, buf, sizeof(challenge)) != 0) {
- printf("challenge_hash failed\n");
- errors++;
- }
-
- nt_password_hash(password, strlen(password), buf);
- if (memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
- printf("nt_password_hash failed\n");
- errors++;
- }
-
- generate_nt_response(auth_challenge, peer_challenge,
- username, strlen(username),
- password, strlen(password),
- buf);
- if (memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
- printf("generate_nt_response failed\n");
- errors++;
- }
-
- hash_nt_password_hash(password_hash, buf);
- if (memcmp(password_hash_hash, buf, sizeof(password_hash_hash)) != 0) {
- printf("hash_nt_password_hash failed\n");
- errors++;
- }
-
- generate_authenticator_response(password, strlen(password),
- peer_challenge, auth_challenge,
- username, strlen(username),
- nt_response, buf);
- if (memcmp(authenticator_response, buf, sizeof(authenticator_response))
- != 0) {
- printf("generate_authenticator_response failed\n");
- errors++;
- }
-
- get_master_key(password_hash_hash, nt_response, buf);
- if (memcmp(master_key, buf, sizeof(master_key)) != 0) {
- printf("get_master_key failed\n");
- errors++;
- }
-
- get_asymetric_start_key(master_key, buf, sizeof(send_start_key), 1, 1);
- if (memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
- printf("get_asymetric_start_key failed\n");
- errors++;
- }
-
- if (errors)
- printf("FAILED! %d errors\n", errors);
-
- return errors;
-}
-#endif /* TEST_MAIN_MS_FUNCS */
diff --git a/contrib/wpa_supplicant/ms_funcs.h b/contrib/wpa_supplicant/ms_funcs.h
index 38d1bd63fe61..8067c097214a 100644
--- a/contrib/wpa_supplicant/ms_funcs.h
+++ b/contrib/wpa_supplicant/ms_funcs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,11 +19,21 @@ void generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
const u8 *username, size_t username_len,
const u8 *password, size_t password_len,
u8 *response);
+void generate_nt_response_pwhash(const u8 *auth_challenge,
+ const u8 *peer_challenge,
+ const u8 *username, size_t username_len,
+ const u8 *password_hash,
+ u8 *response);
void generate_authenticator_response(const u8 *password, size_t password_len,
const u8 *peer_challenge,
const u8 *auth_challenge,
const u8 *username, size_t username_len,
const u8 *nt_response, u8 *response);
+void generate_authenticator_response_pwhash(
+ const u8 *password_hash,
+ const u8 *peer_challenge, const u8 *auth_challenge,
+ const u8 *username, size_t username_len,
+ const u8 *nt_response, u8 *response);
void nt_challenge_response(const u8 *challenge, const u8 *password,
size_t password_len, u8 *response);
@@ -46,5 +56,4 @@ void old_nt_password_hash_encrypted_with_new_nt_password_hash(
const u8 *old_password, size_t old_password_len,
u8 *encrypted_password_hash);
-
#endif /* MS_FUNCS_H */
diff --git a/contrib/wpa_supplicant/nmake.mak b/contrib/wpa_supplicant/nmake.mak
new file mode 100644
index 000000000000..3afabadeb9b5
--- /dev/null
+++ b/contrib/wpa_supplicant/nmake.mak
@@ -0,0 +1,188 @@
+# Makefile for Microsoft nmake to build wpa_supplicant
+
+# This can be run in Visual Studio 2005 Command Prompt
+
+# Note: Make sure that cl.exe is configured to include Platform SDK
+# include and lib directories (vsvars32.bat)
+
+all: wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe wpasvc.exe win_if_list.exe
+
+# Root directory for WinPcap developer's pack
+# (http://www.winpcap.org/install/bin/WpdPack_3_1.zip)
+WINPCAPDIR=C:\dev\WpdPack
+
+# Root directory for OpenSSL
+# (http://www.openssl.org/source/openssl-0.9.8a.tar.gz)
+# Build and installed following instructions in INSTALL.W32
+# Note: If EAP-FAST is included in the build, OpenSSL needs to be patched to
+# support it (openssl-tls-extensions.patch)
+# Alternatively, see README-Windows.txt for information about binary
+# installation package for OpenSSL.
+OPENSSLDIR=C:\dev\openssl
+
+CC = cl
+OBJDIR = objs
+
+CFLAGS = /DCONFIG_NATIVE_WINDOWS
+CFLAGS = $(CFLAGS) /DCONFIG_NDIS_EVENTS_INTEGRATED
+CFLAGS = $(CFLAGS) /DCONFIG_ANSI_C_EXTRA
+CFLAGS = $(CFLAGS) /DCONFIG_WINPCAP
+CFLAGS = $(CFLAGS) /DIEEE8021X_EAPOL
+CFLAGS = $(CFLAGS) /DEAP_TLS_FUNCS
+CFLAGS = $(CFLAGS) /DPKCS12_FUNCS
+CFLAGS = $(CFLAGS) /DEAP_MD5
+CFLAGS = $(CFLAGS) /DEAP_TLS
+CFLAGS = $(CFLAGS) /DEAP_MSCHAPv2
+CFLAGS = $(CFLAGS) /DEAP_PEAP
+CFLAGS = $(CFLAGS) /DEAP_TTLS
+CFLAGS = $(CFLAGS) /DEAP_GTC
+CFLAGS = $(CFLAGS) /DEAP_OTP
+CFLAGS = $(CFLAGS) /DEAP_SIM
+CFLAGS = $(CFLAGS) /DEAP_LEAP
+CFLAGS = $(CFLAGS) /DEAP_PSK
+CFLAGS = $(CFLAGS) /DEAP_AKA
+#CFLAGS = $(CFLAGS) /DEAP_FAST
+CFLAGS = $(CFLAGS) /DEAP_PAX
+CFLAGS = $(CFLAGS) /DPCSC_FUNCS
+CFLAGS = $(CFLAGS) /DCONFIG_CTRL_IFACE
+CFLAGS = $(CFLAGS) /DCONFIG_CTRL_IFACE_NAMED_PIPE
+CFLAGS = $(CFLAGS) /DCONFIG_DRIVER_NDIS
+CFLAGS = $(CFLAGS) /I..\hostapd /I.
+CFLAGS = $(CFLAGS) /DWIN32
+CFLAGS = $(CFLAGS) /Fo$(OBJDIR)\\ /c
+CFLAGS = $(CFLAGS) /W3
+
+#CFLAGS = $(CFLAGS) /WX
+
+# VS 2005 complains about lot of deprecated string functions; let's ignore them
+# at least for now since snprintf and strncpy can be used in a safe way
+CFLAGS = $(CFLAGS) /D_CRT_SECURE_NO_DEPRECATE
+
+OBJS = \
+ $(OBJDIR)\os_win32.obj \
+ $(OBJDIR)\eloop_win.obj \
+ $(OBJDIR)\sha1.obj \
+ $(OBJDIR)\md5.obj \
+ $(OBJDIR)\rc4.obj \
+ $(OBJDIR)\aes_wrap.obj \
+ $(OBJDIR)\common.obj \
+ $(OBJDIR)\wpa_supplicant.obj \
+ $(OBJDIR)\wpa.obj \
+ $(OBJDIR)\preauth.obj \
+ $(OBJDIR)\pmksa_cache.obj \
+ $(OBJDIR)\eapol_sm.obj \
+ $(OBJDIR)\eap.obj \
+ $(OBJDIR)\eap_methods.obj \
+ $(OBJDIR)\eap_tlv.obj \
+ $(OBJDIR)\eap_md5.obj \
+ $(OBJDIR)\eap_tls.obj \
+ $(OBJDIR)\eap_tls_common.obj \
+ $(OBJDIR)\eap_mschapv2.obj \
+ $(OBJDIR)\eap_peap.obj \
+ $(OBJDIR)\eap_ttls.obj \
+ $(OBJDIR)\eap_gtc.obj \
+ $(OBJDIR)\eap_otp.obj \
+ $(OBJDIR)\eap_leap.obj \
+ $(OBJDIR)\eap_sim.obj \
+ $(OBJDIR)\eap_sim_common.obj \
+ $(OBJDIR)\eap_aka.obj \
+ $(OBJDIR)\eap_pax.obj \
+ $(OBJDIR)\eap_pax_common.obj \
+ $(OBJDIR)\eap_psk.obj \
+ $(OBJDIR)\eap_psk_common.obj \
+ $(OBJDIR)\ctrl_iface.obj \
+ $(OBJDIR)\ctrl_iface_named_pipe.obj \
+ $(OBJDIR)\driver_ndis.obj \
+ $(OBJDIR)\driver_ndis_.obj \
+ $(OBJDIR)\events.obj \
+ $(OBJDIR)\config.obj \
+ $(OBJDIR)\l2_packet_winpcap.obj \
+ $(OBJDIR)\tls_openssl.obj \
+ $(OBJDIR)\ms_funcs.obj \
+ $(OBJDIR)\crypto.obj \
+ $(OBJDIR)\pcsc_funcs.obj \
+ $(OBJDIR)\ndis_events.obj
+
+# OBJS = $(OBJS) $(OBJDIR)\eap_fast.obj
+
+OBJS_t = $(OBJS) \
+ $(OBJDIR)\eapol_test.obj \
+ $(OBJDIR)\radius.obj \
+ $(OBJDIR)\radius_client.obj \
+ $(OBJDIR)\config_file.obj $(OBJDIR)\base64.obj
+
+OBJS_t2 = $(OBJS) \
+ $(OBJDIR)\preauth_test.obj \
+ $(OBJDIR)\config_file.obj $(OBJDIR)\base64.obj
+
+OBJS2 = $(OBJDIR)\drivers.obj \
+ $(OBJDIR)\config_file.obj $(OBJDIR)\base64.obj \
+ $(OBJS2) $(OBJDIR)\main.obj
+
+OBJS3 = $(OBJDIR)\drivers.obj \
+ $(OBJDIR)\config_winreg.obj \
+ $(OBJS3) $(OBJDIR)\main_winsvc.obj
+
+OBJS_c = \
+ $(OBJDIR)\os_win32.obj \
+ $(OBJDIR)\wpa_cli.obj \
+ $(OBJDIR)\wpa_ctrl.obj \
+ $(OBJDIR)\common.obj
+
+OBJS_p = \
+ $(OBJDIR)\os_win32.obj \
+ $(OBJDIR)\common.obj \
+ $(OBJDIR)\sha1.obj \
+ $(OBJDIR)\md5.obj \
+ $(OBJDIR)\crypto.obj \
+ $(OBJDIR)\wpa_passphrase.obj
+
+LIBS = wbemuuid.lib libcmt.lib kernel32.lib uuid.lib ole32.lib oleaut32.lib \
+ ws2_32.lib Advapi32.lib Crypt32.lib Winscard.lib \
+ Packet.lib wpcap.lib \
+ libeay32.lib ssleay32.lib
+# If using Win32 OpenSSL binary installation from Shining Light Productions,
+# replace the last line with this for dynamic libraries
+# libeay32MT.lib ssleay32MT.lib
+# and this for static libraries
+# libeay32MT.lib ssleay32MT.lib Gdi32.lib User32.lib
+
+CFLAGS = $(CFLAGS) /I"$(WINPCAPDIR)/Include" /I"$(OPENSSLDIR)\include"
+LFLAGS = /libpath:"$(WINPCAPDIR)\Lib" /libpath:"$(OPENSSLDIR)\lib"
+
+wpa_supplicant.exe: $(OBJDIR) $(OBJS) $(OBJS2)
+ link.exe /out:wpa_supplicant.exe $(LFLAGS) $(OBJS) $(OBJS2) $(LIBS)
+
+wpasvc.exe: $(OBJDIR) $(OBJS) $(OBJS3)
+ link.exe /out:wpasvc.exe $(LFLAGS) $(OBJS) $(OBJS3) $(LIBS)
+
+wpa_cli.exe: $(OBJDIR) $(OBJS_c)
+ link.exe /out:wpa_cli.exe $(LFLAGS) $(OBJS_c) $(LIBS)
+
+wpa_passphrase.exe: $(OBJDIR) $(OBJS_p)
+ link.exe /out:wpa_passphrase.exe $(LFLAGS) $(OBJS_p) $(LIBS)
+
+eapol_test.exe: $(OBJDIR) $(OBJS_t)
+ link.exe /out:eapol_test.exe $(LFLAGS) $(OBJS_t) $(LIBS)
+
+preauth_test.exe: $(OBJDIR) $(OBJS_t2)
+ link.exe /out:preauth_test.exe $(LFLAGS) $(OBJS_t2) $(LIBS)
+
+win_if_list.exe: $(OBJDIR) $(OBJDIR)\win_if_list.obj
+ link.exe /out:win_if_list.exe $(LFLAGS) $(OBJDIR)\win_if_list.obj $(LIBS)
+
+
+{..\hostapd}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{.\}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{.\}.cpp{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+$(OBJDIR):
+ if not exist "$(OBJDIR)" mkdir "$(OBJDIR)"
+
+clean:
+ erase $(OBJDIR)\*.obj wpa_supplicant.exe
diff --git a/contrib/wpa_supplicant/openssl-0.9.8d-tls-extensions.patch b/contrib/wpa_supplicant/openssl-0.9.8d-tls-extensions.patch
new file mode 100644
index 000000000000..eec6db8a1341
--- /dev/null
+++ b/contrib/wpa_supplicant/openssl-0.9.8d-tls-extensions.patch
@@ -0,0 +1,429 @@
+This patch is adding support for TLS hello extensions and externally
+generated pre-shared key material to OpenSSL 0.9.8d. This is
+based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+
+
+diff -uprN openssl-0.9.8d.orig/include/openssl/ssl.h openssl-0.9.8d/include/openssl/ssl.h
+--- openssl-0.9.8d.orig/include/openssl/ssl.h 2006-06-14 06:52:49.000000000 -0700
++++ openssl-0.9.8d/include/openssl/ssl.h 2006-12-10 08:20:02.000000000 -0800
+@@ -345,6 +345,7 @@ extern "C" {
+ * 'struct ssl_st *' function parameters used to prototype callbacks
+ * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ {
+@@ -973,6 +976,15 @@ struct ssl_st
+ int first_packet;
+ int client_version; /* what was passed, used for
+ * SSLv3/TLS rollback check */
++
++ /* TLS externsions */
++ TLS_EXTENSION *tls_extension;
++ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
++ void *tls_extension_cb_arg;
++
++ /* TLS pre-shared secret session resumption */
++ tls_session_secret_cb_fn tls_session_secret_cb;
++ void *tls_session_secret_cb_arg;
+ };
+
+ #ifdef __cplusplus
+@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
+ #define SSL_F_WRITE_PENDING 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION 213
+
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE 100
+diff -uprN openssl-0.9.8d.orig/include/openssl/tls1.h openssl-0.9.8d/include/openssl/tls1.h
+--- openssl-0.9.8d.orig/include/openssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
++++ openssl-0.9.8d/include/openssl/tls1.h 2006-12-10 08:20:02.000000000 -0800
+@@ -296,6 +296,14 @@ extern "C" {
+ #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
+ #endif
+
++/* TLS extension struct */
++struct tls_extension_st
++{
++ unsigned short type;
++ unsigned short length;
++ void *data;
++};
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff -uprN openssl-0.9.8d.orig/ssl/Makefile openssl-0.9.8d/ssl/Makefile
+--- openssl-0.9.8d.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800
++++ openssl-0.9.8d/ssl/Makefile 2006-12-10 08:20:02.000000000 -0800
+@@ -24,7 +24,7 @@ LIBSRC= \
+ s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
+ s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
+ s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
+- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
++ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
+ d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
+ d1_both.c d1_enc.c \
+ ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
+@@ -35,7 +35,7 @@ LIBOBJ= \
+ s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
+ s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
+ s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
+- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
++ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
+ d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
+ d1_both.o d1_enc.o \
+ ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
+@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
+ t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
+ t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
+ t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
++t1_ext.o: t1_ext.c ssl_locl.h
+diff -uprN openssl-0.9.8d.orig/ssl/s3_clnt.c openssl-0.9.8d/ssl/s3_clnt.c
+--- openssl-0.9.8d.orig/ssl/s3_clnt.c 2005-12-12 23:41:46.000000000 -0800
++++ openssl-0.9.8d/ssl/s3_clnt.c 2006-12-10 08:20:02.000000000 -0800
+@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s)
+ #endif
+ *(p++)=0; /* Add the NULL method */
+
++ /* send client hello extensions if any */
++ if (s->version >= TLS1_VERSION && s->tls_extension)
++ {
++ // set the total extensions length
++ s2n(s->tls_extension->length + 4, p);
++
++ // put the extensions with type and length
++ s2n(s->tls_extension->type, p);
++ s2n(s->tls_extension->length, p);
++
++ memcpy(p, s->tls_extension->data, s->tls_extension->length);
++ p+=s->tls_extension->length;
++ }
++
+ l=(p-d);
+ d=buf;
+ *(d++)=SSL3_MT_CLIENT_HELLO;
+@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s)
+ STACK_OF(SSL_CIPHER) *sk;
+ SSL_CIPHER *c;
+ unsigned char *p,*d;
+- int i,al,ok;
++ int i,al,ok,pre_shared;
+ unsigned int j;
+ long n;
+ #ifndef OPENSSL_NO_COMP
+@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s)
+ goto f_err;
+ }
+
+- if (j != 0 && j == s->session->session_id_length
++ /* check if we want to resume the session based on external pre-shared secret */
++ pre_shared = 0;
++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++ {
++ SSL_CIPHER *pref_cipher=NULL;
++ s->session->master_key_length=sizeof(s->session->master_key);
++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++ {
++ s->hit=1;
++ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++ s->session->session_id_length = j;
++ memcpy(s->session->session_id, p, j);
++ pre_shared = 1;
++ }
++ }
++
++ if ((pre_shared || j != 0) && j == s->session->session_id_length
+ && memcmp(p,s->session->session_id,j) == 0)
+ {
+ if(s->sid_ctx_length != s->session->sid_ctx_length
+diff -uprN openssl-0.9.8d.orig/ssl/s3_srvr.c openssl-0.9.8d/ssl/s3_srvr.c
+--- openssl-0.9.8d.orig/ssl/s3_srvr.c 2006-09-28 04:29:03.000000000 -0700
++++ openssl-0.9.8d/ssl/s3_srvr.c 2006-12-10 08:20:02.000000000 -0800
+@@ -943,6 +943,75 @@ int ssl3_get_client_hello(SSL *s)
+ }
+ #endif
+
++ /* Check for TLS client hello extension here */
++ if (p < (d+n) && s->version >= TLS1_VERSION)
++ {
++ if (s->tls_extension_cb)
++ {
++ TLS_EXTENSION tls_ext;
++ unsigned short ext_total_len;
++
++ n2s(p, ext_total_len);
++ n2s(p, tls_ext.type);
++ n2s(p, tls_ext.length);
++
++ // sanity check in TLS extension len
++ if (tls_ext.length > (d+n) - p)
++ {
++ // just cut the lenth to packet border
++ tls_ext.length = (d+n) - p;
++ }
++
++ tls_ext.data = p;
++
++ // returns an alert code or 0
++ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
++ if (al != 0)
++ {
++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
++ goto f_err;
++ }
++ }
++ }
++
++ /* Check if we want to use external pre-shared secret for this handshake */
++ /* for not reused session only */
++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++ {
++ SSL_CIPHER *pref_cipher=NULL;
++
++ s->session->master_key_length=sizeof(s->session->master_key);
++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++ {
++ s->hit=1;
++ s->session->ciphers=ciphers;
++ s->session->verify_result=X509_V_OK;
++
++ ciphers=NULL;
++
++ /* check if some cipher was preferred by call back */
++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++ if (pref_cipher == NULL)
++ {
++ al=SSL_AD_HANDSHAKE_FAILURE;
++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++ goto f_err;
++ }
++
++ s->session->cipher=pref_cipher;
++
++ if (s->cipher_list)
++ sk_SSL_CIPHER_free(s->cipher_list);
++
++ if (s->cipher_list_by_id)
++ sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++ }
++ }
++
+ /* Given s->session->ciphers and SSL_get_ciphers, we must
+ * pick a cipher */
+
+diff -uprN openssl-0.9.8d.orig/ssl/ssl.h openssl-0.9.8d/ssl/ssl.h
+--- openssl-0.9.8d.orig/ssl/ssl.h 2006-06-14 06:52:49.000000000 -0700
++++ openssl-0.9.8d/ssl/ssl.h 2006-12-10 08:20:02.000000000 -0800
+@@ -345,6 +345,7 @@ extern "C" {
+ * 'struct ssl_st *' function parameters used to prototype callbacks
+ * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ {
+@@ -973,6 +976,15 @@ struct ssl_st
+ int first_packet;
+ int client_version; /* what was passed, used for
+ * SSLv3/TLS rollback check */
++
++ /* TLS externsions */
++ TLS_EXTENSION *tls_extension;
++ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
++ void *tls_extension_cb_arg;
++
++ /* TLS pre-shared secret session resumption */
++ tls_session_secret_cb_fn tls_session_secret_cb;
++ void *tls_session_secret_cb_arg;
+ };
+
+ #ifdef __cplusplus
+@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
+ #define SSL_F_WRITE_PENDING 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION 213
+
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE 100
+diff -uprN openssl-0.9.8d.orig/ssl/ssl_err.c openssl-0.9.8d/ssl/ssl_err.c
+--- openssl-0.9.8d.orig/ssl/ssl_err.c 2006-01-08 13:52:46.000000000 -0800
++++ openssl-0.9.8d/ssl/ssl_err.c 2006-12-10 08:20:02.000000000 -0800
+@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ };
+
+diff -uprN openssl-0.9.8d.orig/ssl/ssl_sess.c openssl-0.9.8d/ssl/ssl_sess.c
+--- openssl-0.9.8d.orig/ssl/ssl_sess.c 2005-12-30 15:51:57.000000000 -0800
++++ openssl-0.9.8d/ssl/ssl_sess.c 2006-12-10 08:20:02.000000000 -0800
+@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ return(s->session_timeout);
+ }
+
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++ if (s == NULL) return(0);
++ s->tls_session_secret_cb = tls_session_secret_cb;
++ s->tls_session_secret_cb_arg = arg;
++ return(1);
++}
++
+ typedef struct timeout_param_st
+ {
+ SSL_CTX *ctx;
+diff -uprN openssl-0.9.8d.orig/ssl/t1_ext.c openssl-0.9.8d/ssl/t1_ext.c
+--- openssl-0.9.8d.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
++++ openssl-0.9.8d/ssl/t1_ext.c 2006-12-10 08:20:02.000000000 -0800
+@@ -0,0 +1,48 @@
++
++#include <stdio.h>
++#include "ssl_locl.h"
++
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++ if(s->version >= TLS1_VERSION)
++ {
++ if(s->tls_extension)
++ {
++ OPENSSL_free(s->tls_extension);
++ s->tls_extension = NULL;
++ }
++
++ if(ext_data)
++ {
++ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++ if(!s->tls_extension)
++ {
++ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++ return 0;
++ }
++
++ s->tls_extension->type = ext_type;
++ s->tls_extension->length = ext_len;
++ s->tls_extension->data = s->tls_extension + 1;
++ memcpy(s->tls_extension->data, ext_data, ext_len);
++ }
++
++ return 1;
++ }
++
++ return 0;
++}
++
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
++{
++ if(s->version >= TLS1_VERSION)
++ {
++ s->tls_extension_cb = cb;
++ s->tls_extension_cb_arg = arg;
++
++ return 1;
++ }
++
++ return 0;
++}
+diff -uprN openssl-0.9.8d.orig/ssl/t1_lib.c openssl-0.9.8d/ssl/t1_lib.c
+--- openssl-0.9.8d.orig/ssl/t1_lib.c 2005-08-05 16:52:07.000000000 -0700
++++ openssl-0.9.8d/ssl/t1_lib.c 2006-12-10 08:20:02.000000000 -0800
+@@ -97,6 +97,10 @@ int tls1_new(SSL *s)
+
+ void tls1_free(SSL *s)
+ {
++ if(s->tls_extension)
++ {
++ OPENSSL_free(s->tls_extension);
++ }
+ ssl3_free(s);
+ }
+
+diff -uprN openssl-0.9.8d.orig/ssl/tls1.h openssl-0.9.8d/ssl/tls1.h
+--- openssl-0.9.8d.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
++++ openssl-0.9.8d/ssl/tls1.h 2006-12-10 08:20:02.000000000 -0800
+@@ -296,6 +296,14 @@ extern "C" {
+ #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
+ #endif
+
++/* TLS extension struct */
++struct tls_extension_st
++{
++ unsigned short type;
++ unsigned short length;
++ void *data;
++};
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff -uprN openssl-0.9.8d.orig/util/ssleay.num openssl-0.9.8d/util/ssleay.num
+--- openssl-0.9.8d.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700
++++ openssl-0.9.8d/util/ssleay.num 2006-12-10 08:20:02.000000000 -0800
+@@ -226,3 +226,6 @@ DTLSv1_server_method
+ SSL_COMP_get_compression_methods 276 EXIST:!VMS:FUNCTION:COMP
+ SSL_COMP_get_compress_methods 276 EXIST:VMS:FUNCTION:COMP
+ SSL_SESSION_get_id 277 EXIST::FUNCTION:
++SSL_set_hello_extension 278 EXIST::FUNCTION:
++SSL_set_hello_extension_cb 279 EXIST::FUNCTION:
++SSL_set_session_secret_cb 280 EXIST::FUNCTION:
diff --git a/contrib/wpa_supplicant/openssl-0.9.8e-tls-extensions.patch b/contrib/wpa_supplicant/openssl-0.9.8e-tls-extensions.patch
new file mode 100644
index 000000000000..ede053f779b6
--- /dev/null
+++ b/contrib/wpa_supplicant/openssl-0.9.8e-tls-extensions.patch
@@ -0,0 +1,353 @@
+This patch is adding support for TLS hello extensions and externally
+generated pre-shared key material to OpenSSL 0.9.8e. This is
+based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+
+
+diff -uprN openssl-0.9.8e.orig/ssl/Makefile openssl-0.9.8e/ssl/Makefile
+--- openssl-0.9.8e.orig/ssl/Makefile 2006-02-03 17:49:35.000000000 -0800
++++ openssl-0.9.8e/ssl/Makefile 2007-03-22 20:23:19.000000000 -0700
+@@ -24,7 +24,7 @@ LIBSRC= \
+ s2_meth.c s2_srvr.c s2_clnt.c s2_lib.c s2_enc.c s2_pkt.c \
+ s3_meth.c s3_srvr.c s3_clnt.c s3_lib.c s3_enc.c s3_pkt.c s3_both.c \
+ s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c s23_pkt.c \
+- t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c \
++ t1_meth.c t1_srvr.c t1_clnt.c t1_lib.c t1_enc.c t1_ext.c \
+ d1_meth.c d1_srvr.c d1_clnt.c d1_lib.c d1_pkt.c \
+ d1_both.c d1_enc.c \
+ ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
+@@ -35,7 +35,7 @@ LIBOBJ= \
+ s2_meth.o s2_srvr.o s2_clnt.o s2_lib.o s2_enc.o s2_pkt.o \
+ s3_meth.o s3_srvr.o s3_clnt.o s3_lib.o s3_enc.o s3_pkt.o s3_both.o \
+ s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o s23_pkt.o \
+- t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o \
++ t1_meth.o t1_srvr.o t1_clnt.o t1_lib.o t1_enc.o t1_ext.o \
+ d1_meth.o d1_srvr.o d1_clnt.o d1_lib.o d1_pkt.o \
+ d1_both.o d1_enc.o \
+ ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
+@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
+ t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
+ t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
+ t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
++t1_ext.o: t1_ext.c ssl_locl.h
+diff -uprN openssl-0.9.8e.orig/ssl/s3_clnt.c openssl-0.9.8e/ssl/s3_clnt.c
+--- openssl-0.9.8e.orig/ssl/s3_clnt.c 2006-09-28 05:23:15.000000000 -0700
++++ openssl-0.9.8e/ssl/s3_clnt.c 2007-03-22 20:23:19.000000000 -0700
+@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s)
+ #endif
+ *(p++)=0; /* Add the NULL method */
+
++ /* send client hello extensions if any */
++ if (s->version >= TLS1_VERSION && s->tls_extension)
++ {
++ // set the total extensions length
++ s2n(s->tls_extension->length + 4, p);
++
++ // put the extensions with type and length
++ s2n(s->tls_extension->type, p);
++ s2n(s->tls_extension->length, p);
++
++ memcpy(p, s->tls_extension->data, s->tls_extension->length);
++ p+=s->tls_extension->length;
++ }
++
+ l=(p-d);
+ d=buf;
+ *(d++)=SSL3_MT_CLIENT_HELLO;
+@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s)
+ STACK_OF(SSL_CIPHER) *sk;
+ SSL_CIPHER *c;
+ unsigned char *p,*d;
+- int i,al,ok;
++ int i,al,ok,pre_shared;
+ unsigned int j;
+ long n;
+ #ifndef OPENSSL_NO_COMP
+@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s)
+ goto f_err;
+ }
+
+- if (j != 0 && j == s->session->session_id_length
++ /* check if we want to resume the session based on external pre-shared secret */
++ pre_shared = 0;
++ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++ {
++ SSL_CIPHER *pref_cipher=NULL;
++ s->session->master_key_length=sizeof(s->session->master_key);
++ if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++ NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++ {
++ s->hit=1;
++ s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++ s->session->session_id_length = j;
++ memcpy(s->session->session_id, p, j);
++ pre_shared = 1;
++ }
++ }
++
++ if ((pre_shared || j != 0) && j == s->session->session_id_length
+ && memcmp(p,s->session->session_id,j) == 0)
+ {
+ if(s->sid_ctx_length != s->session->sid_ctx_length
+diff -uprN openssl-0.9.8e.orig/ssl/s3_srvr.c openssl-0.9.8e/ssl/s3_srvr.c
+--- openssl-0.9.8e.orig/ssl/s3_srvr.c 2007-02-07 12:36:40.000000000 -0800
++++ openssl-0.9.8e/ssl/s3_srvr.c 2007-03-22 20:23:19.000000000 -0700
+@@ -945,6 +945,75 @@ int ssl3_get_client_hello(SSL *s)
+ }
+ #endif
+
++ /* Check for TLS client hello extension here */
++ if (p < (d+n) && s->version >= TLS1_VERSION)
++ {
++ if (s->tls_extension_cb)
++ {
++ TLS_EXTENSION tls_ext;
++ unsigned short ext_total_len;
++
++ n2s(p, ext_total_len);
++ n2s(p, tls_ext.type);
++ n2s(p, tls_ext.length);
++
++ // sanity check in TLS extension len
++ if (tls_ext.length > (d+n) - p)
++ {
++ // just cut the lenth to packet border
++ tls_ext.length = (d+n) - p;
++ }
++
++ tls_ext.data = p;
++
++ // returns an alert code or 0
++ al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
++ if (al != 0)
++ {
++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
++ goto f_err;
++ }
++ }
++ }
++
++ /* Check if we want to use external pre-shared secret for this handshake */
++ /* for not reused session only */
++ if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++ {
++ SSL_CIPHER *pref_cipher=NULL;
++
++ s->session->master_key_length=sizeof(s->session->master_key);
++ if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++ ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++ {
++ s->hit=1;
++ s->session->ciphers=ciphers;
++ s->session->verify_result=X509_V_OK;
++
++ ciphers=NULL;
++
++ /* check if some cipher was preferred by call back */
++ pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++ if (pref_cipher == NULL)
++ {
++ al=SSL_AD_HANDSHAKE_FAILURE;
++ SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++ goto f_err;
++ }
++
++ s->session->cipher=pref_cipher;
++
++ if (s->cipher_list)
++ sk_SSL_CIPHER_free(s->cipher_list);
++
++ if (s->cipher_list_by_id)
++ sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++ s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++ s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++ }
++ }
++
+ /* Given s->session->ciphers and SSL_get_ciphers, we must
+ * pick a cipher */
+
+diff -uprN openssl-0.9.8e.orig/ssl/ssl.h openssl-0.9.8e/ssl/ssl.h
+--- openssl-0.9.8e.orig/ssl/ssl.h 2007-02-19 09:55:07.000000000 -0800
++++ openssl-0.9.8e/ssl/ssl.h 2007-03-22 20:23:19.000000000 -0700
+@@ -345,6 +345,7 @@ extern "C" {
+ * 'struct ssl_st *' function parameters used to prototype callbacks
+ * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ {
+@@ -973,6 +976,15 @@ struct ssl_st
+ int first_packet;
+ int client_version; /* what was passed, used for
+ * SSLv3/TLS rollback check */
++
++ /* TLS externsions */
++ TLS_EXTENSION *tls_extension;
++ int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
++ void *tls_extension_cb_arg;
++
++ /* TLS pre-shared secret session resumption */
++ tls_session_secret_cb_fn tls_session_secret_cb;
++ void *tls_session_secret_cb_arg;
+ };
+
+ #ifdef __cplusplus
+@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+ * made after this point may be overwritten when the script is next run.
+@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK 211
+ #define SSL_F_WRITE_PENDING 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION 213
+
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE 100
+diff -uprN openssl-0.9.8e.orig/ssl/ssl_err.c openssl-0.9.8e/ssl/ssl_err.c
+--- openssl-0.9.8e.orig/ssl/ssl_err.c 2006-11-21 12:14:46.000000000 -0800
++++ openssl-0.9.8e/ssl/ssl_err.c 2007-03-22 20:23:19.000000000 -0700
+@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC), "TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK), "TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING), "WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ };
+
+diff -uprN openssl-0.9.8e.orig/ssl/ssl_sess.c openssl-0.9.8e/ssl/ssl_sess.c
+--- openssl-0.9.8e.orig/ssl/ssl_sess.c 2007-02-10 02:40:24.000000000 -0800
++++ openssl-0.9.8e/ssl/ssl_sess.c 2007-03-22 20:23:19.000000000 -0700
+@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ return(s->session_timeout);
+ }
+
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++ STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++ if (s == NULL) return(0);
++ s->tls_session_secret_cb = tls_session_secret_cb;
++ s->tls_session_secret_cb_arg = arg;
++ return(1);
++}
++
+ typedef struct timeout_param_st
+ {
+ SSL_CTX *ctx;
+diff -uprN openssl-0.9.8e.orig/ssl/t1_ext.c openssl-0.9.8e/ssl/t1_ext.c
+--- openssl-0.9.8e.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
++++ openssl-0.9.8e/ssl/t1_ext.c 2007-03-22 20:23:19.000000000 -0700
+@@ -0,0 +1,48 @@
++
++#include <stdio.h>
++#include "ssl_locl.h"
++
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++ if(s->version >= TLS1_VERSION)
++ {
++ if(s->tls_extension)
++ {
++ OPENSSL_free(s->tls_extension);
++ s->tls_extension = NULL;
++ }
++
++ if(ext_data)
++ {
++ s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++ if(!s->tls_extension)
++ {
++ SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++ return 0;
++ }
++
++ s->tls_extension->type = ext_type;
++ s->tls_extension->length = ext_len;
++ s->tls_extension->data = s->tls_extension + 1;
++ memcpy(s->tls_extension->data, ext_data, ext_len);
++ }
++
++ return 1;
++ }
++
++ return 0;
++}
++
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
++{
++ if(s->version >= TLS1_VERSION)
++ {
++ s->tls_extension_cb = cb;
++ s->tls_extension_cb_arg = arg;
++
++ return 1;
++ }
++
++ return 0;
++}
+diff -uprN openssl-0.9.8e.orig/ssl/t1_lib.c openssl-0.9.8e/ssl/t1_lib.c
+--- openssl-0.9.8e.orig/ssl/t1_lib.c 2007-01-21 08:07:25.000000000 -0800
++++ openssl-0.9.8e/ssl/t1_lib.c 2007-03-22 20:23:19.000000000 -0700
+@@ -97,6 +97,10 @@ int tls1_new(SSL *s)
+
+ void tls1_free(SSL *s)
+ {
++ if(s->tls_extension)
++ {
++ OPENSSL_free(s->tls_extension);
++ }
+ ssl3_free(s);
+ }
+
+diff -uprN openssl-0.9.8e.orig/ssl/tls1.h openssl-0.9.8e/ssl/tls1.h
+--- openssl-0.9.8e.orig/ssl/tls1.h 2006-06-14 10:52:01.000000000 -0700
++++ openssl-0.9.8e/ssl/tls1.h 2007-03-22 20:23:19.000000000 -0700
+@@ -296,6 +296,14 @@ extern "C" {
+ #define TLS_MD_MASTER_SECRET_CONST "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74" /*master secret*/
+ #endif
+
++/* TLS extension struct */
++struct tls_extension_st
++{
++ unsigned short type;
++ unsigned short length;
++ void *data;
++};
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff -uprN openssl-0.9.8e.orig/util/ssleay.num openssl-0.9.8e/util/ssleay.num
+--- openssl-0.9.8e.orig/util/ssleay.num 2006-11-30 05:04:43.000000000 -0800
++++ openssl-0.9.8e/util/ssleay.num 2007-03-22 20:24:07.000000000 -0700
+@@ -238,3 +238,6 @@ SSL_CTX_set_info_callback
+ SSL_CTX_sess_get_new_cb 287 EXIST::FUNCTION:
+ SSL_CTX_get_client_cert_cb 288 EXIST::FUNCTION:
+ SSL_CTX_sess_get_remove_cb 289 EXIST::FUNCTION:
++SSL_set_hello_extension 290 EXIST::FUNCTION:
++SSL_set_hello_extension_cb 291 EXIST::FUNCTION:
++SSL_set_session_secret_cb 292 EXIST::FUNCTION:
diff --git a/contrib/wpa_supplicant/os.h b/contrib/wpa_supplicant/os.h
new file mode 100644
index 000000000000..4931adb2b8c2
--- /dev/null
+++ b/contrib/wpa_supplicant/os.h
@@ -0,0 +1,485 @@
+/*
+ * wpa_supplicant/hostapd / OS specific functions
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef OS_H
+#define OS_H
+
+typedef long os_time_t;
+
+/**
+ * os_sleep - Sleep (sec, usec)
+ * @sec: Number of seconds to sleep
+ * @usec: Number of microseconds to sleep
+ */
+void os_sleep(os_time_t sec, os_time_t usec);
+
+struct os_time {
+ os_time_t sec;
+ os_time_t usec;
+};
+
+/**
+ * os_get_time - Get current time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_time(struct os_time *t);
+
+
+/* Helper macros for handling struct os_time */
+
+#define os_time_before(a, b) \
+ ((a)->sec < (b)->sec || \
+ ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+
+#define os_time_sub(a, b, res) do { \
+ (res)->sec = (a)->sec - (b)->sec; \
+ (res)->usec = (a)->usec - (b)->usec; \
+ if ((res)->usec < 0) { \
+ (res)->sec--; \
+ (res)->usec += 1000000; \
+ } \
+} while (0)
+
+/**
+ * os_mktime - Convert broken-down time into seconds since 1970-01-01
+ * @year: Four digit year
+ * @month: Month (1 .. 12)
+ * @day: Day of month (1 .. 31)
+ * @hour: Hour (0 .. 23)
+ * @min: Minute (0 .. 59)
+ * @sec: Second (0 .. 60)
+ * @t: Buffer for returning calendar time representation (seconds since
+ * 1970-01-01 00:00:00)
+ * Returns: 0 on success, -1 on failure
+ */
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t);
+
+
+/**
+ * os_daemonize - Run in the background (detach from the controlling terminal)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ * Returns: 0 on success, -1 on failure
+ */
+int os_daemonize(const char *pid_file);
+
+/**
+ * os_daemonize_terminate - Stop running in the background (remove pid file)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ */
+void os_daemonize_terminate(const char *pid_file);
+
+/**
+ * os_get_random - Get cryptographically strong pseudo random data
+ * @buf: Buffer for pseudo random data
+ * @len: Length of the buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_random(unsigned char *buf, size_t len);
+
+/**
+ * os_random - Get pseudo random value (not necessarily very strong)
+ * Returns: Pseudo random value
+ */
+unsigned long os_random(void);
+
+/**
+ * os_rel2abs_path - Get an absolute path for a file
+ * @rel_path: Relative path to a file
+ * Returns: Absolute path for the file or %NULL on failure
+ *
+ * This function tries to convert a relative path of a file to an absolute path
+ * in order for the file to be found even if current working directory has
+ * changed. The returned value is allocated and caller is responsible for
+ * freeing it. It is acceptable to just return the same path in an allocated
+ * buffer, e.g., return strdup(rel_path). This function is only used to find
+ * configuration files when os_daemonize() may have changed the current working
+ * directory and relative path would be pointing to a different location.
+ */
+char * os_rel2abs_path(const char *rel_path);
+
+/**
+ * os_program_init - Program initialization (called at start)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when a programs starts. If there are any OS specific
+ * processing that is needed, it can be placed here. It is also acceptable to
+ * just return 0 if not special processing is needed.
+ */
+int os_program_init(void);
+
+/**
+ * os_program_deinit - Program deinitialization (called just before exit)
+ *
+ * This function is called just before a program exists. If there are any OS
+ * specific processing, e.g., freeing resourced allocated in os_program_init(),
+ * it should be done here. It is also acceptable for this function to do
+ * nothing.
+ */
+void os_program_deinit(void);
+
+/**
+ * os_setenv - Set environment variable
+ * @name: Name of the variable
+ * @value: Value to set to the variable
+ * @overwrite: Whether existing variable should be overwritten
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_setenv(const char *name, const char *value, int overwrite);
+
+/**
+ * os_unsetenv - Delete environent variable
+ * @name: Name of the variable
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_unsetenv(const char *name);
+
+/**
+ * os_readfile - Read a file to an allocated memory buffer
+ * @name: Name of the file to read
+ * @len: For returning the length of the allocated buffer
+ * Returns: Pointer to the allocated buffer or %NULL on failure
+ *
+ * This function allocates memory and reads the given file to this buffer. Both
+ * binary and text files can be read with this function. The caller is
+ * responsible for freeing the returned buffer with os_free().
+ */
+char * os_readfile(const char *name, size_t *len);
+
+/**
+ * os_zalloc - Allocate and zero memory
+ * @size: Number of bytes to allocate
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_zalloc(size_t size);
+
+
+/*
+ * The following functions are wrapper for standard ANSI C or POSIX functions.
+ * By default, they are just defined to use the standard function name and no
+ * os_*.c implementation is needed for them. This avoids extra function calls
+ * by allowing the C pre-processor take care of the function name mapping.
+ *
+ * If the target system uses a C library that does not provide these functions,
+ * build_config.h can be used to define the wrappers to use a different
+ * function name. This can be done on function-by-function basis since the
+ * defines here are only used if build_config.h does not define the os_* name.
+ * If needed, os_*.c file can be used to implement the functions that are not
+ * included in the C library on the target system. Alternatively,
+ * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case
+ * these functions need to be implemented in os_*.c file for the target system.
+ */
+
+#ifdef OS_NO_C_LIB_DEFINES
+
+/**
+ * os_malloc - Allocate dynamic memory
+ * @size: Size of the buffer to allocate
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_malloc(size_t size);
+
+/**
+ * os_realloc - Re-allocate dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc()
+ * @size: Size of the new buffer
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ * If re-allocation fails, %NULL is returned and the original buffer (ptr) is
+ * not freed and caller is still responsible for freeing it.
+ */
+void * os_realloc(void *ptr, size_t size);
+
+/**
+ * os_free - Free dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL
+ */
+void os_free(void *ptr);
+
+/**
+ * os_memcpy - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst must not overlap. os_memmove() can be used with
+ * overlapping memory.
+ */
+void * os_memcpy(void *dest, const void *src, size_t n);
+
+/**
+ * os_memmove - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst may overlap.
+ */
+void * os_memmove(void *dest, const void *src, size_t n);
+
+/**
+ * os_memset - Fill memory with a constant byte
+ * @s: Memory area to be filled
+ * @c: Constant byte
+ * @n: Number of bytes started from s to fill with c
+ * Returns: s
+ */
+void * os_memset(void *s, int c, size_t n);
+
+/**
+ * os_memcmp - Compare memory areas
+ * @s1: First buffer
+ * @s2: Second buffer
+ * @n: Maximum numbers of octets to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_memcmp(const void *s1, const void *s2, size_t n);
+
+/**
+ * os_strdup - Duplicate a string
+ * @s: Source string
+ * Returns: Allocated buffer with the string copied into it or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+char * os_strdup(const char *s);
+
+/**
+ * os_strlen - Calculate the length of a string
+ * @s: '\0' terminated string
+ * Returns: Number of characters in s (not counting the '\0' terminator)
+ */
+size_t os_strlen(const char *s);
+
+/**
+ * os_strcasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcasecmp(const char *s1, const char *s2);
+
+/**
+ * os_strncasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncasecmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strchr - Locate the first occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strchr(const char *s, int c);
+
+/**
+ * os_strrchr - Locate the last occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strrchr(const char *s, int c);
+
+/**
+ * os_strcmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcmp(const char *s1, const char *s2);
+
+/**
+ * os_strncmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strncpy - Copy a string
+ * @dest: Destination
+ * @src: Source
+ * @n: Maximum number of characters to copy
+ * Returns: dest
+ */
+char * os_strncpy(char *dest, const char *src, size_t n);
+
+/**
+ * os_strstr - Locate a substring
+ * @haystack: String (haystack) to search from
+ * @needle: Needle to search from haystack
+ * Returns: Pointer to the beginning of the substring or %NULL if not found
+ */
+char * os_strstr(const char *haystack, const char *needle);
+
+/**
+ * os_snprintf - Print to a memory buffer
+ * @str: Memory buffer to print into
+ * @size: Maximum length of the str buffer
+ * @format: printf format
+ * Returns: Number of characters printed (not including trailing '\0').
+ *
+ * If the output buffer is truncated, number of characters which would have
+ * been written is returned. Since some C libraries return -1 in such a case,
+ * the caller must be prepared on that value, too, to indicate truncation.
+ *
+ * Note: Some C library implementations of snprintf() may not guarantee null
+ * termination in case the output is truncated. The OS wrapper function of
+ * os_snprintf() should provide this guarantee, i.e., to null terminate the
+ * output buffer if a C library version of the function is used and if that
+ * function does not guarantee null termination.
+ *
+ * If the target system does not include snprintf(), see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for an example of a portable
+ * implementation of snprintf.
+ */
+int os_snprintf(char *str, size_t size, const char *format, ...);
+
+#else /* OS_NO_C_LIB_DEFINES */
+
+#ifndef os_malloc
+#define os_malloc(s) malloc((s))
+#endif
+#ifndef os_realloc
+#define os_realloc(p, s) realloc((p), (s))
+#endif
+#ifndef os_free
+#define os_free(p) free((p))
+#endif
+
+#ifndef os_memcpy
+#define os_memcpy(d, s, n) memcpy((d), (s), (n))
+#endif
+#ifndef os_memmove
+#define os_memmove(d, s, n) memmove((d), (s), (n))
+#endif
+#ifndef os_memset
+#define os_memset(s, c, n) memset(s, c, n)
+#endif
+#ifndef os_memcmp
+#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+
+#ifndef os_strdup
+#ifdef _MSC_VER
+#define os_strdup(s) _strdup(s)
+#else
+#define os_strdup(s) strdup(s)
+#endif
+#endif
+#ifndef os_strlen
+#define os_strlen(s) strlen(s)
+#endif
+#ifndef os_strcasecmp
+#ifdef _MSC_VER
+#define os_strcasecmp(s1, s2) _stricmp((s1), (s2))
+#else
+#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2))
+#endif
+#endif
+#ifndef os_strncasecmp
+#ifdef _MSC_VER
+#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n))
+#else
+#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
+#endif
+#endif
+#ifndef os_strchr
+#define os_strchr(s, c) strchr((s), (c))
+#endif
+#ifndef os_strcmp
+#define os_strcmp(s1, s2) strcmp((s1), (s2))
+#endif
+#ifndef os_strncmp
+#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
+#endif
+#ifndef os_strncpy
+#define os_strncpy(d, s, n) strncpy((d), (s), (n))
+#endif
+#ifndef os_strrchr
+#define os_strrchr(s, c) strrchr((s), (c))
+#endif
+#ifndef os_strstr
+#define os_strstr(h, n) strstr((h), (n))
+#endif
+
+#ifndef os_snprintf
+#ifdef _MSC_VER
+#define os_snprintf _snprintf
+#else
+#define os_snprintf snprintf
+#endif
+#endif
+
+#endif /* OS_NO_C_LIB_DEFINES */
+
+
+#ifdef OS_REJECT_C_LIB_FUNCTIONS
+#define malloc OS_DO_NOT_USE_malloc
+#define realloc OS_DO_NOT_USE_realloc
+#define free OS_DO_NOT_USE_free
+#define memcpy OS_DO_NOT_USE_memcpy
+#define memmove OS_DO_NOT_USE_memmove
+#define memset OS_DO_NOT_USE_memset
+#define memcmp OS_DO_NOT_USE_memcmp
+#undef strdup
+#define strdup OS_DO_NOT_USE_strdup
+#define strlen OS_DO_NOT_USE_strlen
+#define strcasecmp OS_DO_NOT_USE_strcasecmp
+#define strncasecmp OS_DO_NOT_USE_strncasecmp
+#undef strchr
+#define strchr OS_DO_NOT_USE_strchr
+#undef strcmp
+#define strcmp OS_DO_NOT_USE_strcmp
+#undef strncmp
+#define strncmp OS_DO_NOT_USE_strncmp
+#undef strncpy
+#define strncpy OS_DO_NOT_USE_strncpy
+#define strrchr OS_DO_NOT_USE_strrchr
+#define strstr OS_DO_NOT_USE_strstr
+#undef snprintf
+#define snprintf OS_DO_NOT_USE_snprintf
+
+#define strcpy OS_DO_NOT_USE_strcpy
+#endif /* OS_REJECT_C_LIB_FUNCTIONS */
+
+#endif /* OS_H */
diff --git a/contrib/wpa_supplicant/os_internal.c b/contrib/wpa_supplicant/os_internal.c
new file mode 100644
index 000000000000..b2183ea38f4d
--- /dev/null
+++ b/contrib/wpa_supplicant/os_internal.c
@@ -0,0 +1,441 @@
+/*
+ * wpa_supplicant/hostapd / Internal implementation of OS specific functions
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file is an example of operating system specific wrapper functions.
+ * This version implements many of the functions internally, so it can be used
+ * to fill in missing functions from the target system C libraries.
+ *
+ * Some of the functions are using standard C library calls in order to keep
+ * this file in working condition to allow the functions to be tested on a
+ * Linux target. Please note that OS_NO_C_LIB_DEFINES needs to be defined for
+ * this file to work correctly. Note that these implementations are only
+ * examples and are not optimized for speed.
+ */
+
+#include "includes.h"
+
+#undef OS_REJECT_C_LIB_FUNCTIONS
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+ if (sec)
+ sleep(sec);
+ if (usec)
+ usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+ int res;
+ struct timeval tv;
+ res = gettimeofday(&tv, NULL);
+ t->sec = tv.tv_sec;
+ t->usec = tv.tv_usec;
+ return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t)
+{
+ struct tm tm;
+
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+ sec > 60)
+ return -1;
+
+ os_memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ *t = (os_time_t) mktime(&tm);
+ return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+ if (daemon(0, 0)) {
+ perror("daemon");
+ return -1;
+ }
+
+ if (pid_file) {
+ FILE *f = fopen(pid_file, "w");
+ if (f) {
+ fprintf(f, "%u\n", getpid());
+ fclose(f);
+ }
+ }
+
+ return -0;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+ if (pid_file)
+ unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ FILE *f;
+ size_t rc;
+
+ f = fopen("/dev/urandom", "rb");
+ if (f == NULL) {
+ printf("Could not open /dev/urandom.\n");
+ return -1;
+ }
+
+ rc = fread(buf, 1, len, f);
+ fclose(f);
+
+ return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+ return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+ char *buf = NULL, *cwd, *ret;
+ size_t len = 128, cwd_len, rel_len, ret_len;
+
+ if (rel_path[0] == '/')
+ return os_strdup(rel_path);
+
+ for (;;) {
+ buf = os_malloc(len);
+ if (buf == NULL)
+ return NULL;
+ cwd = getcwd(buf, len);
+ if (cwd == NULL) {
+ os_free(buf);
+ if (errno != ERANGE) {
+ return NULL;
+ }
+ len *= 2;
+ } else {
+ break;
+ }
+ }
+
+ cwd_len = strlen(cwd);
+ rel_len = strlen(rel_path);
+ ret_len = cwd_len + 1 + rel_len + 1;
+ ret = os_malloc(ret_len);
+ if (ret) {
+ os_memcpy(ret, cwd, cwd_len);
+ ret[cwd_len] = '/';
+ os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+ ret[ret_len - 1] = '\0';
+ }
+ os_free(buf);
+ return ret;
+}
+
+
+int os_program_init(void)
+{
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+ unsetenv(name);
+ return 0;
+#else
+ return unsetenv(name);
+#endif
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ FILE *f;
+ char *buf;
+
+ f = fopen(name, "rb");
+ if (f == NULL)
+ return NULL;
+
+ fseek(f, 0, SEEK_END);
+ *len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ buf = os_malloc(*len);
+ if (buf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ fread(buf, 1, *len, f);
+ fclose(f);
+
+ return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+ void *n = os_malloc(size);
+ if (n)
+ os_memset(n, 0, size);
+ return n;
+}
+
+
+void * os_malloc(size_t size)
+{
+ return malloc(size);
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+ return realloc(ptr, size);
+}
+
+
+void os_free(void *ptr)
+{
+ free(ptr);
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+ char *d = dest;
+ const char *s = src;
+ while (n--)
+ *d++ = *s++;
+ return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+ if (dest < src)
+ os_memcpy(dest, src, n);
+ else {
+ /* overlapping areas */
+ char *d = (char *) dest + n;
+ const char *s = (const char *) src + n;
+ while (n--)
+ *--d = *--s;
+ }
+ return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+ char *p = s;
+ while (n--)
+ *p++ = c;
+ return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+ const unsigned char *p1 = s1, *p2 = s2;
+
+ if (n == 0)
+ return 0;
+
+ while (*p1 == *p2) {
+ p1++;
+ p2++;
+ n--;
+ if (n == 0)
+ return 0;
+ }
+
+ return *p1 - *p2;
+}
+
+
+char * os_strdup(const char *s)
+{
+ char *res;
+ size_t len;
+ if (s == NULL)
+ return NULL;
+ len = os_strlen(s);
+ res = os_malloc(len + 1);
+ if (res)
+ os_memcpy(res, s, len + 1);
+ return res;
+}
+
+
+size_t os_strlen(const char *s)
+{
+ const char *p = s;
+ while (*p)
+ p++;
+ return p - s;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+ while (*s) {
+ if (*s == c)
+ return (char *) s;
+ s++;
+ }
+ return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+ const char *p = s;
+ while (*p)
+ p++;
+ p--;
+ while (p >= s) {
+ if (*p == c)
+ return (char *) p;
+ p--;
+ }
+ return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+ while (*s1 == *s2) {
+ if (*s1 == '\0')
+ break;
+ s1++;
+ s2++;
+ }
+
+ return *s1 - *s2;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+ if (n == 0)
+ return 0;
+
+ while (*s1 == *s2) {
+ if (*s1 == '\0')
+ break;
+ s1++;
+ s2++;
+ n--;
+ if (n == 0)
+ return 0;
+ }
+
+ return *s1 - *s2;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+ char *d = dest;
+
+ while (n--) {
+ *d = *src;
+ if (*src == '\0')
+ break;
+ d++;
+ src++;
+ }
+
+ return dest;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+ size_t len = os_strlen(needle);
+ while (*haystack) {
+ if (os_strncmp(haystack, needle, len) == 0)
+ return (char *) haystack;
+ haystack++;
+ }
+
+ return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+
+ /* See http://www.ijs.si/software/snprintf/ for portable
+ * implementation of snprintf.
+ */
+
+ va_start(ap, format);
+ ret = vsnprintf(str, size, format, ap);
+ va_end(ap);
+ if (size > 0)
+ str[size - 1] = '\0';
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/os_none.c b/contrib/wpa_supplicant/os_none.c
new file mode 100644
index 000000000000..7404e2293af5
--- /dev/null
+++ b/contrib/wpa_supplicant/os_none.c
@@ -0,0 +1,220 @@
+/*
+ * wpa_supplicant/hostapd / Empty OS specific functions
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file can be used as a starting point when adding a new OS target. The
+ * functions here do not really work as-is since they are just empty or only
+ * return an error value. os_internal.c can be used as another starting point
+ * or reference since it has example implementation of many of these functions.
+ */
+
+#include "includes.h"
+
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+}
+
+
+int os_get_time(struct os_time *t)
+{
+ return -1;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t)
+{
+ return -1;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+ return -1;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ return -1;
+}
+
+
+unsigned long os_random(void)
+{
+ return 0;
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+ return NULL; /* strdup(rel_path) can be used here */
+}
+
+
+int os_program_init(void)
+{
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return -1;
+}
+
+
+int os_unsetenv(const char *name)
+{
+ return -1;
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ return NULL;
+}
+
+
+void * os_zalloc(size_t size)
+{
+ return NULL;
+}
+
+
+#ifdef OS_NO_C_LIB_DEFINES
+void * os_malloc(size_t size)
+{
+ return NULL;
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+ return NULL;
+}
+
+
+void os_free(void *ptr)
+{
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+ return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+ return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+ return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+ return 0;
+}
+
+
+char * os_strdup(const char *s)
+{
+ return NULL;
+}
+
+
+size_t os_strlen(const char *s)
+{
+ return 0;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+ return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+ return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+ return 0;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+ return 0;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+ return dest;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+ return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+ return 0;
+}
+#endif /* OS_NO_C_LIB_DEFINES */
diff --git a/contrib/wpa_supplicant/os_unix.c b/contrib/wpa_supplicant/os_unix.c
new file mode 100644
index 000000000000..fb8149a7f3b9
--- /dev/null
+++ b/contrib/wpa_supplicant/os_unix.c
@@ -0,0 +1,212 @@
+/*
+ * wpa_supplicant/hostapd / OS specific functions for UNIX/POSIX systems
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+ if (sec)
+ sleep(sec);
+ if (usec)
+ usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+ int res;
+ struct timeval tv;
+ res = gettimeofday(&tv, NULL);
+ t->sec = tv.tv_sec;
+ t->usec = tv.tv_usec;
+ return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t)
+{
+ struct tm tm;
+
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+ sec > 60)
+ return -1;
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ *t = (os_time_t) mktime(&tm);
+ return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+ if (daemon(0, 0)) {
+ perror("daemon");
+ return -1;
+ }
+
+ if (pid_file) {
+ FILE *f = fopen(pid_file, "w");
+ if (f) {
+ fprintf(f, "%u\n", getpid());
+ fclose(f);
+ }
+ }
+
+ return -0;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+ if (pid_file)
+ unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ FILE *f;
+ size_t rc;
+
+ f = fopen("/dev/urandom", "rb");
+ if (f == NULL) {
+ printf("Could not open /dev/urandom.\n");
+ return -1;
+ }
+
+ rc = fread(buf, 1, len, f);
+ fclose(f);
+
+ return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+ return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+ char *buf = NULL, *cwd, *ret;
+ size_t len = 128, cwd_len, rel_len, ret_len;
+ int last_errno;
+
+ if (rel_path[0] == '/')
+ return strdup(rel_path);
+
+ for (;;) {
+ buf = malloc(len);
+ if (buf == NULL)
+ return NULL;
+ cwd = getcwd(buf, len);
+ if (cwd == NULL) {
+ last_errno = errno;
+ free(buf);
+ if (last_errno != ERANGE)
+ return NULL;
+ len *= 2;
+ if (len > 2000)
+ return NULL;
+ } else {
+ buf[len - 1] = '\0';
+ break;
+ }
+ }
+
+ cwd_len = strlen(cwd);
+ rel_len = strlen(rel_path);
+ ret_len = cwd_len + 1 + rel_len + 1;
+ ret = malloc(ret_len);
+ if (ret) {
+ memcpy(ret, cwd, cwd_len);
+ ret[cwd_len] = '/';
+ memcpy(ret + cwd_len + 1, rel_path, rel_len);
+ ret[ret_len - 1] = '\0';
+ }
+ free(buf);
+ return ret;
+}
+
+
+int os_program_init(void)
+{
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+ unsetenv(name);
+ return 0;
+#else
+ return unsetenv(name);
+#endif
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ FILE *f;
+ char *buf;
+
+ f = fopen(name, "rb");
+ if (f == NULL)
+ return NULL;
+
+ fseek(f, 0, SEEK_END);
+ *len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ buf = malloc(*len);
+ if (buf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ fread(buf, 1, *len, f);
+ fclose(f);
+
+ return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+ return calloc(1, size);
+}
diff --git a/contrib/wpa_supplicant/pcsc_funcs.c b/contrib/wpa_supplicant/pcsc_funcs.c
index 2ccfd0065e33..cef86534598f 100644
--- a/contrib/wpa_supplicant/pcsc_funcs.c
+++ b/contrib/wpa_supplicant/pcsc_funcs.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -10,15 +10,16 @@
* license.
*
* See README and COPYING for more details.
+ *
+ * This file implements wrapper functions for accessing GSM SIM and 3GPP USIM
+ * cards through PC/SC smartcard library. These functions are used to implement
+ * authentication routines for EAP-SIM and EAP-AKA.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include <winscard.h>
#include "common.h"
-#include "wpa_supplicant.h"
#include "pcsc_funcs.h"
@@ -38,6 +39,9 @@
* P1 = ID of alg in card
* P2 = ID of secret key
* READ BINARY: B0 <offset high> <offset low> <len>
+ * READ RECORD: B2 <record number> <mode> <len>
+ * P2 (mode) = '02' (next record), '03' (previous record),
+ * '04' (absolute mode)
* VERIFY CHV: 20 00 <CHV number> 08
* CHANGE CHV: 24 00 <CHV number> 10
* DISABLE CHV: 26 00 01 08
@@ -51,6 +55,7 @@
#define SIM_CMD_RUN_GSM_ALG 0xa0, 0x88, 0x00, 0x00, 0x10
#define SIM_CMD_GET_RESPONSE 0xa0, 0xc0, 0x00, 0x00
#define SIM_CMD_READ_BIN 0xa0, 0xb0, 0x00, 0x00
+#define SIM_CMD_READ_RECORD 0xa0, 0xb2, 0x00, 0x00
#define SIM_CMD_VERIFY_CHV1 0xa0, 0x20, 0x00, 0x01, 0x08
/* USIM commands */
@@ -58,6 +63,8 @@
#define USIM_CMD_RUN_UMTS_ALG 0x00, 0x88, 0x00, 0x81, 0x22
#define USIM_CMD_GET_RESPONSE 0x00, 0xc0, 0x00, 0x00
+#define SIM_RECORD_MODE_ABSOLUTE 0x04
+
#define USIM_FSP_TEMPL_TAG 0x62
#define USIM_TLV_FILE_DESC 0x82
@@ -83,20 +90,151 @@
typedef enum { SCARD_GSM_SIM, SCARD_USIM } sim_types;
struct scard_data {
- long ctx;
- long card;
- unsigned long protocol;
+ SCARDCONTEXT ctx;
+ SCARDHANDLE card;
+ DWORD protocol;
sim_types sim_type;
int pin1_required;
};
+#ifdef __MINGW32_VERSION
+/* MinGW does not yet support WinScard, so load the needed functions
+ * dynamically from winscard.dll for now. */
+
+static HINSTANCE dll = NULL; /* winscard.dll */
+
+static const SCARD_IO_REQUEST *dll_g_rgSCardT0Pci, *dll_g_rgSCardT1Pci;
+#undef SCARD_PCI_T0
+#define SCARD_PCI_T0 (dll_g_rgSCardT0Pci)
+#undef SCARD_PCI_T1
+#define SCARD_PCI_T1 (dll_g_rgSCardT1Pci)
+
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardEstablishContext)(IN DWORD dwScope,
+ IN LPCVOID pvReserved1,
+ IN LPCVOID pvReserved2,
+ OUT LPSCARDCONTEXT phContext);
+#define SCardEstablishContext dll_SCardEstablishContext
+
+static long (*dll_SCardReleaseContext)(long hContext);
+#define SCardReleaseContext dll_SCardReleaseContext
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardListReadersA)(IN SCARDCONTEXT hContext,
+ IN LPCSTR mszGroups,
+ OUT LPSTR mszReaders,
+ IN OUT LPDWORD pcchReaders);
+#undef SCardListReaders
+#define SCardListReaders dll_SCardListReadersA
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardConnectA)(IN SCARDCONTEXT hContext,
+ IN LPCSTR szReader,
+ IN DWORD dwShareMode,
+ IN DWORD dwPreferredProtocols,
+ OUT LPSCARDHANDLE phCard,
+ OUT LPDWORD pdwActiveProtocol);
+#undef SCardConnect
+#define SCardConnect dll_SCardConnectA
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardDisconnect)(IN SCARDHANDLE hCard,
+ IN DWORD dwDisposition);
+#define SCardDisconnect dll_SCardDisconnect
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardTransmit)(IN SCARDHANDLE hCard,
+ IN LPCSCARD_IO_REQUEST pioSendPci,
+ IN LPCBYTE pbSendBuffer,
+ IN DWORD cbSendLength,
+ IN OUT LPSCARD_IO_REQUEST pioRecvPci,
+ OUT LPBYTE pbRecvBuffer,
+ IN OUT LPDWORD pcbRecvLength);
+#define SCardTransmit dll_SCardTransmit
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardBeginTransaction)(IN SCARDHANDLE hCard);
+#define SCardBeginTransaction dll_SCardBeginTransaction
+
+static WINSCARDAPI LONG WINAPI
+(*dll_SCardEndTransaction)(IN SCARDHANDLE hCard, IN DWORD dwDisposition);
+#define SCardEndTransaction dll_SCardEndTransaction
+
+
+static int mingw_load_symbols(void)
+{
+ char *sym;
+
+ if (dll)
+ return 0;
+
+ dll = LoadLibrary("winscard");
+ if (dll == NULL) {
+ wpa_printf(MSG_DEBUG, "WinSCard: Could not load winscard.dll "
+ "library");
+ return -1;
+ }
+
+#define LOADSYM(s) \
+ sym = #s; \
+ dll_ ## s = (void *) GetProcAddress(dll, sym); \
+ if (dll_ ## s == NULL) \
+ goto fail;
+
+ LOADSYM(SCardEstablishContext);
+ LOADSYM(SCardReleaseContext);
+ LOADSYM(SCardListReadersA);
+ LOADSYM(SCardConnectA);
+ LOADSYM(SCardDisconnect);
+ LOADSYM(SCardTransmit);
+ LOADSYM(SCardBeginTransaction);
+ LOADSYM(SCardEndTransaction);
+ LOADSYM(g_rgSCardT0Pci);
+ LOADSYM(g_rgSCardT1Pci);
+
+#undef LOADSYM
+
+ return 0;
+
+fail:
+ wpa_printf(MSG_DEBUG, "WinSCard: Could not get address for %s from "
+ "winscard.dll", sym);
+ FreeLibrary(dll);
+ dll = NULL;
+ return -1;
+}
+
+
+static void mingw_unload_symbols(void)
+{
+ if (dll == NULL)
+ return;
+
+ FreeLibrary(dll);
+ dll = NULL;
+}
+
+#else /* __MINGW32_VERSION */
+
+#define mingw_load_symbols() 0
+#define mingw_unload_symbols() do { } while (0)
+
+#endif /* __MINGW32_VERSION */
+
static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
unsigned char *buf, size_t *buf_len,
- sim_types sim_type, unsigned char *aid);
+ sim_types sim_type, unsigned char *aid,
+ size_t aidlen);
static int scard_select_file(struct scard_data *scard, unsigned short file_id,
unsigned char *buf, size_t *buf_len);
static int scard_verify_pin(struct scard_data *scard, const char *pin);
+static int scard_get_record_len(struct scard_data *scard,
+ unsigned char recnum, unsigned char mode);
+static int scard_read_record(struct scard_data *scard,
+ unsigned char *data, size_t len,
+ unsigned char recnum, unsigned char mode);
static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
@@ -175,27 +313,145 @@ static int scard_pin_needed(struct scard_data *scard,
return -1;
/* TODO: there could be more than one PS_DO entry because of
* multiple PINs in key reference.. */
- if (ps_do)
+ if (ps_do > 0 && (ps_do & 0x80))
return 1;
+ return 0;
}
return -1;
}
+static int scard_get_aid(struct scard_data *scard, unsigned char *aid,
+ size_t maxlen)
+{
+ int rlen, rec;
+ struct efdir {
+ unsigned char appl_template_tag; /* 0x61 */
+ unsigned char appl_template_len;
+ unsigned char appl_id_tag; /* 0x4f */
+ unsigned char aid_len;
+ unsigned char rid[5];
+ unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
+ } *efdir;
+ unsigned char buf[100];
+ size_t blen;
+
+ efdir = (struct efdir *) buf;
+ blen = sizeof(buf);
+ if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR select", buf, blen);
+
+ for (rec = 1; rec < 10; rec++) {
+ rlen = scard_get_record_len(scard, rec,
+ SIM_RECORD_MODE_ABSOLUTE);
+ if (rlen < 0) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to get EF_DIR "
+ "record length");
+ return -1;
+ }
+ blen = sizeof(buf);
+ if (rlen > (int) blen) {
+ wpa_printf(MSG_DEBUG, "SCARD: Too long EF_DIR record");
+ return -1;
+ }
+ if (scard_read_record(scard, buf, rlen, rec,
+ SIM_RECORD_MODE_ABSOLUTE) < 0) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to read "
+ "EF_DIR record %d", rec);
+ return -1;
+ }
+ wpa_hexdump(MSG_DEBUG, "SCARD: EF_DIR record", buf, rlen);
+
+ if (efdir->appl_template_tag != 0x61) {
+ wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
+ "template tag 0x%x",
+ efdir->appl_template_tag);
+ continue;
+ }
+
+ if (efdir->appl_template_len > rlen - 2) {
+ wpa_printf(MSG_DEBUG, "SCARD: Too long application "
+ "template (len=%d rlen=%d)",
+ efdir->appl_template_len, rlen);
+ continue;
+ }
+
+ if (efdir->appl_id_tag != 0x4f) {
+ wpa_printf(MSG_DEBUG, "SCARD: Unexpected application "
+ "identifier tag 0x%x", efdir->appl_id_tag);
+ continue;
+ }
+
+ if (efdir->aid_len < 1 || efdir->aid_len > 16) {
+ wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
+ efdir->aid_len);
+ continue;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
+ efdir->rid, efdir->aid_len);
+
+ if (efdir->appl_code[0] == 0x10 &&
+ efdir->appl_code[1] == 0x02) {
+ wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app found from "
+ "EF_DIR record %d", rec);
+ break;
+ }
+ }
+
+ if (rec >= 10) {
+ wpa_printf(MSG_DEBUG, "SCARD: 3G USIM app not found "
+ "from EF_DIR records");
+ return -1;
+ }
+
+ if (efdir->aid_len > maxlen) {
+ wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
+ return -1;
+ }
+
+ os_memcpy(aid, efdir->rid, efdir->aid_len);
+
+ return efdir->aid_len;
+}
+
+
+/**
+ * scard_init - Initialize SIM/USIM connection using PC/SC
+ * @sim_type: Allowed SIM types (SIM, USIM, or both)
+ * Returns: Pointer to private data structure, or %NULL on failure
+ *
+ * This function is used to initialize SIM/USIM connection. PC/SC is used to
+ * open connection to the SIM/USIM card and the card is verified to support the
+ * selected sim_type. In addition, local flag is set if a PIN is needed to
+ * access some of the card functions. Once the connection is not needed
+ * anymore, scard_deinit() can be used to close it.
+ */
struct scard_data * scard_init(scard_sim_type sim_type)
{
- long ret, len;
+ long ret;
+ unsigned long len;
struct scard_data *scard;
+#ifdef CONFIG_NATIVE_WINDOWS
+ TCHAR *readers = NULL;
+#else /* CONFIG_NATIVE_WINDOWS */
char *readers = NULL;
- char buf[100];
+#endif /* CONFIG_NATIVE_WINDOWS */
+ unsigned char buf[100];
size_t blen;
+ int transaction = 0;
+ int pin_needed;
wpa_printf(MSG_DEBUG, "SCARD: initializing smart card interface");
- scard = malloc(sizeof(*scard));
+ if (mingw_load_symbols())
+ return NULL;
+ scard = os_zalloc(sizeof(*scard));
if (scard == NULL)
return NULL;
- memset(scard, 0, sizeof(*scard));
ret = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL,
&scard->ctx);
@@ -212,9 +468,12 @@ struct scard_data * scard_init(scard_sim_type sim_type)
goto failed;
}
- readers = malloc(len);
+#ifdef UNICODE
+ len *= 2;
+#endif /* UNICODE */
+ readers = os_malloc(len);
if (readers == NULL) {
- printf("malloc failed\n");
+ wpa_printf(MSG_INFO, "SCARD: malloc failed\n");
goto failed;
}
@@ -233,23 +492,36 @@ struct scard_data * scard_init(scard_sim_type sim_type)
* double NUL.
* TODO: add support for selecting the reader; now just use the first
* one.. */
+#ifdef UNICODE
+ wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%S'", readers);
+#else /* UNICODE */
wpa_printf(MSG_DEBUG, "SCARD: Selected reader='%s'", readers);
+#endif /* UNICODE */
ret = SCardConnect(scard->ctx, readers, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0, &scard->card, &scard->protocol);
if (ret != SCARD_S_SUCCESS) {
- if (ret == SCARD_E_NO_SMARTCARD)
+ if (ret == (long) SCARD_E_NO_SMARTCARD)
wpa_printf(MSG_INFO, "No smart card inserted.");
else
wpa_printf(MSG_WARNING, "SCardConnect err=%lx", ret);
goto failed;
}
- free(readers);
+ os_free(readers);
readers = NULL;
- wpa_printf(MSG_DEBUG, "SCARD: card=%ld active_protocol=%lu",
- scard->card, scard->protocol);
+ wpa_printf(MSG_DEBUG, "SCARD: card=0x%x active_protocol=%lu (%s)",
+ (unsigned int) scard->card, scard->protocol,
+ scard->protocol == SCARD_PROTOCOL_T0 ? "T0" : "T1");
+
+ ret = SCardBeginTransaction(scard->card);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: Could not begin transaction: "
+ "0x%x", (unsigned int) ret);
+ goto failed;
+ }
+ transaction = 1;
blen = sizeof(buf);
@@ -257,7 +529,7 @@ struct scard_data * scard_init(scard_sim_type sim_type)
if (sim_type == SCARD_USIM_ONLY || sim_type == SCARD_TRY_BOTH) {
wpa_printf(MSG_DEBUG, "SCARD: verifying USIM support");
if (_scard_select_file(scard, SCARD_FILE_MF, buf, &blen,
- SCARD_USIM, NULL)) {
+ SCARD_USIM, NULL, 0)) {
wpa_printf(MSG_DEBUG, "SCARD: USIM is not supported");
if (sim_type == SCARD_USIM_ONLY)
goto failed;
@@ -282,31 +554,66 @@ struct scard_data * scard_init(scard_sim_type sim_type)
goto failed;
}
} else {
- /* Select based on AID = 3G RID */
+ unsigned char aid[32];
+ int aid_len;
+
+ aid_len = scard_get_aid(scard, aid, sizeof(aid));
+ if (aid_len < 0) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to find AID for "
+ "3G USIM app - try to use standard 3G RID");
+ os_memcpy(aid, "\xa0\x00\x00\x00\x87", 5);
+ aid_len = 5;
+ }
+ wpa_hexdump(MSG_DEBUG, "SCARD: 3G USIM AID", aid, aid_len);
+
+ /* Select based on AID = 3G RID from EF_DIR. This is usually
+ * starting with A0 00 00 00 87. */
blen = sizeof(buf);
if (_scard_select_file(scard, 0, buf, &blen, scard->sim_type,
- "\xA0\x00\x00\x00\x87")) {
- wpa_printf(MSG_DEBUG, "SCARD: Failed to read 3G RID "
- "AID");
+ aid, aid_len)) {
+ wpa_printf(MSG_INFO, "SCARD: Failed to read 3G USIM "
+ "app");
+ wpa_hexdump(MSG_INFO, "SCARD: 3G USIM AID",
+ aid, aid_len);
goto failed;
}
}
/* Verify whether CHV1 (PIN1) is needed to access the card. */
- if (scard_pin_needed(scard, buf, blen)) {
+ pin_needed = scard_pin_needed(scard, buf, blen);
+ if (pin_needed < 0) {
+ wpa_printf(MSG_DEBUG, "SCARD: Failed to determine whether PIN "
+ "is needed");
+ goto failed;
+ }
+ if (pin_needed) {
scard->pin1_required = 1;
wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
}
+ ret = SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: Could not end transaction: "
+ "0x%x", (unsigned int) ret);
+ }
+
return scard;
failed:
- free(readers);
+ if (transaction)
+ SCardEndTransaction(scard->card, SCARD_LEAVE_CARD);
+ os_free(readers);
scard_deinit(scard);
return NULL;
}
+/**
+ * scard_set_pin - Set PIN (CHV1/PIN1) code for accessing SIM/USIM commands
+ * @scard: Pointer to private data from scard_init()
+ * pin: PIN code as an ASCII string (e.g., "1234")
+ * Returns: 0 on success, -1 on failure
+ */
int scard_set_pin(struct scard_data *scard, const char *pin)
{
if (scard == NULL)
@@ -330,6 +637,12 @@ int scard_set_pin(struct scard_data *scard, const char *pin)
}
+/**
+ * scard_deinit - Deinitialize SIM/USIM connection
+ * @scard: Pointer to private data from scard_init()
+ *
+ * This function closes the SIM/USIM connect opened with scard_init().
+ */
void scard_deinit(struct scard_data *scard)
{
long ret;
@@ -353,29 +666,30 @@ void scard_deinit(struct scard_data *scard)
"context (err=%ld)", ret);
}
}
- free(scard);
+ os_free(scard);
+ mingw_unload_symbols();
}
static long scard_transmit(struct scard_data *scard,
- unsigned char *send, size_t send_len,
- unsigned char *recv, size_t *recv_len)
+ unsigned char *_send, size_t send_len,
+ unsigned char *_recv, size_t *recv_len)
{
long ret;
unsigned long rlen;
wpa_hexdump_key(MSG_DEBUG, "SCARD: scard_transmit: send",
- send, send_len);
+ _send, send_len);
rlen = *recv_len;
ret = SCardTransmit(scard->card,
scard->protocol == SCARD_PROTOCOL_T1 ?
SCARD_PCI_T1 : SCARD_PCI_T0,
- send, (unsigned long) send_len,
- NULL, recv, &rlen);
+ _send, (unsigned long) send_len,
+ NULL, _recv, &rlen);
*recv_len = rlen;
if (ret == SCARD_S_SUCCESS) {
wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
- recv, rlen);
+ _recv, rlen);
} else {
wpa_printf(MSG_WARNING, "SCARD: SCardTransmit failed "
"(err=0x%lx)", ret);
@@ -386,11 +700,12 @@ static long scard_transmit(struct scard_data *scard,
static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
unsigned char *buf, size_t *buf_len,
- sim_types sim_type, unsigned char *aid)
+ sim_types sim_type, unsigned char *aid,
+ size_t aidlen)
{
long ret;
unsigned char resp[3];
- unsigned char cmd[10] = { SIM_CMD_SELECT };
+ unsigned char cmd[50] = { SIM_CMD_SELECT };
int cmdlen;
unsigned char get_resp[5] = { SIM_CMD_GET_RESPONSE };
size_t len, rlen;
@@ -403,10 +718,14 @@ static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
wpa_printf(MSG_DEBUG, "SCARD: select file %04x", file_id);
if (aid) {
+ wpa_hexdump(MSG_DEBUG, "SCARD: select file by AID",
+ aid, aidlen);
+ if (5 + aidlen > sizeof(cmd))
+ return -1;
cmd[2] = 0x04; /* Select by AID */
- cmd[4] = 5; /* len */
- memcpy(cmd + 5, aid, 5);
- cmdlen = 10;
+ cmd[4] = aidlen; /* len */
+ os_memcpy(cmd + 5, aid, aidlen);
+ cmdlen = 5 + aidlen;
} else {
cmd[5] = file_id >> 8;
cmd[6] = file_id & 0xff;
@@ -464,19 +783,102 @@ static int scard_select_file(struct scard_data *scard, unsigned short file_id,
unsigned char *buf, size_t *buf_len)
{
return _scard_select_file(scard, file_id, buf, buf_len,
- scard->sim_type, NULL);
+ scard->sim_type, NULL, 0);
+}
+
+
+static int scard_get_record_len(struct scard_data *scard, unsigned char recnum,
+ unsigned char mode)
+{
+ unsigned char buf[255];
+ unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
+ size_t blen;
+ long ret;
+
+ if (scard->sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ cmd[2] = recnum;
+ cmd[3] = mode;
+ cmd[4] = sizeof(buf);
+
+ blen = sizeof(buf);
+ ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
+ if (ret != SCARD_S_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "SCARD: failed to determine file "
+ "length for record %d", recnum);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
+ buf, blen);
+
+ if (blen < 2 || buf[0] != 0x6c) {
+ wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
+ "length determination");
+ return -1;
+ }
+
+ return buf[1];
+}
+
+
+static int scard_read_record(struct scard_data *scard,
+ unsigned char *data, size_t len,
+ unsigned char recnum, unsigned char mode)
+{
+ unsigned char cmd[5] = { SIM_CMD_READ_RECORD /* , len */ };
+ size_t blen = len + 3;
+ unsigned char *buf;
+ long ret;
+
+ if (scard->sim_type == SCARD_USIM)
+ cmd[0] = USIM_CLA;
+ cmd[2] = recnum;
+ cmd[3] = mode;
+ cmd[4] = len;
+
+ buf = os_malloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
+ if (ret != SCARD_S_SUCCESS) {
+ os_free(buf);
+ return -2;
+ }
+ if (blen != len + 2) {
+ wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
+ "length %d (expected %d)", blen, len + 2);
+ os_free(buf);
+ return -3;
+ }
+
+ if (buf[len] != 0x90 || buf[len + 1] != 0x00) {
+ wpa_printf(MSG_DEBUG, "SCARD: record read returned unexpected "
+ "status %02x %02x (expected 90 00)",
+ buf[len], buf[len + 1]);
+ os_free(buf);
+ return -4;
+ }
+
+ os_memcpy(data, buf, len);
+ os_free(buf);
+
+ return 0;
}
static int scard_read_file(struct scard_data *scard,
unsigned char *data, size_t len)
{
- char cmd[5] = { SIM_CMD_READ_BIN, len };
+ unsigned char cmd[5] = { SIM_CMD_READ_BIN /* , len */ };
size_t blen = len + 3;
unsigned char *buf;
long ret;
- buf = malloc(blen);
+ cmd[4] = len;
+
+ buf = os_malloc(blen);
if (buf == NULL)
return -1;
@@ -484,13 +886,13 @@ static int scard_read_file(struct scard_data *scard,
cmd[0] = USIM_CLA;
ret = scard_transmit(scard, cmd, sizeof(cmd), buf, &blen);
if (ret != SCARD_S_SUCCESS) {
- free(buf);
+ os_free(buf);
return -2;
}
if (blen != len + 2) {
wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
"length %d (expected %d)", blen, len + 2);
- free(buf);
+ os_free(buf);
return -3;
}
@@ -498,12 +900,12 @@ static int scard_read_file(struct scard_data *scard,
wpa_printf(MSG_DEBUG, "SCARD: file read returned unexpected "
"status %02x %02x (expected 90 00)",
buf[len], buf[len + 1]);
- free(buf);
+ os_free(buf);
return -4;
}
- memcpy(data, buf, len);
- free(buf);
+ os_memcpy(data, buf, len);
+ os_free(buf);
return 0;
}
@@ -513,18 +915,18 @@ static int scard_verify_pin(struct scard_data *scard, const char *pin)
{
long ret;
unsigned char resp[3];
- char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
+ unsigned char cmd[5 + 8] = { SIM_CMD_VERIFY_CHV1 };
size_t len;
wpa_printf(MSG_DEBUG, "SCARD: verifying PIN");
- if (pin == NULL || strlen(pin) > 8)
+ if (pin == NULL || os_strlen(pin) > 8)
return -1;
if (scard->sim_type == SCARD_USIM)
cmd[0] = USIM_CLA;
- memcpy(cmd + 5, pin, strlen(pin));
- memset(cmd + 5 + strlen(pin), 0xff, 8 - strlen(pin));
+ os_memcpy(cmd + 5, pin, os_strlen(pin));
+ os_memset(cmd + 5 + os_strlen(pin), 0xff, 8 - os_strlen(pin));
len = sizeof(resp);
ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
@@ -541,12 +943,25 @@ static int scard_verify_pin(struct scard_data *scard, const char *pin)
}
+/**
+ * scard_get_imsi - Read IMSI from SIM/USIM card
+ * @scard: Pointer to private data from scard_init()
+ * @imsi: Buffer for IMSI
+ * @len: Length of imsi buffer; set to IMSI length on success
+ * Returns: 0 on success, -1 if IMSI file cannot be selected, -2 if IMSI file
+ * selection returns invalid result code, -3 if parsing FSP template file fails
+ * (USIM only), -4 if IMSI does not fit in the provided imsi buffer (len is set
+ * to needed length), -5 if reading IMSI file fails.
+ *
+ * This function can be used to read IMSI from the SIM/USIM card. If the IMSI
+ * file is PIN protected, scard_set_pin() must have been used to set the
+ * correct PIN code before calling scard_get_imsi().
+ */
int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
{
- char buf[100];
- size_t blen, imsilen;
+ unsigned char buf[100];
+ size_t blen, imsilen, i;
char *pos;
- int i;
wpa_printf(MSG_DEBUG, "SCARD: reading IMSI from (GSM) EF-IMSI");
blen = sizeof(buf);
@@ -606,7 +1021,22 @@ int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len)
}
-int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
+/**
+ * scard_gsm_auth - Run GSM authentication command on SIM card
+ * @scard: Pointer to private data from scard_init()
+ * @_rand: 16-byte RAND value from HLR/AuC
+ * @sres: 4-byte buffer for SRES
+ * @kc: 8-byte buffer for Kc
+ * Returns: 0 on success, -1 if SIM/USIM connection has not been initialized,
+ * -2 if authentication command execution fails, -3 if unknown response code
+ * for authentication command is received, -4 if reading of response fails,
+ * -5 if if response data is of unexpected length
+ *
+ * This function performs GSM authentication using SIM/USIM card and the
+ * provided RAND value from HLR/AuC. If authentication command can be completed
+ * successfully, SRES and Kc values will be written into sres and kc buffers.
+ */
+int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
unsigned char *sres, unsigned char *kc)
{
unsigned char cmd[5 + 1 + 16] = { SIM_CMD_RUN_GSM_ALG };
@@ -619,17 +1049,17 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
if (scard == NULL)
return -1;
- wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", rand, 16);
+ wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - RAND", _rand, 16);
if (scard->sim_type == SCARD_GSM_SIM) {
cmdlen = 5 + 16;
- memcpy(cmd + 5, rand, 16);
+ os_memcpy(cmd + 5, _rand, 16);
} else {
cmdlen = 5 + 1 + 16;
cmd[0] = USIM_CLA;
cmd[3] = 0x80;
cmd[4] = 17;
cmd[5] = 16;
- memcpy(cmd + 6, rand, 16);
+ os_memcpy(cmd + 6, _rand, 16);
}
len = sizeof(resp);
ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
@@ -659,8 +1089,8 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
len);
return -5;
}
- memcpy(sres, buf, 4);
- memcpy(kc, buf + 4, 8);
+ os_memcpy(sres, buf, 4);
+ os_memcpy(kc, buf + 4, 8);
} else {
if (len != 1 + 4 + 1 + 8 + 2) {
wpa_printf(MSG_WARNING, "SCARD: unexpected data "
@@ -673,8 +1103,8 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
"length (%d %d, expected 4 8)",
buf[0], buf[5]);
}
- memcpy(sres, buf + 1, 4);
- memcpy(kc, buf + 6, 8);
+ os_memcpy(sres, buf + 1, 4);
+ os_memcpy(kc, buf + 6, 8);
}
wpa_hexdump(MSG_DEBUG, "SCARD: GSM auth - SRES", sres, 4);
@@ -684,13 +1114,33 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
}
-int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
- unsigned char *autn, unsigned char *res, size_t *res_len,
+/**
+ * scard_umts_auth - Run UMTS authentication command on USIM card
+ * @scard: Pointer to private data from scard_init()
+ * @_rand: 16-byte RAND value from HLR/AuC
+ * @autn: 16-byte AUTN value from HLR/AuC
+ * @res: 16-byte buffer for RES
+ * @res_len: Variable that will be set to RES length
+ * @ik: 16-byte buffer for IK
+ * @ck: 16-byte buffer for CK
+ * @auts: 14-byte buffer for AUTS
+ * Returns: 0 on success, -1 on failure, or -2 if USIM reports synchronization
+ * failure
+ *
+ * This function performs AKA authentication using USIM card and the provided
+ * RAND and AUTN values from HLR/AuC. If authentication command can be
+ * completed successfully, RES, IK, and CK values will be written into provided
+ * buffers and res_len is set to length of received RES value. If USIM reports
+ * synchronization failure, the received AUTS value will be written into auts
+ * buffer. In this case, RES, IK, and CK are not valid.
+ */
+int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
+ const unsigned char *autn,
+ unsigned char *res, size_t *res_len,
unsigned char *ik, unsigned char *ck, unsigned char *auts)
{
unsigned char cmd[5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN] =
{ USIM_CMD_RUN_UMTS_ALG };
- int cmdlen;
unsigned char get_resp[5] = { USIM_CMD_GET_RESPONSE };
unsigned char resp[3], buf[64], *pos, *end;
size_t len;
@@ -705,20 +1155,19 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
return -1;
}
- wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", rand, AKA_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - RAND", _rand, AKA_RAND_LEN);
wpa_hexdump(MSG_DEBUG, "SCARD: UMTS auth - AUTN", autn, AKA_AUTN_LEN);
- cmdlen = 5 + 1 + AKA_RAND_LEN + 1 + AKA_AUTN_LEN;
cmd[5] = AKA_RAND_LEN;
- memcpy(cmd + 6, rand, AKA_RAND_LEN);
+ os_memcpy(cmd + 6, _rand, AKA_RAND_LEN);
cmd[6 + AKA_RAND_LEN] = AKA_AUTN_LEN;
- memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
+ os_memcpy(cmd + 6 + AKA_RAND_LEN + 1, autn, AKA_AUTN_LEN);
len = sizeof(resp);
ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
if (ret != SCARD_S_SUCCESS)
return -1;
- if (len >= 0 && len <= sizeof(resp))
+ if (len <= sizeof(resp))
wpa_hexdump(MSG_DEBUG, "SCARD: UMTS alg response", resp, len);
if (len == 2 && resp[0] == 0x98 && resp[1] == 0x62) {
@@ -735,14 +1184,14 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
len = sizeof(buf);
ret = scard_transmit(scard, get_resp, sizeof(get_resp), buf, &len);
- if (ret != SCARD_S_SUCCESS || len < 0 || len > sizeof(buf))
+ if (ret != SCARD_S_SUCCESS || len > sizeof(buf))
return -1;
wpa_hexdump(MSG_DEBUG, "SCARD: UMTS get response result", buf, len);
if (len >= 2 + AKA_AUTS_LEN && buf[0] == 0xdc &&
buf[1] == AKA_AUTS_LEN) {
wpa_printf(MSG_DEBUG, "SCARD: UMTS Synchronization-Failure");
- memcpy(auts, buf + 2, AKA_AUTS_LEN);
+ os_memcpy(auts, buf + 2, AKA_AUTS_LEN);
wpa_hexdump(MSG_DEBUG, "SCARD: AUTS", auts, AKA_AUTS_LEN);
return -2;
} else if (len >= 6 + IK_LEN + CK_LEN && buf[0] == 0xdb) {
@@ -755,7 +1204,7 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
return -1;
}
*res_len = *pos++;
- memcpy(res, pos, *res_len);
+ os_memcpy(res, pos, *res_len);
pos += *res_len;
wpa_hexdump(MSG_DEBUG, "SCARD: RES", res, *res_len);
@@ -765,7 +1214,7 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
return -1;
}
pos++;
- memcpy(ck, pos, CK_LEN);
+ os_memcpy(ck, pos, CK_LEN);
pos += CK_LEN;
wpa_hexdump(MSG_DEBUG, "SCARD: CK", ck, CK_LEN);
@@ -775,7 +1224,7 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
return -1;
}
pos++;
- memcpy(ik, pos, IK_LEN);
+ os_memcpy(ik, pos, IK_LEN);
pos += IK_LEN;
wpa_hexdump(MSG_DEBUG, "SCARD: IK", ik, IK_LEN);
diff --git a/contrib/wpa_supplicant/pcsc_funcs.h b/contrib/wpa_supplicant/pcsc_funcs.h
index 47ac66ce92a3..543f7c598419 100644
--- a/contrib/wpa_supplicant/pcsc_funcs.h
+++ b/contrib/wpa_supplicant/pcsc_funcs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -26,6 +26,7 @@
#define SCARD_FILE_GSM_DF 0x7F20
#define SCARD_FILE_UMTS_DF 0x7F50
#define SCARD_FILE_GSM_EF_IMSI 0x6F07
+#define SCARD_FILE_EF_DIR 0x2F00
#define SCARD_FILE_EF_ICCID 0x2FE2
#define SCARD_FILE_EF_CK 0x6FE1
#define SCARD_FILE_EF_IK 0x6FE2
@@ -46,10 +47,11 @@ void scard_deinit(struct scard_data *scard);
int scard_set_pin(struct scard_data *scard, const char *pin);
int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len);
-int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
+int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
unsigned char *sres, unsigned char *kc);
-int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
- unsigned char *autn, unsigned char *res, size_t *res_len,
+int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
+ const unsigned char *autn,
+ unsigned char *res, size_t *res_len,
unsigned char *ik, unsigned char *ck, unsigned char *auts);
#else /* PCSC_FUNCS */
diff --git a/contrib/wpa_supplicant/pmksa_cache.c b/contrib/wpa_supplicant/pmksa_cache.c
new file mode 100644
index 000000000000..127c3571bb6a
--- /dev/null
+++ b/contrib/wpa_supplicant/pmksa_cache.c
@@ -0,0 +1,502 @@
+/*
+ * WPA Supplicant - RSN PMKSA cache
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa.h"
+#include "eloop.h"
+#include "config_ssid.h"
+#include "sha1.h"
+#include "wpa_i.h"
+#include "l2_packet.h"
+#include "eapol_sm.h"
+#include "pmksa_cache.h"
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+static const int pmksa_cache_max_entries = 32;
+
+struct rsn_pmksa_cache {
+ struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */
+ int pmksa_count; /* number of entries in PMKSA cache */
+ struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
+
+ void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
+ int replace);
+ void *ctx;
+};
+
+
+/**
+ * rsn_pmkid - Calculate PMK identifier
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of pmk in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ *
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
+ */
+static void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid)
+{
+ char *title = "PMK Name";
+ const u8 *addr[3];
+ const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+ unsigned char hash[SHA1_MAC_LEN];
+
+ addr[0] = (u8 *) title;
+ addr[1] = aa;
+ addr[2] = spa;
+
+ hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
+ os_memcpy(pmkid, hash, PMKID_LEN);
+}
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
+
+
+static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
+{
+ os_free(entry);
+}
+
+
+static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+ struct rsn_pmksa_cache_entry *entry,
+ int replace)
+{
+ pmksa->pmksa_count--;
+ pmksa->free_cb(entry, pmksa->ctx, replace);
+ _pmksa_cache_free_entry(entry);
+}
+
+
+static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+{
+ struct rsn_pmksa_cache *pmksa = eloop_ctx;
+ struct os_time now;
+
+ os_get_time(&now);
+ while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+ pmksa->pmksa = entry->next;
+ wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
+ MACSTR, MAC2STR(entry->aa));
+ pmksa_cache_free_entry(pmksa, entry, 0);
+ }
+
+ pmksa_cache_set_expiration(pmksa);
+}
+
+
+static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
+{
+ struct rsn_pmksa_cache *pmksa = eloop_ctx;
+ pmksa->sm->cur_pmksa = NULL;
+ eapol_sm_request_reauth(pmksa->sm->eapol);
+}
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
+{
+ int sec;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_time now;
+
+ eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+ eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
+ if (pmksa->pmksa == NULL)
+ return;
+ os_get_time(&now);
+ sec = pmksa->pmksa->expiration - now.sec;
+ if (sec < 0)
+ sec = 0;
+ eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
+
+ entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
+ pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL);
+ if (entry) {
+ sec = pmksa->pmksa->reauth_time - now.sec;
+ if (sec < 0)
+ sec = 0;
+ eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa,
+ NULL);
+ }
+}
+
+
+/**
+ * pmksa_cache_add - Add a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @pmk: The new pairwise master key
+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @ssid: The network configuration for which this PMK is being added
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
+ * cache. If an old entry is already in the cache for the same Authenticator,
+ * this entry will be replaced with the new entry. PMKID will be calculated
+ * based on the PMK and the driver interface is notified of the new PMKID.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *aa, const u8 *spa, struct wpa_ssid *ssid)
+{
+ struct rsn_pmksa_cache_entry *entry, *pos, *prev;
+ struct os_time now;
+
+ if (pmksa->sm->proto != WPA_PROTO_RSN || pmk_len > PMK_LEN)
+ return NULL;
+
+ entry = os_zalloc(sizeof(*entry));
+ if (entry == NULL)
+ return NULL;
+ os_memcpy(entry->pmk, pmk, pmk_len);
+ entry->pmk_len = pmk_len;
+ rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid);
+ os_get_time(&now);
+ entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
+ entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
+ pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
+ entry->akmp = WPA_KEY_MGMT_IEEE8021X;
+ os_memcpy(entry->aa, aa, ETH_ALEN);
+ entry->ssid = ssid;
+
+ /* Replace an old entry for the same Authenticator (if found) with the
+ * new entry */
+ pos = pmksa->pmksa;
+ prev = NULL;
+ while (pos) {
+ if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
+ if (pos->pmk_len == pmk_len &&
+ os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
+ os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
+ 0) {
+ wpa_printf(MSG_DEBUG, "WPA: reusing previous "
+ "PMKSA entry");
+ os_free(entry);
+ return pos;
+ }
+ if (prev == NULL)
+ pmksa->pmksa = pos->next;
+ else
+ prev->next = pos->next;
+ if (pos == pmksa->sm->cur_pmksa) {
+ /* We are about to replace the current PMKSA
+ * cache entry. This happens when the PMKSA
+ * caching attempt fails, so we don't want to
+ * force pmksa_cache_free_entry() to disconnect
+ * at this point. Let's just make sure the old
+ * PMKSA cache entry will not be used in the
+ * future.
+ */
+ wpa_printf(MSG_DEBUG, "RSN: replacing current "
+ "PMKSA entry");
+ pmksa->sm->cur_pmksa = NULL;
+ }
+ wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+ "the current AP");
+ pmksa_cache_free_entry(pmksa, pos, 1);
+ break;
+ }
+ prev = pos;
+ pos = pos->next;
+ }
+
+ if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
+ /* Remove the oldest entry to make room for the new entry */
+ pos = pmksa->pmksa;
+ pmksa->pmksa = pos->next;
+ wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
+ "entry (for " MACSTR ") to make room for new one",
+ MAC2STR(pos->aa));
+ wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid);
+ pmksa_cache_free_entry(pmksa, pos, 0);
+ }
+
+ /* Add the new entry; order by expiration time */
+ pos = pmksa->pmksa;
+ prev = NULL;
+ while (pos) {
+ if (pos->expiration > entry->expiration)
+ break;
+ prev = pos;
+ pos = pos->next;
+ }
+ if (prev == NULL) {
+ entry->next = pmksa->pmksa;
+ pmksa->pmksa = entry;
+ pmksa_cache_set_expiration(pmksa);
+ } else {
+ entry->next = prev->next;
+ prev->next = entry;
+ }
+ pmksa->pmksa_count++;
+ wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
+ MAC2STR(entry->aa));
+ wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+
+ return entry;
+}
+
+
+/**
+ * pmksa_cache_deinit - Free all entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ */
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+ struct rsn_pmksa_cache_entry *entry, *prev;
+
+ if (pmksa == NULL)
+ return;
+
+ entry = pmksa->pmksa;
+ pmksa->pmksa = NULL;
+ while (entry) {
+ prev = entry;
+ entry = entry->next;
+ os_free(prev);
+ }
+ pmksa_cache_set_expiration(pmksa);
+ os_free(pmksa);
+}
+
+
+/**
+ * pmksa_cache_get - Fetch a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @aa: Authenticator address or %NULL to match any
+ * @pmkid: PMKID or %NULL to match any
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+ const u8 *aa, const u8 *pmkid)
+{
+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+ while (entry) {
+ if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
+ (pmkid == NULL ||
+ os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
+ return entry;
+ entry = entry->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ *
+ * Clear references to old data structures when wpa_supplicant is reconfigured.
+ */
+void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
+{
+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+ while (entry) {
+ entry->ssid = NULL;
+ entry = entry->next;
+ }
+}
+
+
+static struct rsn_pmksa_cache_entry *
+pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
+ const struct rsn_pmksa_cache_entry *old_entry,
+ const u8 *aa)
+{
+ struct rsn_pmksa_cache_entry *new_entry;
+
+ new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
+ aa, pmksa->sm->own_addr, old_entry->ssid);
+ if (new_entry == NULL)
+ return NULL;
+
+ /* TODO: reorder entries based on expiration time? */
+ new_entry->expiration = old_entry->expiration;
+ new_entry->opportunistic = 1;
+
+ return new_entry;
+}
+
+
+/**
+ * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @ssid: Pointer to the current network configuration
+ * @aa: Authenticator address for the new AP
+ * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
+ *
+ * Try to create a new PMKSA cache entry opportunistically by guessing that the
+ * new AP is sharing the same PMK as another AP that has the same SSID and has
+ * already an entry in PMKSA cache.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
+ struct wpa_ssid *ssid, const u8 *aa)
+{
+ struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+
+ if (ssid == NULL)
+ return NULL;
+ while (entry) {
+ if (entry->ssid == ssid) {
+ entry = pmksa_cache_clone_entry(pmksa, entry, aa);
+ if (entry) {
+ wpa_printf(MSG_DEBUG, "RSN: added "
+ "opportunistic PMKSA cache entry "
+ "for " MACSTR, MAC2STR(aa));
+ }
+ return entry;
+ }
+ entry = entry->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * pmksa_cache_get_current - Get the current used PMKSA entry
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
+{
+ if (sm == NULL)
+ return NULL;
+ return sm->cur_pmksa;
+}
+
+
+/**
+ * pmksa_cache_clear_current - Clear the current PMKSA entry selection
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void pmksa_cache_clear_current(struct wpa_sm *sm)
+{
+ if (sm == NULL)
+ return;
+ sm->cur_pmksa = NULL;
+}
+
+
+/**
+ * pmksa_cache_set_current - Set the current PMKSA entry selection
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @pmkid: PMKID for selecting PMKSA or %NULL if not used
+ * @bssid: BSSID for PMKSA or %NULL if not used
+ * @ssid: The network configuration for the current network
+ * @try_opportunistic: Whether to allow opportunistic PMKSA caching
+ * Returns: 0 if PMKSA was found or -1 if no matching entry was found
+ */
+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+ const u8 *bssid, struct wpa_ssid *ssid,
+ int try_opportunistic)
+{
+ struct rsn_pmksa_cache *pmksa = sm->pmksa;
+ sm->cur_pmksa = NULL;
+ if (pmkid)
+ sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid);
+ if (sm->cur_pmksa == NULL && bssid)
+ sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL);
+ if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
+ sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa, ssid,
+ bssid);
+ if (sm->cur_pmksa) {
+ wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
+ sm->cur_pmksa->pmkid, PMKID_LEN);
+ return 0;
+ }
+ return -1;
+}
+
+
+/**
+ * pmksa_cache_list - Dump text list of entries in PMKSA cache
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA command.
+ */
+int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
+{
+ int i, ret;
+ char *pos = buf;
+ struct rsn_pmksa_cache_entry *entry;
+ struct os_time now;
+
+ os_get_time(&now);
+ ret = os_snprintf(pos, buf + len - pos,
+ "Index / AA / PMKID / expiration (in seconds) / "
+ "opportunistic\n");
+ if (ret < 0 || ret >= buf + len - pos)
+ return pos - buf;
+ pos += ret;
+ i = 0;
+ entry = sm->pmksa->pmksa;
+ while (entry) {
+ i++;
+ ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+ i, MAC2STR(entry->aa));
+ if (ret < 0 || ret >= buf + len - pos)
+ return pos - buf;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
+ PMKID_LEN);
+ ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+ (int) (entry->expiration - now.sec),
+ entry->opportunistic);
+ if (ret < 0 || ret >= buf + len - pos)
+ return pos - buf;
+ pos += ret;
+ entry = entry->next;
+ }
+ return pos - buf;
+}
+
+
+/**
+ * pmksa_cache_init - Initialize PMKSA cache
+ * @free_cb: Callback function to be called when a PMKSA cache entry is freed
+ * @ctx: Context pointer for free_cb function
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: Pointer to PMKSA cache data or %NULL on failure
+ */
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+ void *ctx, int replace),
+ void *ctx, struct wpa_sm *sm)
+{
+ struct rsn_pmksa_cache *pmksa;
+
+ pmksa = os_zalloc(sizeof(*pmksa));
+ if (pmksa) {
+ pmksa->free_cb = free_cb;
+ pmksa->ctx = ctx;
+ pmksa->sm = sm;
+ }
+
+ return pmksa;
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
diff --git a/contrib/wpa_supplicant/pmksa_cache.h b/contrib/wpa_supplicant/pmksa_cache.h
new file mode 100644
index 000000000000..7fe6ff3429f3
--- /dev/null
+++ b/contrib/wpa_supplicant/pmksa_cache.h
@@ -0,0 +1,116 @@
+/*
+ * wpa_supplicant - WPA2/RSN PMKSA cache functions
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef PMKSA_CACHE_H
+#define PMKSA_CACHE_H
+
+/**
+ * struct rsn_pmksa_cache_entry - PMKSA cache entry
+ */
+struct rsn_pmksa_cache_entry {
+ struct rsn_pmksa_cache_entry *next;
+ u8 pmkid[PMKID_LEN];
+ u8 pmk[PMK_LEN];
+ size_t pmk_len;
+ os_time_t expiration;
+ int akmp; /* WPA_KEY_MGMT_* */
+ u8 aa[ETH_ALEN];
+
+ os_time_t reauth_time;
+ struct wpa_ssid *ssid;
+ int opportunistic;
+};
+
+struct rsn_pmksa_cache;
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+ void *ctx, int replace),
+ void *ctx, struct wpa_sm *sm);
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+ const u8 *aa, const u8 *pmkid);
+int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *aa, const u8 *spa, struct wpa_ssid *ssid);
+void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa);
+struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
+void pmksa_cache_clear_current(struct wpa_sm *sm);
+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+ const u8 *bssid, struct wpa_ssid *ssid,
+ int try_opportunistic);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
+ struct wpa_ssid *ssid, const u8 *aa);
+
+#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+static inline struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+ void *ctx, int replace),
+ void *ctx, struct wpa_sm *sm)
+{
+ return (void *) -1;
+}
+
+static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid)
+{
+ return NULL;
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_get_current(struct wpa_sm *sm)
+{
+ return NULL;
+}
+
+static inline int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
+{
+ return -1;
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+ const u8 *aa, const u8 *spa, struct wpa_ssid *ssid)
+{
+ return NULL;
+}
+
+static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
+{
+}
+
+static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
+{
+}
+
+static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+ const u8 *bssid,
+ struct wpa_ssid *ssid,
+ int try_opportunistic)
+{
+ return -1;
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+#endif /* PMKSA_CACHE_H */
diff --git a/contrib/wpa_supplicant/preauth.c b/contrib/wpa_supplicant/preauth.c
index 74a4b0ca747b..4873c49030e2 100644
--- a/contrib/wpa_supplicant/preauth.c
+++ b/contrib/wpa_supplicant/preauth.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant - RSN pre-authentication and PMKSA caching
- * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ * WPA Supplicant - RSN pre-authentication
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,30 +12,21 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <sys/time.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <netinet/in.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-#include <string.h>
-#include <time.h>
+#include "includes.h"
#include "common.h"
-#include "sha1.h"
#include "wpa.h"
#include "driver.h"
#include "eloop.h"
-#include "wpa_supplicant.h"
#include "config.h"
#include "l2_packet.h"
#include "eapol_sm.h"
#include "preauth.h"
+#include "pmksa_cache.h"
#include "wpa_i.h"
#define PMKID_CANDIDATE_PRIO_SCAN 1000
-static const int pmksa_cache_max_entries = 32;
struct rsn_pmksa_candidate {
@@ -46,429 +37,6 @@ struct rsn_pmksa_candidate {
/**
- * rsn_pmkid - Calculate PMK identifier
- * @pmk: Pairwise master key
- * @aa: Authenticator address
- * @spa: Supplicant address
- *
- * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
- * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
- */
-static void rsn_pmkid(const u8 *pmk, const u8 *aa, const u8 *spa, u8 *pmkid)
-{
- char *title = "PMK Name";
- const unsigned char *addr[3];
- const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
- unsigned char hash[SHA1_MAC_LEN];
-
- addr[0] = (unsigned char *) title;
- addr[1] = aa;
- addr[2] = spa;
-
- hmac_sha1_vector(pmk, PMK_LEN, 3, addr, len, hash);
- memcpy(pmkid, hash, PMKID_LEN);
-}
-
-
-static void pmksa_cache_set_expiration(struct wpa_sm *sm);
-
-
-static void pmksa_cache_free_entry(struct wpa_sm *sm,
- struct rsn_pmksa_cache *entry, int replace)
-{
- int current;
-
- current = sm->cur_pmksa == entry ||
- (sm->pmk_len == entry->pmk_len &&
- memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0);
-
- free(entry);
- sm->pmksa_count--;
-
- if (current) {
- wpa_printf(MSG_DEBUG, "RSN: removed current PMKSA entry");
- sm->cur_pmksa = NULL;
-
- if (replace) {
- /* A new entry is being added, so no need to
- * deauthenticate in this case. This happens when EAP
- * authentication is completed again (reauth or failed
- * PMKSA caching attempt). */
- return;
- }
-
- memset(sm->pmk, 0, sizeof(sm->pmk));
- wpa_sm_deauthenticate(sm, REASON_UNSPECIFIED);
- wpa_sm_req_scan(sm, 0, 0);
- }
-}
-
-
-static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_sm *sm = eloop_ctx;
- time_t now;
-
- time(&now);
- while (sm->pmksa && sm->pmksa->expiration <= now) {
- struct rsn_pmksa_cache *entry = sm->pmksa;
- sm->pmksa = entry->next;
- wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
- MACSTR, MAC2STR(entry->aa));
- pmksa_cache_free_entry(sm, entry, 0);
- }
-
- pmksa_cache_set_expiration(sm);
-}
-
-
-static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
-{
- struct wpa_sm *sm = eloop_ctx;
- sm->cur_pmksa = NULL;
- eapol_sm_request_reauth(sm->eapol);
-}
-
-
-static void pmksa_cache_set_expiration(struct wpa_sm *sm)
-{
- int sec;
- struct rsn_pmksa_cache *entry;
-
- eloop_cancel_timeout(pmksa_cache_expire, sm, NULL);
- eloop_cancel_timeout(pmksa_cache_reauth, sm, NULL);
- if (sm->pmksa == NULL)
- return;
- sec = sm->pmksa->expiration - time(NULL);
- if (sec < 0)
- sec = 0;
- eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, sm, NULL);
-
- entry = sm->cur_pmksa ? sm->cur_pmksa :
- pmksa_cache_get(sm, sm->bssid, NULL);
- if (entry) {
- sec = sm->pmksa->reauth_time - time(NULL);
- if (sec < 0)
- sec = 0;
- eloop_register_timeout(sec, 0, pmksa_cache_reauth, sm, NULL);
- }
-}
-
-
-/**
- * pmksa_cache_add - Add a PMKSA cache entry
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @pmk: The new pairwise master key
- * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
- * @aa: Authenticator address
- * @spa: Supplicant address
- * @ssid: The network configuration for which this PMK is being added
- * Returns: Pointer to the added PMKSA cache entry or %NULL on error
- *
- * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
- * cache. If an old entry is already in the cache for the same Authenticator,
- * this entry will be replaced with the new entry. PMKID will be calculated
- * based on the PMK and the driver interface is notified of the new PMKID.
- */
-struct rsn_pmksa_cache *
-pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk,
- size_t pmk_len, const u8 *aa, const u8 *spa,
- struct wpa_ssid *ssid)
-{
- struct rsn_pmksa_cache *entry, *pos, *prev;
- time_t now;
-
- if (sm->proto != WPA_PROTO_RSN || pmk_len > PMK_LEN)
- return NULL;
-
- entry = malloc(sizeof(*entry));
- if (entry == NULL)
- return NULL;
- memset(entry, 0, sizeof(*entry));
- memcpy(entry->pmk, pmk, pmk_len);
- entry->pmk_len = pmk_len;
- rsn_pmkid(pmk, aa, spa, entry->pmkid);
- now = time(NULL);
- entry->expiration = now + sm->dot11RSNAConfigPMKLifetime;
- entry->reauth_time = now + sm->dot11RSNAConfigPMKLifetime *
- sm->dot11RSNAConfigPMKReauthThreshold / 100;
- entry->akmp = WPA_KEY_MGMT_IEEE8021X;
- memcpy(entry->aa, aa, ETH_ALEN);
- entry->ssid = ssid;
-
- /* Replace an old entry for the same Authenticator (if found) with the
- * new entry */
- pos = sm->pmksa;
- prev = NULL;
- while (pos) {
- if (memcmp(aa, pos->aa, ETH_ALEN) == 0) {
- if (pos->pmk_len == pmk_len &&
- memcmp(pos->pmk, pmk, pmk_len) == 0 &&
- memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) == 0) {
- wpa_printf(MSG_DEBUG, "WPA: reusing previous "
- "PMKSA entry");
- free(entry);
- return pos;
- }
- if (prev == NULL)
- sm->pmksa = pos->next;
- else
- prev->next = pos->next;
- wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
- "the current AP");
- pmksa_cache_free_entry(sm, pos, 1);
- break;
- }
- prev = pos;
- pos = pos->next;
- }
-
- if (sm->pmksa_count >= pmksa_cache_max_entries && sm->pmksa) {
- /* Remove the oldest entry to make room for the new entry */
- pos = sm->pmksa;
- sm->pmksa = pos->next;
- wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
- "entry (for " MACSTR ") to make room for new one",
- MAC2STR(pos->aa));
- wpa_sm_remove_pmkid(sm, pos->aa, pos->pmkid);
- pmksa_cache_free_entry(sm, pos, 0);
- }
-
- /* Add the new entry; order by expiration time */
- pos = sm->pmksa;
- prev = NULL;
- while (pos) {
- if (pos->expiration > entry->expiration)
- break;
- prev = pos;
- pos = pos->next;
- }
- if (prev == NULL) {
- entry->next = sm->pmksa;
- sm->pmksa = entry;
- pmksa_cache_set_expiration(sm);
- } else {
- entry->next = prev->next;
- prev->next = entry;
- }
- sm->pmksa_count++;
- wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
- MAC2STR(entry->aa));
- wpa_sm_add_pmkid(sm, entry->aa, entry->pmkid);
-
- return entry;
-}
-
-
-/**
- * pmksa_cache_free - Free all entries in PMKSA cache
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- */
-void pmksa_cache_free(struct wpa_sm *sm)
-{
- struct rsn_pmksa_cache *entry, *prev;
-
- if (sm == NULL)
- return;
-
- entry = sm->pmksa;
- sm->pmksa = NULL;
- while (entry) {
- prev = entry;
- entry = entry->next;
- free(prev);
- }
- pmksa_cache_set_expiration(sm);
- sm->cur_pmksa = NULL;
-}
-
-
-/**
- * pmksa_cache_get - Fetch a PMKSA cache entry
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @aa: Authenticator address or %NULL to match any
- * @pmkid: PMKID or %NULL to match any
- * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
- */
-struct rsn_pmksa_cache * pmksa_cache_get(struct wpa_sm *sm,
- const u8 *aa, const u8 *pmkid)
-{
- struct rsn_pmksa_cache *entry = sm->pmksa;
- while (entry) {
- if ((aa == NULL || memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
- (pmkid == NULL ||
- memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
- return entry;
- entry = entry->next;
- }
- return NULL;
-}
-
-
-/**
- * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- *
- * Clear references to old data structures when wpa_supplicant is reconfigured.
- */
-void pmksa_cache_notify_reconfig(struct wpa_sm *sm)
-{
- struct rsn_pmksa_cache *entry = sm->pmksa;
- while (entry) {
- entry->ssid = NULL;
- entry = entry->next;
- }
-}
-
-
-static struct rsn_pmksa_cache *
-pmksa_cache_clone_entry(struct wpa_sm *sm,
- const struct rsn_pmksa_cache *old_entry, const u8 *aa)
-{
- struct rsn_pmksa_cache *new_entry;
-
- new_entry = pmksa_cache_add(sm, old_entry->pmk, old_entry->pmk_len,
- aa, sm->own_addr, old_entry->ssid);
- if (new_entry == NULL)
- return NULL;
-
- /* TODO: reorder entries based on expiration time? */
- new_entry->expiration = old_entry->expiration;
- new_entry->opportunistic = 1;
-
- return new_entry;
-}
-
-
-/**
- * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @ssid: Pointer to the current network configuration
- * @aa: Authenticator address for the new AP
- * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
- *
- * Try to create a new PMKSA cache entry opportunistically by guessing that the
- * new AP is sharing the same PMK as another AP that has the same SSID and has
- * already an entry in PMKSA cache.
- */
-static struct rsn_pmksa_cache *
-pmksa_cache_get_opportunistic(struct wpa_sm *sm,
- struct wpa_ssid *ssid, const u8 *aa)
-{
- struct rsn_pmksa_cache *entry = sm->pmksa;
-
- if (ssid == NULL)
- return NULL;
- while (entry) {
- if (entry->ssid == ssid) {
- entry = pmksa_cache_clone_entry(sm, entry, aa);
- if (entry) {
- wpa_printf(MSG_DEBUG, "RSN: added "
- "opportunistic PMKSA cache entry "
- "for " MACSTR, MAC2STR(aa));
- }
- return entry;
- }
- entry = entry->next;
- }
- return NULL;
-}
-
-
-/**
- * pmksa_cache_get_current - Get the current used PMKSA entry
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
- */
-struct rsn_pmksa_cache * pmksa_cache_get_current(struct wpa_sm *sm)
-{
- if (sm == NULL)
- return NULL;
- return sm->cur_pmksa;
-}
-
-
-/**
- * pmksa_cache_clear_current - Clear the current PMKSA entry selection
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- */
-void pmksa_cache_clear_current(struct wpa_sm *sm)
-{
- if (sm == NULL)
- return;
- sm->cur_pmksa = NULL;
-}
-
-
-/**
- * pmksa_cache_set_current - Set the current PMKSA entry selection
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @pmkid: PMKID for selecting PMKSA or %NULL if not used
- * @bssid: BSSID for PMKSA or %NULL if not used
- * @ssid: The network configuration for the current network
- * @try_opportunistic: Whether to allow opportunistic PMKSA caching
- * Returns: 0 if PMKSA was found or -1 if no matching entry was found
- */
-int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
- const u8 *bssid, struct wpa_ssid *ssid,
- int try_opportunistic)
-{
- sm->cur_pmksa = NULL;
- if (pmkid)
- sm->cur_pmksa = pmksa_cache_get(sm, NULL, pmkid);
- if (sm->cur_pmksa == NULL && bssid)
- sm->cur_pmksa = pmksa_cache_get(sm, bssid, NULL);
- if (sm->cur_pmksa == NULL && try_opportunistic)
- sm->cur_pmksa = pmksa_cache_get_opportunistic(sm, ssid, bssid);
- if (sm->cur_pmksa) {
- wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
- sm->cur_pmksa->pmkid, PMKID_LEN);
- return 0;
- }
- return -1;
-}
-
-
-/**
- * pmksa_cache_list - Dump text list of entries in PMKSA cache
- * @sm: Pointer to WPA state machine data from wpa_sm_init()
- * @buf: Buffer for the list
- * @len: Length of the buffer
- * Returns: number of bytes written to buffer
- *
- * This function is used to generate a text format representation of the
- * current PMKSA cache contents for the ctrl_iface PMKSA command.
- */
-int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
-{
- int i, j;
- char *pos = buf;
- struct rsn_pmksa_cache *entry;
- time_t now;
-
- time(&now);
- pos += snprintf(pos, buf + len - pos,
- "Index / AA / PMKID / expiration (in seconds) / "
- "opportunistic\n");
- i = 0;
- entry = sm->pmksa;
- while (entry) {
- i++;
- pos += snprintf(pos, buf + len - pos, "%d " MACSTR " ",
- i, MAC2STR(entry->aa));
- for (j = 0; j < PMKID_LEN; j++)
- pos += snprintf(pos, buf + len - pos, "%02x",
- entry->pmkid[j]);
- pos += snprintf(pos, buf + len - pos, " %d %d\n",
- (int) (entry->expiration - now),
- entry->opportunistic);
- entry = entry->next;
- }
- return pos - buf;
-}
-
-
-/**
* pmksa_candidate_free - Free all entries in PMKSA candidate list
* @sm: Pointer to WPA state machine data from wpa_sm_init()
*/
@@ -484,12 +52,12 @@ void pmksa_candidate_free(struct wpa_sm *sm)
while (entry) {
prev = entry;
entry = entry->next;
- free(prev);
+ os_free(prev);
}
}
-#ifdef IEEE8021X_EAPOL
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
const u8 *buf, size_t len)
@@ -500,9 +68,9 @@ static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
if (sm->preauth_eapol == NULL ||
- memcmp(sm->preauth_bssid, "\x00\x00\x00\x00\x00\x00",
- ETH_ALEN) == 0 ||
- memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
+ os_memcmp(sm->preauth_bssid, "\x00\x00\x00\x00\x00\x00",
+ ETH_ALEN) == 0 ||
+ os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
"unexpected source " MACSTR " - dropped",
MAC2STR(src_addr));
@@ -523,17 +91,19 @@ static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
int res, pmk_len;
pmk_len = PMK_LEN;
res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
-#ifdef EAP_LEAP
if (res) {
+ /*
+ * EAP-LEAP is an exception from other EAP methods: it
+ * uses only 16-byte PMK.
+ */
res = eapol_sm_get_key(eapol, pmk, 16);
pmk_len = 16;
}
-#endif /* EAP_LEAP */
if (res == 0) {
wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth",
pmk, pmk_len);
sm->pmk_len = pmk_len;
- pmksa_cache_add(sm, pmk, pmk_len,
+ pmksa_cache_add(sm->pmksa, pmk, pmk_len,
sm->preauth_bssid, sm->own_addr,
sm->cur_ssid);
} else {
@@ -585,7 +155,7 @@ static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid,
ETH_P_RSN_PREAUTH, msg, msglen);
- free(msg);
+ os_free(msg);
return res;
}
@@ -624,12 +194,24 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, struct wpa_ssid *config)
return -2;
}
- ctx = malloc(sizeof(*ctx));
+ if (sm->bridge_ifname) {
+ sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname,
+ sm->own_addr,
+ ETH_P_RSN_PREAUTH,
+ rsn_preauth_receive, sm, 0);
+ if (sm->l2_preauth_br == NULL) {
+ wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
+ "packet processing (bridge) for "
+ "pre-authentication");
+ return -2;
+ }
+ }
+
+ ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL) {
wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
return -4;
}
- memset(ctx, 0, sizeof(*ctx));
ctx->ctx = sm->ctx->ctx;
ctx->msg_ctx = sm->ctx->ctx;
ctx->preauth = 1;
@@ -643,12 +225,12 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, struct wpa_ssid *config)
sm->preauth_eapol = eapol_sm_init(ctx);
if (sm->preauth_eapol == NULL) {
- free(ctx);
+ os_free(ctx);
wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
"state machines for pre-authentication");
return -3;
}
- memset(&eapol_conf, 0, sizeof(eapol_conf));
+ os_memset(&eapol_conf, 0, sizeof(eapol_conf));
eapol_conf.accept_802_1x_keys = 0;
eapol_conf.required_keys = 0;
eapol_conf.fast_reauth = sm->fast_reauth;
@@ -662,7 +244,7 @@ int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, struct wpa_ssid *config)
* after the 4-Way Handshake.
*/
eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
- memcpy(sm->preauth_bssid, dst, ETH_ALEN);
+ os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
/* 802.1X::portControl = Auto */
@@ -690,10 +272,14 @@ void rsn_preauth_deinit(struct wpa_sm *sm)
eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL);
eapol_sm_deinit(sm->preauth_eapol);
sm->preauth_eapol = NULL;
- memset(sm->preauth_bssid, 0, ETH_ALEN);
+ os_memset(sm->preauth_bssid, 0, ETH_ALEN);
l2_packet_deinit(sm->l2_preauth);
sm->l2_preauth = NULL;
+ if (sm->l2_preauth_br) {
+ l2_packet_deinit(sm->l2_preauth_br);
+ sm->l2_preauth_br = NULL;
+ }
}
@@ -726,10 +312,10 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
}
while (sm->pmksa_candidates) {
- struct rsn_pmksa_cache *p = NULL;
+ struct rsn_pmksa_cache_entry *p = NULL;
candidate = sm->pmksa_candidates;
- p = pmksa_cache_get(sm, candidate->bssid, NULL);
- if (memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
+ p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL);
+ if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
(p == NULL || p->opportunistic)) {
wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA "
"candidate " MACSTR
@@ -737,7 +323,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
MAC2STR(candidate->bssid));
sm->pmksa_candidates = candidate->next;
rsn_preauth_init(sm, candidate->bssid, sm->cur_ssid);
- free(candidate);
+ os_free(candidate);
return;
}
wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA candidate "
@@ -750,7 +336,7 @@ void rsn_preauth_candidate_process(struct wpa_sm *sm)
}
sm->pmksa_candidates = candidate->next;
- free(candidate);
+ os_free(candidate);
}
wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
"candidates");
@@ -774,7 +360,7 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
struct rsn_pmksa_candidate *cand, *prev, *pos;
if (sm->cur_ssid && sm->cur_ssid->proactive_key_caching)
- pmksa_cache_get_opportunistic(sm, sm->cur_ssid, bssid);
+ pmksa_cache_get_opportunistic(sm->pmksa, sm->cur_ssid, bssid);
if (!preauth) {
wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
@@ -787,7 +373,7 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
prev = NULL;
cand = sm->pmksa_candidates;
while (cand) {
- if (memcmp(cand->bssid, bssid, ETH_ALEN) == 0) {
+ if (os_memcmp(cand->bssid, bssid, ETH_ALEN) == 0) {
if (prev)
prev->next = cand->next;
else
@@ -802,11 +388,10 @@ void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
if (prio < PMKID_CANDIDATE_PRIO_SCAN)
cand->priority = prio;
} else {
- cand = malloc(sizeof(*cand));
+ cand = os_zalloc(sizeof(*cand));
if (cand == NULL)
return;
- memset(cand, 0, sizeof(*cand));
- memcpy(cand->bssid, bssid, ETH_ALEN);
+ os_memcpy(cand->bssid, bssid, ETH_ALEN);
cand->priority = prio;
}
@@ -849,7 +434,7 @@ void rsn_preauth_scan_results(struct wpa_sm *sm,
struct wpa_scan_result *r;
struct wpa_ie_data ie;
int i;
- struct rsn_pmksa_cache *pmksa;
+ struct rsn_pmksa_cache_entry *pmksa;
if (sm->cur_ssid == NULL)
return;
@@ -863,18 +448,18 @@ void rsn_preauth_scan_results(struct wpa_sm *sm,
for (i = count - 1; i >= 0; i--) {
r = &results[i];
if (r->ssid_len != sm->cur_ssid->ssid_len ||
- memcmp(r->ssid, sm->cur_ssid->ssid,
- r->ssid_len) != 0)
+ os_memcmp(r->ssid, sm->cur_ssid->ssid,
+ r->ssid_len) != 0)
continue;
- if (memcmp(r->bssid, sm->bssid, ETH_ALEN) == 0)
+ if (os_memcmp(r->bssid, sm->bssid, ETH_ALEN) == 0)
continue;
if (r->rsn_ie_len == 0 ||
wpa_parse_wpa_ie(r->rsn_ie, r->rsn_ie_len, &ie))
continue;
- pmksa = pmksa_cache_get(sm, r->bssid, NULL);
+ pmksa = pmksa_cache_get(sm->pmksa, r->bssid, NULL);
if (pmksa &&
(!pmksa->opportunistic ||
!(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
@@ -891,6 +476,7 @@ void rsn_preauth_scan_results(struct wpa_sm *sm,
}
+#ifdef CONFIG_CTRL_IFACE
/**
* rsn_preauth_get_status - Get pre-authentication status
* @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -907,11 +493,14 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose)
{
char *pos = buf, *end = buf + buflen;
- int res;
+ int res, ret;
if (sm->preauth_eapol) {
- pos += snprintf(pos, end - pos, "Pre-authentication "
- "EAPOL state machines:\n");
+ ret = os_snprintf(pos, end - pos, "Pre-authentication "
+ "EAPOL state machines:\n");
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
res = eapol_sm_get_status(sm->preauth_eapol,
pos, end - pos, verbose);
if (res >= 0)
@@ -920,6 +509,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
return pos - buf;
}
+#endif /* CONFIG_CTRL_IFACE */
/**
@@ -931,4 +521,4 @@ int rsn_preauth_in_progress(struct wpa_sm *sm)
return sm->preauth_eapol != NULL;
}
-#endif /* IEEE8021X_EAPOL */
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
diff --git a/contrib/wpa_supplicant/preauth.h b/contrib/wpa_supplicant/preauth.h
index 9b528f070b9c..07e3e006622a 100644
--- a/contrib/wpa_supplicant/preauth.h
+++ b/contrib/wpa_supplicant/preauth.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA2/RSN pre-authentication functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,63 +19,18 @@ struct wpa_scan_result;
#ifndef CONFIG_NO_WPA
-void pmksa_cache_free(struct wpa_sm *sm);
-struct rsn_pmksa_cache * pmksa_cache_get(struct wpa_sm *sm,
- const u8 *aa, const u8 *pmkid);
-int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
void pmksa_candidate_free(struct wpa_sm *sm);
-struct rsn_pmksa_cache *
-pmksa_cache_add(struct wpa_sm *sm, const u8 *pmk,
- size_t pmk_len, const u8 *aa, const u8 *spa,
- struct wpa_ssid *ssid);
-void pmksa_cache_notify_reconfig(struct wpa_sm *sm);
-struct rsn_pmksa_cache * pmksa_cache_get_current(struct wpa_sm *sm);
-void pmksa_cache_clear_current(struct wpa_sm *sm);
-int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
- const u8 *bssid, struct wpa_ssid *ssid,
- int try_opportunistic);
#else /* CONFIG_NO_WPA */
-static inline void pmksa_cache_free(struct wpa_sm *sm)
-{
-}
-
static inline void pmksa_candidate_free(struct wpa_sm *sm)
{
}
-static inline void pmksa_cache_notify_reconfig(struct wpa_sm *sm)
-{
-}
-
-static inline struct rsn_pmksa_cache *
-pmksa_cache_get_current(struct wpa_sm *sm)
-{
- return NULL;
-}
-
-static inline int pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
-{
- return -1;
-}
-
-static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
-{
-}
-
-static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
- const u8 *bssid,
- struct wpa_ssid *ssid,
- int try_opportunistic)
-{
- return -1;
-}
-
#endif /* CONFIG_NO_WPA */
-#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA)
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
struct wpa_ssid *config);
@@ -89,7 +44,7 @@ int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose);
int rsn_preauth_in_progress(struct wpa_sm *sm);
-#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA */
+#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
static inline void rsn_preauth_candidate_process(struct wpa_sm *sm)
{
@@ -127,6 +82,6 @@ static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
return 0;
}
-#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA */
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
#endif /* PREAUTH_H */
diff --git a/contrib/wpa_supplicant/preauth_test.c b/contrib/wpa_supplicant/preauth_test.c
index d89058d555e1..bd31d8b443e9 100644
--- a/contrib/wpa_supplicant/preauth_test.c
+++ b/contrib/wpa_supplicant/preauth_test.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - test code for pre-authentication
- * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,15 +15,8 @@
* Not used in production version.
*/
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-#include <signal.h>
-#include <netinet/in.h>
+#include "includes.h"
#include <assert.h>
-#include <arpa/inet.h>
#include "common.h"
#include "config.h"
@@ -37,12 +30,13 @@
#include "ctrl_iface.h"
#include "pcsc_funcs.h"
#include "preauth.h"
+#include "pmksa_cache.h"
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
-struct wpa_driver_ops *wpa_supplicant_drivers[] = { };
+struct wpa_driver_ops *wpa_supplicant_drivers[] = { NULL };
struct preauth_test_data {
@@ -75,7 +69,7 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
struct ieee802_1x_hdr *hdr;
*msg_len = sizeof(*hdr) + data_len;
- hdr = malloc(*msg_len);
+ hdr = os_malloc(*msg_len);
if (hdr == NULL)
return NULL;
@@ -84,9 +78,9 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
hdr->length = htons(data_len);
if (data)
- memcpy(hdr + 1, data, data_len);
+ os_memcpy(hdr + 1, data, data_len);
else
- memset(hdr + 1, 0, data_len);
+ os_memset(hdr + 1, 0, data_len);
if (data_pos)
*data_pos = hdr + 1;
@@ -167,6 +161,15 @@ static int wpa_supplicant_set_key(void *wpa_s, wpa_alg alg,
}
+static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
+ int protection_type,
+ int key_type)
+{
+ printf("%s - not implemented\n", __func__);
+ return -1;
+}
+
+
static int wpa_supplicant_add_pmkid(void *wpa_s,
const u8 *bssid, const u8 *pmkid)
{
@@ -203,10 +206,12 @@ static void test_eapol_clean(struct wpa_supplicant *wpa_s)
{
rsn_preauth_deinit(wpa_s->wpa);
pmksa_candidate_free(wpa_s->wpa);
- pmksa_cache_free(wpa_s->wpa);
wpa_sm_deinit(wpa_s->wpa);
scard_deinit(wpa_s->scard);
- wpa_supplicant_ctrl_iface_deinit(wpa_s);
+ if (wpa_s->ctrl_iface) {
+ wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
+ }
wpa_config_free(wpa_s->conf);
}
@@ -240,13 +245,12 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
struct l2_packet_data *l2;
struct wpa_sm_ctx *ctx;
- memset(&dummy_driver, 0, sizeof(dummy_driver));
+ os_memset(&dummy_driver, 0, sizeof(dummy_driver));
wpa_s->driver = &dummy_driver;
- ctx = malloc(sizeof(*ctx));
+ ctx = os_zalloc(sizeof(*ctx));
assert(ctx != NULL);
- memset(ctx, 0, sizeof(*ctx));
ctx->ctx = wpa_s;
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
@@ -265,13 +269,14 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
+ ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
wpa_s->wpa = wpa_sm_init(ctx);
assert(wpa_s->wpa != NULL);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, WPA_PROTO_RSN);
- strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
- wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname);
+ os_strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+ wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname, NULL);
l2 = l2_packet_init(wpa_s->ifname, NULL, ETH_P_RSN_PREAUTH, NULL,
NULL, 0);
@@ -301,7 +306,10 @@ int main(int argc, char *argv[])
u8 bssid[ETH_ALEN];
struct preauth_test_data preauth_test;
- memset(&preauth_test, 0, sizeof(preauth_test));
+ if (os_program_init())
+ return -1;
+
+ os_memset(&preauth_test, 0, sizeof(preauth_test));
wpa_debug_level = 0;
wpa_debug_show_keys = 1;
@@ -317,9 +325,17 @@ int main(int argc, char *argv[])
return -1;
}
- eloop_init(&wpa_s);
+ if (eap_peer_register_methods()) {
+ wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+ return -1;
+ }
+
+ if (eloop_init(&wpa_s)) {
+ wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+ return -1;
+ }
- memset(&wpa_s, 0, sizeof(wpa_s));
+ os_memset(&wpa_s, 0, sizeof(wpa_s));
wpa_s.conf = wpa_config_read(argv[1]);
if (wpa_s.conf == NULL) {
printf("Failed to parse configuration file '%s'.\n", argv[1]);
@@ -331,7 +347,8 @@ int main(int argc, char *argv[])
}
wpa_init_conf(&wpa_s, argv[3]);
- if (wpa_supplicant_ctrl_iface_init(&wpa_s)) {
+ wpa_s.ctrl_iface = wpa_supplicant_ctrl_iface_init(&wpa_s);
+ if (wpa_s.ctrl_iface == NULL) {
printf("Failed to initialize control interface '%s'.\n"
"You may have another preauth_test process already "
"running or the file was\n"
@@ -350,20 +367,24 @@ int main(int argc, char *argv[])
eloop_register_timeout(30, 0, eapol_test_timeout, &preauth_test, NULL);
eloop_register_timeout(0, 100000, eapol_test_poll, &wpa_s, NULL);
- eloop_register_signal(SIGINT, eapol_test_terminate, NULL);
- eloop_register_signal(SIGTERM, eapol_test_terminate, NULL);
- eloop_register_signal(SIGHUP, eapol_test_terminate, NULL);
+ eloop_register_signal_terminate(eapol_test_terminate, NULL);
+ eloop_register_signal_reconfig(eapol_test_terminate, NULL);
eloop_run();
if (preauth_test.auth_timed_out)
ret = -2;
else {
- ret = pmksa_cache_get(wpa_s.wpa, bssid, NULL) ? 0 : -3;
+ ret = pmksa_cache_set_current(wpa_s.wpa, NULL, bssid, NULL, 0)
+ ? 0 : -3;
}
test_eapol_clean(&wpa_s);
+ eap_peer_unregister_methods();
+
eloop_destroy();
+ os_program_deinit();
+
return ret;
}
diff --git a/contrib/wpa_supplicant/radius.c b/contrib/wpa_supplicant/radius.c
index ce79a62c141c..bf39b2fc42e8 100644
--- a/contrib/wpa_supplicant/radius.c
+++ b/contrib/wpa_supplicant/radius.c
@@ -1,7 +1,6 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / RADIUS client
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / RADIUS message processing
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,18 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/time.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <netinet/in.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
#include "common.h"
#include "radius.h"
@@ -36,12 +24,12 @@ struct radius_msg *radius_msg_new(u8 code, u8 identifier)
{
struct radius_msg *msg;
- msg = (struct radius_msg *) malloc(sizeof(*msg));
+ msg = os_malloc(sizeof(*msg));
if (msg == NULL)
return NULL;
if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {
- free(msg);
+ os_free(msg);
return NULL;
}
@@ -56,20 +44,19 @@ int radius_msg_initialize(struct radius_msg *msg, size_t init_len)
if (msg == NULL || init_len < sizeof(struct radius_hdr))
return -1;
- memset(msg, 0, sizeof(*msg));
- msg->buf = (unsigned char *) malloc(init_len);
+ os_memset(msg, 0, sizeof(*msg));
+ msg->buf = wpa_zalloc(init_len);
if (msg->buf == NULL)
return -1;
- memset(msg->buf, 0, init_len);
msg->buf_size = init_len;
msg->hdr = (struct radius_hdr *) msg->buf;
msg->buf_used = sizeof(*msg->hdr);
- msg->attrs = (struct radius_attr_hdr **)
- malloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attrs));
+ msg->attrs =
+ os_malloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attrs));
if (msg->attrs == NULL) {
- free(msg->buf);
+ os_free(msg->buf);
msg->buf = NULL;
msg->hdr = NULL;
return -1;
@@ -92,14 +79,14 @@ void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
void radius_msg_free(struct radius_msg *msg)
{
if (msg->buf != NULL) {
- free(msg->buf);
+ os_free(msg->buf);
msg->buf = NULL;
msg->hdr = NULL;
}
msg->buf_size = msg->buf_used = 0;
if (msg->attrs != NULL) {
- free(msg->attrs);
+ os_free(msg->attrs);
msg->attrs = NULL;
}
msg->attr_size = msg->attr_used = 0;
@@ -178,10 +165,15 @@ static struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
+ { RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
+ RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
RADIUS_ATTR_UNDIST },
+ { RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
+ RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
RADIUS_ATTR_INT32 },
{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
@@ -191,7 +183,7 @@ static struct radius_attr_type radius_attrs[] =
static struct radius_attr_type *radius_get_attr_type(u8 type)
{
- int i;
+ size_t i;
for (i = 0; i < RADIUS_ATTRS; i++) {
if (type == radius_attrs[i].type)
@@ -202,6 +194,15 @@ static struct radius_attr_type *radius_get_attr_type(u8 type)
}
+static void print_char(char c)
+{
+ if (c >= 32 && c < 127)
+ printf("%c", c);
+ else
+ printf("<%02x>", c);
+}
+
+
static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
{
struct radius_attr_type *attr;
@@ -257,11 +258,9 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
break;
case RADIUS_ATTR_INT32:
- if (len == 4) {
- u32 *val = (u32 *) pos;
- printf(" Value: %u\n",
- (unsigned int) ntohl(*val));
- } else
+ if (len == 4)
+ printf(" Value: %u\n", WPA_GET_BE32(pos));
+ else
printf(" Invalid INT32 length %d\n", len);
break;
@@ -273,7 +272,7 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
void radius_msg_dump(struct radius_msg *msg)
{
- int i;
+ size_t i;
printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
msg->hdr->code, radius_code_string(msg->hdr->code),
@@ -291,7 +290,7 @@ int radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len)
u8 auth[MD5_MAC_LEN];
struct radius_attr_hdr *attr;
- memset(auth, 0, MD5_MAC_LEN);
+ os_memset(auth, 0, MD5_MAC_LEN);
attr = radius_msg_add_attr(msg,
RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
auth, MD5_MAC_LEN);
@@ -323,7 +322,7 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
const u8 *addr[4];
size_t len[4];
- memset(auth, 0, MD5_MAC_LEN);
+ os_memset(auth, 0, MD5_MAC_LEN);
attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
auth, MD5_MAC_LEN);
if (attr == NULL) {
@@ -331,8 +330,8 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
return -1;
}
msg->hdr->length = htons(msg->buf_used);
- memcpy(msg->hdr->authenticator, req_authenticator,
- sizeof(msg->hdr->authenticator));
+ os_memcpy(msg->hdr->authenticator, req_authenticator,
+ sizeof(msg->hdr->authenticator));
hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
(u8 *) (attr + 1));
@@ -363,7 +362,7 @@ void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
size_t len[2];
msg->hdr->length = htons(msg->buf_used);
- memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
+ os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
addr[0] = msg->buf;
len[0] = msg->buf_used;
addr[1] = secret;
@@ -384,9 +383,7 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg,
struct radius_attr_hdr **nattrs;
int nlen = msg->attr_size * 2;
- nattrs = (struct radius_attr_hdr **)
- realloc(msg->attrs, nlen * sizeof(*msg->attrs));
-
+ nattrs = os_realloc(msg->attrs, nlen * sizeof(*msg->attrs));
if (nattrs == NULL)
return -1;
@@ -417,12 +414,12 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
if (msg->buf_size < buf_needed) {
/* allocate more space for message buffer */
unsigned char *nbuf;
- int nlen = msg->buf_size;
- int diff, i;
+ size_t i, nlen = msg->buf_size;
+ int diff;
while (nlen < buf_needed)
nlen *= 2;
- nbuf = (unsigned char *) realloc(msg->buf, nlen);
+ nbuf = os_realloc(msg->buf, nlen);
if (nbuf == NULL)
return NULL;
diff = nbuf - msg->buf;
@@ -432,7 +429,7 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
for (i = 0; i < msg->attr_used; i++)
msg->attrs[i] = (struct radius_attr_hdr *)
(((u8 *) msg->attrs[i]) + diff);
- memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
+ os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
msg->buf_size = nlen;
}
@@ -440,7 +437,7 @@ struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
attr->type = type;
attr->length = sizeof(*attr) + data_len;
if (data_len > 0)
- memcpy(attr + 1, data, data_len);
+ os_memcpy(attr + 1, data, data_len);
msg->buf_used += sizeof(*attr) + data_len;
@@ -475,23 +472,23 @@ struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
(unsigned long) len - msg_len);
}
- msg = (struct radius_msg *) malloc(sizeof(*msg));
+ msg = os_malloc(sizeof(*msg));
if (msg == NULL)
return NULL;
if (radius_msg_initialize(msg, msg_len)) {
- free(msg);
+ os_free(msg);
return NULL;
}
- memcpy(msg->buf, data, msg_len);
+ os_memcpy(msg->buf, data, msg_len);
msg->buf_size = msg->buf_used = msg_len;
/* parse attributes */
pos = (unsigned char *) (msg->hdr + 1);
end = msg->buf + msg->buf_used;
while (pos < end) {
- if (end - pos < sizeof(*attr))
+ if ((size_t) (end - pos) < sizeof(*attr))
goto fail;
attr = (struct radius_attr_hdr *) pos;
@@ -511,7 +508,7 @@ struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
fail:
radius_msg_free(msg);
- free(msg);
+ os_free(msg);
return NULL;
}
@@ -543,8 +540,7 @@ int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
{
u8 *eap, *pos;
- size_t len;
- int i;
+ size_t len, i;
if (msg == NULL)
return NULL;
@@ -559,7 +555,7 @@ u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
if (len == 0)
return NULL;
- eap = malloc(len);
+ eap = os_malloc(len);
if (eap == NULL)
return NULL;
@@ -568,7 +564,7 @@ u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
if (msg->attrs[i]->type == RADIUS_ATTR_EAP_MESSAGE) {
struct radius_attr_hdr *attr = msg->attrs[i];
int flen = attr->length - sizeof(*attr);
- memcpy(pos, attr + 1, flen);
+ os_memcpy(pos, attr + 1, flen);
pos += flen;
}
}
@@ -586,7 +582,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
u8 orig_authenticator[16];
struct radius_attr_hdr *attr = NULL;
- int i;
+ size_t i;
for (i = 0; i < msg->attr_used; i++) {
if (msg->attrs[i]->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
@@ -604,22 +600,22 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
return 1;
}
- memcpy(orig, attr + 1, MD5_MAC_LEN);
- memset(attr + 1, 0, MD5_MAC_LEN);
+ os_memcpy(orig, attr + 1, MD5_MAC_LEN);
+ os_memset(attr + 1, 0, MD5_MAC_LEN);
if (req_auth) {
- memcpy(orig_authenticator, msg->hdr->authenticator,
- sizeof(orig_authenticator));
- memcpy(msg->hdr->authenticator, req_auth,
- sizeof(msg->hdr->authenticator));
+ os_memcpy(orig_authenticator, msg->hdr->authenticator,
+ sizeof(orig_authenticator));
+ os_memcpy(msg->hdr->authenticator, req_auth,
+ sizeof(msg->hdr->authenticator));
}
hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
- memcpy(attr + 1, orig, MD5_MAC_LEN);
+ os_memcpy(attr + 1, orig, MD5_MAC_LEN);
if (req_auth) {
- memcpy(msg->hdr->authenticator, orig_authenticator,
- sizeof(orig_authenticator));
+ os_memcpy(msg->hdr->authenticator, orig_authenticator,
+ sizeof(orig_authenticator));
}
- if (memcmp(orig, auth, MD5_MAC_LEN) != 0) {
+ if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
printf("Invalid Message-Authenticator!\n");
return 1;
}
@@ -656,13 +652,12 @@ int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
addr[3] = secret;
len[3] = secret_len;
md5_vector(4, addr, len, hash);
- if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+ if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
printf("Response Authenticator invalid!\n");
return 1;
}
return 0;
-
}
@@ -670,7 +665,7 @@ int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
u8 type)
{
struct radius_attr_hdr *attr = NULL;
- int i;
+ size_t i;
for (i = 0; i < src->attr_used; i++) {
if (src->attrs[i]->type == type) {
@@ -695,15 +690,15 @@ int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
* Use one-way MD5 hash calculated from current timestamp and some data given
* by the caller. */
void radius_msg_make_authenticator(struct radius_msg *msg,
- u8 *data, size_t len)
+ const u8 *data, size_t len)
{
- struct timeval tv;
+ struct os_time tv;
long int l;
const u8 *addr[3];
size_t elen[3];
- gettimeofday(&tv, NULL);
- l = random();
+ os_get_time(&tv);
+ l = os_random();
addr[0] = (u8 *) &tv;
elen[0] = sizeof(tv);
addr[1] = data;
@@ -717,21 +712,21 @@ void radius_msg_make_authenticator(struct radius_msg *msg,
/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
* Returns the Attribute payload and sets alen to indicate the length of the
* payload if a vendor attribute with subtype is found, otherwise returns NULL.
- * The returned payload is allocated with malloc() and caller must free it.
+ * The returned payload is allocated with os_malloc() and caller must free it
+ * by calling os_free().
*/
static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
u8 subtype, size_t *alen)
{
u8 *data, *pos;
- int i;
- size_t len;
+ size_t i, len;
if (msg == NULL)
return NULL;
for (i = 0; i < msg->attr_used; i++) {
struct radius_attr_hdr *attr = msg->attrs[i];
- int left;
+ size_t left;
u32 vendor_id;
struct radius_attr_vendor *vhdr;
@@ -744,7 +739,7 @@ static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
pos = (u8 *) (attr + 1);
- memcpy(&vendor_id, pos, 4);
+ os_memcpy(&vendor_id, pos, 4);
pos += 4;
left -= 4;
@@ -765,10 +760,10 @@ static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
}
len = vhdr->vendor_length - sizeof(*vhdr);
- data = malloc(len);
+ data = os_malloc(len);
if (data == NULL)
return NULL;
- memcpy(data, pos + sizeof(*vhdr), len);
+ os_memcpy(data, pos + sizeof(*vhdr), len);
if (alen)
*alen = len;
return data;
@@ -804,7 +799,7 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
}
plen = left;
- ppos = plain = malloc(plen);
+ ppos = plain = os_malloc(plen);
if (plain == NULL)
return NULL;
@@ -833,19 +828,19 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
if (plain[0] > plen - 1) {
printf("Failed to decrypt MPPE key\n");
- free(plain);
+ os_free(plain);
return NULL;
}
- res = malloc(plain[0]);
+ res = os_malloc(plain[0]);
if (res == NULL) {
- free(plain);
+ os_free(plain);
return NULL;
}
- memcpy(res, plain + 1, plain[0]);
+ os_memcpy(res, plain + 1, plain[0]);
if (reslen)
*reslen = plain[0];
- free(plain);
+ os_free(plain);
return res;
}
@@ -867,9 +862,9 @@ static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
if (len & 0x0f) {
len = (len & 0xf0) + 16;
}
- memset(ebuf, 0, len);
+ os_memset(ebuf, 0, len);
ebuf[0] = key_len;
- memcpy(ebuf + 1, key, key_len);
+ os_memcpy(ebuf + 1, key, key_len);
*elen = len;
@@ -910,12 +905,10 @@ radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
if (msg == NULL || sent_msg == NULL)
return NULL;
- keys = (struct radius_ms_mppe_keys *) malloc(sizeof(*keys));
+ keys = wpa_zalloc(sizeof(*keys));
if (keys == NULL)
return NULL;
- memset(keys, 0, sizeof(*keys));
-
key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
&keylen);
@@ -924,7 +917,7 @@ radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
sent_msg->hdr->authenticator,
secret, secret_len,
&keys->send_len);
- free(key);
+ os_free(key);
}
key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
@@ -935,7 +928,7 @@ radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
sent_msg->hdr->authenticator,
secret, secret_len,
&keys->recv_len);
- free(key);
+ os_free(key);
}
return keys;
@@ -953,21 +946,20 @@ radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
if (msg == NULL || sent_msg == NULL)
return NULL;
- keys = (struct radius_ms_mppe_keys *) malloc(sizeof(*keys));
+ keys = wpa_zalloc(sizeof(*keys));
if (keys == NULL)
return NULL;
- memset(keys, 0, sizeof(*keys));
-
key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
RADIUS_CISCO_AV_PAIR, &keylen);
- if (key && keylen == 51 && memcmp(key, "leap:session-key=", 17) == 0) {
+ if (key && keylen == 51 &&
+ os_memcmp(key, "leap:session-key=", 17) == 0) {
keys->recv = decrypt_ms_key(key + 17, keylen - 17,
sent_msg->hdr->authenticator,
secret, secret_len,
&keys->recv_len);
- free(key);
}
+ os_free(key);
return keys;
}
@@ -991,17 +983,17 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg,
hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
/* MS-MPPE-Send-Key */
- buf = malloc(hlen + send_key_len + 16);
+ buf = os_malloc(hlen + send_key_len + 16);
if (buf == NULL) {
return 0;
}
pos = buf;
- memcpy(pos, &vendor_id, sizeof(vendor_id));
+ os_memcpy(pos, &vendor_id, sizeof(vendor_id));
pos += sizeof(vendor_id);
vhdr = (struct radius_attr_vendor *) pos;
vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
pos = (u8 *) (vhdr + 1);
- salt = random() | 0x8000;
+ salt = os_random() | 0x8000;
*pos++ = salt >> 8;
*pos++ = salt;
encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
@@ -1010,18 +1002,18 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg,
attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
buf, hlen + elen);
- free(buf);
+ os_free(buf);
if (attr == NULL) {
return 0;
}
/* MS-MPPE-Recv-Key */
- buf = malloc(hlen + send_key_len + 16);
+ buf = os_malloc(hlen + send_key_len + 16);
if (buf == NULL) {
return 0;
}
pos = buf;
- memcpy(pos, &vendor_id, sizeof(vendor_id));
+ os_memcpy(pos, &vendor_id, sizeof(vendor_id));
pos += sizeof(vendor_id);
vhdr = (struct radius_attr_vendor *) pos;
vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
@@ -1035,7 +1027,7 @@ int radius_msg_add_mppe_keys(struct radius_msg *msg,
attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
buf, hlen + elen);
- free(buf);
+ os_free(buf);
if (attr == NULL) {
return 0;
}
@@ -1052,8 +1044,8 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
u8 *secret, size_t secret_len)
{
u8 buf[128];
- int padlen, i, pos;
- size_t buf_len;
+ int padlen, i;
+ size_t buf_len, pos;
const u8 *addr[2];
size_t len[2];
u8 hash[16];
@@ -1061,13 +1053,13 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
if (data_len > 128)
return NULL;
- memcpy(buf, data, data_len);
+ os_memcpy(buf, data, data_len);
buf_len = data_len;
padlen = data_len % 16;
if (padlen) {
padlen = 16 - padlen;
- memset(buf + data_len, 0, padlen);
+ os_memset(buf + data_len, 0, padlen);
buf_len += padlen;
}
@@ -1101,9 +1093,8 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
{
- int i;
struct radius_attr_hdr *attr = NULL;
- size_t dlen;
+ size_t i, dlen;
for (i = 0; i < msg->attr_used; i++) {
if (msg->attrs[i]->type == type) {
@@ -1117,7 +1108,7 @@ int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
dlen = attr->length - sizeof(*attr);
if (buf)
- memcpy(buf, (attr + 1), dlen > len ? len : dlen);
+ os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
return dlen;
}
@@ -1125,7 +1116,7 @@ int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
size_t *len, const u8 *start)
{
- int i;
+ size_t i;
struct radius_attr_hdr *attr = NULL;
for (i = 0; i < msg->attr_used; i++) {
@@ -1147,7 +1138,8 @@ int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
{
- int i, count;
+ size_t i;
+ int count;
for (count = 0, i = 0; i < msg->attr_used; i++) {
if (msg->attrs[i]->type == type &&
@@ -1158,3 +1150,80 @@ int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
return count;
}
+
+
+struct radius_tunnel_attrs {
+ int tag_used;
+ int type; /* Tunnel-Type */
+ int medium_type; /* Tunnel-Medium-Type */
+ int vlanid;
+};
+
+
+/**
+ * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
+ * @msg: RADIUS message
+ * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
+ */
+int radius_msg_get_vlanid(struct radius_msg *msg)
+{
+ struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
+ size_t i;
+ struct radius_attr_hdr *attr = NULL;
+ const u8 *data;
+ char buf[10];
+ size_t dlen;
+
+ os_memset(&tunnel, 0, sizeof(tunnel));
+
+ for (i = 0; i < msg->attr_used; i++) {
+ attr = msg->attrs[i];
+ data = (const u8 *) (attr + 1);
+ dlen = attr->length - sizeof(*attr);
+ if (attr->length < 3)
+ continue;
+ if (data[0] >= RADIUS_TUNNEL_TAGS)
+ tun = &tunnel[0];
+ else
+ tun = &tunnel[data[0]];
+
+ switch (attr->type) {
+ case RADIUS_ATTR_TUNNEL_TYPE:
+ if (attr->length != 6)
+ break;
+ tun->tag_used++;
+ tun->type = (data[1] << 16) | (data[2] << 8) | data[3];
+ break;
+ case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
+ if (attr->length != 6)
+ break;
+ tun->tag_used++;
+ tun->medium_type =
+ (data[1] << 16) | (data[2] << 8) | data[3];
+ break;
+ case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
+ if (data[0] < RADIUS_TUNNEL_TAGS) {
+ data++;
+ dlen--;
+ }
+ if (dlen >= sizeof(buf))
+ break;
+ os_memcpy(buf, data, dlen);
+ buf[dlen] = '\0';
+ tun->tag_used++;
+ tun->vlanid = atoi(buf);
+ break;
+ }
+ }
+
+ for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
+ tun = &tunnel[i];
+ if (tun->tag_used &&
+ tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
+ tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
+ tun->vlanid > 0)
+ return tun->vlanid;
+ }
+
+ return -1;
+}
diff --git a/contrib/wpa_supplicant/radius.h b/contrib/wpa_supplicant/radius.h
index b9f8977f421e..d1b909da98bf 100644
--- a/contrib/wpa_supplicant/radius.h
+++ b/contrib/wpa_supplicant/radius.h
@@ -1,15 +1,33 @@
+/*
+ * hostapd / RADIUS message processing
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifndef RADIUS_H
#define RADIUS_H
/* RFC 2865 - RADIUS */
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct radius_hdr {
u8 code;
u8 identifier;
u16 length; /* including this header */
u8 authenticator[16];
/* followed by length-20 octets of attributes */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
enum { RADIUS_CODE_ACCESS_REQUEST = 1,
RADIUS_CODE_ACCESS_ACCEPT = 2,
@@ -26,7 +44,7 @@ struct radius_attr_hdr {
u8 type;
u8 length; /* including this header */
/* followed by length-2 octets of attribute value */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr))
@@ -60,9 +78,12 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
RADIUS_ATTR_EVENT_TIMESTAMP = 55,
RADIUS_ATTR_NAS_PORT_TYPE = 61,
+ RADIUS_ATTR_TUNNEL_TYPE = 64,
+ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
RADIUS_ATTR_CONNECT_INFO = 77,
RADIUS_ATTR_EAP_MESSAGE = 79,
RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
+ RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
};
@@ -107,11 +128,25 @@ enum { RADIUS_ATTR_USER_NAME = 1,
#define RADIUS_ACCT_TERMINATE_CAUSE_USER_ERROR 17
#define RADIUS_ACCT_TERMINATE_CAUSE_HOST_REQUEST 18
+#define RADIUS_TUNNEL_TAGS 32
+
+/* Tunnel-Type */
+#define RADIUS_TUNNEL_TYPE_PPTP 1
+#define RADIUS_TUNNEL_TYPE_L2TP 3
+#define RADIUS_TUNNEL_TYPE_IPIP 7
+#define RADIUS_TUNNEL_TYPE_GRE 10
+#define RADIUS_TUNNEL_TYPE_VLAN 13
+
+/* Tunnel-Medium-Type */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV4 1
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV6 2
+#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6
+
struct radius_attr_vendor {
u8 vendor_type;
u8 vendor_length;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
#define RADIUS_VENDOR_ID_CISCO 9
#define RADIUS_CISCO_AV_PAIR 1
@@ -123,6 +158,10 @@ enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16,
RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
};
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
struct radius_ms_mppe_keys {
u8 *send;
size_t send_len;
@@ -182,7 +221,7 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
u8 type);
void radius_msg_make_authenticator(struct radius_msg *msg,
- u8 *data, size_t len);
+ const u8 *data, size_t len);
struct radius_ms_mppe_keys *
radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
u8 *secret, size_t secret_len);
@@ -199,6 +238,7 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
u8 *data, size_t data_len,
u8 *secret, size_t secret_len);
int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
+int radius_msg_get_vlanid(struct radius_msg *msg);
static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
u32 value)
diff --git a/contrib/wpa_supplicant/radius_client.c b/contrib/wpa_supplicant/radius_client.c
index abc28bdfc70d..5b00bbeb8577 100644
--- a/contrib/wpa_supplicant/radius_client.c
+++ b/contrib/wpa_supplicant/radius_client.c
@@ -1,7 +1,6 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / RADIUS client
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / RADIUS client
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,19 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <time.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <errno.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <arpa/inet.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
#include "hostapd.h"
#include "radius.h"
@@ -60,11 +47,11 @@ struct radius_msg_list {
* for the same STA. */
struct radius_msg *msg;
RadiusType msg_type;
- time_t first_try;
- time_t next_try;
+ os_time_t first_try;
+ os_time_t next_try;
int attempts;
int next_wait;
- struct timeval last_attempt;
+ struct os_time last_attempt;
u8 *shared_secret;
size_t shared_secret_len;
@@ -110,8 +97,8 @@ static int radius_client_init_auth(struct radius_client_data *radius);
static void radius_client_msg_free(struct radius_msg_list *req)
{
radius_msg_free(req->msg);
- free(req->msg);
- free(req);
+ os_free(req->msg);
+ os_free(req);
}
@@ -135,9 +122,8 @@ int radius_client_register(struct radius_client_data *radius,
num = &radius->num_auth_handlers;
}
- newh = (struct radius_rx_handler *)
- realloc(*handlers,
- (*num + 1) * sizeof(struct radius_rx_handler));
+ newh = os_realloc(*handlers,
+ (*num + 1) * sizeof(struct radius_rx_handler));
if (newh == NULL)
return -1;
@@ -173,7 +159,8 @@ static void radius_client_handle_send_error(struct radius_client_data *radius,
static int radius_client_retransmit(struct radius_client_data *radius,
- struct radius_msg_list *entry, time_t now)
+ struct radius_msg_list *entry,
+ os_time_t now)
{
struct hostapd_radius_servers *conf = radius->conf;
int s;
@@ -203,7 +190,7 @@ static int radius_client_retransmit(struct radius_client_data *radius,
HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
entry->msg->hdr->identifier);
- gettimeofday(&entry->last_attempt, NULL);
+ os_get_time(&entry->last_attempt);
if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
radius_client_handle_send_error(radius, s, entry->msg_type);
@@ -225,7 +212,8 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
{
struct radius_client_data *radius = eloop_ctx;
struct hostapd_radius_servers *conf = radius->conf;
- time_t now, first;
+ struct os_time now;
+ os_time_t first;
struct radius_msg_list *entry, *prev, *tmp;
int auth_failover = 0, acct_failover = 0;
char abuf[50];
@@ -234,13 +222,13 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
if (!entry)
return;
- time(&now);
+ os_get_time(&now);
first = 0;
prev = NULL;
while (entry) {
- if (now >= entry->next_try &&
- radius_client_retransmit(radius, entry, now)) {
+ if (now.sec >= entry->next_try &&
+ radius_client_retransmit(radius, entry, now.sec)) {
if (prev)
prev->next = entry->next;
else
@@ -269,14 +257,14 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
}
if (radius->msgs) {
- if (first < now)
- first = now;
- eloop_register_timeout(first - now, 0,
+ if (first < now.sec)
+ first = now.sec;
+ eloop_register_timeout(first - now.sec, 0,
radius_client_timer, radius, NULL);
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
"retransmit in %ld seconds",
- (long int) (first - now));
+ (long int) (first - now.sec));
}
if (auth_failover && conf->num_auth_servers > 1) {
@@ -332,7 +320,8 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
static void radius_client_update_timeout(struct radius_client_data *radius)
{
- time_t now, first;
+ struct os_time now;
+ os_time_t first;
struct radius_msg_list *entry;
eloop_cancel_timeout(radius_client_timer, radius, NULL);
@@ -347,21 +336,21 @@ static void radius_client_update_timeout(struct radius_client_data *radius)
first = entry->next_try;
}
- time(&now);
- if (first < now)
- first = now;
- eloop_register_timeout(first - now, 0, radius_client_timer, radius,
+ os_get_time(&now);
+ if (first < now.sec)
+ first = now.sec;
+ eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
NULL);
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
- " %ld seconds\n", (long int) (first - now));
+ " %ld seconds\n", (long int) (first - now.sec));
}
static void radius_client_list_add(struct radius_client_data *radius,
struct radius_msg *msg,
RadiusType msg_type, u8 *shared_secret,
- size_t shared_secret_len, u8 *addr)
+ size_t shared_secret_len, const u8 *addr)
{
struct radius_msg_list *entry, *prev;
@@ -369,29 +358,28 @@ static void radius_client_list_add(struct radius_client_data *radius,
/* No point in adding entries to retransmit queue since event
* loop has already been terminated. */
radius_msg_free(msg);
- free(msg);
+ os_free(msg);
return;
}
- entry = malloc(sizeof(*entry));
+ entry = wpa_zalloc(sizeof(*entry));
if (entry == NULL) {
printf("Failed to add RADIUS packet into retransmit list\n");
radius_msg_free(msg);
- free(msg);
+ os_free(msg);
return;
}
- memset(entry, 0, sizeof(*entry));
if (addr)
- memcpy(entry->addr, addr, ETH_ALEN);
+ os_memcpy(entry->addr, addr, ETH_ALEN);
entry->msg = msg;
entry->msg_type = msg_type;
entry->shared_secret = shared_secret;
entry->shared_secret_len = shared_secret_len;
- time(&entry->first_try);
+ os_get_time(&entry->last_attempt);
+ entry->first_try = entry->last_attempt.sec;
entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
entry->attempts = 1;
- gettimeofday(&entry->last_attempt, NULL);
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
entry->next = radius->msgs;
radius->msgs = entry;
@@ -415,7 +403,7 @@ static void radius_client_list_add(struct radius_client_data *radius,
static void radius_client_list_del(struct radius_client_data *radius,
- RadiusType msg_type, u8 *addr)
+ RadiusType msg_type, const u8 *addr)
{
struct radius_msg_list *entry, *prev, *tmp;
@@ -426,7 +414,7 @@ static void radius_client_list_del(struct radius_client_data *radius,
prev = NULL;
while (entry) {
if (entry->msg_type == msg_type &&
- memcmp(entry->addr, addr, ETH_ALEN) == 0) {
+ os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
if (prev)
prev->next = entry->next;
else
@@ -448,7 +436,8 @@ static void radius_client_list_del(struct radius_client_data *radius,
int radius_client_send(struct radius_client_data *radius,
- struct radius_msg *msg, RadiusType msg_type, u8 *addr)
+ struct radius_msg *msg, RadiusType msg_type,
+ const u8 *addr)
{
struct hostapd_radius_servers *conf = radius->conf;
u8 *shared_secret;
@@ -499,13 +488,13 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
struct radius_client_data *radius = eloop_ctx;
struct hostapd_radius_servers *conf = radius->conf;
RadiusType msg_type = (RadiusType) sock_ctx;
- int len, i, roundtrip;
+ int len, roundtrip;
unsigned char buf[3000];
struct radius_msg *msg;
struct radius_rx_handler *handlers;
- size_t num_handlers;
+ size_t num_handlers, i;
struct radius_msg_list *req, *prev_req;
- struct timeval tv;
+ struct os_time now;
struct hostapd_radius_server *rconf;
int invalid_authenticator = 0;
@@ -584,9 +573,9 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
goto fail;
}
- gettimeofday(&tv, NULL);
- roundtrip = (tv.tv_sec - req->last_attempt.tv_sec) * 100 +
- (tv.tv_usec - req->last_attempt.tv_usec) / 10000;
+ os_get_time(&now);
+ roundtrip = (now.sec - req->last_attempt.sec) * 100 +
+ (now.usec - req->last_attempt.usec) / 10000;
hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG,
"Received RADIUS packet matched with a pending "
@@ -609,7 +598,7 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
switch (res) {
case RADIUS_RX_PROCESSED:
radius_msg_free(msg);
- free(msg);
+ os_free(msg);
/* continue */
case RADIUS_RX_QUEUED:
radius_client_msg_free(req);
@@ -637,13 +626,13 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
fail:
radius_msg_free(msg);
- free(msg);
+ os_free(msg);
}
u8 radius_client_get_id(struct radius_client_data *radius)
{
- struct radius_msg_list *entry, *prev, *remove;
+ struct radius_msg_list *entry, *prev, *_remove;
u8 id = radius->next_radius_identifier++;
/* remove entries with matching id from retransmit list to avoid
@@ -661,36 +650,69 @@ u8 radius_client_get_id(struct radius_client_data *radius)
prev->next = entry->next;
else
radius->msgs = entry->next;
- remove = entry;
- } else
- remove = NULL;
- prev = entry;
+ _remove = entry;
+ } else {
+ _remove = NULL;
+ prev = entry;
+ }
entry = entry->next;
- if (remove)
- radius_client_msg_free(remove);
+ if (_remove)
+ radius_client_msg_free(_remove);
}
return id;
}
-void radius_client_flush(struct radius_client_data *radius)
+void radius_client_flush(struct radius_client_data *radius, int only_auth)
{
- struct radius_msg_list *entry, *prev;
+ struct radius_msg_list *entry, *prev, *tmp;
if (!radius)
return;
- eloop_cancel_timeout(radius_client_timer, radius, NULL);
-
+ prev = NULL;
entry = radius->msgs;
- radius->msgs = NULL;
- radius->num_msgs = 0;
+
while (entry) {
- prev = entry;
- entry = entry->next;
- radius_client_msg_free(prev);
+ if (!only_auth || entry->msg_type == RADIUS_AUTH) {
+ if (prev)
+ prev->next = entry->next;
+ else
+ radius->msgs = entry->next;
+
+ tmp = entry;
+ entry = entry->next;
+ radius_client_msg_free(tmp);
+ radius->num_msgs--;
+ } else {
+ prev = entry;
+ entry = entry->next;
+ }
+ }
+
+ if (radius->msgs == NULL)
+ eloop_cancel_timeout(radius_client_timer, radius, NULL);
+}
+
+
+void radius_client_update_acct_msgs(struct radius_client_data *radius,
+ u8 *shared_secret,
+ size_t shared_secret_len)
+{
+ struct radius_msg_list *entry;
+
+ if (!radius)
+ return;
+
+ for (entry = radius->msgs; entry; entry = entry->next) {
+ if (entry->msg_type == RADIUS_ACCT) {
+ entry->shared_secret = shared_secret;
+ entry->shared_secret_len = shared_secret_len;
+ radius_msg_finish_acct(entry->msg, shared_secret,
+ shared_secret_len);
+ }
}
}
@@ -709,6 +731,7 @@ radius_change_server(struct radius_client_data *radius,
socklen_t addrlen;
char abuf[50];
int sel_sock;
+ struct radius_msg_list *entry;
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO,
@@ -718,37 +741,43 @@ radius_change_server(struct radius_client_data *radius,
nserv->port);
if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
- memcmp(nserv->shared_secret, oserv->shared_secret,
- nserv->shared_secret_len) != 0) {
- /* Pending RADIUS packets used different shared
- * secret, so they would need to be modified. Could
- * update all message authenticators and
- * User-Passwords, etc. and retry with new server. For
- * now, just drop all pending packets. */
- radius_client_flush(radius);
- } else {
- /* Reset retry counters for the new server */
- struct radius_msg_list *entry;
- entry = radius->msgs;
- while (entry) {
- entry->next_try = entry->first_try +
- RADIUS_CLIENT_FIRST_WAIT;
- entry->attempts = 0;
- entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
- entry = entry->next;
- }
- if (radius->msgs) {
- eloop_cancel_timeout(radius_client_timer, radius,
- NULL);
- eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
- radius_client_timer, radius,
- NULL);
+ os_memcmp(nserv->shared_secret, oserv->shared_secret,
+ nserv->shared_secret_len) != 0) {
+ /* Pending RADIUS packets used different shared secret, so
+ * they need to be modified. Update accounting message
+ * authenticators here. Authentication messages are removed
+ * since they would require more changes and the new RADIUS
+ * server may not be prepared to receive them anyway due to
+ * missing state information. Client will likely retry
+ * authentication, so this should not be an issue. */
+ if (auth)
+ radius_client_flush(radius, 1);
+ else {
+ radius_client_update_acct_msgs(
+ radius, nserv->shared_secret,
+ nserv->shared_secret_len);
}
}
+ /* Reset retry counters for the new server */
+ for (entry = radius->msgs; entry; entry = entry->next) {
+ if ((auth && entry->msg_type != RADIUS_AUTH) ||
+ (!auth && entry->msg_type != RADIUS_ACCT))
+ continue;
+ entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
+ entry->attempts = 0;
+ entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
+ }
+
+ if (radius->msgs) {
+ eloop_cancel_timeout(radius_client_timer, radius, NULL);
+ eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
+ radius_client_timer, radius, NULL);
+ }
+
switch (nserv->addr.af) {
case AF_INET:
- memset(&serv, 0, sizeof(serv));
+ os_memset(&serv, 0, sizeof(serv));
serv.sin_family = AF_INET;
serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
serv.sin_port = htons(nserv->port);
@@ -758,10 +787,10 @@ radius_change_server(struct radius_client_data *radius,
break;
#ifdef CONFIG_IPV6
case AF_INET6:
- memset(&serv6, 0, sizeof(serv6));
+ os_memset(&serv6, 0, sizeof(serv6));
serv6.sin6_family = AF_INET6;
- memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
- sizeof(struct in6_addr));
+ os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
+ sizeof(struct in6_addr));
serv6.sin6_port = htons(nserv->port);
addr = (struct sockaddr *) &serv6;
addrlen = sizeof(serv6);
@@ -878,6 +907,17 @@ static int radius_client_init_acct(struct radius_client_data *radius)
else
ok++;
+#ifdef CONFIG_IPV6
+ radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (radius->acct_serv_sock6 < 0)
+ perror("socket[PF_INET6,SOCK_DGRAM]");
+ else
+ ok++;
+#endif /* CONFIG_IPV6 */
+
+ if (ok == 0)
+ return -1;
+
radius_change_server(radius, conf->acct_server, NULL,
radius->acct_serv_sock, radius->acct_serv_sock6,
0);
@@ -911,11 +951,10 @@ radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
{
struct radius_client_data *radius;
- radius = malloc(sizeof(struct radius_client_data));
+ radius = wpa_zalloc(sizeof(struct radius_client_data));
if (radius == NULL)
return NULL;
- memset(radius, 0, sizeof(struct radius_client_data));
radius->ctx = ctx;
radius->conf = conf;
radius->auth_serv_sock = radius->acct_serv_sock =
@@ -946,12 +985,17 @@ void radius_client_deinit(struct radius_client_data *radius)
if (!radius)
return;
+ if (radius->auth_serv_sock >= 0)
+ eloop_unregister_read_sock(radius->auth_serv_sock);
+ if (radius->acct_serv_sock >= 0)
+ eloop_unregister_read_sock(radius->acct_serv_sock);
+
eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
- radius_client_flush(radius);
- free(radius->auth_handlers);
- free(radius->acct_handlers);
- free(radius);
+ radius_client_flush(radius, 0);
+ os_free(radius->auth_handlers);
+ os_free(radius->acct_handlers);
+ os_free(radius);
}
@@ -963,7 +1007,7 @@ void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
entry = radius->msgs;
while (entry) {
if (entry->msg_type == RADIUS_AUTH &&
- memcmp(entry->addr, addr, ETH_ALEN) == 0) {
+ os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
hostapd_logger(radius->ctx, addr,
HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG,
@@ -1003,37 +1047,37 @@ static int radius_client_dump_auth_server(char *buf, size_t buflen,
}
}
- return snprintf(buf, buflen,
- "radiusAuthServerIndex=%d\n"
- "radiusAuthServerAddress=%s\n"
- "radiusAuthClientServerPortNumber=%d\n"
- "radiusAuthClientRoundTripTime=%d\n"
- "radiusAuthClientAccessRequests=%u\n"
- "radiusAuthClientAccessRetransmissions=%u\n"
- "radiusAuthClientAccessAccepts=%u\n"
- "radiusAuthClientAccessRejects=%u\n"
- "radiusAuthClientAccessChallenges=%u\n"
- "radiusAuthClientMalformedAccessResponses=%u\n"
- "radiusAuthClientBadAuthenticators=%u\n"
- "radiusAuthClientPendingRequests=%u\n"
- "radiusAuthClientTimeouts=%u\n"
- "radiusAuthClientUnknownTypes=%u\n"
- "radiusAuthClientPacketsDropped=%u\n",
- serv->index,
- hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
- serv->port,
- serv->round_trip_time,
- serv->requests,
- serv->retransmissions,
- serv->access_accepts,
- serv->access_rejects,
- serv->access_challenges,
- serv->malformed_responses,
- serv->bad_authenticators,
- pending,
- serv->timeouts,
- serv->unknown_types,
- serv->packets_dropped);
+ return os_snprintf(buf, buflen,
+ "radiusAuthServerIndex=%d\n"
+ "radiusAuthServerAddress=%s\n"
+ "radiusAuthClientServerPortNumber=%d\n"
+ "radiusAuthClientRoundTripTime=%d\n"
+ "radiusAuthClientAccessRequests=%u\n"
+ "radiusAuthClientAccessRetransmissions=%u\n"
+ "radiusAuthClientAccessAccepts=%u\n"
+ "radiusAuthClientAccessRejects=%u\n"
+ "radiusAuthClientAccessChallenges=%u\n"
+ "radiusAuthClientMalformedAccessResponses=%u\n"
+ "radiusAuthClientBadAuthenticators=%u\n"
+ "radiusAuthClientPendingRequests=%u\n"
+ "radiusAuthClientTimeouts=%u\n"
+ "radiusAuthClientUnknownTypes=%u\n"
+ "radiusAuthClientPacketsDropped=%u\n",
+ serv->index,
+ hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
+ serv->port,
+ serv->round_trip_time,
+ serv->requests,
+ serv->retransmissions,
+ serv->access_accepts,
+ serv->access_rejects,
+ serv->access_challenges,
+ serv->malformed_responses,
+ serv->bad_authenticators,
+ pending,
+ serv->timeouts,
+ serv->unknown_types,
+ serv->packets_dropped);
}
@@ -1053,33 +1097,33 @@ static int radius_client_dump_acct_server(char *buf, size_t buflen,
}
}
- return snprintf(buf, buflen,
- "radiusAccServerIndex=%d\n"
- "radiusAccServerAddress=%s\n"
- "radiusAccClientServerPortNumber=%d\n"
- "radiusAccClientRoundTripTime=%d\n"
- "radiusAccClientRequests=%u\n"
- "radiusAccClientRetransmissions=%u\n"
- "radiusAccClientResponses=%u\n"
- "radiusAccClientMalformedResponses=%u\n"
- "radiusAccClientBadAuthenticators=%u\n"
- "radiusAccClientPendingRequests=%u\n"
- "radiusAccClientTimeouts=%u\n"
- "radiusAccClientUnknownTypes=%u\n"
- "radiusAccClientPacketsDropped=%u\n",
- serv->index,
- hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
- serv->port,
- serv->round_trip_time,
- serv->requests,
- serv->retransmissions,
- serv->responses,
- serv->malformed_responses,
- serv->bad_authenticators,
- pending,
- serv->timeouts,
- serv->unknown_types,
- serv->packets_dropped);
+ return os_snprintf(buf, buflen,
+ "radiusAccServerIndex=%d\n"
+ "radiusAccServerAddress=%s\n"
+ "radiusAccClientServerPortNumber=%d\n"
+ "radiusAccClientRoundTripTime=%d\n"
+ "radiusAccClientRequests=%u\n"
+ "radiusAccClientRetransmissions=%u\n"
+ "radiusAccClientResponses=%u\n"
+ "radiusAccClientMalformedResponses=%u\n"
+ "radiusAccClientBadAuthenticators=%u\n"
+ "radiusAccClientPendingRequests=%u\n"
+ "radiusAccClientTimeouts=%u\n"
+ "radiusAccClientUnknownTypes=%u\n"
+ "radiusAccClientPacketsDropped=%u\n",
+ serv->index,
+ hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
+ serv->port,
+ serv->round_trip_time,
+ serv->requests,
+ serv->retransmissions,
+ serv->responses,
+ serv->malformed_responses,
+ serv->bad_authenticators,
+ pending,
+ serv->timeouts,
+ serv->unknown_types,
+ serv->packets_dropped);
}
@@ -1113,3 +1157,48 @@ int radius_client_get_mib(struct radius_client_data *radius, char *buf,
return count;
}
+
+
+static int radius_servers_diff(struct hostapd_radius_server *nserv,
+ struct hostapd_radius_server *oserv,
+ int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++) {
+ if (hostapd_ip_diff(&nserv[i].addr, &oserv[i].addr) ||
+ nserv[i].port != oserv[i].port ||
+ nserv[i].shared_secret_len != oserv[i].shared_secret_len ||
+ memcmp(nserv[i].shared_secret, oserv[i].shared_secret,
+ nserv[i].shared_secret_len) != 0)
+ return 1;
+ }
+
+ return 0;
+}
+
+
+struct radius_client_data *
+radius_client_reconfig(struct radius_client_data *old, void *ctx,
+ struct hostapd_radius_servers *oldconf,
+ struct hostapd_radius_servers *newconf)
+{
+ radius_client_flush(old, 0);
+
+ if (newconf->retry_primary_interval !=
+ oldconf->retry_primary_interval ||
+ newconf->num_auth_servers != oldconf->num_auth_servers ||
+ newconf->num_acct_servers != oldconf->num_acct_servers ||
+ radius_servers_diff(newconf->auth_servers, oldconf->auth_servers,
+ newconf->num_auth_servers) ||
+ radius_servers_diff(newconf->acct_servers, oldconf->acct_servers,
+ newconf->num_acct_servers)) {
+ hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG,
+ "Reconfiguring RADIUS client");
+ radius_client_deinit(old);
+ return radius_client_init(ctx, newconf);
+ }
+
+ return old;
+}
diff --git a/contrib/wpa_supplicant/radius_client.h b/contrib/wpa_supplicant/radius_client.h
index d21ca83faead..df1ba1f9b209 100644
--- a/contrib/wpa_supplicant/radius_client.h
+++ b/contrib/wpa_supplicant/radius_client.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / RADIUS client
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifndef RADIUS_CLIENT_H
#define RADIUS_CLIENT_H
@@ -73,15 +87,19 @@ int radius_client_register(struct radius_client_data *radius,
void *data);
int radius_client_send(struct radius_client_data *radius,
struct radius_msg *msg,
- RadiusType msg_type, u8 *addr);
+ RadiusType msg_type, const u8 *addr);
u8 radius_client_get_id(struct radius_client_data *radius);
-void radius_client_flush(struct radius_client_data *radius);
+void radius_client_flush(struct radius_client_data *radius, int only_auth);
struct radius_client_data *
radius_client_init(void *ctx, struct hostapd_radius_servers *conf);
void radius_client_deinit(struct radius_client_data *radius);
void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr);
int radius_client_get_mib(struct radius_client_data *radius, char *buf,
size_t buflen);
+struct radius_client_data *
+radius_client_reconfig(struct radius_client_data *old, void *ctx,
+ struct hostapd_radius_servers *oldconf,
+ struct hostapd_radius_servers *newconf);
#endif /* RADIUS_CLIENT_H */
diff --git a/contrib/wpa_supplicant/rc4.c b/contrib/wpa_supplicant/rc4.c
index 4cf14d91d1af..8480cc55cea6 100644
--- a/contrib/wpa_supplicant/rc4.c
+++ b/contrib/wpa_supplicant/rc4.c
@@ -1,6 +1,6 @@
/*
* RC4 stream cipher
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,7 +12,8 @@
* See README and COPYING for more details.
*/
-#include <stdio.h>
+#include "includes.h"
+
#include "common.h"
#include "rc4.h"
@@ -35,7 +36,7 @@ void rc4_skip(const u8 *key, size_t keylen, size_t skip,
{
u32 i, j, k;
u8 S[256], *pos;
- int kpos;
+ size_t kpos;
/* Setup RC4 state */
for (i = 0; i < 256; i++)
diff --git a/contrib/wpa_supplicant/rc4.h b/contrib/wpa_supplicant/rc4.h
index 3873240496df..01f13833ddc8 100644
--- a/contrib/wpa_supplicant/rc4.h
+++ b/contrib/wpa_supplicant/rc4.h
@@ -1,6 +1,6 @@
/*
* RC4 stream cipher
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
diff --git a/contrib/wpa_supplicant/rsa.c b/contrib/wpa_supplicant/rsa.c
new file mode 100644
index 000000000000..bfc0d5222495
--- /dev/null
+++ b/contrib/wpa_supplicant/rsa.c
@@ -0,0 +1,359 @@
+/*
+ * RSA
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "asn1.h"
+#include "bignum.h"
+#include "rsa.h"
+
+
+struct crypto_rsa_key {
+ int private_key; /* whether private key is set */
+ struct bignum *n; /* modulus (p * q) */
+ struct bignum *e; /* public exponent */
+ /* The following parameters are available only if private_key is set */
+ struct bignum *d; /* private exponent */
+ struct bignum *p; /* prime p (factor of n) */
+ struct bignum *q; /* prime q (factor of n) */
+ struct bignum *dmp1; /* d mod (p - 1); CRT exponent */
+ struct bignum *dmq1; /* d mod (q - 1); CRT exponent */
+ struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */
+};
+
+
+static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,
+ struct bignum *num)
+{
+ struct asn1_hdr hdr;
+
+ if (pos == NULL)
+ return NULL;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d "
+ "tag 0x%x", hdr.class, hdr.tag);
+ return NULL;
+ }
+
+ if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) {
+ wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER");
+ return NULL;
+ }
+
+ return hdr.payload + hdr.length;
+}
+
+
+/**
+ * crypto_rsa_import_public_key - Import an RSA public key
+ * @buf: Key buffer (DER encoded RSA public key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the public key or %NULL on failure
+ */
+struct crypto_rsa_key *
+crypto_rsa_import_public_key(const u8 *buf, size_t len)
+{
+ struct crypto_rsa_key *key;
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+
+ key = os_zalloc(sizeof(*key));
+ if (key == NULL)
+ return NULL;
+
+ key->n = bignum_init();
+ key->e = bignum_init();
+ if (key->n == NULL || key->e == NULL) {
+ crypto_rsa_free(key);
+ return NULL;
+ }
+
+ /*
+ * PKCS #1, 7.1:
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER -- e
+ * }
+ */
+
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
+ "(public key) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto error;
+ }
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ pos = crypto_rsa_parse_integer(pos, end, key->n);
+ pos = crypto_rsa_parse_integer(pos, end, key->e);
+
+ if (pos == NULL)
+ goto error;
+
+ if (pos != end) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSA: Extra data in public key SEQUENCE",
+ pos, end - pos);
+ goto error;
+ }
+
+ return key;
+
+error:
+ crypto_rsa_free(key);
+ return NULL;
+}
+
+
+/**
+ * crypto_rsa_import_private_key - Import an RSA private key
+ * @buf: Key buffer (DER encoded RSA private key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the private key or %NULL on failure
+ */
+struct crypto_rsa_key *
+crypto_rsa_import_private_key(const u8 *buf, size_t len)
+{
+ struct crypto_rsa_key *key;
+ struct bignum *zero;
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+
+ key = os_zalloc(sizeof(*key));
+ if (key == NULL)
+ return NULL;
+
+ key->private_key = 1;
+
+ key->n = bignum_init();
+ key->e = bignum_init();
+ key->d = bignum_init();
+ key->p = bignum_init();
+ key->q = bignum_init();
+ key->dmp1 = bignum_init();
+ key->dmq1 = bignum_init();
+ key->iqmp = bignum_init();
+
+ if (key->n == NULL || key->e == NULL || key->d == NULL ||
+ key->p == NULL || key->q == NULL || key->dmp1 == NULL ||
+ key->dmq1 == NULL || key->iqmp == NULL) {
+ crypto_rsa_free(key);
+ return NULL;
+ }
+
+ /*
+ * PKCS #1, 7.2:
+ * RSAPrivateKey ::= SEQUENCE {
+ * version Version,
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER -- (inverse of q) mod p
+ * }
+ *
+ * Version ::= INTEGER -- shall be 0 for this version of the standard
+ */
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
+ "(public key) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ goto error;
+ }
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ zero = bignum_init();
+ if (zero == NULL)
+ goto error;
+ pos = crypto_rsa_parse_integer(pos, end, zero);
+ if (pos == NULL || bignum_cmp_d(zero, 0) != 0) {
+ wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the "
+ "beginning of private key; not found");
+ bignum_deinit(zero);
+ goto error;
+ }
+ bignum_deinit(zero);
+
+ pos = crypto_rsa_parse_integer(pos, end, key->n);
+ pos = crypto_rsa_parse_integer(pos, end, key->e);
+ pos = crypto_rsa_parse_integer(pos, end, key->d);
+ pos = crypto_rsa_parse_integer(pos, end, key->p);
+ pos = crypto_rsa_parse_integer(pos, end, key->q);
+ pos = crypto_rsa_parse_integer(pos, end, key->dmp1);
+ pos = crypto_rsa_parse_integer(pos, end, key->dmq1);
+ pos = crypto_rsa_parse_integer(pos, end, key->iqmp);
+
+ if (pos == NULL)
+ goto error;
+
+ if (pos != end) {
+ wpa_hexdump(MSG_DEBUG,
+ "RSA: Extra data in public key SEQUENCE",
+ pos, end - pos);
+ goto error;
+ }
+
+ return key;
+
+error:
+ crypto_rsa_free(key);
+ return NULL;
+}
+
+
+/**
+ * crypto_rsa_get_modulus_len - Get the modulus length of the RSA key
+ * @key: RSA key
+ * Returns: Modulus length of the key
+ */
+size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key)
+{
+ return bignum_get_unsigned_bin_len(key->n);
+}
+
+
+/**
+ * crypto_rsa_exptmod - RSA modular exponentiation
+ * @in: Input data
+ * @inlen: Input data length
+ * @out: Buffer for output data
+ * @outlen: Maximum size of the output buffer and used size on success
+ * @key: RSA key
+ * @use_private: 1 = Use RSA private key, 0 = Use RSA public key
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
+ struct crypto_rsa_key *key, int use_private)
+{
+ struct bignum *tmp, *a = NULL, *b = NULL;
+ int ret = -1;
+ size_t modlen;
+
+ if (use_private && !key->private_key)
+ return -1;
+
+ tmp = bignum_init();
+ if (tmp == NULL)
+ return -1;
+
+ if (bignum_set_unsigned_bin(tmp, in, inlen) < 0)
+ goto error;
+ if (bignum_cmp(key->n, tmp) < 0) {
+ /* Too large input value for the RSA key modulus */
+ goto error;
+ }
+
+ if (use_private) {
+ /*
+ * Decrypt (or sign) using Chinese remainer theorem to speed
+ * up calculation. This is equivalent to tmp = tmp^d mod n
+ * (which would require more CPU to calculate directly).
+ *
+ * dmp1 = (1/e) mod (p-1)
+ * dmq1 = (1/e) mod (q-1)
+ * iqmp = (1/q) mod p, where p > q
+ * m1 = c^dmp1 mod p
+ * m2 = c^dmq1 mod q
+ * h = q^-1 (m1 - m2) mod p
+ * m = m2 + hq
+ */
+ a = bignum_init();
+ b = bignum_init();
+ if (a == NULL || b == NULL)
+ goto error;
+
+ /* a = tmp^dmp1 mod p */
+ if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0)
+ goto error;
+
+ /* b = tmp^dmq1 mod q */
+ if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0)
+ goto error;
+
+ /* tmp = (a - b) * (1/q mod p) (mod p) */
+ if (bignum_sub(a, b, tmp) < 0 ||
+ bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0)
+ goto error;
+
+ /* tmp = b + q * tmp */
+ if (bignum_mul(tmp, key->q, tmp) < 0 ||
+ bignum_add(tmp, b, tmp) < 0)
+ goto error;
+ } else {
+ /* Encrypt (or verify signature) */
+ /* tmp = tmp^e mod N */
+ if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0)
+ goto error;
+ }
+
+ modlen = crypto_rsa_get_modulus_len(key);
+ if (modlen > *outlen) {
+ *outlen = modlen;
+ goto error;
+ }
+
+ if (bignum_get_unsigned_bin_len(tmp) > modlen)
+ goto error; /* should never happen */
+
+ *outlen = modlen;
+ os_memset(out, 0, modlen);
+ if (bignum_get_unsigned_bin(
+ tmp, out +
+ (modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0)
+ goto error;
+
+ ret = 0;
+
+error:
+ bignum_deinit(tmp);
+ bignum_deinit(a);
+ bignum_deinit(b);
+ return ret;
+}
+
+
+/**
+ * crypto_rsa_free - Free RSA key
+ * @key: RSA key to be freed
+ *
+ * This function frees an RSA key imported with either
+ * crypto_rsa_import_public_key() or crypto_rsa_import_private_key().
+ */
+void crypto_rsa_free(struct crypto_rsa_key *key)
+{
+ if (key) {
+ bignum_deinit(key->n);
+ bignum_deinit(key->e);
+ bignum_deinit(key->d);
+ bignum_deinit(key->p);
+ bignum_deinit(key->q);
+ bignum_deinit(key->dmp1);
+ bignum_deinit(key->dmq1);
+ bignum_deinit(key->iqmp);
+ os_free(key);
+ }
+}
diff --git a/contrib/wpa_supplicant/rsa.h b/contrib/wpa_supplicant/rsa.h
new file mode 100644
index 000000000000..ac50dfd69d3e
--- /dev/null
+++ b/contrib/wpa_supplicant/rsa.h
@@ -0,0 +1,29 @@
+/*
+ * RSA
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef RSA_H
+#define RSA_H
+
+struct crypto_rsa_key;
+
+struct crypto_rsa_key *
+crypto_rsa_import_public_key(const u8 *buf, size_t len);
+struct crypto_rsa_key *
+crypto_rsa_import_private_key(const u8 *buf, size_t len);
+size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key);
+int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
+ struct crypto_rsa_key *key, int use_private);
+void crypto_rsa_free(struct crypto_rsa_key *key);
+
+#endif /* RSA_H */
diff --git a/contrib/wpa_supplicant/sha1.c b/contrib/wpa_supplicant/sha1.c
index 7e32e31ca1ba..194db1601d1e 100644
--- a/contrib/wpa_supplicant/sha1.c
+++ b/contrib/wpa_supplicant/sha1.c
@@ -1,6 +1,6 @@
/*
* SHA1 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "sha1.h"
@@ -36,9 +34,8 @@ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
{
unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
unsigned char tk[20];
- int i;
const u8 *_addr[6];
- size_t _len[6];
+ size_t _len[6], i;
if (num_elem > 5) {
/*
@@ -65,8 +62,8 @@ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
* and text is the data being protected */
/* start out by storing key in ipad */
- memset(k_pad, 0, sizeof(k_pad));
- memcpy(k_pad, key, key_len);
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
/* XOR key with ipad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x36;
@@ -80,8 +77,8 @@ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
}
sha1_vector(1 + num_elem, _addr, _len, mac);
- memset(k_pad, 0, sizeof(k_pad));
- memcpy(k_pad, key, key_len);
+ os_memset(k_pad, 0, sizeof(k_pad));
+ os_memcpy(k_pad, key, key_len);
/* XOR key with opad values */
for (i = 0; i < 64; i++)
k_pad[i] ^= 0x5c;
@@ -129,7 +126,7 @@ void sha1_prf(const u8 *key, size_t key_len, const char *label,
u8 zero = 0, counter = 0;
size_t pos, plen;
u8 hash[SHA1_MAC_LEN];
- size_t label_len = strlen(label);
+ size_t label_len = os_strlen(label);
const unsigned char *addr[4];
size_t len[4];
@@ -152,7 +149,7 @@ void sha1_prf(const u8 *key, size_t key_len, const char *label,
} else {
hmac_sha1_vector(key, key_len, 4, addr, len,
hash);
- memcpy(&buf[pos], hash, plen);
+ os_memcpy(&buf[pos], hash, plen);
break;
}
counter++;
@@ -180,7 +177,7 @@ void sha1_t_prf(const u8 *key, size_t key_len, const char *label,
unsigned char counter = 0;
size_t pos, plen;
u8 hash[SHA1_MAC_LEN];
- size_t label_len = strlen(label);
+ size_t label_len = os_strlen(label);
u8 output_len[2];
const unsigned char *addr[5];
size_t len[5];
@@ -204,10 +201,10 @@ void sha1_t_prf(const u8 *key, size_t key_len, const char *label,
plen = buf_len - pos;
hmac_sha1_vector(key, key_len, 5, addr, len, hash);
if (plen >= SHA1_MAC_LEN) {
- memcpy(&buf[pos], hash, SHA1_MAC_LEN);
+ os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
pos += SHA1_MAC_LEN;
} else {
- memcpy(&buf[pos], hash, plen);
+ os_memcpy(&buf[pos], hash, plen);
break;
}
len[0] = SHA1_MAC_LEN;
@@ -224,18 +221,19 @@ void sha1_t_prf(const u8 *key, size_t key_len, const char *label,
* @seed_len: Length of the seed
* @out: Buffer for the generated pseudo-random key
* @outlen: Number of bytes of key to generate
-*
+ * Returns: 0 on success, -1 on failure.
+ *
* This function is used to derive new, cryptographically separate keys from a
* given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
*/
int tls_prf(const u8 *secret, size_t secret_len, const char *label,
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
{
- size_t L_S1, L_S2;
+ size_t L_S1, L_S2, i;
const u8 *S1, *S2;
u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
- int i, MD5_pos, SHA1_pos;
+ int MD5_pos, SHA1_pos;
const u8 *MD5_addr[3];
size_t MD5_len[3];
const unsigned char *SHA1_addr[3];
@@ -247,14 +245,14 @@ int tls_prf(const u8 *secret, size_t secret_len, const char *label,
MD5_addr[0] = A_MD5;
MD5_len[0] = MD5_MAC_LEN;
MD5_addr[1] = (unsigned char *) label;
- MD5_len[1] = strlen(label);
+ MD5_len[1] = os_strlen(label);
MD5_addr[2] = seed;
MD5_len[2] = seed_len;
SHA1_addr[0] = A_SHA1;
SHA1_len[0] = SHA1_MAC_LEN;
SHA1_addr[1] = (unsigned char *) label;
- SHA1_len[1] = strlen(label);
+ SHA1_len[1] = os_strlen(label);
SHA1_addr[2] = seed;
SHA1_len[2] = seed_len;
@@ -297,7 +295,7 @@ int tls_prf(const u8 *secret, size_t secret_len, const char *label,
static void pbkdf2_sha1_f(const char *passphrase, const char *ssid,
- size_t ssid_len, int iterations, int count,
+ size_t ssid_len, int iterations, unsigned int count,
u8 *digest)
{
unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN];
@@ -305,7 +303,7 @@ static void pbkdf2_sha1_f(const char *passphrase, const char *ssid,
unsigned char count_buf[4];
const u8 *addr[2];
size_t len[2];
- size_t passphrase_len = strlen(passphrase);
+ size_t passphrase_len = os_strlen(passphrase);
addr[0] = (u8 *) ssid;
len[0] = ssid_len;
@@ -323,12 +321,12 @@ static void pbkdf2_sha1_f(const char *passphrase, const char *ssid,
count_buf[2] = (count >> 8) & 0xff;
count_buf[3] = count & 0xff;
hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len, tmp);
- memcpy(digest, tmp, SHA1_MAC_LEN);
+ os_memcpy(digest, tmp, SHA1_MAC_LEN);
for (i = 1; i < iterations; i++) {
hmac_sha1((u8 *) passphrase, passphrase_len, tmp, SHA1_MAC_LEN,
tmp2);
- memcpy(tmp, tmp2, SHA1_MAC_LEN);
+ os_memcpy(tmp, tmp2, SHA1_MAC_LEN);
for (j = 0; j < SHA1_MAC_LEN; j++)
digest[j] ^= tmp2[j];
}
@@ -351,7 +349,7 @@ static void pbkdf2_sha1_f(const char *passphrase, const char *ssid,
void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen)
{
- int count = 0;
+ unsigned int count = 0;
unsigned char *pos = buf;
size_t left = buflen, plen;
unsigned char digest[SHA1_MAC_LEN];
@@ -361,24 +359,28 @@ void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations, count,
digest);
plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left;
- memcpy(pos, digest, plen);
+ os_memcpy(pos, digest, plen);
pos += plen;
left -= plen;
}
}
-#ifndef EAP_TLS_FUNCS
+#ifdef INTERNAL_SHA1
-typedef struct {
+struct SHA1Context {
u32 state[5];
u32 count[2];
unsigned char buffer[64];
-} SHA1_CTX;
+};
+
+typedef struct SHA1Context SHA1_CTX;
-static void SHA1Init(SHA1_CTX *context);
-static void SHA1Update(SHA1_CTX *context, const void *data, u32 len);
-static void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
+#ifndef CONFIG_CRYPTO_INTERNAL
+static void SHA1Init(struct SHA1Context *context);
+static void SHA1Update(struct SHA1Context *context, const void *data, u32 len);
+static void SHA1Final(unsigned char digest[20], struct SHA1Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
static void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
@@ -393,7 +395,7 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
SHA1_CTX ctx;
- int i;
+ size_t i;
SHA1Init(&ctx);
for (i = 0; i < num_elem; i++)
@@ -402,19 +404,57 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
}
-/**
- * sha1_transform - Perform one SHA-1 transform step
- * @state: SHA-1 state
- * @data: Input data for the SHA-1 transform
- *
- * This function is used to implement random number generation specified in
- * NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is
- * similar to SHA-1, but has different message padding and as such, access to
- * just part of the SHA-1 is needed.
- */
-void sha1_transform(u8 *state, const u8 data[64])
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
{
- SHA1Transform((u32 *) state, data);
+ u8 xkey[64];
+ u32 t[5], _t[5];
+ int i, j, m, k;
+ u8 *xpos = x;
+ u32 carry;
+
+ if (seed_len > sizeof(xkey))
+ seed_len = sizeof(xkey);
+
+ /* FIPS 186-2 + change notice 1 */
+
+ os_memcpy(xkey, seed, seed_len);
+ os_memset(xkey + seed_len, 0, 64 - seed_len);
+ t[0] = 0x67452301;
+ t[1] = 0xEFCDAB89;
+ t[2] = 0x98BADCFE;
+ t[3] = 0x10325476;
+ t[4] = 0xC3D2E1F0;
+
+ m = xlen / 40;
+ for (j = 0; j < m; j++) {
+ /* XSEED_j = 0 */
+ for (i = 0; i < 2; i++) {
+ /* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+ /* w_i = G(t, XVAL) */
+ os_memcpy(_t, t, 20);
+ SHA1Transform(_t, xkey);
+ _t[0] = host_to_be32(_t[0]);
+ _t[1] = host_to_be32(_t[1]);
+ _t[2] = host_to_be32(_t[2]);
+ _t[3] = host_to_be32(_t[3]);
+ _t[4] = host_to_be32(_t[4]);
+ os_memcpy(xpos, _t, 20);
+
+ /* XKEY = (1 + XKEY + w_i) mod 2^b */
+ carry = 1;
+ for (k = 19; k >= 0; k--) {
+ carry += xkey[k] + xpos[k];
+ xkey[k] = carry & 0xff;
+ carry >>= 8;
+ }
+
+ xpos += SHA1_MAC_LEN;
+ }
+ /* x_j = w_0|w_1 */
+ }
+
+ return 0;
}
@@ -479,11 +519,11 @@ Modified to run on Compaq Alpha hardware.
-----------------
Modified 4/01
-By Jouni Malinen <jkmaline@cc.hut.fi>
+By Jouni Malinen <j@w1.fi>
Minor changes to match the coding style used in Dynamics.
Modified September 24, 2004
-By Jouni Malinen <jkmaline@cc.hut.fi>
+By Jouni Malinen <j@w1.fi>
Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined.
*/
@@ -557,7 +597,7 @@ static void SHA1Transform(u32 state[5], const unsigned char buffer[64])
#ifdef SHA1HANDSOFF
u32 workspace[16];
block = (CHAR64LONG16 *) workspace;
- memcpy(block, buffer, 64);
+ os_memcpy(block, buffer, 64);
#else
block = (CHAR64LONG16 *) buffer;
#endif
@@ -597,14 +637,14 @@ static void SHA1Transform(u32 state[5], const unsigned char buffer[64])
/* Wipe variables */
a = b = c = d = e = 0;
#ifdef SHA1HANDSOFF
- memset(block, 0, 64);
+ os_memset(block, 0, 64);
#endif
}
/* SHA1Init - Initialize new context */
-static void SHA1Init(SHA1_CTX* context)
+void SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
@@ -618,7 +658,7 @@ static void SHA1Init(SHA1_CTX* context)
/* Run your data through this. */
-static void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
+void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
{
u32 i, j;
const unsigned char *data = _data;
@@ -631,7 +671,7 @@ static void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
context->count[1]++;
context->count[1] += (len >> 29);
if ((j + len) > 63) {
- memcpy(&context->buffer[j], data, (i = 64-j));
+ os_memcpy(&context->buffer[j], data, (i = 64-j));
SHA1Transform(context->state, context->buffer);
for ( ; i + 63 < len; i += 64) {
SHA1Transform(context->state, &data[i]);
@@ -639,7 +679,7 @@ static void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
j = 0;
}
else i = 0;
- memcpy(&context->buffer[j], &data[i], len - i);
+ os_memcpy(&context->buffer[j], &data[i], len - i);
#ifdef VERBOSE
SHAPrintContext(context, "after ");
#endif
@@ -648,7 +688,7 @@ static void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
/* Add padding and return the message digest. */
-static void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
u32 i;
unsigned char finalcount[8];
@@ -671,324 +711,12 @@ static void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
}
/* Wipe variables */
i = 0;
- memset(context->buffer, 0, 64);
- memset(context->state, 0, 20);
- memset(context->count, 0, 8);
- memset(finalcount, 0, 8);
+ os_memset(context->buffer, 0, 64);
+ os_memset(context->state, 0, 20);
+ os_memset(context->count, 0, 8);
+ os_memset(finalcount, 0, 8);
}
/* ===== end - public domain SHA1 implementation ===== */
-#endif /* EAP_TLS_FUNCS */
-
-
-#ifdef TEST_MAIN
-
-#include "md5.c"
-
-static int test_eap_fast(void)
-{
- /* draft-cam-winget-eap-fast-01.txt */
- const u8 pac_key[] = {
- 0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09,
- 0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B,
- 0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA,
- 0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14
- };
- const u8 seed[] = {
- 0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A,
- 0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3,
- 0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93,
- 0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A,
- 0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A,
- 0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F,
- 0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A,
- 0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00
- };
- const u8 master_secret[] = {
- 0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02,
- 0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64,
- 0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77,
- 0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29,
- 0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
- 0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2
- };
- const u8 key_block[] = {
- 0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
- 0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
- 0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B,
- 0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57,
- 0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70,
- 0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB,
- 0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF,
- 0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44,
- 0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29,
- 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
- 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
- 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
- 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
- 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
- };
- const u8 sks[] = {
- 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
- 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
- 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
- 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
- 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
- };
- const u8 isk[] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
- };
- const u8 imck[] = {
- 0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9,
- 0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80,
- 0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96,
- 0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1,
- 0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5,
- 0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9,
- 0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8,
- 0x15, 0xEC, 0x57, 0x7B
- };
- const u8 msk[] = {
- 0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED,
- 0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33,
- 0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51,
- 0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9,
- 0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A,
- 0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49,
- 0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59,
- 0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3
- };
- u8 tlv[] = {
- 0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00,
- 0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8,
- 0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14,
- 0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62,
- 0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58,
- 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
- 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
- 0x05, 0xC5, 0x5B, 0xB7
- };
- const u8 compound_mac[] = {
- 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
- 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
- 0x05, 0xC5, 0x5B, 0xB7
- };
- u8 buf[512];
- const u8 *simck, *cmk;
- int errors = 0;
-
- printf("EAP-FAST test cases\n");
-
- printf("- T-PRF (SHA1) test case / master_secret\n");
- sha1_t_prf(pac_key, sizeof(pac_key), "PAC to master secret label hash",
- seed, sizeof(seed), buf, sizeof(master_secret));
- if (memcmp(master_secret, buf, sizeof(master_secret)) != 0) {
- printf("T-PRF test - FAILED!\n");
- errors++;
- }
-
- printf("- PRF (TLS, SHA1/MD5) test case / key_block\n");
- tls_prf(master_secret, sizeof(master_secret), "key expansion",
- seed, sizeof(seed), buf, sizeof(key_block));
- if (memcmp(key_block, buf, sizeof(key_block)) != 0) {
- printf("PRF test - FAILED!\n");
- errors++;
- }
-
- printf("- T-PRF (SHA1) test case / IMCK\n");
- sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
- isk, sizeof(isk), buf, sizeof(imck));
- if (memcmp(imck, buf, sizeof(imck)) != 0) {
- printf("T-PRF test - FAILED!\n");
- errors++;
- }
-
- simck = imck;
- cmk = imck + 40;
-
- printf("- T-PRF (SHA1) test case / MSK\n");
- sha1_t_prf(simck, 40, "Session Key Generating Function",
- "", 0, buf, sizeof(msk));
- if (memcmp(msk, buf, sizeof(msk)) != 0) {
- printf("T-PRF test - FAILED!\n");
- errors++;
- }
-
- printf("- Compound MAC test case\n");
- memset(tlv + sizeof(tlv) - 20, 0, 20);
- hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20);
- if (memcmp(tlv + sizeof(tlv) - 20, compound_mac, sizeof(compound_mac))
- != 0) {
- printf("Compound MAC test - FAILED!\n");
- errors++;
- }
-
- return errors;
-}
-
-
-static u8 key0[] =
-{
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
- 0x0b, 0x0b, 0x0b, 0x0b
-};
-static u8 data0[] = "Hi There";
-static u8 prf0[] =
-{
- 0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
- 0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
- 0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06,
- 0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee,
- 0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88,
- 0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb,
- 0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e,
- 0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
-};
-
-static u8 key1[] = "Jefe";
-static u8 data1[] = "what do ya want for nothing?";
-static u8 prf1[] =
-{
- 0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
- 0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
- 0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58,
- 0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09,
- 0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa,
- 0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02,
- 0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7,
- 0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc
-};
-
-
-static u8 key2[] =
-{
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
- 0xaa, 0xaa, 0xaa, 0xaa
-};
-static u8 data2[] =
-{
- 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
- 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
- 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
- 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
- 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
- 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
- 0xdd, 0xdd
-};
-static u8 prf2[] =
-{
- 0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
- 0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
- 0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1,
- 0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce,
- 0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc,
- 0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae,
- 0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6,
- 0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07
-};
-
-
-struct passphrase_test {
- char *passphrase;
- char *ssid;
- char psk[32];
-};
-
-static struct passphrase_test passphrase_tests[] =
-{
- {
- "password",
- "IEEE",
- {
- 0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef,
- 0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90,
- 0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2,
- 0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e
- }
- },
- {
- "ThisIsAPassword",
- "ThisIsASSID",
- {
- 0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6,
- 0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3,
- 0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08,
- 0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf
- }
- },
- {
- "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
- "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
- {
- 0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83,
- 0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c,
- 0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48,
- 0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62
- }
- },
-};
-
-#define NUM_PASSPHRASE_TESTS \
-(sizeof(passphrase_tests) / sizeof(passphrase_tests[0]))
-
-
-int main(int argc, char *argv[])
-{
- u8 res[512];
- int ret = 0, i;
-
- printf("PRF-SHA1 test cases:\n");
-
- sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1,
- res, sizeof(prf0));
- if (memcmp(res, prf0, sizeof(prf0)) == 0)
- printf("Test case 0 - OK\n");
- else {
- printf("Test case 0 - FAILED!\n");
- ret++;
- }
-
- sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1,
- res, sizeof(prf1));
- if (memcmp(res, prf1, sizeof(prf1)) == 0)
- printf("Test case 1 - OK\n");
- else {
- printf("Test case 1 - FAILED!\n");
- ret++;
- }
-
- sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2),
- res, sizeof(prf2));
- if (memcmp(res, prf2, sizeof(prf2)) == 0)
- printf("Test case 2 - OK\n");
- else {
- printf("Test case 2 - FAILED!\n");
- ret++;
- }
-
- ret += test_eap_fast();
-
- printf("PBKDF2-SHA1 Passphrase test cases:\n");
- for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
- u8 psk[32];
- struct passphrase_test *test = &passphrase_tests[i];
- pbkdf2_sha1(test->passphrase,
- test->ssid, strlen(test->ssid),
- 4096, psk, 32);
- if (memcmp(psk, test->psk, 32) == 0)
- printf("Test case %d - OK\n", i);
- else {
- printf("Test case %d - FAILED!\n", i);
- ret++;
- }
- }
-
- return ret;
-}
-#endif /* TEST_MAIN */
+#endif /* INTERNAL_SHA1 */
diff --git a/contrib/wpa_supplicant/sha1.h b/contrib/wpa_supplicant/sha1.h
index 3c6d915146d9..97affa1a620d 100644
--- a/contrib/wpa_supplicant/sha1.h
+++ b/contrib/wpa_supplicant/sha1.h
@@ -1,6 +1,6 @@
/*
* SHA1 hash implementation and interface functions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -30,4 +30,12 @@ int tls_prf(const u8 *secret, size_t secret_len, const char *label,
void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen);
+#ifdef CONFIG_CRYPTO_INTERNAL
+struct SHA1Context;
+
+void SHA1Init(struct SHA1Context *context);
+void SHA1Update(struct SHA1Context *context, const void *data, u32 len);
+void SHA1Final(unsigned char digest[20], struct SHA1Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
+
#endif /* SHA1_H */
diff --git a/contrib/wpa_supplicant/sha256.c b/contrib/wpa_supplicant/sha256.c
new file mode 100644
index 000000000000..175ec8b637da
--- /dev/null
+++ b/contrib/wpa_supplicant/sha256.c
@@ -0,0 +1,379 @@
+/*
+ * SHA-256 hash implementation and interface functions
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (32 bytes)
+ */
+void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
+ unsigned char tk[32];
+ const u8 *_addr[6];
+ size_t _len[6], i;
+
+ if (num_elem > 5) {
+ /*
+ * Fixed limit on the number of fragments to avoid having to
+ * allocate memory (which could fail).
+ */
+ return;
+ }
+
+ /* if key is longer than 64 bytes reset it to key = SHA256(key) */
+ if (key_len > 64) {
+ sha256_vector(1, &key, &key_len, tk);
+ key = tk;
+ key_len = 32;
+ }
+
+ /* the HMAC_SHA256 transform looks like:
+ *
+ * SHA256(K XOR opad, SHA256(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected */
+
+ /* start out by storing key in ipad */
+ memset(k_pad, 0, sizeof(k_pad));
+ memcpy(k_pad, key, key_len);
+ /* XOR key with ipad values */
+ for (i = 0; i < 64; i++)
+ k_pad[i] ^= 0x36;
+
+ /* perform inner SHA256 */
+ _addr[0] = k_pad;
+ _len[0] = 64;
+ for (i = 0; i < num_elem; i++) {
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
+ }
+ sha256_vector(1 + num_elem, _addr, _len, mac);
+
+ memset(k_pad, 0, sizeof(k_pad));
+ memcpy(k_pad, key, key_len);
+ /* XOR key with opad values */
+ for (i = 0; i < 64; i++)
+ k_pad[i] ^= 0x5c;
+
+ /* perform outer SHA256 */
+ _addr[0] = k_pad;
+ _len[0] = 64;
+ _addr[1] = mac;
+ _len[1] = SHA256_MAC_LEN;
+ sha256_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (20 bytes)
+ */
+void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+/**
+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5A.3)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key.
+ */
+void sha256_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+ u16 counter = 0;
+ size_t pos, plen;
+ u8 hash[SHA256_MAC_LEN];
+ const u8 *addr[3];
+ size_t len[3];
+ u8 counter_le[2];
+
+ addr[0] = counter_le;
+ len[0] = 2;
+ addr[1] = (u8 *) label;
+ len[1] = strlen(label) + 1;
+ addr[2] = data;
+ len[2] = data_len;
+
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ WPA_PUT_LE16(counter_le, counter);
+ if (plen >= SHA256_MAC_LEN) {
+ hmac_sha256_vector(key, key_len, 3, addr, len,
+ &buf[pos]);
+ pos += SHA256_MAC_LEN;
+ } else {
+ hmac_sha256_vector(key, key_len, 3, addr, len, hash);
+ memcpy(&buf[pos], hash, plen);
+ break;
+ }
+ counter++;
+ }
+}
+
+
+#ifdef INTERNAL_SHA256
+
+struct sha256_state {
+ u64 length;
+ u32 state[8], curlen;
+ u8 buf[64];
+};
+
+static void sha256_init(struct sha256_state *md);
+static int sha256_process(struct sha256_state *md, const unsigned char *in,
+ unsigned long inlen);
+static int sha256_done(struct sha256_state *md, unsigned char *out);
+
+
+/**
+ * sha256_vector - SHA256 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ */
+void sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac)
+{
+ struct sha256_state ctx;
+ size_t i;
+
+ sha256_init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ sha256_process(&ctx, addr[i], len[i]);
+ sha256_done(&ctx, mac);
+}
+
+
+/* ===== start - public domain SHA256 implementation ===== */
+
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+/* the K array */
+static const unsigned long K[64] = {
+ 0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+ 0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+ 0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+ 0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+ 0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+ 0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+ 0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+ 0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+ 0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+ 0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+ 0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+ 0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+ 0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+
+/* Various logical functions */
+#define RORc(x, y) \
+( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
+ ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define Ch(x,y,z) (z ^ (x & (y ^ z)))
+#define Maj(x,y,z) (((x | y) & z) | (x & y))
+#define S(x, n) RORc((x), (n))
+#define R(x, n) (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x) (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x) (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x) (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x) (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+/* compress 512-bits */
+static int sha256_compress(struct sha256_state *md, unsigned char *buf)
+{
+ u32 S[8], W[64], t0, t1;
+ u32 t;
+ int i;
+
+ /* copy state into S */
+ for (i = 0; i < 8; i++) {
+ S[i] = md->state[i];
+ }
+
+ /* copy the state into 512-bits into W[0..15] */
+ for (i = 0; i < 16; i++)
+ W[i] = WPA_GET_BE32(buf + (4 * i));
+
+ /* fill W[16..63] */
+ for (i = 16; i < 64; i++) {
+ W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+ W[i - 16];
+ }
+
+ /* Compress */
+#define RND(a,b,c,d,e,f,g,h,i) \
+ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
+ t1 = Sigma0(a) + Maj(a, b, c); \
+ d += t0; \
+ h = t0 + t1;
+
+ for (i = 0; i < 64; ++i) {
+ RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
+ t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4];
+ S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+ }
+
+ /* feedback */
+ for (i = 0; i < 8; i++) {
+ md->state[i] = md->state[i] + S[i];
+ }
+ return 0;
+}
+
+
+/* Initialize the hash state */
+static void sha256_init(struct sha256_state *md)
+{
+ md->curlen = 0;
+ md->length = 0;
+ md->state[0] = 0x6A09E667UL;
+ md->state[1] = 0xBB67AE85UL;
+ md->state[2] = 0x3C6EF372UL;
+ md->state[3] = 0xA54FF53AUL;
+ md->state[4] = 0x510E527FUL;
+ md->state[5] = 0x9B05688CUL;
+ md->state[6] = 0x1F83D9ABUL;
+ md->state[7] = 0x5BE0CD19UL;
+}
+
+/**
+ Process a block of memory though the hash
+ @param md The hash state
+ @param in The data to hash
+ @param inlen The length of the data (octets)
+ @return CRYPT_OK if successful
+*/
+static int sha256_process(struct sha256_state *md, const unsigned char *in,
+ unsigned long inlen)
+{
+ unsigned long n;
+#define block_size 64
+
+ if (md->curlen > sizeof(md->buf))
+ return -1;
+
+ while (inlen > 0) {
+ if (md->curlen == 0 && inlen >= block_size) {
+ if (sha256_compress(md, (unsigned char *) in) < 0)
+ return -1;
+ md->length += block_size * 8;
+ in += block_size;
+ inlen -= block_size;
+ } else {
+ n = MIN(inlen, (block_size - md->curlen));
+ memcpy(md->buf + md->curlen, in, n);
+ md->curlen += n;
+ in += n;
+ inlen -= n;
+ if (md->curlen == block_size) {
+ if (sha256_compress(md, md->buf) < 0)
+ return -1;
+ md->length += 8 * block_size;
+ md->curlen = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ Terminate the hash to get the digest
+ @param md The hash state
+ @param out [out] The destination of the hash (32 bytes)
+ @return CRYPT_OK if successful
+*/
+static int sha256_done(struct sha256_state *md, unsigned char *out)
+{
+ int i;
+
+ if (md->curlen >= sizeof(md->buf))
+ return -1;
+
+ /* increase the length of the message */
+ md->length += md->curlen * 8;
+
+ /* append the '1' bit */
+ md->buf[md->curlen++] = (unsigned char) 0x80;
+
+ /* if the length is currently above 56 bytes we append zeros
+ * then compress. Then we can fall back to padding zeros and length
+ * encoding like normal.
+ */
+ if (md->curlen > 56) {
+ while (md->curlen < 64) {
+ md->buf[md->curlen++] = (unsigned char) 0;
+ }
+ sha256_compress(md, md->buf);
+ md->curlen = 0;
+ }
+
+ /* pad upto 56 bytes of zeroes */
+ while (md->curlen < 56) {
+ md->buf[md->curlen++] = (unsigned char) 0;
+ }
+
+ /* store length */
+ WPA_PUT_BE64(md->buf + 56, md->length);
+ sha256_compress(md, md->buf);
+
+ /* copy output */
+ for (i = 0; i < 8; i++)
+ WPA_PUT_BE32(out + (4 * i), md->state[i]);
+
+ return 0;
+}
+
+/* ===== end - public domain SHA256 implementation ===== */
+
+#endif /* INTERNAL_SHA256 */
diff --git a/contrib/wpa_supplicant/sha256.h b/contrib/wpa_supplicant/sha256.h
new file mode 100644
index 000000000000..dc597f09b53a
--- /dev/null
+++ b/contrib/wpa_supplicant/sha256.h
@@ -0,0 +1,27 @@
+/*
+ * SHA256 hash implementation and interface functions
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef SHA256_H
+#define SHA256_H
+
+#define SHA256_MAC_LEN 32
+
+void hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac);
+void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac);
+void sha256_prf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+
+#endif /* SHA256_H */
diff --git a/contrib/wpa_supplicant/state_machine.h b/contrib/wpa_supplicant/state_machine.h
new file mode 100644
index 000000000000..62766bf40ba4
--- /dev/null
+++ b/contrib/wpa_supplicant/state_machine.h
@@ -0,0 +1,144 @@
+/*
+ * wpa_supplicant/hostapd - State machine definitions
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file includes a set of pre-processor macros that can be used to
+ * implement a state machine. In addition to including this header file, each
+ * file implementing a state machine must define STATE_MACHINE_DATA to be the
+ * data structure including state variables (enum <machine>_state,
+ * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
+ * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define
+ * a group of state machines with shared data structure, STATE_MACHINE_ADDR
+ * needs to be defined to point to the MAC address used in debug output.
+ * SM_ENTRY_M macro can be used to define similar group of state machines
+ * without this additional debug info.
+ */
+
+#ifndef STATE_MACHINE_H
+#define STATE_MACHINE_H
+
+/**
+ * SM_STATE - Declaration of a state machine function
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used to declare a state machine function. It is used in place
+ * of a C function definition to declare functions to be run when the state is
+ * entered by calling SM_ENTER or SM_ENTER_GLOBAL.
+ */
+#define SM_STATE(machine, state) \
+static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \
+ int global)
+
+/**
+ * SM_ENTRY - State machine function entry point
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used inside each state machine function declared with
+ * SM_STATE. SM_ENTRY should be in the beginning of the function body, but
+ * after declaration of possible local variables. This macro prints debug
+ * information about state transition and update the state machine state.
+ */
+#define SM_ENTRY(machine, state) \
+if (!global || sm->machine ## _state != machine ## _ ## state) { \
+ sm->changed = TRUE; \
+ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \
+ " entering state " #state); \
+} \
+sm->machine ## _state = machine ## _ ## state;
+
+/**
+ * SM_ENTRY_M - State machine function entry point for state machine group
+ * @machine: State machine name
+ * @_state: State machine state
+ * @data: State variable prefix (full variable: <prefix>_state)
+ *
+ * This macro is like SM_ENTRY, but for state machine groups that use a shared
+ * data structure for more than one state machine. Both machine and prefix
+ * parameters are set to "sub-state machine" name. prefix is used to allow more
+ * than one state variable to be stored in the same data structure.
+ */
+#define SM_ENTRY_M(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+ sm->changed = TRUE; \
+ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \
+ #machine " entering state " #_state); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * SM_ENTRY_MA - State machine function entry point for state machine group
+ * @machine: State machine name
+ * @_state: State machine state
+ * @data: State variable prefix (full variable: <prefix>_state)
+ *
+ * This macro is like SM_ENTRY_M, but a MAC address is included in debug
+ * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to
+ * be included in debug.
+ */
+#define SM_ENTRY_MA(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+ sm->changed = TRUE; \
+ wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \
+ #machine " entering state " #_state, \
+ MAC2STR(STATE_MACHINE_ADDR)); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * SM_ENTER - Enter a new state machine state
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro expands to a function call to a state machine function defined
+ * with SM_STATE macro. SM_ENTER is used in a state machine step function to
+ * move the state machine to a new state.
+ */
+#define SM_ENTER(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 0)
+
+/**
+ * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is like SM_ENTER, but this is used when entering a new state
+ * based on a global (not specific to any particular state) rule. A separate
+ * macro is used to avoid unwanted debug message floods when the same global
+ * rule is forcing a state machine to remain in on state.
+ */
+#define SM_ENTER_GLOBAL(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 1)
+
+/**
+ * SM_STEP - Declaration of a state machine step function
+ * @machine: State machine name
+ *
+ * This macro is used to declare a state machine step function. It is used in
+ * place of a C function definition to declare a function that is used to move
+ * state machine to a new state based on state variables. This function uses
+ * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state.
+ */
+#define SM_STEP(machine) \
+static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm)
+
+/**
+ * SM_STEP_RUN - Call the state machine step function
+ * @machine: State machine name
+ *
+ * This macro expands to a function call to a state machine step function
+ * defined with SM_STEP macro.
+ */
+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
+
+#endif /* STATE_MACHINE_H */
diff --git a/contrib/wpa_supplicant/tls.h b/contrib/wpa_supplicant/tls.h
index a6a8110c7dab..30d8842837fc 100644
--- a/contrib/wpa_supplicant/tls.h
+++ b/contrib/wpa_supplicant/tls.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / SSL/TLS interface definition
- * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -18,21 +18,14 @@
struct tls_connection;
struct tls_keys {
- const u8 *master_key;
+ const u8 *master_key; /* TLS master secret */
size_t master_key_len;
const u8 *client_random;
size_t client_random_len;
const u8 *server_random;
size_t server_random_len;
-
- /*
- * If TLS library does not provide access to master_key, but only to
- * EAP key block, this pointer can be set to point to the result of
- * PRF(master_secret, "client EAP encryption",
- * client_random + server_random).
- */
- const u8 *eap_tls_prf;
- size_t eap_tls_prf_len;
+ const u8 *inner_secret; /* TLS/IA inner secret */
+ size_t inner_secret_len;
};
struct tls_config {
@@ -71,8 +64,10 @@ struct tls_config {
* @ppin: pointer to the pin variable in the configuration
* (this is OpenSSL specific for now)
* @key_id: the private key's key id (this is OpenSSL specific for now)
+ * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
*
- * TLS connection parameters to be configured with tls_connection_set_params().
+ * TLS connection parameters to be configured with tls_connection_set_params()
+ * and tls_global_set_params().
*
* Certificates and private key can be configured either as a reference name
* (file path or reference to certificate store) or by providing the same data
@@ -96,6 +91,7 @@ struct tls_connection_params {
const char *dh_file;
const u8 *dh_blob;
size_t dh_blob_len;
+ int tls_ia;
/* OpenSSL specific variables */
int engine;
@@ -134,7 +130,6 @@ void tls_deinit(void *tls_ctx);
/**
* tls_get_errors - Process pending errors
* @tls_ctx: TLS context data from tls_init()
- *
* Returns: Number of found error, 0 if no errors detected.
*
* Process all pending TLS errors.
@@ -144,7 +139,6 @@ int tls_get_errors(void *tls_ctx);
/**
* tls_connection_init - Initialize a new TLS connection
* @tls_ctx: TLS context data from tls_init()
- *
* Returns: Connection context data, conn for other function calls
*/
struct tls_connection * tls_connection_init(void *tls_ctx);
@@ -162,16 +156,14 @@ void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
* tls_connection_established - Has the TLS connection been completed?
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- *
* Returns: 1 if TLS connection has been completed, 0 if not.
*/
int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
/**
- * tls_connection_shutdown - Shutdown TLS connection data.
+ * tls_connection_shutdown - Shutdown TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- *
* Returns: 0 on success, -1 on failure
*
* Shutdown current TLS connection without releasing all resources. New
@@ -185,12 +177,12 @@ enum {
TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
};
+
/**
* tls_connection_set_params - Set TLS connection parameters
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @params: Connection parameters
- *
* Returns: 0 on success, -1 on failure,
* TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
* PKCS#11 engine failure, or
@@ -201,21 +193,23 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
const struct tls_connection_params *params);
/**
- * tls_global_ca_cert - Set trusted CA certificate for all TLS connections
+ * tls_global_set_params - Set TLS parameters for all TLS connection
* @tls_ctx: TLS context data from tls_init()
- * @ca_cert: File name for CA certificate in PEM or DER format
- * %NULL to allow all subjects
- *
- * Returns: 0 on success, -1 on failure
+ * @params: Global TLS parameters
+ * Returns: 0 on success, -1 on failure,
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
+ * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
+ * PKCS#11 engine private key.
*/
-int tls_global_ca_cert(void *tls_ctx, const char *ca_cert);
+int tls_global_set_params(void *tls_ctx,
+ const struct tls_connection_params *params);
/**
* tls_global_set_verify - Set global certificate verification options
* @tls_ctx: TLS context data from tls_init()
* @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
* 2 = verify CRL for all certificates
- *
* Returns: 0 on success, -1 on failure
*/
int tls_global_set_verify(void *tls_ctx, int check_crl);
@@ -225,55 +219,73 @@ int tls_global_set_verify(void *tls_ctx, int check_crl);
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @verify_peer: 1 = verify peer certificate
- *
* Returns: 0 on success, -1 on failure
*/
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
int verify_peer);
/**
- * tls_global_client_cert - Set client certificate for all TLS connections
+ * tls_connection_set_ia - Set TLS/IA parameters
* @tls_ctx: TLS context data from tls_init()
- * @client_cert: File name for client certificate in PEM or DER format
- *
+ * @conn: Connection context data from tls_connection_init()
+ * @tls_ia: 1 = enable TLS/IA
* Returns: 0 on success, -1 on failure
- */
-int tls_global_client_cert(void *tls_ctx, const char *client_cert);
-
-/**
- * tls_global_private_key - Set private key for all TLS connections
- * @tls_ctx: TLS context data from tls_init()
- * @private_key: File name for client private key in PEM or DER format
- * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
- * passphrase is used.
*
- * Returns: 0 on success, -1 on failure
+ * This function is used to configure TLS/IA in server mode where
+ * tls_connection_set_params() is not used.
*/
-int tls_global_private_key(void *tls_ctx, const char *private_key,
- const char *private_key_passwd);
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+ int tls_ia);
/**
* tls_connection_get_keys - Get master key and random data from TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @keys: Structure of key/random data (filled on success)
- *
* Returns: 0 on success, -1 on failure
*/
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys);
/**
+ * tls_connection_prf - Use TLS-PRF to derive keying material
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is optional to implement if tls_connection_get_keys() provides
+ * access to master secret and server/client random values. If these values are
+ * not exported from the TLS library, tls_connection_prf() is required so that
+ * further keying material can be derived from the master secret. If not
+ * implemented, the function will still need to be defined, but it can just
+ * return -1. Example implementation of this function is in tls_prf() function
+ * when it is called with seed set to client_random|server_random (or
+ * server_random|client_random).
+ */
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len);
+
+/**
* tls_connection_handshake - Process TLS handshake (client side)
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @in_data: Input data from TLS peer
* @in_len: Input data length
* @out_len: Length of the output buffer.
- *
+ * @appl_data: Pointer to application data pointer, or %NULL if dropped
+ * @appl_data_len: Pointer to variable that is set to appl_data length
* Returns: Pointer to output data, %NULL on failure
*
- * Caller is responsible for freeing returned output data.
+ * Caller is responsible for freeing returned output data. If the final
+ * handshake message includes application data, this is decrypted and
+ * appl_data (if not %NULL) is set to point this data. Caller is responsible
+ * for freeing appl_data.
*
* This function is used during TLS handshake. The first call is done with
* in_data == %NULL and the library is expected to return ClientHello packet.
@@ -291,7 +303,8 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
*/
u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn,
const u8 *in_data, size_t in_len,
- size_t *out_len);
+ size_t *out_len, u8 **appl_data,
+ size_t *appl_data_len);
/**
* tls_connection_server_handshake - Process TLS handshake (server side)
@@ -300,7 +313,6 @@ u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn,
* @in_data: Input data from TLS peer
* @in_len: Input data length
* @out_len: Length of the output buffer.
- *
* Returns: pointer to output data, %NULL on failure
*
* Caller is responsible for freeing returned output data.
@@ -318,7 +330,6 @@ u8 * tls_connection_server_handshake(void *tls_ctx,
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (encrypted TLS data)
* @out_len: Maximum out_data length
- *
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
@@ -336,7 +347,6 @@ int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn,
* @in_len: Input buffer length
* @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
* @out_len: Maximum out_data length
- *
* Returns: Number of bytes written to out_data, -1 on failure
*
* This function is used after TLS handshake has been completed successfully to
@@ -350,7 +360,6 @@ int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn,
* tls_connection_resumed - Was session resumption used
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- *
* Returns: 1 if current session used session resumption, 0 if not
*/
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
@@ -361,23 +370,29 @@ int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
* @conn: Connection context data from tls_connection_init()
* @key: TLS pre-master-secret
* @key_len: length of key in bytes
- *
* Returns: 0 on success, -1 on failure
*/
int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
const u8 *key, size_t key_len);
+enum {
+ TLS_CIPHER_NONE,
+ TLS_CIPHER_RC4_SHA /* 0x0005 */,
+ TLS_CIPHER_AES128_SHA /* 0x002f */,
+ TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
+ TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
+};
+
/**
- * tls_connection_set_anon_dh - Configure TLS connection to use anonymous DH
+ * tls_connection_set_cipher_list - Configure acceptable cipher suites
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- *
+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
+ * (TLS_CIPHER_*).
* Returns: 0 on success, -1 on failure
- *
- * TODO: consider changing this to more generic routine for configuring allowed
- * ciphers
*/
-int tls_connection_set_anon_dh(void *tls_ctx, struct tls_connection *conn);
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+ u8 *ciphers);
/**
* tls_get_cipher - Get current cipher name
@@ -385,7 +400,6 @@ int tls_connection_set_anon_dh(void *tls_ctx, struct tls_connection *conn);
* @conn: Connection context data from tls_connection_init()
* @buf: Buffer for the cipher name
* @buflen: buf size
- *
* Returns: 0 on success, -1 on failure
*
* Get the name of the currently used cipher.
@@ -397,7 +411,6 @@ int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
* tls_connection_enable_workaround - Enable TLS workaround options
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- *
* Returns: 0 on success, -1 on failure
*
* This function is used to enable connection-specific workaround options for
@@ -411,9 +424,8 @@ int tls_connection_enable_workaround(void *tls_ctx,
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @ext_type: Extension type
- * @data: Extension payload (NULL to remove extension)
+ * @data: Extension payload (%NULL to remove extension)
* @data_len: Extension payload length
- *
* Returns: 0 on success, -1 on failure
*/
int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
@@ -433,7 +445,6 @@ int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn);
* tls_connection_get_read_alerts - Get connection read alert status
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- *
* Returns: Number of times a fatal read (remote end reported error) has
* happened during this connection.
*/
@@ -443,7 +454,6 @@ int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
* tls_connection_get_write_alerts - Get connection write alert status
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- *
* Returns: Number of times a fatal write (locally detected error) has happened
* during this connection.
*/
@@ -460,4 +470,52 @@ int tls_connection_get_write_alerts(void *tls_ctx,
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn);
+#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */
+/**
+ * tls_capabilities - Get supported TLS capabilities
+ * @tls_ctx: TLS context data from tls_init()
+ * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
+ */
+unsigned int tls_capabilities(void *tls_ctx);
+
+/**
+ * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished
+ * @out_data: Pointer to output buffer (encrypted TLS/IA data)
+ * @out_len: Maximum out_data length
+ * Returns: Number of bytes written to out_data on success, -1 on failure
+ *
+ * This function is used to send the TLS/IA end phase message, e.g., when the
+ * EAP server completes EAP-TTLSv1.
+ */
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+ struct tls_connection *conn,
+ int final,
+ u8 *out_data, size_t out_len);
+
+/**
+ * tls_connection_ia_final_phase_finished - Has final phase been completed
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1
+ * on failure
+ */
+int tls_connection_ia_final_phase_finished(void *tls_ctx,
+ struct tls_connection *conn);
+
+/**
+ * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @key: Session key material (session_key vectors with 2-octet length), or
+ * %NULL if no session key was generating in the current phase
+ * @key_len: Length of session key material
+ * Returns: 0 on success, -1 on failure
+ */
+int tls_connection_ia_permute_inner_secret(void *tls_ctx,
+ struct tls_connection *conn,
+ const u8 *key, size_t key_len);
+
#endif /* TLS_H */
diff --git a/contrib/wpa_supplicant/tls_gnutls.c b/contrib/wpa_supplicant/tls_gnutls.c
index 2bc9ed8e5090..07893983189d 100644
--- a/contrib/wpa_supplicant/tls_gnutls.c
+++ b/contrib/wpa_supplicant/tls_gnutls.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / SSL/TLS interface functions for openssl
- * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,17 +12,43 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
+#include "includes.h"
#include <gnutls/gnutls.h>
#include <gnutls/x509.h>
+#ifdef PKCS12_FUNCS
+#include <gnutls/pkcs12.h>
+#endif /* PKCS12_FUNCS */
+
+#ifdef CONFIG_GNUTLS_EXTRA
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+#define GNUTLS_IA
+#include <gnutls/extra.h>
+#if LIBGNUTLS_VERSION_NUMBER == 0x010302
+/* This function is not included in the current gnutls/extra.h even though it
+ * should be, so define it here as a workaround for the time being. */
+int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
+#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* CONFIG_GNUTLS_EXTRA */
#include "common.h"
#include "tls.h"
+#define TLS_RANDOM_SIZE 32
+#define TLS_MASTER_SIZE 48
+
+
+#if LIBGNUTLS_VERSION_NUMBER < 0x010302
+/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
+ * use of internal structures to get the master_secret and
+ * {server,client}_random.
+ */
+#define GNUTLS_INTERNAL_STRUCTURE_HACK
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
+
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
/*
* It looks like gnutls does not provide access to client/server_random and
* master_key. This is somewhat unfortunate since these are needed for key
@@ -32,8 +58,6 @@
*/
typedef u8 uint8;
-#define TLS_RANDOM_SIZE 32
-#define TLS_MASTER_SIZE 48
typedef unsigned char opaque;
typedef struct {
uint8 suite[2];
@@ -59,9 +83,21 @@ struct gnutls_session_int {
security_parameters_st security_parameters;
/* followed by things we are not interested in */
};
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
static int tls_gnutls_ref_count = 0;
+struct tls_global {
+ /* Data for session resumption */
+ void *session_data;
+ size_t session_data_size;
+
+ int server;
+
+ int params_set;
+ gnutls_certificate_credentials_t xcred;
+};
+
struct tls_connection {
gnutls_session session;
char *subject_match, *altsubject_match;
@@ -75,7 +111,23 @@ struct tls_connection {
u8 *push_buf, *pull_buf, *pull_buf_offset;
size_t push_buf_len, pull_buf_len;
+ int params_set;
gnutls_certificate_credentials_t xcred;
+
+ int tls_ia;
+ int final_phase_finished;
+
+#ifdef GNUTLS_IA
+ gnutls_ia_server_credentials_t iacred_srv;
+ gnutls_ia_client_credentials_t iacred_cli;
+
+ /* Session keys generated in the current phase for inner secret
+ * permutation before generating/verifying PhaseFinished. */
+ u8 *session_keys;
+ size_t session_keys_len;
+
+ u8 inner_secret[TLS_MASTER_SIZE];
+#endif /* GNUTLS_IA */
};
@@ -87,7 +139,7 @@ static void tls_log_func(int level, const char *msg)
return;
}
- s = strdup(msg);
+ s = os_strdup(msg);
if (s == NULL)
return;
@@ -101,7 +153,7 @@ static void tls_log_func(int level, const char *msg)
}
wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
"gnutls<%d> %s", level, s);
- free(s);
+ os_free(s);
}
@@ -109,21 +161,36 @@ extern int wpa_debug_show_keys;
void * tls_init(const struct tls_config *conf)
{
+ struct tls_global *global;
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
/* Because of the horrible hack to get master_secret and client/server
* random, we need to make sure that the gnutls version is something
* that is expected to have same structure definition for the session
* data.. */
const char *ver;
- const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", NULL };
+ const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
+ "1.3.2",
+ NULL };
int i;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+ global = os_zalloc(sizeof(*global));
+ if (global == NULL)
+ return NULL;
- if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0)
+ if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
+ os_free(global);
return NULL;
+ }
tls_gnutls_ref_count++;
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
ver = gnutls_check_version(NULL);
- if (ver == NULL)
+ if (ver == NULL) {
+ tls_deinit(global);
return NULL;
+ }
wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
for (i = 0; ok_ver[i]; i++) {
if (strcmp(ok_ver[i], ver) == 0)
@@ -132,18 +199,28 @@ void * tls_init(const struct tls_config *conf)
if (ok_ver[i] == NULL) {
wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
"to be tested and enabled in tls_gnutls.c", ver);
+ tls_deinit(global);
return NULL;
}
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
gnutls_global_set_log_function(tls_log_func);
if (wpa_debug_show_keys)
gnutls_global_set_log_level(11);
- return (void *) 1;
+ return global;
}
void tls_deinit(void *ssl_ctx)
{
+ struct tls_global *global = ssl_ctx;
+ if (global) {
+ if (global->params_set)
+ gnutls_certificate_free_credentials(global->xcred);
+ os_free(global->session_data);
+ os_free(global);
+ }
+
tls_gnutls_ref_count--;
if (tls_gnutls_ref_count == 0)
gnutls_global_deinit();
@@ -167,13 +244,13 @@ static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
}
end = conn->pull_buf + conn->pull_buf_len;
- if (end - conn->pull_buf_offset < len)
+ if ((size_t) (end - conn->pull_buf_offset) < len)
len = end - conn->pull_buf_offset;
- memcpy(buf, conn->pull_buf_offset, len);
+ os_memcpy(buf, conn->pull_buf_offset, len);
conn->pull_buf_offset += len;
if (conn->pull_buf_offset == end) {
wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
- free(conn->pull_buf);
+ os_free(conn->pull_buf);
conn->pull_buf = conn->pull_buf_offset = NULL;
conn->pull_buf_len = 0;
} else {
@@ -190,12 +267,12 @@ static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
struct tls_connection *conn = (struct tls_connection *) ptr;
u8 *nbuf;
- nbuf = realloc(conn->push_buf, conn->push_buf_len + len);
+ nbuf = os_realloc(conn->push_buf, conn->push_buf_len + len);
if (nbuf == NULL) {
errno = ENOMEM;
return -1;
}
- memcpy(nbuf + conn->push_buf_len, buf, len);
+ os_memcpy(nbuf + conn->push_buf_len, buf, len);
conn->push_buf = nbuf;
conn->push_buf_len += len;
@@ -203,33 +280,78 @@ static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
}
-struct tls_connection * tls_connection_init(void *ssl_ctx)
+static int tls_gnutls_init_session(struct tls_global *global,
+ struct tls_connection *conn)
{
- struct tls_connection *conn;
const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
const int protos[2] = { GNUTLS_TLS1, 0 };
+ int ret;
-
- conn = malloc(sizeof(*conn));
- if (conn == NULL)
- return NULL;
- memset(conn, 0, sizeof(*conn));
- if (gnutls_init(&conn->session, GNUTLS_CLIENT) < 0) {
+ ret = gnutls_init(&conn->session,
+ global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
+ if (ret < 0) {
wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
- "connection");
- free(conn);
- return NULL;
+ "connection: %s", gnutls_strerror(ret));
+ return -1;
}
- gnutls_set_default_priority(conn->session);
- gnutls_certificate_type_set_priority(conn->session, cert_types);
- gnutls_protocol_set_priority(conn->session, protos);
+ ret = gnutls_set_default_priority(conn->session);
+ if (ret < 0)
+ goto fail;
+
+ ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
+ if (ret < 0)
+ goto fail;
+
+ ret = gnutls_protocol_set_priority(conn->session, protos);
+ if (ret < 0)
+ goto fail;
gnutls_transport_set_pull_function(conn->session, tls_pull_func);
gnutls_transport_set_push_function(conn->session, tls_push_func);
gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
- gnutls_certificate_allocate_credentials(&conn->xcred);
+ return 0;
+
+fail:
+ wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
+ gnutls_strerror(ret));
+ gnutls_deinit(conn->session);
+ return -1;
+}
+
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+ struct tls_global *global = ssl_ctx;
+ struct tls_connection *conn;
+ int ret;
+
+ conn = os_zalloc(sizeof(*conn));
+ if (conn == NULL)
+ return NULL;
+
+ if (tls_gnutls_init_session(global, conn)) {
+ os_free(conn);
+ return NULL;
+ }
+
+ if (global->params_set) {
+ ret = gnutls_credentials_set(conn->session,
+ GNUTLS_CRD_CERTIFICATE,
+ global->xcred);
+ if (ret < 0) {
+ wpa_printf(MSG_INFO, "Failed to configure "
+ "credentials: %s", gnutls_strerror(ret));
+ os_free(conn);
+ return NULL;
+ }
+ }
+
+ if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
+ os_free(conn);
+ return NULL;
+ }
return conn;
}
@@ -239,14 +361,26 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
+
+#ifdef GNUTLS_IA
+ if (conn->iacred_srv)
+ gnutls_ia_free_server_credentials(conn->iacred_srv);
+ if (conn->iacred_cli)
+ gnutls_ia_free_client_credentials(conn->iacred_cli);
+ if (conn->session_keys) {
+ os_memset(conn->session_keys, 0, conn->session_keys_len);
+ os_free(conn->session_keys);
+ }
+#endif /* GNUTLS_IA */
+
gnutls_certificate_free_credentials(conn->xcred);
gnutls_deinit(conn->session);
- free(conn->pre_shared_secret);
- free(conn->subject_match);
- free(conn->altsubject_match);
- free(conn->push_buf);
- free(conn->pull_buf);
- free(conn);
+ os_free(conn->pre_shared_secret);
+ os_free(conn->subject_match);
+ os_free(conn->altsubject_match);
+ os_free(conn->push_buf);
+ os_free(conn->pull_buf);
+ os_free(conn);
}
@@ -258,6 +392,9 @@ int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
{
+ struct tls_global *global = ssl_ctx;
+ int ret;
+
if (conn == NULL)
return -1;
@@ -265,11 +402,46 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
* because the connection was already terminated in practice
* and "close notify" shutdown alert would confuse AS. */
gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
- free(conn->push_buf);
+ os_free(conn->push_buf);
conn->push_buf = NULL;
conn->push_buf_len = 0;
conn->established = 0;
- /* TODO: what to do trigger new handshake for re-auth? */
+ conn->final_phase_finished = 0;
+#ifdef GNUTLS_IA
+ if (conn->session_keys) {
+ os_memset(conn->session_keys, 0, conn->session_keys_len);
+ os_free(conn->session_keys);
+ }
+ conn->session_keys_len = 0;
+#endif /* GNUTLS_IA */
+
+ gnutls_deinit(conn->session);
+ if (tls_gnutls_init_session(global, conn)) {
+ wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
+ "for session resumption use");
+ return -1;
+ }
+
+ ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
+ conn->params_set ? conn->xcred :
+ global->xcred);
+ if (ret < 0) {
+ wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
+ "for session resumption: %s", gnutls_strerror(ret));
+ return -1;
+ }
+
+ if (global->session_data) {
+ ret = gnutls_session_set_data(conn->session,
+ global->session_data,
+ global->session_data_size);
+ if (ret < 0) {
+ wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
+ "data: %s", gnutls_strerror(ret));
+ return -1;
+ }
+ }
+
return 0;
}
@@ -309,15 +481,15 @@ static int tls_match_altsubject(X509 *cert, const char *match)
wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
field, gen->d.ia5->data);
- len = strlen(field) + 1 + strlen((char *) gen->d.ia5->data) +
- 1;
- tmp = malloc(len);
+ len = os_strlen(field) + 1 +
+ strlen((char *) gen->d.ia5->data) + 1;
+ tmp = os_malloc(len);
if (tmp == NULL)
continue;
snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
if (strstr(tmp, match))
found++;
- free(tmp);
+ os_free(tmp);
}
return found;
@@ -380,18 +552,18 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
if (conn == NULL || params == NULL)
return -1;
- free(conn->subject_match);
+ os_free(conn->subject_match);
conn->subject_match = NULL;
if (params->subject_match) {
- conn->subject_match = strdup(params->subject_match);
+ conn->subject_match = os_strdup(params->subject_match);
if (conn->subject_match == NULL)
return -1;
}
- free(conn->altsubject_match);
+ os_free(conn->altsubject_match);
conn->altsubject_match = NULL;
if (params->altsubject_match) {
- conn->altsubject_match = strdup(params->altsubject_match);
+ conn->altsubject_match = os_strdup(params->altsubject_match);
if (conn->altsubject_match == NULL)
return -1;
}
@@ -415,6 +587,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
"'%s' in DER format: %s",
params->ca_cert,
gnutls_strerror(ret));
+ return -1;
}
}
}
@@ -437,8 +610,33 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return ret;
}
}
+ } else if (params->private_key) {
+ int pkcs12_ok = 0;
+#ifdef PKCS12_FUNCS
+ /* Try to load in PKCS#12 format */
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+ ret = gnutls_certificate_set_x509_simple_pkcs12_file(
+ conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
+ params->private_key_passwd);
+ if (ret != 0) {
+ wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+ "PKCS#12 format: %s", gnutls_strerror(ret));
+ return -1;
+ } else
+ pkcs12_ok = 1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* PKCS12_FUNCS */
+
+ if (!pkcs12_ok) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
+ "included");
+ return -1;
+ }
}
+ conn->tls_ia = params->tls_ia;
+ conn->params_set = 1;
+
ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
conn->xcred);
if (ret < 0) {
@@ -446,13 +644,122 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
gnutls_strerror(ret));
}
+#ifdef GNUTLS_IA
+ if (conn->iacred_cli)
+ gnutls_ia_free_client_credentials(conn->iacred_cli);
+
+ ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
+ gnutls_strerror(ret));
+ return -1;
+ }
+
+ ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
+ conn->iacred_cli);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
+ gnutls_strerror(ret));
+ gnutls_ia_free_client_credentials(conn->iacred_cli);
+ conn->iacred_cli = NULL;
+ return -1;
+ }
+#endif /* GNUTLS_IE */
+
return ret;
}
-int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
+int tls_global_set_params(void *tls_ctx,
+ const struct tls_connection_params *params)
{
- /* TODO */
+ struct tls_global *global = tls_ctx;
+ int ret;
+
+ /* Currently, global parameters are only set when running in server
+ * mode. */
+ global->server = 1;
+
+ if (global->params_set) {
+ gnutls_certificate_free_credentials(global->xcred);
+ global->params_set = 0;
+ }
+
+ ret = gnutls_certificate_allocate_credentials(&global->xcred);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
+ "%s", gnutls_strerror(ret));
+ return -1;
+ }
+
+ if (params->ca_cert) {
+ ret = gnutls_certificate_set_x509_trust_file(
+ global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
+ "in PEM format: %s", params->ca_cert,
+ gnutls_strerror(ret));
+ ret = gnutls_certificate_set_x509_trust_file(
+ global->xcred, params->ca_cert,
+ GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to read CA cert "
+ "'%s' in DER format: %s",
+ params->ca_cert,
+ gnutls_strerror(ret));
+ goto fail;
+ }
+ }
+ }
+
+ if (params->client_cert && params->private_key) {
+ /* TODO: private_key_passwd? */
+ ret = gnutls_certificate_set_x509_key_file(
+ global->xcred, params->client_cert,
+ params->private_key, GNUTLS_X509_FMT_PEM);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
+ "in PEM format: %s", gnutls_strerror(ret));
+ ret = gnutls_certificate_set_x509_key_file(
+ global->xcred, params->client_cert,
+ params->private_key, GNUTLS_X509_FMT_DER);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to read client "
+ "cert/key in DER format: %s",
+ gnutls_strerror(ret));
+ goto fail;
+ }
+ }
+ } else if (params->private_key) {
+ int pkcs12_ok = 0;
+#ifdef PKCS12_FUNCS
+ /* Try to load in PKCS#12 format */
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+ ret = gnutls_certificate_set_x509_simple_pkcs12_file(
+ global->xcred, params->private_key,
+ GNUTLS_X509_FMT_DER, params->private_key_passwd);
+ if (ret != 0) {
+ wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+ "PKCS#12 format: %s", gnutls_strerror(ret));
+ goto fail;
+ } else
+ pkcs12_ok = 1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* PKCS12_FUNCS */
+
+ if (!pkcs12_ok) {
+ wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
+ "included");
+ goto fail;
+ }
+ }
+
+ global->params_set = 1;
+
+ return 0;
+
+fail:
+ gnutls_certificate_free_credentials(global->xcred);
return -1;
}
@@ -460,62 +767,85 @@ int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
int tls_global_set_verify(void *ssl_ctx, int check_crl)
{
/* TODO */
- return -1;
+ return 0;
}
int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
int verify_peer)
{
- if (conn == NULL)
+ if (conn == NULL || conn->session == NULL)
return -1;
- /* TODO */
-
- return 1;
-}
-
+ conn->verify_peer = verify_peer;
+ gnutls_certificate_server_set_request(conn->session,
+ verify_peer ? GNUTLS_CERT_REQUIRE
+ : GNUTLS_CERT_REQUEST);
-int tls_global_client_cert(void *_ssl_ctx, const char *client_cert)
-{
- /* TODO */
- return -1;
-}
-
-
-int tls_global_private_key(void *_ssl_ctx, const char *private_key,
- const char *private_key_passwd)
-{
- /* TODO */
- return -1;
+ return 0;
}
int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
struct tls_keys *keys)
{
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
security_parameters_st *sec;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
if (conn == NULL || conn->session == NULL || keys == NULL)
return -1;
- memset(keys, 0, sizeof(*keys));
+ os_memset(keys, 0, sizeof(*keys));
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
sec = &conn->session->security_parameters;
keys->master_key = sec->master_secret;
keys->master_key_len = TLS_MASTER_SIZE;
keys->client_random = sec->client_random;
- keys->client_random_len = TLS_RANDOM_SIZE;
keys->server_random = sec->server_random;
+#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+ keys->client_random =
+ (u8 *) gnutls_session_get_client_random(conn->session);
+ keys->server_random =
+ (u8 *) gnutls_session_get_server_random(conn->session);
+ /* No access to master_secret */
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+#ifdef GNUTLS_IA
+ gnutls_ia_extract_inner_secret(conn->session,
+ (char *) conn->inner_secret);
+ keys->inner_secret = conn->inner_secret;
+ keys->inner_secret_len = TLS_MASTER_SIZE;
+#endif /* GNUTLS_IA */
+
+ keys->client_random_len = TLS_RANDOM_SIZE;
keys->server_random_len = TLS_RANDOM_SIZE;
return 0;
}
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len)
+{
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+ if (conn == NULL || conn->session == NULL)
+ return -1;
+
+ return gnutls_prf(conn->session, os_strlen(label), label,
+ server_random_first, 0, NULL, out_len, (char *) out);
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+ return -1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+}
+
+
static int tls_connection_verify_peer(struct tls_connection *conn)
{
unsigned int status, num_certs, i;
- time_t now;
+ struct os_time now;
const gnutls_datum_t *certs;
gnutls_x509_crt_t cert;
@@ -541,7 +871,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
return -1;
}
- now = time(NULL);
+ os_get_time(&now);
certs = gnutls_certificate_get_peers(conn->session, &num_certs);
if (certs == NULL) {
@@ -569,7 +899,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
gnutls_x509_crt_get_dn(cert, NULL, &len);
len++;
- buf = malloc(len + 1);
+ buf = os_malloc(len + 1);
if (buf) {
buf[0] = buf[len] = '\0';
gnutls_x509_crt_get_dn(cert, buf, &len);
@@ -581,10 +911,10 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
/* TODO: validate subject_match and altsubject_match */
}
- free(buf);
+ os_free(buf);
- if (gnutls_x509_crt_get_expiration_time(cert) < now ||
- gnutls_x509_crt_get_activation_time(cert) > now) {
+ if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
+ gnutls_x509_crt_get_activation_time(cert) > now.sec) {
wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
"not valid at this time",
i + 1, num_certs);
@@ -601,21 +931,26 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
const u8 *in_data, size_t in_len,
- size_t *out_len)
+ size_t *out_len, u8 **appl_data,
+ size_t *appl_data_len)
{
+ struct tls_global *global = ssl_ctx;
u8 *out_data;
int ret;
+ if (appl_data)
+ *appl_data = NULL;
+
if (in_data && in_len) {
if (conn->pull_buf) {
wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
"pull_buf", __func__, conn->pull_buf_len);
- free(conn->pull_buf);
+ os_free(conn->pull_buf);
}
- conn->pull_buf = malloc(in_len);
+ conn->pull_buf = os_malloc(in_len);
if (conn->pull_buf == NULL)
return NULL;
- memcpy(conn->pull_buf, in_data, in_len);
+ os_memcpy(conn->pull_buf, in_data, in_len);
conn->pull_buf_offset = conn->pull_buf;
conn->pull_buf_len = in_len;
}
@@ -624,6 +959,12 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
if (ret < 0) {
switch (ret) {
case GNUTLS_E_AGAIN:
+ if (global->server && conn->established &&
+ conn->push_buf == NULL) {
+ /* Need to return something to trigger
+ * completion of EAP-TLS. */
+ conn->push_buf = os_malloc(1);
+ }
break;
case GNUTLS_E_FATAL_ALERT_RECEIVED:
wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
@@ -637,17 +978,44 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
conn->failed++;
}
} else {
- wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
+ size_t size;
+
if (conn->verify_peer && tls_connection_verify_peer(conn)) {
wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
"failed validation");
conn->failed++;
return NULL;
}
+
+ if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
+ wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
+ conn->failed++;
+ return NULL;
+ }
+
+ if (conn->tls_ia)
+ wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
+ else {
+ wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
+ "successfully");
+ }
conn->established = 1;
if (conn->push_buf == NULL) {
/* Need to return something to get final TLS ACK. */
- conn->push_buf = malloc(1);
+ conn->push_buf = os_malloc(1);
+ }
+
+ gnutls_session_get_data(conn->session, NULL, &size);
+ if (global->session_data == NULL ||
+ global->session_data_size < size) {
+ os_free(global->session_data);
+ global->session_data = os_malloc(size);
+ }
+ if (global->session_data) {
+ global->session_data_size = size;
+ gnutls_session_get_data(conn->session,
+ global->session_data,
+ &global->session_data_size);
}
}
@@ -664,8 +1032,8 @@ u8 * tls_connection_server_handshake(void *ssl_ctx,
const u8 *in_data, size_t in_len,
size_t *out_len)
{
- /* TODO */
- return NULL;
+ return tls_connection_handshake(ssl_ctx, conn, in_data, in_len,
+ out_len, NULL, NULL);
}
@@ -674,13 +1042,24 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
u8 *out_data, size_t out_len)
{
ssize_t res;
+
+#ifdef GNUTLS_IA
+ if (conn->tls_ia)
+ res = gnutls_ia_send(conn->session, (char *) in_data, in_len);
+ else
+#endif /* GNUTLS_IA */
res = gnutls_record_send(conn->session, in_data, in_len);
+ if (res < 0) {
+ wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
+ __func__, gnutls_strerror(res));
+ return -1;
+ }
if (conn->push_buf == NULL)
return -1;
if (conn->push_buf_len < out_len)
out_len = conn->push_buf_len;
- memcpy(out_data, conn->push_buf, out_len);
- free(conn->push_buf);
+ os_memcpy(out_data, conn->push_buf, out_len);
+ os_free(conn->push_buf);
conn->push_buf = NULL;
conn->push_buf_len = 0;
return out_len;
@@ -696,15 +1075,70 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
if (conn->pull_buf) {
wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
"pull_buf", __func__, conn->pull_buf_len);
- free(conn->pull_buf);
+ os_free(conn->pull_buf);
}
- conn->pull_buf = malloc(in_len);
+ conn->pull_buf = os_malloc(in_len);
if (conn->pull_buf == NULL)
return -1;
- memcpy(conn->pull_buf, in_data, in_len);
+ os_memcpy(conn->pull_buf, in_data, in_len);
conn->pull_buf_offset = conn->pull_buf;
conn->pull_buf_len = in_len;
+#ifdef GNUTLS_IA
+ if (conn->tls_ia) {
+ res = gnutls_ia_recv(conn->session, (char *) out_data,
+ out_len);
+ if (out_len >= 12 &&
+ (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
+ res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED)) {
+ int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
+ wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
+ __func__, final ? "Final" : "Intermediate");
+
+ res = gnutls_ia_permute_inner_secret(
+ conn->session, conn->session_keys_len,
+ (char *) conn->session_keys);
+ if (conn->session_keys) {
+ os_memset(conn->session_keys, 0,
+ conn->session_keys_len);
+ os_free(conn->session_keys);
+ }
+ conn->session_keys = NULL;
+ conn->session_keys_len = 0;
+ if (res) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to permute "
+ "inner secret: %s",
+ __func__, gnutls_strerror(res));
+ return -1;
+ }
+
+ res = gnutls_ia_verify_endphase(conn->session,
+ (char *) out_data);
+ if (res == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Correct endphase "
+ "checksum", __func__);
+ } else {
+ wpa_printf(MSG_INFO, "%s: Endphase "
+ "verification failed: %s",
+ __func__, gnutls_strerror(res));
+ return -1;
+ }
+
+ if (final)
+ conn->final_phase_finished = 1;
+
+ return 0;
+ }
+
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
+ "(%s)", __func__, res,
+ gnutls_strerror(res));
+ }
+ return res;
+ }
+#endif /* GNUTLS_IA */
+
res = gnutls_record_recv(conn->session, out_data, out_len);
if (res < 0) {
wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
@@ -723,19 +1157,18 @@ int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
}
-#ifdef EAP_FAST
int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
const u8 *key, size_t key_len)
{
/* TODO */
return -1;
}
-#endif /* EAP_FAST */
-int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn)
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+ u8 *ciphers)
{
- /* TODO: set ADH-AES128-SHA cipher */
+ /* TODO */
return -1;
}
@@ -757,7 +1190,6 @@ int tls_connection_enable_workaround(void *ssl_ctx,
}
-#ifdef EAP_FAST
int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
@@ -765,7 +1197,6 @@ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
/* TODO */
return -1;
}
-#endif /* EAP_FAST */
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
@@ -790,3 +1221,150 @@ int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
return -1;
return conn->write_alerts;
}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ /* TODO */
+ return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+ unsigned int capa = 0;
+
+#ifdef GNUTLS_IA
+ capa |= TLS_CAPABILITY_IA;
+#endif /* GNUTLS_IA */
+
+ return capa;
+}
+
+
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+ int tls_ia)
+{
+#ifdef GNUTLS_IA
+ int ret;
+
+ if (conn == NULL)
+ return -1;
+
+ conn->tls_ia = tls_ia;
+ if (!tls_ia)
+ return 0;
+
+ ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
+ gnutls_strerror(ret));
+ return -1;
+ }
+
+ ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
+ conn->iacred_srv);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
+ gnutls_strerror(ret));
+ gnutls_ia_free_server_credentials(conn->iacred_srv);
+ conn->iacred_srv = NULL;
+ return -1;
+ }
+
+ return 0;
+#else /* GNUTLS_IA */
+ return -1;
+#endif /* GNUTLS_IA */
+}
+
+
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+ struct tls_connection *conn,
+ int final,
+ u8 *out_data, size_t out_len)
+{
+#ifdef GNUTLS_IA
+ int ret;
+
+ if (conn == NULL || conn->session == NULL || !conn->tls_ia)
+ return -1;
+
+ ret = gnutls_ia_permute_inner_secret(conn->session,
+ conn->session_keys_len,
+ (char *) conn->session_keys);
+ if (conn->session_keys) {
+ os_memset(conn->session_keys, 0, conn->session_keys_len);
+ os_free(conn->session_keys);
+ }
+ conn->session_keys = NULL;
+ conn->session_keys_len = 0;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
+ __func__, gnutls_strerror(ret));
+ return -1;
+ }
+
+ ret = gnutls_ia_endphase_send(conn->session, final);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
+ __func__, gnutls_strerror(ret));
+ return -1;
+ }
+
+ if (conn->push_buf == NULL)
+ return -1;
+ if (conn->push_buf_len < out_len)
+ out_len = conn->push_buf_len;
+ os_memcpy(out_data, conn->push_buf, out_len);
+ os_free(conn->push_buf);
+ conn->push_buf = NULL;
+ conn->push_buf_len = 0;
+ return out_len;
+#else /* GNUTLS_IA */
+ return -1;
+#endif /* GNUTLS_IA */
+}
+
+
+int tls_connection_ia_final_phase_finished(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+
+ return conn->final_phase_finished;
+}
+
+
+int tls_connection_ia_permute_inner_secret(void *tls_ctx,
+ struct tls_connection *conn,
+ const u8 *key, size_t key_len)
+{
+#ifdef GNUTLS_IA
+ if (conn == NULL || !conn->tls_ia)
+ return -1;
+
+ if (conn->session_keys) {
+ os_memset(conn->session_keys, 0, conn->session_keys_len);
+ os_free(conn->session_keys);
+ }
+ conn->session_keys_len = 0;
+
+ if (key) {
+ conn->session_keys = os_malloc(key_len);
+ if (conn->session_keys == NULL)
+ return -1;
+ os_memcpy(conn->session_keys, key, key_len);
+ conn->session_keys_len = key_len;
+ } else {
+ conn->session_keys = NULL;
+ conn->session_keys_len = 0;
+ }
+
+ return 0;
+#else /* GNUTLS_IA */
+ return -1;
+#endif /* GNUTLS_IA */
+}
diff --git a/contrib/wpa_supplicant/tls_internal.c b/contrib/wpa_supplicant/tls_internal.c
new file mode 100644
index 000000000000..a3858dd8a9c7
--- /dev/null
+++ b/contrib/wpa_supplicant/tls_internal.c
@@ -0,0 +1,326 @@
+/*
+ * WPA Supplicant / TLS interface functions and an internal TLS implementation
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file interface functions for hostapd/wpa_supplicant to use the
+ * integrated TLSv1 implementation.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "tls.h"
+#include "tlsv1_client.h"
+
+
+static int tls_ref_count = 0;
+
+struct tls_global {
+ int dummy;
+};
+
+struct tls_connection {
+ struct tlsv1_client *client;
+};
+
+
+void * tls_init(const struct tls_config *conf)
+{
+ struct tls_global *global;
+
+ if (tls_ref_count == 0) {
+ if (tlsv1_client_global_init())
+ return NULL;
+ }
+ tls_ref_count++;
+
+ global = os_zalloc(sizeof(*global));
+ if (global == NULL)
+ return NULL;
+
+ return global;
+}
+
+void tls_deinit(void *ssl_ctx)
+{
+ struct tls_global *global = ssl_ctx;
+ tls_ref_count--;
+ if (tls_ref_count == 0) {
+ tlsv1_client_global_deinit();
+ }
+ os_free(global);
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+ return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+ struct tls_connection *conn;
+
+ conn = os_zalloc(sizeof(*conn));
+ if (conn == NULL)
+ return NULL;
+
+ conn->client = tlsv1_client_init();
+ if (conn->client == NULL) {
+ os_free(conn);
+ return NULL;
+ }
+
+ return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return;
+ tlsv1_client_deinit(conn->client);
+ os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+ return tlsv1_client_established(conn->client);
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+ return tlsv1_client_shutdown(conn->client);
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+ const struct tls_connection_params *params)
+{
+ if (tlsv1_client_set_ca_cert(conn->client, params->ca_cert,
+ params->ca_cert_blob,
+ params->ca_cert_blob_len,
+ params->ca_path)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
+ "certificates");
+ return -1;
+ }
+
+ if (tlsv1_client_set_client_cert(conn->client, params->client_cert,
+ params->client_cert_blob,
+ params->client_cert_blob_len)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to configure client "
+ "certificate");
+ return -1;
+ }
+
+ if (tlsv1_client_set_private_key(conn->client,
+ 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");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+ const struct tls_connection_params *params)
+{
+ wpa_printf(MSG_INFO, "TLS: not implemented - %s", __func__);
+ return -1;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+ wpa_printf(MSG_INFO, "TLS: not implemented - %s", __func__);
+ return -1;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+ int verify_peer)
+{
+ return -1;
+}
+
+
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+ int tls_ia)
+{
+ return -1;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+ struct tls_keys *keys)
+{
+ return tlsv1_client_get_keys(conn->client, keys);
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len)
+{
+ return tlsv1_client_prf(conn->client, label, server_random_first,
+ out, out_len);
+}
+
+
+u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len, u8 **appl_data,
+ size_t *appl_data_len)
+{
+ if (appl_data)
+ *appl_data = NULL;
+
+ wpa_printf(MSG_DEBUG, "TLS: %s(in_data=%p in_len=%lu)",
+ __func__, in_data, (unsigned long) in_len);
+ return tlsv1_client_handshake(conn->client, in_data, in_len, out_len);
+}
+
+
+u8 * tls_connection_server_handshake(void *tls_ctx,
+ struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len)
+{
+ wpa_printf(MSG_INFO, "TLS: not implemented - %s", __func__);
+ return NULL;
+}
+
+
+int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ return tlsv1_client_encrypt(conn->client, in_data, in_len, out_data,
+ out_len);
+}
+
+
+int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ return tlsv1_client_decrypt(conn->client, in_data, in_len, out_data,
+ out_len);
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+ return tlsv1_client_resumed(conn->client);
+}
+
+
+int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
+ const u8 *key, size_t key_len)
+{
+ return tlsv1_client_set_master_key(conn->client, key, key_len);
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+ u8 *ciphers)
+{
+ return tlsv1_client_set_cipher_list(conn->client, ciphers);
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ if (conn == NULL)
+ return -1;
+ return tlsv1_client_get_cipher(conn->client, buf, buflen);
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+ int ext_type, const u8 *data,
+ size_t data_len)
+{
+ return tlsv1_client_hello_ext(conn->client, ext_type, data, data_len);
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+ return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+ return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ return tlsv1_client_get_keyblock_size(conn->client);
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+ return 0;
+}
+
+
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+ struct tls_connection *conn,
+ int final,
+ u8 *out_data, size_t out_len)
+{
+ return -1;
+}
+
+
+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;
+}
diff --git a/contrib/wpa_supplicant/tls_none.c b/contrib/wpa_supplicant/tls_none.c
index 07fd879ec8c8..ad08d5076c88 100644
--- a/contrib/wpa_supplicant/tls_none.c
+++ b/contrib/wpa_supplicant/tls_none.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / SSL/TLS interface functions for no TLS case
- * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,8 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
+#include "includes.h"
#include "common.h"
#include "tls.h"
@@ -26,3 +25,217 @@ void * tls_init(const struct tls_config *conf)
void tls_deinit(void *ssl_ctx)
{
}
+
+
+#ifdef EAP_TLS_NONE
+
+int tls_get_errors(void *tls_ctx)
+{
+ return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+ return NULL;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+ return -1;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+ return -1;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+ const struct tls_connection_params *params)
+{
+ return -1;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+ const struct tls_connection_params *params)
+{
+ return -1;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+ return -1;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+ int verify_peer)
+{
+ return -1;
+}
+
+
+int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
+ int tls_ia)
+{
+ return -1;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+ struct tls_keys *keys)
+{
+ return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len)
+{
+ return -1;
+}
+
+
+u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len, u8 **appl_data,
+ size_t *appl_data_len)
+{
+ return NULL;
+}
+
+
+u8 * tls_connection_server_handshake(void *tls_ctx,
+ struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len)
+{
+ return NULL;
+}
+
+
+int tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ return -1;
+}
+
+
+int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ return -1;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+ return 0;
+}
+
+
+int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
+ const u8 *key, size_t key_len)
+{
+ return -1;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+ u8 *ciphers)
+{
+ return -1;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ return -1;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+ int ext_type, const u8 *data,
+ size_t data_len)
+{
+ return -1;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+ return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+ return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+ return 0;
+}
+
+
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+ struct tls_connection *conn,
+ int final,
+ u8 *out_data, size_t out_len)
+{
+ return -1;
+}
+
+
+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;
+}
+
+#endif /* EAP_TLS_NONE */
diff --git a/contrib/wpa_supplicant/tls_openssl.c b/contrib/wpa_supplicant/tls_openssl.c
index 08d5a800daab..c8d941f7a113 100644
--- a/contrib/wpa_supplicant/tls_openssl.c
+++ b/contrib/wpa_supplicant/tls_openssl.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / SSL/TLS interface functions for openssl
- * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#ifndef CONFIG_SMARTCARD
#ifndef OPENSSL_NO_ENGINE
@@ -235,7 +233,7 @@ static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
goto err;
}
- if (hash_size != flen) {
+ 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,
@@ -248,7 +246,7 @@ static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
}
len = RSA_size(rsa);
- buf = malloc(len);
+ buf = os_malloc(len);
if (buf == NULL) {
RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
goto err;
@@ -264,7 +262,7 @@ static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
ret = len;
err:
- free(buf);
+ os_free(buf);
CryptDestroyHash(hash);
return ret;
@@ -287,14 +285,14 @@ static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
CryptReleaseContext(priv->crypt_prov, 0);
if (priv->cert)
CertFreeCertificateContext(priv->cert);
- free(priv);
+ os_free(priv);
}
static int cryptoapi_finish(RSA *rsa)
{
cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
- free((void *) rsa->meth);
+ os_free((void *) rsa->meth);
rsa->meth = NULL;
return 1;
}
@@ -315,8 +313,7 @@ static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
if (strncmp(name, "cert://", 7) == 0) {
unsigned short wbuf[255];
- MultiByteToWideChar(CP_ACP, 0, name + 7, -1,
- wbuf, sizeof(wbuf));
+ MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
PKCS_7_ASN_ENCODING,
0, CERT_FIND_SUBJECT_STR,
@@ -327,8 +324,8 @@ static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
const char *hash = name + 7;
unsigned char *buf;
- len = strlen(hash) / 2;
- buf = malloc(len);
+ len = os_strlen(hash) / 2;
+ buf = os_malloc(len);
if (buf && hexstr2bin(hash, buf, len) == 0) {
blob.cbData = len;
blob.pbData = buf;
@@ -338,7 +335,7 @@ static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
0, CERT_FIND_HASH,
&blob, NULL);
}
- free(buf);
+ os_free(buf);
}
CertCloseStore(cs, 0);
@@ -359,17 +356,15 @@ static int tls_cryptoapi_cert(SSL *ssl, const char *name)
strncmp(name, "hash://", 7) != 0))
return -1;
- priv = malloc(sizeof(*priv));
- rsa_meth = malloc(sizeof(*rsa_meth));
+ 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");
- free(priv);
- free(rsa_meth);
+ os_free(priv);
+ os_free(rsa_meth);
return -1;
}
- memset(priv, 0, sizeof(*priv));
- memset(rsa_meth, 0, sizeof(*rsa_meth));
priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
if (priv->cert == NULL) {
@@ -419,8 +414,11 @@ static int tls_cryptoapi_cert(SSL *ssl, const char *name)
goto err;
}
- if (!SSL_use_certificate(ssl, cert))
+ 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;
@@ -442,7 +440,7 @@ err:
if (rsa)
RSA_free(rsa);
else {
- free(rsa_meth);
+ os_free(rsa_meth);
cryptoapi_free_data(priv);
}
return -1;
@@ -455,6 +453,10 @@ static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
PCCERT_CONTEXT ctx = NULL;
X509 *cert;
char buf[128];
+ const char *store;
+#ifdef UNICODE
+ WCHAR *wstore;
+#endif /* UNICODE */
if (mingw_load_crypto_func())
return -1;
@@ -462,10 +464,20 @@ static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
return -1;
- cs = CertOpenSystemStore(0, name + 13);
+ 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__, name + 13,
+ "'%s': error=%d", __func__, store,
(int) GetLastError());
return -1;
}
@@ -643,21 +655,25 @@ static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
{
char *engine_id = "pkcs11";
const char *pre_cmd[] = {
- "SO_PATH", pkcs11_so_path,
- "ID", engine_id,
+ "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", pkcs11_module_path,
+ "MODULE_PATH", NULL /* pkcs11_module_path */,
NULL, NULL
};
if (!pkcs11_so_path || !pkcs11_module_path)
return 0;
+ pre_cmd[1] = pkcs11_so_path;
+ pre_cmd[3] = engine_id;
+ post_cmd[1] = pkcs11_module_path;
+
wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
pkcs11_so_path);
@@ -673,8 +689,8 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
{
char *engine_id = "opensc";
const char *pre_cmd[] = {
- "SO_PATH", opensc_so_path,
- "ID", engine_id,
+ "SO_PATH", NULL /* opensc_so_path */,
+ "ID", NULL /* engine_id */,
"LIST_ADD", "1",
"LOAD", NULL,
NULL, NULL
@@ -683,6 +699,9 @@ static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
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);
@@ -853,15 +872,14 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
SSL_CTX *ssl = ssl_ctx;
struct tls_connection *conn;
- conn = malloc(sizeof(*conn));
+ conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
- memset(conn, 0, sizeof(*conn));
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
tls_show_errors(MSG_INFO, __func__,
"Failed to initialize new SSL connection");
- free(conn);
+ os_free(conn);
return NULL;
}
@@ -875,7 +893,7 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
tls_show_errors(MSG_INFO, __func__,
"Failed to create a new BIO for ssl_in");
SSL_free(conn->ssl);
- free(conn);
+ os_free(conn);
return NULL;
}
@@ -885,7 +903,7 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
"Failed to create a new BIO for ssl_out");
SSL_free(conn->ssl);
BIO_free(conn->ssl_in);
- free(conn);
+ os_free(conn);
return NULL;
}
@@ -899,12 +917,12 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
- free(conn->pre_shared_secret);
+ os_free(conn->pre_shared_secret);
SSL_free(conn->ssl);
tls_engine_deinit(conn);
- free(conn->subject_match);
- free(conn->altsubject_match);
- free(conn);
+ os_free(conn->subject_match);
+ os_free(conn->altsubject_match);
+ os_free(conn);
}
@@ -928,55 +946,71 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
}
-static int tls_match_altsubject(X509 *cert, const char *match)
+static int tls_match_altsubject_component(X509 *cert, int type,
+ const char *value, size_t len)
{
GENERAL_NAME *gen;
- char *field, *tmp;
void *ext;
int i, found = 0;
- size_t len;
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);
- switch (gen->type) {
- case GEN_EMAIL:
- field = "EMAIL";
- break;
- case GEN_DNS:
- field = "DNS";
- break;
- case GEN_URI:
- field = "URI";
- break;
- default:
- field = NULL;
- wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
- "unsupported type=%d", gen->type);
- break;
- }
-
- if (!field)
- continue;
-
- wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
- field, gen->d.ia5->data);
- len = strlen(field) + 1 + strlen((char *) gen->d.ia5->data) +
- 1;
- tmp = malloc(len);
- if (tmp == NULL)
+ if (gen->type != type)
continue;
- snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
- if (strstr(tmp, match))
+ if (os_strlen((char *) gen->d.ia5->data) == len &&
+ os_memcmp(value, gen->d.ia5->data, len) == 0)
found++;
- free(tmp);
}
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;
+}
+
+
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
@@ -1006,7 +1040,7 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
"preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
preverify_ok, err,
X509_verify_cert_error_string(err), depth, buf);
- if (depth == 0 && match && strstr(buf, match) == NULL) {
+ 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;
@@ -1071,11 +1105,20 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
}
if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ unsigned long err = ERR_peek_error();
tls_show_errors(MSG_WARNING, __func__,
"Failed to add ca_cert_blob to "
"certificate store");
- X509_free(cert);
- return -1;
+ 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 "
@@ -1128,9 +1171,8 @@ static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
}
-int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
+static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
if (ca_cert) {
if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
{
@@ -1174,23 +1216,22 @@ int tls_global_set_verify(void *ssl_ctx, int check_crl)
}
-static int tls_connection_set_subject_match(void *ssl_ctx,
- struct tls_connection *conn,
+static int tls_connection_set_subject_match(struct tls_connection *conn,
const char *subject_match,
const char *altsubject_match)
{
- free(conn->subject_match);
+ os_free(conn->subject_match);
conn->subject_match = NULL;
if (subject_match) {
- conn->subject_match = strdup(subject_match);
+ conn->subject_match = os_strdup(subject_match);
if (conn->subject_match == NULL)
return -1;
}
- free(conn->altsubject_match);
+ os_free(conn->altsubject_match);
conn->altsubject_match = NULL;
if (altsubject_match) {
- conn->altsubject_match = strdup(altsubject_match);
+ conn->altsubject_match = os_strdup(altsubject_match);
if (conn->altsubject_match == NULL)
return -1;
}
@@ -1219,8 +1260,7 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
}
-static int tls_connection_client_cert(void *ssl_ctx,
- struct tls_connection *conn,
+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)
@@ -1270,10 +1310,9 @@ static int tls_connection_client_cert(void *ssl_ctx,
}
-int tls_global_client_cert(void *_ssl_ctx, const char *client_cert)
+static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
{
#ifndef OPENSSL_NO_STDIO
- SSL_CTX *ssl_ctx = _ssl_ctx;
if (client_cert == NULL)
return 0;
@@ -1300,9 +1339,9 @@ static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
if (password == NULL) {
return 0;
}
- strncpy(buf, (char *) password, size);
+ os_strncpy(buf, (char *) password, size);
buf[size - 1] = '\0';
- return strlen(buf);
+ return os_strlen(buf);
}
@@ -1322,6 +1361,7 @@ static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
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");
@@ -1388,7 +1428,7 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
FILE *f;
PKCS12 *p12;
- f = fopen(private_key, "r");
+ f = fopen(private_key, "rb");
if (f == NULL)
return -1;
@@ -1434,8 +1474,7 @@ static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
}
-static int tls_connection_engine_private_key(void *_ssl_ctx,
- struct tls_connection *conn)
+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) {
@@ -1472,7 +1511,7 @@ static int tls_connection_private_key(void *_ssl_ctx,
return 0;
if (private_key_passwd) {
- passwd = strdup(private_key_passwd);
+ passwd = os_strdup(private_key_passwd);
if (passwd == NULL)
return -1;
} else
@@ -1582,13 +1621,13 @@ static int tls_connection_private_key(void *_ssl_ctx,
if (!ok) {
wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key");
- free(passwd);
+ os_free(passwd);
ERR_clear_error();
return -1;
}
ERR_clear_error();
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
- free(passwd);
+ os_free(passwd);
if (!SSL_check_private_key(conn->ssl)) {
tls_show_errors(MSG_INFO, __func__, "Private key failed "
@@ -1601,17 +1640,16 @@ static int tls_connection_private_key(void *_ssl_ctx,
}
-int tls_global_private_key(void *_ssl_ctx, const char *private_key,
- const char *private_key_passwd)
+static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
+ const char *private_key_passwd)
{
- SSL_CTX *ssl_ctx = _ssl_ctx;
char *passwd;
if (private_key == NULL)
return 0;
if (private_key_passwd) {
- passwd = strdup(private_key_passwd);
+ passwd = os_strdup(private_key_passwd);
if (passwd == NULL)
return -1;
} else
@@ -1629,11 +1667,11 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
tls_show_errors(MSG_INFO, __func__,
"Failed to load private key");
- free(passwd);
+ os_free(passwd);
ERR_clear_error();
return -1;
}
- free(passwd);
+ os_free(passwd);
ERR_clear_error();
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
@@ -1647,8 +1685,7 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
}
-static int tls_connection_dh(void *ssl_ctx, struct tls_connection *conn,
- const char *dh_file)
+static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
{
#ifdef OPENSSL_NO_DH
if (dh_file == NULL)
@@ -1733,7 +1770,7 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
return -1;
- memset(keys, 0, sizeof(*keys));
+ 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;
@@ -1745,13 +1782,25 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
}
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len)
+{
+ return -1;
+}
+
+
u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
const u8 *in_data, size_t in_len,
- size_t *out_len)
+ size_t *out_len, u8 **appl_data,
+ size_t *appl_data_len)
{
int res;
u8 *out_data;
+ if (appl_data)
+ *appl_data = NULL;
+
/*
* Give TLS handshake data from the server (if available) to OpenSSL
* for processing.
@@ -1782,7 +1831,7 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
/* 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 = malloc(res == 0 ? 1 : res);
+ out_data = os_malloc(res == 0 ? 1 : res);
if (out_data == NULL) {
wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
"handshake output (%d bytes)", res);
@@ -1805,6 +1854,26 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
return NULL;
}
*out_len = res;
+
+ if (SSL_is_init_finished(conn->ssl) && appl_data) {
+ *appl_data = os_malloc(in_len);
+ if (*appl_data) {
+ res = SSL_read(conn->ssl, *appl_data, in_len);
+ if (res < 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to read possible "
+ "Application Data");
+ os_free(*appl_data);
+ *appl_data = NULL;
+ } else {
+ *appl_data_len = res;
+ wpa_hexdump_key(MSG_MSGDUMP, "SSL: Application"
+ " Data in Finish message",
+ *appl_data, *appl_data_len);
+ }
+ }
+ }
+
return out_data;
}
@@ -1833,7 +1902,7 @@ u8 * tls_connection_server_handshake(void *ssl_ctx,
res = BIO_ctrl_pending(conn->ssl_out);
wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
- out_data = malloc(res == 0 ? 1 : res);
+ out_data = os_malloc(res == 0 ? 1 : res);
if (out_data == NULL) {
wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
"handshake output (%d bytes)", res);
@@ -1930,7 +1999,7 @@ int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
}
-#ifdef EAP_FAST
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
/* 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. */
@@ -1944,7 +2013,8 @@ static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
if (conn == NULL || conn->pre_shared_secret == 0)
return 0;
- memcpy(secret, conn->pre_shared_secret, conn->pre_shared_secret_len);
+ os_memcpy(secret, conn->pre_shared_secret,
+ conn->pre_shared_secret_len);
*secret_len = conn->pre_shared_secret_len;
return 1;
@@ -1957,14 +2027,14 @@ int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
if (conn == NULL || key_len > SSL_MAX_MASTER_KEY_LENGTH)
return -1;
- free(conn->pre_shared_secret);
+ os_free(conn->pre_shared_secret);
conn->pre_shared_secret = NULL;
conn->pre_shared_secret_len = 0;
if (key) {
- conn->pre_shared_secret = malloc(key_len);
+ conn->pre_shared_secret = os_malloc(key_len);
if (conn->pre_shared_secret) {
- memcpy(conn->pre_shared_secret, key, key_len);
+ os_memcpy(conn->pre_shared_secret, key, key_len);
conn->pre_shared_secret_len = key_len;
}
if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
@@ -1977,17 +2047,58 @@ int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
return 0;
}
-#endif /* EAP_FAST */
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
-int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn)
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+ u8 *ciphers)
{
- if (conn == NULL || conn->ssl == NULL)
+ char buf[100], *pos, *end;
+ u8 *c;
+ int ret;
+
+ if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
return -1;
- if (SSL_set_cipher_list(conn->ssl, "ADH-AES128-SHA") != 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)
+ break;
+ pos += ret;
+
+ c++;
+ }
+
+ wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
+
+ if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
tls_show_errors(MSG_INFO, __func__,
- "Anon DH configuration failed");
+ "Cipher suite configuration failed");
return -1;
}
@@ -2006,7 +2117,8 @@ int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
if (name == NULL)
return -1;
- snprintf(buf, buflen, "%s", name);
+ os_snprintf(buf, buflen, "%s", name);
+ buf[buflen - 1] = '\0';
return 0;
}
@@ -2020,7 +2132,7 @@ int tls_connection_enable_workaround(void *ssl_ctx,
}
-#ifdef EAP_FAST
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC)
/* 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. */
@@ -2037,7 +2149,7 @@ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
return 0;
}
-#endif /* EAP_FAST */
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC */
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
@@ -2078,7 +2190,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
__func__, ERR_error_string(err, NULL));
}
- if (tls_connection_set_subject_match(tls_ctx, conn,
+ if (tls_connection_set_subject_match(conn,
params->subject_match,
params->altsubject_match))
return -1;
@@ -2087,7 +2199,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
params->ca_cert_blob_len,
params->ca_path))
return -1;
- if (tls_connection_client_cert(tls_ctx, conn, params->client_cert,
+ if (tls_connection_client_cert(conn, params->client_cert,
params->client_cert_blob,
params->client_cert_blob_len))
return -1;
@@ -2098,7 +2210,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
params->key_id);
if (ret)
return ret;
- if (tls_connection_engine_private_key(tls_ctx, conn))
+ if (tls_connection_engine_private_key(conn))
return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
} else if (tls_connection_private_key(tls_ctx, conn,
params->private_key,
@@ -2110,7 +2222,7 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
- if (tls_connection_dh(tls_ctx, conn, params->dh_file)) {
+ if (tls_connection_dh(conn, params->dh_file)) {
wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
params->dh_file);
return -1;
@@ -2122,6 +2234,31 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
}
+int tls_global_set_params(void *tls_ctx,
+ const struct tls_connection_params *params)
+{
+ SSL_CTX *ssl_ctx = tls_ctx;
+ 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;
+
+ return 0;
+}
+
+
int tls_connection_get_keyblock_size(void *tls_ctx,
struct tls_connection *conn)
{
@@ -2141,3 +2278,40 @@ int tls_connection_get_keyblock_size(void *tls_ctx,
EVP_MD_size(h) +
EVP_CIPHER_iv_length(c));
}
+
+
+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;
+}
+
+
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+ struct tls_connection *conn,
+ int final,
+ u8 *out_data, size_t out_len)
+{
+ return -1;
+}
+
+
+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;
+}
diff --git a/contrib/wpa_supplicant/tls_schannel.c b/contrib/wpa_supplicant/tls_schannel.c
index d06a1c34b41a..4ecfae0063fb 100644
--- a/contrib/wpa_supplicant/tls_schannel.c
+++ b/contrib/wpa_supplicant/tls_schannel.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / SSL/TLS interface functions for Microsoft Schannel
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -20,9 +20,7 @@
* TODO: add support for EAP-TLS (client cert/key conf)
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include <windows.h>
#include <wincrypt.h>
#include <schannel.h>
@@ -57,7 +55,7 @@ static int schannel_load_lib(struct tls_global *global)
{
INIT_SECURITY_INTERFACE pInitSecurityInterface;
- global->hsecurity = LoadLibrary("Secur32.dll");
+ global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
if (global->hsecurity == NULL) {
wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
__func__, (unsigned int) GetLastError());
@@ -93,12 +91,11 @@ void * tls_init(const struct tls_config *conf)
{
struct tls_global *global;
- global = malloc(sizeof(*global));
+ global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
- memset(global, 0, sizeof(*global));
if (schannel_load_lib(global)) {
- free(global);
+ os_free(global);
return NULL;
}
return global;
@@ -112,7 +109,7 @@ void tls_deinit(void *ssl_ctx)
if (global->my_cert_store)
CertCloseStore(global->my_cert_store, 0);
FreeLibrary(global->hsecurity);
- free(global);
+ os_free(global);
}
@@ -126,10 +123,9 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
{
struct tls_connection *conn;
- conn = malloc(sizeof(*conn));
+ conn = os_zalloc(sizeof(*conn));
if (conn == NULL)
return NULL;
- memset(conn, 0, sizeof(*conn));
conn->start = 1;
return conn;
@@ -141,7 +137,7 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
if (conn == NULL)
return;
- free(conn);
+ os_free(conn);
}
@@ -167,7 +163,8 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
}
-int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
+int tls_global_set_params(void *tls_ctx,
+ const struct tls_connection_params *params)
{
return -1;
}
@@ -186,27 +183,18 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
}
-int tls_global_client_cert(void *_ssl_ctx, const char *client_cert)
-{
- return -1;
-}
-
-
-int tls_global_private_key(void *_ssl_ctx, const char *private_key,
- const char *private_key_passwd)
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_keys *keys)
{
+ /* Schannel does not export master secret or client/server random. */
return -1;
}
-int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
- struct tls_keys *keys)
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+ const char *label, int server_random_first,
+ u8 *out, size_t out_len)
{
- if (conn == NULL || keys == NULL || !conn->eap_tls_prf_set)
- return -1;
-
- memset(keys, 0, sizeof(*keys));
-
/*
* Cannot get master_key from Schannel, but EapKeyBlock can be used to
* generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
@@ -215,8 +203,13 @@ int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
* and just use Schannel or CryptoAPI for low-level crypto
* functionality..
*/
- keys->eap_tls_prf = conn->eap_tls_prf;
- keys->eap_tls_prf_len = sizeof(conn->eap_tls_prf);
+
+ if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
+ os_strcmp(label, "client EAP encryption") != 0 ||
+ out_len > sizeof(conn->eap_tls_prf))
+ return -1;
+
+ os_memcpy(out, conn->eap_tls_prf, out_len);
return 0;
}
@@ -248,10 +241,17 @@ static u8 * tls_conn_hs_clienthello(struct tls_global *global,
outbuf.pBuffers = outbufs;
outbuf.ulVersion = SECBUFFER_VERSION;
+#ifdef UNICODE
+ status = global->sspi->InitializeSecurityContextW(
+ &conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
+ SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
+ &outbuf, &sspi_flags_out, &ts_expiry);
+#else /* UNICODE */
status = global->sspi->InitializeSecurityContextA(
&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
&outbuf, &sspi_flags_out, &ts_expiry);
+#endif /* UNICODE */
if (status != SEC_I_CONTINUE_NEEDED) {
wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
"failed - 0x%x",
@@ -265,10 +265,10 @@ static u8 * tls_conn_hs_clienthello(struct tls_global *global,
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
conn->start = 0;
*out_len = outbufs[0].cbBuffer;
- buf = malloc(*out_len);
+ buf = os_malloc(*out_len);
if (buf == NULL)
return NULL;
- memcpy(buf, outbufs[0].pvBuffer, *out_len);
+ os_memcpy(buf, outbufs[0].pvBuffer, *out_len);
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
return buf;
}
@@ -310,14 +310,16 @@ static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
kb.rgbIVs, sizeof(kb.rgbIVs));
- memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
+ os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
conn->eap_tls_prf_set = 1;
+ return 0;
}
u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
const u8 *in_data, size_t in_len,
- size_t *out_len)
+ size_t *out_len, u8 **appl_data,
+ size_t *appl_data_len)
{
struct tls_global *global = ssl_ctx;
DWORD sspi_flags, sspi_flags_out;
@@ -327,6 +329,9 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
TimeStamp ts_expiry;
u8 *out_buf = NULL;
+ if (appl_data)
+ *appl_data = NULL;
+
if (conn->start) {
return tls_conn_hs_clienthello(global, conn, out_len);
}
@@ -363,12 +368,19 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
outbuf.pBuffers = outbufs;
outbuf.ulVersion = SECBUFFER_VERSION;
+#ifdef UNICODE
+ status = global->sspi->InitializeSecurityContextW(
+ &conn->creds, &conn->context, NULL, sspi_flags, 0,
+ SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
+ &outbuf, &sspi_flags_out, &ts_expiry);
+#else /* UNICODE */
status = global->sspi->InitializeSecurityContextA(
&conn->creds, &conn->context, NULL, sspi_flags, 0,
SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
&outbuf, &sspi_flags_out, &ts_expiry);
+#endif /* UNICODE */
- wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContextA -> "
+ wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
"status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
"intype[1]=%d outlen[0]=%d",
(int) status, (int) inbufs[0].cbBuffer,
@@ -381,12 +393,14 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
outbufs[0].pvBuffer, outbufs[0].cbBuffer);
*out_len = outbufs[0].cbBuffer;
- out_buf = malloc(*out_len);
- if (out_buf == NULL)
- return NULL;
- memcpy(out_buf, outbufs[0].pvBuffer, *out_len);
+ out_buf = os_malloc(*out_len);
+ if (out_buf)
+ os_memcpy(out_buf, outbufs[0].pvBuffer,
+ *out_len);
global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
outbufs[0].pvBuffer = NULL;
+ if (out_buf == NULL)
+ return NULL;
}
}
@@ -406,14 +420,20 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
/* Need to return something to get final TLS ACK. */
if (out_buf == NULL)
- out_buf = malloc(1);
+ out_buf = os_malloc(1);
if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
"application data",
inbufs[1].pvBuffer, inbufs[1].cbBuffer);
- /* FIX: need to fix TLS API to allow this data to be
- * passed to the caller */
+ if (appl_data) {
+ *appl_data_len = outbufs[1].cbBuffer;
+ appl_data = os_malloc(*appl_data_len);
+ if (appl_data)
+ os_memcpy(appl_data,
+ outbufs[1].pvBuffer,
+ *appl_data_len);
+ }
global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
inbufs[1].pvBuffer = NULL;
}
@@ -494,12 +514,12 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
return -1;
}
- memset(&bufs, 0, sizeof(bufs));
+ os_memset(&bufs, 0, sizeof(bufs));
bufs[0].pvBuffer = out_data;
bufs[0].cbBuffer = sizes.cbHeader;
bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
- memcpy(out_data + sizes.cbHeader, in_data, in_len);
+ os_memcpy(out_data + sizes.cbHeader, in_data, in_len);
bufs[1].pvBuffer = out_data + sizes.cbHeader;
bufs[1].cbBuffer = in_len;
bufs[1].BufferType = SECBUFFER_DATA;
@@ -565,8 +585,8 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
wpa_hexdump(MSG_MSGDUMP, "Schannel: Encrypted data to DecryptMessage",
in_data, in_len);
- memset(&bufs, 0, sizeof(bufs));
- memcpy(out_data, in_data, in_len);
+ os_memset(&bufs, 0, sizeof(bufs));
+ os_memcpy(out_data, in_data, in_len);
bufs[0].pvBuffer = out_data;
bufs[0].cbBuffer = in_len;
bufs[0].BufferType = SECBUFFER_DATA;
@@ -618,7 +638,7 @@ int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
__func__);
return -1;
}
- memmove(out_data, bufs[i].pvBuffer, bufs[i].cbBuffer);
+ os_memmove(out_data, bufs[i].pvBuffer, bufs[i].cbBuffer);
return bufs[i].cbBuffer;
}
@@ -634,16 +654,15 @@ int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
}
-#ifdef EAP_FAST
int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
const u8 *key, size_t key_len)
{
return -1;
}
-#endif /* EAP_FAST */
-int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn)
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+ u8 *ciphers)
{
return -1;
}
@@ -663,17 +682,12 @@ int tls_connection_enable_workaround(void *ssl_ctx,
}
-#ifdef EAP_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)
{
return -1;
}
-#endif /* EAP_FAST */
int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
@@ -712,22 +726,29 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
if (global->my_cert_store == NULL &&
- (global->my_cert_store = CertOpenSystemStore(0, "MY")) == NULL) {
+ (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
+ NULL) {
wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
__func__, (unsigned int) GetLastError());
return -1;
}
- memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
+ os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
algs[0] = CALG_RSA_KEYX;
conn->schannel_cred.cSupportedAlgs = 1;
conn->schannel_cred.palgSupportedAlgs = algs;
conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
+#ifdef UNICODE
+ status = global->sspi->AcquireCredentialsHandleW(
+ NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
+ &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
+#else /* UNICODE */
status = global->sspi->AcquireCredentialsHandleA(
NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
+#endif /* UNICODE */
if (status != SEC_E_OK) {
wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
"0x%x", __func__, (unsigned int) status);
@@ -736,3 +757,40 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return 0;
}
+
+
+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;
+}
+
+
+int tls_connection_ia_send_phase_finished(void *tls_ctx,
+ struct tls_connection *conn,
+ int final,
+ u8 *out_data, size_t out_len)
+{
+ return -1;
+}
+
+
+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;
+}
diff --git a/contrib/wpa_supplicant/tlsv1_client.c b/contrib/wpa_supplicant/tlsv1_client.c
new file mode 100644
index 000000000000..2d62ff0ab60c
--- /dev/null
+++ b/contrib/wpa_supplicant/tlsv1_client.c
@@ -0,0 +1,2609 @@
+/*
+ * wpa_supplicant: TLSv1 client (RFC 2246)
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "base64.h"
+#include "md5.h"
+#include "sha1.h"
+#include "crypto.h"
+#include "tls.h"
+#include "tlsv1_common.h"
+#include "tlsv1_client.h"
+#include "x509v3.h"
+
+/* TODO:
+ * Support for a message fragmented across several records (RFC 2246, 6.2.1)
+ */
+
+struct tlsv1_client {
+ enum {
+ CLIENT_HELLO, SERVER_HELLO, SERVER_CERTIFICATE,
+ SERVER_KEY_EXCHANGE, SERVER_CERTIFICATE_REQUEST,
+ SERVER_HELLO_DONE, CLIENT_KEY_EXCHANGE, CHANGE_CIPHER_SPEC,
+ SERVER_CHANGE_CIPHER_SPEC, SERVER_FINISHED, ACK_FINISHED,
+ ESTABLISHED, FAILED
+ } state;
+
+ struct tlsv1_record_layer rl;
+
+ u8 session_id[TLS_SESSION_ID_MAX_LEN];
+ size_t session_id_len;
+ u8 client_random[TLS_RANDOM_LEN];
+ u8 server_random[TLS_RANDOM_LEN];
+ u8 master_secret[TLS_MASTER_SECRET_LEN];
+
+ u8 alert_level;
+ u8 alert_description;
+
+ unsigned int certificate_requested:1;
+ unsigned int session_resumed:1;
+ unsigned int ticket:1;
+ unsigned int ticket_key:1;
+
+ struct crypto_public_key *server_rsa_key;
+
+ struct crypto_hash *verify_md5_client;
+ struct crypto_hash *verify_sha1_client;
+ struct crypto_hash *verify_md5_server;
+ struct crypto_hash *verify_sha1_server;
+ struct crypto_hash *verify_md5_cert;
+ struct crypto_hash *verify_sha1_cert;
+
+#define MAX_CIPHER_COUNT 30
+ u16 cipher_suites[MAX_CIPHER_COUNT];
+ size_t num_cipher_suites;
+
+ u16 prev_cipher_suite;
+
+ u8 *client_hello_ext;
+ size_t client_hello_ext_len;
+
+ /* The prime modulus used for Diffie-Hellman */
+ u8 *dh_p;
+ size_t dh_p_len;
+ /* The generator used for Diffie-Hellman */
+ u8 *dh_g;
+ size_t dh_g_len;
+ /* The server's Diffie-Hellman public value */
+ u8 *dh_ys;
+ size_t dh_ys_len;
+
+ struct x509_certificate *trusted_certs;
+ struct x509_certificate *client_cert;
+ struct crypto_private_key *client_key;
+};
+
+
+static int tls_derive_keys(struct tlsv1_client *conn,
+ const u8 *pre_master_secret,
+ size_t pre_master_secret_len);
+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len);
+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len);
+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len);
+
+
+static void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
+{
+ conn->alert_level = level;
+ conn->alert_description = description;
+}
+
+
+static void tls_verify_hash_add(struct tlsv1_client *conn, const u8 *buf,
+ size_t len)
+{
+ if (conn->verify_md5_client && conn->verify_sha1_client) {
+ crypto_hash_update(conn->verify_md5_client, buf, len);
+ crypto_hash_update(conn->verify_sha1_client, buf, len);
+ }
+ if (conn->verify_md5_server && conn->verify_sha1_server) {
+ crypto_hash_update(conn->verify_md5_server, buf, len);
+ crypto_hash_update(conn->verify_sha1_server, buf, len);
+ }
+ if (conn->verify_md5_cert && conn->verify_sha1_cert) {
+ crypto_hash_update(conn->verify_md5_cert, buf, len);
+ crypto_hash_update(conn->verify_sha1_cert, buf, len);
+ }
+}
+
+
+static u8 * tls_send_alert(struct tlsv1_client *conn,
+ u8 level, u8 description,
+ size_t *out_len)
+{
+ u8 *alert, *pos, *length;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
+ *out_len = 0;
+
+ alert = os_malloc(10);
+ if (alert == NULL)
+ return NULL;
+
+ pos = alert;
+
+ /* TLSPlaintext */
+ /* ContentType type */
+ *pos++ = TLS_CONTENT_TYPE_ALERT;
+ /* ProtocolVersion version */
+ WPA_PUT_BE16(pos, TLS_VERSION);
+ pos += 2;
+ /* uint16 length (to be filled) */
+ length = pos;
+ pos += 2;
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Alert */
+ /* AlertLevel level */
+ *pos++ = level;
+ /* AlertDescription description */
+ *pos++ = description;
+
+ WPA_PUT_BE16(length, pos - length - 2);
+ *out_len = pos - alert;
+
+ return alert;
+}
+
+
+static u8 * tls_send_client_hello(struct tlsv1_client *conn,
+ size_t *out_len)
+{
+ u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
+ struct os_time now;
+ size_t len, i;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
+ *out_len = 0;
+
+ os_get_time(&now);
+ WPA_PUT_BE32(conn->client_random, now.sec);
+ if (os_get_random(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
+ wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
+ "client_random");
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
+ conn->client_random, TLS_RANDOM_LEN);
+
+ len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
+ hello = os_malloc(len);
+ if (hello == NULL)
+ return NULL;
+ end = hello + len;
+
+ rhdr = hello;
+ pos = rhdr + TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - ClientHello */
+ /* ProtocolVersion client_version */
+ WPA_PUT_BE16(pos, TLS_VERSION);
+ pos += 2;
+ /* Random random: uint32 gmt_unix_time, opaque random_bytes */
+ os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
+ pos += TLS_RANDOM_LEN;
+ /* SessionID session_id */
+ *pos++ = conn->session_id_len;
+ os_memcpy(pos, conn->session_id, conn->session_id_len);
+ pos += conn->session_id_len;
+ /* CipherSuite cipher_suites<2..2^16-1> */
+ WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
+ pos += 2;
+ for (i = 0; i < conn->num_cipher_suites; i++) {
+ WPA_PUT_BE16(pos, conn->cipher_suites[i]);
+ pos += 2;
+ }
+ /* CompressionMethod compression_methods<1..2^8-1> */
+ *pos++ = 1;
+ *pos++ = TLS_COMPRESSION_NULL;
+
+ if (conn->client_hello_ext) {
+ os_memcpy(pos, conn->client_hello_ext,
+ conn->client_hello_ext_len);
+ pos += conn->client_hello_ext_len;
+ }
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+ tls_verify_hash_add(conn, hs_start, pos - hs_start);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(hello);
+ return NULL;
+ }
+
+ conn->state = SERVER_HELLO;
+
+ return hello;
+}
+
+
+static int tls_process_server_hello(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len, i;
+ u16 cipher_suite;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4)
+ goto decode_error;
+
+ /* HandshakeType msg_type */
+ if (*pos != TLS_HANDSHAKE_TYPE_SERVER_HELLO) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected ServerHello)", *pos);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHello");
+ pos++;
+ /* uint24 length */
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left)
+ goto decode_error;
+
+ /* body - ServerHello */
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: ServerHello", pos, len);
+ end = pos + len;
+
+ /* ProtocolVersion server_version */
+ if (end - pos < 2)
+ goto decode_error;
+ if (WPA_GET_BE16(pos) != TLS_VERSION) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
+ "ServerHello");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_PROTOCOL_VERSION);
+ return -1;
+ }
+ pos += 2;
+
+ /* Random random */
+ if (end - pos < TLS_RANDOM_LEN)
+ goto decode_error;
+
+ os_memcpy(conn->server_random, pos, TLS_RANDOM_LEN);
+ pos += TLS_RANDOM_LEN;
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
+ conn->server_random, TLS_RANDOM_LEN);
+
+ /* SessionID session_id */
+ if (end - pos < 1)
+ goto decode_error;
+ if (end - pos < 1 + *pos || *pos > TLS_SESSION_ID_MAX_LEN)
+ goto decode_error;
+ if (conn->session_id_len && conn->session_id_len == *pos &&
+ os_memcmp(conn->session_id, pos + 1, conn->session_id_len) == 0) {
+ pos += 1 + conn->session_id_len;
+ wpa_printf(MSG_DEBUG, "TLSv1: Resuming old session");
+ conn->session_resumed = 1;
+ } else {
+ conn->session_id_len = *pos;
+ pos++;
+ os_memcpy(conn->session_id, pos, conn->session_id_len);
+ pos += conn->session_id_len;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
+ conn->session_id, conn->session_id_len);
+
+ /* CipherSuite cipher_suite */
+ if (end - pos < 2)
+ goto decode_error;
+ cipher_suite = WPA_GET_BE16(pos);
+ pos += 2;
+ for (i = 0; i < conn->num_cipher_suites; i++) {
+ if (cipher_suite == conn->cipher_suites[i])
+ break;
+ }
+ if (i == conn->num_cipher_suites) {
+ wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
+ "cipher suite 0x%04x", cipher_suite);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ if (conn->session_resumed && cipher_suite != conn->prev_cipher_suite) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Server selected a different "
+ "cipher suite for a resumed connection (0x%04x != "
+ "0x%04x)", cipher_suite, conn->prev_cipher_suite);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_ILLEGAL_PARAMETER);
+ return -1;
+ }
+
+ if (tlsv1_record_set_cipher_suite(&conn->rl, cipher_suite) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set CipherSuite for "
+ "record layer");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ conn->prev_cipher_suite = cipher_suite;
+
+ if (conn->session_resumed || conn->ticket_key)
+ tls_derive_keys(conn, NULL, 0);
+
+ /* CompressionMethod compression_method */
+ if (end - pos < 1)
+ goto decode_error;
+ if (*pos != TLS_COMPRESSION_NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Server selected unexpected "
+ "compression 0x%02x", *pos);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_ILLEGAL_PARAMETER);
+ return -1;
+ }
+ pos++;
+
+ if (end != pos) {
+ wpa_hexdump(MSG_DEBUG, "TLSv1: Unexpected extra data in the "
+ "end of ServerHello", pos, end - pos);
+ goto decode_error;
+ }
+
+ *in_len = end - in_data;
+
+ conn->state = (conn->session_resumed || conn->ticket) ?
+ SERVER_CHANGE_CIPHER_SPEC : SERVER_CERTIFICATE;
+
+ return 0;
+
+decode_error:
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decode ServerHello");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+}
+
+
+static int tls_server_key_exchange_allowed(struct tlsv1_client *conn)
+{
+ const struct tls_cipher_suite *suite;
+
+ /* RFC 2246, Section 7.4.3 */
+ suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+ if (suite == NULL)
+ return 0;
+
+ switch (suite->key_exchange) {
+ case TLS_KEY_X_DHE_DSS:
+ case TLS_KEY_X_DHE_DSS_EXPORT:
+ case TLS_KEY_X_DHE_RSA:
+ case TLS_KEY_X_DHE_RSA_EXPORT:
+ case TLS_KEY_X_DH_anon_EXPORT:
+ case TLS_KEY_X_DH_anon:
+ return 1;
+ case TLS_KEY_X_RSA_EXPORT:
+ return 1 /* FIX: public key len > 512 bits */;
+ default:
+ return 0;
+ }
+}
+
+
+static int tls_process_certificate(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len, list_len, cert_len, idx;
+ u8 type;
+ struct x509_certificate *chain = NULL, *last = NULL, *cert;
+ int reason;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate message "
+ "(len=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected Certificate message "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ if (type == TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE)
+ return tls_process_server_key_exchange(conn, ct, in_data,
+ in_len);
+ if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
+ return tls_process_certificate_request(conn, ct, in_data,
+ in_len);
+ if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+ return tls_process_server_hello_done(conn, ct, in_data,
+ in_len);
+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected Certificate/"
+ "ServerKeyExchange/CertificateRequest/"
+ "ServerHelloDone)", type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "TLSv1: Received Certificate (certificate_list len %lu)",
+ (unsigned long) len);
+
+ /*
+ * opaque ASN.1Cert<2^24-1>;
+ *
+ * struct {
+ * ASN.1Cert certificate_list<1..2^24-1>;
+ * } Certificate;
+ */
+
+ end = pos + len;
+
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short Certificate "
+ "(left=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ list_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) != list_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate_list "
+ "length (len=%lu left=%lu)",
+ (unsigned long) list_len,
+ (unsigned long) (end - pos));
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ idx = 0;
+ while (pos < end) {
+ if (end - pos < 3) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+ "certificate_list");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ cert_len = WPA_GET_BE24(pos);
+ pos += 3;
+
+ if ((size_t) (end - pos) < cert_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected certificate "
+ "length (len=%lu left=%lu)",
+ (unsigned long) cert_len,
+ (unsigned long) (end - pos));
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Certificate %lu (len %lu)",
+ (unsigned long) idx, (unsigned long) cert_len);
+
+ if (idx == 0) {
+ crypto_public_key_free(conn->server_rsa_key);
+ if (tls_parse_cert(pos, cert_len,
+ &conn->server_rsa_key)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+ "the certificate");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+ }
+
+ cert = x509_certificate_parse(pos, cert_len);
+ if (cert == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse "
+ "the certificate");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_BAD_CERTIFICATE);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ if (last == NULL)
+ chain = cert;
+ else
+ last->next = cert;
+ last = cert;
+
+ idx++;
+ pos += cert_len;
+ }
+
+ if (x509_certificate_chain_validate(conn->trusted_certs, chain,
+ &reason) < 0) {
+ int tls_reason;
+ wpa_printf(MSG_DEBUG, "TLSv1: Server certificate chain "
+ "validation failed (reason=%d)", reason);
+ switch (reason) {
+ case X509_VALIDATE_BAD_CERTIFICATE:
+ tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+ break;
+ case X509_VALIDATE_UNSUPPORTED_CERTIFICATE:
+ tls_reason = TLS_ALERT_UNSUPPORTED_CERTIFICATE;
+ break;
+ case X509_VALIDATE_CERTIFICATE_REVOKED:
+ tls_reason = TLS_ALERT_CERTIFICATE_REVOKED;
+ break;
+ case X509_VALIDATE_CERTIFICATE_EXPIRED:
+ tls_reason = TLS_ALERT_CERTIFICATE_EXPIRED;
+ break;
+ case X509_VALIDATE_CERTIFICATE_UNKNOWN:
+ tls_reason = TLS_ALERT_CERTIFICATE_UNKNOWN;
+ break;
+ case X509_VALIDATE_UNKNOWN_CA:
+ tls_reason = TLS_ALERT_UNKNOWN_CA;
+ break;
+ default:
+ tls_reason = TLS_ALERT_BAD_CERTIFICATE;
+ break;
+ }
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, tls_reason);
+ x509_certificate_chain_free(chain);
+ return -1;
+ }
+
+ x509_certificate_chain_free(chain);
+
+ *in_len = end - in_data;
+
+ conn->state = SERVER_KEY_EXCHANGE;
+
+ return 0;
+}
+
+
+static void tlsv1_client_free_dh(struct tlsv1_client *conn)
+{
+ os_free(conn->dh_p);
+ os_free(conn->dh_g);
+ os_free(conn->dh_ys);
+ conn->dh_p = conn->dh_g = conn->dh_ys = NULL;
+}
+
+
+static int tlsv1_process_diffie_hellman(struct tlsv1_client *conn,
+ const u8 *buf, size_t len)
+{
+ const u8 *pos, *end;
+
+ tlsv1_client_free_dh(conn);
+
+ pos = buf;
+ end = buf + len;
+
+ if (end - pos < 3)
+ goto fail;
+ conn->dh_p_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len)
+ goto fail;
+ conn->dh_p = os_malloc(conn->dh_p_len);
+ if (conn->dh_p == NULL)
+ goto fail;
+ os_memcpy(conn->dh_p, pos, conn->dh_p_len);
+ pos += conn->dh_p_len;
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH p (prime)",
+ conn->dh_p, conn->dh_p_len);
+
+ if (end - pos < 3)
+ goto fail;
+ conn->dh_g_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
+ goto fail;
+ conn->dh_g = os_malloc(conn->dh_g_len);
+ if (conn->dh_g == NULL)
+ goto fail;
+ os_memcpy(conn->dh_g, pos, conn->dh_g_len);
+ pos += conn->dh_g_len;
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH g (generator)",
+ conn->dh_g, conn->dh_g_len);
+ if (conn->dh_g_len == 1 && conn->dh_g[0] < 2)
+ goto fail;
+
+ if (end - pos < 3)
+ goto fail;
+ conn->dh_ys_len = WPA_GET_BE16(pos);
+ pos += 2;
+ if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
+ goto fail;
+ conn->dh_ys = os_malloc(conn->dh_ys_len);
+ if (conn->dh_ys == NULL)
+ goto fail;
+ os_memcpy(conn->dh_ys, pos, conn->dh_ys_len);
+ pos += conn->dh_ys_len;
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
+ conn->dh_ys, conn->dh_ys_len);
+
+ return 0;
+
+fail:
+ tlsv1_client_free_dh(conn);
+ return -1;
+}
+
+
+static int tls_process_server_key_exchange(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type;
+ const struct tls_cipher_suite *suite;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerKeyExchange "
+ "(Left=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerKeyExchange "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ end = pos + len;
+
+ if (type == TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST)
+ return tls_process_certificate_request(conn, ct, in_data,
+ in_len);
+ if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+ return tls_process_server_hello_done(conn, ct, in_data,
+ in_len);
+ if (type != TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected ServerKeyExchange/"
+ "CertificateRequest/ServerHelloDone)", type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ServerKeyExchange");
+
+ if (!tls_server_key_exchange_allowed(conn)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not allowed "
+ "with the selected cipher suite");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_hexdump(MSG_DEBUG, "TLSv1: ServerKeyExchange", pos, len);
+ suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+ if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
+ if (tlsv1_process_diffie_hellman(conn, pos, len) < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "TLSv1: UnexpectedServerKeyExchange");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ *in_len = end - in_data;
+
+ conn->state = SERVER_CERTIFICATE_REQUEST;
+
+ return 0;
+}
+
+
+static int tls_process_certificate_request(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short CertificateRequest "
+ "(left=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in CertificateRequest "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ end = pos + len;
+
+ if (type == TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE)
+ return tls_process_server_hello_done(conn, ct, in_data,
+ in_len);
+ if (type != TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected CertificateRequest/"
+ "ServerHelloDone)", type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received CertificateRequest");
+
+ conn->certificate_requested = 1;
+
+ *in_len = end - in_data;
+
+ conn->state = SERVER_HELLO_DONE;
+
+ return 0;
+}
+
+
+static int tls_process_server_hello_done(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len;
+ u8 type;
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ServerHelloDone "
+ "(left=%lu)", (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ type = *pos++;
+ len = WPA_GET_BE24(pos);
+ pos += 3;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Mismatch in ServerHelloDone "
+ "length (len=%lu != left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ end = pos + len;
+
+ if (type != TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Received unexpected handshake "
+ "message %d (expected ServerHelloDone)", type);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ServerHelloDone");
+
+ *in_len = end - in_data;
+
+ conn->state = CLIENT_KEY_EXCHANGE;
+
+ return 0;
+}
+
+
+static int tls_process_server_change_cipher_spec(struct tlsv1_client *conn,
+ u8 ct, const u8 *in_data,
+ size_t *in_len)
+{
+ const u8 *pos;
+ size_t left;
+
+ if (ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 1) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short ChangeCipherSpec");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ if (*pos != TLS_CHANGE_CIPHER_SPEC) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected ChangeCipherSpec; "
+ "received data 0x%x", *pos);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received ChangeCipherSpec");
+ if (tlsv1_record_change_read_cipher(&conn->rl) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to change read cipher "
+ "for record layer");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ *in_len = pos + 1 - in_data;
+
+ conn->state = SERVER_FINISHED;
+
+ return 0;
+}
+
+
+static int tls_process_server_finished(struct tlsv1_client *conn, u8 ct,
+ const u8 *in_data, size_t *in_len)
+{
+ const u8 *pos, *end;
+ size_t left, len, hlen;
+ u8 verify_data[TLS_VERIFY_DATA_LEN];
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+ if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; "
+ "received content type 0x%x", ct);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ pos = in_data;
+ left = *in_len;
+
+ if (left < 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (left=%lu) for "
+ "Finished",
+ (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+
+ if (pos[0] != TLS_HANDSHAKE_TYPE_FINISHED) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Expected Finished; received "
+ "type 0x%x", pos[0]);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ len = WPA_GET_BE24(pos + 1);
+
+ pos += 4;
+ left -= 4;
+
+ if (len > left) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short buffer for Finished "
+ "(len=%lu > left=%lu)",
+ (unsigned long) len, (unsigned long) left);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ end = pos + len;
+ if (len != TLS_VERIFY_DATA_LEN) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected verify_data length "
+ "in Finished: %lu (expected %d)",
+ (unsigned long) len, TLS_VERIFY_DATA_LEN);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
+ pos, TLS_VERIFY_DATA_LEN);
+
+ hlen = MD5_MAC_LEN;
+ if (conn->verify_md5_server == NULL ||
+ crypto_hash_finish(conn->verify_md5_server, hash, &hlen) < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify_md5_server = NULL;
+ crypto_hash_finish(conn->verify_sha1_server, NULL, NULL);
+ conn->verify_sha1_server = NULL;
+ return -1;
+ }
+ conn->verify_md5_server = NULL;
+ hlen = SHA1_MAC_LEN;
+ if (conn->verify_sha1_server == NULL ||
+ crypto_hash_finish(conn->verify_sha1_server, hash + MD5_MAC_LEN,
+ &hlen) < 0) {
+ conn->verify_sha1_server = NULL;
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify_sha1_server = NULL;
+
+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+ verify_data, TLS_VERIFY_DATA_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECRYPT_ERROR);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
+ verify_data, TLS_VERIFY_DATA_LEN);
+
+ if (os_memcmp(pos, verify_data, TLS_VERIFY_DATA_LEN) != 0) {
+ wpa_printf(MSG_INFO, "TLSv1: Mismatch in verify_data");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received Finished");
+
+ *in_len = end - in_data;
+
+ conn->state = (conn->session_resumed || conn->ticket) ?
+ CHANGE_CIPHER_SPEC : ACK_FINISHED;
+
+ return 0;
+}
+
+
+static int tls_derive_pre_master_secret(u8 *pre_master_secret)
+{
+ WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
+ if (os_get_random(pre_master_secret + 2,
+ TLS_PRE_MASTER_SECRET_LEN - 2))
+ return -1;
+ return 0;
+}
+
+
+static int tls_derive_keys(struct tlsv1_client *conn,
+ const u8 *pre_master_secret,
+ size_t pre_master_secret_len)
+{
+ u8 seed[2 * TLS_RANDOM_LEN];
+ u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
+ u8 *pos;
+ size_t key_block_len;
+
+ if (pre_master_secret) {
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
+ pre_master_secret, pre_master_secret_len);
+ os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+ TLS_RANDOM_LEN);
+ if (tls_prf(pre_master_secret, pre_master_secret_len,
+ "master secret", seed, 2 * TLS_RANDOM_LEN,
+ conn->master_secret, TLS_MASTER_SECRET_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
+ "master_secret");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
+ conn->master_secret, TLS_MASTER_SECRET_LEN);
+ }
+
+ os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
+ key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
+ conn->rl.iv_size);
+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "key expansion", seed, 2 * TLS_RANDOM_LEN,
+ key_block, key_block_len)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
+ key_block, key_block_len);
+
+ pos = key_block;
+
+ /* client_write_MAC_secret */
+ os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
+ pos += conn->rl.hash_size;
+ /* server_write_MAC_secret */
+ os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
+ pos += conn->rl.hash_size;
+
+ /* client_write_key */
+ os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
+ pos += conn->rl.key_material_len;
+ /* server_write_key */
+ os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
+ pos += conn->rl.key_material_len;
+
+ /* client_write_IV */
+ os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
+ pos += conn->rl.iv_size;
+ /* server_write_IV */
+ os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
+ pos += conn->rl.iv_size;
+
+ return 0;
+}
+
+
+static int tls_write_client_certificate(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
+ size_t rlen;
+ struct x509_certificate *cert;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - Certificate */
+ /* uint24 length (to be filled) */
+ cert_start = pos;
+ pos += 3;
+ cert = conn->client_cert;
+ while (cert) {
+ if (pos + 3 + cert->cert_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
+ "for Certificate (cert_len=%lu left=%lu)",
+ (unsigned long) cert->cert_len,
+ (unsigned long) (end - pos));
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE24(pos, cert->cert_len);
+ pos += 3;
+ os_memcpy(pos, cert->cert_start, cert->cert_len);
+ pos += cert->cert_len;
+
+ if (x509_certificate_self_signed(cert))
+ break;
+ cert = x509_certificate_get_subject(conn->trusted_certs,
+ &cert->issuer);
+ }
+ if (cert == conn->client_cert || cert == NULL) {
+ /*
+ * Client was not configured with all the needed certificates
+ * to form a full certificate chain. The server may fail to
+ * validate the chain unless it is configured with all the
+ * missing CA certificates.
+ */
+ wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
+ "not configured - validation may fail");
+ }
+ WPA_PUT_BE24(cert_start, pos - cert_start - 3);
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(conn, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
+{
+#ifdef EAP_FAST
+ /* ClientDiffieHellmanPublic */
+ u8 *csecret, *csecret_start, *dh_yc, *shared;
+ size_t csecret_len, dh_yc_len, shared_len;
+
+ csecret_len = conn->dh_p_len;
+ csecret = os_malloc(csecret_len);
+ if (csecret == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+ "memory for Yc (Diffie-Hellman)");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ if (os_get_random(csecret, csecret_len)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
+ "data for Diffie-Hellman");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(csecret);
+ return -1;
+ }
+
+ if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
+ csecret[0] = 0; /* make sure Yc < p */
+
+ csecret_start = csecret;
+ while (csecret_len > 1 && *csecret_start == 0) {
+ csecret_start++;
+ csecret_len--;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
+ csecret_start, csecret_len);
+
+ /* Yc = g^csecret mod p */
+ dh_yc_len = conn->dh_p_len;
+ dh_yc = os_malloc(dh_yc_len);
+ if (dh_yc == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+ "memory for Diffie-Hellman");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(csecret);
+ return -1;
+ }
+ crypto_mod_exp(conn->dh_g, conn->dh_g_len,
+ csecret_start, csecret_len,
+ conn->dh_p, conn->dh_p_len,
+ dh_yc, &dh_yc_len);
+
+ wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
+ dh_yc, dh_yc_len);
+
+ WPA_PUT_BE16(*pos, dh_yc_len);
+ *pos += 2;
+ if (*pos + dh_yc_len > end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
+ "message buffer for Yc");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(csecret);
+ os_free(dh_yc);
+ return -1;
+ }
+ os_memcpy(*pos, dh_yc, dh_yc_len);
+ *pos += dh_yc_len;
+ os_free(dh_yc);
+
+ shared_len = conn->dh_p_len;
+ shared = os_malloc(shared_len);
+ if (shared == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
+ "DH");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(csecret);
+ return -1;
+ }
+
+ /* shared = Ys^csecret mod p */
+ crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
+ csecret_start, csecret_len,
+ conn->dh_p, conn->dh_p_len,
+ shared, &shared_len);
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
+ shared, shared_len);
+
+ os_memset(csecret_start, 0, csecret_len);
+ os_free(csecret);
+ if (tls_derive_keys(conn, shared, shared_len)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ os_free(shared);
+ return -1;
+ }
+ os_memset(shared, 0, shared_len);
+ os_free(shared);
+ tlsv1_client_free_dh(conn);
+ return 0;
+#else /* EAP_FAST */
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+#endif /* EAP_FAST */
+}
+
+
+static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
+{
+ u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
+ size_t clen;
+ int res;
+
+ if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
+ tls_derive_keys(conn, pre_master_secret,
+ TLS_PRE_MASTER_SECRET_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* EncryptedPreMasterSecret */
+ if (conn->server_rsa_key == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
+ "use for encrypting pre-master secret");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ /* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
+ *pos += 2;
+ clen = end - *pos;
+ res = crypto_public_key_encrypt_pkcs1_v15(
+ conn->server_rsa_key,
+ pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
+ *pos, &clen);
+ os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE16(*pos - 2, clen);
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
+ *pos, clen);
+ *pos += clen;
+
+ return 0;
+}
+
+
+static int tls_write_client_key_exchange(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen;
+ tls_key_exchange keyx;
+ const struct tls_cipher_suite *suite;
+
+ suite = tls_get_cipher_suite(conn->rl.cipher_suite);
+ if (suite == NULL)
+ keyx = TLS_KEY_X_NULL;
+ else
+ keyx = suite->key_exchange;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
+
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* opaque fragment[TLSPlaintext.length] */
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ /* body - ClientKeyExchange */
+ if (keyx == TLS_KEY_X_DH_anon) {
+ if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
+ return -1;
+ } else {
+ if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
+ return -1;
+ }
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+ tls_verify_hash_add(conn, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
+ size_t rlen, hlen, clen;
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
+ enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+
+ /*
+ * RFC 2246: 7.4.3 and 7.4.8:
+ * Signature signature
+ *
+ * RSA:
+ * digitally-signed struct {
+ * opaque md5_hash[16];
+ * opaque sha_hash[20];
+ * };
+ *
+ * DSA:
+ * digitally-signed struct {
+ * opaque sha_hash[20];
+ * };
+ *
+ * The hash values are calculated over all handshake messages sent or
+ * received starting at ClientHello up to, but not including, this
+ * CertificateVerify message, including the type and length fields of
+ * the handshake messages.
+ */
+
+ hpos = hash;
+
+ if (alg == SIGN_ALG_RSA) {
+ hlen = MD5_MAC_LEN;
+ if (conn->verify_md5_cert == NULL ||
+ crypto_hash_finish(conn->verify_md5_cert, hpos, &hlen) < 0)
+ {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify_md5_cert = NULL;
+ crypto_hash_finish(conn->verify_sha1_cert, NULL, NULL);
+ conn->verify_sha1_cert = NULL;
+ return -1;
+ }
+ hpos += MD5_MAC_LEN;
+ } else
+ crypto_hash_finish(conn->verify_md5_cert, NULL, NULL);
+
+ conn->verify_md5_cert = NULL;
+ hlen = SHA1_MAC_LEN;
+ if (conn->verify_sha1_cert == NULL ||
+ crypto_hash_finish(conn->verify_sha1_cert, hpos, &hlen) < 0) {
+ conn->verify_sha1_cert = NULL;
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify_sha1_cert = NULL;
+
+ if (alg == SIGN_ALG_RSA)
+ hlen += MD5_MAC_LEN;
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
+
+ /*
+ * RFC 2246, 4.7:
+ * In digital signing, one-way hash functions are used as input for a
+ * signing algorithm. A digitally-signed element is encoded as an
+ * opaque vector <0..2^16-1>, where the length is specified by the
+ * signing algorithm and key.
+ *
+ * In RSA signing, a 36-byte structure of two hashes (one SHA and one
+ * MD5) is signed (encrypted with the private key). It is encoded with
+ * PKCS #1 block type 0 or type 1 as described in [PKCS1].
+ */
+ signed_start = pos; /* length to be filled */
+ pos += 2;
+ clen = end - pos;
+ if (crypto_private_key_sign_pkcs1(conn->client_key, hash, hlen,
+ pos, &clen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ WPA_PUT_BE16(signed_start, clen);
+
+ pos += clen;
+
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ pos = rhdr + rlen;
+
+ tls_verify_hash_add(conn, hs_start, pos - hs_start);
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr;
+ size_t rlen;
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+ *pos = TLS_CHANGE_CIPHER_SPEC;
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
+ rhdr, end - rhdr, 1, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
+ "record layer");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ *msgpos = rhdr + rlen;
+
+ return 0;
+}
+
+
+static int tls_write_client_finished(struct tlsv1_client *conn,
+ u8 **msgpos, u8 *end)
+{
+ u8 *pos, *rhdr, *hs_start, *hs_length;
+ size_t rlen, hlen;
+ u8 verify_data[TLS_VERIFY_DATA_LEN];
+ u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
+
+ pos = *msgpos;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
+
+ /* Encrypted Handshake Message: Finished */
+
+ hlen = MD5_MAC_LEN;
+ if (conn->verify_md5_client == NULL ||
+ crypto_hash_finish(conn->verify_md5_client, hash, &hlen) < 0) {
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ conn->verify_md5_client = NULL;
+ crypto_hash_finish(conn->verify_sha1_client, NULL, NULL);
+ conn->verify_sha1_client = NULL;
+ return -1;
+ }
+ conn->verify_md5_client = NULL;
+ hlen = SHA1_MAC_LEN;
+ if (conn->verify_sha1_client == NULL ||
+ crypto_hash_finish(conn->verify_sha1_client, hash + MD5_MAC_LEN,
+ &hlen) < 0) {
+ conn->verify_sha1_client = NULL;
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ conn->verify_sha1_client = NULL;
+
+ if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+ verify_data, TLS_VERIFY_DATA_LEN)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
+ verify_data, TLS_VERIFY_DATA_LEN);
+
+ rhdr = pos;
+ pos += TLS_RECORD_HEADER_LEN;
+ /* Handshake */
+ hs_start = pos;
+ /* HandshakeType msg_type */
+ *pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
+ /* uint24 length (to be filled) */
+ hs_length = pos;
+ pos += 3;
+ os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
+ pos += TLS_VERIFY_DATA_LEN;
+ WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+ tls_verify_hash_add(conn, hs_start, pos - hs_start);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
+ rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ pos = rhdr + rlen;
+
+ *msgpos = pos;
+
+ return 0;
+}
+
+
+static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
+{
+ size_t len = 0;
+ struct x509_certificate *cert;
+
+ cert = conn->client_cert;
+ while (cert) {
+ len += 3 + cert->cert_len;
+ if (x509_certificate_self_signed(cert))
+ break;
+ cert = x509_certificate_get_subject(conn->trusted_certs,
+ &cert->issuer);
+ }
+
+ return len;
+}
+
+
+static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
+ size_t *out_len)
+{
+ u8 *msg, *end, *pos;
+ size_t msglen;
+
+ *out_len = 0;
+
+ msglen = 1000;
+ if (conn->certificate_requested)
+ msglen += tls_client_cert_chain_der_len(conn);
+
+ msg = os_malloc(msglen);
+ if (msg == NULL)
+ return NULL;
+
+ pos = msg;
+ end = msg + msglen;
+
+ if (conn->certificate_requested) {
+ if (tls_write_client_certificate(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+ }
+
+ if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
+ (conn->certificate_requested && conn->client_key &&
+ tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
+ tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
+ tls_write_client_finished(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+
+ *out_len = pos - msg;
+
+ conn->state = SERVER_CHANGE_CIPHER_SPEC;
+
+ return msg;
+}
+
+
+static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
+ size_t *out_len)
+{
+ u8 *msg, *end, *pos;
+
+ *out_len = 0;
+
+ msg = os_malloc(1000);
+ if (msg == NULL)
+ return NULL;
+
+ pos = msg;
+ end = msg + 1000;
+
+ if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
+ tls_write_client_finished(conn, &pos, end) < 0) {
+ os_free(msg);
+ return NULL;
+ }
+
+ *out_len = pos - msg;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
+ "successfully");
+ conn->state = ESTABLISHED;
+
+ return msg;
+}
+
+
+static int tlsv1_client_process_handshake(struct tlsv1_client *conn, u8 ct,
+ const u8 *buf, size_t *len)
+{
+ if (ct == TLS_CONTENT_TYPE_HANDSHAKE && *len >= 4 &&
+ buf[0] == TLS_HANDSHAKE_TYPE_HELLO_REQUEST) {
+ size_t hr_len = WPA_GET_BE24(buf + 1);
+ if (hr_len > *len - 4) {
+ wpa_printf(MSG_DEBUG, "TLSv1: HelloRequest underflow");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_DECODE_ERROR);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "TLSv1: Ignored HelloRequest");
+ *len = 4 + hr_len;
+ return 0;
+ }
+
+ switch (conn->state) {
+ case SERVER_HELLO:
+ if (tls_process_server_hello(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_CERTIFICATE:
+ if (tls_process_certificate(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_KEY_EXCHANGE:
+ if (tls_process_server_key_exchange(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_CERTIFICATE_REQUEST:
+ if (tls_process_certificate_request(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_HELLO_DONE:
+ if (tls_process_server_hello_done(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_CHANGE_CIPHER_SPEC:
+ if (tls_process_server_change_cipher_spec(conn, ct, buf, len))
+ return -1;
+ break;
+ case SERVER_FINISHED:
+ if (tls_process_server_finished(conn, ct, buf, len))
+ return -1;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d "
+ "while processing received message",
+ conn->state);
+ return -1;
+ }
+
+ if (ct == TLS_CONTENT_TYPE_HANDSHAKE)
+ tls_verify_hash_add(conn, buf, *len);
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_handshake - Process TLS handshake
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @in_data: Input data from TLS peer
+ * @in_len: Input data length
+ * @out_len: Length of the output buffer.
+ * Returns: Pointer to output data, %NULL on failure
+ */
+u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len)
+{
+ const u8 *pos, *end;
+ u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
+ size_t in_msg_len;
+
+ if (conn->state == CLIENT_HELLO) {
+ if (in_len)
+ return NULL;
+ return tls_send_client_hello(conn, out_len);
+ }
+
+ if (in_data == NULL || in_len == 0)
+ return NULL;
+
+ pos = in_data;
+ end = in_data + in_len;
+ in_msg = os_malloc(in_len);
+ if (in_msg == NULL)
+ return NULL;
+
+ /* Each received packet may include multiple records */
+ while (pos < end) {
+ in_msg_len = in_len;
+ if (tlsv1_record_receive(&conn->rl, pos, end - pos,
+ in_msg, &in_msg_len, &alert)) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
+ "record failed");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ goto failed;
+ }
+ ct = pos[0];
+
+ in_pos = in_msg;
+ in_end = in_msg + in_msg_len;
+
+ /* Each received record may include multiple messages of the
+ * same ContentType. */
+ while (in_pos < in_end) {
+ in_msg_len = in_end - in_pos;
+ if (tlsv1_client_process_handshake(conn, ct, in_pos,
+ &in_msg_len) < 0)
+ goto failed;
+ in_pos += in_msg_len;
+ }
+
+ pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ }
+
+ os_free(in_msg);
+ in_msg = NULL;
+
+ switch (conn->state) {
+ case CLIENT_KEY_EXCHANGE:
+ msg = tls_send_client_key_exchange(conn, out_len);
+ break;
+ case CHANGE_CIPHER_SPEC:
+ msg = tls_send_change_cipher_spec(conn, out_len);
+ break;
+ case ACK_FINISHED:
+ wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
+ "successfully");
+ conn->state = ESTABLISHED;
+ /* Need to return something to get final TLS ACK. */
+ msg = os_malloc(1);
+ *out_len = 0;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
+ "generating reply", conn->state);
+ break;
+ }
+
+failed:
+ os_free(in_msg);
+ if (conn->alert_level) {
+ conn->state = FAILED;
+ os_free(msg);
+ msg = tls_send_alert(conn, conn->alert_level,
+ conn->alert_description, out_len);
+ }
+
+ return msg;
+}
+
+
+/**
+ * tlsv1_client_encrypt - Encrypt data into TLS tunnel
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @in_data: Pointer to plaintext data to be encrypted
+ * @in_len: Input buffer length
+ * @out_data: Pointer to output buffer (encrypted TLS data)
+ * @out_len: Maximum out_data length
+ * Returns: Number of bytes written to out_data, -1 on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * send data in the encrypted tunnel.
+ */
+int tlsv1_client_encrypt(struct tlsv1_client *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ size_t rlen;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
+ in_data, in_len);
+
+ os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
+
+ if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
+ out_data, out_len, in_len, &rlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ return rlen;
+}
+
+
+/**
+ * tlsv1_client_decrypt - Decrypt data from TLS tunnel
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @in_data: Pointer to input buffer (encrypted TLS data)
+ * @in_len: Input buffer length
+ * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
+ * @out_len: Maximum out_data length
+ * Returns: Number of bytes written to out_data, -1 on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * receive data from the encrypted tunnel.
+ */
+int tlsv1_client_decrypt(struct tlsv1_client *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ const u8 *in_end, *pos;
+ int res;
+ u8 alert, *out_end, *out_pos;
+ size_t olen;
+
+ pos = in_data;
+ in_end = in_data + in_len;
+ out_pos = out_data;
+ out_end = out_data + out_len;
+
+ while (pos < in_end) {
+ if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+ "0x%x", pos[0]);
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ olen = out_end - out_pos;
+ res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+ out_pos, &olen, &alert);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+ "failed");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+ return -1;
+ }
+ out_pos += olen;
+ if (out_pos > out_end) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
+ "for processing the received record");
+ tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+ TLS_ALERT_INTERNAL_ERROR);
+ return -1;
+ }
+
+ pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+ }
+
+ return out_pos - out_data;
+}
+
+
+/**
+ * tlsv1_client_global_init - Initialize TLSv1 client
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function must be called before using any other TLSv1 client functions.
+ */
+int tlsv1_client_global_init(void)
+{
+ return crypto_global_init();
+}
+
+
+/**
+ * tlsv1_client_global_deinit - Deinitialize TLSv1 client
+ *
+ * This function can be used to deinitialize the TLSv1 client that was
+ * initialized by calling tlsv1_client_global_init(). No TLSv1 client functions
+ * can be called after this before calling tlsv1_client_global_init() again.
+ */
+void tlsv1_client_global_deinit(void)
+{
+ crypto_global_deinit();
+}
+
+
+static void tlsv1_client_free_verify_hashes(struct tlsv1_client *conn)
+{
+ crypto_hash_finish(conn->verify_md5_client, NULL, NULL);
+ crypto_hash_finish(conn->verify_md5_server, NULL, NULL);
+ crypto_hash_finish(conn->verify_md5_cert, NULL, NULL);
+ crypto_hash_finish(conn->verify_sha1_client, NULL, NULL);
+ crypto_hash_finish(conn->verify_sha1_server, NULL, NULL);
+ crypto_hash_finish(conn->verify_sha1_cert, NULL, NULL);
+ conn->verify_md5_client = NULL;
+ conn->verify_md5_server = NULL;
+ conn->verify_md5_cert = NULL;
+ conn->verify_sha1_client = NULL;
+ conn->verify_sha1_server = NULL;
+ conn->verify_sha1_cert = NULL;
+}
+
+
+static int tlsv1_client_init_verify_hashes(struct tlsv1_client *conn)
+{
+ conn->verify_md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL,
+ 0);
+ conn->verify_md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL,
+ 0);
+ conn->verify_md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
+ conn->verify_sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL,
+ 0);
+ conn->verify_sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL,
+ 0);
+ conn->verify_sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL,
+ 0);
+ if (conn->verify_md5_client == NULL ||
+ conn->verify_md5_server == NULL ||
+ conn->verify_md5_cert == NULL ||
+ conn->verify_sha1_client == NULL ||
+ conn->verify_sha1_server == NULL ||
+ conn->verify_sha1_cert == NULL) {
+ tlsv1_client_free_verify_hashes(conn);
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_init - Initialize TLSv1 client connection
+ * Returns: Pointer to TLSv1 client connection data or %NULL on failure
+ */
+struct tlsv1_client * tlsv1_client_init(void)
+{
+ struct tlsv1_client *conn;
+ size_t count;
+ u16 *suites;
+
+ conn = os_zalloc(sizeof(*conn));
+ if (conn == NULL)
+ return NULL;
+
+ conn->state = CLIENT_HELLO;
+
+ if (tlsv1_client_init_verify_hashes(conn) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
+ "hash");
+ os_free(conn);
+ return NULL;
+ }
+
+ count = 0;
+ suites = conn->cipher_suites;
+#ifndef CONFIG_CRYPTO_INTERNAL
+ suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
+#endif /* CONFIG_CRYPTO_INTERNAL */
+ suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
+ suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
+ suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
+ conn->num_cipher_suites = count;
+
+ return conn;
+}
+
+
+/**
+ * tlsv1_client_deinit - Deinitialize TLSv1 client connection
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ */
+void tlsv1_client_deinit(struct tlsv1_client *conn)
+{
+ crypto_public_key_free(conn->server_rsa_key);
+ tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
+ tlsv1_record_change_write_cipher(&conn->rl);
+ tlsv1_record_change_read_cipher(&conn->rl);
+ tlsv1_client_free_verify_hashes(conn);
+ os_free(conn->client_hello_ext);
+ tlsv1_client_free_dh(conn);
+ x509_certificate_chain_free(conn->trusted_certs);
+ x509_certificate_chain_free(conn->client_cert);
+ crypto_private_key_free(conn->client_key);
+ os_free(conn);
+}
+
+
+/**
+ * tlsv1_client_established - Check whether connection has been established
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * Returns: 1 if connection is established, 0 if not
+ */
+int tlsv1_client_established(struct tlsv1_client *conn)
+{
+ return conn->state == ESTABLISHED;
+}
+
+
+/**
+ * tlsv1_client_prf - Use TLS-PRF to derive keying material
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+ int server_random_first, u8 *out, size_t out_len)
+{
+ u8 seed[2 * TLS_RANDOM_LEN];
+
+ if (conn->state != ESTABLISHED)
+ return -1;
+
+ if (server_random_first) {
+ os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
+ TLS_RANDOM_LEN);
+ } else {
+ os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
+ os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
+ TLS_RANDOM_LEN);
+ }
+
+ return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+ label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
+}
+
+
+/**
+ * tlsv1_client_get_cipher - Get current cipher name
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @buf: Buffer for the cipher name
+ * @buflen: buf size
+ * Returns: 0 on success, -1 on failure
+ *
+ * Get the name of the currently used cipher.
+ */
+int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
+ size_t buflen)
+{
+ char *cipher;
+
+ switch (conn->rl.cipher_suite) {
+ case TLS_RSA_WITH_RC4_128_MD5:
+ cipher = "RC4-MD5";
+ break;
+ case TLS_RSA_WITH_RC4_128_SHA:
+ cipher = "RC4-SHA";
+ break;
+ case TLS_RSA_WITH_DES_CBC_SHA:
+ cipher = "DES-CBC-SHA";
+ break;
+ case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ cipher = "DES-CBC3-SHA";
+ break;
+ default:
+ return -1;
+ }
+
+ os_snprintf(buf, buflen, "%s", cipher);
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_shutdown - Shutdown TLS connection
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_shutdown(struct tlsv1_client *conn)
+{
+ conn->state = CLIENT_HELLO;
+
+ tlsv1_client_free_verify_hashes(conn);
+ if (tlsv1_client_init_verify_hashes(conn) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
+ "hash");
+ return -1;
+ }
+
+ tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
+ tlsv1_record_change_write_cipher(&conn->rl);
+ tlsv1_record_change_read_cipher(&conn->rl);
+
+ conn->certificate_requested = 0;
+ crypto_public_key_free(conn->server_rsa_key);
+ conn->server_rsa_key = NULL;
+ conn->session_resumed = 0;
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_resumed - Was session resumption used
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * Returns: 1 if current session used session resumption, 0 if not
+ */
+int tlsv1_client_resumed(struct tlsv1_client *conn)
+{
+ return !!conn->session_resumed;
+}
+
+
+/**
+ * tlsv1_client_hello_ext - Set TLS extension for ClientHello
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @ext_type: Extension type
+ * @data: Extension payload (%NULL to remove extension)
+ * @data_len: Extension payload length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
+ const u8 *data, size_t data_len)
+{
+ u8 *pos;
+
+ conn->ticket = 0;
+ os_free(conn->client_hello_ext);
+ conn->client_hello_ext = NULL;
+ conn->client_hello_ext_len = 0;
+
+ if (data == NULL || data_len == 0)
+ return 0;
+
+ pos = conn->client_hello_ext = os_malloc(6 + data_len);
+ if (pos == NULL)
+ return -1;
+
+ WPA_PUT_BE16(pos, 4 + data_len);
+ pos += 2;
+ WPA_PUT_BE16(pos, ext_type);
+ pos += 2;
+ WPA_PUT_BE16(pos, data_len);
+ pos += 2;
+ os_memcpy(pos, data, data_len);
+ conn->client_hello_ext_len = 6 + data_len;
+
+ if (ext_type == TLS_EXT_PAC_OPAQUE) {
+ conn->ticket = 1;
+ wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_get_keys - Get master key and random data from TLS connection
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @keys: Structure of key/random data (filled on success)
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
+{
+ os_memset(keys, 0, sizeof(*keys));
+ if (conn->state == CLIENT_HELLO)
+ return -1;
+
+ keys->client_random = conn->client_random;
+ keys->client_random_len = TLS_RANDOM_LEN;
+
+ if (conn->state != SERVER_HELLO) {
+ keys->server_random = conn->server_random;
+ keys->server_random_len = TLS_RANDOM_LEN;
+ keys->master_key = conn->master_secret;
+ keys->master_key_len = TLS_MASTER_SECRET_LEN;
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_set_master_key - Configure master secret for TLS connection
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @key: TLS pre-master-secret
+ * @key_len: length of key in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_set_master_key(struct tlsv1_client *conn,
+ const u8 *key, size_t key_len)
+{
+ if (key_len > TLS_MASTER_SECRET_LEN)
+ return -1;
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret from session "
+ "ticket", key, key_len);
+ os_memcpy(conn->master_secret, key, key_len);
+ conn->ticket_key = 1;
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_get_keyblock_size - Get TLS key_block size
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on
+ * failure
+ */
+int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)
+{
+ if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
+ return -1;
+
+ return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
+ conn->rl.iv_size);
+}
+
+
+/**
+ * tlsv1_client_set_cipher_list - Configure acceptable cipher suites
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
+ * (TLS_CIPHER_*).
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
+{
+#ifdef EAP_FAST
+ size_t count;
+ u16 *suites;
+
+ /* TODO: implement proper configuration of cipher suites */
+ if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
+ count = 0;
+ suites = conn->cipher_suites;
+ suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
+ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
+ suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
+ suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
+ suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
+ conn->num_cipher_suites = count;
+ }
+
+ return 0;
+#else /* EAP_FAST */
+ return -1;
+#endif /* EAP_FAST */
+}
+
+
+static int tlsv1_client_add_cert_der(struct x509_certificate **chain,
+ const u8 *buf, size_t len)
+{
+ struct x509_certificate *cert;
+ char name[128];
+
+ cert = x509_certificate_parse(buf, len);
+ if (cert == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
+ __func__);
+ return -1;
+ }
+
+ cert->next = *chain;
+ *chain = cert;
+
+ x509_name_string(&cert->subject, name, sizeof(name));
+ wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
+
+ return 0;
+}
+
+
+static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
+static const char *pem_cert_end = "-----END CERTIFICATE-----";
+
+
+static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
+{
+ size_t i, plen;
+
+ plen = os_strlen(tag);
+ if (len < plen)
+ return NULL;
+
+ for (i = 0; i < len - plen; i++) {
+ if (os_memcmp(buf + i, tag, plen) == 0)
+ return buf + i;
+ }
+
+ return NULL;
+}
+
+
+static int tlsv1_client_add_cert(struct x509_certificate **chain,
+ const u8 *buf, size_t len)
+{
+ const u8 *pos, *end;
+ unsigned char *der;
+ size_t der_len;
+
+ pos = search_tag(pem_cert_begin, buf, len);
+ if (!pos) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
+ "assume DER format");
+ return tlsv1_client_add_cert_der(chain, buf, len);
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
+ "DER format");
+
+ while (pos) {
+ pos += os_strlen(pem_cert_begin);
+ end = search_tag(pem_cert_end, pos, buf + len - pos);
+ if (end == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
+ "certificate end tag (%s)", pem_cert_end);
+ return -1;
+ }
+
+ der = base64_decode(pos, end - pos, &der_len);
+ if (der == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
+ "certificate");
+ return -1;
+ }
+
+ if (tlsv1_client_add_cert_der(chain, der, der_len) < 0) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
+ "certificate after DER conversion");
+ os_free(der);
+ return -1;
+ }
+
+ os_free(der);
+
+ end += os_strlen(pem_cert_end);
+ pos = search_tag(pem_cert_begin, end, buf + len - end);
+ }
+
+ return 0;
+}
+
+
+static int tlsv1_client_set_cert_chain(struct x509_certificate **chain,
+ const char *cert, const u8 *cert_blob,
+ size_t cert_blob_len)
+{
+ if (cert_blob)
+ return tlsv1_client_add_cert(chain, cert_blob, cert_blob_len);
+
+ if (cert) {
+ u8 *buf;
+ size_t len;
+ int ret;
+
+ buf = (u8 *) os_readfile(cert, &len);
+ if (buf == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+ cert);
+ return -1;
+ }
+
+ ret = tlsv1_client_add_cert(chain, buf, len);
+ os_free(buf);
+ return ret;
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_set_ca_cert - Set trusted CA certificate(s)
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @cert: File or reference name for X.509 certificate in PEM or DER format
+ * @cert_blob: cert as inlined data or %NULL if not used
+ * @cert_blob_len: ca_cert_blob length
+ * @path: Path to CA certificates (not yet supported)
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_set_ca_cert(struct tlsv1_client *conn, const char *cert,
+ const u8 *cert_blob, size_t cert_blob_len,
+ const char *path)
+{
+ if (tlsv1_client_set_cert_chain(&conn->trusted_certs, cert,
+ cert_blob, cert_blob_len) < 0)
+ return -1;
+
+ if (path) {
+ /* TODO: add support for reading number of certificate files */
+ wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
+ "not yet supported");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_set_client_cert - Set client certificate
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @cert: File or reference name for X.509 certificate in PEM or DER format
+ * @cert_blob: cert as inlined data or %NULL if not used
+ * @cert_blob_len: ca_cert_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_set_client_cert(struct tlsv1_client *conn, const char *cert,
+ const u8 *cert_blob, size_t cert_blob_len)
+{
+ return tlsv1_client_set_cert_chain(&conn->client_cert, cert,
+ cert_blob, cert_blob_len);
+}
+
+
+static int tlsv1_client_set_key(struct tlsv1_client *conn,
+ const u8 *key, size_t len)
+{
+ conn->client_key = crypto_private_key_import(key, len);
+ if (conn->client_key == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * tlsv1_client_set_private_key - Set client private key
+ * @conn: TLSv1 client connection data from tlsv1_client_init()
+ * @private_key: File or reference name for the key in PEM or DER format
+ * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
+ * passphrase is used.
+ * @private_key_blob: private_key as inlined data or %NULL if not used
+ * @private_key_blob_len: private_key_blob length
+ * Returns: 0 on success, -1 on failure
+ */
+int tlsv1_client_set_private_key(struct tlsv1_client *conn,
+ const char *private_key,
+ const char *private_key_passwd,
+ const u8 *private_key_blob,
+ size_t private_key_blob_len)
+{
+ crypto_private_key_free(conn->client_key);
+ conn->client_key = NULL;
+
+ if (private_key_blob)
+ return tlsv1_client_set_key(conn, private_key_blob,
+ private_key_blob_len);
+
+ if (private_key) {
+ u8 *buf;
+ size_t len;
+ int ret;
+
+ buf = (u8 *) os_readfile(private_key, &len);
+ if (buf == NULL) {
+ wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
+ private_key);
+ return -1;
+ }
+
+ ret = tlsv1_client_set_key(conn, buf, len);
+ os_free(buf);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/tlsv1_client.h b/contrib/wpa_supplicant/tlsv1_client.h
new file mode 100644
index 000000000000..dced874d1bfc
--- /dev/null
+++ b/contrib/wpa_supplicant/tlsv1_client.h
@@ -0,0 +1,58 @@
+/*
+ * wpa_supplicant: TLSv1 client (RFC 2246)
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_CLIENT_H
+#define TLSV1_CLIENT_H
+
+struct tlsv1_client;
+
+int tlsv1_client_global_init(void);
+void tlsv1_client_global_deinit(void);
+struct tlsv1_client * tlsv1_client_init(void);
+void tlsv1_client_deinit(struct tlsv1_client *conn);
+int tlsv1_client_established(struct tlsv1_client *conn);
+int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
+ int server_random_first, u8 *out, size_t out_len);
+u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len);
+int tlsv1_client_encrypt(struct tlsv1_client *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len);
+int tlsv1_client_decrypt(struct tlsv1_client *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len);
+int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
+ size_t buflen);
+int tlsv1_client_shutdown(struct tlsv1_client *conn);
+int tlsv1_client_resumed(struct tlsv1_client *conn);
+int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
+ const u8 *data, size_t data_len);
+int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys);
+int tlsv1_client_set_master_key(struct tlsv1_client *conn,
+ const u8 *key, size_t key_len);
+int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn);
+int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers);
+int tlsv1_client_set_ca_cert(struct tlsv1_client *conn, const char *cert,
+ const u8 *cert_blob, size_t cert_blob_len,
+ const char *path);
+int tlsv1_client_set_client_cert(struct tlsv1_client *conn, const char *cert,
+ const u8 *cert_blob, size_t cert_blob_len);
+int tlsv1_client_set_private_key(struct tlsv1_client *conn,
+ const char *private_key,
+ const char *private_key_passwd,
+ const u8 *private_key_blob,
+ size_t private_key_blob_len);
+
+#endif /* TLSV1_CLIENT_H */
diff --git a/contrib/wpa_supplicant/tlsv1_common.c b/contrib/wpa_supplicant/tlsv1_common.c
new file mode 100644
index 000000000000..8432398bf517
--- /dev/null
+++ b/contrib/wpa_supplicant/tlsv1_common.c
@@ -0,0 +1,552 @@
+/*
+ * wpa_supplicant/hostapd: TLSv1 common routines
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "sha1.h"
+#include "crypto.h"
+#include "x509v3.h"
+#include "tlsv1_common.h"
+
+
+/*
+ * TODO:
+ * RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
+ * Add support for commonly used cipher suites; don't bother with exportable
+ * suites.
+ */
+
+static const struct tls_cipher_suite tls_cipher_suites[] = {
+ { TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL,
+ TLS_HASH_NULL },
+ { TLS_RSA_WITH_RC4_128_MD5, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
+ TLS_HASH_MD5 },
+ { TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
+ TLS_HASH_SHA },
+ { TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC,
+ TLS_HASH_SHA },
+ { TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
+ TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
+ { TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
+ TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
+ { TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
+ TLS_CIPHER_DES_CBC, TLS_HASH_SHA },
+ { TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon,
+ TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
+ { TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
+ TLS_HASH_SHA },
+ { TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
+ TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
+ { TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
+ TLS_HASH_SHA },
+ { TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
+ TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }
+};
+
+#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
+#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
+
+
+static const struct tls_cipher_data tls_ciphers[] = {
+ { TLS_CIPHER_NULL, TLS_CIPHER_STREAM, 0, 0, 0,
+ CRYPTO_CIPHER_NULL },
+ { TLS_CIPHER_IDEA_CBC, TLS_CIPHER_BLOCK, 16, 16, 8,
+ CRYPTO_CIPHER_NULL },
+ { TLS_CIPHER_RC2_CBC_40, TLS_CIPHER_BLOCK, 5, 16, 0,
+ CRYPTO_CIPHER_ALG_RC2 },
+ { TLS_CIPHER_RC4_40, TLS_CIPHER_STREAM, 5, 16, 0,
+ CRYPTO_CIPHER_ALG_RC4 },
+ { TLS_CIPHER_RC4_128, TLS_CIPHER_STREAM, 16, 16, 0,
+ CRYPTO_CIPHER_ALG_RC4 },
+ { TLS_CIPHER_DES40_CBC, TLS_CIPHER_BLOCK, 5, 8, 8,
+ CRYPTO_CIPHER_ALG_DES },
+ { TLS_CIPHER_DES_CBC, TLS_CIPHER_BLOCK, 8, 8, 8,
+ CRYPTO_CIPHER_ALG_DES },
+ { TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK, 24, 24, 8,
+ CRYPTO_CIPHER_ALG_3DES },
+ { TLS_CIPHER_AES_128_CBC, TLS_CIPHER_BLOCK, 16, 16, 16,
+ CRYPTO_CIPHER_ALG_AES },
+ { TLS_CIPHER_AES_256_CBC, TLS_CIPHER_BLOCK, 32, 32, 16,
+ CRYPTO_CIPHER_ALG_AES }
+};
+
+#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
+
+
+/**
+ * tls_get_cipher_suite - Get TLS cipher suite
+ * @suite: Cipher suite identifier
+ * Returns: Pointer to the cipher data or %NULL if not found
+ */
+const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite)
+{
+ size_t i;
+ for (i = 0; i < NUM_TLS_CIPHER_SUITES; i++)
+ if (tls_cipher_suites[i].suite == suite)
+ return &tls_cipher_suites[i];
+ return NULL;
+}
+
+
+static const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)
+{
+ size_t i;
+ for (i = 0; i < NUM_TLS_CIPHER_DATA; i++)
+ if (tls_ciphers[i].cipher == cipher)
+ return &tls_ciphers[i];
+ return NULL;
+}
+
+
+/**
+ * tls_parse_cert - Parse DER encoded X.509 certificate and get public key
+ * @buf: ASN.1 DER encoded certificate
+ * @len: Length of the buffer
+ * @pk: Buffer for returning the allocated public key
+ * Returns: 0 on success, -1 on failure
+ *
+ * This functions parses an ASN.1 DER encoded X.509 certificate and retrieves
+ * the public key from it. The caller is responsible for freeing the public key
+ * by calling crypto_public_key_free().
+ */
+int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk)
+{
+ struct x509_certificate *cert;
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Parse ASN.1 DER certificate",
+ buf, len);
+
+ *pk = crypto_public_key_from_cert(buf, len);
+ if (*pk)
+ return 0;
+
+ cert = x509_certificate_parse(buf, len);
+ if (cert == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse X.509 "
+ "certificate");
+ return -1;
+ }
+
+ /* TODO
+ * verify key usage (must allow encryption)
+ *
+ * All certificate profiles, key and cryptographic formats are
+ * defined by the IETF PKIX working group [PKIX]. When a key
+ * usage extension is present, the digitalSignature bit must be
+ * set for the key to be eligible for signing, as described
+ * above, and the keyEncipherment bit must be present to allow
+ * encryption, as described above. The keyAgreement bit must be
+ * set on Diffie-Hellman certificates. (PKIX: RFC 3280)
+ */
+
+ *pk = crypto_public_key_import(cert->public_key, cert->public_key_len);
+ x509_certificate_free(cert);
+
+ if (*pk == NULL) {
+ wpa_printf(MSG_ERROR, "TLSv1: Failed to import "
+ "server public key");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
+ * @rl: Pointer to TLS record layer data
+ * @cipher_suite: New cipher suite
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to prepare TLS record layer for cipher suite change.
+ * tlsv1_record_change_write_cipher() and
+ * tlsv1_record_change_read_cipher() functions can then be used to change the
+ * currently used ciphers.
+ */
+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
+ u16 cipher_suite)
+{
+ const struct tls_cipher_suite *suite;
+ const struct tls_cipher_data *data;
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
+ cipher_suite);
+ rl->cipher_suite = cipher_suite;
+
+ suite = tls_get_cipher_suite(cipher_suite);
+ if (suite == NULL)
+ return -1;
+
+ if (suite->hash == TLS_HASH_MD5) {
+ rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
+ rl->hash_size = MD5_MAC_LEN;
+ } else if (suite->hash == TLS_HASH_SHA) {
+ rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
+ rl->hash_size = SHA1_MAC_LEN;
+ }
+
+ data = tls_get_cipher_data(suite->cipher);
+ if (data == NULL)
+ return -1;
+
+ rl->key_material_len = data->key_material;
+ rl->iv_size = data->block_size;
+ rl->cipher_alg = data->alg;
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
+ * @rl: Pointer to TLS record layer data
+ * Returns: 0 on success (cipher changed), -1 on failure
+ *
+ * This function changes TLS record layer to use the new cipher suite
+ * configured with tlsv1_record_set_cipher_suite() for writing.
+ */
+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
+{
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
+ "0x%04x", rl->cipher_suite);
+ rl->write_cipher_suite = rl->cipher_suite;
+ os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
+
+ if (rl->write_cbc) {
+ crypto_cipher_deinit(rl->write_cbc);
+ rl->write_cbc = NULL;
+ }
+ if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
+ rl->write_cbc = crypto_cipher_init(rl->cipher_alg,
+ rl->write_iv, rl->write_key,
+ rl->key_material_len);
+ if (rl->write_cbc == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
+ "cipher");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
+ * @rl: Pointer to TLS record layer data
+ * Returns: 0 on success (cipher changed), -1 on failure
+ *
+ * This function changes TLS record layer to use the new cipher suite
+ * configured with tlsv1_record_set_cipher_suite() for reading.
+ */
+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
+{
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
+ "0x%04x", rl->cipher_suite);
+ rl->read_cipher_suite = rl->cipher_suite;
+ os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
+
+ if (rl->read_cbc) {
+ crypto_cipher_deinit(rl->read_cbc);
+ rl->read_cbc = NULL;
+ }
+ if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
+ rl->read_cbc = crypto_cipher_init(rl->cipher_alg,
+ rl->read_iv, rl->read_key,
+ rl->key_material_len);
+ if (rl->read_cbc == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
+ "cipher");
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_record_send - TLS record layer: Send a message
+ * @rl: Pointer to TLS record layer data
+ * @content_type: Content type (TLS_CONTENT_TYPE_*)
+ * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
+ * beginning for record layer to fill in; payload filled in after this and
+ * extra space in the end for HMAC).
+ * @buf_size: Maximum buf size
+ * @payload_len: Length of the payload
+ * @out_len: Buffer for returning the used buf length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function fills in the TLS record layer header, adds HMAC, and encrypts
+ * the data using the current write cipher.
+ */
+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
+ size_t buf_size, size_t payload_len, size_t *out_len)
+{
+ u8 *pos, *ct_start, *length, *payload;
+ struct crypto_hash *hmac;
+ size_t clen;
+
+ pos = buf;
+ /* ContentType type */
+ ct_start = pos;
+ *pos++ = content_type;
+ /* ProtocolVersion version */
+ WPA_PUT_BE16(pos, TLS_VERSION);
+ pos += 2;
+ /* uint16 length */
+ length = pos;
+ WPA_PUT_BE16(length, payload_len);
+ pos += 2;
+
+ /* opaque fragment[TLSPlaintext.length] */
+ payload = pos;
+ pos += payload_len;
+
+ if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+ hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
+ rl->hash_size);
+ if (hmac == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+ "to initialize HMAC");
+ return -1;
+ }
+ crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
+ /* type + version + length + fragment */
+ crypto_hash_update(hmac, ct_start, pos - ct_start);
+ clen = buf + buf_size - pos;
+ if (clen < rl->hash_size) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
+ "enough room for MAC");
+ crypto_hash_finish(hmac, NULL, NULL);
+ return -1;
+ }
+
+ if (crypto_hash_finish(hmac, pos, &clen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+ "to calculate HMAC");
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
+ pos, clen);
+ pos += clen;
+ if (rl->iv_size) {
+ size_t len = pos - payload;
+ size_t pad;
+ pad = (len + 1) % rl->iv_size;
+ if (pad)
+ pad = rl->iv_size - pad;
+ if (pos + pad + 1 > buf + buf_size) {
+ wpa_printf(MSG_DEBUG, "TLSv1: No room for "
+ "block cipher padding");
+ return -1;
+ }
+ os_memset(pos, pad, pad + 1);
+ pos += pad + 1;
+ }
+
+ if (crypto_cipher_encrypt(rl->write_cbc, payload,
+ payload, pos - payload) < 0)
+ return -1;
+ }
+
+ WPA_PUT_BE16(length, pos - length - 2);
+ inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
+
+ *out_len = pos - buf;
+
+ return 0;
+}
+
+
+/**
+ * tlsv1_record_receive - TLS record layer: Process a received message
+ * @rl: Pointer to TLS record layer data
+ * @in_data: Received data
+ * @in_len: Length of the received data
+ * @out_data: Buffer for output data (must be at least as long as in_data)
+ * @out_len: Set to maximum out_data length by caller; used to return the
+ * length of the used data
+ * @alert: Buffer for returning an alert value on failure
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function decrypts the received message, verifies HMAC and TLS record
+ * layer header.
+ */
+int tlsv1_record_receive(struct tlsv1_record_layer *rl,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t *out_len, u8 *alert)
+{
+ size_t i, rlen, hlen;
+ u8 padlen;
+ struct crypto_hash *hmac;
+ u8 len[2], hash[100];
+
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+ in_data, in_len);
+
+ if (in_len < TLS_RECORD_HEADER_LEN) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
+ (unsigned long) in_len);
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
+ "length %d", in_data[0], in_data[1], in_data[2],
+ WPA_GET_BE16(in_data + 3));
+
+ if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
+ in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
+ in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
+ in_data[0]);
+ *alert = TLS_ALERT_UNEXPECTED_MESSAGE;
+ return -1;
+ }
+
+ if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
+ "%d.%d", in_data[1], in_data[2]);
+ *alert = TLS_ALERT_PROTOCOL_VERSION;
+ return -1;
+ }
+
+ rlen = WPA_GET_BE16(in_data + 3);
+
+ /* TLSCiphertext must not be more than 2^14+2048 bytes */
+ if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
+ (unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
+ *alert = TLS_ALERT_RECORD_OVERFLOW;
+ return -1;
+ }
+
+ in_data += TLS_RECORD_HEADER_LEN;
+ in_len -= TLS_RECORD_HEADER_LEN;
+
+ if (rlen > in_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
+ "(rlen=%lu > in_len=%lu)",
+ (unsigned long) rlen, (unsigned long) in_len);
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+
+ in_len = rlen;
+
+ if (*out_len < in_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
+ "processing received record");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+
+ os_memcpy(out_data, in_data, in_len);
+ *out_len = in_len;
+
+ if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+ if (crypto_cipher_decrypt(rl->read_cbc, out_data,
+ out_data, in_len) < 0) {
+ *alert = TLS_ALERT_DECRYPTION_FAILED;
+ return -1;
+ }
+ if (rl->iv_size) {
+ if (in_len == 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
+ " (no pad)");
+ *alert = TLS_ALERT_DECODE_ERROR;
+ return -1;
+ }
+ padlen = out_data[in_len - 1];
+ if (padlen >= in_len) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
+ "length (%u, in_len=%lu) in "
+ "received record",
+ padlen, (unsigned long) in_len);
+ *alert = TLS_ALERT_DECRYPTION_FAILED;
+ return -1;
+ }
+ for (i = in_len - padlen; i < in_len; i++) {
+ if (out_data[i] != padlen) {
+ wpa_hexdump(MSG_DEBUG,
+ "TLSv1: Invalid pad in "
+ "received record",
+ out_data + in_len - padlen,
+ padlen);
+ *alert = TLS_ALERT_DECRYPTION_FAILED;
+ return -1;
+ }
+ }
+
+ *out_len -= padlen + 1;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP,
+ "TLSv1: Record Layer - Decrypted data",
+ out_data, in_len);
+
+ if (*out_len < rl->hash_size) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
+ "hash value");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+
+ *out_len -= rl->hash_size;
+
+ hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
+ rl->hash_size);
+ if (hmac == NULL) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+ "to initialize HMAC");
+ *alert = TLS_ALERT_INTERNAL_ERROR;
+ return -1;
+ }
+
+ crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
+ /* type + version + length + fragment */
+ crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
+ WPA_PUT_BE16(len, *out_len);
+ crypto_hash_update(hmac, len, 2);
+ crypto_hash_update(hmac, out_data, *out_len);
+ hlen = sizeof(hash);
+ if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
+ "to calculate HMAC");
+ return -1;
+ }
+ if (hlen != rl->hash_size ||
+ os_memcmp(hash, out_data + *out_len, hlen) != 0) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
+ "received message");
+ *alert = TLS_ALERT_BAD_RECORD_MAC;
+ return -1;
+ }
+ }
+
+ /* TLSCompressed must not be more than 2^14+1024 bytes */
+ if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
+ wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
+ (unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
+ *alert = TLS_ALERT_RECORD_OVERFLOW;
+ return -1;
+ }
+
+ inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
+
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/tlsv1_common.h b/contrib/wpa_supplicant/tlsv1_common.h
new file mode 100644
index 000000000000..9ecabfa2762b
--- /dev/null
+++ b/contrib/wpa_supplicant/tlsv1_common.h
@@ -0,0 +1,233 @@
+/*
+ * wpa_supplicant/hostapd: TLSv1 common definitions
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef TLSV1_COMMON
+#define TLSV1_COMMON
+
+#define TLS_VERSION 0x0301 /* TLSv1 */
+#define TLS_RANDOM_LEN 32
+#define TLS_PRE_MASTER_SECRET_LEN 48
+#define TLS_MASTER_SECRET_LEN 48
+#define TLS_SESSION_ID_MAX_LEN 32
+#define TLS_VERIFY_DATA_LEN 12
+#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
+#define TLS_MAX_WRITE_KEY_LEN 32
+#define TLS_MAX_IV_LEN 16
+#define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
+ TLS_MAX_WRITE_KEY_LEN + TLS_MAX_IV_LEN))
+#define TLS_SEQ_NUM_LEN 8
+#define TLS_RECORD_HEADER_LEN 5
+
+/* ContentType */
+enum {
+ TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC = 20,
+ TLS_CONTENT_TYPE_ALERT = 21,
+ TLS_CONTENT_TYPE_HANDSHAKE = 22,
+ TLS_CONTENT_TYPE_APPLICATION_DATA = 23
+};
+
+/* HandshakeType */
+enum {
+ TLS_HANDSHAKE_TYPE_HELLO_REQUEST = 0,
+ TLS_HANDSHAKE_TYPE_CLIENT_HELLO = 1,
+ TLS_HANDSHAKE_TYPE_SERVER_HELLO = 2,
+ TLS_HANDSHAKE_TYPE_CERTIFICATE = 11,
+ TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE = 12,
+ TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST = 13,
+ TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE = 14,
+ TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY = 15,
+ TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE = 16,
+ TLS_HANDSHAKE_TYPE_FINISHED = 20
+};
+
+/* CipherSuite */
+#define TLS_NULL_WITH_NULL_NULL 0x0000 /* RFC 2246 */
+#define TLS_RSA_WITH_NULL_MD5 0x0001 /* RFC 2246 */
+#define TLS_RSA_WITH_NULL_SHA 0x0002 /* RFC 2246 */
+#define TLS_RSA_EXPORT_WITH_RC4_40_MD5 0x0003 /* RFC 2246 */
+#define TLS_RSA_WITH_RC4_128_MD5 0x0004 /* RFC 2246 */
+#define TLS_RSA_WITH_RC4_128_SHA 0x0005 /* RFC 2246 */
+#define TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 0x0006 /* RFC 2246 */
+#define TLS_RSA_WITH_IDEA_CBC_SHA 0x0007 /* RFC 2246 */
+#define TLS_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0008 /* RFC 2246 */
+#define TLS_RSA_WITH_DES_CBC_SHA 0x0009 /* RFC 2246 */
+#define TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A /* RFC 2246 */
+#define TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA 0x000B /* RFC 2246 */
+#define TLS_DH_DSS_WITH_DES_CBC_SHA 0x000C /* RFC 2246 */
+#define TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D /* RFC 2246 */
+#define TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA 0x000E /* RFC 2246 */
+#define TLS_DH_RSA_WITH_DES_CBC_SHA 0x000F /* RFC 2246 */
+#define TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010 /* RFC 2246 */
+#define TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA 0x0011 /* RFC 2246 */
+#define TLS_DHE_DSS_WITH_DES_CBC_SHA 0x0012 /* RFC 2246 */
+#define TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013 /* RFC 2246 */
+#define TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA 0x0014 /* RFC 2246 */
+#define TLS_DHE_RSA_WITH_DES_CBC_SHA 0x0015 /* RFC 2246 */
+#define TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016 /* RFC 2246 */
+#define TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 0x0017 /* RFC 2246 */
+#define TLS_DH_anon_WITH_RC4_128_MD5 0x0018 /* RFC 2246 */
+#define TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA 0x0019 /* RFC 2246 */
+#define TLS_DH_anon_WITH_DES_CBC_SHA 0x001A /* RFC 2246 */
+#define TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B /* RFC 2246 */
+#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F /* RFC 3268 */
+#define TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030 /* RFC 3268 */
+#define TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031 /* RFC 3268 */
+#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032 /* RFC 3268 */
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033 /* RFC 3268 */
+#define TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034 /* RFC 3268 */
+#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035 /* RFC 3268 */
+#define TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036 /* RFC 3268 */
+#define TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037 /* RFC 3268 */
+#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038 /* RFC 3268 */
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039 /* RFC 3268 */
+#define TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A /* RFC 3268 */
+
+/* CompressionMethod */
+#define TLS_COMPRESSION_NULL 0
+
+/* AlertLevel */
+#define TLS_ALERT_LEVEL_WARNING 1
+#define TLS_ALERT_LEVEL_FATAL 2
+
+/* AlertDescription */
+#define TLS_ALERT_CLOSE_NOTIFY 0
+#define TLS_ALERT_UNEXPECTED_MESSAGE 10
+#define TLS_ALERT_BAD_RECORD_MAC 20
+#define TLS_ALERT_DECRYPTION_FAILED 21
+#define TLS_ALERT_RECORD_OVERFLOW 22
+#define TLS_ALERT_DECOMPRESSION_FAILURE 30
+#define TLS_ALERT_HANDSHAKE_FAILURE 40
+#define TLS_ALERT_BAD_CERTIFICATE 42
+#define TLS_ALERT_UNSUPPORTED_CERTIFICATE 43
+#define TLS_ALERT_CERTIFICATE_REVOKED 44
+#define TLS_ALERT_CERTIFICATE_EXPIRED 45
+#define TLS_ALERT_CERTIFICATE_UNKNOWN 46
+#define TLS_ALERT_ILLEGAL_PARAMETER 47
+#define TLS_ALERT_UNKNOWN_CA 48
+#define TLS_ALERT_ACCESS_DENIED 49
+#define TLS_ALERT_DECODE_ERROR 50
+#define TLS_ALERT_DECRYPT_ERROR 51
+#define TLS_ALERT_EXPORT_RESTRICTION 60
+#define TLS_ALERT_PROTOCOL_VERSION 70
+#define TLS_ALERT_INSUFFICIENT_SECURITY 71
+#define TLS_ALERT_INTERNAL_ERROR 80
+#define TLS_ALERT_USER_CANCELED 90
+#define TLS_ALERT_NO_RENEGOTIATION 100
+
+/* ChangeCipherSpec */
+enum {
+ TLS_CHANGE_CIPHER_SPEC = 1
+};
+
+/* TLS Extensions */
+#define TLS_EXT_PAC_OPAQUE 35
+
+
+typedef enum {
+ TLS_KEY_X_NULL,
+ TLS_KEY_X_RSA,
+ TLS_KEY_X_RSA_EXPORT,
+ TLS_KEY_X_DH_DSS_EXPORT,
+ TLS_KEY_X_DH_DSS,
+ TLS_KEY_X_DH_RSA_EXPORT,
+ TLS_KEY_X_DH_RSA,
+ TLS_KEY_X_DHE_DSS_EXPORT,
+ TLS_KEY_X_DHE_DSS,
+ TLS_KEY_X_DHE_RSA_EXPORT,
+ TLS_KEY_X_DHE_RSA,
+ TLS_KEY_X_DH_anon_EXPORT,
+ TLS_KEY_X_DH_anon
+} tls_key_exchange;
+
+typedef enum {
+ TLS_CIPHER_NULL,
+ TLS_CIPHER_RC4_40,
+ TLS_CIPHER_RC4_128,
+ TLS_CIPHER_RC2_CBC_40,
+ TLS_CIPHER_IDEA_CBC,
+ TLS_CIPHER_DES40_CBC,
+ TLS_CIPHER_DES_CBC,
+ TLS_CIPHER_3DES_EDE_CBC,
+ TLS_CIPHER_AES_128_CBC,
+ TLS_CIPHER_AES_256_CBC
+} tls_cipher;
+
+typedef enum {
+ TLS_HASH_NULL,
+ TLS_HASH_MD5,
+ TLS_HASH_SHA
+} tls_hash;
+
+struct tls_cipher_suite {
+ u16 suite;
+ tls_key_exchange key_exchange;
+ tls_cipher cipher;
+ tls_hash hash;
+};
+
+typedef enum {
+ TLS_CIPHER_STREAM,
+ TLS_CIPHER_BLOCK
+} tls_cipher_type;
+
+struct tls_cipher_data {
+ tls_cipher cipher;
+ tls_cipher_type type;
+ size_t key_material;
+ size_t expanded_key_material;
+ size_t block_size; /* also iv_size */
+ enum crypto_cipher_alg alg;
+};
+
+
+struct tlsv1_record_layer {
+ u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
+ u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
+ u8 write_key[TLS_MAX_WRITE_KEY_LEN];
+ u8 read_key[TLS_MAX_WRITE_KEY_LEN];
+ u8 write_iv[TLS_MAX_IV_LEN];
+ u8 read_iv[TLS_MAX_IV_LEN];
+
+ size_t hash_size;
+ size_t key_material_len;
+ size_t iv_size; /* also block_size */
+
+ enum crypto_hash_alg hash_alg;
+ enum crypto_cipher_alg cipher_alg;
+
+ u8 write_seq_num[TLS_SEQ_NUM_LEN];
+ u8 read_seq_num[TLS_SEQ_NUM_LEN];
+
+ u16 cipher_suite;
+ u16 write_cipher_suite;
+ u16 read_cipher_suite;
+
+ struct crypto_cipher *write_cbc;
+ struct crypto_cipher *read_cbc;
+};
+
+
+const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite);
+int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk);
+int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
+ u16 cipher_suite);
+int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
+int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
+int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
+ size_t buf_size, size_t payload_len, size_t *out_len);
+int tlsv1_record_receive(struct tlsv1_record_layer *rl,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t *out_len, u8 *alert);
+
+#endif /* TLSV1_COMMON_H */
diff --git a/contrib/wpa_supplicant/todo.txt b/contrib/wpa_supplicant/todo.txt
index 5ecda1db5d70..edfff4fd1673 100644
--- a/contrib/wpa_supplicant/todo.txt
+++ b/contrib/wpa_supplicant/todo.txt
@@ -19,33 +19,23 @@ To do:
- EAP-SIM/AKA: AT_RESULT_IND
- on disconnect event, could try to associate with another AP if one is
present in scan results; would need to update scan results periodically..
-- add flag scan_requested and only try to re-associate if this is set when
- new scan results are received; this would allow background scans without
- triggering re-assoc..
- if driver/hw is not WPA2 capable, must remove WPA_PROTO_RSN flag from
ssid->proto fields to avoid detecting downgrade attacks when the driver
is not reporting RSN IE, but msg 3/4 has one
-- EAP-SIM/AKA: if SIM reader initialization fails, do not start authentication
- Cisco AP and non-zero keyidx for unicast -> map to broadcast
(actually, this already works with driver_ndis; so maybe just change
driver_*.c to do the mapping for drivers that cannot handle non-zero keyidx
for unicast); worked also with Host AP driver and madwifi
- IEEE 802.1X and key update with driver_ndis?? wpa_supplicant did not seem
to see unencrypted EAPOL-Key frames at all..
-- -Dwired: if ssid is set in network block, authentication gets "stuck" since
- driver_wired.c only reports empty SSID and association is not assumed to be
- ok
- EAP-PAX with PAX_SEC
-- EAP: extended nak, vendor method; go through rfc
- RFC 3748
- * Expanded Type (Sect. 5.7)
- * Experimental Type
- * Expanded Nak (Sect. 5.3.2)
+- EAP (RFC 3748)
* OTP Extended Responses (Sect. 5.5)
- test what happens if authenticator sends EAP-Success before real EAP
authentication ("canned" Success); this should be ignored based on
RFC 3748 Sect. 4.2
- test compilation with gcc -W options (more warnings?)
+ (Done once; number of unused function arguments still present)
- add proper support for using dot11RSNAConfigSATimeout
- ctrl_iface: get/set/remove blob
- use doc/docbook/*.sgml and docbook2{txt,html,pdf} to replace README and
@@ -53,3 +43,82 @@ To do:
in one page; how to build a PDF file with all the SGML included?
- test wait-for-interface and daemonize combinations with number of driver
interfaces
+ * 'test' worked with WPA-PSK
+- EAP-POTP/RSA SecurID profile (draft-nystrom-eap-potp-03.txt)
+- document wpa_gui build and consider adding it to 'make install'
+- test madwifi with pairwise=TKIP group=WEP104
+- possibility to link in WPA Authenticator state machine to wpa_supplicant
+ (new STAKey handshake, WPA2 IBSS)
+- consider merging hostapd and wpa_supplicant PMKSA cache implementations
+- add support for configuring password for MSCHAPv2 as NtPasswordHash in
+ the same way as was added to hostapd (hash:<hex value>)
+- test_driver: configure directory and create AP-<mac> and STA-<mac> files
+ there to allow scanning multiple APs (e.g., for testing pre-auth and PMKSA
+ caching testing) and to exchange STA-STA EAPOL frames
+- consider adding generic buffer functionality that could be used in number
+ of places
+ * allocate buffer (with default max size), allow reserving head room to
+ make it possible to add a header without having to reallocate buffer
+ * reallocate buffer (add head and/or tail room)
+ * ref count and free when count=0 ?
+ * add data (to tail): re-alloc more tailroom if needed and copy new data
+ * error flag so that caller can do multiple add()s and only in the end
+ check whether something has failed; this should make error handling
+ simpler
+- consider redesigning pending EAP requests (identity/password/otp from
+ ctrl_iface) by moving the retrying of the previous request into EAP
+ state machine so that EAPOL state machine is not needed for this
+- rfc4284.txt (network selection for eap)
+- www pages about configuring wpa_supplicant:
+ * global options (ap_scan, ctrl_interfaces) based on OS/driver
+ * network block
+ * key_mgmt selection
+ * WPA parameters
+ * EAP options (one page for each method)
+ * "configuration wizard" (step 1: select OS, step 2: select driver, ...) to
+ generate example configuration
+- error path in rsn_preauth_init: should probably deinit l2_packet handlers
+ if something fails; does something else need deinit?
+- consider moving SIM card functionality (IMSI fetching) away from eap.c;
+ this should likely happen before EAP is initialized for authentication;
+ now IMSI is read only after receiving EAP-Identity/Request, but since it is
+ really needed for all cases, reading IMSI and generating Identity string
+ could very well be done before EAP has been started
+- test all allowed EAP Phase 2 methods (i.e., anything else than PEAP, TTLS,
+ FAST): SIM AKA PAX PSK LEAP; if these work, include in eap_testing.txt; if
+ not, either fix or make eap_allowed_phase2_type reject
+- try to work around race in receiving association event and first EAPOL
+ message
+- helper function to do memcmp(addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN)
+- add wpa_secure_memzero() macro and secure implementation (volatile u8*) to
+ clear memory; this would be used to clear temporary buffers containing
+ private data (e.g., keys); the macro can be defined to NOP in order to save
+ space (i.e., no code should depend on the macro doing something)
+- make sure that TLS session cache is not shared between EAP types or if it
+ is, that the cache entries are bound to only one EAP type; e.g., cache entry
+ created with EAP-TLS must not be allowed to do fast re-auth with EAP-TTLS
+- consider moving eap_tls_build_ack() call into eap_tls_process_helper()
+ (it seems to be called always if helper returns 1)
+ * could need to modify eap_{ttls,peap,fast}_decrypt to do same
+- add support for fetching full user cert chain from Windows certificate
+ stores even when there are intermediate CA certs that are not in the
+ configured ca_cert store (e.g., ROOT) (they could be, e.g., in CA store)
+
+
+0.6.x branch:
+- clean up common.[ch]
+- change TLS/crypto library interface to use a structure of function
+ pointers and helper inline functions (like driver_ops) instead of
+ requiring every TLS wrapper to implement all functions
+- move from CVS to git (0.3.x, 0.4.x, 0.5.x releases will continue
+ to be updated only on CVS)
+- move files into subdirectories and combine wpa_supplicant and hostapd
+ into a repository that matches in directory structure with the release
+ tarballs
+ (subdirs: eap_common, eap_peer, eap_server, driver, driver_ap, ...)
+- make it clearer that EAP server/peer can be used as a separate library
+ for other programs
+- add support for encrypted configuration fields (e.g., password, psk,
+ passphrase, pin)
+- wpa_gui: add support for setting and showing priority, id_str, auth_alg
+ (open/shared for static WEP)
diff --git a/contrib/wpa_supplicant/version.h b/contrib/wpa_supplicant/version.h
index 8f8eff860b87..2eed290d1b92 100644
--- a/contrib/wpa_supplicant/version.h
+++ b/contrib/wpa_supplicant/version.h
@@ -1,6 +1,6 @@
#ifndef VERSION_H
#define VERSION_H
-#define VERSION_STR "0.4.8"
+#define VERSION_STR "0.5.8"
#endif /* VERSION_H */
diff --git a/contrib/wpa_supplicant/wpa.c b/contrib/wpa_supplicant/wpa.c
index 91e1f2a6a21b..b6dd75668fe5 100644
--- a/contrib/wpa_supplicant/wpa.c
+++ b/contrib/wpa_supplicant/wpa.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - WPA state machine and EAPOL-Key processing
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,12 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <netinet/in.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "md5.h"
@@ -26,11 +21,11 @@
#include "aes_wrap.h"
#include "wpa.h"
#include "eloop.h"
-#include "wpa_supplicant.h"
#include "config.h"
#include "l2_packet.h"
#include "eapol_sm.h"
#include "preauth.h"
+#include "pmksa_cache.h"
#include "wpa_i.h"
@@ -43,7 +38,9 @@ static const u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x50, 0xf2, 2 };
static const u8 WPA_CIPHER_SUITE_NONE[] = { 0x00, 0x50, 0xf2, 0 };
static const u8 WPA_CIPHER_SUITE_WEP40[] = { 0x00, 0x50, 0xf2, 1 };
static const u8 WPA_CIPHER_SUITE_TKIP[] = { 0x00, 0x50, 0xf2, 2 };
+#if 0
static const u8 WPA_CIPHER_SUITE_WRAP[] = { 0x00, 0x50, 0xf2, 3 };
+#endif
static const u8 WPA_CIPHER_SUITE_CCMP[] = { 0x00, 0x50, 0xf2, 4 };
static const u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
@@ -61,13 +58,21 @@ static const u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
* WPA Capabilities (2 octets, little endian) (default: 0)
*/
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct wpa_ie_hdr {
u8 elem_id;
u8 len;
u8 oui[3];
u8 oui_type;
u8 version[2];
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
static const int RSN_SELECTOR_LEN = 4;
@@ -77,17 +82,53 @@ static const u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[] = { 0x00, 0x0f, 0xac, 2 };
static const u8 RSN_CIPHER_SUITE_NONE[] = { 0x00, 0x0f, 0xac, 0 };
static const u8 RSN_CIPHER_SUITE_WEP40[] = { 0x00, 0x0f, 0xac, 1 };
static const u8 RSN_CIPHER_SUITE_TKIP[] = { 0x00, 0x0f, 0xac, 2 };
+#if 0
static const u8 RSN_CIPHER_SUITE_WRAP[] = { 0x00, 0x0f, 0xac, 3 };
+#endif
static const u8 RSN_CIPHER_SUITE_CCMP[] = { 0x00, 0x0f, 0xac, 4 };
static const u8 RSN_CIPHER_SUITE_WEP104[] = { 0x00, 0x0f, 0xac, 5 };
+#ifdef CONFIG_IEEE80211W
+static const u8 RSN_CIPHER_SUITE_AES_128_CMAC[] = { 0x00, 0x0f, 0xac, 6 };
+#endif /* CONFIG_IEEE80211W */
/* EAPOL-Key Key Data Encapsulation
- * GroupKey and STAKey require encryption, otherwise, encryption is optional.
+ * GroupKey and PeerKey require encryption, otherwise, encryption is optional.
*/
static const u8 RSN_KEY_DATA_GROUPKEY[] = { 0x00, 0x0f, 0xac, 1 };
+#if 0
static const u8 RSN_KEY_DATA_STAKEY[] = { 0x00, 0x0f, 0xac, 2 };
+#endif
static const u8 RSN_KEY_DATA_MAC_ADDR[] = { 0x00, 0x0f, 0xac, 3 };
static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 };
+#ifdef CONFIG_PEERKEY
+static const u8 RSN_KEY_DATA_SMK[] = { 0x00, 0x0f, 0xac, 5 };
+static const u8 RSN_KEY_DATA_NONCE[] = { 0x00, 0x0f, 0xac, 6 };
+static const u8 RSN_KEY_DATA_LIFETIME[] = { 0x00, 0x0f, 0xac, 7 };
+static const u8 RSN_KEY_DATA_ERROR[] = { 0x00, 0x0f, 0xac, 8 };
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+/* FIX: IEEE 802.11w/D1.0 is using subtypes 5 and 6 for these, but they were
+ * already taken by 802.11ma (PeerKey). Need to update the values here once
+ * IEEE 802.11w fixes these. */
+static const u8 RSN_KEY_DATA_DHV[] = { 0x00, 0x0f, 0xac, 9 };
+static const u8 RSN_KEY_DATA_IGTK[] = { 0x00, 0x0f, 0xac, 10 };
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_PEERKEY
+enum {
+ STK_MUI_4WAY_STA_AP = 1,
+ STK_MUI_4WAY_STAT_STA = 2,
+ STK_MUI_GTK = 3,
+ STK_MUI_SMK = 4
+};
+
+enum {
+ STK_ERR_STA_NR = 1,
+ STK_ERR_STA_NRSN = 2,
+ STK_ERR_CPHR_NS = 3,
+ STK_ERR_NO_STSL = 4
+};
+#endif /* CONFIG_PEERKEY */
/* 1/4: PMKID
* 2/4: RSN IE
@@ -110,13 +151,18 @@ static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 };
* RSN Capabilities (2 octets, little endian) (default: 0)
* PMKID Count (2 octets) (default: 0)
* PMKID List (16 * n octets)
+ * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC)
*/
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct rsn_ie_hdr {
u8 elem_id; /* WLAN_EID_RSN */
u8 len;
u8 version[2];
-} __attribute__ ((packed));
+} STRUCT_PACKED;
struct wpa_eapol_key {
@@ -132,9 +178,31 @@ struct wpa_eapol_key {
u8 key_mic[16];
u8 key_data_length[2];
/* followed by key_data_length bytes of key_data */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+
+struct rsn_error_kde {
+ u16 mui;
+ u16 error_type;
+} STRUCT_PACKED;
+
+#ifdef CONFIG_IEEE80211W
+struct wpa_dhv_kde {
+ u8 dhv[WPA_DHV_LEN];
+} STRUCT_PACKED;
+
+struct wpa_igtk_kde {
+ u8 keyid[2];
+ u8 pn[6];
+ u8 igtk[WPA_IGTK_LEN];
+} STRUCT_PACKED;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
-#define WPA_KEY_INFO_TYPE_MASK (BIT(0) | BIT(1) | BIT(2))
+#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
@@ -149,8 +217,14 @@ struct wpa_eapol_key {
#define WPA_KEY_INFO_ERROR BIT(10)
#define WPA_KEY_INFO_REQUEST BIT(11)
#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
+#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)
+#ifdef CONFIG_PEERKEY
+static void wpa_supplicant_peerkey_free(struct wpa_sm *sm,
+ struct wpa_peerkey *peerkey);
+#endif /* CONFIG_PEERKEY */
+
/**
* wpa_cipher_txt - Convert cipher suite to a text string
@@ -203,15 +277,15 @@ static const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
static int wpa_selector_to_bitfield(const u8 *s)
{
- if (memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == 0)
return WPA_CIPHER_NONE;
- if (memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == 0)
return WPA_CIPHER_WEP40;
- if (memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == 0)
return WPA_CIPHER_TKIP;
- if (memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == 0)
return WPA_CIPHER_CCMP;
- if (memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == 0)
return WPA_CIPHER_WEP104;
return 0;
}
@@ -219,42 +293,72 @@ static int wpa_selector_to_bitfield(const u8 *s)
static int wpa_key_mgmt_to_bitfield(const u8 *s)
{
- if (memcmp(s, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN) == 0)
- return WPA_KEY_MGMT_IEEE8021X;
- if (memcmp(s, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X, WPA_SELECTOR_LEN) ==
+ if (os_memcmp(s, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN) ==
0)
+ return WPA_KEY_MGMT_IEEE8021X;
+ if (os_memcmp(s, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X, WPA_SELECTOR_LEN)
+ == 0)
return WPA_KEY_MGMT_PSK;
- if (memcmp(s, WPA_AUTH_KEY_MGMT_NONE, WPA_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, WPA_AUTH_KEY_MGMT_NONE, WPA_SELECTOR_LEN) == 0)
return WPA_KEY_MGMT_WPA_NONE;
return 0;
}
+#ifndef CONFIG_NO_WPA2
static int rsn_selector_to_bitfield(const u8 *s)
{
- if (memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == 0)
return WPA_CIPHER_NONE;
- if (memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == 0)
return WPA_CIPHER_WEP40;
- if (memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == 0)
return WPA_CIPHER_TKIP;
- if (memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == 0)
return WPA_CIPHER_CCMP;
- if (memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == 0)
+ if (os_memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == 0)
return WPA_CIPHER_WEP104;
+#ifdef CONFIG_IEEE80211W
+ if (os_memcmp(s, RSN_CIPHER_SUITE_AES_128_CMAC, RSN_SELECTOR_LEN) == 0)
+ return WPA_CIPHER_AES_128_CMAC;
+#endif /* CONFIG_IEEE80211W */
return 0;
}
static int rsn_key_mgmt_to_bitfield(const u8 *s)
{
- if (memcmp(s, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN) == 0)
- return WPA_KEY_MGMT_IEEE8021X;
- if (memcmp(s, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X, RSN_SELECTOR_LEN) ==
+ if (os_memcmp(s, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN) ==
0)
+ return WPA_KEY_MGMT_IEEE8021X;
+ if (os_memcmp(s, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X, RSN_SELECTOR_LEN)
+ == 0)
return WPA_KEY_MGMT_PSK;
return 0;
}
+#endif /* CONFIG_NO_WPA2 */
+
+
+#ifdef CONFIG_PEERKEY
+static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
+{
+ os_memcpy(pos, ie, ie_len);
+ return pos + ie_len;
+}
+
+
+static u8 * wpa_add_kde(u8 *pos, const u8 *kde, const u8 *data,
+ size_t data_len)
+{
+ *pos++ = GENERIC_INFO_ELEM;
+ *pos++ = RSN_SELECTOR_LEN + data_len;
+ os_memcpy(pos, kde, RSN_SELECTOR_LEN);
+ pos += RSN_SELECTOR_LEN;
+ os_memcpy(pos, data, data_len);
+ pos += data_len;
+ return pos;
+}
+#endif /* CONFIG_PEERKEY */
static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
@@ -272,6 +376,7 @@ static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
data->capabilities = 0;
data->pmkid = NULL;
data->num_pmkid = 0;
+ data->mgmt_group_cipher = 0;
if (wpa_ie_len == 0) {
/* No WPA IE - fail silently */
@@ -288,7 +393,7 @@ static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
if (hdr->elem_id != GENERIC_INFO_ELEM ||
hdr->len != wpa_ie_len - 2 ||
- memcmp(&hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN) != 0 ||
+ os_memcmp(hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN) != 0 ||
WPA_GET_LE16(hdr->version) != WPA_VERSION) {
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
__func__);
@@ -357,9 +462,8 @@ static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
}
if (left > 0) {
- wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes",
+ wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
__func__, left);
- return -1;
}
return 0;
@@ -369,6 +473,7 @@ static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data)
{
+#ifndef CONFIG_NO_WPA2
const struct rsn_ie_hdr *hdr;
const u8 *pos;
int left;
@@ -381,6 +486,12 @@ static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
data->capabilities = 0;
data->pmkid = NULL;
data->num_pmkid = 0;
+#ifdef CONFIG_IEEE80211W
+ data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+#else /* CONFIG_IEEE80211W */
+ data->mgmt_group_cipher = 0;
+#endif /* CONFIG_IEEE80211W */
+
if (rsn_ie_len == 0) {
/* No RSN IE - fail silently */
@@ -408,6 +519,13 @@ static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
if (left >= RSN_SELECTOR_LEN) {
data->group_cipher = rsn_selector_to_bitfield(pos);
+#ifdef CONFIG_IEEE80211W
+ if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
+ wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
+ "cipher", __func__);
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211W */
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
} else if (left > 0) {
@@ -431,6 +549,13 @@ static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
pos += RSN_SELECTOR_LEN;
left -= RSN_SELECTOR_LEN;
}
+#ifdef CONFIG_IEEE80211W
+ if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
+ wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
+ "pairwise cipher", __func__);
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211W */
} else if (left == 1) {
wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
__func__);
@@ -480,12 +605,29 @@ static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
}
}
+#ifdef CONFIG_IEEE80211W
+ if (left >= 4) {
+ data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
+ if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+ wpa_printf(MSG_DEBUG, "%s: Unsupported management "
+ "group cipher 0x%x", __func__,
+ data->mgmt_group_cipher);
+ return -1;
+ }
+ pos += RSN_SELECTOR_LEN;
+ left -= RSN_SELECTOR_LEN;
+ }
+#endif /* CONFIG_IEEE80211W */
+
if (left > 0) {
wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
__func__, left);
}
return 0;
+#else /* CONFIG_NO_WPA2 */
+ return -1;
+#endif /* CONFIG_NO_WPA2 */
}
@@ -521,18 +663,18 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
hdr = (struct wpa_ie_hdr *) wpa_ie;
hdr->elem_id = GENERIC_INFO_ELEM;
- memcpy(&hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN);
+ os_memcpy(hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN);
WPA_PUT_LE16(hdr->version, WPA_VERSION);
pos = (u8 *) (hdr + 1);
if (group_cipher == WPA_CIPHER_CCMP) {
- memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
} else if (group_cipher == WPA_CIPHER_TKIP) {
- memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
} else if (group_cipher == WPA_CIPHER_WEP104) {
- memcpy(pos, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN);
} else if (group_cipher == WPA_CIPHER_WEP40) {
- memcpy(pos, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
group_cipher);
@@ -543,11 +685,11 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
*pos++ = 1;
*pos++ = 0;
if (pairwise_cipher == WPA_CIPHER_CCMP) {
- memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
- memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
} else if (pairwise_cipher == WPA_CIPHER_NONE) {
- memcpy(pos, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
pairwise_cipher);
@@ -558,12 +700,13 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
*pos++ = 1;
*pos++ = 0;
if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
- memcpy(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X,
+ WPA_SELECTOR_LEN);
} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
- memcpy(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X,
- WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X,
+ WPA_SELECTOR_LEN);
} else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
- memcpy(pos, WPA_AUTH_KEY_MGMT_NONE, WPA_SELECTOR_LEN);
+ os_memcpy(pos, WPA_AUTH_KEY_MGMT_NONE, WPA_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
@@ -575,7 +718,7 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
hdr->len = (pos - wpa_ie) - 2;
- WPA_ASSERT(pos - wpa_ie <= wpa_ie_len);
+ WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
return pos - wpa_ie;
}
@@ -583,10 +726,13 @@ static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
int pairwise_cipher, int group_cipher,
- int key_mgmt, struct wpa_sm *sm)
+ int key_mgmt, int mgmt_group_cipher,
+ struct wpa_sm *sm)
{
+#ifndef CONFIG_NO_WPA2
u8 *pos;
struct rsn_ie_hdr *hdr;
+ u16 capab;
if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
@@ -599,13 +745,13 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
pos = (u8 *) (hdr + 1);
if (group_cipher == WPA_CIPHER_CCMP) {
- memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
+ os_memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
} else if (group_cipher == WPA_CIPHER_TKIP) {
- memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
+ os_memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
} else if (group_cipher == WPA_CIPHER_WEP104) {
- memcpy(pos, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN);
+ os_memcpy(pos, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN);
} else if (group_cipher == WPA_CIPHER_WEP40) {
- memcpy(pos, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN);
+ os_memcpy(pos, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
group_cipher);
@@ -616,11 +762,11 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
*pos++ = 1;
*pos++ = 0;
if (pairwise_cipher == WPA_CIPHER_CCMP) {
- memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
+ os_memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
} else if (pairwise_cipher == WPA_CIPHER_TKIP) {
- memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
+ os_memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
} else if (pairwise_cipher == WPA_CIPHER_NONE) {
- memcpy(pos, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN);
+ os_memcpy(pos, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
pairwise_cipher);
@@ -631,10 +777,11 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
*pos++ = 1;
*pos++ = 0;
if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
- memcpy(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN);
+ os_memcpy(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X,
+ RSN_SELECTOR_LEN);
} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
- memcpy(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X,
- RSN_SELECTOR_LEN);
+ os_memcpy(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X,
+ RSN_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
key_mgmt);
@@ -643,23 +790,46 @@ static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
pos += RSN_SELECTOR_LEN;
/* RSN Capabilities */
- *pos++ = 0;
- *pos++ = 0;
+ capab = 0;
+#ifdef CONFIG_IEEE80211W
+ if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC)
+ capab |= WPA_CAPABILITY_MGMT_FRAME_PROTECTION;
+#endif /* CONFIG_IEEE80211W */
+ WPA_PUT_LE16(pos, capab);
+ pos += 2;
if (sm->cur_pmksa) {
/* PMKID Count (2 octets, little endian) */
*pos++ = 1;
*pos++ = 0;
/* PMKID */
- memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
+ os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
pos += PMKID_LEN;
}
+#ifdef CONFIG_IEEE80211W
+ if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+ if (!sm->cur_pmksa) {
+ /* PMKID Count */
+ WPA_PUT_LE16(pos, 0);
+ pos += 2;
+
+ /* Management Group Cipher Suite */
+ memcpy(pos, RSN_CIPHER_SUITE_AES_128_CMAC,
+ RSN_SELECTOR_LEN);
+ pos += RSN_SELECTOR_LEN;
+ }
+ }
+#endif /* CONFIG_IEEE80211W */
+
hdr->len = (pos - rsn_ie) - 2;
- WPA_ASSERT(pos - rsn_ie <= rsn_ie_len);
+ WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
return pos - rsn_ie;
+#else /* CONFIG_NO_WPA2 */
+ return -1;
+#endif /* CONFIG_NO_WPA2 */
}
@@ -676,7 +846,8 @@ static int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
sm->pairwise_cipher,
sm->group_cipher,
- sm->key_mgmt, sm);
+ sm->key_mgmt, sm->mgmt_group_cipher,
+ sm);
else
return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
sm->pairwise_cipher,
@@ -688,6 +859,8 @@ static int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
/**
* wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
* @pmk: Pairwise master key
+ * @pmk_len: Length of PMK
+ * @label: Label to use in derivation
* @addr1: AA or SA
* @addr2: SA or AA
* @nonce1: ANonce or SNonce
@@ -699,32 +872,36 @@ static int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
* PTK = PRF-X(PMK, "Pairwise key expansion",
* Min(AA, SA) || Max(AA, SA) ||
* Min(ANonce, SNonce) || Max(ANonce, SNonce))
+ *
+ * STK = PRF-X(SMK, "Peer key expansion",
+ * Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
+ * Min(INonce, PNonce) || Max(INonce, PNonce))
*/
static void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
+ const char *label,
const u8 *addr1, const u8 *addr2,
const u8 *nonce1, const u8 *nonce2,
u8 *ptk, size_t ptk_len)
{
u8 data[2 * ETH_ALEN + 2 * 32];
- if (memcmp(addr1, addr2, ETH_ALEN) < 0) {
- memcpy(data, addr1, ETH_ALEN);
- memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
+ if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
+ os_memcpy(data, addr1, ETH_ALEN);
+ os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
} else {
- memcpy(data, addr2, ETH_ALEN);
- memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
+ os_memcpy(data, addr2, ETH_ALEN);
+ os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
}
- if (memcmp(nonce1, nonce2, 32) < 0) {
- memcpy(data + 2 * ETH_ALEN, nonce1, 32);
- memcpy(data + 2 * ETH_ALEN + 32, nonce2, 32);
+ if (os_memcmp(nonce1, nonce2, 32) < 0) {
+ os_memcpy(data + 2 * ETH_ALEN, nonce1, 32);
+ os_memcpy(data + 2 * ETH_ALEN + 32, nonce2, 32);
} else {
- memcpy(data + 2 * ETH_ALEN, nonce2, 32);
- memcpy(data + 2 * ETH_ALEN + 32, nonce1, 32);
+ os_memcpy(data + 2 * ETH_ALEN, nonce2, 32);
+ os_memcpy(data + 2 * ETH_ALEN + 32, nonce1, 32);
}
- sha1_prf(pmk, pmk_len, "Pairwise key expansion", data, sizeof(data),
- ptk, ptk_len);
+ sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk, ptk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
@@ -756,7 +933,7 @@ static void wpa_eapol_key_mic(const u8 *key, int ver,
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
u8 hash[SHA1_MAC_LEN];
hmac_sha1(key, 16, buf, len, hash);
- memcpy(mic, hash, MD5_MAC_LEN);
+ os_memcpy(mic, hash, MD5_MAC_LEN);
}
}
@@ -765,13 +942,29 @@ static void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
int ver, const u8 *dest, u16 proto,
u8 *msg, size_t msg_len, u8 *key_mic)
{
+ if (os_memcmp(dest, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0 &&
+ os_memcmp(sm->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) {
+ /*
+ * Association event was not yet received; try to fetch
+ * BSSID from the driver.
+ */
+ if (wpa_sm_get_bssid(sm, sm->bssid) < 0) {
+ wpa_printf(MSG_DEBUG, "WPA: Failed to read BSSID for "
+ "EAPOL-Key destination address");
+ } else {
+ dest = sm->bssid;
+ wpa_printf(MSG_DEBUG, "WPA: Use BSSID (" MACSTR
+ ") as the destination for EAPOL-Key",
+ MAC2STR(dest));
+ }
+ }
if (key_mic) {
wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic);
}
wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
eapol_sm_notify_tx_eapol_key(sm->eapol);
- free(msg);
+ os_free(msg);
}
@@ -820,8 +1013,8 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
key_info |= WPA_KEY_INFO_KEY_TYPE;
WPA_PUT_BE16(reply->key_info, key_info);
WPA_PUT_BE16(reply->key_length, 0);
- memcpy(reply->replay_counter, sm->request_counter,
- WPA_REPLAY_COUNTER_LEN);
+ os_memcpy(reply->replay_counter, sm->request_counter,
+ WPA_REPLAY_COUNTER_LEN);
inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
WPA_PUT_BE16(reply->key_data_length, 0);
@@ -835,6 +1028,149 @@ void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
}
+/**
+ * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1)
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @peer: MAC address of the peer STA
+ * Returns: 0 on success, or -1 on failure
+ *
+ * Send an EAPOL-Key Request to the current authenticator to start STK
+ * handshake with the peer.
+ */
+int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
+{
+#ifdef CONFIG_PEERKEY
+ size_t rlen, kde_len;
+ struct wpa_eapol_key *req;
+ int key_info, ver;
+ u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos;
+ u16 count;
+ struct wpa_ssid *ssid = sm->cur_ssid;
+ struct rsn_ie_hdr *hdr;
+ struct wpa_peerkey *peerkey;
+ struct wpa_ie_data ie;
+
+ if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set ||
+ ssid == NULL || !ssid->peerkey)
+ return -1;
+
+ if (sm->ap_rsn_ie &&
+ wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 &&
+ !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) {
+ wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK");
+ return -1;
+ }
+
+ if (sm->pairwise_cipher == WPA_CIPHER_CCMP)
+ ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+ else
+ ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+ if (wpa_sm_get_bssid(sm, bssid) < 0) {
+ wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
+ "SMK M1");
+ return -1;
+ }
+
+ /* TODO: find existing entry and if found, use that instead of adding
+ * a new one */
+ peerkey = os_malloc(sizeof(*peerkey));
+ if (peerkey == NULL)
+ return -1;
+ os_memset(peerkey, 0, sizeof(*peerkey));
+ peerkey->initiator = 1;
+ os_memcpy(peerkey->addr, peer, ETH_ALEN);
+
+ /* SMK M1:
+ * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
+ * MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE))
+ */
+
+ hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i;
+ hdr->elem_id = RSN_INFO_ELEM;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+ /* Group Suite can be anything for SMK RSN IE; receiver will just
+ * ignore it. */
+ os_memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
+ pos += RSN_SELECTOR_LEN;
+ count_pos = pos;
+ pos += 2;
+
+ count = 0;
+ if (ssid->pairwise_cipher & WPA_CIPHER_CCMP) {
+ os_memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
+ pos += RSN_SELECTOR_LEN;
+ count++;
+ }
+ if (ssid->pairwise_cipher & WPA_CIPHER_TKIP) {
+ os_memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
+ pos += RSN_SELECTOR_LEN;
+ count++;
+ }
+ WPA_PUT_LE16(count_pos, count);
+
+ hdr->len = (pos - peerkey->rsnie_i) - 2;
+ peerkey->rsnie_i_len = pos - peerkey->rsnie_i;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
+ peerkey->rsnie_i, peerkey->rsnie_i_len);
+
+ kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+
+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+ sizeof(*req) + kde_len, &rlen,
+ (void *) &req);
+ if (rbuf == NULL) {
+ wpa_supplicant_peerkey_free(sm, peerkey);
+ return -1;
+ }
+
+ req->type = EAPOL_KEY_TYPE_RSN;
+ key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver;
+ WPA_PUT_BE16(req->key_info, key_info);
+ WPA_PUT_BE16(req->key_length, 0);
+ os_memcpy(req->replay_counter, sm->request_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
+
+ if (hostapd_get_rand(peerkey->inonce, WPA_NONCE_LEN)) {
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
+ "WPA: Failed to get random data for INonce");
+ os_free(rbuf);
+ wpa_supplicant_peerkey_free(sm, peerkey);
+ return -1;
+ }
+ os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake",
+ req->key_nonce, WPA_NONCE_LEN);
+
+ WPA_PUT_BE16(req->key_data_length, (u16) kde_len);
+ pos = (u8 *) (req + 1);
+
+ /* Initiator RSN IE */
+ pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
+ /* Peer MAC address KDE */
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
+
+ wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
+ MACSTR ")", MAC2STR(peer));
+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
+ rbuf, rlen, req->key_mic);
+
+ peerkey->next = sm->peerkey;
+ sm->peerkey = peerkey;
+
+ return 0;
+
+#else /* CONFIG_PEERKEY */
+
+ return -1;
+
+#endif /* CONFIG_PEERKEY */
+}
+
+
struct wpa_eapol_ie_parse {
const u8 *wpa_ie;
size_t wpa_ie_len;
@@ -843,6 +1179,24 @@ struct wpa_eapol_ie_parse {
const u8 *pmkid;
const u8 *gtk;
size_t gtk_len;
+ const u8 *mac_addr;
+ size_t mac_addr_len;
+#ifdef CONFIG_PEERKEY
+ const u8 *smk;
+ size_t smk_len;
+ const u8 *nonce;
+ size_t nonce_len;
+ const u8 *lifetime;
+ size_t lifetime_len;
+ const u8 *error;
+ size_t error_len;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+ const u8 *dhv;
+ size_t dhv_len;
+ const u8 *igtk;
+ size_t igtk_len;
+#endif /* CONFIG_IEEE80211W */
};
@@ -860,7 +1214,7 @@ static int wpa_supplicant_parse_generic(const u8 *pos, const u8 *end,
return 1;
if (pos[1] >= 6 &&
- memcmp(pos + 2, WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0 &&
+ os_memcmp(pos + 2, WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0 &&
pos[2 + WPA_SELECTOR_LEN] == 1 &&
pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
ie->wpa_ie = pos;
@@ -870,17 +1224,71 @@ static int wpa_supplicant_parse_generic(const u8 *pos, const u8 *end,
if (pos + 1 + RSN_SELECTOR_LEN < end &&
pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- memcmp(pos + 2, RSN_KEY_DATA_PMKID, RSN_SELECTOR_LEN) == 0) {
+ os_memcmp(pos + 2, RSN_KEY_DATA_PMKID, RSN_SELECTOR_LEN) == 0) {
ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
return 0;
}
if (pos[1] > RSN_SELECTOR_LEN + 2 &&
- memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY, RSN_SELECTOR_LEN) == 0) {
+ os_memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY, RSN_SELECTOR_LEN) == 0) {
ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ os_memcmp(pos + 2, RSN_KEY_DATA_MAC_ADDR, RSN_SELECTOR_LEN) == 0) {
+ ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+ ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+#ifdef CONFIG_PEERKEY
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ os_memcmp(pos + 2, RSN_KEY_DATA_SMK, RSN_SELECTOR_LEN) == 0) {
+ ie->smk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
}
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ os_memcmp(pos + 2, RSN_KEY_DATA_NONCE, RSN_SELECTOR_LEN) == 0) {
+ ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
+ ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ os_memcmp(pos + 2, RSN_KEY_DATA_LIFETIME, RSN_SELECTOR_LEN) == 0) {
+ ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
+ ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ os_memcmp(pos + 2, RSN_KEY_DATA_ERROR, RSN_SELECTOR_LEN) == 0) {
+ ie->error = pos + 2 + RSN_SELECTOR_LEN;
+ ie->error_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211W
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ os_memcmp(pos + 2, RSN_KEY_DATA_DHV, RSN_SELECTOR_LEN) == 0) {
+ ie->dhv = pos + 2 + RSN_SELECTOR_LEN;
+ ie->dhv_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ os_memcmp(pos + 2, RSN_KEY_DATA_IGTK, RSN_SELECTOR_LEN) == 0) {
+ ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+ ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+ return 0;
+ }
+#endif /* CONFIG_IEEE80211W */
+
return 0;
}
@@ -898,11 +1306,19 @@ static int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
const u8 *pos, *end;
int ret = 0;
- memset(ie, 0, sizeof(*ie));
+ os_memset(ie, 0, sizeof(*ie));
for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+ if (pos[0] == 0xdd &&
+ ((pos == buf + len - 1) || pos[1] == 0)) {
+ /* Ignore padding */
+ break;
+ }
if (pos + 2 + pos[1] > end) {
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
- "underflow (ie=%d len=%d)", pos[0], pos[1]);
+ "underflow (ie=%d len=%d pos=%d)",
+ pos[0], pos[1], (int) (pos - buf));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
+ buf, len);
ret = -1;
break;
}
@@ -938,7 +1354,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
* not have enough time to get the association information
* event before receiving this 1/4 message, so try to find a
* matching PMKSA cache entry here. */
- sm->cur_pmksa = pmksa_cache_get(sm, src_addr, pmkid);
+ sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid);
if (sm->cur_pmksa) {
wpa_printf(MSG_DEBUG, "RSN: found matching PMKID from "
"PMKSA cache");
@@ -949,7 +1365,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
}
if (pmkid && sm->cur_pmksa &&
- memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+ os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
wpa_sm_set_pmk_from_pmksa(sm);
wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
@@ -959,20 +1375,22 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
int res, pmk_len;
pmk_len = PMK_LEN;
res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
-#ifdef EAP_LEAP
if (res) {
+ /*
+ * EAP-LEAP is an exception from other EAP methods: it
+ * uses only 16-byte PMK.
+ */
res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
pmk_len = 16;
}
-#endif /* EAP_LEAP */
if (res == 0) {
wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
"machines", sm->pmk, pmk_len);
sm->pmk_len = pmk_len;
- pmksa_cache_add(sm, sm->pmk, pmk_len, src_addr,
+ pmksa_cache_add(sm->pmksa, sm->pmk, pmk_len, src_addr,
sm->own_addr, sm->cur_ssid);
if (!sm->cur_pmksa && pmkid &&
- pmksa_cache_get(sm, src_addr, pmkid)) {
+ pmksa_cache_get(sm->pmksa, src_addr, pmkid)) {
wpa_printf(MSG_DEBUG, "RSN: the new PMK "
"matches with the PMKID");
abort_cached = 0;
@@ -1006,7 +1424,7 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
if (buf) {
wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL,
buf, buflen);
- free(buf);
+ os_free(buf);
}
return -1;
@@ -1017,24 +1435,22 @@ static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
static int wpa_supplicant_send_2_of_4(struct wpa_sm *sm,
- const unsigned char *src_addr,
+ const unsigned char *dst,
const struct wpa_eapol_key *key,
- int ver)
+ int ver, const u8 *nonce,
+ const u8 *wpa_ie, size_t wpa_ie_len,
+ struct wpa_ptk *ptk)
{
size_t rlen;
struct wpa_eapol_key *reply;
- struct wpa_ptk *ptk;
- u8 buf[8], *rbuf, *wpa_ie;
- int wpa_ie_len;
+ u8 *rbuf;
- if (sm->assoc_wpa_ie == NULL) {
- wpa_printf(MSG_WARNING, "WPA: No assoc_wpa_ie set - cannot "
+ if (wpa_ie == NULL) {
+ wpa_printf(MSG_WARNING, "WPA: No wpa_ie set - cannot "
"generate msg 2/4");
return -1;
}
- wpa_ie = sm->assoc_wpa_ie;
- wpa_ie_len = sm->assoc_wpa_ie_len;
wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
@@ -1050,40 +1466,17 @@ static int wpa_supplicant_send_2_of_4(struct wpa_sm *sm,
if (sm->proto == WPA_PROTO_RSN)
WPA_PUT_BE16(reply->key_length, 0);
else
- memcpy(reply->key_length, key->key_length, 2);
- memcpy(reply->replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
+ os_memcpy(reply->key_length, key->key_length, 2);
+ os_memcpy(reply->replay_counter, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
- memcpy(reply + 1, wpa_ie, wpa_ie_len);
+ os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
- if (sm->renew_snonce) {
- if (hostapd_get_rand(sm->snonce, WPA_NONCE_LEN)) {
- wpa_msg(sm->ctx->ctx, MSG_WARNING,
- "WPA: Failed to get random data for SNonce");
- free(rbuf);
- return -1;
- }
- sm->renew_snonce = 0;
- wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
- sm->snonce, WPA_NONCE_LEN);
- }
- memcpy(reply->key_nonce, sm->snonce, WPA_NONCE_LEN);
-
- /* Calculate PTK which will be stored as a temporary PTK until it has
- * been verified when processing message 3/4. */
- ptk = &sm->tptk;
- wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, sm->own_addr, src_addr,
- sm->snonce, key->key_nonce,
- (u8 *) ptk, sizeof(*ptk));
- /* Supplicant: swap tx/rx Mic keys */
- memcpy(buf, ptk->u.auth.tx_mic_key, 8);
- memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
- memcpy(ptk->u.auth.rx_mic_key, buf, 8);
- sm->tptk_set = 1;
+ os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
- wpa_eapol_key_send(sm, ptk->kck, ver, src_addr, ETH_P_EAPOL,
+ wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
rbuf, rlen, reply->key_mic);
return 0;
@@ -1096,6 +1489,8 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
u16 ver)
{
struct wpa_eapol_ie_parse ie;
+ struct wpa_ptk *ptk;
+ u8 buf[8];
if (wpa_sm_get_ssid(sm) == NULL) {
wpa_printf(MSG_WARNING, "WPA: No SSID info found (msg 1 of "
@@ -1107,27 +1502,54 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
wpa_printf(MSG_DEBUG, "WPA: RX message 1 of 4-Way Handshake from "
MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
- memset(&ie, 0, sizeof(ie));
+ os_memset(&ie, 0, sizeof(ie));
+#ifndef CONFIG_NO_WPA2
if (sm->proto == WPA_PROTO_RSN) {
/* RSN: msg 1/4 should contain PMKID for the selected PMK */
- const u8 *buf = (const u8 *) (key + 1);
+ const u8 *_buf = (const u8 *) (key + 1);
size_t len = WPA_GET_BE16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", buf, len);
- wpa_supplicant_parse_ies(buf, len, &ie);
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
+ wpa_supplicant_parse_ies(_buf, len, &ie);
if (ie.pmkid) {
wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
"Authenticator", ie.pmkid, PMKID_LEN);
}
}
+#endif /* CONFIG_NO_WPA2 */
if (wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid))
return;
- if (wpa_supplicant_send_2_of_4(sm, src_addr, key, ver))
+ if (sm->renew_snonce) {
+ if (hostapd_get_rand(sm->snonce, WPA_NONCE_LEN)) {
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
+ "WPA: Failed to get random data for SNonce");
+ return;
+ }
+ sm->renew_snonce = 0;
+ wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
+ sm->snonce, WPA_NONCE_LEN);
+ }
+
+ /* Calculate PTK which will be stored as a temporary PTK until it has
+ * been verified when processing message 3/4. */
+ ptk = &sm->tptk;
+ wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
+ sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
+ (u8 *) ptk, sizeof(*ptk));
+ /* Supplicant: swap tx/rx Mic keys */
+ os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
+ os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
+ os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
+ sm->tptk_set = 1;
+
+ if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
+ sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
+ ptk))
return;
- memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
+ os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
}
@@ -1150,7 +1572,9 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
wpa_sm_set_state(sm, WPA_COMPLETED);
if (secure) {
- /* MLME.SETPROTECTION.request(TA, Tx_Rx) */
+ wpa_sm_mlme_setprotection(
+ sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
+ MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
eapol_sm_notify_portValid(sm->eapol, TRUE);
if (sm->key_mgmt == WPA_KEY_MGMT_PSK)
eapol_sm_notify_eap_success(sm->eapol, TRUE);
@@ -1173,10 +1597,10 @@ static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
- const unsigned char *src_addr,
const struct wpa_eapol_key *key)
{
- int alg, keylen, rsclen;
+ int keylen, rsclen;
+ wpa_alg alg;
const u8 *key_rsc;
u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -1210,8 +1634,8 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
}
- if (wpa_sm_set_key(sm, alg, src_addr, 0, 1, key_rsc, rsclen,
- (u8 *) &sm->ptk.tk1, keylen) < 0) {
+ if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
+ (u8 *) sm->ptk.tk1, keylen) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set PTK to the "
"driver.");
return -1;
@@ -1222,7 +1646,7 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
static int wpa_supplicant_check_group_cipher(int group_cipher,
int keylen, int maxkeylen,
- int *key_rsc_len, int *alg)
+ int *key_rsc_len, wpa_alg *alg)
{
int ret = 0;
@@ -1276,7 +1700,8 @@ static int wpa_supplicant_check_group_cipher(int group_cipher,
struct wpa_gtk_data {
- int alg, tx, key_rsc_len, keyidx;
+ wpa_alg alg;
+ int tx, key_rsc_len, keyidx;
u8 gtk[32];
int gtk_len;
};
@@ -1295,9 +1720,9 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len);
if (sm->group_cipher == WPA_CIPHER_TKIP) {
/* Swap Tx/Rx keys for Michael MIC */
- memcpy(gtk_buf, gd->gtk, 16);
- memcpy(gtk_buf + 16, gd->gtk + 24, 8);
- memcpy(gtk_buf + 24, gd->gtk + 16, 8);
+ os_memcpy(gtk_buf, gd->gtk, 16);
+ os_memcpy(gtk_buf + 16, gd->gtk + 24, 8);
+ os_memcpy(gtk_buf + 24, gd->gtk + 16, 8);
_gtk = gtk_buf;
}
if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
@@ -1340,11 +1765,11 @@ static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
- const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- const u8 *gtk, int gtk_len,
+ const u8 *gtk, size_t gtk_len,
int key_info)
{
+#ifndef CONFIG_NO_WPA2
struct wpa_gtk_data gd;
/*
@@ -1355,7 +1780,7 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
* GTK
*/
- memset(&gd, 0, sizeof(gd));
+ os_memset(&gd, 0, sizeof(gd));
wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake",
gtk, gtk_len);
@@ -1368,7 +1793,7 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
gtk += 2;
gtk_len -= 2;
- memcpy(gd.gtk, gtk, gtk_len);
+ os_memcpy(gd.gtk, gtk, gtk_len);
gd.gtk_len = gtk_len;
if (wpa_supplicant_check_group_cipher(sm->group_cipher,
@@ -1379,9 +1804,68 @@ static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
return -1;
}
- wpa_supplicant_key_neg_complete(sm, src_addr,
+ wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info & WPA_KEY_INFO_SECURE);
return 0;
+#else /* CONFIG_NO_WPA2 */
+ return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+static int ieee80211w_set_keys(struct wpa_sm *sm,
+ struct wpa_eapol_ie_parse *ie)
+{
+#ifdef CONFIG_IEEE80211W
+ if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+ return 0;
+
+ if (ie->igtk) {
+ const struct wpa_igtk_kde *igtk;
+ u16 keyidx;
+ if (ie->igtk_len != sizeof(*igtk))
+ return -1;
+ igtk = (const struct wpa_igtk_kde *) ie->igtk;
+ keyidx = WPA_GET_LE16(igtk->keyid);
+ wpa_printf(MSG_DEBUG, "WPA: IGTK keyid %d "
+ "pn %02x%02x%02x%02x%02x%02x",
+ keyidx, MAC2STR(igtk->pn));
+ wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
+ igtk->igtk, WPA_IGTK_LEN);
+ if (keyidx > 4095) {
+ wpa_printf(MSG_WARNING, "WPA: Invalid IGTK KeyID %d",
+ keyidx);
+ return -1;
+ }
+ if (wpa_sm_set_key(sm, WPA_ALG_IGTK,
+ (u8 *) "\xff\xff\xff\xff\xff\xff",
+ keyidx, 0, igtk->pn, sizeof(igtk->pn),
+ igtk->igtk, WPA_IGTK_LEN) < 0) {
+ wpa_printf(MSG_WARNING, "WPA: Failed to configure IGTK"
+ " to the driver");
+ return -1;
+ }
+ }
+
+ if (ie->dhv) {
+ const struct wpa_dhv_kde *dhv;
+ if (ie->dhv_len != sizeof(*dhv))
+ return -1;
+ dhv = (const struct wpa_dhv_kde *) ie->dhv;
+ wpa_hexdump_key(MSG_DEBUG, "WPA: DHV", dhv->dhv, WPA_DHV_LEN);
+ if (wpa_sm_set_key(sm, WPA_ALG_DHV,
+ (u8 *) "\xff\xff\xff\xff\xff\xff", 0, 0,
+ NULL, 0, dhv->dhv, WPA_DHV_LEN) < 0) {
+ wpa_printf(MSG_WARNING, "WPA: Failed to configure DHV "
+ "to the driver");
+ return -1;
+ }
+ }
+
+ return 0;
+#else /* CONFIG_IEEE80211W */
+ return 0;
+#endif /* CONFIG_IEEE80211W */
}
@@ -1442,12 +1926,21 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
}
}
+ if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
+ (sm->ap_wpa_ie || sm->ap_rsn_ie)) {
+ wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
+ "with IE in Beacon/ProbeResp (no IE?)",
+ src_addr, ie->wpa_ie, ie->wpa_ie_len,
+ ie->rsn_ie, ie->rsn_ie_len);
+ return -1;
+ }
+
if ((ie->wpa_ie && sm->ap_wpa_ie &&
(ie->wpa_ie_len != sm->ap_wpa_ie_len ||
- memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) ||
+ os_memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) ||
(ie->rsn_ie && sm->ap_rsn_ie &&
(ie->rsn_ie_len != sm->ap_rsn_ie_len ||
- memcmp(ie->rsn_ie, sm->ap_rsn_ie, ie->rsn_ie_len) != 0))) {
+ os_memcmp(ie->rsn_ie, sm->ap_rsn_ie, ie->rsn_ie_len) != 0))) {
wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
"with IE in Beacon/ProbeResp",
src_addr, ie->wpa_ie, ie->wpa_ie_len,
@@ -1472,16 +1965,22 @@ static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
static int wpa_supplicant_send_4_of_4(struct wpa_sm *sm,
- const unsigned char *src_addr,
+ const unsigned char *dst,
const struct wpa_eapol_key *key,
- u16 ver, u16 key_info)
+ u16 ver, u16 key_info,
+ const u8 *kde, size_t kde_len,
+ struct wpa_ptk *ptk)
{
size_t rlen;
struct wpa_eapol_key *reply;
u8 *rbuf;
+ if (kde)
+ wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len);
+
rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
- sizeof(*reply), &rlen, (void *) &reply);
+ sizeof(*reply) + kde_len,
+ &rlen, (void *) &reply);
if (rbuf == NULL)
return -1;
@@ -1493,14 +1992,16 @@ static int wpa_supplicant_send_4_of_4(struct wpa_sm *sm,
if (sm->proto == WPA_PROTO_RSN)
WPA_PUT_BE16(reply->key_length, 0);
else
- memcpy(reply->key_length, key->key_length, 2);
- memcpy(reply->replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
+ os_memcpy(reply->key_length, key->key_length, 2);
+ os_memcpy(reply->replay_counter, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
- WPA_PUT_BE16(reply->key_data_length, 0);
+ WPA_PUT_BE16(reply->key_data_length, kde_len);
+ if (kde)
+ os_memcpy(reply + 1, kde, kde_len);
wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
+ wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
rbuf, rlen, reply->key_mic);
return 0;
@@ -1508,9 +2009,8 @@ static int wpa_supplicant_send_4_of_4(struct wpa_sm *sm,
static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
- const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- int extra_len, u16 ver)
+ u16 ver)
{
u16 key_info, keylen, len;
const u8 *pos;
@@ -1518,7 +2018,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
wpa_printf(MSG_DEBUG, "WPA: RX message 3 of 4-Way Handshake from "
- MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
+ MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver);
key_info = WPA_GET_BE16(key->key_info);
@@ -1530,14 +2030,33 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_printf(MSG_WARNING, "WPA: GTK IE in unencrypted key data");
return;
}
+#ifdef CONFIG_IEEE80211W
+ if ((ie.dhv || ie.igtk) && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+ wpa_printf(MSG_WARNING, "WPA: DHV/IGTK KDE in unencrypted key "
+ "data");
+ return;
+ }
+
+ if (ie.dhv && ie.dhv_len != sizeof(struct wpa_dhv_kde)) {
+ wpa_printf(MSG_WARNING, "WPA: Invalid DHV KDE length %lu",
+ (unsigned long) ie.dhv_len);
+ return;
+ }
- if (wpa_supplicant_validate_ie(sm, src_addr, &ie) < 0)
+ if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
+ wpa_printf(MSG_WARNING, "WPA: Invalid IGTK KDE length %lu",
+ (unsigned long) ie.igtk_len);
+ return;
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
return;
- if (memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
+ if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_WARNING, "WPA: ANonce from message 1 of 4-Way "
"Handshake differs from 3 of 4-Way Handshake - drop"
- " packet (src=" MACSTR ")", MAC2STR(src_addr));
+ " packet (src=" MACSTR ")", MAC2STR(sm->bssid));
return;
}
@@ -1547,7 +2066,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (keylen != 16) {
wpa_printf(MSG_WARNING, "WPA: Invalid CCMP key length "
"%d (src=" MACSTR ")",
- keylen, MAC2STR(src_addr));
+ keylen, MAC2STR(sm->bssid));
return;
}
break;
@@ -1555,13 +2074,14 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
if (keylen != 32) {
wpa_printf(MSG_WARNING, "WPA: Invalid TKIP key length "
"%d (src=" MACSTR ")",
- keylen, MAC2STR(src_addr));
+ keylen, MAC2STR(sm->bssid));
return;
}
break;
}
- if (wpa_supplicant_send_4_of_4(sm, src_addr, key, ver, key_info))
+ if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
+ NULL, 0, &sm->ptk))
return;
/* SNonce was successfully used in msg 3/4, so mark it to be renewed
@@ -1570,27 +2090,881 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
sm->renew_snonce = 1;
if (key_info & WPA_KEY_INFO_INSTALL) {
- wpa_supplicant_install_ptk(sm, src_addr, key);
+ wpa_supplicant_install_ptk(sm, key);
}
if (key_info & WPA_KEY_INFO_SECURE) {
- /* MLME.SETPROTECTION.request(TA, Tx_Rx) */
+ wpa_sm_mlme_setprotection(
+ sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX,
+ MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
eapol_sm_notify_portValid(sm->eapol, TRUE);
}
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
if (ie.gtk &&
- wpa_supplicant_pairwise_gtk(sm, src_addr, key,
+ wpa_supplicant_pairwise_gtk(sm, key,
ie.gtk, ie.gtk_len, key_info) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to configure GTK");
}
+
+ if (ieee80211w_set_keys(sm, &ie) < 0)
+ wpa_printf(MSG_INFO, "RSN: Failed to configure DHV/IGTK");
+}
+
+
+#ifdef CONFIG_PEERKEY
+static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+#if 0
+ struct wpa_sm *sm = eloop_ctx;
+ struct wpa_peerkey *peerkey = timeout_ctx;
+#endif
+ /* TODO: time out SMK and any STK that was generated using this SMK */
+}
+
+
+static void wpa_supplicant_peerkey_free(struct wpa_sm *sm,
+ struct wpa_peerkey *peerkey)
+{
+ eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
+ os_free(peerkey);
+}
+
+
+static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
+ const u8 *peer,
+ u16 mui, u16 error_type, int ver)
+{
+#ifndef CONFIG_NO_WPA2
+ size_t rlen;
+ struct wpa_eapol_key *err;
+ struct rsn_error_kde error;
+ u8 *rbuf, *pos;
+ size_t kde_len;
+ u16 key_info;
+
+ kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error);
+ if (peer)
+ kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+
+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
+ NULL, sizeof(*err) + kde_len, &rlen,
+ (void *) &err);
+ if (rbuf == NULL)
+ return -1;
+
+ err->type = EAPOL_KEY_TYPE_RSN;
+ key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR |
+ WPA_KEY_INFO_REQUEST;
+ WPA_PUT_BE16(err->key_info, key_info);
+ WPA_PUT_BE16(err->key_length, 0);
+ os_memcpy(err->replay_counter, sm->request_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
+
+ WPA_PUT_BE16(err->key_data_length, (u16) kde_len);
+ pos = (u8 *) (err + 1);
+
+ if (peer) {
+ /* Peer MAC Address KDE */
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
+ }
+
+ /* Error KDE */
+ error.mui = host_to_be16(mui);
+ error.error_type = host_to_be16(error_type);
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
+ (u8 *) &error, sizeof(error));
+
+ if (peer) {
+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer "
+ MACSTR " mui %d error_type %d)",
+ MAC2STR(peer), mui, error_type);
+ } else {
+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error "
+ "(mui %d error_type %d)", mui, error_type);
+ }
+
+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
+ rbuf, rlen, err->key_mic);
+
+ return 0;
+#else /* CONFIG_NO_WPA2 */
+ return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
+ const unsigned char *src_addr,
+ const struct wpa_eapol_key *key,
+ int ver, struct wpa_peerkey *peerkey)
+{
+ size_t rlen;
+ struct wpa_eapol_key *reply;
+ u8 *rbuf, *pos;
+ size_t kde_len;
+ u16 key_info;
+
+ /* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */
+ kde_len = peerkey->rsnie_p_len +
+ 2 + RSN_SELECTOR_LEN + ETH_ALEN +
+ 2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN;
+
+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
+ NULL, sizeof(*reply) + kde_len, &rlen,
+ (void *) &reply);
+ if (rbuf == NULL)
+ return -1;
+
+ reply->type = EAPOL_KEY_TYPE_RSN;
+ key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
+ WPA_KEY_INFO_SECURE;
+ WPA_PUT_BE16(reply->key_info, key_info);
+ WPA_PUT_BE16(reply->key_length, 0);
+ os_memcpy(reply->replay_counter, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+
+ os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN);
+
+ WPA_PUT_BE16(reply->key_data_length, (u16) kde_len);
+ pos = (u8 *) (reply + 1);
+
+ /* Peer RSN IE */
+ pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
+
+ /* Initiator MAC Address KDE */
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN);
+
+ /* Initiator Nonce */
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE,
+ peerkey->inonce, WPA_NONCE_LEN);
+
+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
+ rbuf, rlen, reply->key_mic);
+
+ return 0;
}
+static int wpa_supplicant_process_smk_m2(
+ struct wpa_sm *sm, const unsigned char *src_addr,
+ const struct wpa_eapol_key *key, size_t extra_len, int ver)
+{
+ struct wpa_ssid *ssid = sm->cur_ssid;
+ struct wpa_peerkey *peerkey;
+ struct wpa_eapol_ie_parse kde;
+ struct wpa_ie_data ie;
+ int cipher;
+ struct rsn_ie_hdr *hdr;
+ u8 *pos;
+
+ wpa_printf(MSG_DEBUG, "RSN: Received SMK M2");
+
+ if (ssid == NULL || !ssid->peerkey || sm->proto != WPA_PROTO_RSN) {
+ wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for "
+ "the current network");
+ return -1;
+ }
+
+ if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
+ 0) {
+ wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
+ return -1;
+ }
+
+ if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
+ kde.mac_addr_len < ETH_ALEN) {
+ wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
+ "SMK M2");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR,
+ MAC2STR(kde.mac_addr));
+
+ if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) {
+ wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK "
+ "M2");
+ return -1;
+ }
+
+ if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
+ wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2");
+ return -1;
+ }
+
+ cipher = ie.pairwise_cipher & ssid->pairwise_cipher;
+ if (cipher & WPA_CIPHER_CCMP) {
+ wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
+ cipher = WPA_CIPHER_CCMP;
+ } else if (cipher & WPA_CIPHER_TKIP) {
+ wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
+ cipher = WPA_CIPHER_TKIP;
+ } else {
+ wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
+ wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
+ STK_MUI_SMK, STK_ERR_CPHR_NS,
+ ver);
+ return -1;
+ }
+
+ /* TODO: find existing entry and if found, use that instead of adding
+ * a new one; how to handle the case where both ends initiate at the
+ * same time? */
+ peerkey = os_malloc(sizeof(*peerkey));
+ if (peerkey == NULL)
+ return -1;
+ os_memset(peerkey, 0, sizeof(*peerkey));
+ os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
+ os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
+ os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
+ peerkey->rsnie_i_len = kde.rsn_ie_len;
+ peerkey->cipher = cipher;
+
+ if (hostapd_get_rand(peerkey->pnonce, WPA_NONCE_LEN)) {
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
+ "WPA: Failed to get random data for PNonce");
+ wpa_supplicant_peerkey_free(sm, peerkey);
+ return -1;
+ }
+
+ hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p;
+ hdr->elem_id = RSN_INFO_ELEM;
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
+ pos = (u8 *) (hdr + 1);
+ /* Group Suite can be anything for SMK RSN IE; receiver will just
+ * ignore it. */
+ os_memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
+ pos += RSN_SELECTOR_LEN;
+ /* Include only the selected cipher in pairwise cipher suite */
+ WPA_PUT_LE16(pos, 1);
+ pos += 2;
+ if (cipher == WPA_CIPHER_CCMP)
+ os_memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
+ else if (cipher == WPA_CIPHER_TKIP)
+ os_memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
+ pos += RSN_SELECTOR_LEN;
+
+ hdr->len = (pos - peerkey->rsnie_p) - 2;
+ peerkey->rsnie_p_len = pos - peerkey->rsnie_p;
+ wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
+ peerkey->rsnie_p, peerkey->rsnie_p_len);
+
+ wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey);
+
+ peerkey->next = sm->peerkey;
+ sm->peerkey = peerkey;
+
+ return 0;
+}
+
+
+/**
+ * rsn_smkid - Derive SMK identifier
+ * @smk: Station master key (32 bytes)
+ * @pnonce: Peer Nonce
+ * @mac_p: Peer MAC address
+ * @inonce: Initiator Nonce
+ * @mac_i: Initiator MAC address
+ *
+ * 8.5.1.4 Station to station (STK) key hierarchy
+ * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
+ */
+static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
+ const u8 *inonce, const u8 *mac_i, u8 *smkid)
+{
+ char *title = "SMK Name";
+ const u8 *addr[5];
+ const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN,
+ ETH_ALEN };
+ unsigned char hash[SHA1_MAC_LEN];
+
+ addr[0] = (u8 *) title;
+ addr[1] = pnonce;
+ addr[2] = mac_p;
+ addr[3] = inonce;
+ addr[4] = mac_i;
+
+ hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash);
+ os_memcpy(smkid, hash, PMKID_LEN);
+}
+
+
+static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
+ struct wpa_peerkey *peerkey)
+{
+ size_t mlen;
+ struct wpa_eapol_key *msg;
+ u8 *mbuf;
+ size_t kde_len;
+ u16 key_info, ver;
+
+ kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
+
+ mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+ sizeof(*msg) + kde_len, &mlen,
+ (void *) &msg);
+ if (mbuf == NULL)
+ return;
+
+ msg->type = EAPOL_KEY_TYPE_RSN;
+
+ if (peerkey->cipher == WPA_CIPHER_CCMP)
+ ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+ else
+ ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+ key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
+ WPA_PUT_BE16(msg->key_info, key_info);
+
+ if (peerkey->cipher == WPA_CIPHER_CCMP)
+ WPA_PUT_BE16(msg->key_length, 16);
+ else
+ WPA_PUT_BE16(msg->key_length, 32);
+
+ os_memcpy(msg->replay_counter, peerkey->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
+
+ WPA_PUT_BE16(msg->key_data_length, kde_len);
+ wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
+ peerkey->smkid, PMKID_LEN);
+
+ if (hostapd_get_rand(peerkey->inonce, WPA_NONCE_LEN)) {
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
+ "RSN: Failed to get random data for INonce (STK)");
+ os_free(mbuf);
+ return;
+ }
+ wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake",
+ peerkey->inonce, WPA_NONCE_LEN);
+ os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
+
+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
+ MAC2STR(peerkey->addr));
+ wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
+ mbuf, mlen, NULL);
+}
+
+
+static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
+ struct wpa_peerkey *peerkey)
+{
+ size_t mlen;
+ struct wpa_eapol_key *msg;
+ u8 *mbuf, *pos;
+ size_t kde_len;
+ u16 key_info, ver;
+ u32 lifetime;
+
+ kde_len = peerkey->rsnie_i_len +
+ 2 + RSN_SELECTOR_LEN + sizeof(lifetime);
+
+ mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+ sizeof(*msg) + kde_len, &mlen,
+ (void *) &msg);
+ if (mbuf == NULL)
+ return;
+
+ msg->type = EAPOL_KEY_TYPE_RSN;
+
+ if (peerkey->cipher == WPA_CIPHER_CCMP)
+ ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+ else
+ ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+ key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK |
+ WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
+ WPA_PUT_BE16(msg->key_info, key_info);
+
+ if (peerkey->cipher == WPA_CIPHER_CCMP)
+ WPA_PUT_BE16(msg->key_length, 16);
+ else
+ WPA_PUT_BE16(msg->key_length, 32);
+
+ os_memcpy(msg->replay_counter, peerkey->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
+
+ WPA_PUT_BE16(msg->key_data_length, kde_len);
+ pos = (u8 *) (msg + 1);
+ pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
+ lifetime = host_to_be32(peerkey->lifetime);
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+ (u8 *) &lifetime, sizeof(lifetime));
+
+ os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
+
+ wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
+ MAC2STR(peerkey->addr));
+ wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
+ ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
+}
+
+
+static int wpa_supplicant_process_smk_m45(
+ struct wpa_sm *sm, const unsigned char *src_addr,
+ const struct wpa_eapol_key *key, size_t extra_len, int ver)
+{
+ struct wpa_ssid *ssid = sm->cur_ssid;
+ struct wpa_peerkey *peerkey;
+ struct wpa_eapol_ie_parse kde;
+ u32 lifetime;
+ struct os_time now;
+ struct wpa_ie_data ie;
+
+ if (ssid == NULL || !ssid->peerkey || sm->proto != WPA_PROTO_RSN) {
+ wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
+ "the current network");
+ return -1;
+ }
+
+ if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
+ 0) {
+ wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5");
+ return -1;
+ }
+
+ if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
+ kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN ||
+ kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN ||
+ kde.lifetime == NULL || kde.lifetime_len < 4) {
+ wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or "
+ "Lifetime KDE in SMK M4/M5");
+ return -1;
+ }
+
+ for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+ if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 &&
+ os_memcmp(peerkey->initiator ? peerkey->inonce :
+ peerkey->pnonce,
+ key->key_nonce, WPA_NONCE_LEN) == 0)
+ break;
+ }
+ if (peerkey == NULL) {
+ wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found "
+ "for SMK M4/M5: peer " MACSTR,
+ MAC2STR(kde.mac_addr));
+ return -1;
+ }
+
+ if (peerkey->initiator) {
+ int cipher;
+ wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")",
+ MAC2STR(kde.mac_addr));
+ if (kde.rsn_ie == NULL || kde.rsn_ie_len > PEERKEY_MAX_IE_LEN
+ || wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) <
+ 0) {
+ wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5");
+ /* TODO: abort negotiation */
+ return -1;
+ }
+
+ if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN)
+ != 0) {
+ wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does "
+ "not match with INonce used in SMK M1");
+ return -1;
+ }
+
+ if (os_memcmp(kde.smk + PMK_LEN, peerkey->inonce,
+ WPA_NONCE_LEN) != 0) {
+ wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not "
+ "match with the one used in SMK M1");
+ return -1;
+ }
+
+ os_memcpy(peerkey->rsnie_p, kde.rsn_ie, kde.rsn_ie_len);
+ peerkey->rsnie_p_len = kde.rsn_ie_len;
+ os_memcpy(peerkey->pnonce, kde.nonce, WPA_NONCE_LEN);
+
+ cipher = ie.pairwise_cipher & ssid->pairwise_cipher;
+ if (cipher & WPA_CIPHER_CCMP) {
+ wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
+ peerkey->cipher = WPA_CIPHER_CCMP;
+ } else if (cipher & WPA_CIPHER_TKIP) {
+ wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
+ peerkey->cipher = WPA_CIPHER_TKIP;
+ } else {
+ wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR
+ " selected unacceptable cipher",
+ MAC2STR(kde.mac_addr));
+ wpa_supplicant_send_smk_error(
+ sm, src_addr, kde.mac_addr,
+ STK_MUI_SMK, STK_ERR_CPHR_NS, ver);
+ /* TODO: abort negotiation */
+ return -1;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator "
+ MACSTR ")", MAC2STR(kde.mac_addr));
+
+ if (os_memcmp(kde.smk + PMK_LEN, peerkey->pnonce,
+ WPA_NONCE_LEN) != 0) {
+ wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not "
+ "match with the one used in SMK M3");
+ return -1;
+ }
+
+ if (os_memcmp(kde.nonce, peerkey->inonce, WPA_NONCE_LEN) != 0)
+ {
+ wpa_printf(MSG_INFO, "RSN: INonce in SMK M5 did not "
+ "match with the one received in SMK M2");
+ return -1;
+ }
+ }
+
+ os_memcpy(peerkey->smk, kde.smk, PMK_LEN);
+ peerkey->smk_complete = 1;
+ wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN);
+ lifetime = WPA_GET_BE32(kde.lifetime);
+ wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
+ if (lifetime > 1000000000)
+ lifetime = 1000000000; /* avoid overflowing expiration time */
+ peerkey->lifetime = lifetime;
+ os_get_time(&now);
+ peerkey->expiration = now.sec + lifetime;
+ eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
+ sm, peerkey);
+
+ if (peerkey->initiator) {
+ rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
+ peerkey->inonce, sm->own_addr, peerkey->smkid);
+ wpa_supplicant_send_stk_1_of_4(sm, peerkey);
+ } else {
+ rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
+ peerkey->inonce, peerkey->addr, peerkey->smkid);
+ }
+ wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
+
+ return 0;
+}
+
+
+static int wpa_supplicant_process_smk_error(
+ struct wpa_sm *sm, const unsigned char *src_addr,
+ const struct wpa_eapol_key *key, size_t extra_len)
+{
+ struct wpa_ssid *ssid = sm->cur_ssid;
+ struct wpa_eapol_ie_parse kde;
+ struct rsn_error_kde error;
+ u8 peer[ETH_ALEN];
+ u16 error_type;
+
+ wpa_printf(MSG_DEBUG, "RSN: Received SMK Error");
+
+ if (ssid == NULL || !ssid->peerkey || sm->proto != WPA_PROTO_RSN) {
+ wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
+ "the current network");
+ return -1;
+ }
+
+ if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
+ 0) {
+ wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
+ return -1;
+ }
+
+ if (kde.error == NULL || kde.error_len < sizeof(error)) {
+ wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error");
+ return -1;
+ }
+
+ if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN)
+ os_memcpy(peer, kde.mac_addr, ETH_ALEN);
+ os_memcpy(&error, kde.error, sizeof(error));
+ error_type = be_to_host16(error.error_type);
+ wpa_msg(sm->ctx->ctx, MSG_INFO,
+ "RSN: SMK Error KDE received: MUI %d error_type %d peer "
+ MACSTR,
+ be_to_host16(error.mui), error_type,
+ MAC2STR(peer));
+
+ if (kde.mac_addr &&
+ (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN ||
+ error_type == STK_ERR_CPHR_NS)) {
+ struct wpa_peerkey *peerkey;
+
+ for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+ if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) ==
+ 0)
+ break;
+ }
+ if (peerkey == NULL) {
+ wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake "
+ "found for SMK Error");
+ return -1;
+ }
+ /* TODO: abort SMK/STK handshake and remove all related keys */
+ }
+
+ return 0;
+}
+
+
+static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
+ struct wpa_peerkey *peerkey,
+ const struct wpa_eapol_key *key,
+ u16 ver)
+{
+ struct wpa_eapol_ie_parse ie;
+ const u8 *kde;
+ size_t len, kde_buf_len;
+ struct wpa_ptk *stk;
+ u8 buf[8], *kde_buf, *pos;
+ u32 lifetime;
+
+ wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from "
+ MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+ os_memset(&ie, 0, sizeof(ie));
+
+ /* RSN: msg 1/4 should contain SMKID for the selected SMK */
+ kde = (const u8 *) (key + 1);
+ len = WPA_GET_BE16(key->key_data_length);
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len);
+ if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) {
+ wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
+ return;
+ }
+ if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+ wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
+ ie.pmkid, PMKID_LEN);
+ return;
+ }
+
+ if (hostapd_get_rand(peerkey->pnonce, WPA_NONCE_LEN)) {
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
+ "RSN: Failed to get random data for PNonce");
+ return;
+ }
+ wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce",
+ peerkey->pnonce, WPA_NONCE_LEN);
+
+ /* Calculate STK which will be stored as a temporary STK until it has
+ * been verified when processing message 3/4. */
+ stk = &peerkey->tstk;
+ wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
+ sm->own_addr, peerkey->addr,
+ peerkey->pnonce, key->key_nonce,
+ (u8 *) stk, sizeof(*stk));
+ /* Supplicant: swap tx/rx Mic keys */
+ os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
+ os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
+ os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
+ peerkey->tstk_set = 1;
+
+ kde_buf_len = peerkey->rsnie_p_len +
+ 2 + RSN_SELECTOR_LEN + sizeof(lifetime) +
+ 2 + RSN_SELECTOR_LEN + PMKID_LEN;
+ kde_buf = os_malloc(kde_buf_len);
+ if (kde_buf == NULL)
+ return;
+ pos = kde_buf;
+ pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
+ lifetime = host_to_be32(peerkey->lifetime);
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+ (u8 *) &lifetime, sizeof(lifetime));
+ pos = wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN);
+
+ if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver,
+ peerkey->pnonce, kde_buf, kde_buf_len,
+ stk)) {
+ os_free(kde_buf);
+ return;
+ }
+ os_free(kde_buf);
+
+ os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
+}
+
+
+static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
+ struct wpa_peerkey *peerkey,
+ struct wpa_eapol_ie_parse *kde)
+{
+ u32 lifetime;
+ struct os_time now;
+
+ if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
+ return;
+
+ lifetime = WPA_GET_BE32(kde->lifetime);
+
+ if (lifetime >= peerkey->lifetime) {
+ wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds "
+ "which is larger than or equal to own value %u "
+ "seconds - ignored", lifetime, peerkey->lifetime);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds "
+ "(own was %u seconds) - updated",
+ lifetime, peerkey->lifetime);
+ peerkey->lifetime = lifetime;
+
+ os_get_time(&now);
+ peerkey->expiration = now.sec + lifetime;
+ eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
+ eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
+ sm, peerkey);
+}
+
+
+static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
+ struct wpa_peerkey *peerkey,
+ const struct wpa_eapol_key *key,
+ u16 ver)
+{
+ struct wpa_eapol_ie_parse kde;
+ const u8 *keydata;
+ size_t len;
+
+ wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
+ MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+ os_memset(&kde, 0, sizeof(kde));
+
+ /* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
+ * from the peer. It may also include Lifetime KDE. */
+ keydata = (const u8 *) (key + 1);
+ len = WPA_GET_BE16(key->key_data_length);
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len);
+ if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 ||
+ kde.pmkid == NULL || kde.rsn_ie == NULL) {
+ wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
+ return;
+ }
+
+ if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+ wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
+ kde.pmkid, PMKID_LEN);
+ return;
+ }
+
+ if (kde.rsn_ie_len != peerkey->rsnie_p_len ||
+ os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) {
+ wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK "
+ "handshakes did not match");
+ wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake",
+ peerkey->rsnie_p, peerkey->rsnie_p_len);
+ wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake",
+ kde.rsn_ie, kde.rsn_ie_len);
+ return;
+ }
+
+ wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
+
+ wpa_supplicant_send_stk_3_of_4(sm, peerkey);
+ os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN);
+}
+
+
+static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
+ struct wpa_peerkey *peerkey,
+ const struct wpa_eapol_key *key,
+ u16 ver)
+{
+ struct wpa_eapol_ie_parse kde;
+ const u8 *keydata;
+ size_t len, key_len;
+ const u8 *_key;
+ u8 key_buf[32], rsc[6];
+
+ wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from "
+ MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+ os_memset(&kde, 0, sizeof(kde));
+
+ /* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
+ * Lifetime KDE. */
+ keydata = (const u8 *) (key + 1);
+ len = WPA_GET_BE16(key->key_data_length);
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len);
+ if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) {
+ wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
+ "STK 3/4");
+ return;
+ }
+
+ if (kde.rsn_ie_len != peerkey->rsnie_i_len ||
+ os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) {
+ wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK "
+ "handshakes did not match");
+ wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK "
+ "handshake",
+ peerkey->rsnie_i, peerkey->rsnie_i_len);
+ wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK "
+ "handshake",
+ kde.rsn_ie, kde.rsn_ie_len);
+ return;
+ }
+
+ if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
+ wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK "
+ "4-Way Handshake differs from 3 of STK 4-Way "
+ "Handshake - drop packet (src=" MACSTR ")",
+ MAC2STR(peerkey->addr));
+ return;
+ }
+
+ wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
+
+ if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
+ WPA_GET_BE16(key->key_info),
+ NULL, 0, &peerkey->stk))
+ return;
+
+ _key = (u8 *) peerkey->stk.tk1;
+ if (peerkey->cipher == WPA_CIPHER_TKIP) {
+ /* Swap Tx/Rx keys for Michael MIC */
+ os_memcpy(key_buf, _key, 16);
+ os_memcpy(key_buf + 16, _key + 24, 8);
+ os_memcpy(key_buf + 24, _key + 16, 8);
+ _key = key_buf;
+ key_len = 32;
+ } else
+ key_len = 16;
+
+ os_memset(rsc, 0, 6);
+ if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
+ rsc, sizeof(rsc), _key, key_len) < 0) {
+ wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
+ "driver.");
+ return;
+ }
+}
+
+
+static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
+ struct wpa_peerkey *peerkey,
+ const struct wpa_eapol_key *key,
+ u16 ver)
+{
+ u8 rsc[6];
+
+ wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from "
+ MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+ os_memset(rsc, 0, 6);
+ if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
+ rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
+ peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
+ wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
+ "driver.");
+ return;
+ }
+}
+#endif /* CONFIG_PEERKEY */
+
+
static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
const u8 *keydata,
size_t keydatalen,
- int key_info,
+ u16 key_info,
struct wpa_gtk_data *gd)
{
int maxkeylen;
@@ -1623,7 +2997,10 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
"(len=%lu)", (unsigned long) ie.gtk_len - 2);
return -1;
}
- memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
+ os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
+
+ if (ieee80211w_set_keys(sm, &ie) < 0)
+ wpa_printf(MSG_INFO, "RSN: Failed to configure DHV/IGTK");
return 0;
}
@@ -1632,22 +3009,29 @@ static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
const struct wpa_eapol_key *key,
size_t keydatalen, int key_info,
- int extra_len, u16 ver,
+ size_t extra_len, u16 ver,
struct wpa_gtk_data *gd)
{
- int maxkeylen;
+ size_t maxkeylen;
u8 ek[32];
gd->gtk_len = WPA_GET_BE16(key->key_length);
maxkeylen = keydatalen;
if (keydatalen > extra_len) {
wpa_printf(MSG_INFO, "WPA: Truncated EAPOL-Key packet:"
- " key_data_length=%lu > extra_len=%d",
- (unsigned long) keydatalen, extra_len);
+ " key_data_length=%lu > extra_len=%lu",
+ (unsigned long) keydatalen,
+ (unsigned long) extra_len);
return -1;
}
- if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES)
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+ if (maxkeylen < 8) {
+ wpa_printf(MSG_INFO, "WPA: Too short maxkeylen (%lu)",
+ (unsigned long) maxkeylen);
+ return -1;
+ }
maxkeylen -= 8;
+ }
if (wpa_supplicant_check_group_cipher(sm->group_cipher,
gd->gtk_len, maxkeylen,
@@ -1657,15 +3041,15 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
WPA_KEY_INFO_KEY_INDEX_SHIFT;
if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
- memcpy(ek, key->key_iv, 16);
- memcpy(ek + 16, sm->ptk.kek, 16);
+ os_memcpy(ek, key->key_iv, 16);
+ os_memcpy(ek + 16, sm->ptk.kek, 16);
if (keydatalen > sizeof(gd->gtk)) {
wpa_printf(MSG_WARNING, "WPA: RC4 key data "
"too long (%lu)",
(unsigned long) keydatalen);
return -1;
}
- memcpy(gd->gtk, key + 1, keydatalen);
+ os_memcpy(gd->gtk, key + 1, keydatalen);
rc4_skip(ek, 32, 256, gd->gtk, keydatalen);
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
if (keydatalen % 8) {
@@ -1694,7 +3078,6 @@ static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
- const unsigned char *src_addr,
const struct wpa_eapol_key *key,
int ver, u16 key_info)
{
@@ -1715,14 +3098,14 @@ static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
if (sm->proto == WPA_PROTO_RSN)
WPA_PUT_BE16(reply->key_length, 0);
else
- memcpy(reply->key_length, key->key_length, 2);
- memcpy(reply->replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
+ os_memcpy(reply->key_length, key->key_length, 2);
+ os_memcpy(reply->replay_counter, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
WPA_PUT_BE16(reply->key_data_length, 0);
wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
- wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
rbuf, rlen, reply->key_mic);
return 0;
@@ -1735,13 +3118,12 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
int extra_len, u16 ver)
{
u16 key_info, keydatalen;
- int rekey;
+ int rekey, ret;
struct wpa_gtk_data gd;
- memset(&gd, 0, sizeof(gd));
+ os_memset(&gd, 0, sizeof(gd));
rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
- wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
wpa_printf(MSG_DEBUG, "WPA: RX message 1 of Group Key Handshake from "
MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
@@ -1749,29 +3131,32 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
keydatalen = WPA_GET_BE16(key->key_data_length);
if (sm->proto == WPA_PROTO_RSN) {
- if (wpa_supplicant_process_1_of_2_rsn(sm,
- (const u8 *) (key + 1),
- keydatalen, key_info,
- &gd))
- return;
+ ret = wpa_supplicant_process_1_of_2_rsn(sm,
+ (const u8 *) (key + 1),
+ keydatalen, key_info,
+ &gd);
} else {
- if (wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
- key_info, extra_len,
- ver, &gd))
- return;
+ ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
+ key_info, extra_len,
+ ver, &gd);
}
+ wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
+
+ if (ret)
+ return;
+
if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
- wpa_supplicant_send_2_of_2(sm, src_addr, key, ver, key_info))
+ wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
return;
if (rekey) {
wpa_msg(sm->ctx->ctx, MSG_INFO, "WPA: Group rekeying "
"completed with " MACSTR " [GTK=%s]",
- MAC2STR(src_addr), wpa_cipher_txt(sm->group_cipher));
+ MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
wpa_sm_set_state(sm, WPA_COMPLETED);
} else {
- wpa_supplicant_key_neg_complete(sm, src_addr,
+ wpa_supplicant_key_neg_complete(sm, sm->bssid,
key_info &
WPA_KEY_INFO_SECURE);
}
@@ -1786,27 +3171,27 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
u8 mic[16];
int ok = 0;
- memcpy(mic, key->key_mic, 16);
+ os_memcpy(mic, key->key_mic, 16);
if (sm->tptk_set) {
- memset(key->key_mic, 0, 16);
+ os_memset(key->key_mic, 0, 16);
wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
key->key_mic);
- if (memcmp(mic, key->key_mic, 16) != 0) {
+ if (os_memcmp(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
} else {
ok = 1;
sm->tptk_set = 0;
sm->ptk_set = 1;
- memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
+ os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
}
}
if (!ok && sm->ptk_set) {
- memset(key->key_mic, 0, 16);
+ os_memset(key->key_mic, 0, 16);
wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
key->key_mic);
- if (memcmp(mic, key->key_mic, 16) != 0) {
+ if (os_memcmp(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
"- dropping packet");
return -1;
@@ -1820,13 +3205,72 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
return -1;
}
- memcpy(sm->rx_replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
+ os_memcpy(sm->rx_replay_counter, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
sm->rx_replay_counter_set = 1;
return 0;
}
+#ifdef CONFIG_PEERKEY
+static int wpa_supplicant_verify_eapol_key_mic_peerkey(
+ struct wpa_sm *sm, struct wpa_peerkey *peerkey,
+ struct wpa_eapol_key *key, u16 ver, const u8 *buf, size_t len)
+{
+ u8 mic[16];
+ int ok = 0;
+
+ if (peerkey->initiator && !peerkey->stk_set) {
+ wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
+ sm->own_addr, peerkey->addr,
+ peerkey->inonce, key->key_nonce,
+ (u8 *) &peerkey->stk, sizeof(peerkey->stk));
+ peerkey->stk_set = 1;
+ }
+
+ os_memcpy(mic, key->key_mic, 16);
+ if (peerkey->tstk_set) {
+ os_memset(key->key_mic, 0, 16);
+ wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
+ key->key_mic);
+ if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
+ "when using TSTK - ignoring TSTK");
+ } else {
+ ok = 1;
+ peerkey->tstk_set = 0;
+ peerkey->stk_set = 1;
+ os_memcpy(&peerkey->stk, &peerkey->tstk,
+ sizeof(peerkey->stk));
+ }
+ }
+
+ if (!ok && peerkey->stk_set) {
+ os_memset(key->key_mic, 0, 16);
+ wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
+ key->key_mic);
+ if (os_memcmp(mic, key->key_mic, 16) != 0) {
+ wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
+ "- dropping packet");
+ return -1;
+ }
+ ok = 1;
+ }
+
+ if (!ok) {
+ wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC "
+ "- dropping packet");
+ return -1;
+ }
+
+ os_memcpy(peerkey->replay_counter, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ peerkey->replay_counter_set = 1;
+ return 0;
+}
+#endif /* CONFIG_PEERKEY */
+
+
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
struct wpa_eapol_key *key, u16 ver)
@@ -1845,8 +3289,8 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
* to be implemented separately for each message type. */
if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
u8 ek[32];
- memcpy(ek, key->key_iv, 16);
- memcpy(ek + 16, sm->ptk.kek, 16);
+ os_memcpy(ek, key->key_iv, 16);
+ os_memcpy(ek + 16, sm->ptk.kek, 16);
rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen);
} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
u8 *buf;
@@ -1856,7 +3300,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
return -1;
}
keydatalen -= 8; /* AES-WRAP adds 8 bytes */
- buf = malloc(keydatalen);
+ buf = os_malloc(keydatalen);
if (buf == NULL) {
wpa_printf(MSG_WARNING, "WPA: No memory for "
"AES-UNWRAP buffer");
@@ -1864,13 +3308,13 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
}
if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
(u8 *) (key + 1), buf)) {
- free(buf);
+ os_free(buf);
wpa_printf(MSG_WARNING, "WPA: AES unwrap failed - "
"could not decrypt EAPOL-Key key data");
return -1;
}
- memcpy(key + 1, buf, keydatalen);
- free(buf);
+ os_memcpy(key + 1, buf, keydatalen);
+ os_free(buf);
WPA_PUT_BE16(key->key_data_length, keydatalen);
}
wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
@@ -1880,6 +3324,53 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
/**
+ * wpa_sm_aborted_cached - Notify WPA that PMKSA caching was aborted
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void wpa_sm_aborted_cached(struct wpa_sm *sm)
+{
+ if (sm && sm->cur_pmksa) {
+ wpa_printf(MSG_DEBUG, "RSN: Cancelling PMKSA caching attempt");
+ sm->cur_pmksa = NULL;
+ }
+}
+
+
+static void wpa_eapol_key_dump(const struct wpa_eapol_key *key)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ u16 key_info = WPA_GET_BE16(key->key_info);
+
+ wpa_printf(MSG_DEBUG, " EAPOL-Key type=%d", key->type);
+ wpa_printf(MSG_DEBUG, " key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s"
+ "%s%s%s%s%s%s%s)",
+ key_info, key_info & WPA_KEY_INFO_TYPE_MASK,
+ (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+ WPA_KEY_INFO_KEY_INDEX_SHIFT,
+ (key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13,
+ key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group",
+ key_info & WPA_KEY_INFO_INSTALL ? " Install" : "",
+ key_info & WPA_KEY_INFO_ACK ? " Ack" : "",
+ key_info & WPA_KEY_INFO_MIC ? " MIC" : "",
+ key_info & WPA_KEY_INFO_SECURE ? " Secure" : "",
+ key_info & WPA_KEY_INFO_ERROR ? " Error" : "",
+ key_info & WPA_KEY_INFO_REQUEST ? " Request" : "",
+ key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
+ wpa_printf(MSG_DEBUG, " key_length=%u key_data_length=%u",
+ WPA_GET_BE16(key->key_length),
+ WPA_GET_BE16(key->key_data_length));
+ wpa_hexdump(MSG_DEBUG, " replay_counter",
+ key->replay_counter, WPA_REPLAY_COUNTER_LEN);
+ wpa_hexdump(MSG_DEBUG, " key_nonce", key->key_nonce, WPA_NONCE_LEN);
+ wpa_hexdump(MSG_DEBUG, " key_iv", key->key_iv, 16);
+ wpa_hexdump(MSG_DEBUG, " key_rsc", key->key_rsc, 8);
+ wpa_hexdump(MSG_DEBUG, " key_id (reserved)", key->key_id, 8);
+ wpa_hexdump(MSG_DEBUG, " key_mic", key->key_mic, 16);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+/**
* wpa_sm_rx_eapol - Process received WPA EAPOL frames
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @src_addr: Source MAC address of the EAPOL packet
@@ -1904,6 +3395,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
u16 key_info, ver;
u8 *tmp;
int ret = -1;
+ struct wpa_peerkey *peerkey = NULL;
if (len < sizeof(*hdr) + sizeof(*key)) {
wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short to be a WPA "
@@ -1913,14 +3405,14 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
return 0;
}
- tmp = malloc(len);
+ tmp = os_malloc(len);
if (tmp == NULL)
return -1;
- memcpy(tmp, buf, len);
+ os_memcpy(tmp, buf, len);
hdr = (struct ieee802_1x_hdr *) tmp;
key = (struct wpa_eapol_key *) (hdr + 1);
- plen = ntohs(hdr->length);
+ plen = be_to_host16(hdr->length);
data_len = plen + sizeof(*hdr);
wpa_printf(MSG_DEBUG, "IEEE 802.1X RX: version=%d type=%d length=%lu",
hdr->version, hdr->type, (unsigned long) plen);
@@ -1931,12 +3423,6 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
wpa_printf(MSG_DEBUG, "WPA: EAPOL frame (type %u) discarded, "
"not a Key frame", hdr->type);
- if (sm->cur_pmksa) {
- wpa_printf(MSG_DEBUG, "WPA: Cancelling PMKSA caching "
- "attempt - attempt full EAP "
- "authentication");
- eapol_sm_notify_pmkid_attempt(sm->eapol, 0);
- }
ret = 0;
goto out;
}
@@ -1948,7 +3434,6 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
goto out;
}
- wpa_printf(MSG_DEBUG, " EAPOL-Key type=%d", key->type);
if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
{
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key type (%d) unknown, "
@@ -1956,6 +3441,7 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 0;
goto out;
}
+ wpa_eapol_key_dump(key);
eapol_sm_notify_lower_layer_success(sm->eapol);
wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
@@ -1989,15 +3475,54 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
goto out;
}
- if (sm->rx_replay_counter_set &&
- memcmp(key->replay_counter, sm->rx_replay_counter,
- WPA_REPLAY_COUNTER_LEN) <= 0) {
+#ifdef CONFIG_PEERKEY
+ for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+ if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
+ break;
+ }
+
+ if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) {
+ if (!peerkey->initiator && peerkey->replay_counter_set &&
+ os_memcmp(key->replay_counter, peerkey->replay_counter,
+ WPA_REPLAY_COUNTER_LEN) <= 0) {
+ wpa_printf(MSG_WARNING, "RSN: EAPOL-Key Replay "
+ "Counter did not increase (STK) - dropping "
+ "packet");
+ goto out;
+ } else if (peerkey->initiator) {
+ u8 _tmp[WPA_REPLAY_COUNTER_LEN];
+ os_memcpy(_tmp, key->replay_counter,
+ WPA_REPLAY_COUNTER_LEN);
+ inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
+ if (os_memcmp(_tmp, peerkey->replay_counter,
+ WPA_REPLAY_COUNTER_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "RSN: EAPOL-Key Replay "
+ "Counter did not match (STK) - "
+ "dropping packet");
+ goto out;
+ }
+ }
+ }
+
+ if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
+ wpa_printf(MSG_INFO, "RSN: Ack bit in key_info from STK peer");
+ goto out;
+ }
+#endif /* CONFIG_PEERKEY */
+
+ if (!peerkey && sm->rx_replay_counter_set &&
+ os_memcmp(key->replay_counter, sm->rx_replay_counter,
+ WPA_REPLAY_COUNTER_LEN) <= 0) {
wpa_printf(MSG_WARNING, "WPA: EAPOL-Key Replay Counter did not"
" increase - dropping packet");
goto out;
}
- if (!(key_info & WPA_KEY_INFO_ACK)) {
+ if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))
+#ifdef CONFIG_PEERKEY
+ && (peerkey == NULL || !peerkey->initiator)
+#endif /* CONFIG_PEERKEY */
+ ) {
wpa_printf(MSG_INFO, "WPA: No Ack bit in key_info");
goto out;
}
@@ -2008,10 +3533,17 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
goto out;
}
- if ((key_info & WPA_KEY_INFO_MIC) &&
+ if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
goto out;
+#ifdef CONFIG_PEERKEY
+ if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
+ wpa_supplicant_verify_eapol_key_mic_peerkey(
+ sm, peerkey, key, ver, tmp, data_len))
+ goto out;
+#endif /* CONFIG_PEERKEY */
+
extra_len = data_len - sizeof(*hdr) - sizeof(*key);
if (WPA_GET_BE16(key->key_data_length) > extra_len) {
@@ -2021,11 +3553,14 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
(unsigned long) extra_len);
goto out;
}
+ extra_len = WPA_GET_BE16(key->key_data_length);
if (sm->proto == WPA_PROTO_RSN &&
- (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) &&
- wpa_supplicant_decrypt_key_data(sm, key, ver))
- goto out;
+ (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+ if (wpa_supplicant_decrypt_key_data(sm, key, ver))
+ goto out;
+ extra_len = WPA_GET_BE16(key->key_data_length);
+ }
if (key_info & WPA_KEY_INFO_KEY_TYPE) {
if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
@@ -2033,15 +3568,52 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
"(Pairwise) with non-zero key index");
goto out;
}
+#ifdef CONFIG_PEERKEY
+ if (peerkey) {
+ if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK))
+ == (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
+ /* 3/4 STK 4-Way Handshake */
+ wpa_supplicant_process_stk_3_of_4(sm, peerkey,
+ key, ver);
+ } else if (key_info & WPA_KEY_INFO_ACK) {
+ /* 1/4 STK 4-Way Handshake */
+ wpa_supplicant_process_stk_1_of_4(sm, peerkey,
+ key, ver);
+ } else if (key_info & WPA_KEY_INFO_SECURE) {
+ /* 4/4 STK 4-Way Handshake */
+ wpa_supplicant_process_stk_4_of_4(sm, peerkey,
+ key, ver);
+ } else {
+ /* 2/4 STK 4-Way Handshake */
+ wpa_supplicant_process_stk_2_of_4(sm, peerkey,
+ key, ver);
+ }
+ } else
+#endif /* CONFIG_PEERKEY */
if (key_info & WPA_KEY_INFO_MIC) {
/* 3/4 4-Way Handshake */
- wpa_supplicant_process_3_of_4(sm, src_addr, key,
- extra_len, ver);
+ wpa_supplicant_process_3_of_4(sm, key, ver);
} else {
/* 1/4 4-Way Handshake */
wpa_supplicant_process_1_of_4(sm, src_addr, key,
ver);
}
+ } else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+#ifdef CONFIG_PEERKEY
+ if (key_info & WPA_KEY_INFO_ERROR) {
+ /* SMK Error */
+ wpa_supplicant_process_smk_error(sm, src_addr, key,
+ extra_len);
+ } else if (key_info & WPA_KEY_INFO_ACK) {
+ /* SMK M2 */
+ wpa_supplicant_process_smk_m2(sm, src_addr, key,
+ extra_len, ver);
+ } else {
+ /* SMK M4 or M5 */
+ wpa_supplicant_process_smk_m45(sm, src_addr, key,
+ extra_len, ver);
+ }
+#endif /* CONFIG_PEERKEY */
} else {
if (key_info & WPA_KEY_INFO_MIC) {
/* 1/2 Group Key Handshake */
@@ -2056,11 +3628,12 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
ret = 1;
out:
- free(tmp);
+ os_free(tmp);
return ret;
}
+#ifdef CONFIG_CTRL_IFACE
static int wpa_cipher_bits(int cipher)
{
switch (cipher) {
@@ -2137,15 +3710,13 @@ static const u8 * wpa_cipher_suite(struct wpa_sm *sm, int cipher)
*/
int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
{
- int len, i;
char pmkid_txt[PMKID_LEN * 2 + 1];
- int rsna;
+ int rsna, ret;
+ size_t len;
if (sm->cur_pmksa) {
- char *pos = pmkid_txt;
- for (i = 0; i < PMKID_LEN; i++) {
- pos += sprintf(pos, "%02x", sm->cur_pmksa->pmkid[i]);
- }
+ wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
+ sm->cur_pmksa->pmkid, PMKID_LEN);
} else
pmkid_txt[0] = '\0';
@@ -2156,51 +3727,85 @@ int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
else
rsna = 0;
- len = snprintf(buf, buflen,
- "dot11RSNAOptionImplemented=TRUE\n"
- "dot11RSNAPreauthenticationImplemented=TRUE\n"
- "dot11RSNAEnabled=%s\n"
- "dot11RSNAPreauthenticationEnabled=%s\n"
- "dot11RSNAConfigVersion=%d\n"
- "dot11RSNAConfigPairwiseKeysSupported=5\n"
- "dot11RSNAConfigGroupCipherSize=%d\n"
- "dot11RSNAConfigPMKLifetime=%d\n"
- "dot11RSNAConfigPMKReauthThreshold=%d\n"
- "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n"
- "dot11RSNAConfigSATimeout=%d\n"
- "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
- "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
- "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
- "dot11RSNAPMKIDUsed=%s\n"
- "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
- "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
- "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
- "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n"
- "dot11RSNA4WayHandshakeFailures=%u\n",
- rsna ? "TRUE" : "FALSE",
- rsna ? "TRUE" : "FALSE",
- RSN_VERSION,
- wpa_cipher_bits(sm->group_cipher),
- sm->dot11RSNAConfigPMKLifetime,
- sm->dot11RSNAConfigPMKReauthThreshold,
- sm->dot11RSNAConfigSATimeout,
- RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm,
- sm->pairwise_cipher)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
- pmkid_txt,
- RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm,
- sm->pairwise_cipher)),
- RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
- sm->dot11RSNA4WayHandshakeFailures);
- return len;
+ ret = os_snprintf(buf, buflen,
+ "dot11RSNAOptionImplemented=TRUE\n"
+ "dot11RSNAPreauthenticationImplemented=TRUE\n"
+ "dot11RSNAEnabled=%s\n"
+ "dot11RSNAPreauthenticationEnabled=%s\n"
+ "dot11RSNAConfigVersion=%d\n"
+ "dot11RSNAConfigPairwiseKeysSupported=5\n"
+ "dot11RSNAConfigGroupCipherSize=%d\n"
+ "dot11RSNAConfigPMKLifetime=%d\n"
+ "dot11RSNAConfigPMKReauthThreshold=%d\n"
+ "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n"
+ "dot11RSNAConfigSATimeout=%d\n",
+ rsna ? "TRUE" : "FALSE",
+ rsna ? "TRUE" : "FALSE",
+ RSN_VERSION,
+ wpa_cipher_bits(sm->group_cipher),
+ sm->dot11RSNAConfigPMKLifetime,
+ sm->dot11RSNAConfigPMKReauthThreshold,
+ sm->dot11RSNAConfigSATimeout);
+ if (ret < 0 || (size_t) ret >= buflen)
+ return 0;
+ len = ret;
+
+ ret = os_snprintf(
+ buf + len, buflen - len,
+ "dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
+ "dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
+ "dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
+ "dot11RSNAPMKIDUsed=%s\n"
+ "dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
+ "dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
+ "dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
+ "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n"
+ "dot11RSNA4WayHandshakeFailures=%u\n",
+ RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
+ RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
+ pmkid_txt,
+ RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
+ RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->pairwise_cipher)),
+ RSN_SUITE_ARG(wpa_cipher_suite(sm, sm->group_cipher)),
+ sm->dot11RSNA4WayHandshakeFailures);
+ if (ret >= 0 && (size_t) ret < buflen)
+ len += ret;
+
+ return (int) len;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
+ void *ctx, int replace)
+{
+ struct wpa_sm *sm = ctx;
+
+ if (sm->cur_pmksa == entry ||
+ (sm->pmk_len == entry->pmk_len &&
+ os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
+ wpa_printf(MSG_DEBUG, "RSN: removed current PMKSA entry");
+ sm->cur_pmksa = NULL;
+
+ if (replace) {
+ /* A new entry is being added, so no need to
+ * deauthenticate in this case. This happens when EAP
+ * authentication is completed again (reauth or failed
+ * PMKSA caching attempt). */
+ return;
+ }
+
+ os_memset(sm->pmk, 0, sizeof(sm->pmk));
+ wpa_sm_deauthenticate(sm, REASON_UNSPECIFIED);
+ wpa_sm_req_scan(sm, 0, 0);
+ }
}
/**
* wpa_sm_init - Initialize WPA state machine
- * @ctx: Context pointer for callbacks
+ * @ctx: Context pointer for callbacks; this needs to be an allocated buffer
* Returns: Pointer to the allocated WPA state machine data
*
* This function is used to allocate a new WPA state machine and the returned
@@ -2210,10 +3815,9 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
{
struct wpa_sm *sm;
- sm = malloc(sizeof(*sm));
+ sm = os_zalloc(sizeof(*sm));
if (sm == NULL)
return NULL;
- memset(sm, 0, sizeof(*sm));
sm->renew_snonce = 1;
sm->ctx = ctx;
@@ -2221,6 +3825,14 @@ struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
sm->dot11RSNAConfigPMKReauthThreshold = 70;
sm->dot11RSNAConfigSATimeout = 60;
+ sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
+ if (sm->pmksa == NULL) {
+ wpa_printf(MSG_ERROR, "RSN: PMKSA cache initialization "
+ "failed");
+ os_free(sm);
+ return NULL;
+ }
+
return sm;
}
@@ -2233,12 +3845,23 @@ void wpa_sm_deinit(struct wpa_sm *sm)
{
if (sm == NULL)
return;
- eloop_cancel_timeout(wpa_sm_start_preauth, sm, 0);
- free(sm->assoc_wpa_ie);
- free(sm->ap_wpa_ie);
- free(sm->ap_rsn_ie);
- free(sm->ctx);
- free(sm);
+ pmksa_cache_deinit(sm->pmksa);
+ eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
+ os_free(sm->assoc_wpa_ie);
+ os_free(sm->ap_wpa_ie);
+ os_free(sm->ap_rsn_ie);
+ os_free(sm->ctx);
+#ifdef CONFIG_PEERKEY
+ {
+ struct wpa_peerkey *prev, *peerkey = sm->peerkey;
+ while (peerkey) {
+ prev = peerkey;
+ peerkey = peerkey->next;
+ os_free(prev);
+ }
+ }
+#endif /* CONFIG_PEERKEY */
+ os_free(sm);
}
@@ -2256,11 +3879,11 @@ void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
return;
wpa_printf(MSG_DEBUG, "WPA: Association event - clear replay counter");
- memcpy(sm->bssid, bssid, ETH_ALEN);
- memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
+ os_memcpy(sm->bssid, bssid, ETH_ALEN);
+ os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
sm->rx_replay_counter_set = 0;
sm->renew_snonce = 1;
- if (memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0)
+ if (os_memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0)
rsn_preauth_deinit(sm);
}
@@ -2294,7 +3917,7 @@ void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
return;
sm->pmk_len = pmk_len;
- memcpy(sm->pmk, pmk, pmk_len);
+ os_memcpy(sm->pmk, pmk, pmk_len);
}
@@ -2312,10 +3935,10 @@ void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
if (sm->cur_pmksa) {
sm->pmk_len = sm->cur_pmksa->pmk_len;
- memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
+ os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
} else {
sm->pmk_len = PMK_LEN;
- memset(sm->pmk, 0, PMK_LEN);
+ os_memset(sm->pmk, 0, PMK_LEN);
}
}
@@ -2358,8 +3981,10 @@ void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
*/
void wpa_sm_set_config(struct wpa_sm *sm, struct wpa_ssid *config)
{
- if (sm)
+ if (sm) {
sm->cur_ssid = config;
+ pmksa_cache_notify_reconfig(sm->pmksa);
+ }
}
@@ -2371,7 +3996,7 @@ void wpa_sm_set_config(struct wpa_sm *sm, struct wpa_ssid *config)
void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
{
if (sm)
- memcpy(sm->own_addr, addr, ETH_ALEN);
+ os_memcpy(sm->own_addr, addr, ETH_ALEN);
}
@@ -2379,11 +4004,15 @@ void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
* wpa_sm_set_ifname - Set network interface name
* @sm: Pointer to WPA state machine data from wpa_sm_init()
* @ifname: Interface name
+ * @bridge_ifname: Optional bridge interface name (for pre-auth)
*/
-void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname)
+void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
+ const char *bridge_ifname)
{
- if (sm)
+ if (sm) {
sm->ifname = ifname;
+ sm->bridge_ifname = bridge_ifname;
+ }
}
@@ -2445,6 +4074,13 @@ int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
case WPA_PARAM_KEY_MGMT:
sm->key_mgmt = value;
break;
+#ifdef CONFIG_IEEE80211W
+ case WPA_PARAM_MGMT_GROUP:
+ sm->mgmt_group_cipher = value;
+ break;
+#endif /* CONFIG_IEEE80211W */
+ default:
+ break;
}
return ret;
@@ -2477,6 +4113,10 @@ unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param)
return sm->group_cipher;
case WPA_PARAM_KEY_MGMT:
return sm->key_mgmt;
+#ifdef CONFIG_IEEE80211W
+ case WPA_PARAM_MGMT_GROUP:
+ return sm->mgmt_group_cipher;
+#endif /* CONFIG_IEEE80211W */
default:
return 0;
}
@@ -2499,14 +4139,18 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int verbose)
{
char *pos = buf, *end = buf + buflen;
-
- pos += snprintf(pos, end - pos,
- "pairwise_cipher=%s\n"
- "group_cipher=%s\n"
- "key_mgmt=%s\n",
- wpa_cipher_txt(sm->pairwise_cipher),
- wpa_cipher_txt(sm->group_cipher),
- wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
+ int ret;
+
+ ret = os_snprintf(pos, end - pos,
+ "pairwise_cipher=%s\n"
+ "group_cipher=%s\n"
+ "key_mgmt=%s\n",
+ wpa_cipher_txt(sm->pairwise_cipher),
+ wpa_cipher_txt(sm->group_cipher),
+ wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
+ if (ret < 0 || ret >= end - pos)
+ return pos - buf;
+ pos += ret;
return pos - buf;
}
@@ -2525,12 +4169,15 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
size_t *wpa_ie_len)
{
+ int res;
+
if (sm == NULL)
return -1;
- *wpa_ie_len = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
- if (*wpa_ie_len < 0)
+ res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
+ if (res < 0)
return -1;
+ *wpa_ie_len = res;
wpa_hexdump(MSG_DEBUG, "WPA: Set own WPA IE default",
wpa_ie, *wpa_ie_len);
@@ -2541,11 +4188,11 @@ int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
* the correct version of the IE even if PMKSA caching is
* aborted (which would remove PMKID from IE generation).
*/
- sm->assoc_wpa_ie = malloc(*wpa_ie_len);
+ sm->assoc_wpa_ie = os_malloc(*wpa_ie_len);
if (sm->assoc_wpa_ie == NULL)
return -1;
- memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
+ os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
sm->assoc_wpa_ie_len = *wpa_ie_len;
}
@@ -2569,18 +4216,18 @@ int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
if (sm == NULL)
return -1;
- free(sm->assoc_wpa_ie);
+ os_free(sm->assoc_wpa_ie);
if (ie == NULL || len == 0) {
wpa_printf(MSG_DEBUG, "WPA: clearing own WPA/RSN IE");
sm->assoc_wpa_ie = NULL;
sm->assoc_wpa_ie_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len);
- sm->assoc_wpa_ie = malloc(len);
+ sm->assoc_wpa_ie = os_malloc(len);
if (sm->assoc_wpa_ie == NULL)
return -1;
- memcpy(sm->assoc_wpa_ie, ie, len);
+ os_memcpy(sm->assoc_wpa_ie, ie, len);
sm->assoc_wpa_ie_len = len;
}
@@ -2603,18 +4250,18 @@ int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
if (sm == NULL)
return -1;
- free(sm->ap_wpa_ie);
+ os_free(sm->ap_wpa_ie);
if (ie == NULL || len == 0) {
wpa_printf(MSG_DEBUG, "WPA: clearing AP WPA IE");
sm->ap_wpa_ie = NULL;
sm->ap_wpa_ie_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len);
- sm->ap_wpa_ie = malloc(len);
+ sm->ap_wpa_ie = os_malloc(len);
if (sm->ap_wpa_ie == NULL)
return -1;
- memcpy(sm->ap_wpa_ie, ie, len);
+ os_memcpy(sm->ap_wpa_ie, ie, len);
sm->ap_wpa_ie_len = len;
}
@@ -2637,18 +4284,18 @@ int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
if (sm == NULL)
return -1;
- free(sm->ap_rsn_ie);
+ os_free(sm->ap_rsn_ie);
if (ie == NULL || len == 0) {
wpa_printf(MSG_DEBUG, "WPA: clearing AP RSN IE");
sm->ap_rsn_ie = NULL;
sm->ap_rsn_ie_len = 0;
} else {
wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len);
- sm->ap_rsn_ie = malloc(len);
+ sm->ap_rsn_ie = os_malloc(len);
if (sm->ap_rsn_ie == NULL)
return -1;
- memcpy(sm->ap_rsn_ie, ie, len);
+ os_memcpy(sm->ap_rsn_ie, ie, len);
sm->ap_rsn_ie_len = len;
}
diff --git a/contrib/wpa_supplicant/wpa.h b/contrib/wpa_supplicant/wpa.h
index 6b59d43c019a..df075c35d101 100644
--- a/contrib/wpa_supplicant/wpa.h
+++ b/contrib/wpa_supplicant/wpa.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - WPA definitions
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -16,30 +16,15 @@
#define WPA_H
#include "defs.h"
+#include "wpa_common.h"
+#ifndef BIT
#define BIT(n) (1 << (n))
-
-struct ieee802_1x_hdr {
- u8 version;
- u8 type;
- u16 length;
- /* followed by length octets of data */
-} __attribute__ ((packed));
-
-#define EAPOL_VERSION 2
-
-enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
- IEEE802_1X_TYPE_EAPOL_START = 1,
- IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
- IEEE802_1X_TYPE_EAPOL_KEY = 3,
- IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
-};
-
-enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
- EAPOL_KEY_TYPE_WPA = 254 };
-
+#endif
#define WPA_CAPABILITY_PREAUTH BIT(0)
+#define WPA_CAPABILITY_MGMT_FRAME_PROTECTION BIT(6)
+#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
#define GENERIC_INFO_ELEM 0xdd
#define RSN_INFO_ELEM 0x30
@@ -95,6 +80,8 @@ struct wpa_sm_ctx {
void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
const struct wpa_config_blob * (*get_config_blob)(void *ctx,
const char *name);
+ int (*mlme_setprotection)(void *ctx, const u8 *addr,
+ int protection_type, int key_type);
};
@@ -105,7 +92,8 @@ enum wpa_sm_conf_params {
WPA_PARAM_PROTO,
WPA_PARAM_PAIRWISE,
WPA_PARAM_GROUP,
- WPA_PARAM_KEY_MGMT
+ WPA_PARAM_KEY_MGMT,
+ WPA_PARAM_MGMT_GROUP
};
struct wpa_ie_data {
@@ -116,6 +104,7 @@ struct wpa_ie_data {
int capabilities;
int num_pmkid;
const u8 *pmkid;
+ int mgmt_group_cipher;
};
#ifndef CONFIG_NO_WPA
@@ -130,7 +119,8 @@ void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
void wpa_sm_set_config(struct wpa_sm *sm, struct wpa_ssid *config);
void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr);
-void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname);
+void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
+ const char *bridge_ifname);
void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol);
int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
@@ -149,9 +139,12 @@ int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
+int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
+
int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ie_data *data);
+void wpa_sm_aborted_cached(struct wpa_sm *sm);
int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len);
int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
@@ -201,7 +194,8 @@ static inline void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
{
}
-static inline void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname)
+static inline void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
+ const char *bridge_ifname)
{
}
@@ -263,12 +257,21 @@ static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
{
}
+static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
+{
+ return -1;
+}
+
static inline int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
struct wpa_ie_data *data)
{
return -1;
}
+static inline void wpa_sm_aborted_cached(struct wpa_sm *sm)
+{
+}
+
static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
const u8 *buf, size_t len)
{
diff --git a/contrib/wpa_supplicant/wpa_cli.c b/contrib/wpa_supplicant/wpa_cli.c
index c274723f51ea..a641249bb886 100644
--- a/contrib/wpa_supplicant/wpa_cli.c
+++ b/contrib/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,29 +12,26 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <signal.h>
-#include <unistd.h>
+#include "includes.h"
+
+#ifdef CONFIG_CTRL_IFACE
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
#include <dirent.h>
-#include <errno.h>
-#include <sys/time.h>
+#endif /* CONFIG_CTRL_IFACE_UNIX */
#ifdef CONFIG_READLINE
#include <readline/readline.h>
#include <readline/history.h>
#endif /* CONFIG_READLINE */
#include "wpa_ctrl.h"
-#ifdef CONFIG_NATIVE_WINDOWS
#include "common.h"
-#endif /* CONFIG_NATIVE_WINDOWS */
#include "version.h"
static const char *wpa_cli_version =
"wpa_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
+"Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi> and contributors";
static const char *wpa_cli_license =
@@ -56,7 +53,7 @@ static const char *wpa_cli_full_license =
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
+"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
"\n"
"Alternatively, this software may be distributed under the terms of the\n"
"BSD license.\n"
@@ -129,12 +126,16 @@ static const char *commands_help =
" scan_results = get latest scan results\n"
" get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = "
"get capabilies\n"
+" ap_scan <value> = set ap_scan parameter\n"
+" stkstart <addr> = request STK negotiation with <addr>\n"
" terminate = terminate wpa_supplicant\n"
" quit = exit wpa_cli\n";
static struct wpa_ctrl *ctrl_conn;
static int wpa_cli_quit = 0;
static int wpa_cli_attached = 0;
+static int wpa_cli_connected = 0;
+static int wpa_cli_last_id = 0;
static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
static char *ctrl_ifname = NULL;
static const char *pid_file = NULL;
@@ -161,26 +162,26 @@ static void usage(void)
static struct wpa_ctrl * wpa_cli_open_connection(const char *ifname)
{
-#ifdef CONFIG_CTRL_IFACE_UDP
- ctrl_conn = wpa_ctrl_open("");
+#if defined(CONFIG_CTRL_IFACE_UDP) || defined(CONFIG_CTRL_IFACE_NAMED_PIPE)
+ ctrl_conn = wpa_ctrl_open(ifname);
return ctrl_conn;
-#else /* CONFIG_CTRL_IFACE_UDP */
+#else /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
char *cfile;
int flen;
if (ifname == NULL)
return NULL;
- flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
- cfile = malloc(flen);
+ flen = os_strlen(ctrl_iface_dir) + os_strlen(ifname) + 2;
+ cfile = os_malloc(flen);
if (cfile == NULL)
return NULL;
- snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
+ os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
ctrl_conn = wpa_ctrl_open(cfile);
- free(cfile);
+ os_free(cfile);
return ctrl_conn;
-#endif /* CONFIG_CTRL_IFACE_UDP */
+#endif /* CONFIG_CTRL_IFACE_UDP || CONFIG_CTRL_IFACE_NAMED_PIPE */
}
@@ -215,7 +216,7 @@ static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
return -1;
}
len = sizeof(buf) - 1;
- ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+ ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
wpa_cli_msg_cb);
if (ret == -2) {
printf("'%s' command timed out.\n", cmd);
@@ -240,7 +241,7 @@ static int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
- int verbose = argc > 0 && strcmp(argv[0], "verbose") == 0;
+ int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
}
@@ -307,6 +308,7 @@ static void wpa_cli_show_variables(void)
static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
+ int res;
if (argc == 0) {
wpa_cli_show_variables();
@@ -319,8 +321,8 @@ static int wpa_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
return 0;
}
- if (snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]) >=
- sizeof(cmd) - 1) {
+ res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long SET command.\n");
return 0;
}
@@ -351,6 +353,7 @@ static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256];
+ int res;
if (argc != 1) {
printf("Invalid PREAUTH command: needs one argument "
@@ -358,8 +361,8 @@ static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
return 0;
}
- if (snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]) >=
- sizeof(cmd) - 1) {
+ res = os_snprintf(cmd, sizeof(cmd), "PREAUTH %s", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long PREAUTH command.\n");
return 0;
}
@@ -367,15 +370,61 @@ static int wpa_cli_cmd_preauthenticate(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_ap_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid AP_SCAN command: needs one argument (ap_scan "
+ "value)\n");
+ return 0;
+ }
+ res = os_snprintf(cmd, sizeof(cmd), "AP_SCAN %s", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long AP_SCAN command.\n");
+ return 0;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_stkstart(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+ int res;
+
+ if (argc != 1) {
+ printf("Invalid STKSTART command: needs one argument "
+ "(Peer STA MAC address)\n");
+ return 0;
+ }
+
+ res = os_snprintf(cmd, sizeof(cmd), "STKSTART %s", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long STKSTART command.\n");
+ return 0;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256];
+ int res;
+
if (argc != 1) {
printf("Invalid LEVEL command: needs one argument (debug "
"level)\n");
return 0;
}
- snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
+ res = os_snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+ printf("Too long LEVEL command.\n");
+ return 0;
+ }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -383,7 +432,7 @@ static int wpa_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256], *pos, *end;
- int i;
+ int i, ret;
if (argc < 2) {
printf("Invalid IDENTITY command: needs two arguments "
@@ -393,10 +442,21 @@ static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
end = cmd + sizeof(cmd);
pos = cmd;
- pos += snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
- argv[0], argv[1]);
- for (i = 2; i < argc; i++)
- pos += snprintf(pos, end - pos, " %s", argv[i]);
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
+ argv[0], argv[1]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long IDENTITY command.\n");
+ return 0;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long IDENTITY command.\n");
+ return 0;
+ }
+ pos += ret;
+ }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -405,7 +465,7 @@ static int wpa_cli_cmd_identity(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256], *pos, *end;
- int i;
+ int i, ret;
if (argc < 2) {
printf("Invalid PASSWORD command: needs two arguments "
@@ -415,10 +475,21 @@ static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
end = cmd + sizeof(cmd);
pos = cmd;
- pos += snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
- argv[0], argv[1]);
- for (i = 2; i < argc; i++)
- pos += snprintf(pos, end - pos, " %s", argv[i]);
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
+ argv[0], argv[1]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long PASSWORD command.\n");
+ return 0;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long PASSWORD command.\n");
+ return 0;
+ }
+ pos += ret;
+ }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -428,7 +499,7 @@ static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256], *pos, *end;
- int i;
+ int i, ret;
if (argc < 2) {
printf("Invalid NEW_PASSWORD command: needs two arguments "
@@ -438,10 +509,21 @@ static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
end = cmd + sizeof(cmd);
pos = cmd;
- pos += snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
- argv[0], argv[1]);
- for (i = 2; i < argc; i++)
- pos += snprintf(pos, end - pos, " %s", argv[i]);
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
+ argv[0], argv[1]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long NEW_PASSWORD command.\n");
+ return 0;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long NEW_PASSWORD command.\n");
+ return 0;
+ }
+ pos += ret;
+ }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -450,7 +532,7 @@ static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256], *pos, *end;
- int i;
+ int i, ret;
if (argc < 2) {
printf("Invalid PIN command: needs two arguments "
@@ -460,11 +542,21 @@ static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
end = cmd + sizeof(cmd);
pos = cmd;
- pos += snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
- argv[0], argv[1]);
- for (i = 2; i < argc; i++)
- pos += snprintf(pos, end - pos, " %s", argv[i]);
-
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
+ argv[0], argv[1]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long PIN command.\n");
+ return 0;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long PIN command.\n");
+ return 0;
+ }
+ pos += ret;
+ }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -472,7 +564,7 @@ static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256], *pos, *end;
- int i;
+ int i, ret;
if (argc < 2) {
printf("Invalid OTP command: needs two arguments (network "
@@ -482,10 +574,21 @@ static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
end = cmd + sizeof(cmd);
pos = cmd;
- pos += snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
- argv[0], argv[1]);
- for (i = 2; i < argc; i++)
- pos += snprintf(pos, end - pos, " %s", argv[i]);
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
+ argv[0], argv[1]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long OTP command.\n");
+ return 0;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long OTP command.\n");
+ return 0;
+ }
+ pos += ret;
+ }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -495,7 +598,7 @@ static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256], *pos, *end;
- int i;
+ int i, ret;
if (argc < 2) {
printf("Invalid PASSPHRASE command: needs two arguments "
@@ -505,10 +608,21 @@ static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
end = cmd + sizeof(cmd);
pos = cmd;
- pos += snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
- argv[0], argv[1]);
- for (i = 2; i < argc; i++)
- pos += snprintf(pos, end - pos, " %s", argv[i]);
+ ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
+ argv[0], argv[1]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long PASSPHRASE command.\n");
+ return 0;
+ }
+ pos += ret;
+ for (i = 2; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long PASSPHRASE command.\n");
+ return 0;
+ }
+ pos += ret;
+ }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -517,7 +631,7 @@ static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256], *pos, *end;
- int i;
+ int i, ret;
if (argc < 2) {
printf("Invalid BSSID command: needs two arguments (network "
@@ -527,9 +641,20 @@ static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
end = cmd + sizeof(cmd);
pos = cmd;
- pos += snprintf(pos, end - pos, "BSSID");
- for (i = 0; i < argc; i++)
- pos += snprintf(pos, end - pos, " %s", argv[i]);
+ ret = os_snprintf(pos, end - pos, "BSSID");
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long BSSID command.\n");
+ return 0;
+ }
+ pos += ret;
+ for (i = 0; i < argc; i++) {
+ ret = os_snprintf(pos, end - pos, " %s", argv[i]);
+ if (ret < 0 || ret >= end - pos) {
+ printf("Too long BSSID command.\n");
+ return 0;
+ }
+ pos += ret;
+ }
return wpa_ctrl_command(ctrl, cmd);
}
@@ -553,7 +678,8 @@ static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
return 0;
}
- snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
+ os_snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
+ cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
@@ -570,7 +696,8 @@ static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
return 0;
}
- snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
+ os_snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
+ cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
@@ -587,7 +714,8 @@ static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
return 0;
}
- snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
+ os_snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
+ cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
@@ -611,7 +739,8 @@ static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
return 0;
}
- snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
+ os_snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
+ cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
@@ -642,6 +771,7 @@ static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256];
+ int res;
if (argc == 0) {
wpa_cli_show_network_variables();
@@ -654,8 +784,9 @@ static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
return 0;
}
- if (snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
- argv[0], argv[1], argv[2]) >= sizeof(cmd) - 1) {
+ res = os_snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
+ argv[0], argv[1], argv[2]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long SET_NETWORK command.\n");
return 0;
}
@@ -667,6 +798,7 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char cmd[256];
+ int res;
if (argc == 0) {
wpa_cli_show_network_variables();
@@ -679,8 +811,9 @@ static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
return 0;
}
- if (snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
- argv[0], argv[1]) >= sizeof(cmd) - 1) {
+ res = os_snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
+ argv[0], argv[1]);
+ if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
printf("Too long GET_NETWORK command.\n");
return 0;
}
@@ -720,37 +853,30 @@ static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
{
char cmd[64];
- if (argc != 1) {
- printf("Invalid GET_CAPABILITY command: needs one argument\n");
+ if (argc < 1 || argc > 2) {
+ printf("Invalid GET_CAPABILITY command: need either one or "
+ "two arguments\n");
+ return 0;
+ }
+
+ if ((argc == 2) && os_strcmp(argv[1], "strict") != 0) {
+ printf("Invalid GET_CAPABILITY command: second argument, "
+ "if any, must be 'strict'\n");
return 0;
}
- snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s", argv[0]);
+ os_snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s%s", argv[0],
+ (argc == 2) ? " strict" : "");
+ cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
-static void wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
+static int wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
{
- struct dirent *dent;
- DIR *dir;
-
- dir = opendir(ctrl_iface_dir);
- if (dir == NULL) {
- printf("Control interface directory '%s' could not be "
- "openned.\n", ctrl_iface_dir);
- return;
- }
-
printf("Available interfaces:\n");
- while ((dent = readdir(dir))) {
- if (strcmp(dent->d_name, ".") == 0 ||
- strcmp(dent->d_name, "..") == 0)
- continue;
- printf("%s\n", dent->d_name);
- }
- closedir(dir);
+ return wpa_ctrl_command(ctrl, "INTERFACES");
}
@@ -762,8 +888,8 @@ static int wpa_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
wpa_cli_close_connection();
- free(ctrl_ifname);
- ctrl_ifname = strdup(argv[0]);
+ os_free(ctrl_ifname);
+ ctrl_ifname = os_strdup(argv[0]);
if (wpa_cli_open_connection(ctrl_ifname)) {
printf("Connected to interface '%s.\n", ctrl_ifname);
@@ -804,17 +930,20 @@ static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
printf("Invalid INTERFACE_ADD command: needs at least one "
"argument (interface name)\n"
"All arguments: ifname confname driver ctrl_interface "
- "driver_param\n");
+ "driver_param bridge_name\n");
return 0;
}
/*
* INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
- * <driver_param>
+ * <driver_param>TAB<bridge_name>
*/
- snprintf(cmd, sizeof(cmd), "INTERFACE_ADD %s\t%s\t%s\t%s\t%s", argv[0],
- argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
- argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "");
+ os_snprintf(cmd, sizeof(cmd), "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
+ argv[0],
+ argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
+ argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
+ argc > 5 ? argv[5] : "");
+ cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
@@ -830,7 +959,8 @@ static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
return 0;
}
- snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
+ os_snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
+ cmd[sizeof(cmd) - 1] = '\0';
return wpa_ctrl_command(ctrl, cmd);
}
@@ -879,6 +1009,8 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "terminate", wpa_cli_cmd_terminate },
{ "interface_add", wpa_cli_cmd_interface_add },
{ "interface_remove", wpa_cli_cmd_interface_remove },
+ { "ap_scan", wpa_cli_cmd_ap_scan },
+ { "stkstart", wpa_cli_cmd_stkstart },
{ NULL, NULL }
};
@@ -891,9 +1023,10 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
count = 0;
cmd = wpa_cli_commands;
while (cmd->cmd) {
- if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
+ if (os_strncasecmp(cmd->cmd, argv[0], os_strlen(argv[0])) == 0)
+ {
match = cmd;
- if (strcasecmp(cmd->cmd, argv[0]) == 0) {
+ if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
/* we have an exact match */
count = 1;
break;
@@ -907,8 +1040,8 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
printf("Ambiguous command '%s'; possible commands:", argv[0]);
cmd = wpa_cli_commands;
while (cmd->cmd) {
- if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
- 0) {
+ if (os_strncasecmp(cmd->cmd, argv[0],
+ os_strlen(argv[0])) == 0) {
printf(" %s", cmd->cmd);
}
cmd++;
@@ -924,7 +1057,7 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
static int str_match(const char *a, const char *b)
{
- return strncmp(a, b, strlen(b)) == 0;
+ return os_strncmp(a, b, os_strlen(b)) == 0;
}
@@ -934,13 +1067,16 @@ static int wpa_cli_exec(const char *program, const char *arg1,
char *cmd;
size_t len;
- len = strlen(program) + strlen(arg1) + strlen(arg2) + 3;
- cmd = malloc(len);
+ len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
+ cmd = os_malloc(len);
if (cmd == NULL)
return -1;
- snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
+ os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
+ cmd[len - 1] = '\0';
+#ifndef _WIN32_WCE
system(cmd);
- free(cmd);
+#endif /* _WIN32_WCE */
+ os_free(cmd);
return 0;
}
@@ -949,11 +1085,12 @@ static int wpa_cli_exec(const char *program, const char *arg1,
static void wpa_cli_action_process(const char *msg)
{
const char *pos;
+ char *copy = NULL, *id, *pos2;
pos = msg;
if (*pos == '<') {
/* skip priority */
- pos = strchr(pos, '>');
+ pos = os_strchr(pos, '>');
if (pos)
pos++;
else
@@ -961,9 +1098,46 @@ static void wpa_cli_action_process(const char *msg)
}
if (str_match(pos, WPA_EVENT_CONNECTED)) {
- wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
+ int new_id = -1;
+ os_unsetenv("WPA_ID");
+ os_unsetenv("WPA_ID_STR");
+ os_unsetenv("WPA_CTRL_DIR");
+
+ pos = os_strstr(pos, "[id=");
+ if (pos)
+ copy = os_strdup(pos + 4);
+
+ if (copy) {
+ pos2 = id = copy;
+ while (*pos2 && *pos2 != ' ')
+ pos2++;
+ *pos2++ = '\0';
+ new_id = atoi(id);
+ os_setenv("WPA_ID", id, 1);
+ while (*pos2 && *pos2 != '=')
+ pos2++;
+ if (*pos2 == '=')
+ pos2++;
+ id = pos2;
+ while (*pos2 && *pos2 != ']')
+ pos2++;
+ *pos2 = '\0';
+ os_setenv("WPA_ID_STR", id, 1);
+ os_free(copy);
+ }
+
+ os_setenv("WPA_CTRL_DIR", ctrl_iface_dir, 1);
+
+ if (!wpa_cli_connected || new_id != wpa_cli_last_id) {
+ wpa_cli_connected = 1;
+ wpa_cli_last_id = new_id;
+ wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
+ }
} else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
- wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
+ if (wpa_cli_connected) {
+ wpa_cli_connected = 0;
+ wpa_cli_exec(action_file, ctrl_ifname, "DISCONNECTED");
+ }
} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
printf("wpa_supplicant is terminating - stop monitoring\n");
wpa_cli_quit = 1;
@@ -971,19 +1145,39 @@ static void wpa_cli_action_process(const char *msg)
}
+#ifndef CONFIG_ANSI_C_EXTRA
static void wpa_cli_action_cb(char *msg, size_t len)
{
wpa_cli_action_process(msg);
}
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+
+static void wpa_cli_reconnect(void)
+{
+ wpa_cli_close_connection();
+ ctrl_conn = wpa_cli_open_connection(ctrl_ifname);
+ if (ctrl_conn) {
+ printf("Connection to wpa_supplicant re-established\n");
+ if (wpa_ctrl_attach(ctrl_conn) == 0) {
+ wpa_cli_attached = 1;
+ } else {
+ printf("Warning: Failed to attach to "
+ "wpa_supplicant.\n");
+ }
+ }
+}
static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
int action_monitor)
{
int first = 1;
- if (ctrl_conn == NULL)
+ if (ctrl_conn == NULL) {
+ wpa_cli_reconnect();
return;
- while (wpa_ctrl_pending(ctrl)) {
+ }
+ while (wpa_ctrl_pending(ctrl) > 0) {
char buf[256];
size_t len = sizeof(buf) - 1;
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
@@ -1001,6 +1195,12 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
break;
}
}
+
+ if (wpa_ctrl_pending(ctrl) < 0) {
+ printf("Connection to wpa_supplicant lost - trying to "
+ "reconnect\n");
+ wpa_cli_reconnect();
+ }
}
@@ -1012,13 +1212,13 @@ static char * wpa_cli_cmd_gen(const char *text, int state)
if (state == 0) {
i = 0;
- len = strlen(text);
+ len = os_strlen(text);
}
while ((cmd = wpa_cli_commands[i].cmd)) {
i++;
- if (strncasecmp(cmd, text, len) == 0)
- return strdup(cmd);
+ if (os_strncasecmp(cmd, text, len) == 0)
+ return os_strdup(cmd);
}
return NULL;
@@ -1055,10 +1255,11 @@ static void wpa_cli_interactive(void)
home = getenv("HOME");
if (home) {
const char *fname = ".wpa_cli_history";
- int hfile_len = strlen(home) + 1 + strlen(fname) + 1;
- hfile = malloc(hfile_len);
+ int hfile_len = os_strlen(home) + 1 + os_strlen(fname) + 1;
+ hfile = os_malloc(hfile_len);
if (hfile) {
- snprintf(hfile, hfile_len, "%s/%s", home, fname);
+ os_snprintf(hfile, hfile_len, "%s/%s", home, fname);
+ hfile[hfile_len - 1] = '\0';
read_history(hfile);
stifle_history(100);
}
@@ -1077,7 +1278,7 @@ static void wpa_cli_interactive(void)
while (next_history())
;
h = previous_history();
- if (h == NULL || strcmp(cmd, h->line) != 0)
+ if (h == NULL || os_strcmp(cmd, h->line) != 0)
add_history(cmd);
next_history();
}
@@ -1090,6 +1291,7 @@ static void wpa_cli_interactive(void)
#endif /* CONFIG_NATIVE_WINDOWS */
if (cmd == NULL)
break;
+ wpa_cli_recv_pending(ctrl_conn, 0, 0);
pos = cmd;
while (*pos != '\0') {
if (*pos == '\n') {
@@ -1110,7 +1312,7 @@ static void wpa_cli_interactive(void)
if (argc == max_args)
break;
if (*pos == '"') {
- char *pos2 = strrchr(pos, '"');
+ char *pos2 = os_strrchr(pos, '"');
if (pos2)
pos = pos2 + 1;
}
@@ -1123,7 +1325,7 @@ static void wpa_cli_interactive(void)
wpa_request(ctrl_conn, argc, argv);
if (cmd != cmdbuf)
- free(cmd);
+ os_free(cmd);
} while (!wpa_cli_quit);
#ifdef CONFIG_READLINE
@@ -1137,14 +1339,14 @@ static void wpa_cli_interactive(void)
char *p = h->line;
while (*p == ' ' || *p == '\t')
p++;
- if (strncasecmp(p, "pa", 2) == 0 ||
- strncasecmp(p, "o", 1) == 0 ||
- strncasecmp(p, "n", 1)) {
+ if (os_strncasecmp(p, "pa", 2) == 0 ||
+ os_strncasecmp(p, "o", 1) == 0 ||
+ os_strncasecmp(p, "n", 1)) {
h = remove_history(where_history());
if (h) {
- free(h->line);
- free(h->data);
- free(h);
+ os_free(h->line);
+ os_free(h->data);
+ os_free(h);
}
h = current_history();
} else {
@@ -1152,7 +1354,7 @@ static void wpa_cli_interactive(void)
}
}
write_history(hfile);
- free(hfile);
+ os_free(hfile);
}
#endif /* CONFIG_READLINE */
}
@@ -1160,10 +1362,14 @@ static void wpa_cli_interactive(void)
static void wpa_cli_action(struct wpa_ctrl *ctrl)
{
+#ifdef CONFIG_ANSI_C_EXTRA
+ /* TODO: ANSI C version(?) */
+ printf("Action processing not supported in ANSI C build.\n");
+#else /* CONFIG_ANSI_C_EXTRA */
fd_set rfds;
int fd, res;
struct timeval tv;
- char buf[16];
+ char buf[256]; /* note: large enough to fit in unsolicited messages */
size_t len;
fd = wpa_ctrl_get_fd(ctrl);
@@ -1186,13 +1392,14 @@ static void wpa_cli_action(struct wpa_ctrl *ctrl)
len = sizeof(buf) - 1;
if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
wpa_cli_action_cb) < 0 ||
- len < 4 || memcmp(buf, "PONG", 4) != 0) {
+ len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
printf("wpa_supplicant did not reply to PING "
"command - exiting\n");
break;
}
}
}
+#endif /* CONFIG_ANSI_C_EXTRA */
}
@@ -1200,11 +1407,9 @@ static void wpa_cli_cleanup(void)
{
wpa_cli_close_connection();
if (pid_file)
- unlink(pid_file);
+ os_daemonize_terminate(pid_file);
-#ifdef CONFIG_NATIVE_WINDOWS
- WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
+ os_program_deinit();
}
static void wpa_cli_terminate(int sig)
@@ -1222,19 +1427,8 @@ static void wpa_cli_alarm(int sig)
"reconnect\n");
wpa_cli_close_connection();
}
- if (!ctrl_conn) {
- ctrl_conn = wpa_cli_open_connection(ctrl_ifname);
- if (ctrl_conn) {
- printf("Connection to wpa_supplicant "
- "re-established\n");
- if (wpa_ctrl_attach(ctrl_conn) == 0) {
- wpa_cli_attached = 1;
- } else {
- printf("Warning: Failed to attach to "
- "wpa_supplicant.\n");
- }
- }
- }
+ if (!ctrl_conn)
+ wpa_cli_reconnect();
if (ctrl_conn)
wpa_cli_recv_pending(ctrl_conn, 1, 0);
alarm(1);
@@ -1242,22 +1436,71 @@ static void wpa_cli_alarm(int sig)
#endif /* CONFIG_NATIVE_WINDOWS */
+static char * wpa_cli_get_default_ifname(void)
+{
+ char *ifname = NULL;
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ struct dirent *dent;
+ DIR *dir = opendir(ctrl_iface_dir);
+ if (!dir)
+ return NULL;
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /*
+ * Skip the file if it is not a socket. Also accept
+ * DT_UNKNOWN (0) in case the C library or underlying
+ * file system does not support d_type.
+ */
+ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+ if (os_strcmp(dent->d_name, ".") == 0 ||
+ os_strcmp(dent->d_name, "..") == 0)
+ continue;
+ printf("Selected interface '%s'\n", dent->d_name);
+ ifname = os_strdup(dent->d_name);
+ break;
+ }
+ closedir(dir);
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ char buf[2048], *pos;
+ size_t len;
+ struct wpa_ctrl *ctrl;
+ int ret;
+
+ ctrl = wpa_ctrl_open(NULL);
+ if (ctrl == NULL)
+ return NULL;
+
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
+ if (ret >= 0) {
+ buf[len] = '\0';
+ pos = os_strchr(buf, '\n');
+ if (pos)
+ *pos = '\0';
+ ifname = os_strdup(buf);
+ }
+ wpa_ctrl_close(ctrl);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+ return ifname;
+}
+
+
int main(int argc, char *argv[])
{
int interactive;
int warning_displayed = 0;
int c;
int daemonize = 0;
- FILE *f;
const char *global = NULL;
-#ifdef CONFIG_NATIVE_WINDOWS
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
- printf("Could not find a usable WinSock.dll\n");
+ if (os_program_init())
return -1;
- }
-#endif /* CONFIG_NATIVE_WINDOWS */
for (;;) {
c = getopt(argc, argv, "a:Bg:hi:p:P:v");
@@ -1280,7 +1523,8 @@ int main(int argc, char *argv[])
printf("%s\n", wpa_cli_version);
return 0;
case 'i':
- ctrl_ifname = strdup(optarg);
+ os_free(ctrl_ifname);
+ ctrl_ifname = os_strdup(optarg);
break;
case 'p':
ctrl_iface_dir = optarg;
@@ -1300,7 +1544,11 @@ int main(int argc, char *argv[])
printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
if (global) {
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ ctrl_conn = wpa_ctrl_open(NULL);
+#else /* CONFIG_CTRL_IFACE_NAMED_PIPE */
ctrl_conn = wpa_ctrl_open(global);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
if (ctrl_conn == NULL) {
perror("Failed to connect to wpa_supplicant - "
"wpa_ctrl_open");
@@ -1309,22 +1557,8 @@ int main(int argc, char *argv[])
}
for (; !global;) {
- if (ctrl_ifname == NULL) {
- struct dirent *dent;
- DIR *dir = opendir(ctrl_iface_dir);
- if (dir) {
- while ((dent = readdir(dir))) {
- if (strcmp(dent->d_name, ".") == 0 ||
- strcmp(dent->d_name, "..") == 0)
- continue;
- printf("Selected interface '%s'\n",
- dent->d_name);
- ctrl_ifname = strdup(dent->d_name);
- break;
- }
- closedir(dir);
- }
- }
+ if (ctrl_ifname == NULL)
+ ctrl_ifname = wpa_cli_get_default_ifname();
ctrl_conn = wpa_cli_open_connection(ctrl_ifname);
if (ctrl_conn) {
if (warning_displayed)
@@ -1343,12 +1577,14 @@ int main(int argc, char *argv[])
"re-trying\n");
warning_displayed = 1;
}
- sleep(1);
+ os_sleep(1, 0);
continue;
}
+#ifndef _WIN32_WCE
signal(SIGINT, wpa_cli_terminate);
signal(SIGTERM, wpa_cli_terminate);
+#endif /* _WIN32_WCE */
#ifndef CONFIG_NATIVE_WINDOWS
signal(SIGALRM, wpa_cli_alarm);
#endif /* CONFIG_NATIVE_WINDOWS */
@@ -1364,18 +1600,8 @@ int main(int argc, char *argv[])
}
}
- if (daemonize && daemon(0, 0)) {
- perror("daemon");
+ if (daemonize && os_daemonize(pid_file))
return -1;
- }
-
- if (pid_file) {
- f = fopen(pid_file, "w");
- if (f) {
- fprintf(f, "%u\n", getpid());
- fclose(f);
- }
- }
if (interactive)
wpa_cli_interactive();
@@ -1384,8 +1610,16 @@ int main(int argc, char *argv[])
else
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
- free(ctrl_ifname);
+ os_free(ctrl_ifname);
wpa_cli_cleanup();
return 0;
}
+
+#else /* CONFIG_CTRL_IFACE */
+int main(int argc, char *argv[])
+{
+ printf("CONFIG_CTRL_IFACE not defined - wpa_cli disabled\n");
+ return -1;
+}
+#endif /* CONFIG_CTRL_IFACE */
diff --git a/contrib/wpa_supplicant/wpa_common.h b/contrib/wpa_supplicant/wpa_common.h
new file mode 100644
index 000000000000..6d0316ce4a38
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_common.h
@@ -0,0 +1,58 @@
+/*
+ * WPA definitions shared between hostapd and wpa_supplicant
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef WPA_COMMON_H
+#define WPA_COMMON_H
+
+#define WPA_REPLAY_COUNTER_LEN 8
+#define WPA_NONCE_LEN 32
+#define WPA_KEY_RSC_LEN 8
+
+
+/* IEEE Std 802.1X-2004 */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_hdr {
+ u8 version;
+ u8 type;
+ u16 length;
+ /* followed by length octets of data */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define EAPOL_VERSION 2
+
+enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
+ IEEE802_1X_TYPE_EAPOL_START = 1,
+ IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
+ IEEE802_1X_TYPE_EAPOL_KEY = 3,
+ IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
+};
+
+enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
+ EAPOL_KEY_TYPE_WPA = 254 };
+
+#ifdef CONFIG_IEEE80211W
+#define WPA_DGTK_LEN 16
+#define WPA_DHV_LEN 16
+#define WPA_IGTK_LEN 16
+#endif /* CONFIG_IEEE80211W */
+
+#endif /* WPA_COMMON_H */
diff --git a/contrib/wpa_supplicant/wpa_ctrl.c b/contrib/wpa_supplicant/wpa_ctrl.c
index 98e0669a4738..dcec537fc7a2 100644
--- a/contrib/wpa_supplicant/wpa_ctrl.c
+++ b/contrib/wpa_supplicant/wpa_ctrl.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd control interface library
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,22 +12,21 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/socket.h>
-#include <netinet/in.h>
+#include "includes.h"
+
+#ifdef CONFIG_CTRL_IFACE
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
#include <sys/un.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#endif /* CONFIG_CTRL_IFACE_UNIX */
#include "wpa_ctrl.h"
-#ifdef CONFIG_NATIVE_WINDOWS
#include "common.h"
-#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
+#define CTRL_IFACE_SOCKET
+#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
/**
@@ -40,84 +39,121 @@
* the arguments for most of the control interface library functions.
*/
struct wpa_ctrl {
- int s;
#ifdef CONFIG_CTRL_IFACE_UDP
+ int s;
struct sockaddr_in local;
struct sockaddr_in dest;
-#else /* CONFIG_CTRL_IFACE_UDP */
+ char *cookie;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ int s;
struct sockaddr_un local;
struct sockaddr_un dest;
-#endif /* CONFIG_CTRL_IFACE_UDP */
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ HANDLE pipe;
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
};
+#ifdef CONFIG_CTRL_IFACE_UNIX
+
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
{
struct wpa_ctrl *ctrl;
-#ifndef CONFIG_CTRL_IFACE_UDP
static int counter = 0;
-#endif /* CONFIG_CTRL_IFACE_UDP */
- ctrl = malloc(sizeof(*ctrl));
+ ctrl = os_malloc(sizeof(*ctrl));
if (ctrl == NULL)
return NULL;
- memset(ctrl, 0, sizeof(*ctrl));
+ os_memset(ctrl, 0, sizeof(*ctrl));
-#ifdef CONFIG_CTRL_IFACE_UDP
- ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
+ ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
- perror("socket");
- free(ctrl);
+ os_free(ctrl);
return NULL;
}
- ctrl->local.sin_family = AF_INET;
- ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
+ ctrl->local.sun_family = AF_UNIX;
+ os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
+ "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
- sizeof(ctrl->local)) < 0) {
+ sizeof(ctrl->local)) < 0) {
close(ctrl->s);
- free(ctrl);
+ os_free(ctrl);
return NULL;
}
- ctrl->dest.sin_family = AF_INET;
- ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
- ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
+ ctrl->dest.sun_family = AF_UNIX;
+ os_snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s",
+ ctrl_path);
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
- perror("connect");
close(ctrl->s);
- free(ctrl);
+ unlink(ctrl->local.sun_path);
+ os_free(ctrl);
return NULL;
}
-#else /* CONFIG_CTRL_IFACE_UDP */
- ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
+
+ return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+ unlink(ctrl->local.sun_path);
+ close(ctrl->s);
+ os_free(ctrl);
+}
+
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+ struct wpa_ctrl *ctrl;
+ char buf[128];
+ size_t len;
+
+ ctrl = os_malloc(sizeof(*ctrl));
+ if (ctrl == NULL)
+ return NULL;
+ os_memset(ctrl, 0, sizeof(*ctrl));
+
+ ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
if (ctrl->s < 0) {
- free(ctrl);
+ perror("socket");
+ os_free(ctrl);
return NULL;
}
- ctrl->local.sun_family = AF_UNIX;
- snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
- "/tmp/wpa_ctrl_%d-%d", getpid(), counter++);
+ ctrl->local.sin_family = AF_INET;
+ ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
- sizeof(ctrl->local)) < 0) {
+ sizeof(ctrl->local)) < 0) {
close(ctrl->s);
- free(ctrl);
+ os_free(ctrl);
return NULL;
}
- ctrl->dest.sun_family = AF_UNIX;
- snprintf(ctrl->dest.sun_path, sizeof(ctrl->dest.sun_path), "%s",
- ctrl_path);
+ ctrl->dest.sin_family = AF_INET;
+ ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
+ ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
+ perror("connect");
close(ctrl->s);
- unlink(ctrl->local.sun_path);
- free(ctrl);
+ os_free(ctrl);
return NULL;
}
-#endif /* CONFIG_CTRL_IFACE_UDP */
+
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
+ buf[len] = '\0';
+ ctrl->cookie = strdup(buf);
+ }
return ctrl;
}
@@ -125,14 +161,15 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
void wpa_ctrl_close(struct wpa_ctrl *ctrl)
{
-#ifndef CONFIG_CTRL_IFACE_UDP
- unlink(ctrl->local.sun_path);
-#endif /* CONFIG_CTRL_IFACE_UDP */
close(ctrl->s);
- free(ctrl);
+ os_free(ctrl->cookie);
+ os_free(ctrl);
}
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+#ifdef CTRL_IFACE_SOCKET
int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
char *reply, size_t *reply_len,
void (*msg_cb)(char *msg, size_t len))
@@ -140,9 +177,35 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
struct timeval tv;
int res;
fd_set rfds;
+ const char *_cmd;
+ char *cmd_buf = NULL;
+ size_t _cmd_len;
- if (send(ctrl->s, cmd, cmd_len, 0) < 0)
+#ifdef CONFIG_CTRL_IFACE_UDP
+ if (ctrl->cookie) {
+ char *pos;
+ _cmd_len = strlen(ctrl->cookie) + 1 + cmd_len;
+ cmd_buf = os_malloc(_cmd_len );
+ if (cmd_buf == NULL)
+ return -1;
+ _cmd = cmd_buf;
+ pos = cmd_buf;
+ strcpy(pos, ctrl->cookie);
+ pos += strlen(ctrl->cookie);
+ *pos++ = ' ';
+ memcpy(pos, cmd, cmd_len);
+ } else
+#endif /* CONFIG_CTRL_IFACE_UDP */
+ {
+ _cmd = cmd;
+ _cmd_len = cmd_len;
+ }
+
+ if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
+ os_free(cmd_buf);
return -1;
+ }
+ os_free(cmd_buf);
for (;;) {
tv.tv_sec = 2;
@@ -177,6 +240,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
}
return 0;
}
+#endif /* CTRL_IFACE_SOCKET */
static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
@@ -189,7 +253,7 @@ static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
buf, &len, NULL);
if (ret < 0)
return ret;
- if (len == 3 && memcmp(buf, "OK\n", 3) == 0)
+ if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
return 0;
return -1;
}
@@ -207,6 +271,8 @@ int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
}
+#ifdef CTRL_IFACE_SOCKET
+
int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
{
int res;
@@ -222,13 +288,12 @@ int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
{
struct timeval tv;
- int res;
fd_set rfds;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rfds);
FD_SET(ctrl->s, &rfds);
- res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+ select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
return FD_ISSET(ctrl->s, &rfds);
}
@@ -237,3 +302,124 @@ int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
{
return ctrl->s;
}
+
+#endif /* CTRL_IFACE_SOCKET */
+
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+
+#ifndef WPA_SUPPLICANT_NAMED_PIPE
+#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
+#endif
+#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+ struct wpa_ctrl *ctrl;
+ DWORD mode;
+ TCHAR name[256];
+ int i;
+
+ ctrl = os_malloc(sizeof(*ctrl));
+ if (ctrl == NULL)
+ return NULL;
+ os_memset(ctrl, 0, sizeof(*ctrl));
+
+#ifdef UNICODE
+ if (ctrl_path == NULL)
+ _snwprintf(name, 256, NAMED_PIPE_PREFIX);
+ else
+ _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
+ ctrl_path);
+#else /* UNICODE */
+ if (ctrl_path == NULL)
+ os_snprintf(name, 256, NAMED_PIPE_PREFIX);
+ else
+ os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
+ ctrl_path);
+#endif /* UNICODE */
+
+ for (i = 0; i < 10; i++) {
+ ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
+ NULL, OPEN_EXISTING, 0, NULL);
+ /*
+ * Current named pipe server side in wpa_supplicant is
+ * re-opening the pipe for new clients only after the previous
+ * one is taken into use. This leaves a small window for race
+ * conditions when two connections are being opened at almost
+ * the same time. Retry if that was the case.
+ */
+ if (ctrl->pipe != INVALID_HANDLE_VALUE ||
+ GetLastError() != ERROR_PIPE_BUSY)
+ break;
+ WaitNamedPipe(name, 1000);
+ }
+ if (ctrl->pipe == INVALID_HANDLE_VALUE) {
+ os_free(ctrl);
+ return NULL;
+ }
+
+ mode = PIPE_READMODE_MESSAGE;
+ if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
+ CloseHandle(ctrl->pipe);
+ os_free(ctrl);
+ return NULL;
+ }
+
+ return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+ CloseHandle(ctrl->pipe);
+ os_free(ctrl);
+}
+
+
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+ char *reply, size_t *reply_len,
+ void (*msg_cb)(char *msg, size_t len))
+{
+ DWORD written;
+ DWORD readlen = *reply_len;
+
+ if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
+ return -1;
+
+ if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
+ return -1;
+ *reply_len = readlen;
+
+ return 0;
+}
+
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+ DWORD len = *reply_len;
+ if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
+ return -1;
+ *reply_len = len;
+ return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+ DWORD left;
+
+ if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
+ return -1;
+ return left ? 1 : 0;
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+ return -1;
+}
+
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+#endif /* CONFIG_CTRL_IFACE */
diff --git a/contrib/wpa_supplicant/wpa_ctrl.h b/contrib/wpa_supplicant/wpa_ctrl.h
index c8fa48d69385..6166fda26ee9 100644
--- a/contrib/wpa_supplicant/wpa_ctrl.h
+++ b/contrib/wpa_supplicant/wpa_ctrl.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd control interface library
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -147,7 +147,7 @@ int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
/**
* wpa_ctrl_pending - Check whether there are pending event messages
* @ctrl: Control interface data from wpa_ctrl_open()
- * Returns: Non-zero if there are pending messages
+ * Returns: 1 if there are pending messages, 0 if no, or -1 on error
*
* This function will check whether there are any pending control interface
* message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp
new file mode 100644
index 000000000000..ebf3c9712d45
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp
@@ -0,0 +1,122 @@
+/*
+ * wpa_gui - EventHistory class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <QHeaderView>
+
+#include "eventhistory.h"
+
+
+int EventListModel::rowCount(const QModelIndex &) const
+{
+ return msgList.count();
+}
+
+
+int EventListModel::columnCount(const QModelIndex &) const
+{
+ return 2;
+}
+
+
+QVariant EventListModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == Qt::DisplayRole)
+ if (index.column() == 0) {
+ if (index.row() >= timeList.size())
+ return QVariant();
+ return timeList.at(index.row());
+ } else {
+ if (index.row() >= msgList.size())
+ return QVariant();
+ return msgList.at(index.row());
+ }
+ else
+ return QVariant();
+}
+
+
+QVariant EventListModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ if (orientation == Qt::Horizontal) {
+ switch (section) {
+ case 0:
+ return QString("Timestamp");
+ case 1:
+ return QString("Message");
+ default:
+ return QVariant();
+ }
+ } else
+ return QString("%1").arg(section);
+}
+
+
+void EventListModel::addEvent(QString time, QString msg)
+{
+ beginInsertRows(QModelIndex(), msgList.size(), msgList.size() + 1);
+ timeList << time;
+ msgList << msg;
+ endInsertRows();
+}
+
+
+EventHistory::EventHistory(QWidget *parent, const char *, bool, Qt::WFlags)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
+
+ elm = new EventListModel(parent);
+ eventListView->setModel(elm);
+}
+
+
+EventHistory::~EventHistory()
+{
+ destroy();
+ delete elm;
+}
+
+
+void EventHistory::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+void EventHistory::addEvents(WpaMsgList msgs)
+{
+ WpaMsgList::iterator it;
+ for (it = msgs.begin(); it != msgs.end(); it++)
+ addEvent(*it);
+}
+
+
+void EventHistory::addEvent(WpaMsg msg)
+{
+ elm->addEvent(msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"),
+ msg.getMsg());
+#if QT_VERSION >= 0x040100
+ eventListView->resizeColumnsToContents();
+ eventListView->resizeRowsToContents();
+#endif
+}
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.h b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.h
new file mode 100644
index 000000000000..40dff6d6d779
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.h
@@ -0,0 +1,63 @@
+/*
+ * wpa_gui - EventHistory class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EVENTHISTORY_H
+#define EVENTHISTORY_H
+
+#include <QObject>
+#include "ui_eventhistory.h"
+
+
+class EventListModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ EventListModel(QObject *parent = 0)
+ : QAbstractTableModel(parent) {}
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ void addEvent(QString time, QString msg);
+
+private:
+ QStringList timeList;
+ QStringList msgList;
+};
+
+
+class EventHistory : public QDialog, public Ui::EventHistory
+{
+ Q_OBJECT
+
+public:
+ EventHistory(QWidget *parent = 0, const char *name = 0,
+ bool modal = false, Qt::WFlags fl = 0);
+ ~EventHistory();
+
+public slots:
+ virtual void addEvents(WpaMsgList msgs);
+ virtual void addEvent(WpaMsg msg);
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ EventListModel *elm;
+};
+
+#endif /* EVENTHISTORY_H */
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui
index 3735fb70e8f9..d47f461380a5 100644
--- a/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui
@@ -1,125 +1,93 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>EventHistory</class>
-<widget class="QDialog">
- <property name="name">
- <cstring>EventHistory</cstring>
+<ui version="4.0" stdsetdef="1" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>EventHistory</class>
+ <widget class="QDialog" name="EventHistory" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>533</width>
+ <height>285</height>
+ </rect>
</property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>533</width>
- <height>285</height>
- </rect>
+ <property name="windowTitle" >
+ <string>Event history</string>
</property>
- <property name="caption">
- <string>Event history</string>
- </property>
- <vbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QListView">
- <column>
- <property name="text">
- <string>Timestamp</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>Message</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <property name="name">
- <cstring>eventListView</cstring>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QTableView" name="eventListView" >
+ <property name="sizePolicy" >
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="selectionMode" >
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ <column>
+ <property name="text" >
+ <string>Timestamp</string>
</property>
- <property name="sizePolicy">
- <sizepolicy>
- <hsizetype>7</hsizetype>
- <vsizetype>7</vsizetype>
- <horstretch>0</horstretch>
- <verstretch>0</verstretch>
- </sizepolicy>
+ <property name="clickable" >
+ <bool>true</bool>
</property>
- <property name="resizePolicy">
- <enum>Manual</enum>
+ <property name="resizable" >
+ <bool>true</bool>
</property>
- <property name="selectionMode">
- <enum>NoSelection</enum>
+ </column>
+ <column>
+ <property name="text" >
+ <string>Message</string>
</property>
- <property name="resizeMode">
- <enum>LastColumn</enum>
+ <property name="clickable" >
+ <bool>true</bool>
</property>
- </widget>
- <widget class="QLayoutWidget">
- <property name="name">
- <cstring>layout30</cstring>
+ <property name="resizable" >
+ <bool>true</bool>
</property>
- <hbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <spacer>
- <property name="name">
- <cstring>spacer3</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- <widget class="QPushButton">
- <property name="name">
- <cstring>closeButton</cstring>
- </property>
- <property name="text">
- <string>Close</string>
- </property>
- </widget>
- </hbox>
+ </column>
</widget>
- </vbox>
-</widget>
-<connections>
- <connection>
- <sender>closeButton</sender>
- <signal>clicked()</signal>
- <receiver>EventHistory</receiver>
- <slot>close()</slot>
- </connection>
-</connections>
-<includes>
- <include location="local" impldecl="in declaration">wpamsg.h</include>
- <include location="local" impldecl="in implementation">eventhistory.ui.h</include>
-</includes>
-<slots>
- <slot>addEvents( WpaMsgList msgs )</slot>
- <slot>addEvent( WpaMsg msg )</slot>
-</slots>
-<functions>
- <function access="private" specifier="non virtual">init()</function>
- <function access="private" specifier="non virtual">destroy()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="spacer3" >
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="sizeType" >
+ <enum>Expanding</enum>
+ </property>
+ <property name="orientation" >
+ <enum>Horizontal</enum>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
+ <includes>
+ <include location="local" >wpamsg.h</include>
+ </includes>
+</ui>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/main.cpp b/contrib/wpa_supplicant/wpa_gui-qt4/main.cpp
index a78473a8c6b1..eeeda399d862 100644
--- a/contrib/wpa_supplicant/wpa_gui-qt4/main.cpp
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/main.cpp
@@ -1,30 +1,44 @@
+/*
+ * wpa_gui - Application startup
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifdef CONFIG_NATIVE_WINDOWS
#include <winsock.h>
#endif /* CONFIG_NATIVE_WINDOWS */
-#include <qapplication.h>
+#include <QApplication>
#include "wpagui.h"
-int main( int argc, char ** argv )
+int main(int argc, char *argv[])
{
- QApplication a( argc, argv );
- WpaGui w;
- int ret;
+ QApplication app(argc, argv);
+ WpaGui w;
+ int ret;
#ifdef CONFIG_NATIVE_WINDOWS
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
- printf("Could not find a usable WinSock.dll\n");
- return -1;
- }
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
+ printf("Could not find a usable WinSock.dll\n");
+ return -1;
+ }
#endif /* CONFIG_NATIVE_WINDOWS */
- w.show();
- a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
- ret = a.exec();
+ w.show();
+ app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit()));
+ ret = app.exec();
#ifdef CONFIG_NATIVE_WINDOWS
- WSACleanup();
+ WSACleanup();
#endif /* CONFIG_NATIVE_WINDOWS */
- return ret;
+ return ret;
}
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
new file mode 100644
index 000000000000..ca86265121fb
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
@@ -0,0 +1,582 @@
+/*
+ * wpa_gui - NetworkConfig class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <QMessageBox>
+
+#include "networkconfig.h"
+#include "wpagui.h"
+
+enum {
+ AUTH_NONE = 0,
+ AUTH_IEEE8021X = 1,
+ AUTH_WPA_PSK = 2,
+ AUTH_WPA_EAP = 3,
+ AUTH_WPA2_PSK = 4,
+ AUTH_WPA2_EAP = 5
+};
+
+#define WPA_GUI_KEY_DATA "[key is configured]"
+
+
+NetworkConfig::NetworkConfig(QWidget *parent, const char *, bool, Qt::WFlags)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ connect(authSelect, SIGNAL(activated(int)), this,
+ SLOT(authChanged(int)));
+ connect(cancelButton, SIGNAL(clicked()), this, SLOT(close()));
+ connect(addButton, SIGNAL(clicked()), this, SLOT(addNetwork()));
+ connect(encrSelect, SIGNAL(activated(const QString &)), this,
+ SLOT(encrChanged(const QString &)));
+ connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork()));
+
+ wpagui = NULL;
+ new_network = false;
+}
+
+
+NetworkConfig::~NetworkConfig()
+{
+}
+
+
+void NetworkConfig::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+void NetworkConfig::paramsFromScanResults(Q3ListViewItem *sel)
+{
+ new_network = true;
+
+ /* SSID BSSID frequency signal flags */
+ setCaption(sel->text(0));
+ ssidEdit->setText(sel->text(0));
+
+ QString flags = sel->text(4);
+ int auth, encr = 0;
+ if (flags.find("[WPA2-EAP") >= 0)
+ auth = AUTH_WPA2_EAP;
+ else if (flags.find("[WPA-EAP") >= 0)
+ auth = AUTH_WPA_EAP;
+ else if (flags.find("[WPA2-PSK") >= 0)
+ auth = AUTH_WPA2_PSK;
+ else if (flags.find("[WPA-PSK") >= 0)
+ auth = AUTH_WPA_PSK;
+ else
+ auth = AUTH_NONE;
+
+ if (flags.find("-CCMP") >= 0)
+ encr = 1;
+ else if (flags.find("-TKIP") >= 0)
+ encr = 0;
+ else if (flags.find("WEP") >= 0)
+ encr = 1;
+ else
+ encr = 0;
+
+ authSelect->setCurrentItem(auth);
+ authChanged(auth);
+ encrSelect->setCurrentItem(encr);
+
+ getEapCapa();
+}
+
+
+void NetworkConfig::authChanged(int sel)
+{
+ pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK);
+ bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP ||
+ sel == AUTH_WPA2_EAP;
+ eapSelect->setEnabled(eap);
+ identityEdit->setEnabled(eap);
+ passwordEdit->setEnabled(eap);
+ cacertEdit->setEnabled(eap);
+
+ while (encrSelect->count())
+ encrSelect->removeItem(0);
+
+ if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) {
+ encrSelect->insertItem("None");
+ encrSelect->insertItem("WEP");
+ encrSelect->setCurrentItem(sel == AUTH_NONE ? 0 : 1);
+ } else {
+ encrSelect->insertItem("TKIP");
+ encrSelect->insertItem("CCMP");
+ encrSelect->setCurrentItem((sel == AUTH_WPA2_PSK ||
+ sel == AUTH_WPA2_EAP) ? 1 : 0);
+ }
+
+ wepEnabled(sel == AUTH_IEEE8021X);
+}
+
+
+void NetworkConfig::addNetwork()
+{
+ char reply[10], cmd[256];
+ size_t reply_len;
+ int id;
+ int psklen = pskEdit->text().length();
+ int auth = authSelect->currentItem();
+
+ if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) {
+ if (psklen < 8 || psklen > 64) {
+ QMessageBox::warning(this, "wpa_gui",
+ "WPA-PSK requires a passphrase "
+ "of 8 to 63 characters\n"
+ "or 64 hex digit PSK");
+ return;
+ }
+ }
+
+ if (wpagui == NULL)
+ return;
+
+ memset(reply, 0, sizeof(reply));
+ reply_len = sizeof(reply) - 1;
+
+ if (new_network) {
+ wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len);
+ if (reply[0] == 'F') {
+ QMessageBox::warning(this, "wpa_gui", "Failed to add "
+ "network to wpa_supplicant\n"
+ "configuration.");
+ return;
+ }
+ id = atoi(reply);
+ } else
+ id = edit_network_id;
+
+ setNetworkParam(id, "ssid", ssidEdit->text().ascii(), true);
+
+ char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL;
+ switch (auth) {
+ case AUTH_NONE:
+ key_mgmt = "NONE";
+ break;
+ case AUTH_IEEE8021X:
+ key_mgmt = "IEEE8021X";
+ break;
+ case AUTH_WPA_PSK:
+ key_mgmt = "WPA-PSK";
+ proto = "WPA";
+ break;
+ case AUTH_WPA_EAP:
+ key_mgmt = "WPA-EAP";
+ proto = "WPA";
+ break;
+ case AUTH_WPA2_PSK:
+ key_mgmt = "WPA-PSK";
+ proto = "WPA2";
+ break;
+ case AUTH_WPA2_EAP:
+ key_mgmt = "WPA-EAP";
+ proto = "WPA2";
+ break;
+ }
+
+ if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP ||
+ auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) {
+ int encr = encrSelect->currentItem();
+ if (encr == 0)
+ pairwise = "TKIP";
+ else
+ pairwise = "CCMP";
+ }
+
+ if (proto)
+ setNetworkParam(id, "proto", proto, false);
+ if (key_mgmt)
+ setNetworkParam(id, "key_mgmt", key_mgmt, false);
+ if (pairwise) {
+ setNetworkParam(id, "pairwise", pairwise, false);
+ setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
+ }
+ if (pskEdit->isEnabled() &&
+ strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
+ setNetworkParam(id, "psk", pskEdit->text().ascii(),
+ psklen != 64);
+ if (eapSelect->isEnabled())
+ setNetworkParam(id, "eap", eapSelect->currentText().ascii(),
+ false);
+ if (identityEdit->isEnabled())
+ setNetworkParam(id, "identity", identityEdit->text().ascii(),
+ true);
+ if (passwordEdit->isEnabled() &&
+ strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
+ setNetworkParam(id, "password", passwordEdit->text().ascii(),
+ true);
+ if (cacertEdit->isEnabled())
+ setNetworkParam(id, "ca_cert", cacertEdit->text().ascii(),
+ true);
+ writeWepKey(id, wep0Edit, 0);
+ writeWepKey(id, wep1Edit, 1);
+ writeWepKey(id, wep2Edit, 2);
+ writeWepKey(id, wep3Edit, 3);
+
+ if (wep0Radio->isEnabled() && wep0Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "0", false);
+ else if (wep1Radio->isEnabled() && wep1Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "1", false);
+ else if (wep2Radio->isEnabled() && wep2Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "2", false);
+ else if (wep3Radio->isEnabled() && wep3Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "3", false);
+
+ snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id);
+ reply_len = sizeof(reply);
+ wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (strncmp(reply, "OK", 2) != 0) {
+ QMessageBox::warning(this, "wpa_gui", "Failed to enable "
+ "network in wpa_supplicant\n"
+ "configuration.");
+ /* Network was added, so continue anyway */
+ }
+ wpagui->triggerUpdate();
+ wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
+
+ close();
+}
+
+
+void NetworkConfig::setWpaGui(WpaGui *_wpagui)
+{
+ wpagui = _wpagui;
+}
+
+
+int NetworkConfig::setNetworkParam(int id, const char *field,
+ const char *value, bool quote)
+{
+ char reply[10], cmd[256];
+ size_t reply_len;
+ snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s",
+ id, field, quote ? "\"" : "", value, quote ? "\"" : "");
+ reply_len = sizeof(reply);
+ wpagui->ctrlRequest(cmd, reply, &reply_len);
+ return strncmp(reply, "OK", 2) == 0 ? 0 : -1;
+}
+
+
+void NetworkConfig::encrChanged(const QString &sel)
+{
+ wepEnabled(sel.find("WEP") == 0);
+}
+
+
+void NetworkConfig::wepEnabled(bool enabled)
+{
+ wep0Edit->setEnabled(enabled);
+ wep1Edit->setEnabled(enabled);
+ wep2Edit->setEnabled(enabled);
+ wep3Edit->setEnabled(enabled);
+ wep0Radio->setEnabled(enabled);
+ wep1Radio->setEnabled(enabled);
+ wep2Radio->setEnabled(enabled);
+ wep3Radio->setEnabled(enabled);
+}
+
+
+void NetworkConfig::writeWepKey(int network_id, QLineEdit *edit, int id)
+{
+ char buf[10];
+ bool hex;
+ const char *txt, *pos;
+ size_t len;
+
+ if (!edit->isEnabled() || edit->text().isEmpty())
+ return;
+
+ /*
+ * Assume hex key if only hex characters are present and length matches
+ * with 40, 104, or 128-bit key
+ */
+ txt = edit->text().ascii();
+ if (strcmp(txt, WPA_GUI_KEY_DATA) == 0)
+ return;
+ len = strlen(txt);
+ if (len == 0)
+ return;
+ pos = txt;
+ hex = true;
+ while (*pos) {
+ if (!((*pos >= '0' && *pos <= '9') ||
+ (*pos >= 'a' && *pos <= 'f') ||
+ (*pos >= 'A' && *pos <= 'F'))) {
+ hex = false;
+ break;
+ }
+ pos++;
+ }
+ if (hex && len != 10 && len != 26 && len != 32)
+ hex = false;
+ snprintf(buf, sizeof(buf), "wep_key%d", id);
+ setNetworkParam(network_id, buf, txt, !hex);
+}
+
+
+static int key_value_isset(const char *reply, size_t reply_len)
+{
+ return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0);
+}
+
+
+void NetworkConfig::paramsFromConfig(int network_id)
+{
+ int i, res;
+
+ edit_network_id = network_id;
+ getEapCapa();
+
+ char reply[1024], cmd[256], *pos;
+ size_t reply_len;
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ ssidEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id);
+ reply_len = sizeof(reply) - 1;
+ int wpa = 0;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
+ reply[reply_len] = '\0';
+ if (strstr(reply, "RSN") || strstr(reply, "WPA2"))
+ wpa = 2;
+ else if (strstr(reply, "WPA"))
+ wpa = 1;
+ }
+
+ int auth = AUTH_NONE, encr = 0;
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
+ reply[reply_len] = '\0';
+ if (strstr(reply, "WPA-EAP"))
+ auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP;
+ else if (strstr(reply, "WPA-PSK"))
+ auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK;
+ else if (strstr(reply, "IEEE8021X")) {
+ auth = AUTH_IEEE8021X;
+ encr = 1;
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
+ reply[reply_len] = '\0';
+ if (strstr(reply, "CCMP"))
+ encr = 1;
+ else if (strstr(reply, "TKIP"))
+ encr = 0;
+ else if (strstr(reply, "WEP"))
+ encr = 1;
+ else
+ encr = 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id);
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ pskEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ pskEdit->setText(WPA_GUI_KEY_DATA);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ identityEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id);
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ passwordEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ passwordEdit->setText(WPA_GUI_KEY_DATA);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ cacertEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 1) {
+ reply[reply_len] = '\0';
+ for (i = 0; i < eapSelect->count(); i++) {
+ if (eapSelect->text(i).compare(reply) == 0) {
+ eapSelect->setCurrentItem(i);
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ QLineEdit *wepEdit;
+ switch (i) {
+ default:
+ case 0:
+ wepEdit = wep0Edit;
+ break;
+ case 1:
+ wepEdit = wep1Edit;
+ break;
+ case 2:
+ wepEdit = wep2Edit;
+ break;
+ case 3:
+ wepEdit = wep3Edit;
+ break;
+ }
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d",
+ network_id, i);
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ encr = 1;
+
+ wepEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ encr = 1;
+ wepEdit->setText(WPA_GUI_KEY_DATA);
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1)
+ {
+ reply[reply_len] = '\0';
+ switch (atoi(reply)) {
+ case 0:
+ wep0Radio->setChecked(true);
+ break;
+ case 1:
+ wep1Radio->setChecked(true);
+ break;
+ case 2:
+ wep2Radio->setChecked(true);
+ break;
+ case 3:
+ wep3Radio->setChecked(true);
+ break;
+ }
+ }
+
+ authSelect->setCurrentItem(auth);
+ authChanged(auth);
+ encrSelect->setCurrentItem(encr);
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ wepEnabled(encr == 1);
+
+ removeButton->setEnabled(true);
+ addButton->setText("Save");
+}
+
+
+void NetworkConfig::removeNetwork()
+{
+ char reply[10], cmd[256];
+ size_t reply_len;
+
+ if (QMessageBox::information(this, "wpa_gui",
+ "This will permanently remove the "
+ "network\n"
+ "from the configuration. Do you really "
+ "want\n"
+ "to remove this network?", "Yes", "No")
+ != 0)
+ return;
+
+ snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id);
+ reply_len = sizeof(reply);
+ wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (strncmp(reply, "OK", 2) != 0) {
+ QMessageBox::warning(this, "wpa_gui",
+ "Failed to remove network from "
+ "wpa_supplicant\n"
+ "configuration.");
+ } else {
+ wpagui->triggerUpdate();
+ wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
+ }
+
+ close();
+}
+
+
+void NetworkConfig::newNetwork()
+{
+ new_network = true;
+ getEapCapa();
+}
+
+
+void NetworkConfig::getEapCapa()
+{
+ char reply[256];
+ size_t reply_len;
+
+ if (wpagui == NULL)
+ return;
+
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0)
+ return;
+ reply[reply_len] = '\0';
+
+ QString res(reply);
+ QStringList types = QStringList::split(QChar(' '), res);
+ eapSelect->insertStringList(types);
+}
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.h b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.h
new file mode 100644
index 000000000000..5a12d70f1f21
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.h
@@ -0,0 +1,58 @@
+/*
+ * wpa_gui - NetworkConfig class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef NETWORKCONFIG_H
+#define NETWORKCONFIG_H
+
+#include <QObject>
+#include "ui_networkconfig.h"
+
+class WpaGui;
+
+class NetworkConfig : public QDialog, public Ui::NetworkConfig
+{
+ Q_OBJECT
+
+public:
+ NetworkConfig(QWidget *parent = 0, const char *name = 0,
+ bool modal = false, Qt::WFlags fl = 0);
+ ~NetworkConfig();
+
+ virtual void paramsFromScanResults(Q3ListViewItem *sel);
+ virtual void setWpaGui(WpaGui *_wpagui);
+ virtual int setNetworkParam(int id, const char *field,
+ const char *value, bool quote);
+ virtual void paramsFromConfig(int network_id);
+ virtual void newNetwork();
+
+public slots:
+ virtual void authChanged(int sel);
+ virtual void addNetwork();
+ virtual void encrChanged(const QString &sel);
+ virtual void writeWepKey(int network_id, QLineEdit *edit, int id);
+ virtual void removeNetwork();
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ WpaGui *wpagui;
+ int edit_network_id;
+ bool new_network;
+
+ virtual void wepEnabled(bool enabled);
+ virtual void getEapCapa();
+};
+
+#endif /* NETWORKCONFIG_H */
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui
index 1f98372f5cd9..6b15da4af69b 100644
--- a/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui
@@ -1,404 +1,335 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>NetworkConfig</class>
-<widget class="QDialog">
- <property name="name">
- <cstring>NetworkConfig</cstring>
+<ui version="4.0" stdsetdef="1" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>NetworkConfig</class>
+ <widget class="QDialog" name="NetworkConfig" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>413</height>
+ </rect>
</property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>380</width>
- <height>413</height>
- </rect>
+ <property name="windowTitle" >
+ <string>NetworkConfig</string>
</property>
- <property name="caption">
- <string>NetworkConfig</string>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QPushButton" row="1" column="3">
- <property name="name">
- <cstring>cancelButton</cstring>
- </property>
- <property name="text">
- <string>Cancel</string>
- </property>
+ <layout class="QGridLayout" >
+ <item row="1" column="3" >
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
</widget>
- <widget class="QFrame" row="0" column="0" rowspan="1" colspan="4">
- <property name="name">
- <cstring>frame9</cstring>
- </property>
- <property name="frameShape">
- <enum>StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>Raised</enum>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
+ </item>
+ <item rowspan="1" row="0" column="0" colspan="4" >
+ <widget class="QFrame" name="frame9" >
+ <property name="frameShape" >
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>Raised</enum>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="textLabel1" >
+ <property name="text" >
+ <string>SSID</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="ssidEdit" >
+ <property name="text" >
+ <string/>
+ </property>
+ <property name="toolTip" stdset="0" >
+ <string>Network name (Service Set IDentifier)</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="textLabel2" >
+ <property name="text" >
+ <string>Authentication</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="authSelect" >
+ <item>
+ <property name="text" >
+ <string>Plaintext or static WEP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>IEEE 802.1X</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WPA-Personal (PSK)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WPA-Enterprise (EAP)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WPA2-Personal (PSK)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WPA2-Enterprise (EAP)</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="textLabel3" >
+ <property name="text" >
+ <string>Encryption</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="encrSelect" >
+ <item>
+ <property name="text" >
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WEP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>TKIP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>CCMP</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="textLabel4" >
+ <property name="text" >
+ <string>PSK</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="pskEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ <property name="toolTip" stdset="0" >
+ <string>WPA/WPA2 pre-shared key or passphrase</string>
+ </property>
+ <property name="whatsThis" stdset="0" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="textLabel5" >
+ <property name="text" >
+ <string>EAP method</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QComboBox" name="eapSelect" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="textLabel6" >
+ <property name="text" >
+ <string>Identity</string>
</property>
- <widget class="QLabel" row="0" column="0">
- <property name="name">
- <cstring>textLabel1</cstring>
- </property>
- <property name="text">
- <string>SSID</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="0" column="1">
- <property name="name">
- <cstring>ssidEdit</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- <property name="toolTip" stdset="0">
- <string>Network name (Service Set IDentifier)</string>
- </property>
- </widget>
- <widget class="QLabel" row="1" column="0">
- <property name="name">
- <cstring>textLabel2</cstring>
- </property>
- <property name="text">
- <string>Authentication</string>
- </property>
- </widget>
- <widget class="QComboBox" row="1" column="1">
- <item>
- <property name="text">
- <string>Plaintext or static WEP</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>IEEE 802.1X</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WPA-Personal (PSK)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WPA-Enterprise (EAP)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WPA2-Personal (PSK)</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WPA2-Enterprise (EAP)</string>
- </property>
- </item>
- <property name="name">
- <cstring>authSelect</cstring>
- </property>
- </widget>
- <widget class="QLabel" row="2" column="0">
- <property name="name">
- <cstring>textLabel3</cstring>
- </property>
- <property name="text">
- <string>Encryption</string>
- </property>
- </widget>
- <widget class="QComboBox" row="2" column="1">
- <item>
- <property name="text">
- <string>None</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>WEP</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>TKIP</string>
- </property>
- </item>
- <item>
- <property name="text">
- <string>CCMP</string>
- </property>
- </item>
- <property name="name">
- <cstring>encrSelect</cstring>
- </property>
- </widget>
- <widget class="QLabel" row="3" column="0">
- <property name="name">
- <cstring>textLabel4</cstring>
- </property>
- <property name="text">
- <string>PSK</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="3" column="1">
- <property name="name">
- <cstring>pskEdit</cstring>
- </property>
- <property name="enabled">
+ </widget>
+ </item>
+ <item row="5" column="1" >
+ <widget class="QLineEdit" name="identityEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0" >
+ <string>Username/Identity for EAP methods</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0" >
+ <widget class="QLabel" name="textLabel7" >
+ <property name="text" >
+ <string>Password</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1" >
+ <widget class="QLineEdit" name="passwordEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ <property name="toolTip" stdset="0" >
+ <string>Password for EAP methods</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0" >
+ <widget class="QLabel" name="textLabel1_2" >
+ <property name="text" >
+ <string>CA certificate</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1" >
+ <widget class="QLineEdit" name="cacertEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item rowspan="1" row="8" column="0" colspan="2" >
+ <widget class="QGroupBox" name="buttonGroup1" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ <property name="title" >
+ <string>WEP keys</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QRadioButton" name="wep0Radio" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>key 0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QRadioButton" name="wep1Radio" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>key 1</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QRadioButton" name="wep3Radio" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>key 3</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QRadioButton" name="wep2Radio" >
+ <property name="enabled" >
<bool>false</bool>
- </property>
- <property name="echoMode">
- <enum>Password</enum>
- </property>
- <property name="toolTip" stdset="0">
- <string>WPA/WPA2 pre-shared key or passphrase</string>
- </property>
- <property name="whatsThis" stdset="0">
- <string></string>
- </property>
- </widget>
- <widget class="QLabel" row="4" column="0">
- <property name="name">
- <cstring>textLabel5</cstring>
- </property>
- <property name="text">
- <string>EAP method</string>
- </property>
- </widget>
- <widget class="QComboBox" row="4" column="1">
- <property name="name">
- <cstring>eapSelect</cstring>
- </property>
- <property name="enabled">
+ </property>
+ <property name="text" >
+ <string>key 2</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="wep0Edit" >
+ <property name="enabled" >
<bool>false</bool>
- </property>
- </widget>
- <widget class="QLabel" row="5" column="0">
- <property name="name">
- <cstring>textLabel6</cstring>
- </property>
- <property name="text">
- <string>Identity</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="5" column="1">
- <property name="name">
- <cstring>identityEdit</cstring>
- </property>
- <property name="enabled">
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="wep1Edit" >
+ <property name="enabled" >
<bool>false</bool>
- </property>
- <property name="toolTip" stdset="0">
- <string>Username/Identity for EAP methods</string>
- </property>
- </widget>
- <widget class="QLabel" row="6" column="0">
- <property name="name">
- <cstring>textLabel7</cstring>
- </property>
- <property name="text">
- <string>Password</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="6" column="1">
- <property name="name">
- <cstring>passwordEdit</cstring>
- </property>
- <property name="enabled">
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="wep2Edit" >
+ <property name="enabled" >
<bool>false</bool>
- </property>
- <property name="echoMode">
- <enum>Password</enum>
- </property>
- <property name="toolTip" stdset="0">
- <string>Password for EAP methods</string>
- </property>
- </widget>
- <widget class="QLabel" row="7" column="0">
- <property name="name">
- <cstring>textLabel1_2</cstring>
- </property>
- <property name="text">
- <string>CA certificate</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="7" column="1">
- <property name="name">
- <cstring>cacertEdit</cstring>
- </property>
- <property name="enabled">
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="wep3Edit" >
+ <property name="enabled" >
<bool>false</bool>
- </property>
- </widget>
- <widget class="QButtonGroup" row="8" column="0" rowspan="1" colspan="2">
- <property name="name">
- <cstring>buttonGroup1</cstring>
- </property>
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="title">
- <string>WEP keys</string>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QRadioButton" row="0" column="0">
- <property name="name">
- <cstring>wep0Radio</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>key 0</string>
- </property>
- </widget>
- <widget class="QRadioButton" row="1" column="0">
- <property name="name">
- <cstring>wep1Radio</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>key 1</string>
- </property>
- </widget>
- <widget class="QRadioButton" row="3" column="0">
- <property name="name">
- <cstring>wep3Radio</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>key 3</string>
- </property>
- </widget>
- <widget class="QRadioButton" row="2" column="0">
- <property name="name">
- <cstring>wep2Radio</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>key 2</string>
- </property>
- </widget>
- <widget class="QLineEdit" row="0" column="1">
- <property name="name">
- <cstring>wep0Edit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLineEdit" row="1" column="1">
- <property name="name">
- <cstring>wep1Edit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLineEdit" row="2" column="1">
- <property name="name">
- <cstring>wep2Edit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- <widget class="QLineEdit" row="3" column="1">
- <property name="name">
- <cstring>wep3Edit</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- </widget>
- </grid>
- </widget>
- </grid>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
</widget>
- <spacer row="1" column="0">
- <property name="name">
- <cstring>spacer5</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>130</width>
- <height>20</height>
- </size>
- </property>
+ </item>
+ <item row="1" column="0" >
+ <spacer name="spacer5" >
+ <property name="sizeHint" >
+ <size>
+ <width>130</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="sizeType" >
+ <enum>Expanding</enum>
+ </property>
+ <property name="orientation" >
+ <enum>Horizontal</enum>
+ </property>
</spacer>
- <widget class="QPushButton" row="1" column="1">
- <property name="name">
- <cstring>addButton</cstring>
- </property>
- <property name="text">
- <string>Add</string>
- </property>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="addButton" >
+ <property name="text" >
+ <string>Add</string>
+ </property>
</widget>
- <widget class="QPushButton" row="1" column="2">
- <property name="name">
- <cstring>removeButton</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Remove</string>
- </property>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="removeButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Remove</string>
+ </property>
</widget>
- </grid>
-</widget>
-<connections>
- <connection>
- <sender>authSelect</sender>
- <signal>activated(int)</signal>
- <receiver>NetworkConfig</receiver>
- <slot>authChanged(int)</slot>
- </connection>
- <connection>
- <sender>cancelButton</sender>
- <signal>clicked()</signal>
- <receiver>NetworkConfig</receiver>
- <slot>close()</slot>
- </connection>
- <connection>
- <sender>addButton</sender>
- <signal>clicked()</signal>
- <receiver>NetworkConfig</receiver>
- <slot>addNetwork()</slot>
- </connection>
- <connection>
- <sender>encrSelect</sender>
- <signal>activated(const QString&amp;)</signal>
- <receiver>NetworkConfig</receiver>
- <slot>encrChanged(const QString&amp;)</slot>
- </connection>
- <connection>
- <sender>removeButton</sender>
- <signal>clicked()</signal>
- <receiver>NetworkConfig</receiver>
- <slot>removeNetwork()</slot>
- </connection>
-</connections>
-<tabstops>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
+ <tabstops>
<tabstop>ssidEdit</tabstop>
<tabstop>authSelect</tabstop>
<tabstop>encrSelect</tabstop>
@@ -418,38 +349,8 @@
<tabstop>addButton</tabstop>
<tabstop>removeButton</tabstop>
<tabstop>cancelButton</tabstop>
-</tabstops>
-<includes>
- <include location="global" impldecl="in declaration">qlistview.h</include>
- <include location="global" impldecl="in implementation">qmessagebox.h</include>
- <include location="local" impldecl="in implementation">wpagui.h</include>
- <include location="local" impldecl="in implementation">networkconfig.ui.h</include>
-</includes>
-<forwards>
- <forward>class WpaGui;</forward>
-</forwards>
-<variables>
- <variable access="private">WpaGui *wpagui;</variable>
- <variable access="private">int edit_network_id;</variable>
- <variable access="private">bool new_network;</variable>
-</variables>
-<slots>
- <slot>authChanged( int sel )</slot>
- <slot>addNetwork()</slot>
- <slot>encrChanged( const QString &amp; sel )</slot>
- <slot>writeWepKey( int network_id, QLineEdit * edit, int id )</slot>
- <slot>removeNetwork()</slot>
-</slots>
-<functions>
- <function access="private" specifier="non virtual">init()</function>
- <function>paramsFromScanResults( QListViewItem * sel )</function>
- <function>setWpaGui( WpaGui * _wpagui )</function>
- <function returnType="int">setNetworkParam( int id, const char * field, const char * value, bool quote )</function>
- <function access="private">wepEnabled( bool enabled )</function>
- <function>paramsFromConfig( int network_id )</function>
- <function>newNetwork()</function>
- <function access="private">getEapCapa()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
+ </tabstops>
+ <includes>
+ <include location="global" >q3listview.h</include>
+ </includes>
+</ui>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
new file mode 100644
index 000000000000..57cf71637ce9
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
@@ -0,0 +1,124 @@
+/*
+ * wpa_gui - ScanResults class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <QTimer>
+
+#include "scanresults.h"
+#include "wpagui.h"
+#include "networkconfig.h"
+
+
+ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WFlags)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
+ connect(scanButton, SIGNAL(clicked()), this, SLOT(scanRequest()));
+ connect(scanResultsView, SIGNAL(doubleClicked(Q3ListViewItem *)), this,
+ SLOT(bssSelected(Q3ListViewItem *)));
+
+ wpagui = NULL;
+}
+
+
+ScanResults::~ScanResults()
+{
+ delete timer;
+}
+
+
+void ScanResults::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+void ScanResults::setWpaGui(WpaGui *_wpagui)
+{
+ wpagui = _wpagui;
+ updateResults();
+
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), SLOT(getResults()));
+ timer->start(10000, FALSE);
+}
+
+
+void ScanResults::updateResults()
+{
+ char reply[8192];
+ size_t reply_len;
+
+ if (wpagui == NULL)
+ return;
+
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest("SCAN_RESULTS", reply, &reply_len) < 0)
+ return;
+ reply[reply_len] = '\0';
+
+ scanResultsView->clear();
+
+ QString res(reply);
+ QStringList lines = QStringList::split(QChar('\n'), res);
+ bool first = true;
+ for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++)
+ {
+ if (first) {
+ first = false;
+ continue;
+ }
+
+ QStringList cols = QStringList::split(QChar('\t'), *it, true);
+ QString ssid, bssid, freq, signal, flags;
+ bssid = cols.count() > 0 ? cols[0] : "";
+ freq = cols.count() > 1 ? cols[1] : "";
+ signal = cols.count() > 2 ? cols[2] : "";
+ flags = cols.count() > 3 ? cols[3] : "";
+ ssid = cols.count() > 4 ? cols[4] : "";
+ new Q3ListViewItem(scanResultsView, ssid, bssid, freq, signal,
+ flags);
+ }
+}
+
+
+void ScanResults::scanRequest()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (wpagui == NULL)
+ return;
+
+ wpagui->ctrlRequest("SCAN", reply, &reply_len);
+}
+
+
+void ScanResults::getResults()
+{
+ updateResults();
+}
+
+
+void ScanResults::bssSelected( Q3ListViewItem * sel )
+{
+ NetworkConfig *nc = new NetworkConfig();
+ if (nc == NULL)
+ return;
+ nc->setWpaGui(wpagui);
+ nc->paramsFromScanResults(sel);
+ nc->show();
+ nc->exec();
+}
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.h b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.h
new file mode 100644
index 000000000000..22b54c9b49e6
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.h
@@ -0,0 +1,47 @@
+/*
+ * wpa_gui - ScanResults class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef SCANRESULTS_H
+#define SCANRESULTS_H
+
+#include <QObject>
+#include "ui_scanresults.h"
+
+class WpaGui;
+
+class ScanResults : public QDialog, public Ui::ScanResults
+{
+ Q_OBJECT
+
+public:
+ ScanResults(QWidget *parent = 0, const char *name = 0,
+ bool modal = false, Qt::WFlags fl = 0);
+ ~ScanResults();
+
+public slots:
+ virtual void setWpaGui(WpaGui *_wpagui);
+ virtual void updateResults();
+ virtual void scanRequest();
+ virtual void getResults();
+ virtual void bssSelected(Q3ListViewItem *sel);
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ WpaGui *wpagui;
+ QTimer *timer;
+};
+
+#endif /* SCANRESULTS_H */
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui
index 66c8b4b76f32..4a49b05ca8ae 100644
--- a/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui
@@ -1,179 +1,125 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>ScanResults</class>
-<widget class="QDialog">
- <property name="name">
- <cstring>ScanResults</cstring>
+<ui version="4.0" stdsetdef="1" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>ScanResults</class>
+ <widget class="QDialog" name="ScanResults" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>452</width>
+ <height>225</height>
+ </rect>
</property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>452</width>
- <height>225</height>
- </rect>
+ <property name="windowTitle" >
+ <string>Scan results</string>
</property>
- <property name="caption">
- <string>Scan results</string>
- </property>
- <vbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QListView">
- <column>
- <property name="text">
- <string>SSID</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>BSSID</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>frequency</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>signal</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <column>
- <property name="text">
- <string>flags</string>
- </property>
- <property name="clickable">
- <bool>true</bool>
- </property>
- <property name="resizable">
- <bool>true</bool>
- </property>
- </column>
- <property name="name">
- <cstring>scanResultsView</cstring>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="Q3ListView" name="scanResultsView" >
+ <property name="frameShape" >
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Sunken</enum>
+ </property>
+ <column>
+ <property name="text" >
+ <string>SSID</string>
</property>
- <property name="frameShape">
- <enum>StyledPanel</enum>
+ <property name="clickable" >
+ <bool>true</bool>
</property>
- <property name="frameShadow">
- <enum>Sunken</enum>
+ <property name="resizable" >
+ <bool>true</bool>
</property>
- </widget>
- <widget class="QLayoutWidget">
- <property name="name">
- <cstring>layout24</cstring>
+ </column>
+ <column>
+ <property name="text" >
+ <string>BSSID</string>
+ </property>
+ <property name="clickable" >
+ <bool>true</bool>
+ </property>
+ <property name="resizable" >
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>frequency</string>
+ </property>
+ <property name="clickable" >
+ <bool>true</bool>
+ </property>
+ <property name="resizable" >
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>signal</string>
+ </property>
+ <property name="clickable" >
+ <bool>true</bool>
+ </property>
+ <property name="resizable" >
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>flags</string>
+ </property>
+ <property name="clickable" >
+ <bool>true</bool>
+ </property>
+ <property name="resizable" >
+ <bool>true</bool>
</property>
- <hbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <spacer>
- <property name="name">
- <cstring>spacer6</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>50</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- <widget class="QPushButton">
- <property name="name">
- <cstring>scanButton</cstring>
- </property>
- <property name="text">
- <string>Scan</string>
- </property>
- </widget>
- <widget class="QPushButton">
- <property name="name">
- <cstring>closeButton</cstring>
- </property>
- <property name="text">
- <string>Close</string>
- </property>
- </widget>
- </hbox>
+ </column>
</widget>
- </vbox>
-</widget>
-<connections>
- <connection>
- <sender>closeButton</sender>
- <signal>clicked()</signal>
- <receiver>ScanResults</receiver>
- <slot>close()</slot>
- </connection>
- <connection>
- <sender>scanButton</sender>
- <signal>clicked()</signal>
- <receiver>ScanResults</receiver>
- <slot>scanRequest()</slot>
- </connection>
- <connection>
- <sender>scanResultsView</sender>
- <signal>doubleClicked(QListViewItem*)</signal>
- <receiver>ScanResults</receiver>
- <slot>bssSelected(QListViewItem*)</slot>
- </connection>
-</connections>
-<includes>
- <include location="local" impldecl="in implementation">wpa_ctrl.h</include>
- <include location="local" impldecl="in implementation">wpagui.h</include>
- <include location="local" impldecl="in implementation">networkconfig.h</include>
- <include location="local" impldecl="in implementation">scanresults.ui.h</include>
-</includes>
-<forwards>
- <forward>class WpaGui;</forward>
-</forwards>
-<variables>
- <variable access="private">WpaGui *wpagui;</variable>
- <variable access="private">QTimer *timer;</variable>
-</variables>
-<slots>
- <slot>setWpaGui( WpaGui * _wpagui )</slot>
- <slot>updateResults()</slot>
- <slot>scanRequest()</slot>
- <slot>getResults()</slot>
- <slot>bssSelected( QListViewItem * sel )</slot>
-</slots>
-<functions>
- <function access="private" specifier="non virtual">init()</function>
- <function access="private" specifier="non virtual">destroy()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="spacer6" >
+ <property name="sizeHint" >
+ <size>
+ <width>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="sizeType" >
+ <enum>Expanding</enum>
+ </property>
+ <property name="orientation" >
+ <enum>Horizontal</enum>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="scanButton" >
+ <property name="text" >
+ <string>Scan</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
+</ui>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp
new file mode 100644
index 000000000000..e198955b4d93
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp
@@ -0,0 +1,100 @@
+/*
+ * wpa_gui - UserDataRequest class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "userdatarequest.h"
+#include "wpagui.h"
+#include "wpa_ctrl.h"
+
+
+UserDataRequest::UserDataRequest(QWidget *parent, const char *, bool,
+ Qt::WFlags)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ connect(buttonOk, SIGNAL(clicked()), this, SLOT(sendReply()));
+ connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(queryEdit, SIGNAL(returnPressed()), this, SLOT(sendReply()));
+}
+
+
+UserDataRequest::~UserDataRequest()
+{
+}
+
+
+void UserDataRequest::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg)
+{
+ char *tmp, *pos, *pos2;
+ wpagui = _wpagui;
+ tmp = strdup(reqMsg);
+ if (tmp == NULL)
+ return -1;
+ pos = strchr(tmp, '-');
+ if (pos == NULL) {
+ free(tmp);
+ return -1;
+ }
+ *pos++ = '\0';
+ field = tmp;
+ pos2 = strchr(pos, ':');
+ if (pos2 == NULL) {
+ free(tmp);
+ return -1;
+ }
+ *pos2++ = '\0';
+
+ networkid = atoi(pos);
+ queryInfo->setText(pos2);
+ if (strcmp(tmp, "PASSWORD") == 0) {
+ queryField->setText("Password: ");
+ queryEdit->setEchoMode(QLineEdit::Password);
+ } else if (strcmp(tmp, "NEW_PASSWORD") == 0) {
+ queryField->setText("New password: ");
+ queryEdit->setEchoMode(QLineEdit::Password);
+ } else if (strcmp(tmp, "IDENTITY") == 0)
+ queryField->setText("Identity: ");
+ else if (strcmp(tmp, "PASSPHRASE") == 0) {
+ queryField->setText("Private key passphrase: ");
+ queryEdit->setEchoMode(QLineEdit::Password);
+ } else
+ queryField->setText(field + ":");
+ free(tmp);
+
+ return 0;
+}
+
+
+void UserDataRequest::sendReply()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (wpagui == NULL) {
+ reject();
+ return;
+ }
+
+ QString cmd = QString(WPA_CTRL_RSP) + field + '-' +
+ QString::number(networkid) + ':' +
+ queryEdit->text();
+ wpagui->ctrlRequest(cmd.ascii(), reply, &reply_len);
+ accept();
+}
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.h b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
new file mode 100644
index 000000000000..2b6e8371bc65
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
@@ -0,0 +1,46 @@
+/*
+ * wpa_gui - UserDataRequest class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef USERDATAREQUEST_H
+#define USERDATAREQUEST_H
+
+#include <QObject>
+#include "ui_userdatarequest.h"
+
+class WpaGui;
+
+class UserDataRequest : public QDialog, public Ui::UserDataRequest
+{
+ Q_OBJECT
+
+public:
+ UserDataRequest(QWidget *parent = 0, const char *name = 0,
+ bool modal = false, Qt::WFlags fl = 0);
+ ~UserDataRequest();
+
+ int setParams(WpaGui *_wpagui, const char *reqMsg);
+
+public slots:
+ virtual void sendReply();
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ WpaGui *wpagui;
+ int networkid;
+ QString field;
+};
+
+#endif /* USERDATAREQUEST_H */
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui
index c3d545fa620a..ea0172194987 100644
--- a/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui
@@ -1,163 +1,109 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>UserDataRequest</class>
-<widget class="QDialog">
- <property name="name">
- <cstring>UserDataRequest</cstring>
+<ui version="4.0" stdsetdef="1" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>UserDataRequest</class>
+ <widget class="QDialog" name="UserDataRequest" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>216</width>
+ <height>103</height>
+ </rect>
</property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>216</width>
- <height>103</height>
- </rect>
+ <property name="windowTitle" >
+ <string>Authentication credentials required</string>
</property>
- <property name="caption">
- <string>Authentication credentials required</string>
+ <property name="sizeGripEnabled" >
+ <bool>true</bool>
</property>
- <property name="sizeGripEnabled">
- <bool>true</bool>
- </property>
- <vbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QLabel">
- <property name="name">
- <cstring>queryInfo</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLayoutWidget">
- <property name="name">
- <cstring>layout28</cstring>
- </property>
- <hbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QLabel">
- <property name="name">
- <cstring>queryField</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
- </widget>
- <widget class="QLineEdit">
- <property name="name">
- <cstring>queryEdit</cstring>
- </property>
- <property name="enabled">
- <bool>true</bool>
- </property>
- <property name="echoMode">
- <enum>Password</enum>
- </property>
- </widget>
- </hbox>
- </widget>
- <widget class="QLayoutWidget">
- <property name="name">
- <cstring>layout27</cstring>
- </property>
- <hbox>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <spacer>
- <property name="name">
- <cstring>spacer4</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>20</width>
- <height>20</height>
- </size>
- </property>
- </spacer>
- <widget class="QPushButton">
- <property name="name">
- <cstring>buttonOk</cstring>
- </property>
- <property name="text">
- <string>&amp;OK</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
- <property name="autoDefault">
- <bool>true</bool>
- </property>
- <property name="default">
- <bool>true</bool>
- </property>
- </widget>
- <widget class="QPushButton">
- <property name="name">
- <cstring>buttonCancel</cstring>
- </property>
- <property name="text">
- <string>&amp;Cancel</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
- <property name="autoDefault">
- <bool>true</bool>
- </property>
- </widget>
- </hbox>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QLabel" name="queryInfo" >
+ <property name="text" >
+ <string/>
+ </property>
</widget>
- </vbox>
-</widget>
-<connections>
- <connection>
- <sender>buttonOk</sender>
- <signal>clicked()</signal>
- <receiver>UserDataRequest</receiver>
- <slot>sendReply()</slot>
- </connection>
- <connection>
- <sender>buttonCancel</sender>
- <signal>clicked()</signal>
- <receiver>UserDataRequest</receiver>
- <slot>reject()</slot>
- </connection>
- <connection>
- <sender>queryEdit</sender>
- <signal>returnPressed()</signal>
- <receiver>UserDataRequest</receiver>
- <slot>sendReply()</slot>
- </connection>
-</connections>
-<includes>
- <include location="local" impldecl="in implementation">wpa_ctrl.h</include>
- <include location="local" impldecl="in implementation">wpagui.h</include>
- <include location="local" impldecl="in implementation">userdatarequest.ui.h</include>
-</includes>
-<forwards>
- <forward>class WpaGui;</forward>
-</forwards>
-<variables>
- <variable access="private">WpaGui *wpagui;</variable>
- <variable access="private">int networkid;</variable>
- <variable access="private">QString field;</variable>
-</variables>
-<slots>
- <slot>sendReply()</slot>
-</slots>
-<functions>
- <function specifier="non virtual" returnType="int">setParams( WpaGui * _wpagui, const char * reqMsg )</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="queryField" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="queryEdit" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="spacer4" >
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="sizeType" >
+ <enum>Expanding</enum>
+ </property>
+ <property name="orientation" >
+ <enum>Horizontal</enum>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonOk" >
+ <property name="text" >
+ <string>&amp;OK</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonCancel" >
+ <property name="text" >
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
+</ui>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
index a1ad0ee09ab8..0d1c32b5714c 100644
--- a/contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
@@ -3,20 +3,34 @@ LANGUAGE = C++
CONFIG += qt warn_on release
+DEFINES += CONFIG_CTRL_IFACE
+
win32 {
LIBS += -lws2_32 -static
- DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_UDP
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
} else:win32-g++ {
# cross compilation to win32
LIBS += -lws2_32 -static
- DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_UDP
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
+} else {
+ DEFINES += CONFIG_CTRL_IFACE_UNIX
}
-INCLUDEPATH += . ..
+INCLUDEPATH += . .. ../../hostapd
-HEADERS += wpamsg.h
+HEADERS += wpamsg.h \
+ wpagui.h \
+ eventhistory.h \
+ scanresults.h \
+ userdatarequest.h \
+ networkconfig.h
SOURCES += main.cpp \
+ wpagui.cpp \
+ eventhistory.cpp \
+ scanresults.cpp \
+ userdatarequest.cpp \
+ networkconfig.cpp \
../wpa_ctrl.c
FORMS = wpagui.ui \
@@ -32,10 +46,5 @@ unix {
OBJECTS_DIR = .obj
}
-
-
-#The following line was inserted by qt3to4
-QT += qt3support
-#The following line was inserted by qt3to4
-CONFIG += uic3
-
+# TODO: remove need for Qt3 support code
+QT += qt3support
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
new file mode 100644
index 000000000000..1dc7af240d5b
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -0,0 +1,779 @@
+/*
+ * wpa_gui - WpaGui class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifdef __MINGW32__
+/* Need to get getopt() */
+#include <unistd.h>
+#endif
+
+#include <QMessageBox>
+
+#include "wpagui.h"
+#include "dirent.h"
+#include "wpa_ctrl.h"
+#include "userdatarequest.h"
+#include "networkconfig.h"
+
+WpaGui::WpaGui(QWidget *parent, const char *, Qt::WFlags)
+ : QMainWindow(parent)
+{
+ setupUi(this);
+
+ (void) statusBar();
+
+ connect(helpIndexAction, SIGNAL(activated()), this, SLOT(helpIndex()));
+ connect(helpContentsAction, SIGNAL(activated()), this,
+ SLOT(helpContents()));
+ connect(helpAboutAction, SIGNAL(activated()), this, SLOT(helpAbout()));
+ connect(fileExitAction, SIGNAL(activated()), this, SLOT(close()));
+ connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
+ connect(scanButton, SIGNAL(clicked()), this, SLOT(scan()));
+ connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB()));
+ connect(fileEventHistoryAction, SIGNAL(activated()), this,
+ SLOT(eventHistory()));
+ connect(networkSelect, SIGNAL(activated(const QString&)), this,
+ SLOT(selectNetwork(const QString&)));
+ connect(fileEdit_networkAction, SIGNAL(activated()), this,
+ SLOT(editNetwork()));
+ connect(fileAdd_NetworkAction, SIGNAL(activated()), this,
+ SLOT(addNetwork()));
+ connect(adapterSelect, SIGNAL(activated(const QString&)), this,
+ SLOT(selectAdapter(const QString&)));
+
+ eh = NULL;
+ scanres = NULL;
+ udr = NULL;
+ ctrl_iface = NULL;
+ ctrl_conn = NULL;
+ monitor_conn = NULL;
+ msgNotifier = NULL;
+ ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
+
+ parse_argv();
+
+ textStatus->setText("connecting to wpa_supplicant");
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), SLOT(ping()));
+ timer->start(1000, FALSE);
+
+ if (openCtrlConnection(ctrl_iface) < 0) {
+ printf("Failed to open control connection to "
+ "wpa_supplicant.\n");
+ }
+
+ updateStatus();
+ networkMayHaveChanged = true;
+ updateNetworks();
+}
+
+
+WpaGui::~WpaGui()
+{
+ delete msgNotifier;
+
+ if (monitor_conn) {
+ wpa_ctrl_detach(monitor_conn);
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ }
+ if (ctrl_conn) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ }
+
+ if (eh) {
+ eh->close();
+ delete eh;
+ eh = NULL;
+ }
+
+ if (scanres) {
+ scanres->close();
+ delete scanres;
+ scanres = NULL;
+ }
+
+ if (udr) {
+ udr->close();
+ delete udr;
+ udr = NULL;
+ }
+
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+
+ free(ctrl_iface_dir);
+ ctrl_iface_dir = NULL;
+}
+
+
+void WpaGui::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+void WpaGui::parse_argv()
+{
+ int c;
+ for (;;) {
+ c = getopt(qApp->argc(), qApp->argv(), "i:p:");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'i':
+ free(ctrl_iface);
+ ctrl_iface = strdup(optarg);
+ break;
+ case 'p':
+ free(ctrl_iface_dir);
+ ctrl_iface_dir = strdup(optarg);
+ break;
+ }
+ }
+}
+
+
+int WpaGui::openCtrlConnection(const char *ifname)
+{
+ char *cfile;
+ int flen;
+ char buf[2048], *pos, *pos2;
+ size_t len;
+
+ if (ifname) {
+ if (ifname != ctrl_iface) {
+ free(ctrl_iface);
+ ctrl_iface = strdup(ifname);
+ }
+ } else {
+#ifdef CONFIG_CTRL_IFACE_UDP
+ free(ctrl_iface);
+ ctrl_iface = strdup("udp");
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ struct dirent *dent;
+ DIR *dir = opendir(ctrl_iface_dir);
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+ if (dir) {
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket.
+ * Also accept DT_UNKNOWN (0) in case
+ * the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK &&
+ dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ printf("Selected interface '%s'\n",
+ dent->d_name);
+ ctrl_iface = strdup(dent->d_name);
+ break;
+ }
+ closedir(dir);
+ }
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ struct wpa_ctrl *ctrl;
+ int ret;
+
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+
+ ctrl = wpa_ctrl_open(NULL);
+ if (ctrl) {
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
+ &len, NULL);
+ if (ret >= 0) {
+ buf[len] = '\0';
+ pos = strchr(buf, '\n');
+ if (pos)
+ *pos = '\0';
+ ctrl_iface = strdup(buf);
+ }
+ wpa_ctrl_close(ctrl);
+ }
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+ }
+
+ if (ctrl_iface == NULL)
+ return -1;
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
+ cfile = (char *) malloc(flen);
+ if (cfile == NULL)
+ return -1;
+ snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
+#else /* CONFIG_CTRL_IFACE_UNIX */
+ flen = strlen(ctrl_iface) + 1;
+ cfile = (char *) malloc(flen);
+ if (cfile == NULL)
+ return -1;
+ snprintf(cfile, flen, "%s", ctrl_iface);
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+ if (ctrl_conn) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ }
+
+ if (monitor_conn) {
+ delete msgNotifier;
+ msgNotifier = NULL;
+ wpa_ctrl_detach(monitor_conn);
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ }
+
+ printf("Trying to connect to '%s'\n", cfile);
+ ctrl_conn = wpa_ctrl_open(cfile);
+ if (ctrl_conn == NULL) {
+ free(cfile);
+ return -1;
+ }
+ monitor_conn = wpa_ctrl_open(cfile);
+ free(cfile);
+ if (monitor_conn == NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ return -1;
+ }
+ if (wpa_ctrl_attach(monitor_conn)) {
+ printf("Failed to attach to wpa_supplicant\n");
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ return -1;
+ }
+
+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
+ msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
+ QSocketNotifier::Read, this);
+ connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
+#endif
+
+ adapterSelect->clear();
+ adapterSelect->insertItem(ctrl_iface);
+ adapterSelect->setCurrentItem(0);
+
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
+ 0) {
+ buf[len] = '\0';
+ pos = buf;
+ while (*pos) {
+ pos2 = strchr(pos, '\n');
+ if (pos2)
+ *pos2 = '\0';
+ if (strcmp(pos, ctrl_iface) != 0)
+ adapterSelect->insertItem(pos);
+ if (pos2)
+ pos = pos2 + 1;
+ else
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static void wpa_gui_msg_cb(char *msg, size_t)
+{
+ /* This should not happen anymore since two control connections are
+ * used. */
+ printf("missed message: %s\n", msg);
+}
+
+
+int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
+{
+ int ret;
+
+ if (ctrl_conn == NULL)
+ return -3;
+ ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
+ wpa_gui_msg_cb);
+ if (ret == -2)
+ printf("'%s' command timed out.\n", cmd);
+ else if (ret < 0)
+ printf("'%s' command failed.\n", cmd);
+
+ return ret;
+}
+
+
+void WpaGui::updateStatus()
+{
+ char buf[2048], *start, *end, *pos;
+ size_t len;
+
+ pingsToStatusUpdate = 10;
+
+ len = sizeof(buf) - 1;
+ if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
+ textStatus->setText("Could not get status from "
+ "wpa_supplicant");
+ textAuthentication->clear();
+ textEncryption->clear();
+ textSsid->clear();
+ textBssid->clear();
+ textIpAddress->clear();
+ return;
+ }
+
+ buf[len] = '\0';
+
+ bool auth_updated = false, ssid_updated = false;
+ bool bssid_updated = false, ipaddr_updated = false;
+ bool status_updated = false;
+ char *pairwise_cipher = NULL, *group_cipher = NULL;
+
+ start = buf;
+ while (*start) {
+ bool last = false;
+ end = strchr(start, '\n');
+ if (end == NULL) {
+ last = true;
+ end = start;
+ while (end[0] && end[1])
+ end++;
+ }
+ *end = '\0';
+
+ pos = strchr(start, '=');
+ if (pos) {
+ *pos++ = '\0';
+ if (strcmp(start, "bssid") == 0) {
+ bssid_updated = true;
+ textBssid->setText(pos);
+ } else if (strcmp(start, "ssid") == 0) {
+ ssid_updated = true;
+ textSsid->setText(pos);
+ } else if (strcmp(start, "ip_address") == 0) {
+ ipaddr_updated = true;
+ textIpAddress->setText(pos);
+ } else if (strcmp(start, "wpa_state") == 0) {
+ status_updated = true;
+ textStatus->setText(pos);
+ } else if (strcmp(start, "key_mgmt") == 0) {
+ auth_updated = true;
+ textAuthentication->setText(pos);
+ /* TODO: could add EAP status to this */
+ } else if (strcmp(start, "pairwise_cipher") == 0) {
+ pairwise_cipher = pos;
+ } else if (strcmp(start, "group_cipher") == 0) {
+ group_cipher = pos;
+ }
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+
+ if (pairwise_cipher || group_cipher) {
+ QString encr;
+ if (pairwise_cipher && group_cipher &&
+ strcmp(pairwise_cipher, group_cipher) != 0) {
+ encr.append(pairwise_cipher);
+ encr.append(" + ");
+ encr.append(group_cipher);
+ } else if (pairwise_cipher) {
+ encr.append(pairwise_cipher);
+ } else if (group_cipher) {
+ encr.append(group_cipher);
+ encr.append(" [group key only]");
+ } else {
+ encr.append("?");
+ }
+ textEncryption->setText(encr);
+ } else
+ textEncryption->clear();
+
+ if (!status_updated)
+ textStatus->clear();
+ if (!auth_updated)
+ textAuthentication->clear();
+ if (!ssid_updated)
+ textSsid->clear();
+ if (!bssid_updated)
+ textBssid->clear();
+ if (!ipaddr_updated)
+ textIpAddress->clear();
+}
+
+
+void WpaGui::updateNetworks()
+{
+ char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
+ size_t len;
+ int first_active = -1;
+ bool selected = false;
+
+ if (!networkMayHaveChanged)
+ return;
+
+ networkSelect->clear();
+
+ if (ctrl_conn == NULL)
+ return;
+
+ len = sizeof(buf) - 1;
+ if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
+ return;
+
+ buf[len] = '\0';
+ start = strchr(buf, '\n');
+ if (start == NULL)
+ return;
+ start++;
+
+ while (*start) {
+ bool last = false;
+ end = strchr(start, '\n');
+ if (end == NULL) {
+ last = true;
+ end = start;
+ while (end[0] && end[1])
+ end++;
+ }
+ *end = '\0';
+
+ id = start;
+ ssid = strchr(id, '\t');
+ if (ssid == NULL)
+ break;
+ *ssid++ = '\0';
+ bssid = strchr(ssid, '\t');
+ if (bssid == NULL)
+ break;
+ *bssid++ = '\0';
+ flags = strchr(bssid, '\t');
+ if (flags == NULL)
+ break;
+ *flags++ = '\0';
+
+ QString network(id);
+ network.append(": ");
+ network.append(ssid);
+ networkSelect->insertItem(network);
+
+ if (strstr(flags, "[CURRENT]")) {
+ networkSelect->setCurrentItem(networkSelect->count() -
+ 1);
+ selected = true;
+ } else if (first_active < 0 &&
+ strstr(flags, "[DISABLED]") == NULL)
+ first_active = networkSelect->count() - 1;
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+
+ if (!selected && first_active >= 0)
+ networkSelect->setCurrentItem(first_active);
+
+ networkMayHaveChanged = false;
+}
+
+
+void WpaGui::helpIndex()
+{
+ printf("helpIndex\n");
+}
+
+
+void WpaGui::helpContents()
+{
+ printf("helpContents\n");
+}
+
+
+void WpaGui::helpAbout()
+{
+ QMessageBox::about(this, "wpa_gui for wpa_supplicant",
+ "Copyright (c) 2003-2006,\n"
+ "Jouni Malinen <j@w1.fi>\n"
+ "and contributors.\n"
+ "\n"
+ "This program is free software. You can\n"
+ "distribute it and/or modify it under the terms "
+ "of\n"
+ "the GNU General Public License version 2.\n"
+ "\n"
+ "Alternatively, this software may be distributed\n"
+ "under the terms of the BSD license.\n"
+ "\n"
+ "This product includes software developed\n"
+ "by the OpenSSL Project for use in the\n"
+ "OpenSSL Toolkit (http://www.openssl.org/)\n");
+}
+
+
+void WpaGui::disconnect()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+ ctrlRequest("DISCONNECT", reply, &reply_len);
+}
+
+
+void WpaGui::scan()
+{
+ if (scanres) {
+ scanres->close();
+ delete scanres;
+ }
+
+ scanres = new ScanResults();
+ if (scanres == NULL)
+ return;
+ scanres->setWpaGui(this);
+ scanres->show();
+ scanres->exec();
+}
+
+
+void WpaGui::eventHistory()
+{
+ if (eh) {
+ eh->close();
+ delete eh;
+ }
+
+ eh = new EventHistory();
+ if (eh == NULL)
+ return;
+ eh->addEvents(msgs);
+ eh->show();
+ eh->exec();
+}
+
+
+void WpaGui::ping()
+{
+ char buf[10];
+ size_t len;
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ /*
+ * QSocketNotifier cannot be used with Windows named pipes, so use a
+ * timer to check for received messages for now. This could be
+ * optimized be doing something specific to named pipes or Windows
+ * events, but it is not clear what would be the best way of doing that
+ * in Qt.
+ */
+ receiveMsgs();
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+ if (scanres && !scanres->isVisible()) {
+ delete scanres;
+ scanres = NULL;
+ }
+
+ if (eh && !eh->isVisible()) {
+ delete eh;
+ eh = NULL;
+ }
+
+ if (udr && !udr->isVisible()) {
+ delete udr;
+ udr = NULL;
+ }
+
+ len = sizeof(buf) - 1;
+ if (ctrlRequest("PING", buf, &len) < 0) {
+ printf("PING failed - trying to reconnect\n");
+ if (openCtrlConnection(ctrl_iface) >= 0) {
+ printf("Reconnected successfully\n");
+ pingsToStatusUpdate = 0;
+ }
+ }
+
+ pingsToStatusUpdate--;
+ if (pingsToStatusUpdate <= 0) {
+ updateStatus();
+ updateNetworks();
+ }
+}
+
+
+static int str_match(const char *a, const char *b)
+{
+ return strncmp(a, b, strlen(b)) == 0;
+}
+
+
+void WpaGui::processMsg(char *msg)
+{
+ char *pos = msg, *pos2;
+ int priority = 2;
+
+ if (*pos == '<') {
+ /* skip priority */
+ pos++;
+ priority = atoi(pos);
+ pos = strchr(pos, '>');
+ if (pos)
+ pos++;
+ else
+ pos = msg;
+ }
+
+ WpaMsg wm(pos, priority);
+ if (eh)
+ eh->addEvent(wm);
+ msgs.append(wm);
+ while (msgs.count() > 100)
+ msgs.pop_front();
+
+ /* Update last message with truncated version of the event */
+ if (strncmp(pos, "CTRL-", 5) == 0) {
+ pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
+ if (pos2)
+ pos2++;
+ else
+ pos2 = pos;
+ } else
+ pos2 = pos;
+ QString lastmsg = pos2;
+ lastmsg.truncate(40);
+ textLastMessage->setText(lastmsg);
+
+ pingsToStatusUpdate = 0;
+ networkMayHaveChanged = true;
+
+ if (str_match(pos, WPA_CTRL_REQ))
+ processCtrlReq(pos + strlen(WPA_CTRL_REQ));
+}
+
+
+void WpaGui::processCtrlReq(const char *req)
+{
+ if (udr) {
+ udr->close();
+ delete udr;
+ }
+ udr = new UserDataRequest();
+ if (udr == NULL)
+ return;
+ if (udr->setParams(this, req) < 0) {
+ delete udr;
+ udr = NULL;
+ return;
+ }
+ udr->show();
+ udr->exec();
+}
+
+
+void WpaGui::receiveMsgs()
+{
+ char buf[256];
+ size_t len;
+
+ while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
+ buf[len] = '\0';
+ processMsg(buf);
+ }
+ }
+}
+
+
+void WpaGui::connectB()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+ ctrlRequest("REASSOCIATE", reply, &reply_len);
+}
+
+
+void WpaGui::selectNetwork( const QString &sel )
+{
+ QString cmd(sel);
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ int pos = cmd.find(':');
+ if (pos < 0) {
+ printf("Invalid selectNetwork '%s'\n", cmd.ascii());
+ return;
+ }
+ cmd.truncate(pos);
+ cmd.prepend("SELECT_NETWORK ");
+ ctrlRequest(cmd.ascii(), reply, &reply_len);
+}
+
+
+void WpaGui::editNetwork()
+{
+ QString sel(networkSelect->currentText());
+ int pos = sel.find(':');
+ if (pos < 0) {
+ printf("Invalid selectNetwork '%s'\n", sel.ascii());
+ return;
+ }
+ sel.truncate(pos);
+
+ NetworkConfig *nc = new NetworkConfig();
+ if (nc == NULL)
+ return;
+ nc->setWpaGui(this);
+
+ nc->paramsFromConfig(sel.toInt());
+ nc->show();
+ nc->exec();
+}
+
+
+void WpaGui::triggerUpdate()
+{
+ updateStatus();
+ networkMayHaveChanged = true;
+ updateNetworks();
+}
+
+
+void WpaGui::addNetwork()
+{
+ NetworkConfig *nc = new NetworkConfig();
+ if (nc == NULL)
+ return;
+ nc->setWpaGui(this);
+ nc->newNetwork();
+ nc->show();
+ nc->exec();
+}
+
+
+void WpaGui::selectAdapter( const QString & sel )
+{
+ if (openCtrlConnection(sel.ascii()) < 0)
+ printf("Failed to open control connection to "
+ "wpa_supplicant.\n");
+ updateStatus();
+ updateNetworks();
+}
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.h b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.h
new file mode 100644
index 000000000000..cd5c1afa4463
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.h
@@ -0,0 +1,76 @@
+/*
+ * wpa_gui - WpaGui class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef WPAGUI_H
+#define WPAGUI_H
+
+#include <QObject>
+#include "ui_wpagui.h"
+
+class UserDataRequest;
+
+
+class WpaGui : public QMainWindow, public Ui::WpaGui
+{
+ Q_OBJECT
+
+public:
+ WpaGui(QWidget *parent = 0, const char *name = 0,
+ Qt::WFlags fl = Qt::WType_TopLevel);
+ ~WpaGui();
+
+ virtual int ctrlRequest(const char *cmd, char *buf, size_t *buflen);
+ virtual void triggerUpdate();
+
+public slots:
+ virtual void parse_argv();
+ virtual void updateStatus();
+ virtual void updateNetworks();
+ virtual void helpIndex();
+ virtual void helpContents();
+ virtual void helpAbout();
+ virtual void disconnect();
+ virtual void scan();
+ virtual void eventHistory();
+ virtual void ping();
+ virtual void processMsg(char *msg);
+ virtual void processCtrlReq(const char *req);
+ virtual void receiveMsgs();
+ virtual void connectB();
+ virtual void selectNetwork(const QString &sel);
+ virtual void editNetwork();
+ virtual void addNetwork();
+ virtual void selectAdapter(const QString &sel);
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ ScanResults *scanres;
+ bool networkMayHaveChanged;
+ char *ctrl_iface;
+ EventHistory *eh;
+ struct wpa_ctrl *ctrl_conn;
+ QSocketNotifier *msgNotifier;
+ QTimer *timer;
+ int pingsToStatusUpdate;
+ WpaMsgList msgs;
+ char *ctrl_iface_dir;
+ struct wpa_ctrl *monitor_conn;
+ UserDataRequest *udr;
+
+ int openCtrlConnection(const char *ifname);
+};
+
+#endif /* WPAGUI_H */
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui
index 7097bfa90396..7047a2a106fc 100644
--- a/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui
@@ -1,464 +1,318 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>WpaGui</class>
-<widget class="QMainWindow">
- <property name="name">
- <cstring>WpaGui</cstring>
+<ui version="4.0" stdsetdef="1" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>WpaGui</class>
+ <widget class="QMainWindow" name="WpaGui" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>279</width>
+ <height>308</height>
+ </rect>
</property>
- <property name="geometry">
- <rect>
- <x>0</x>
- <y>0</y>
- <width>279</width>
- <height>308</height>
- </rect>
+ <property name="windowTitle" >
+ <string>wpa_gui</string>
</property>
- <property name="caption">
- <string>wpa_gui</string>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
- <property name="name">
- <cstring>textLabel16</cstring>
- </property>
- <property name="text">
- <string>Adapter:</string>
- </property>
- </widget>
- <widget class="QComboBox" row="0" column="2" rowspan="1" colspan="2">
- <property name="name">
- <cstring>adapterSelect</cstring>
- </property>
- </widget>
- <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
- <property name="name">
- <cstring>textLabel8</cstring>
+ <widget class="QWidget" >
+ <layout class="QGridLayout" >
+ <item rowspan="1" row="0" column="0" colspan="2" >
+ <widget class="QLabel" name="textLabel16" >
+ <property name="text" >
+ <string>Adapter:</string>
</property>
- <property name="text">
- <string>Network:</string>
+ </widget>
+ </item>
+ <item rowspan="1" row="0" column="2" colspan="2" >
+ <widget class="QComboBox" name="adapterSelect" />
+ </item>
+ <item rowspan="1" row="1" column="0" colspan="2" >
+ <widget class="QLabel" name="textLabel8" >
+ <property name="text" >
+ <string>Network:</string>
</property>
- </widget>
- <widget class="QComboBox" row="1" column="2" rowspan="1" colspan="2">
- <property name="name">
- <cstring>networkSelect</cstring>
+ </widget>
+ </item>
+ <item rowspan="1" row="1" column="2" colspan="2" >
+ <widget class="QComboBox" name="networkSelect" />
+ </item>
+ <item rowspan="1" row="2" column="0" colspan="4" >
+ <widget class="QFrame" name="frame3" >
+ <property name="frameShape" >
+ <enum>StyledPanel</enum>
</property>
- </widget>
- <widget class="QFrame" row="2" column="0" rowspan="1" colspan="4">
- <property name="name">
- <cstring>frame3</cstring>
+ <property name="frameShadow" >
+ <enum>Raised</enum>
</property>
- <property name="frameShape">
- <enum>StyledPanel</enum>
- </property>
- <property name="frameShadow">
- <enum>Raised</enum>
- </property>
- <grid>
- <property name="name">
- <cstring>unnamed</cstring>
- </property>
- <widget class="QLabel" row="0" column="0">
- <property name="name">
- <cstring>textLabel1</cstring>
- </property>
- <property name="text">
- <string>Status:</string>
- </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="textLabel1" >
+ <property name="text" >
+ <string>Status:</string>
+ </property>
</widget>
- <widget class="QLabel" row="1" column="0">
- <property name="name">
- <cstring>textLabel2</cstring>
- </property>
- <property name="text">
- <string>Last message:</string>
- </property>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="textLabel2" >
+ <property name="text" >
+ <string>Last message:</string>
+ </property>
</widget>
- <widget class="QLabel" row="2" column="0">
- <property name="name">
- <cstring>textLabel3</cstring>
- </property>
- <property name="text">
- <string>Authentication:</string>
- </property>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="textLabel3" >
+ <property name="text" >
+ <string>Authentication:</string>
+ </property>
</widget>
- <widget class="QLabel" row="3" column="0">
- <property name="name">
- <cstring>textLabel4</cstring>
- </property>
- <property name="text">
- <string>Encryption:</string>
- </property>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="textLabel4" >
+ <property name="text" >
+ <string>Encryption:</string>
+ </property>
</widget>
- <widget class="QLabel" row="4" column="0">
- <property name="name">
- <cstring>textLabel5</cstring>
- </property>
- <property name="text">
- <string>SSID:</string>
- </property>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="textLabel5" >
+ <property name="text" >
+ <string>SSID:</string>
+ </property>
</widget>
- <widget class="QLabel" row="5" column="0">
- <property name="name">
- <cstring>textLabel6</cstring>
- </property>
- <property name="text">
- <string>BSSID:</string>
- </property>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="textLabel6" >
+ <property name="text" >
+ <string>BSSID:</string>
+ </property>
</widget>
- <widget class="QLabel" row="6" column="0">
- <property name="name">
- <cstring>textLabel7</cstring>
- </property>
- <property name="text">
- <string>IP address:</string>
- </property>
+ </item>
+ <item row="6" column="0" >
+ <widget class="QLabel" name="textLabel7" >
+ <property name="text" >
+ <string>IP address:</string>
+ </property>
</widget>
- <widget class="QLabel" row="0" column="1">
- <property name="name">
- <cstring>textStatus</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="textStatus" >
+ <property name="text" >
+ <string/>
+ </property>
</widget>
- <widget class="QLabel" row="1" column="1" rowspan="1" colspan="3">
- <property name="name">
- <cstring>textLastMessage</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
+ </item>
+ <item rowspan="1" row="1" column="1" colspan="3" >
+ <widget class="QLabel" name="textLastMessage" >
+ <property name="text" >
+ <string/>
+ </property>
</widget>
- <widget class="QLabel" row="2" column="1">
- <property name="name">
- <cstring>textAuthentication</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLabel" name="textAuthentication" >
+ <property name="text" >
+ <string/>
+ </property>
</widget>
- <widget class="QLabel" row="3" column="1">
- <property name="name">
- <cstring>textEncryption</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLabel" name="textEncryption" >
+ <property name="text" >
+ <string/>
+ </property>
</widget>
- <widget class="QLabel" row="4" column="1">
- <property name="name">
- <cstring>textSsid</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLabel" name="textSsid" >
+ <property name="text" >
+ <string/>
+ </property>
</widget>
- <widget class="QLabel" row="5" column="1">
- <property name="name">
- <cstring>textBssid</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
+ </item>
+ <item row="5" column="1" >
+ <widget class="QLabel" name="textBssid" >
+ <property name="text" >
+ <string/>
+ </property>
</widget>
- <widget class="QLabel" row="6" column="1">
- <property name="name">
- <cstring>textIpAddress</cstring>
- </property>
- <property name="text">
- <string></string>
- </property>
+ </item>
+ <item row="6" column="1" >
+ <widget class="QLabel" name="textIpAddress" >
+ <property name="text" >
+ <string/>
+ </property>
</widget>
- </grid>
- </widget>
- <spacer row="3" column="0">
- <property name="name">
- <cstring>spacer7</cstring>
- </property>
- <property name="orientation">
- <enum>Horizontal</enum>
- </property>
- <property name="sizeType">
- <enum>Expanding</enum>
- </property>
- <property name="sizeHint">
- <size>
- <width>16</width>
- <height>16</height>
- </size>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <spacer name="spacer7" >
+ <property name="sizeHint" >
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
</property>
- </spacer>
- <widget class="QPushButton" row="3" column="1">
- <property name="name">
- <cstring>connectButton</cstring>
+ <property name="sizeType" >
+ <enum>Expanding</enum>
</property>
- <property name="text">
- <string>Connect</string>
+ <property name="orientation" >
+ <enum>Horizontal</enum>
</property>
- </widget>
- <widget class="QPushButton" row="3" column="2">
- <property name="name">
- <cstring>disconnectButton</cstring>
+ </spacer>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QPushButton" name="connectButton" >
+ <property name="text" >
+ <string>Connect</string>
</property>
- <property name="text">
- <string>Disconnect</string>
+ </widget>
+ </item>
+ <item row="3" column="2" >
+ <widget class="QPushButton" name="disconnectButton" >
+ <property name="text" >
+ <string>Disconnect</string>
</property>
- </widget>
- <widget class="QPushButton" row="3" column="3">
- <property name="name">
- <cstring>scanButton</cstring>
+ </widget>
+ </item>
+ <item row="3" column="3" >
+ <widget class="QPushButton" name="scanButton" >
+ <property name="text" >
+ <string>Scan</string>
</property>
- <property name="text">
- <string>Scan</string>
- </property>
- </widget>
- </grid>
-</widget>
-<menubar>
- <property name="name">
- <cstring>MenuBar</cstring>
- </property>
- <item text="&amp;File" name="fileMenu">
- <separator/>
- <action name="fileEventHistoryAction"/>
- <action name="fileAdd_NetworkAction"/>
- <action name="fileEdit_networkAction"/>
- <separator/>
- <action name="fileExitAction"/>
- </item>
- <item text="&amp;Help" name="helpMenu">
- <action name="helpContentsAction"/>
- <action name="helpIndexAction"/>
- <separator/>
- <action name="helpAboutAction"/>
- </item>
-</menubar>
-<toolbars>
-</toolbars>
-<actions>
- <action>
- <property name="name">
- <cstring>fileExitAction</cstring>
- </property>
- <property name="text">
- <string>Exit</string>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="MenuBar" >
+ <widget class="QMenu" name="fileMenu" >
+ <property name="title" >
+ <string>&amp;File</string>
</property>
- <property name="menuText">
- <string>E&amp;xit</string>
- </property>
- <property name="accel">
- <string>Ctrl+Q</string>
+ <addaction name="separator" />
+ <addaction name="fileEventHistoryAction" />
+ <addaction name="fileAdd_NetworkAction" />
+ <addaction name="fileEdit_networkAction" />
+ <addaction name="separator" />
+ <addaction name="fileExitAction" />
+ </widget>
+ <widget class="QMenu" name="helpMenu" >
+ <property name="title" >
+ <string>&amp;Help</string>
</property>
+ <addaction name="helpContentsAction" />
+ <addaction name="helpIndexAction" />
+ <addaction name="separator" />
+ <addaction name="helpAboutAction" />
+ </widget>
+ <addaction name="fileMenu" />
+ <addaction name="helpMenu" />
+ </widget>
+ <action name="fileExitAction" >
+ <property name="name" >
+ <cstring>fileExitAction</cstring>
+ </property>
+ <property name="iconText" >
+ <string>Exit</string>
+ </property>
+ <property name="text" >
+ <string>E&amp;xit</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+Q</string>
+ </property>
</action>
- <action>
- <property name="name">
- <cstring>helpContentsAction</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Contents</string>
- </property>
- <property name="menuText">
- <string>&amp;Contents...</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
+ <action name="helpContentsAction" >
+ <property name="name" >
+ <cstring>helpContentsAction</cstring>
+ </property>
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="iconText" >
+ <string>Contents</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Contents...</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
</action>
- <action>
- <property name="name">
- <cstring>helpIndexAction</cstring>
- </property>
- <property name="enabled">
- <bool>false</bool>
- </property>
- <property name="text">
- <string>Index</string>
- </property>
- <property name="menuText">
- <string>&amp;Index...</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
+ <action name="helpIndexAction" >
+ <property name="name" >
+ <cstring>helpIndexAction</cstring>
+ </property>
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="iconText" >
+ <string>Index</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Index...</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
</action>
- <action>
- <property name="name">
- <cstring>helpAboutAction</cstring>
- </property>
- <property name="text">
- <string>About</string>
- </property>
- <property name="menuText">
- <string>&amp;About</string>
- </property>
- <property name="accel">
- <string></string>
- </property>
+ <action name="helpAboutAction" >
+ <property name="name" >
+ <cstring>helpAboutAction</cstring>
+ </property>
+ <property name="iconText" >
+ <string>About</string>
+ </property>
+ <property name="text" >
+ <string>&amp;About</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
</action>
- <action>
- <property name="name">
- <cstring>fileEventHistoryAction</cstring>
- </property>
- <property name="text">
- <string>Event History</string>
- </property>
- <property name="menuText">
- <string>Event &amp;History</string>
- </property>
+ <action name="fileEventHistoryAction" >
+ <property name="name" >
+ <cstring>fileEventHistoryAction</cstring>
+ </property>
+ <property name="iconText" >
+ <string>Event History</string>
+ </property>
+ <property name="text" >
+ <string>Event &amp;History</string>
+ </property>
</action>
- <action>
- <property name="name">
- <cstring>fileAdd_NetworkAction</cstring>
- </property>
- <property name="text">
- <string>Add Network</string>
- </property>
- <property name="menuText">
- <string>&amp;Add Network</string>
- </property>
+ <action name="fileAdd_NetworkAction" >
+ <property name="name" >
+ <cstring>fileAdd_NetworkAction</cstring>
+ </property>
+ <property name="iconText" >
+ <string>Add Network</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Add Network</string>
+ </property>
</action>
- <action>
- <property name="name">
- <cstring>fileEdit_networkAction</cstring>
- </property>
- <property name="text">
- <string>Edit Network</string>
- </property>
- <property name="menuText">
- <string>&amp;Edit Network</string>
- </property>
+ <action name="fileEdit_networkAction" >
+ <property name="name" >
+ <cstring>fileEdit_networkAction</cstring>
+ </property>
+ <property name="iconText" >
+ <string>Edit Network</string>
+ </property>
+ <property name="text" >
+ <string>&amp;Edit Network</string>
+ </property>
</action>
-</actions>
-<connections>
- <connection>
- <sender>helpIndexAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>helpIndex()</slot>
- </connection>
- <connection>
- <sender>helpContentsAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>helpContents()</slot>
- </connection>
- <connection>
- <sender>helpAboutAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>helpAbout()</slot>
- </connection>
- <connection>
- <sender>fileExitAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>close()</slot>
- </connection>
- <connection>
- <sender>disconnectButton</sender>
- <signal>clicked()</signal>
- <receiver>WpaGui</receiver>
- <slot>disconnect()</slot>
- </connection>
- <connection>
- <sender>scanButton</sender>
- <signal>clicked()</signal>
- <receiver>WpaGui</receiver>
- <slot>scan()</slot>
- </connection>
- <connection>
- <sender>connectButton</sender>
- <signal>clicked()</signal>
- <receiver>WpaGui</receiver>
- <slot>connectB()</slot>
- </connection>
- <connection>
- <sender>fileEventHistoryAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>eventHistory()</slot>
- </connection>
- <connection>
- <sender>networkSelect</sender>
- <signal>activated(const QString&amp;)</signal>
- <receiver>WpaGui</receiver>
- <slot>selectNetwork(const QString&amp;)</slot>
- </connection>
- <connection>
- <sender>fileEdit_networkAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>editNetwork()</slot>
- </connection>
- <connection>
- <sender>fileAdd_NetworkAction</sender>
- <signal>activated()</signal>
- <receiver>WpaGui</receiver>
- <slot>addNetwork()</slot>
- </connection>
-</connections>
-<includes>
- <include location="global" impldecl="in declaration">qtimer.h</include>
- <include location="global" impldecl="in declaration">qsocketnotifier.h</include>
- <include location="local" impldecl="in declaration">wpamsg.h</include>
- <include location="local" impldecl="in declaration">eventhistory.h</include>
- <include location="local" impldecl="in declaration">scanresults.h</include>
- <include location="local" impldecl="in implementation">wpa_ctrl.h</include>
- <include location="global" impldecl="in implementation">dirent.h</include>
- <include location="global" impldecl="in implementation">qmessagebox.h</include>
- <include location="global" impldecl="in implementation">qapplication.h</include>
- <include location="local" impldecl="in implementation">userdatarequest.h</include>
- <include location="local" impldecl="in implementation">networkconfig.h</include>
- <include location="local" impldecl="in implementation">wpagui.ui.h</include>
-</includes>
-<forwards>
- <forward>class UserDataRequest;</forward>
-</forwards>
-<variables>
- <variable access="private">ScanResults *scanres;</variable>
- <variable access="private">bool networkMayHaveChanged;</variable>
- <variable access="private">char *ctrl_iface;</variable>
- <variable access="private">EventHistory *eh;</variable>
- <variable access="private">struct wpa_ctrl *ctrl_conn;</variable>
- <variable access="private">QSocketNotifier *msgNotifier;</variable>
- <variable access="private">QTimer *timer;</variable>
- <variable access="private">int pingsToStatusUpdate;</variable>
- <variable access="private">WpaMsgList msgs;</variable>
- <variable access="private">char *ctrl_iface_dir;</variable>
- <variable access="private">struct wpa_ctrl *monitor_conn;</variable>
- <variable access="private">UserDataRequest *udr;</variable>
-</variables>
-<slots>
- <slot>parse_argv()</slot>
- <slot>updateStatus()</slot>
- <slot>updateNetworks()</slot>
- <slot>helpIndex()</slot>
- <slot>helpContents()</slot>
- <slot>helpAbout()</slot>
- <slot>disconnect()</slot>
- <slot>scan()</slot>
- <slot>eventHistory()</slot>
- <slot>ping()</slot>
- <slot>processMsg( char * msg )</slot>
- <slot>processCtrlReq( const char * req )</slot>
- <slot>receiveMsgs()</slot>
- <slot>connectB()</slot>
- <slot>selectNetwork( const QString &amp; sel )</slot>
- <slot>editNetwork()</slot>
- <slot>addNetwork()</slot>
-</slots>
-<functions>
- <function access="private" specifier="non virtual">init()</function>
- <function access="private" specifier="non virtual">destroy()</function>
- <function access="private" specifier="non virtual" returnType="int">openCtrlConnection( const char * ifname )</function>
- <function returnType="int">ctrlRequest( const char * cmd, char * buf, size_t * buflen )</function>
- <function>triggerUpdate()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction>qPixmapFromMimeSource</pixmapfunction>
+ <includes>
+ <include location="global" >qtimer.h</include>
+ <include location="global" >qsocketnotifier.h</include>
+ <include location="local" >wpamsg.h</include>
+ <include location="local" >eventhistory.h</include>
+ <include location="local" >scanresults.h</include>
+ </includes>
+</ui>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h b/contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h
index 0808e1f0cb3f..65ce2e884414 100644
--- a/contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h
@@ -1,3 +1,17 @@
+/*
+ * wpa_gui - WpaMsg class for storing event messages
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifndef WPAMSG_H
#define WPAMSG_H
@@ -6,21 +20,21 @@
class WpaMsg {
public:
- WpaMsg() {}
- WpaMsg(const QString &_msg, int _priority = 2)
- : msg(_msg), priority(_priority)
- {
- timestamp = QDateTime::currentDateTime();
- }
-
- QString getMsg() const { return msg; }
- int getPriority() const { return priority; }
- QDateTime getTimestamp() const { return timestamp; }
-
+ WpaMsg() {}
+ WpaMsg(const QString &_msg, int _priority = 2)
+ : msg(_msg), priority(_priority)
+ {
+ timestamp = QDateTime::currentDateTime();
+ }
+
+ QString getMsg() const { return msg; }
+ int getPriority() const { return priority; }
+ QDateTime getTimestamp() const { return timestamp; }
+
private:
- QString msg;
- int priority;
- QDateTime timestamp;
+ QString msg;
+ int priority;
+ QDateTime timestamp;
};
typedef QLinkedList<WpaMsg> WpaMsgList;
diff --git a/contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h b/contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h
index 8d8fa48f033a..cb2caab2e4e1 100644
--- a/contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h
+++ b/contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h
@@ -31,8 +31,8 @@ void EventHistory::addEvents(WpaMsgList msgs)
void EventHistory::addEvent(WpaMsg msg)
{
- QListViewItem *item;
- item = new QListViewItem(eventListView,
+ Q3ListViewItem *item;
+ item = new Q3ListViewItem(eventListView,
msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"),
msg.getMsg());
if (item == NULL)
diff --git a/contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h b/contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h
index c03260bf2171..49bc7225ef3f 100644
--- a/contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h
+++ b/contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h
@@ -20,13 +20,15 @@ enum {
AUTH_WPA2_EAP = 5
};
+#define WPA_GUI_KEY_DATA "[key is configured]"
+
void NetworkConfig::init()
{
wpagui = NULL;
new_network = false;
}
-void NetworkConfig::paramsFromScanResults(QListViewItem *sel)
+void NetworkConfig::paramsFromScanResults(Q3ListViewItem *sel)
{
new_network = true;
@@ -172,13 +174,15 @@ void NetworkConfig::addNetwork()
setNetworkParam(id, "pairwise", pairwise, false);
setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
}
- if (pskEdit->isEnabled())
+ if (pskEdit->isEnabled() &&
+ strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
setNetworkParam(id, "psk", pskEdit->text().ascii(), psklen != 64);
if (eapSelect->isEnabled())
setNetworkParam(id, "eap", eapSelect->currentText().ascii(), false);
if (identityEdit->isEnabled())
setNetworkParam(id, "identity", identityEdit->text().ascii(), true);
- if (passwordEdit->isEnabled())
+ if (passwordEdit->isEnabled() &&
+ strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
setNetworkParam(id, "password", passwordEdit->text().ascii(), true);
if (cacertEdit->isEnabled())
setNetworkParam(id, "ca_cert", cacertEdit->text().ascii(), true);
@@ -263,6 +267,8 @@ void NetworkConfig::writeWepKey( int network_id, QLineEdit *edit, int id )
* with 40, 104, or 128-bit key
*/
txt = edit->text().ascii();
+ if (strcmp(txt, WPA_GUI_KEY_DATA) == 0)
+ return;
len = strlen(txt);
if (len == 0)
return;
@@ -283,9 +289,15 @@ void NetworkConfig::writeWepKey( int network_id, QLineEdit *edit, int id )
}
+static int key_value_isset(const char *reply, size_t reply_len)
+{
+ return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0);
+}
+
+
void NetworkConfig::paramsFromConfig( int network_id )
{
- int i;
+ int i, res;
edit_network_id = network_id;
getEapCapa();
@@ -294,7 +306,7 @@ void NetworkConfig::paramsFromConfig( int network_id )
size_t reply_len;
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id);
- reply_len = sizeof(reply);
+ reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
reply[0] == '"') {
reply[reply_len] = '\0';
@@ -305,7 +317,7 @@ void NetworkConfig::paramsFromConfig( int network_id )
}
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id);
- reply_len = sizeof(reply);
+ reply_len = sizeof(reply) - 1;
int wpa = 0;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
reply[reply_len] = '\0';
@@ -317,7 +329,7 @@ void NetworkConfig::paramsFromConfig( int network_id )
int auth = AUTH_NONE, encr = 0;
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id);
- reply_len = sizeof(reply);
+ reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
reply[reply_len] = '\0';
if (strstr(reply, "WPA-EAP"))
@@ -331,7 +343,7 @@ void NetworkConfig::paramsFromConfig( int network_id )
}
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id);
- reply_len = sizeof(reply);
+ reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
reply[reply_len] = '\0';
if (strstr(reply, "CCMP"))
@@ -345,18 +357,20 @@ void NetworkConfig::paramsFromConfig( int network_id )
}
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id);
- reply_len = sizeof(reply);
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
- reply[0] == '"') {
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
reply[reply_len] = '\0';
pos = strchr(reply + 1, '"');
if (pos)
*pos = '\0';
pskEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ pskEdit->setText(WPA_GUI_KEY_DATA);
}
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
- reply_len = sizeof(reply);
+ reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
reply[0] == '"') {
reply[reply_len] = '\0';
@@ -367,18 +381,21 @@ void NetworkConfig::paramsFromConfig( int network_id )
}
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id);
- reply_len = sizeof(reply);
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 &&
reply[0] == '"') {
reply[reply_len] = '\0';
pos = strchr(reply + 1, '"');
if (pos)
*pos = '\0';
passwordEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ passwordEdit->setText(WPA_GUI_KEY_DATA);
}
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
- reply_len = sizeof(reply);
+ reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
reply[0] == '"') {
reply[reply_len] = '\0';
@@ -389,7 +406,7 @@ void NetworkConfig::paramsFromConfig( int network_id )
}
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id);
- reply_len = sizeof(reply);
+ reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
reply[reply_len] = '\0';
for (i = 0; i < eapSelect->count(); i++) {
@@ -401,10 +418,26 @@ void NetworkConfig::paramsFromConfig( int network_id )
}
for (i = 0; i < 4; i++) {
+ QLineEdit *wepEdit;
+ switch (i) {
+ default:
+ case 0:
+ wepEdit = wep0Edit;
+ break;
+ case 1:
+ wepEdit = wep1Edit;
+ break;
+ case 2:
+ wepEdit = wep2Edit;
+ break;
+ case 3:
+ wepEdit = wep3Edit;
+ break;
+ }
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", network_id, i);
- reply_len = sizeof(reply);
- if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
- reply[0] == '"') {
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
reply[reply_len] = '\0';
pos = strchr(reply + 1, '"');
if (pos)
@@ -412,25 +445,16 @@ void NetworkConfig::paramsFromConfig( int network_id )
if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
encr = 1;
- switch (i) {
- case 0:
- wep0Edit->setText(reply + 1);
- break;
- case 1:
- wep1Edit->setText(reply + 1);
- break;
- case 2:
- wep2Edit->setText(reply + 1);
- break;
- case 3:
- wep3Edit->setText(reply + 1);
- break;
- }
+ wepEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ encr = 1;
+ wepEdit->setText(WPA_GUI_KEY_DATA);
}
}
snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
- reply_len = sizeof(reply);
+ reply_len = sizeof(reply) - 1;
if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
reply[reply_len] = '\0';
switch (atoi(reply)) {
diff --git a/contrib/wpa_supplicant/wpa_gui/scanresults.ui.h b/contrib/wpa_supplicant/wpa_gui/scanresults.ui.h
index 61555b5a0b83..530d2e6a495c 100644
--- a/contrib/wpa_supplicant/wpa_gui/scanresults.ui.h
+++ b/contrib/wpa_supplicant/wpa_gui/scanresults.ui.h
@@ -64,7 +64,7 @@ void ScanResults::updateResults()
signal = cols.count() > 2 ? cols[2] : "";
flags = cols.count() > 3 ? cols[3] : "";
ssid = cols.count() > 4 ? cols[4] : "";
- new QListViewItem(scanResultsView, ssid, bssid, freq, signal, flags);
+ new Q3ListViewItem(scanResultsView, ssid, bssid, freq, signal, flags);
}
}
@@ -89,7 +89,7 @@ void ScanResults::getResults()
-void ScanResults::bssSelected( QListViewItem * sel )
+void ScanResults::bssSelected( Q3ListViewItem * sel )
{
NetworkConfig *nc = new NetworkConfig();
if (nc == NULL)
@@ -98,4 +98,4 @@ void ScanResults::bssSelected( QListViewItem * sel )
nc->paramsFromScanResults(sel);
nc->show();
nc->exec();
- }
+}
diff --git a/contrib/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling b/contrib/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling
new file mode 100755
index 000000000000..e173b0013781
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# qmake seems to be forcing include and lib paths from the original build
+# and I have no idea how to change these. For now, just override the
+# directories in the Makefile.Release file after qmake run.
+
+qmake -spec /q/jm/qt4-win/4.0.0/mkspecs/win32-g++ wpa_gui.pro -o Makefile
+cat Makefile.Release |
+ sed s%qt4/lib%qt4-win/4.0.0/lib%g |
+ sed s%qt4/include%qt4-win/4.0.0/include%g > tmp.Makefile.Release &&
+mv -f tmp.Makefile.Release Makefile.Release
diff --git a/contrib/wpa_supplicant/wpa_gui/wpa_gui.pro b/contrib/wpa_supplicant/wpa_gui/wpa_gui.pro
index 7134c7de7318..07829ba30334 100644
--- a/contrib/wpa_supplicant/wpa_gui/wpa_gui.pro
+++ b/contrib/wpa_supplicant/wpa_gui/wpa_gui.pro
@@ -3,11 +3,20 @@ LANGUAGE = C++
CONFIG += qt warn_on release
-# For Windows build:
-#LIBS += -lws2_32 -static
-#DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_UDP
+DEFINES += CONFIG_CTRL_IFACE
+
+win32 {
+ LIBS += -lws2_32 -static
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
+} else:win32-g++ {
+ # cross compilation to win32
+ LIBS += -lws2_32 -static
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
+} else {
+ DEFINES += CONFIG_CTRL_IFACE_UNIX
+}
-INCLUDEPATH += ..
+INCLUDEPATH += . .. ../../hostapd
HEADERS += wpamsg.h
@@ -27,5 +36,12 @@ unix {
OBJECTS_DIR = .obj
}
-
-
+qtver = $$[QT_VERSION]
+isEmpty( qtver ) {
+ message(Compiling for Qt 3.x)
+ DEFINES += Q3ListViewItem=QListViewItem
+} else {
+ message(Compiling for Qt $$qtver)
+ QT += qt3support
+ CONFIG += uic3
+}
diff --git a/contrib/wpa_supplicant/wpa_gui/wpagui.ui b/contrib/wpa_supplicant/wpa_gui/wpagui.ui
index 7097bfa90396..01666a363479 100644
--- a/contrib/wpa_supplicant/wpa_gui/wpagui.ui
+++ b/contrib/wpa_supplicant/wpa_gui/wpagui.ui
@@ -401,6 +401,12 @@
<receiver>WpaGui</receiver>
<slot>addNetwork()</slot>
</connection>
+ <connection>
+ <sender>adapterSelect</sender>
+ <signal>activated(const QString&amp;)</signal>
+ <receiver>WpaGui</receiver>
+ <slot>selectAdapter(const QString&amp;)</slot>
+ </connection>
</connections>
<includes>
<include location="global" impldecl="in declaration">qtimer.h</include>
@@ -451,6 +457,7 @@
<slot>selectNetwork( const QString &amp; sel )</slot>
<slot>editNetwork()</slot>
<slot>addNetwork()</slot>
+ <slot>selectAdapter( const QString &amp; sel )</slot>
</slots>
<functions>
<function access="private" specifier="non virtual">init()</function>
diff --git a/contrib/wpa_supplicant/wpa_gui/wpagui.ui.h b/contrib/wpa_supplicant/wpa_gui/wpagui.ui.h
index 58760e734471..04e438df1eab 100644
--- a/contrib/wpa_supplicant/wpa_gui/wpagui.ui.h
+++ b/contrib/wpa_supplicant/wpa_gui/wpagui.ui.h
@@ -110,6 +110,8 @@ int WpaGui::openCtrlConnection(const char *ifname)
{
char *cfile;
int flen;
+ char buf[2048], *pos, *pos2;
+ size_t len;
if (ifname) {
if (ifname != ctrl_iface) {
@@ -120,13 +122,24 @@ int WpaGui::openCtrlConnection(const char *ifname)
#ifdef CONFIG_CTRL_IFACE_UDP
free(ctrl_iface);
ctrl_iface = strdup("udp");
-#else /* CONFIG_CTRL_IFACE_UDP */
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
struct dirent *dent;
DIR *dir = opendir(ctrl_iface_dir);
free(ctrl_iface);
ctrl_iface = NULL;
if (dir) {
while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket.
+ * Also accept DT_UNKNOWN (0) in case
+ * the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK &&
+ dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+
if (strcmp(dent->d_name, ".") == 0 ||
strcmp(dent->d_name, "..") == 0)
continue;
@@ -136,17 +149,46 @@ int WpaGui::openCtrlConnection(const char *ifname)
}
closedir(dir);
}
-#endif /* CONFIG_CTRL_IFACE_UDP */
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ struct wpa_ctrl *ctrl;
+ int ret;
+
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+
+ ctrl = wpa_ctrl_open(NULL);
+ if (ctrl) {
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
+ if (ret >= 0) {
+ buf[len] = '\0';
+ pos = strchr(buf, '\n');
+ if (pos)
+ *pos = '\0';
+ ctrl_iface = strdup(buf);
+ }
+ wpa_ctrl_close(ctrl);
+ }
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
}
if (ctrl_iface == NULL)
return -1;
+#ifdef CONFIG_CTRL_IFACE_UNIX
flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
cfile = (char *) malloc(flen);
if (cfile == NULL)
return -1;
snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
+#else /* CONFIG_CTRL_IFACE_UNIX */
+ flen = strlen(ctrl_iface) + 1;
+ cfile = (char *) malloc(flen);
+ if (cfile == NULL)
+ return -1;
+ snprintf(cfile, flen, "%s", ctrl_iface);
+#endif /* CONFIG_CTRL_IFACE_UNIX */
if (ctrl_conn) {
wpa_ctrl_close(ctrl_conn);
@@ -182,14 +224,33 @@ int WpaGui::openCtrlConnection(const char *ifname)
return -1;
}
+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
QSocketNotifier::Read, this);
connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
+#endif
adapterSelect->clear();
adapterSelect->insertItem(ctrl_iface);
adapterSelect->setCurrentItem(0);
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) {
+ buf[len] = '\0';
+ pos = buf;
+ while (*pos) {
+ pos2 = strchr(pos, '\n');
+ if (pos2)
+ *pos2 = '\0';
+ if (strcmp(pos, ctrl_iface) != 0)
+ adapterSelect->insertItem(pos);
+ if (pos2)
+ pos = pos2 + 1;
+ else
+ break;
+ }
+ }
+
return 0;
}
@@ -408,7 +469,7 @@ void WpaGui::helpAbout()
{
QMessageBox::about(this, "wpa_gui for wpa_supplicant",
"Copyright (c) 2003-2005,\n"
- "Jouni Malinen <jkmaline@cc.hut.fi>\n"
+ "Jouni Malinen <j@w1.fi>\n"
"and contributors.\n"
"\n"
"This program is free software. You can\n"
@@ -469,6 +530,16 @@ void WpaGui::ping()
char buf[10];
size_t len;
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ /*
+ * QSocketNotifier cannot be used with Windows named pipes, so use a timer
+ * to check for received messages for now. This could be optimized be doing
+ * something specific to named pipes or Windows events, but it is not clear
+ * what would be the best way of doing that in Qt.
+ */
+ receiveMsgs();
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
if (scanres && !scanres->isVisible()) {
delete scanres;
scanres = NULL;
@@ -575,7 +646,7 @@ void WpaGui::receiveMsgs()
char buf[256];
size_t len;
- while (wpa_ctrl_pending(monitor_conn)) {
+ while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
len = sizeof(buf) - 1;
if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
buf[len] = '\0';
@@ -649,3 +720,12 @@ void WpaGui::addNetwork()
nc->show();
nc->exec();
}
+
+
+void WpaGui::selectAdapter( const QString & sel )
+{
+ if (openCtrlConnection(sel.ascii()) < 0)
+ printf("Failed to open control connection to wpa_supplicant.\n");
+ updateStatus();
+ updateNetworks();
+}
diff --git a/contrib/wpa_supplicant/wpa_gui/wpamsg.h b/contrib/wpa_supplicant/wpa_gui/wpamsg.h
index 29840175f6f1..f3fce06978c7 100644
--- a/contrib/wpa_supplicant/wpa_gui/wpamsg.h
+++ b/contrib/wpa_supplicant/wpa_gui/wpamsg.h
@@ -1,7 +1,16 @@
#ifndef WPAMSG_H
#define WPAMSG_H
+class WpaMsg;
+
+#if QT_VERSION >= 0x040000
+#include <QDateTime>
+#include <QLinkedList>
+typedef QLinkedList<WpaMsg> WpaMsgList;
+#else
#include <qdatetime.h>
+typedef QValueList<WpaMsg> WpaMsgList;
+#endif
class WpaMsg {
public:
@@ -22,6 +31,4 @@ private:
QDateTime timestamp;
};
-typedef QValueList<WpaMsg> WpaMsgList;
-
#endif /* WPAMSG_H */
diff --git a/contrib/wpa_supplicant/wpa_i.h b/contrib/wpa_supplicant/wpa_i.h
index 4442832ad3c5..b5adb5e2c0d7 100644
--- a/contrib/wpa_supplicant/wpa_i.h
+++ b/contrib/wpa_supplicant/wpa_i.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - Internal WPA state machine definitions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,12 +15,12 @@
#ifndef WPA_I_H
#define WPA_I_H
-#define WPA_NONCE_LEN 32
-#define WPA_REPLAY_COUNTER_LEN 8
-
-
struct rsn_pmksa_candidate;
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
/**
* struct wpa_ptk - WPA Pairwise Transient Key
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
@@ -36,24 +36,40 @@ struct wpa_ptk {
u8 rx_mic_key[8];
} auth;
} u;
-} __attribute__ ((packed));
-
-
-/**
- * struct rsn_pmksa_cache - PMKSA cache entry
- */
-struct rsn_pmksa_cache {
- struct rsn_pmksa_cache *next;
- u8 pmkid[PMKID_LEN];
- u8 pmk[PMK_LEN];
- size_t pmk_len;
- time_t expiration;
- time_t reauth_time;
- int akmp; /* WPA_KEY_MGMT_* */
- u8 aa[ETH_ALEN];
- struct wpa_ssid *ssid;
- int opportunistic;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+#ifdef CONFIG_PEERKEY
+#define PEERKEY_MAX_IE_LEN 80
+struct wpa_peerkey {
+ struct wpa_peerkey *next;
+ int initiator; /* whether this end was initator for SMK handshake */
+ u8 addr[ETH_ALEN]; /* other end MAC address */
+ u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
+ u8 pnonce[WPA_NONCE_LEN]; /* Peer Nonce */
+ u8 rsnie_i[PEERKEY_MAX_IE_LEN]; /* Initiator RSN IE */
+ size_t rsnie_i_len;
+ u8 rsnie_p[PEERKEY_MAX_IE_LEN]; /* Peer RSN IE */
+ size_t rsnie_p_len;
+ u8 smk[PMK_LEN];
+ int smk_complete;
+ u8 smkid[PMKID_LEN];
+ u32 lifetime;
+ os_time_t expiration;
+ int cipher; /* Selected cipher (WPA_CIPHER_*) */
+ u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+ int replay_counter_set;
+
+ struct wpa_ptk stk, tstk;
+ int stk_set, tstk_set;
};
+#else /* CONFIG_PEERKEY */
+struct wpa_peerkey;
+#endif /* CONFIG_PEERKEY */
/**
@@ -74,11 +90,11 @@ struct wpa_sm {
struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
struct rsn_pmksa_cache *pmksa; /* PMKSA cache */
- struct rsn_pmksa_cache *cur_pmksa; /* current PMKSA entry */
- int pmksa_count; /* number of entries in PMKSA cache */
+ struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */
struct rsn_pmksa_candidate *pmksa_candidates;
struct l2_packet_data *l2_preauth;
+ struct l2_packet_data *l2_preauth_br;
u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or
* 00:00:00:00:00:00 if no pre-auth is
* in progress */
@@ -93,6 +109,7 @@ struct wpa_sm {
u8 own_addr[ETH_ALEN];
const char *ifname;
+ const char *bridge_ifname;
u8 bssid[ETH_ALEN];
unsigned int dot11RSNAConfigPMKLifetime;
@@ -106,11 +123,16 @@ struct wpa_sm {
unsigned int pairwise_cipher;
unsigned int group_cipher;
unsigned int key_mgmt;
+ unsigned int mgmt_group_cipher;
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
size_t assoc_wpa_ie_len;
u8 *ap_wpa_ie, *ap_rsn_ie;
size_t ap_wpa_ie_len, ap_rsn_ie_len;
+
+#ifdef CONFIG_PEERKEY
+ struct wpa_peerkey *peerkey;
+#endif /* CONFIG_PEERKEY */
};
@@ -194,4 +216,11 @@ static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid,
return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid);
}
+static inline int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,
+ int protect_type, int key_type)
+{
+ return sm->ctx->mlme_setprotection(sm->ctx->ctx, addr, protect_type,
+ key_type);
+}
+
#endif /* WPA_I_H */
diff --git a/contrib/wpa_supplicant/wpa_passphrase.c b/contrib/wpa_supplicant/wpa_passphrase.c
index 2a68cb52cf39..96b0c32c2cee 100644
--- a/contrib/wpa_supplicant/wpa_passphrase.c
+++ b/contrib/wpa_supplicant/wpa_passphrase.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - ASCII passphrase to WPA PSK tool
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,8 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "sha1.h"
@@ -54,12 +53,12 @@ int main(int argc, char *argv[])
passphrase = buf;
}
- if (strlen(passphrase) < 8 || strlen(passphrase) > 63) {
+ if (os_strlen(passphrase) < 8 || os_strlen(passphrase) > 63) {
printf("Passphrase must be 8..63 characters\n");
return 1;
}
- pbkdf2_sha1(passphrase, ssid, strlen(ssid), 4096, psk, 32);
+ pbkdf2_sha1(passphrase, ssid, os_strlen(ssid), 4096, psk, 32);
printf("network={\n");
printf("\tssid=\"%s\"\n", ssid);
diff --git a/contrib/wpa_supplicant/wpa_supplicant.c b/contrib/wpa_supplicant/wpa_supplicant.c
index 8e5ea440d990..f7ac13e836ab 100644
--- a/contrib/wpa_supplicant/wpa_supplicant.c
+++ b/contrib/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -10,18 +10,13 @@
* license.
*
* See README and COPYING for more details.
+ *
+ * This file implements functions for registering and unregistering
+ * %wpa_supplicant interfaces. In addition, this file contains number of
+ * functions for managing network connections.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <time.h>
-#include <signal.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <netinet/in.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
#include "common.h"
#include "eapol_sm.h"
@@ -33,14 +28,17 @@
#include "l2_packet.h"
#include "wpa_supplicant_i.h"
#include "ctrl_iface.h"
+#include "ctrl_iface_dbus.h"
#include "pcsc_funcs.h"
#include "version.h"
#include "preauth.h"
+#include "pmksa_cache.h"
#include "wpa_ctrl.h"
+#include "mlme.h"
const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
+"Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> and contributors";
const char *wpa_supplicant_license =
"This program is free software. You can distribute it and/or modify it\n"
@@ -48,14 +46,15 @@ const char *wpa_supplicant_license =
"\n"
"Alternatively, this software may be distributed under the terms of the\n"
"BSD license. See README and COPYING for more details.\n"
-#ifdef EAP_TLS_FUNCS
+#ifdef EAP_TLS_OPENSSL
"\nThis product includes software developed by the OpenSSL Project\n"
"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
-#endif /* EAP_TLS_FUNCS */
+#endif /* EAP_TLS_OPENSSL */
;
#ifndef CONFIG_NO_STDOUT_DEBUG
-const char *wpa_supplicant_full_license =
+/* Long text divided into parts in order to fit in C89 strings size limits. */
+const char *wpa_supplicant_full_license1 =
"This program is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License version 2 as\n"
"published by the Free Software Foundation.\n"
@@ -64,10 +63,11 @@ const char *wpa_supplicant_full_license =
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"GNU General Public License for more details.\n"
-"\n"
+"\n";
+const char *wpa_supplicant_full_license2 =
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
-"Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\n"
+"Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"
"\n"
"Alternatively, this software may be distributed under the terms of the\n"
"BSD license.\n"
@@ -75,14 +75,16 @@ const char *wpa_supplicant_full_license =
"Redistribution and use in source and binary forms, with or without\n"
"modification, are permitted provided that the following conditions are\n"
"met:\n"
-"\n"
+"\n";
+const char *wpa_supplicant_full_license3 =
"1. Redistributions of source code must retain the above copyright\n"
" notice, this list of conditions and the following disclaimer.\n"
"\n"
"2. Redistributions in binary form must reproduce the above copyright\n"
" notice, this list of conditions and the following disclaimer in the\n"
" documentation and/or other materials provided with the distribution.\n"
-"\n"
+"\n";
+const char *wpa_supplicant_full_license4 =
"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
" names of its contributors may be used to endorse or promote products\n"
" derived from this software without specific prior written permission.\n"
@@ -90,7 +92,8 @@ const char *wpa_supplicant_full_license =
"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
-"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n";
+const char *wpa_supplicant_full_license5 =
"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
@@ -103,37 +106,14 @@ const char *wpa_supplicant_full_license =
extern struct wpa_driver_ops *wpa_supplicant_drivers[];
+extern int wpa_debug_use_file;
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
extern int wpa_debug_timestamp;
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx);
-void wpa_msg(struct wpa_supplicant *wpa_s, int level, char *fmt, ...)
-{
- va_list ap;
- char *buf;
- const int buflen = 2048;
- int len;
-
- buf = malloc(buflen);
- if (buf == NULL) {
- printf("Failed to allocate message buffer for:\n");
- va_start(ap, fmt);
- vprintf(fmt, ap);
- printf("\n");
- va_end(ap);
- return;
- }
- va_start(ap, fmt);
- len = vsnprintf(buf, buflen, fmt, ap);
- va_end(ap);
- wpa_printf(level, "%s", buf);
- wpa_supplicant_ctrl_iface_send(wpa_s, level, buf, len);
- free(buf);
-}
-
-
+#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
const void *data, u16 data_len,
size_t *msg_len, void **data_pos)
@@ -141,18 +121,18 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
struct ieee802_1x_hdr *hdr;
*msg_len = sizeof(*hdr) + data_len;
- hdr = malloc(*msg_len);
+ hdr = os_malloc(*msg_len);
if (hdr == NULL)
return NULL;
hdr->version = wpa_s->conf->eapol_version;
hdr->type = type;
- hdr->length = htons(data_len);
+ hdr->length = host_to_be16(data_len);
if (data)
- memcpy(hdr + 1, data, data_len);
+ os_memcpy(hdr + 1, data, data_len);
else
- memset(hdr + 1, 0, data_len);
+ os_memset(hdr + 1, 0, data_len);
if (data_pos)
*data_pos = hdr + 1;
@@ -163,14 +143,15 @@ static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
/**
* wpa_ether_send - Send Ethernet frame
- * @wpa_s: pointer to wpa_supplicant data
+ * @wpa_s: Pointer to wpa_supplicant data
* @dest: Destination MAC address
- * @proto: Ethertype
+ * @proto: Ethertype in host byte order
* @buf: Frame payload starting from IEEE 802.1X header
* @len: Frame payload length
+ * Returns: >=0 on success, <0 on failure
*/
-int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, u16 proto,
- const u8 *buf, size_t len)
+static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len)
{
if (wpa_s->l2) {
return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
@@ -178,15 +159,17 @@ int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest, u16 proto,
return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
}
+#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
#ifdef IEEE8021X_EAPOL
/**
* wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator
- * @ctx: pointer to wpa_supplicant data
+ * @ctx: Pointer to wpa_supplicant data (wpa_s)
* @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*)
* @buf: EAPOL payload (after IEEE 802.1X header)
* @len: EAPOL payload length
+ * Returns: >=0 on success, <0 on failure
*
* This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame
* to the current Authenticator.
@@ -222,11 +205,13 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
return -1;
}
- if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0) {
+ if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+ {
wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an "
"EAPOL frame");
if (wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
- memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0) {
+ os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) !=
+ 0) {
dst = bssid;
wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR
" from the driver as the EAPOL destination",
@@ -250,30 +235,45 @@ static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen);
res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
- free(msg);
+ os_free(msg);
return res;
}
/**
* wpa_eapol_set_wep_key - set WEP key for the driver
- * @ctx: pointer to wpa_supplicant data
+ * @ctx: Pointer to wpa_supplicant data (wpa_s)
* @unicast: 1 = individual unicast key, 0 = broadcast key
* @keyidx: WEP key index (0..3)
- * @key: pointer to key data
- * @keylen: key length in bytes
- *
- * Returns 0 on success or < 0 on error.
+ * @key: Pointer to key data
+ * @keylen: Key length in bytes
+ * Returns: 0 on success or < 0 on error.
*/
static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
const u8 *key, size_t keylen)
{
struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 :
+ WPA_CIPHER_WEP104;
+ if (unicast)
+ wpa_s->pairwise_cipher = cipher;
+ else
+ wpa_s->group_cipher = cipher;
+ }
return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
unicast ? wpa_s->bssid :
(u8 *) "\xff\xff\xff\xff\xff\xff",
keyidx, unicast, (u8 *) "", 0, key, keylen);
}
+
+
+static void wpa_supplicant_aborted_cached(void *ctx)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ wpa_sm_aborted_cached(wpa_s->wpa);
+}
+
#endif /* IEEE8021X_EAPOL */
@@ -330,14 +330,14 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
switch (wpa_s->group_cipher) {
case WPA_CIPHER_CCMP:
- memcpy(key, ssid->psk, 16);
+ os_memcpy(key, ssid->psk, 16);
keylen = 16;
alg = WPA_ALG_CCMP;
break;
case WPA_CIPHER_TKIP:
/* WPA-None uses the same Michael MIC key for both TX and RX */
- memcpy(key, ssid->psk, 16 + 8);
- memcpy(key + 16 + 8, ssid->psk + 16, 8);
+ os_memcpy(key, ssid->psk, 16 + 8);
+ os_memcpy(key + 16 + 8, ssid->psk + 16, 8);
keylen = 32;
alg = WPA_ALG_TKIP;
break;
@@ -371,6 +371,12 @@ static void wpa_supplicant_notify_eapol_done(void *ctx)
#endif /* IEEE8021X_EAPOL */
+/**
+ * wpa_blacklist_get - Get the blacklist entry for a BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Matching blacklist entry for the BSSID or %NULL if not found
+ */
struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
const u8 *bssid)
{
@@ -378,7 +384,7 @@ struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
e = wpa_s->blacklist;
while (e) {
- if (memcmp(e->bssid, bssid, ETH_ALEN) == 0)
+ if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
return e;
e = e->next;
}
@@ -387,6 +393,22 @@ struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
}
+/**
+ * wpa_blacklist_add - Add an BSSID to the blacklist
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be added to the blacklist
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function adds the specified BSSID to the blacklist or increases the
+ * blacklist count if the BSSID was already listed. It should be called when
+ * an association attempt fails either due to the selected BSS rejecting
+ * association or due to timeout.
+ *
+ * This blacklist is used to force %wpa_supplicant to go through all available
+ * BSSes before retrying to associate with an BSS that rejected or timed out
+ * association. It does not prevent the listed BSS from being used; it only
+ * changes the order in which they are tried.
+ */
int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e;
@@ -400,11 +422,10 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
return 0;
}
- e = malloc(sizeof(*e));
+ e = os_zalloc(sizeof(*e));
if (e == NULL)
return -1;
- memset(e, 0, sizeof(*e));
- memcpy(e->bssid, bssid, ETH_ALEN);
+ os_memcpy(e->bssid, bssid, ETH_ALEN);
e->count = 1;
e->next = wpa_s->blacklist;
wpa_s->blacklist = e;
@@ -415,13 +436,13 @@ int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
-int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
+static int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e, *prev = NULL;
e = wpa_s->blacklist;
while (e) {
- if (memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
+ if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
if (prev == NULL) {
wpa_s->blacklist = e->next;
} else {
@@ -429,7 +450,7 @@ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
"blacklist", MAC2STR(bssid));
- free(e);
+ os_free(e);
return 0;
}
prev = e;
@@ -439,6 +460,10 @@ int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
+/**
+ * wpa_blacklist_clear - Clear the blacklist of all entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
{
struct wpa_blacklist *e, *prev;
@@ -450,28 +475,20 @@ void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
e = e->next;
wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
"blacklist (clear)", MAC2STR(prev->bssid));
- free(prev);
- }
-}
-
-
-const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
-{
- static char ssid_txt[MAX_SSID_LEN + 1];
- char *pos;
-
- if (ssid_len > MAX_SSID_LEN)
- ssid_len = MAX_SSID_LEN;
- memcpy(ssid_txt, ssid, ssid_len);
- ssid_txt[ssid_len] = '\0';
- for (pos = ssid_txt; *pos != '\0'; pos++) {
- if ((u8) *pos < 32 || (u8) *pos >= 127)
- *pos = '_';
+ os_free(prev);
}
- return ssid_txt;
}
+/**
+ * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to scan
+ * @usec: Number of microseconds after which to scan
+ *
+ * This function is used to schedule a scan for neighboring access points after
+ * the specified time.
+ */
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
{
wpa_msg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
@@ -481,6 +498,13 @@ void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
}
+/**
+ * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel a scan request scheduled with
+ * wpa_supplicant_req_scan().
+ */
void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
{
wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request");
@@ -491,9 +515,12 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
+ const u8 *bssid = wpa_s->bssid;
+ if (os_memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
+ bssid = wpa_s->pending_bssid;
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(wpa_s->bssid));
- wpa_blacklist_add(wpa_s, wpa_s->bssid);
+ wpa_blacklist_add(wpa_s, bssid);
wpa_sm_notify_disassoc(wpa_s->wpa);
wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
@@ -501,11 +528,20 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
}
+/**
+ * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to time out authentication
+ * @usec: Number of microseconds after which to time out authentication
+ *
+ * This function is used to schedule a timeout for the current authentication
+ * attempt.
+ */
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec)
{
if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
- wpa_s->driver && strcmp(wpa_s->driver->name, "wired") == 0)
+ wpa_s->driver && os_strcmp(wpa_s->driver->name, "wired") == 0)
return;
wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
@@ -515,6 +551,14 @@ void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
}
+/**
+ * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel authentication timeout scheduled with
+ * wpa_supplicant_req_auth_timeout() and it is called when authentication has
+ * been completed.
+ */
void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
{
wpa_msg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
@@ -523,8 +567,16 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
}
+/**
+ * wpa_supplicant_initiate_eapol - Configure EAPOL state machine
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to configure EAPOL state machine based on the selected
+ * authentication mode.
+ */
void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
{
+#ifdef IEEE8021X_EAPOL
struct eapol_config eapol_conf;
struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -538,7 +590,7 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
else
eapol_sm_notify_portControl(wpa_s->eapol, Auto);
- memset(&eapol_conf, 0, sizeof(eapol_conf));
+ os_memset(&eapol_conf, 0, sizeof(eapol_conf));
if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
eapol_conf.accept_802_1x_keys = 1;
eapol_conf.required_keys = 0;
@@ -551,18 +603,29 @@ void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
}
if (wpa_s->conf && wpa_s->driver &&
- strcmp(wpa_s->driver->name, "wired") == 0) {
+ os_strcmp(wpa_s->driver->name, "wired") == 0) {
eapol_conf.required_keys = 0;
}
}
- eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+ if (wpa_s->conf)
+ eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
eapol_conf.workaround = ssid->eap_workaround;
eapol_conf.eap_disabled = wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA;
eapol_sm_notify_config(wpa_s->eapol, ssid, &eapol_conf);
+#endif /* IEEE8021X_EAPOL */
}
+/**
+ * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @ssid: Configuration data for the network
+ *
+ * This function is used to configure WPA state machine and related parameters
+ * to a mode where WPA is not enabled. This is called as part of the
+ * authentication configuration when the selected network does not use WPA.
+ */
void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid)
{
@@ -577,6 +640,7 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
wpa_s->group_cipher = WPA_CIPHER_NONE;
+ wpa_s->mgmt_group_cipher = 0;
for (i = 0; i < NUM_WEP_KEYS; i++) {
if (ssid->wep_key_len[i] > 5) {
@@ -594,6 +658,10 @@ void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
+#ifdef CONFIG_IEEE80211W
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
+ wpa_s->mgmt_group_cipher);
+#endif /* CONFIG_IEEE80211W */
pmksa_cache_clear_current(wpa_s->wpa);
}
@@ -607,14 +675,21 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = NULL;
+ if (wpa_s->l2_br) {
+ l2_packet_deinit(wpa_s->l2_br);
+ wpa_s->l2_br = NULL;
+ }
- wpa_supplicant_ctrl_iface_deinit(wpa_s);
+ if (wpa_s->ctrl_iface) {
+ wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
+ }
if (wpa_s->conf != NULL) {
wpa_config_free(wpa_s->conf);
wpa_s->conf = NULL;
}
- free(wpa_s->confname);
+ os_free(wpa_s->confname);
wpa_s->confname = NULL;
wpa_sm_set_eapol(wpa_s->wpa, NULL);
@@ -624,19 +699,29 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
rsn_preauth_deinit(wpa_s->wpa);
pmksa_candidate_free(wpa_s->wpa);
- pmksa_cache_free(wpa_s->wpa);
wpa_sm_deinit(wpa_s->wpa);
wpa_s->wpa = NULL;
wpa_blacklist_clear(wpa_s);
- free(wpa_s->scan_results);
+ os_free(wpa_s->scan_results);
wpa_s->scan_results = NULL;
wpa_s->num_scan_results = 0;
wpa_supplicant_cancel_scan(wpa_s);
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+
+ ieee80211_sta_deinit(wpa_s);
}
+/**
+ * wpa_clear_keys - Clear keys configured for the driver
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @addr: Previously used BSSID or %NULL if not available
+ *
+ * This function clears the encryption keys that has been previously configured
+ * for the driver.
+ */
void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
@@ -654,6 +739,7 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
return;
}
+ /* MLME-DELETEKEYS.request */
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 0, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
@@ -661,11 +747,21 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
if (addr) {
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
0);
+ /* MLME-SETPROTECTION.request(None) */
+ wpa_drv_mlme_setprotection(
+ wpa_s, addr,
+ MLME_SETPROTECTION_PROTECT_TYPE_NONE,
+ MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
}
wpa_s->keys_cleared = 1;
}
+/**
+ * wpa_supplicant_state_txt - Get the connection state name as a text string
+ * @state: State (wpa_state; WPA_*)
+ * Returns: The state name as a printable text string
+ */
const char * wpa_supplicant_state_txt(int state)
{
switch (state) {
@@ -691,26 +787,50 @@ const char * wpa_supplicant_state_txt(int state)
}
+/**
+ * wpa_supplicant_set_state - Set current connection state
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @state: The new connection state
+ *
+ * This function is called whenever the connection state changes, e.g.,
+ * association is completed for WPA/WPA2 4-Way Handshake is started.
+ */
void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_states state)
{
wpa_printf(MSG_DEBUG, "State: %s -> %s",
wpa_supplicant_state_txt(wpa_s->wpa_state),
wpa_supplicant_state_txt(state));
+
+ wpa_supplicant_dbus_notify_state_change(wpa_s, state,
+ wpa_s->wpa_state);
+
if (state == WPA_COMPLETED && wpa_s->new_connection) {
- wpa_s->new_connection = 0;
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
- MACSTR " completed %s",
+ MACSTR " completed %s [id=%d id_str=%s]",
MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
- "(reauth)" : "(auth)");
+ "(reauth)" : "(auth)",
+ ssid ? ssid->id : -1,
+ ssid && ssid->id_str ? ssid->id_str : "");
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+ wpa_s->new_connection = 0;
wpa_s->reassociated_connection = 1;
+ wpa_drv_set_operstate(wpa_s, 1);
} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
state == WPA_ASSOCIATED) {
wpa_s->new_connection = 1;
+ wpa_drv_set_operstate(wpa_s, 0);
}
wpa_s->wpa_state = state;
}
+/**
+ * wpa_supplicant_get_state - Get the connection state
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: The current connection state (WPA_*)
+ */
wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s)
{
return wpa_s->wpa_state;
@@ -730,6 +850,27 @@ static void wpa_supplicant_terminate(int sig, void *eloop_ctx,
}
+static void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
+{
+ wpa_s->pairwise_cipher = 0;
+ wpa_s->group_cipher = 0;
+ wpa_s->mgmt_group_cipher = 0;
+ wpa_s->key_mgmt = 0;
+ wpa_s->wpa_state = WPA_DISCONNECTED;
+}
+
+
+/**
+ * wpa_supplicant_reload_configuration - Reload configuration data
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success or -1 if configuration parsing failed
+ *
+ * This function can be used to request that the configuration data is reloaded
+ * (e.g., after configuration file change). This function is reloading
+ * configuration only for one interface, so this may need to be called multiple
+ * times if %wpa_supplicant is controlling multiple interfaces and all
+ * interfaces need reconfiguration.
+ */
int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
{
struct wpa_config *conf;
@@ -745,26 +886,30 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
|| (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
- strcmp(conf->ctrl_interface, wpa_s->conf->ctrl_interface)
- != 0);
+ os_strcmp(conf->ctrl_interface,
+ wpa_s->conf->ctrl_interface) != 0);
- if (reconf_ctrl)
- wpa_supplicant_ctrl_iface_deinit(wpa_s);
+ if (reconf_ctrl && wpa_s->ctrl_iface) {
+ wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+ wpa_s->ctrl_iface = NULL;
+ }
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
wpa_s->current_ssid = NULL;
/*
* TODO: should notify EAPOL SM about changes in opensc_engine_path,
* pkcs11_engine_path, pkcs11_module_path.
- */
+ */
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
wpa_sm_set_config(wpa_s->wpa, NULL);
wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
- pmksa_cache_notify_reconfig(wpa_s->wpa);
rsn_preauth_deinit(wpa_s->wpa);
wpa_config_free(wpa_s->conf);
wpa_s->conf = conf;
if (reconf_ctrl)
- wpa_supplicant_ctrl_iface_init(wpa_s);
+ wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
+
+ wpa_supplicant_clear_status(wpa_s);
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
wpa_msg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
@@ -772,7 +917,6 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
}
-#ifndef CONFIG_NATIVE_WINDOWS
static void wpa_supplicant_reconfig(int sig, void *eloop_ctx,
void *signal_ctx)
{
@@ -785,7 +929,6 @@ static void wpa_supplicant_reconfig(int sig, void *eloop_ctx,
}
}
}
-#endif /* CONFIG_NATIVE_WINDOWS */
static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
@@ -802,7 +945,7 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
wpa_supplicant_initiate_eapol(wpa_s);
wpa_printf(MSG_DEBUG, "Already associated with a configured network - "
"generating associated event");
- memset(&data, 0, sizeof(data));
+ os_memset(&data, 0, sizeof(data));
wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
}
@@ -811,7 +954,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
- int enabled, scan_req = 0;
+ int enabled, scan_req = 0, ret;
if (wpa_s->disconnected)
return;
@@ -833,6 +976,13 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
scan_req = wpa_s->scan_req;
wpa_s->scan_req = 0;
+ if (wpa_s->conf->ap_scan != 0 &&
+ wpa_s->driver && os_strcmp(wpa_s->driver->name, "wired") == 0) {
+ wpa_printf(MSG_DEBUG, "Using wired driver - overriding "
+ "ap_scan configuration");
+ wpa_s->conf->ap_scan = 0;
+ }
+
if (wpa_s->conf->ap_scan == 0) {
wpa_supplicant_gen_assoc_event(wpa_s);
return;
@@ -864,8 +1014,13 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
* ap_scan=2 mode - try to associate with each SSID instead of
* scanning for each scan_ssid=1 network.
*/
- if (ssid == NULL)
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "wpa_supplicant_scan: Reached "
+ "end of scan list - go back to beginning");
+ wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
return;
+ }
if (ssid->next) {
/* Continue from the next SSID on the next attempt. */
wpa_s->prev_scan_ssid = ssid;
@@ -886,8 +1041,23 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
} else
wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
- if (wpa_drv_scan(wpa_s, ssid ? ssid->ssid : NULL,
- ssid ? ssid->ssid_len : 0)) {
+ if (wpa_s->scan_res_tried == 0 && wpa_s->conf->ap_scan == 1) {
+ wpa_s->scan_res_tried++;
+ wpa_printf(MSG_DEBUG, "Trying to get current scan results "
+ "first without requesting a new scan to speed up "
+ "initial association");
+ wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL);
+ return;
+ }
+
+ if (wpa_s->use_client_mlme) {
+ ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
+ } else {
+ ret = wpa_drv_scan(wpa_s, ssid ? ssid->ssid : NULL,
+ ssid ? ssid->ssid_len : 0);
+ }
+ if (ret) {
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
wpa_supplicant_req_scan(wpa_s, 10, 0);
}
@@ -964,10 +1134,34 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
return -1;
}
+#ifdef CONFIG_IEEE80211W
+ if (!(ie->capabilities & WPA_CAPABILITY_MGMT_FRAME_PROTECTION) &&
+ ssid->ieee80211w == IEEE80211W_REQUIRED) {
+ wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
+ "that does not support management frame protection - "
+ "reject");
+ return -1;
+ }
+#endif /* CONFIG_IEEE80211W */
+
return 0;
}
+/**
+ * wpa_supplicant_set_suites - Set authentication and encryption parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Scan results for the selected BSS, or %NULL if not available
+ * @ssid: Configuration data for the selected network
+ * @wpa_ie: Buffer for the WPA/RSN IE
+ * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
+ * used buffer length in case the functions returns success.
+ * Returns: 0 on success or -1 on failure
+ *
+ * This function is used to configure authentication and encryption parameters
+ * based on the network configuration and scan result for the selected BSS (if
+ * available).
+ */
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_scan_result *bss,
struct wpa_ssid *ssid,
@@ -999,18 +1193,30 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
else
proto = WPA_PROTO_WPA;
if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
- memset(&ie, 0, sizeof(ie));
+ os_memset(&ie, 0, sizeof(ie));
ie.group_cipher = ssid->group_cipher;
ie.pairwise_cipher = ssid->pairwise_cipher;
ie.key_mgmt = ssid->key_mgmt;
+#ifdef CONFIG_IEEE80211W
+ ie.mgmt_group_cipher =
+ ssid->ieee80211w != NO_IEEE80211W ?
+ WPA_CIPHER_AES_128_CMAC : 0;
+#endif /* CONFIG_IEEE80211W */
wpa_printf(MSG_DEBUG, "WPA: Set cipher suites based "
"on configuration");
- }
+ } else
+ proto = ie.proto;
}
wpa_printf(MSG_DEBUG, "WPA: Selected cipher suites: group %d "
- "pairwise %d key_mgmt %d",
- ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt);
+ "pairwise %d key_mgmt %d proto %d",
+ ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
+#ifdef CONFIG_IEEE80211W
+ if (ssid->ieee80211w) {
+ wpa_printf(MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
+ ie.mgmt_group_cipher);
+ }
+#endif /* CONFIG_IEEE80211W */
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
@@ -1075,6 +1281,23 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
wpa_s->pairwise_cipher);
wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
+#ifdef CONFIG_IEEE80211W
+ sel = ie.mgmt_group_cipher;
+ if (ssid->ieee80211w == NO_IEEE80211W ||
+ !(ie.capabilities & WPA_CAPABILITY_MGMT_FRAME_PROTECTION))
+ sel = 0;
+ if (sel & WPA_CIPHER_AES_128_CMAC) {
+ wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+ wpa_msg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+ "AES-128-CMAC");
+ } else {
+ wpa_s->mgmt_group_cipher = 0;
+ wpa_msg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
+ }
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
+ wpa_s->mgmt_group_cipher);
+#endif /* CONFIG_IEEE80211W */
+
if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
return -1;
@@ -1089,15 +1312,23 @@ int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
+/**
+ * wpa_supplicant_associate - Request association
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Scan results for the selected BSS, or %NULL if not available
+ * @ssid: Configuration data for the selected network
+ *
+ * This function is used to request %wpa_supplicant to associate with a BSS.
+ */
void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
struct wpa_scan_result *bss,
struct wpa_ssid *ssid)
{
u8 wpa_ie[80];
size_t wpa_ie_len;
- int use_crypt;
+ int use_crypt, ret, i;
int algs = AUTH_ALG_OPEN_SYSTEM;
- int cipher_pairwise, cipher_group;
+ wpa_cipher cipher_pairwise, cipher_group;
struct wpa_driver_associate_params params;
int wep_keys_set = 0;
struct wpa_driver_capa capa;
@@ -1108,10 +1339,12 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
" (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
- memset(wpa_s->bssid, 0, ETH_ALEN);
+ os_memset(wpa_s->bssid, 0, ETH_ALEN);
+ os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
} else {
wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
}
wpa_supplicant_cancel_scan(wpa_s);
@@ -1119,6 +1352,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
* previous association. */
wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+#ifdef IEEE8021X_EAPOL
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (ssid->leap) {
if (ssid->non_leap == 0)
@@ -1127,6 +1361,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
algs |= AUTH_ALG_LEAP;
}
}
+#endif /* IEEE8021X_EAPOL */
wpa_printf(MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
if (ssid->auth_alg) {
algs = 0;
@@ -1179,7 +1414,6 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
cipher_group = cipher_suite2driver(wpa_s->group_cipher);
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
- int i;
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
use_crypt = 0;
for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -1194,6 +1428,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
}
}
+#ifdef IEEE8021X_EAPOL
if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if ((ssid->eapol_flags &
(EAPOL_FLAG_REQUIRE_KEY_UNICAST |
@@ -1207,6 +1442,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
cipher_pairwise = cipher_group = CIPHER_WEP104;
}
}
+#endif /* IEEE8021X_EAPOL */
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
/* Set the key before (and later after) association */
@@ -1215,7 +1451,7 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
wpa_drv_set_drop_unencrypted(wpa_s, use_crypt);
wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
- memset(&params, 0, sizeof(params));
+ os_memset(&params, 0, sizeof(params));
if (bss) {
params.bssid = bss->bssid;
params.ssid = bss->ssid;
@@ -1232,7 +1468,32 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
params.auth_alg = algs;
params.mode = ssid->mode;
- if (wpa_drv_associate(wpa_s, &params) < 0) {
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i])
+ params.wep_key[i] = ssid->wep_key[i];
+ params.wep_key_len[i] = ssid->wep_key_len[i];
+ }
+ params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+
+#ifdef CONFIG_IEEE80211W
+ switch (ssid->ieee80211w) {
+ case NO_IEEE80211W:
+ params.mgmt_frame_protection = NO_MGMT_FRAME_PROTECTION;
+ break;
+ case IEEE80211W_OPTIONAL:
+ params.mgmt_frame_protection = MGMT_FRAME_PROTECTION_OPTIONAL;
+ break;
+ case IEEE80211W_REQUIRED:
+ params.mgmt_frame_protection = MGMT_FRAME_PROTECTION_REQUIRED;
+ break;
+ }
+#endif /* CONFIG_IEEE80211W */
+
+ if (wpa_s->use_client_mlme)
+ ret = ieee80211_sta_associate(wpa_s, &params);
+ else
+ ret = wpa_drv_associate(wpa_s, &params);
+ if (ret < 0) {
wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
"failed");
/* try to continue anyway; new association will be tried again
@@ -1263,48 +1524,78 @@ void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) {
/* Set static WEP keys again */
- int i;
- for (i = 0; i < NUM_WEP_KEYS; i++) {
- if (ssid->wep_key_len[i]) {
+ int j;
+ for (j = 0; j < NUM_WEP_KEYS; j++) {
+ if (ssid->wep_key_len[j]) {
wpa_set_wep_key(wpa_s,
- i == ssid->wep_tx_keyidx,
- i, ssid->wep_key[i],
- ssid->wep_key_len[i]);
+ j == ssid->wep_tx_keyidx,
+ j, ssid->wep_key[j],
+ ssid->wep_key_len[j]);
}
}
}
+ if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
+ /*
+ * Do not allow EAP session resumption between different
+ * network configurations.
+ */
+ eapol_sm_invalidate_cached_session(wpa_s->eapol);
+ }
wpa_s->current_ssid = ssid;
wpa_sm_set_config(wpa_s->wpa, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
}
+/**
+ * wpa_supplicant_disassociate - Disassociate the current connection
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @reason_code: IEEE 802.11 reason code for the disassociate frame
+ *
+ * This function is used to request %wpa_supplicant to disassociate with the
+ * current AP.
+ */
void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
int reason_code)
{
u8 *addr = NULL;
- wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
- if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0) {
- wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
+ if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0)
+ {
+ if (wpa_s->use_client_mlme)
+ ieee80211_sta_disassociate(wpa_s, reason_code);
+ else
+ wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
+ wpa_supplicant_mark_disassoc(wpa_s);
wpa_s->current_ssid = NULL;
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
}
+/**
+ * wpa_supplicant_deauthenticate - Deauthenticate the current connection
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
+ *
+ * This function is used to request %wpa_supplicant to disassociate with the
+ * current AP.
+ */
void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code)
{
u8 *addr = NULL;
wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
- if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0) {
- wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
+ if (os_memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0)
+ {
+ if (wpa_s->use_client_mlme)
+ ieee80211_sta_deauthenticate(wpa_s, reason_code);
+ else
+ wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
+ reason_code);
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
@@ -1316,24 +1607,36 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
}
+/**
+ * wpa_supplicant_get_scan_results - Get scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is request the current scan results from the driver and stores
+ * a local copy of the results in wpa_s->scan_results.
+ */
int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
{
#define SCAN_AP_LIMIT 128
struct wpa_scan_result *results, *tmp;
int num;
- results = malloc(SCAN_AP_LIMIT * sizeof(struct wpa_scan_result));
+ results = os_malloc(SCAN_AP_LIMIT * sizeof(struct wpa_scan_result));
if (results == NULL) {
wpa_printf(MSG_WARNING, "Failed to allocate memory for scan "
"results");
return -1;
}
- num = wpa_drv_get_scan_results(wpa_s, results, SCAN_AP_LIMIT);
+ if (wpa_s->use_client_mlme) {
+ num = ieee80211_sta_get_scan_results(wpa_s, results,
+ SCAN_AP_LIMIT);
+ } else
+ num = wpa_drv_get_scan_results(wpa_s, results, SCAN_AP_LIMIT);
wpa_printf(MSG_DEBUG, "Scan results: %d", num);
if (num < 0) {
wpa_printf(MSG_DEBUG, "Failed to get scan results");
- free(results);
+ os_free(results);
return -1;
}
if (num > SCAN_AP_LIMIT) {
@@ -1343,12 +1646,12 @@ int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
}
/* Free unneeded memory for unused scan result entries */
- tmp = realloc(results, num * sizeof(struct wpa_scan_result));
+ tmp = os_realloc(results, num * sizeof(struct wpa_scan_result));
if (tmp || num == 0) {
results = tmp;
}
- free(wpa_s->scan_results);
+ os_free(wpa_s->scan_results);
wpa_s->scan_results = results;
wpa_s->num_scan_results = num;
@@ -1368,7 +1671,14 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
}
for (i = 0; i < wpa_s->num_scan_results; i++) {
- if (memcmp(results[i].bssid, wpa_s->bssid, ETH_ALEN) == 0) {
+ struct wpa_ssid *ssid = wpa_s->current_ssid;
+ if (os_memcmp(results[i].bssid, wpa_s->bssid, ETH_ALEN) != 0)
+ continue;
+ if (ssid == NULL ||
+ ((results[i].ssid_len == ssid->ssid_len &&
+ os_memcmp(results[i].ssid, ssid->ssid, ssid->ssid_len)
+ == 0) ||
+ ssid->ssid_len == 0)) {
curr = &results[i];
break;
}
@@ -1407,36 +1717,52 @@ static int wpa_supplicant_get_beacon_ie(void *ctx)
/**
- * wpa_supplicant_get_ssid - get a pointer to the current network structure
- * @wpa_s: pointer to wpa_supplicant data
- *
- * Returns: a pointer to the current network structure or %NULL on failure
+ * wpa_supplicant_get_ssid - Get a pointer to the current network structure
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: A pointer to the current network structure or %NULL on failure
*/
struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
{
struct wpa_ssid *entry;
u8 ssid[MAX_SSID_LEN];
- int ssid_len;
+ int res;
+ size_t ssid_len;
u8 bssid[ETH_ALEN];
+ int wired;
- ssid_len = wpa_drv_get_ssid(wpa_s, ssid);
- if (ssid_len < 0) {
- wpa_printf(MSG_WARNING, "Could not read SSID from driver.");
- return NULL;
+ if (wpa_s->use_client_mlme) {
+ if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
+ wpa_printf(MSG_WARNING, "Could not read SSID from "
+ "MLME.");
+ return NULL;
+ }
+ } else {
+ res = wpa_drv_get_ssid(wpa_s, ssid);
+ if (res < 0) {
+ wpa_printf(MSG_WARNING, "Could not read SSID from "
+ "driver.");
+ return NULL;
+ }
+ ssid_len = res;
}
- if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+ if (wpa_s->use_client_mlme)
+ os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
+ else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
return NULL;
}
+ wired = wpa_s->conf->ap_scan == 0 && wpa_s->driver &&
+ os_strcmp(wpa_s->driver->name, "wired") == 0;
+
entry = wpa_s->conf->ssid;
while (entry) {
if (!entry->disabled &&
- ssid_len == entry->ssid_len &&
- memcmp(ssid, entry->ssid, ssid_len) == 0 &&
+ ((ssid_len == entry->ssid_len &&
+ os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
(!entry->bssid_set ||
- memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+ os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
return entry;
entry = entry->next;
}
@@ -1503,8 +1829,13 @@ static struct wpa_ssid * _wpa_supplicant_get_ssid(void *wpa_s)
}
-static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid)
+static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
{
+ struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s->use_client_mlme) {
+ os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
+ return 0;
+ }
return wpa_drv_get_bssid(wpa_s, bssid);
}
@@ -1519,6 +1850,15 @@ static int wpa_supplicant_set_key(void *wpa_s, wpa_alg alg,
}
+static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
+ int protection_type,
+ int key_type)
+{
+ return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type,
+ key_type);
+}
+
+
static int wpa_supplicant_add_pmkid(void *wpa_s,
const u8 *bssid, const u8 *pmkid)
{
@@ -1555,13 +1895,13 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
}
for (i = 0; wpa_supplicant_drivers[i]; i++) {
- if (strcmp(name, wpa_supplicant_drivers[i]->name) == 0) {
+ if (os_strcmp(name, wpa_supplicant_drivers[i]->name) == 0) {
wpa_s->driver = wpa_supplicant_drivers[i];
return 0;
}
}
- printf("Unsupported driver '%s'.\n", name);
+ wpa_printf(MSG_ERROR, "Unsupported driver '%s'.\n", name);
return -1;
}
@@ -1602,7 +1942,7 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
* an AP, so just allow any address to be used for now. The replies are
* still sent to the current BSSID (if available), though. */
- memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
+ os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
if (wpa_s->key_mgmt != WPA_KEY_MGMT_PSK &&
eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
return;
@@ -1611,6 +1951,17 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
}
+/**
+ * wpa_supplicant_driver_init - Initialize driver interface parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @wait_for_interface: 0 = do not wait for the interface (reports a failure if
+ * the interface is not present), 1 = wait until the interface is available
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to initialize driver interface parameters.
+ * wpa_drv_init() must have been called before this function to initialize the
+ * driver interface.
+ */
int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
int wait_for_interface)
{
@@ -1620,7 +1971,7 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
if (wpa_s->driver->send_eapol) {
const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
if (addr)
- memcpy(wpa_s->own_addr, addr, ETH_ALEN);
+ os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
break;
}
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
@@ -1631,18 +1982,34 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
break;
else if (!wait_for_interface)
return -1;
- printf("Waiting for interface..\n");
- sleep(5);
+ wpa_printf(MSG_DEBUG, "Waiting for interface..");
+ os_sleep(5, 0);
}
if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
- fprintf(stderr, "Failed to get own L2 address\n");
+ wpa_printf(MSG_ERROR, "Failed to get own L2 address");
return -1;
}
wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR,
MAC2STR(wpa_s->own_addr));
+ if (wpa_s->bridge_ifname[0]) {
+ wpa_printf(MSG_DEBUG, "Receiving packets from bridge interface"
+ " '%s'", wpa_s->bridge_ifname);
+ wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
+ wpa_s->own_addr,
+ ETH_P_EAPOL,
+ wpa_supplicant_rx_eapol, wpa_s,
+ 0);
+ if (wpa_s->l2_br == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to open l2_packet "
+ "connection for the bridge interface '%s'",
+ wpa_s->bridge_ifname);
+ return -1;
+ }
+ }
+
/* Backwards compatibility call to set_wpa() handler. This is called
* only just after init and just before deinit, so these handler can be
* used to implement same functionality. */
@@ -1654,8 +2021,8 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "Driver does not support WPA.");
/* Continue to allow non-WPA modes to be used. */
} else {
- fprintf(stderr, "Failed to enable WPA in the "
- "driver.\n");
+ wpa_printf(MSG_ERROR, "Failed to enable WPA in the "
+ "driver.");
return -1;
}
}
@@ -1679,20 +2046,7 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
static int wpa_supplicant_daemon(const char *pid_file)
{
wpa_printf(MSG_DEBUG, "Daemonize..");
- if (daemon(0, 0)) {
- perror("daemon");
- return -1;
- }
-
- if (pid_file) {
- FILE *f = fopen(pid_file, "w");
- if (f) {
- fprintf(f, "%u\n", getpid());
- fclose(f);
- }
- }
-
- return 0;
+ return os_daemonize(pid_file);
}
@@ -1700,11 +2054,9 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
{
struct wpa_supplicant *wpa_s;
- wpa_s = malloc(sizeof(*wpa_s));
+ wpa_s = os_zalloc(sizeof(*wpa_s));
if (wpa_s == NULL)
return NULL;
- memset(wpa_s, 0, sizeof(*wpa_s));
- wpa_s->ctrl_sock = -1;
wpa_s->scan_req = 1;
return wpa_s;
@@ -1715,10 +2067,11 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
struct wpa_interface *iface)
{
wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
- "'%s' ctrl_interface '%s'", iface->ifname,
+ "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
iface->confname ? iface->confname : "N/A",
iface->driver ? iface->driver : "default",
- iface->ctrl_interface ? iface->ctrl_interface : "N/A");
+ iface->ctrl_interface ? iface->ctrl_interface : "N/A",
+ iface->bridge_ifname ? iface->bridge_ifname : "N/A");
if (wpa_supplicant_set_driver(wpa_s, iface->driver) < 0) {
return -1;
@@ -1726,7 +2079,7 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
if (iface->confname) {
#ifdef CONFIG_BACKEND_FILE
- wpa_s->confname = rel2abs_path(iface->confname);
+ wpa_s->confname = os_rel2abs_path(iface->confname);
if (wpa_s->confname == NULL) {
wpa_printf(MSG_ERROR, "Failed to get absolute path "
"for configuration file '%s'.",
@@ -1736,12 +2089,12 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
iface->confname, wpa_s->confname);
#else /* CONFIG_BACKEND_FILE */
- wpa_s->confname = strdup(iface->confname);
+ wpa_s->confname = os_strdup(iface->confname);
#endif /* CONFIG_BACKEND_FILE */
wpa_s->conf = wpa_config_read(wpa_s->confname);
if (wpa_s->conf == NULL) {
- printf("Failed to read read or parse configuration "
- "'%s'.\n", wpa_s->confname);
+ wpa_printf(MSG_ERROR, "Failed to read or parse "
+ "configuration '%s'.", wpa_s->confname);
return -1;
}
@@ -1750,34 +2103,46 @@ static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
* line.
*/
if (iface->ctrl_interface) {
- free(wpa_s->conf->ctrl_interface);
+ os_free(wpa_s->conf->ctrl_interface);
wpa_s->conf->ctrl_interface =
- strdup(iface->ctrl_interface);
+ os_strdup(iface->ctrl_interface);
}
if (iface->driver_param) {
- free(wpa_s->conf->driver_param);
+ os_free(wpa_s->conf->driver_param);
wpa_s->conf->driver_param =
- strdup(iface->driver_param);
+ os_strdup(iface->driver_param);
}
} else
wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
iface->driver_param);
if (wpa_s->conf == NULL) {
- printf("\nNo configuration found.\n");
+ wpa_printf(MSG_ERROR, "\nNo configuration found.");
return -1;
}
if (iface->ifname == NULL) {
- printf("\nInterface name is required.\n");
+ wpa_printf(MSG_ERROR, "\nInterface name is required.");
return -1;
}
- if (strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
- printf("Too long interface name '%s'.\n", iface->ifname);
+ if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
+ wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
+ iface->ifname);
return -1;
}
- strncpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+ os_strncpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+
+ if (iface->bridge_ifname) {
+ if (os_strlen(iface->bridge_ifname) >=
+ sizeof(wpa_s->bridge_ifname)) {
+ wpa_printf(MSG_ERROR, "\nToo long bridge interface "
+ "name '%s'.", iface->bridge_ifname);
+ return -1;
+ }
+ os_strncpy(wpa_s->bridge_ifname, iface->bridge_ifname,
+ sizeof(wpa_s->bridge_ifname));
+ }
return 0;
}
@@ -1787,13 +2152,12 @@ static int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
{
#ifdef IEEE8021X_EAPOL
struct eapol_ctx *ctx;
- ctx = malloc(sizeof(*ctx));
+ ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL) {
- printf("Failed to allocate EAPOL context.\n");
+ wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context.");
return -1;
}
- memset(ctx, 0, sizeof(*ctx));
ctx->ctx = wpa_s;
ctx->msg_ctx = wpa_s;
ctx->eapol_send_ctx = wpa_s;
@@ -1803,13 +2167,15 @@ static int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
ctx->set_wep_key = wpa_eapol_set_wep_key;
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
+ ctx->aborted_cached = wpa_supplicant_aborted_cached;
ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
wpa_s->eapol = eapol_sm_init(ctx);
if (wpa_s->eapol == NULL) {
- free(ctx);
- printf("Failed to initialize EAPOL state machines.\n");
+ os_free(ctx);
+ wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state "
+ "machines.");
return -1;
}
#endif /* IEEE8021X_EAPOL */
@@ -1822,13 +2188,12 @@ static int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
{
#ifndef CONFIG_NO_WPA
struct wpa_sm_ctx *ctx;
- ctx = malloc(sizeof(*ctx));
+ ctx = os_zalloc(sizeof(*ctx));
if (ctx == NULL) {
- printf("Failed to allocate WPA context.\n");
+ wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
return -1;
}
- memset(ctx, 0, sizeof(*ctx));
ctx->ctx = wpa_s;
ctx->set_state = _wpa_supplicant_set_state;
ctx->get_state = _wpa_supplicant_get_state;
@@ -1847,10 +2212,12 @@ static int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
ctx->set_config_blob = wpa_supplicant_set_config_blob;
ctx->get_config_blob = wpa_supplicant_get_config_blob;
+ ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
wpa_s->wpa = wpa_sm_init(ctx);
if (wpa_s->wpa == NULL) {
- fprintf(stderr, "Failed to initialize WPA state machine\n");
+ wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
+ "machine");
return -1;
}
#endif /* CONFIG_NO_WPA */
@@ -1863,6 +2230,7 @@ static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s,
int wait_for_interface)
{
const char *ifname;
+ struct wpa_driver_capa capa;
wpa_printf(MSG_DEBUG, "Initializing interface (2) '%s'",
wpa_s->ifname);
@@ -1880,50 +2248,52 @@ static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s,
* call. */
wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
if (wpa_s->drv_priv == NULL) {
- fprintf(stderr, "Failed to initialize driver interface\n");
+ wpa_printf(MSG_ERROR, "Failed to initialize driver interface");
return -1;
}
if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
- fprintf(stderr, "Driver interface rejected driver_param "
- "'%s'\n", wpa_s->conf->driver_param);
+ wpa_printf(MSG_ERROR, "Driver interface rejected "
+ "driver_param '%s'", wpa_s->conf->driver_param);
return -1;
}
ifname = wpa_drv_get_ifname(wpa_s);
- if (ifname && strcmp(ifname, wpa_s->ifname) != 0) {
+ if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
wpa_printf(MSG_DEBUG, "Driver interface replaced interface "
"name with '%s'", ifname);
- strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+ os_strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
}
if (wpa_supplicant_init_wpa(wpa_s) < 0)
return -1;
- wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname);
+ wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
+ wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
+ NULL);
wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
- fprintf(stderr, "Invalid WPA parameter value for "
- "dot11RSNAConfigPMKLifetime\n");
+ wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
+ "dot11RSNAConfigPMKLifetime");
return -1;
}
if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
- fprintf(stderr, "Invalid WPA parameter value for "
- "dot11RSNAConfigPMKReauthThreshold\n");
+ wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
+ "dot11RSNAConfigPMKReauthThreshold");
return -1;
}
if (wpa_s->conf->dot11RSNAConfigSATimeout &&
wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
wpa_s->conf->dot11RSNAConfigSATimeout)) {
- fprintf(stderr, "Invalid WPA parameter value for "
- "dot11RSNAConfigSATimeout\n");
+ wpa_printf(MSG_ERROR, "Invalid WPA parameter value for "
+ "dot11RSNAConfigSATimeout");
return -1;
}
@@ -1932,18 +2302,27 @@ static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s,
}
wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
- if (wpa_supplicant_ctrl_iface_init(wpa_s)) {
- printf("Failed to initialize control interface '%s'.\n"
- "You may have another wpa_supplicant process already "
- "running or the file was\n"
- "left by an unclean termination of wpa_supplicant in "
- "which case you will need\n"
- "to manually remove this file before starting "
- "wpa_supplicant again.\n",
- wpa_s->conf->ctrl_interface);
+ wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
+ if (wpa_s->ctrl_iface == NULL) {
+ wpa_printf(MSG_ERROR,
+ "Failed to initialize control interface '%s'.\n"
+ "You may have another wpa_supplicant process "
+ "already running or the file was\n"
+ "left by an unclean termination of wpa_supplicant "
+ "in which case you will need\n"
+ "to manually remove this file before starting "
+ "wpa_supplicant again.\n",
+ wpa_s->conf->ctrl_interface);
return -1;
}
+ if (wpa_drv_get_capa(wpa_s, &capa) == 0 &&
+ capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
+ wpa_s->use_client_mlme = 1;
+ if (ieee80211_sta_init(wpa_s))
+ return -1;
+ }
+
return 0;
}
@@ -1957,17 +2336,21 @@ static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s)
* called only just after init and just before deinit, so these
* handler can be used to implement same functionality. */
if (wpa_drv_set_wpa(wpa_s, 0) < 0) {
- fprintf(stderr, "Failed to disable WPA in the "
- "driver.\n");
+ wpa_printf(MSG_ERROR, "Failed to disable WPA in the "
+ "driver.");
}
wpa_drv_set_drop_unencrypted(wpa_s, 0);
wpa_drv_set_countermeasures(wpa_s, 0);
wpa_clear_keys(wpa_s, NULL);
-
- wpa_drv_deinit(wpa_s);
}
+
+ wpas_dbus_unregister_iface(wpa_s);
+
wpa_supplicant_cleanup(wpa_s);
+
+ if (wpa_s->drv_priv)
+ wpa_drv_deinit(wpa_s);
}
@@ -2001,11 +2384,19 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
wpa_printf(MSG_DEBUG, "Failed to add interface %s",
iface->ifname);
wpa_supplicant_deinit_iface(wpa_s);
- free(wpa_s);
+ os_free(wpa_s);
return NULL;
}
wpa_s->global = global;
+
+ /* Register the interface with the dbus control interface */
+ if (wpas_dbus_register_iface(wpa_s)) {
+ wpa_supplicant_deinit_iface(wpa_s);
+ os_free(wpa_s);
+ return NULL;
+ }
+
wpa_s->next = global->ifaces;
global->ifaces = wpa_s;
@@ -2046,7 +2437,7 @@ int wpa_supplicant_remove_iface(struct wpa_global *global,
wpa_printf(MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
wpa_supplicant_deinit_iface(wpa_s);
- free(wpa_s);
+ os_free(wpa_s);
return 0;
}
@@ -2064,7 +2455,7 @@ struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
struct wpa_supplicant *wpa_s;
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
- if (strcmp(wpa_s->ifname, ifname) == 0)
+ if (os_strcmp(wpa_s->ifname, ifname) == 0)
return wpa_s;
}
return NULL;
@@ -2083,37 +2474,68 @@ struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
{
struct wpa_global *global;
+ int ret;
if (params == NULL)
return NULL;
- global = malloc(sizeof(*global));
+
+ wpa_debug_use_file = params->wpa_debug_use_file;
+ wpa_debug_open_file();
+
+ ret = eap_peer_register_methods();
+ if (ret) {
+ wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+ if (ret == -2)
+ wpa_printf(MSG_ERROR, "Two or more EAP methods used "
+ "the same EAP type.");
+ return NULL;
+ }
+
+ global = os_zalloc(sizeof(*global));
if (global == NULL)
return NULL;
- memset(global, 0, sizeof(*global));
global->params.daemonize = params->daemonize;
global->params.wait_for_interface = params->wait_for_interface;
global->params.wait_for_monitor = params->wait_for_monitor;
+ global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
if (params->pid_file)
- global->params.pid_file = strdup(params->pid_file);
+ global->params.pid_file = os_strdup(params->pid_file);
if (params->ctrl_interface)
- global->params.ctrl_interface = strdup(params->ctrl_interface);
+ global->params.ctrl_interface =
+ os_strdup(params->ctrl_interface);
wpa_debug_level = global->params.wpa_debug_level =
params->wpa_debug_level;
wpa_debug_show_keys = global->params.wpa_debug_show_keys =
params->wpa_debug_show_keys;
wpa_debug_timestamp = global->params.wpa_debug_timestamp =
params->wpa_debug_timestamp;
+ wpa_debug_use_file = global->params.wpa_debug_use_file =
+ params->wpa_debug_use_file;
- eloop_init(global);
+ if (eloop_init(global)) {
+ wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
- if (wpa_supplicant_global_ctrl_iface_init(global)) {
- eloop_destroy();
+ global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
+ if (global->ctrl_iface == NULL) {
+ wpa_supplicant_deinit(global);
return NULL;
}
+ if (global->params.dbus_ctrl_interface) {
+ global->dbus_ctrl_iface =
+ wpa_supplicant_dbus_ctrl_iface_init(global);
+ if (global->dbus_ctrl_iface == NULL) {
+ wpa_supplicant_deinit(global);
+ return NULL;
+ }
+ }
+
if (global->params.wait_for_interface && global->params.daemonize &&
wpa_supplicant_daemon(global->params.pid_file)) {
- eloop_destroy();
+ wpa_supplicant_deinit(global);
return NULL;
}
@@ -2140,14 +2562,13 @@ int wpa_supplicant_run(struct wpa_global *global)
if (global->params.wait_for_monitor) {
for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
- wpa_supplicant_ctrl_iface_wait(wpa_s);
+ if (wpa_s->ctrl_iface)
+ wpa_supplicant_ctrl_iface_wait(
+ wpa_s->ctrl_iface);
}
- eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
- eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL);
-#ifndef CONFIG_NATIVE_WINDOWS
- eloop_register_signal(SIGHUP, wpa_supplicant_reconfig, NULL);
-#endif /* CONFIG_NATIVE_WINDOWS */
+ eloop_register_signal_terminate(wpa_supplicant_terminate, NULL);
+ eloop_register_signal_reconfig(wpa_supplicant_reconfig, NULL);
eloop_run();
@@ -2170,15 +2591,21 @@ void wpa_supplicant_deinit(struct wpa_global *global)
while (global->ifaces)
wpa_supplicant_remove_iface(global, global->ifaces);
- wpa_supplicant_global_ctrl_iface_deinit(global);
+ if (global->ctrl_iface)
+ wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
+ if (global->dbus_ctrl_iface)
+ wpa_supplicant_dbus_ctrl_iface_deinit(global->dbus_ctrl_iface);
+
+ eap_peer_unregister_methods();
eloop_destroy();
if (global->params.pid_file) {
- unlink(global->params.pid_file);
- free(global->params.pid_file);
+ os_daemonize_terminate(global->params.pid_file);
+ os_free(global->params.pid_file);
}
- free(global->params.ctrl_interface);
+ os_free(global->params.ctrl_interface);
- free(global);
+ os_free(global);
+ wpa_debug_close_file();
}
diff --git a/contrib/wpa_supplicant/wpa_supplicant.conf b/contrib/wpa_supplicant/wpa_supplicant.conf
index 92e9ec12ae6c..dce9d8705593 100644
--- a/contrib/wpa_supplicant/wpa_supplicant.conf
+++ b/contrib/wpa_supplicant/wpa_supplicant.conf
@@ -25,16 +25,22 @@
# global configuration (shared by all network blocks)
#
-# Interface for separate control program. If this is specified, wpa_supplicant
-# will create this directory and a UNIX domain socket for listening to requests
-# from external programs (CLI/GUI, etc.) for status information and
-# configuration. The socket file will be named based on the interface name, so
-# multiple wpa_supplicant processes can be run at the same time if more than
-# one interface is used.
+# Parameters for the control interface. If this is specified, wpa_supplicant
+# will open a control interface that is available for external programs to
+# manage wpa_supplicant. The meaning of this string depends on which control
+# interface mechanism is used. For all cases, the existance of this parameter
+# in configuration is used to determine whether the control interface is
+# enabled.
+#
+# For UNIX domain sockets (default on Linux and BSD): This is a directory that
+# will be created for UNIX domain sockets for listening to requests from
+# external programs (CLI/GUI, etc.) for status information and configuration.
+# The socket file will be named based on the interface name, so multiple
+# wpa_supplicant processes can be run at the same time if more than one
+# interface is used.
# /var/run/wpa_supplicant is the recommended directory for sockets and by
# default, wpa_cli will use it when trying to connect with wpa_supplicant.
-ctrl_interface=/var/run/wpa_supplicant
-
+#
# Access control for the control interface can be configured by setting the
# directory to allow only members of a group to use sockets. This way, it is
# possible to run wpa_supplicant as root (since it needs to change network
@@ -48,12 +54,28 @@ ctrl_interface=/var/run/wpa_supplicant
# not included in the configuration file, group will not be changed from the
# value it got by default when the directory or socket was created.
#
-# This variable can be a group name or gid.
-#ctrl_interface_group=wheel
-ctrl_interface_group=0
+# When configuring both the directory and group, use following format:
+# DIR=/var/run/wpa_supplicant GROUP=wheel
+# DIR=/var/run/wpa_supplicant GROUP=0
+# (group can be either group name or gid)
+#
+# For UDP connections (default on Windows): The value will be ignored. This
+# variable is just used to select that the control interface is to be created.
+# The value can be set to, e.g., udp (ctrl_interface=udp)
+#
+# For Windows Named Pipe: This value can be used to set the security descriptor
+# for controlling access to the control interface. Security descriptor can be
+# set using Security Descriptor String Format (see http://msdn.microsoft.com/
+# library/default.asp?url=/library/en-us/secauthz/security/
+# security_descriptor_string_format.asp). The descriptor string needs to be
+# prefixed with SDDL=. For example, ctrl_interface=SDDL=D: would set an empty
+# DACL (which will reject all connections). See README-Windows.txt for more
+# information about SDDL string format.
+#
+ctrl_interface=/var/run/wpa_supplicant
# IEEE 802.1X/EAPOL version
-# wpa_supplicant was implemented based on IEEE 802-1X-REV-d8 which defines
+# wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which defines
# EAPOL version 2. However, there are many APs that do not handle the new
# version number correctly (they seem to drop the frames completely). In order
# to make wpa_supplicant interoperate with these APs, the version number is set
@@ -94,11 +116,18 @@ fast_reauth=1
# They are both from the opensc project (http://www.opensc.org/)
# By default no engines are loaded.
# make the opensc engine available
-opensc_engine_path=/usr/lib/opensc/engine_opensc.so
+#opensc_engine_path=/usr/lib/opensc/engine_opensc.so
# make the pkcs11 engine available
-pkcs11_engine_path=/usr/lib/opensc/engine_pkcs11.so
+#pkcs11_engine_path=/usr/lib/opensc/engine_pkcs11.so
# configure the path to the pkcs11 module required by the pkcs11 engine
-pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
+#pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
+
+# Dynamic EAP methods
+# If EAP methods were built dynamically as shared object files, they need to be
+# loaded here before being used in the network blocks. By default, EAP methods
+# are included statically in the build, so these lines are not needed
+#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_tls.so
+#load_dynamic_eap=/usr/lib/wpa_supplicant/eap_md5.so
# Driver interface parameters
# This field can be used to configure arbitrary driver interace parameters. The
@@ -126,6 +155,10 @@ pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
# 1 = this network block is disabled (can be enabled through ctrl_iface,
# e.g., with wpa_cli or wpa_gui)
#
+# id_str: Network identifier string for external scripts. This value is passed
+# to external action script through wpa_cli as WPA_ID_STR environment
+# variable to make it easier to do network specific configuration.
+#
# ssid: SSID (mandatory); either as an ASCII string with double quotation or
# as hex string; network name
#
@@ -213,6 +246,12 @@ pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
# Note: When using wired authentication, eapol_flags must be set to 0 for the
# authentication to be completed successfully.
#
+# mixed_cell: This option can be used to configure whether so called mixed
+# cells, i.e., networks that use both plaintext and encryption in the same
+# SSID, are allowed when selecting a BSS form scan results.
+# 0 = disabled (default)
+# 1 = enabled
+#
# proactive_key_caching:
# Enable/disable opportunistic PMKSA caching for WPA2.
# 0 = disabled (default)
@@ -222,6 +261,12 @@ pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
# hex without quotation, e.g., 0102030405)
# wep_tx_keyidx: Default WEP key index (TX) (0..3)
#
+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e DLS) is
+# allowed. This is only used with RSN/WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#peerkey=1
+#
# Following fields are only used with internal EAP implementation.
# eap: space-separated list of accepted EAP methods
# MD5 = EAP-MD5 (unsecure and does not generate keying material ->
@@ -253,6 +298,9 @@ pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
# 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.
# 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
@@ -274,6 +322,9 @@ pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
# 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>.
# private_key_passwd: Password for private key file (if left out, this will be
@@ -291,12 +342,13 @@ pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
# 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@example.com
-# altsubject_match: Substring 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 this string in
-# an alternative subject name extension.
+# altsubject_match: 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: DNS:server.example.com
+# Example: EMAIL:server@example.com
+# Example: DNS:server.example.com;DNS:server2.example.com
# Following types are supported: EMAIL, DNS, URI
# phase1: Phase1 (outer authentication, i.e., TLS tunnel) parameters
# (string with field-value pairs, e.g., "peapver=0" or
@@ -336,10 +388,29 @@ pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
# altsubject_match2: Substring to be matched against the alternative subject
# name of the authentication server certificate.
#
+# 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.
+#
# EAP-PSK variables:
# eappsk: 16-byte (128-bit, 32 hex digits) pre-shared key in hex format
# nai: user NAI
#
+# EAP-PAX variables:
+# eappsk: 16-byte (128-bit, 32 hex digits) pre-shared key in hex format
+#
+# EAP-SAKE variables:
+# eappsk: 32-byte (256-bit, 64 hex digits) pre-shared key in hex format
+# (this is concatenation of Root-Secret-A and Root-Secret-B)
+# nai: user NAI (PEERID)
+#
+# EAP-GPSK variables:
+# eappsk: Pre-shared key in hex format (at least 128 bits, i.e., 32 hex digits)
+# nai: user NAI (ID_Client)
+#
# EAP-FAST variables:
# pac_file: File path for the PAC entries. wpa_supplicant will need to be able
# to create this file and write updates to it when PAC is being
@@ -660,3 +731,10 @@ network={
blob-base64-exampleblob={
SGVsbG8gV29ybGQhCg==
}
+
+
+# Wildcard match for SSID (plaintext APs only). This example select any
+# open AP regardless of its SSID.
+network={
+ key_mgmt=NONE
+}
diff --git a/contrib/wpa_supplicant/wpa_supplicant.h b/contrib/wpa_supplicant/wpa_supplicant.h
index e7e6f0d02172..763f30d2add3 100644
--- a/contrib/wpa_supplicant/wpa_supplicant.h
+++ b/contrib/wpa_supplicant/wpa_supplicant.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - Exported functions for wpa_supplicant modules
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -121,7 +121,18 @@ typedef enum wpa_event_type {
* Driver will be notified about successful pre-authentication with
* struct wpa_driver_ops::add_pmkid() calls.
*/
- EVENT_PMKID_CANDIDATE
+ EVENT_PMKID_CANDIDATE,
+
+ /**
+ * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request)
+ *
+ * This event can be used to inform wpa_supplicant about desire to set
+ * up secure direct link connection between two stations as defined in
+ * IEEE 802.11e with a new PeerKey mechanism that replaced the original
+ * STAKey negotiation. The caller will need to set peer address for the
+ * event.
+ */
+ EVENT_STKSTART
} wpa_event_type;
@@ -208,7 +219,7 @@ union wpa_event_data {
* struct interface_status - Data for EVENT_INTERFACE_STATUS
*/
struct interface_status {
- char ifname[20];
+ char ifname[100];
enum {
EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
} ievent;
@@ -225,6 +236,13 @@ union wpa_event_data {
/** Whether RSN IE includes pre-authenticate flag */
int preauth;
} pmkid_candidate;
+
+ /**
+ * struct stkstart - Data for EVENT_STKSTART
+ */
+ struct stkstart {
+ u8 peer[ETH_ALEN];
+ } stkstart;
};
/**
@@ -241,25 +259,6 @@ void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
union wpa_event_data *data);
/**
- * wpa_msg - Conditional printf for default target and ctrl_iface monitors
- * @wpa_s: pointer to wpa_supplicant 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(struct wpa_supplicant *wpa_s, int level, char *fmt, ...)
-__attribute__ ((format (printf, 3, 4)));
-
-const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len);
-
-/**
* wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
* @ctx: Context pointer (wpa_s)
* @src_addr: Source address of the EAPOL frame
diff --git a/contrib/wpa_supplicant/wpa_supplicant_i.h b/contrib/wpa_supplicant/wpa_supplicant_i.h
index a22bc6f7aa58..bb80f898f873 100644
--- a/contrib/wpa_supplicant/wpa_supplicant_i.h
+++ b/contrib/wpa_supplicant/wpa_supplicant_i.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant - Internal definitions
- * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -28,6 +28,15 @@ struct wpa_scan_result;
struct wpa_sm;
struct wpa_supplicant;
+/*
+ * Forward declarations of private structures used within the ctrl_iface
+ * backends. Other parts of wpa_supplicant do not have access to data stored in
+ * these structures.
+ */
+struct ctrl_iface_priv;
+struct ctrl_iface_global_priv;
+struct ctrl_iface_dbus_priv;
+
/**
* struct wpa_interface - Parameters for wpa_supplicant_add_iface()
*/
@@ -72,6 +81,16 @@ struct wpa_interface {
* ifname - Interface name
*/
const char *ifname;
+
+ /**
+ * bridge_ifname - Optional bridge interface name
+ *
+ * If the driver interface (ifname) is included in a Linux bridge
+ * device, the bridge interface may need to be used for receiving EAPOL
+ * frames. This can be enabled by setting this variable to enable
+ * receiving of EAPOL frames from an additional interface.
+ */
+ const char *bridge_ifname;
};
/**
@@ -132,6 +151,16 @@ struct wpa_params {
* ctrl_interface - Global ctrl_iface path/parameter
*/
char *ctrl_interface;
+
+ /**
+ * dbus_ctrl_interface - Enable the DBus control interface
+ */
+ int dbus_ctrl_interface;
+
+ /**
+ * wpa_debug_use_file - Write debug to a file (instead of stdout)
+ */
+ int wpa_debug_use_file;
};
/**
@@ -143,7 +172,91 @@ struct wpa_params {
struct wpa_global {
struct wpa_supplicant *ifaces;
struct wpa_params params;
- int ctrl_sock;
+ struct ctrl_iface_global_priv *ctrl_iface;
+ struct ctrl_iface_dbus_priv *dbus_ctrl_iface;
+};
+
+
+struct wpa_client_mlme {
+#ifdef CONFIG_CLIENT_MLME
+ enum {
+ IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
+ IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
+ IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
+ } state;
+ u8 prev_bssid[ETH_ALEN];
+ u8 ssid[32];
+ size_t ssid_len;
+ u16 aid;
+ u16 ap_capab, capab;
+ u8 *extra_ie; /* to be added to the end of AssocReq */
+ size_t extra_ie_len;
+ wpa_key_mgmt key_mgmt;
+
+ /* The last AssocReq/Resp IEs */
+ u8 *assocreq_ies, *assocresp_ies;
+ size_t assocreq_ies_len, assocresp_ies_len;
+
+ int auth_tries, assoc_tries;
+
+ unsigned int ssid_set:1;
+ unsigned int bssid_set:1;
+ unsigned int prev_bssid_set:1;
+ unsigned int authenticated:1;
+ unsigned int associated:1;
+ unsigned int probereq_poll:1;
+ unsigned int use_protection:1;
+ unsigned int create_ibss:1;
+ unsigned int mixed_cell:1;
+ unsigned int wmm_enabled:1;
+
+ struct os_time last_probe;
+
+#define IEEE80211_AUTH_ALG_OPEN BIT(0)
+#define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
+#define IEEE80211_AUTH_ALG_LEAP BIT(2)
+ unsigned int auth_algs; /* bitfield of allowed auth algs */
+ int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
+ int auth_transaction;
+
+ struct os_time ibss_join_req;
+ u8 *probe_resp; /* ProbeResp template for IBSS */
+ size_t probe_resp_len;
+ u32 supp_rates_bits;
+
+ int wmm_last_param_set;
+
+ int sta_scanning;
+ int scan_hw_mode_idx;
+ int scan_channel_idx;
+ enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
+ struct os_time last_scan_completed;
+ int scan_oper_channel;
+ int scan_oper_freq;
+ int scan_oper_phymode;
+ u8 scan_ssid[32];
+ size_t scan_ssid_len;
+ int scan_skip_11b;
+
+ struct ieee80211_sta_bss *sta_bss_list;
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+ struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
+
+ int cts_protect_erp_frames;
+
+ int phymode; /* current mode; WPA_MODE_IEEE80211A, .. */
+ struct wpa_hw_modes *modes;
+ size_t num_modes;
+ unsigned int hw_modes; /* bitfield of allowed hardware modes;
+ * (1 << MODE_*) */
+ int num_curr_rates;
+ struct wpa_rate_data *curr_rates;
+ int freq; /* The current frequency in MHz */
+ int channel; /* The current IEEE 802.11 channel number */
+#else /* CONFIG_CLIENT_MLME */
+ int dummy; /* to keep MSVC happy */
+#endif /* CONFIG_CLIENT_MLME */
};
/**
@@ -158,14 +271,21 @@ struct wpa_supplicant {
struct wpa_global *global;
struct wpa_supplicant *next;
struct l2_packet_data *l2;
+ struct l2_packet_data *l2_br;
unsigned char own_addr[ETH_ALEN];
char ifname[100];
+#ifdef CONFIG_CTRL_IFACE_DBUS
+ char *dbus_path;
+#endif /* CONFIG_CTRL_IFACE_DBUS */
+ char bridge_ifname[16];
char *confname;
struct wpa_config *conf;
int countermeasures;
- time_t last_michael_mic_error;
+ os_time_t last_michael_mic_error;
u8 bssid[ETH_ALEN];
+ u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
+ * field contains the targer BSSID. */
int reassociate; /* reassociation requested */
int disconnected; /* all connections disabled; i.e., do no reassociate
* before this has been cleared */
@@ -175,6 +295,7 @@ struct wpa_supplicant {
int pairwise_cipher;
int group_cipher;
int key_mgmt;
+ int mgmt_group_cipher;
void *drv_priv; /* private data used by driver_ops */
@@ -195,9 +316,7 @@ struct wpa_supplicant {
struct wpa_sm *wpa;
struct eapol_sm *eapol;
- int ctrl_sock; /* UNIX domain socket for control interface or -1 if
- * not used */
- struct wpa_ctrl_dst *ctrl_dst;
+ struct ctrl_iface_priv *ctrl_iface;
wpa_states wpa_state;
int new_connection;
@@ -216,6 +335,13 @@ struct wpa_supplicant {
int scan_req; /* manual scan request; this forces a scan even if there
* are no enabled networks in the configuration */
+ int scan_res_tried; /* whether ap_scan=1 mode has tried to fetch scan
+ * results without a new scan request; this is used
+ * to speed up the first association if the driver
+ * has already available scan results. */
+
+ struct wpa_client_mlme mlme;
+ int use_client_mlme;
};
@@ -230,7 +356,6 @@ int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
const u8 *bssid);
int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
-int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
void wpa_blacklist_clear(struct wpa_supplicant *wpa_s);
int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
struct wpa_scan_result *bss,
@@ -270,6 +395,8 @@ void wpa_supplicant_deinit(struct wpa_global *global);
int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
+/* events.c */
+void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
/* driver_ops */
static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s,
@@ -481,4 +608,89 @@ static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s,
return -1;
}
+static inline int wpa_drv_set_operstate(struct wpa_supplicant *wpa_s,
+ int state)
+{
+ if (wpa_s->driver->set_operstate)
+ return wpa_s->driver->set_operstate(wpa_s->drv_priv, state);
+ return 0;
+}
+
+static inline int wpa_drv_mlme_setprotection(struct wpa_supplicant *wpa_s,
+ const u8 *addr, int protect_type,
+ int key_type)
+{
+ if (wpa_s->driver->mlme_setprotection)
+ return wpa_s->driver->mlme_setprotection(wpa_s->drv_priv, addr,
+ protect_type,
+ key_type);
+ return 0;
+}
+
+static inline struct wpa_hw_modes *
+wpa_drv_get_hw_feature_data(struct wpa_supplicant *wpa_s, u16 *num_modes,
+ u16 *flags)
+{
+ if (wpa_s->driver->get_hw_feature_data)
+ return wpa_s->driver->get_hw_feature_data(wpa_s->drv_priv,
+ num_modes, flags);
+ return NULL;
+}
+
+static inline int wpa_drv_set_channel(struct wpa_supplicant *wpa_s,
+ wpa_hw_mode phymode, int chan,
+ int freq)
+{
+ if (wpa_s->driver->set_channel)
+ return wpa_s->driver->set_channel(wpa_s->drv_priv, phymode,
+ chan, freq);
+ return -1;
+}
+
+static inline int wpa_drv_set_ssid(struct wpa_supplicant *wpa_s,
+ const u8 *ssid, size_t ssid_len)
+{
+ if (wpa_s->driver->set_ssid) {
+ return wpa_s->driver->set_ssid(wpa_s->drv_priv, ssid,
+ ssid_len);
+ }
+ return -1;
+}
+
+static inline int wpa_drv_set_bssid(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
+{
+ if (wpa_s->driver->set_bssid) {
+ return wpa_s->driver->set_bssid(wpa_s->drv_priv, bssid);
+ }
+ return -1;
+}
+
+static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
+ const u8 *data, size_t data_len)
+{
+ if (wpa_s->driver->send_mlme)
+ return wpa_s->driver->send_mlme(wpa_s->drv_priv,
+ data, data_len);
+ return -1;
+}
+
+static inline int wpa_drv_mlme_add_sta(struct wpa_supplicant *wpa_s,
+ const u8 *addr, const u8 *supp_rates,
+ size_t supp_rates_len)
+{
+ if (wpa_s->driver->mlme_add_sta)
+ return wpa_s->driver->mlme_add_sta(wpa_s->drv_priv, addr,
+ supp_rates, supp_rates_len);
+ return -1;
+}
+
+static inline int wpa_drv_mlme_remove_sta(struct wpa_supplicant *wpa_s,
+ const u8 *addr)
+{
+ if (wpa_s->driver->mlme_remove_sta)
+ return wpa_s->driver->mlme_remove_sta(wpa_s->drv_priv, addr);
+ return -1;
+}
+
#endif /* WPA_SUPPLICANT_I_H */
diff --git a/contrib/wpa_supplicant/x509v3.c b/contrib/wpa_supplicant/x509v3.c
new file mode 100644
index 000000000000..1283fff04f7d
--- /dev/null
+++ b/contrib/wpa_supplicant/x509v3.c
@@ -0,0 +1,1596 @@
+/*
+ * X.509v3 certificate parsing and processing (RFC 3280 profile)
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+
+#ifdef CONFIG_INTERNAL_X509
+
+#include "asn1.h"
+#include "crypto.h"
+#include "x509v3.h"
+
+
+static void x509_free_name(struct x509_name *name)
+{
+ os_free(name->cn);
+ os_free(name->c);
+ os_free(name->l);
+ os_free(name->st);
+ os_free(name->o);
+ os_free(name->ou);
+ os_free(name->email);
+ name->cn = name->c = name->l = name->st = name->o = name->ou = NULL;
+ name->email = NULL;
+}
+
+
+/**
+ * x509_certificate_free - Free an X.509 certificate
+ * @cert: Certificate to be freed
+ */
+void x509_certificate_free(struct x509_certificate *cert)
+{
+ if (cert == NULL)
+ return;
+ if (cert->next) {
+ wpa_printf(MSG_DEBUG, "X509: x509_certificate_free: cer=%p "
+ "was still on a list (next=%p)\n",
+ cert, cert->next);
+ }
+ x509_free_name(&cert->issuer);
+ x509_free_name(&cert->subject);
+ os_free(cert->public_key);
+ os_free(cert->sign_value);
+ os_free(cert);
+}
+
+
+/**
+ * x509_certificate_free - Free an X.509 certificate chain
+ * @cert: Pointer to the first certificate in the chain
+ */
+void x509_certificate_chain_free(struct x509_certificate *cert)
+{
+ struct x509_certificate *next;
+
+ while (cert) {
+ next = cert->next;
+ cert->next = NULL;
+ x509_certificate_free(cert);
+ cert = next;
+ }
+}
+
+
+static int x509_str_compare(const char *a, const char *b)
+{
+ if (!a && b)
+ return -1;
+ if (a && !b)
+ return 1;
+ if (!a && !b)
+ return 0;
+
+ return os_strcmp(a, b);
+}
+
+
+/**
+ * x509_name_compare - Compare X.509 certificate names
+ * @a: Certificate name
+ * @b: Certifiatte name
+ * Returns: <0, 0, or >0 based on whether a is less than, equal to, or
+ * greater than b
+ */
+int x509_name_compare(struct x509_name *a, struct x509_name *b)
+{
+ int res;
+
+ if (!a && b)
+ return -1;
+ if (a && !b)
+ return 1;
+ if (!a && !b)
+ return 0;
+
+ res = x509_str_compare(a->cn, b->cn);
+ if (res)
+ return res;
+ res = x509_str_compare(a->c, b->c);
+ if (res)
+ return res;
+ res = x509_str_compare(a->l, b->l);
+ if (res)
+ return res;
+ res = x509_str_compare(a->st, b->st);
+ if (res)
+ return res;
+ res = x509_str_compare(a->o, b->o);
+ if (res)
+ return res;
+ res = x509_str_compare(a->ou, b->ou);
+ if (res)
+ return res;
+ res = x509_str_compare(a->email, b->email);
+ if (res)
+ return res;
+
+ return 0;
+}
+
+
+static int x509_parse_algorithm_identifier(
+ const u8 *buf, size_t len,
+ struct x509_algorithm_identifier *id, const u8 **next)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+
+ /*
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ */
+
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+ "(AlgorithmIdentifier) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ if (end > buf + len)
+ return -1;
+
+ *next = end;
+
+ if (asn1_get_oid(pos, end - pos, &id->oid, &pos))
+ return -1;
+
+ /* TODO: optional parameters */
+
+ return 0;
+}
+
+
+static int x509_parse_public_key(const u8 *buf, size_t len,
+ struct x509_certificate *cert,
+ const u8 **next)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+
+ /*
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ */
+
+ pos = buf;
+ end = buf + len;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+ "(SubjectPublicKeyInfo) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+
+ if (pos + hdr.length > end)
+ return -1;
+ end = pos + hdr.length;
+ *next = end;
+
+ if (x509_parse_algorithm_identifier(pos, end - pos,
+ &cert->public_key_alg, &pos))
+ return -1;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_BITSTRING) {
+ wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
+ "(subjectPublicKey) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length < 1)
+ return -1;
+ pos = hdr.payload;
+ if (*pos) {
+ wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
+ *pos);
+ /*
+ * TODO: should this be rejected? X.509 certificates are
+ * unlikely to use such a construction. Now we would end up
+ * including the extra bits in the buffer which may also be
+ * ok.
+ */
+ }
+ os_free(cert->public_key);
+ cert->public_key = os_malloc(hdr.length - 1);
+ if (cert->public_key == NULL) {
+ wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
+ "public key");
+ return -1;
+ }
+ os_memcpy(cert->public_key, pos + 1, hdr.length - 1);
+ cert->public_key_len = hdr.length - 1;
+ wpa_hexdump(MSG_MSGDUMP, "X509: subjectPublicKey",
+ cert->public_key, cert->public_key_len);
+
+ return 0;
+}
+
+
+static int x509_parse_name(const u8 *buf, size_t len, struct x509_name *name,
+ const u8 **next)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end, *set_pos, *set_end, *seq_pos, *seq_end;
+ struct asn1_oid oid;
+ char **fieldp;
+
+ /*
+ * Name ::= CHOICE { RDNSequence }
+ * RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+ * RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
+ * AttributeTypeAndValue ::= SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue
+ * }
+ * AttributeType ::= OBJECT IDENTIFIER
+ * AttributeValue ::= ANY DEFINED BY AttributeType
+ */
+
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+ "(Name / RDNSequencer) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+
+ if (pos + hdr.length > buf + len)
+ return -1;
+
+ end = *next = pos + hdr.length;
+
+ while (pos < end) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SET) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SET "
+ "(RelativeDistinguishedName) - found class "
+ "%d tag 0x%x", hdr.class, hdr.tag);
+ x509_free_name(name);
+ return -1;
+ }
+
+ set_pos = hdr.payload;
+ pos = set_end = hdr.payload + hdr.length;
+
+ if (asn1_get_next(set_pos, set_end - set_pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+ "(AttributeTypeAndValue) - found class %d "
+ "tag 0x%x", hdr.class, hdr.tag);
+ x509_free_name(name);
+ return -1;
+ }
+
+ seq_pos = hdr.payload;
+ seq_end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(seq_pos, seq_end - seq_pos, &oid, &seq_pos)) {
+ x509_free_name(name);
+ return -1;
+ }
+
+ if (asn1_get_next(seq_pos, seq_end - seq_pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL) {
+ wpa_printf(MSG_DEBUG, "X509: Failed to parse "
+ "AttributeValue");
+ x509_free_name(name);
+ return -1;
+ }
+
+ /* RFC 3280:
+ * MUST: country, organization, organizational-unit,
+ * distinguished name qualifier, state or province name,
+ * common name, serial number.
+ * SHOULD: locality, title, surname, given name, initials,
+ * pseudonym, generation qualifier.
+ * MUST: domainComponent (RFC 2247).
+ */
+ fieldp = NULL;
+ if (oid.len == 4 &&
+ oid.oid[0] == 2 && oid.oid[1] == 5 && oid.oid[2] == 4) {
+ /* id-at ::= 2.5.4 */
+ switch (oid.oid[3]) {
+ case 3:
+ /* commonName */
+ fieldp = &name->cn;
+ break;
+ case 6:
+ /* countryName */
+ fieldp = &name->c;
+ break;
+ case 7:
+ /* localityName */
+ fieldp = &name->l;
+ break;
+ case 8:
+ /* stateOrProvinceName */
+ fieldp = &name->st;
+ break;
+ case 10:
+ /* organizationName */
+ fieldp = &name->o;
+ break;
+ case 11:
+ /* organizationalUnitName */
+ fieldp = &name->ou;
+ break;
+ }
+ } else if (oid.len == 7 &&
+ oid.oid[0] == 1 && oid.oid[1] == 2 &&
+ oid.oid[2] == 840 && oid.oid[3] == 113549 &&
+ oid.oid[4] == 1 && oid.oid[5] == 9 &&
+ oid.oid[6] == 1) {
+ /* 1.2.840.113549.1.9.1 - e-mailAddress */
+ fieldp = &name->email;
+ }
+
+ if (fieldp == NULL) {
+ wpa_hexdump(MSG_DEBUG, "X509: Unrecognized OID",
+ (u8 *) oid.oid,
+ oid.len * sizeof(oid.oid[0]));
+ wpa_hexdump_ascii(MSG_MSGDUMP, "X509: Attribute Data",
+ hdr.payload, hdr.length);
+ continue;
+ }
+
+ os_free(*fieldp);
+ *fieldp = os_malloc(hdr.length + 1);
+ if (*fieldp == NULL) {
+ x509_free_name(name);
+ return -1;
+ }
+ os_memcpy(*fieldp, hdr.payload, hdr.length);
+ (*fieldp)[hdr.length] = '\0';
+ }
+
+ return 0;
+}
+
+
+/**
+ * x509_name_string - Convert an X.509 certificate name into a string
+ * @name: Name to convert
+ * @buf: Buffer for the string
+ * @len: Maximum buffer length
+ */
+void x509_name_string(struct x509_name *name, char *buf, size_t len)
+{
+ char *pos, *end;
+ int ret;
+
+ if (len == 0)
+ return;
+
+ pos = buf;
+ end = buf + len;
+
+ if (name->c) {
+ ret = os_snprintf(pos, end - pos, "C=%s, ", name->c);
+ if (ret < 0 || ret >= end - pos)
+ goto done;
+ pos += ret;
+ }
+ if (name->st) {
+ ret = os_snprintf(pos, end - pos, "ST=%s, ", name->st);
+ if (ret < 0 || ret >= end - pos)
+ goto done;
+ pos += ret;
+ }
+ if (name->l) {
+ ret = os_snprintf(pos, end - pos, "L=%s, ", name->l);
+ if (ret < 0 || ret >= end - pos)
+ goto done;
+ pos += ret;
+ }
+ if (name->o) {
+ ret = os_snprintf(pos, end - pos, "O=%s, ", name->o);
+ if (ret < 0 || ret >= end - pos)
+ goto done;
+ pos += ret;
+ }
+ if (name->ou) {
+ ret = os_snprintf(pos, end - pos, "OU=%s, ", name->ou);
+ if (ret < 0 || ret >= end - pos)
+ goto done;
+ pos += ret;
+ }
+ if (name->cn) {
+ ret = os_snprintf(pos, end - pos, "CN=%s, ", name->cn);
+ if (ret < 0 || ret >= end - pos)
+ goto done;
+ pos += ret;
+ }
+
+ if (pos > buf + 1 && pos[-1] == ' ' && pos[-2] == ',') {
+ *pos-- = '\0';
+ *pos-- = '\0';
+ }
+
+ if (name->email) {
+ ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
+ name->email);
+ if (ret < 0 || ret >= end - pos)
+ goto done;
+ pos += ret;
+ }
+
+done:
+ end[-1] = '\0';
+}
+
+
+static int x509_parse_time(const u8 *buf, size_t len, u8 asn1_tag,
+ os_time_t *val)
+{
+ const char *pos;
+ int year, month, day, hour, min, sec;
+
+ /*
+ * Time ::= CHOICE {
+ * utcTime UTCTime,
+ * generalTime GeneralizedTime
+ * }
+ *
+ * UTCTime: YYMMDDHHMMSSZ
+ * GeneralizedTime: YYYYMMDDHHMMSSZ
+ */
+
+ pos = (const char *) buf;
+
+ switch (asn1_tag) {
+ case ASN1_TAG_UTCTIME:
+ if (len != 13 || buf[12] != 'Z') {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
+ "UTCTime format", buf, len);
+ return -1;
+ }
+ if (sscanf(pos, "%02d", &year) != 1) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
+ "UTCTime year", buf, len);
+ return -1;
+ }
+ if (year < 50)
+ year += 2000;
+ else
+ year += 1900;
+ pos += 2;
+ break;
+ case ASN1_TAG_GENERALIZEDTIME:
+ if (len != 15 || buf[14] != 'Z') {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Unrecognized "
+ "GeneralizedTime format", buf, len);
+ return -1;
+ }
+ if (sscanf(pos, "%04d", &year) != 1) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse "
+ "GeneralizedTime year", buf, len);
+ return -1;
+ }
+ pos += 4;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "X509: Expected UTCTime or "
+ "GeneralizedTime - found tag 0x%x", asn1_tag);
+ return -1;
+ }
+
+ if (sscanf(pos, "%02d", &month) != 1) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+ "(month)", buf, len);
+ return -1;
+ }
+ pos += 2;
+
+ if (sscanf(pos, "%02d", &day) != 1) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+ "(day)", buf, len);
+ return -1;
+ }
+ pos += 2;
+
+ if (sscanf(pos, "%02d", &hour) != 1) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+ "(hour)", buf, len);
+ return -1;
+ }
+ pos += 2;
+
+ if (sscanf(pos, "%02d", &min) != 1) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+ "(min)", buf, len);
+ return -1;
+ }
+ pos += 2;
+
+ if (sscanf(pos, "%02d", &sec) != 1) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse Time "
+ "(sec)", buf, len);
+ return -1;
+ }
+
+ if (os_mktime(year, month, day, hour, min, sec, val) < 0) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to convert Time",
+ buf, len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int x509_parse_validity(const u8 *buf, size_t len,
+ struct x509_certificate *cert, const u8 **next)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos;
+ size_t plen;
+
+ /*
+ * Validity ::= SEQUENCE {
+ * notBefore Time,
+ * notAfter Time
+ * }
+ *
+ * RFC 3280, 4.1.2.5:
+ * CAs conforming to this profile MUST always encode certificate
+ * validity dates through the year 2049 as UTCTime; certificate
+ * validity dates in 2050 or later MUST be encoded as GeneralizedTime.
+ */
+
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+ "(Validity) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ plen = hdr.length;
+
+ if (pos + plen > buf + len)
+ return -1;
+
+ *next = pos + plen;
+
+ if (asn1_get_next(pos, plen, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+ &cert->not_before) < 0) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notBefore "
+ "Time", hdr.payload, hdr.length);
+ return -1;
+ }
+
+ pos = hdr.payload + hdr.length;
+ plen = *next - pos;
+
+ if (asn1_get_next(pos, plen, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ x509_parse_time(hdr.payload, hdr.length, hdr.tag,
+ &cert->not_after) < 0) {
+ wpa_hexdump_ascii(MSG_DEBUG, "X509: Failed to parse notAfter "
+ "Time", hdr.payload, hdr.length);
+ return -1;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "X509: Validity: notBefore: %lu notAfter: %lu",
+ (unsigned long) cert->not_before,
+ (unsigned long) cert->not_after);
+
+ return 0;
+}
+
+
+static int x509_id_ce_oid(struct asn1_oid *oid)
+{
+ /* id-ce arc from X.509 for standard X.509v3 extensions */
+ return oid->len >= 4 &&
+ oid->oid[0] == 2 /* joint-iso-ccitt */ &&
+ oid->oid[1] == 5 /* ds */ &&
+ oid->oid[2] == 29 /* id-ce */;
+}
+
+
+static int x509_parse_ext_key_usage(struct x509_certificate *cert,
+ const u8 *pos, size_t len)
+{
+ struct asn1_hdr hdr;
+
+ /*
+ * KeyUsage ::= BIT STRING {
+ * digitalSignature (0),
+ * nonRepudiation (1),
+ * keyEncipherment (2),
+ * dataEncipherment (3),
+ * keyAgreement (4),
+ * keyCertSign (5),
+ * cRLSign (6),
+ * encipherOnly (7),
+ * decipherOnly (8) }
+ */
+
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_BITSTRING ||
+ hdr.length < 1) {
+ wpa_printf(MSG_DEBUG, "X509: Expected BIT STRING in "
+ "KeyUsage; found %d tag 0x%x len %d",
+ hdr.class, hdr.tag, hdr.length);
+ return -1;
+ }
+
+ cert->extensions_present |= X509_EXT_KEY_USAGE;
+ cert->key_usage = asn1_bit_string_to_long(hdr.payload, hdr.length);
+
+ wpa_printf(MSG_DEBUG, "X509: KeyUsage 0x%lx", cert->key_usage);
+
+ return 0;
+}
+
+
+static int x509_parse_ext_basic_constraints(struct x509_certificate *cert,
+ const u8 *pos, size_t len)
+{
+ struct asn1_hdr hdr;
+ unsigned long value;
+ size_t left;
+
+ /*
+ * BasicConstraints ::= SEQUENCE {
+ * cA BOOLEAN DEFAULT FALSE,
+ * pathLenConstraint INTEGER (0..MAX) OPTIONAL }
+ */
+
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE in "
+ "BasicConstraints; found %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ cert->extensions_present |= X509_EXT_BASIC_CONSTRAINTS;
+
+ if (hdr.length == 0)
+ return 0;
+
+ if (asn1_get_next(hdr.payload, hdr.length, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL) {
+ wpa_printf(MSG_DEBUG, "X509: Failed to parse "
+ "BasicConstraints");
+ return -1;
+ }
+
+ if (hdr.tag == ASN1_TAG_BOOLEAN) {
+ if (hdr.length != 1) {
+ wpa_printf(MSG_DEBUG, "X509: Unexpected "
+ "Boolean length (%u) in BasicConstraints",
+ hdr.length);
+ return -1;
+ }
+ cert->ca = hdr.payload[0];
+
+ if (hdr.payload + hdr.length == pos + len) {
+ wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d",
+ cert->ca);
+ return 0;
+ }
+
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL) {
+ wpa_printf(MSG_DEBUG, "X509: Failed to parse "
+ "BasicConstraints");
+ return -1;
+ }
+ }
+
+ if (hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG, "X509: Expected INTEGER in "
+ "BasicConstraints; found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ left = hdr.length;
+ value = 0;
+ while (left) {
+ value <<= 8;
+ value |= *pos++;
+ left--;
+ }
+
+ cert->path_len_constraint = value;
+ cert->extensions_present |= X509_EXT_PATH_LEN_CONSTRAINT;
+
+ wpa_printf(MSG_DEBUG, "X509: BasicConstraints - cA=%d "
+ "pathLenConstraint=%lu",
+ cert->ca, cert->path_len_constraint);
+
+ return 0;
+}
+
+
+static int x509_parse_extension_data(struct x509_certificate *cert,
+ struct asn1_oid *oid,
+ const u8 *pos, size_t len)
+{
+ if (!x509_id_ce_oid(oid))
+ return 1;
+
+ /* TODO: add other extensions required by RFC 3280, Ch 4.2:
+ * certificate policies (section 4.2.1.5)
+ * the subject alternative name (section 4.2.1.7)
+ * name constraints (section 4.2.1.11)
+ * policy constraints (section 4.2.1.12)
+ * extended key usage (section 4.2.1.13)
+ * inhibit any-policy (section 4.2.1.15)
+ */
+ switch (oid->oid[3]) {
+ case 15: /* id-ce-keyUsage */
+ return x509_parse_ext_key_usage(cert, pos, len);
+ case 19: /* id-ce-basicConstraints */
+ return x509_parse_ext_basic_constraints(cert, pos, len);
+ default:
+ return 1;
+ }
+}
+
+
+static int x509_parse_extension(struct x509_certificate *cert,
+ const u8 *pos, size_t len, const u8 **next)
+{
+ const u8 *end;
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+ int critical_ext = 0, res;
+ char buf[80];
+
+ /*
+ * Extension ::= SEQUENCE {
+ * extnID OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING
+ * }
+ */
+
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
+ "Extensions: class %d tag 0x%x; expected SEQUENCE",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ *next = end = pos + hdr.length;
+
+ if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data for "
+ "Extension (expected OID)");
+ return -1;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ (hdr.tag != ASN1_TAG_BOOLEAN &&
+ hdr.tag != ASN1_TAG_OCTETSTRING)) {
+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header in "
+ "Extensions: class %d tag 0x%x; expected BOOLEAN "
+ "or OCTET STRING", hdr.class, hdr.tag);
+ return -1;
+ }
+
+ if (hdr.tag == ASN1_TAG_BOOLEAN) {
+ if (hdr.length != 1) {
+ wpa_printf(MSG_DEBUG, "X509: Unexpected "
+ "Boolean length (%u)", hdr.length);
+ return -1;
+ }
+ critical_ext = hdr.payload[0];
+ pos = hdr.payload;
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ (hdr.class != ASN1_CLASS_UNIVERSAL &&
+ hdr.class != ASN1_CLASS_PRIVATE) ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 header "
+ "in Extensions: class %d tag 0x%x; "
+ "expected OCTET STRING",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ }
+
+ asn1_oid_to_str(&oid, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "X509: Extension: extnID=%s critical=%d",
+ buf, critical_ext);
+ wpa_hexdump(MSG_MSGDUMP, "X509: extnValue", hdr.payload, hdr.length);
+
+ res = x509_parse_extension_data(cert, &oid, hdr.payload, hdr.length);
+ if (res < 0)
+ return res;
+ if (res == 1 && critical_ext) {
+ wpa_printf(MSG_INFO, "X509: Unknown critical extension %s",
+ buf);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int x509_parse_extensions(struct x509_certificate *cert,
+ const u8 *pos, size_t len)
+{
+ const u8 *end;
+ struct asn1_hdr hdr;
+
+ /* Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension */
+
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Unexpected ASN.1 data "
+ "for Extensions: class %d tag 0x%x; "
+ "expected SEQUENCE", hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ while (pos < end) {
+ if (x509_parse_extension(cert, pos, end - pos, &pos)
+ < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int x509_parse_tbs_certificate(const u8 *buf, size_t len,
+ struct x509_certificate *cert,
+ const u8 **next)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end;
+ size_t left;
+ char sbuf[128];
+ unsigned long value;
+
+ /* tbsCertificate TBSCertificate ::= SEQUENCE */
+ if (asn1_get_next(buf, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: tbsCertificate did not start "
+ "with a valid SEQUENCE - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ pos = hdr.payload;
+ end = *next = pos + hdr.length;
+
+ /*
+ * version [0] EXPLICIT Version DEFAULT v1
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0)
+ return -1;
+ pos = hdr.payload;
+
+ if (hdr.class == ASN1_CLASS_CONTEXT_SPECIFIC) {
+ if (asn1_get_next(pos, end - pos, &hdr) < 0)
+ return -1;
+
+ if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
+ "version field - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ if (hdr.length != 1) {
+ wpa_printf(MSG_DEBUG, "X509: Unexpected version field "
+ "length %u (expected 1)", hdr.length);
+ return -1;
+ }
+ pos = hdr.payload;
+ left = hdr.length;
+ value = 0;
+ while (left) {
+ value <<= 8;
+ value |= *pos++;
+ left--;
+ }
+
+ cert->version = value;
+ if (cert->version != X509_CERT_V1 &&
+ cert->version != X509_CERT_V2 &&
+ cert->version != X509_CERT_V3) {
+ wpa_printf(MSG_DEBUG, "X509: Unsupported version %d",
+ cert->version + 1);
+ return -1;
+ }
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0)
+ return -1;
+ } else
+ cert->version = X509_CERT_V1;
+ wpa_printf(MSG_MSGDUMP, "X509: Version X.509v%d", cert->version + 1);
+
+ /* serialNumber CertificateSerialNumber ::= INTEGER */
+ if (hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_INTEGER) {
+ wpa_printf(MSG_DEBUG, "X509: No INTEGER tag found for "
+ "serialNumber; class=%d tag=0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ left = hdr.length;
+ while (left) {
+ cert->serial_number <<= 8;
+ cert->serial_number |= *pos++;
+ left--;
+ }
+ wpa_printf(MSG_MSGDUMP, "X509: serialNumber %lu", cert->serial_number);
+
+ /* signature AlgorithmIdentifier */
+ if (x509_parse_algorithm_identifier(pos, end - pos, &cert->signature,
+ &pos))
+ return -1;
+
+ /* issuer Name */
+ if (x509_parse_name(pos, end - pos, &cert->issuer, &pos))
+ return -1;
+ x509_name_string(&cert->issuer, sbuf, sizeof(sbuf));
+ wpa_printf(MSG_MSGDUMP, "X509: issuer %s", sbuf);
+
+ /* validity Validity */
+ if (x509_parse_validity(pos, end - pos, cert, &pos))
+ return -1;
+
+ /* subject Name */
+ if (x509_parse_name(pos, end - pos, &cert->subject, &pos))
+ return -1;
+ x509_name_string(&cert->subject, sbuf, sizeof(sbuf));
+ wpa_printf(MSG_MSGDUMP, "X509: subject %s", sbuf);
+
+ /* subjectPublicKeyInfo SubjectPublicKeyInfo */
+ if (x509_parse_public_key(pos, end - pos, cert, &pos))
+ return -1;
+
+ if (pos == end)
+ return 0;
+
+ if (cert->version == X509_CERT_V1)
+ return 0;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+ wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
+ " tag to parse optional tbsCertificate "
+ "field(s); parsed class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+
+ if (hdr.tag == 1) {
+ /* issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL */
+ wpa_printf(MSG_DEBUG, "X509: issuerUniqueID");
+ /* TODO: parse UniqueIdentifier ::= BIT STRING */
+
+ if (hdr.payload + hdr.length == end)
+ return 0;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+ wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
+ " tag to parse optional tbsCertificate "
+ "field(s); parsed class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ }
+
+ if (hdr.tag == 2) {
+ /* subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL */
+ wpa_printf(MSG_DEBUG, "X509: subjectUniqueID");
+ /* TODO: parse UniqueIdentifier ::= BIT STRING */
+
+ if (hdr.payload + hdr.length == end)
+ return 0;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC) {
+ wpa_printf(MSG_DEBUG, "X509: Expected Context-Specific"
+ " tag to parse optional tbsCertificate "
+ "field(s); parsed class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ return -1;
+ }
+ }
+
+ if (hdr.tag != 3) {
+ wpa_printf(MSG_DEBUG, "X509: Ignored unexpected "
+ "Context-Specific tag %d in optional "
+ "tbsCertificate fields", hdr.tag);
+ return 0;
+ }
+
+ /* extensions [3] EXPLICIT Extensions OPTIONAL */
+
+ if (cert->version != X509_CERT_V3) {
+ wpa_printf(MSG_DEBUG, "X509: X.509%d certificate and "
+ "Extensions data which are only allowed for "
+ "version 3", cert->version + 1);
+ return -1;
+ }
+
+ if (x509_parse_extensions(cert, hdr.payload, hdr.length) < 0)
+ return -1;
+
+ pos = hdr.payload + hdr.length;
+ if (pos < end) {
+ wpa_hexdump(MSG_DEBUG,
+ "X509: Ignored extra tbsCertificate data",
+ pos, end - pos);
+ }
+
+ return 0;
+}
+
+
+static int x509_rsadsi_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 4 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 2 /* member-body */ &&
+ oid->oid[2] == 840 /* us */ &&
+ oid->oid[3] == 113549 /* rsadsi */;
+}
+
+
+static int x509_pkcs_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 5 &&
+ x509_rsadsi_oid(oid) &&
+ oid->oid[4] == 1 /* pkcs */;
+}
+
+
+static int x509_digest_oid(struct asn1_oid *oid)
+{
+ return oid->len >= 5 &&
+ x509_rsadsi_oid(oid) &&
+ oid->oid[4] == 2 /* digestAlgorithm */;
+}
+
+
+static int x509_sha1_oid(struct asn1_oid *oid)
+{
+ return oid->len == 6 &&
+ oid->oid[0] == 1 /* iso */ &&
+ oid->oid[1] == 3 /* identified-organization */ &&
+ oid->oid[2] == 14 /* oiw */ &&
+ oid->oid[3] == 3 /* secsig */ &&
+ oid->oid[4] == 2 /* algorithms */ &&
+ oid->oid[5] == 26 /* id-sha1 */;
+}
+
+
+/**
+ * x509_certificate_parse - Parse a X.509 certificate in DER format
+ * @buf: Pointer to the X.509 certificate in DER format
+ * @len: Buffer length
+ * Returns: Pointer to the parsed certificate or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned certificate by calling
+ * x509_certificate_free().
+ */
+struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len)
+{
+ struct asn1_hdr hdr;
+ const u8 *pos, *end, *hash_start;
+ struct x509_certificate *cert;
+
+ cert = os_zalloc(sizeof(*cert) + len);
+ if (cert == NULL)
+ return NULL;
+ os_memcpy(cert + 1, buf, len);
+ cert->cert_start = (u8 *) (cert + 1);
+ cert->cert_len = len;
+
+ pos = buf;
+ end = buf + len;
+
+ /* RFC 3280 - X.509 v3 certificate / ASN.1 DER */
+
+ /* Certificate ::= SEQUENCE */
+ if (asn1_get_next(pos, len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Certificate did not start with "
+ "a valid SEQUENCE - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ x509_certificate_free(cert);
+ return NULL;
+ }
+ pos = hdr.payload;
+
+ if (pos + hdr.length > end) {
+ x509_certificate_free(cert);
+ return NULL;
+ }
+
+ if (pos + hdr.length < end) {
+ wpa_hexdump(MSG_MSGDUMP, "X509: Ignoring extra data after DER "
+ "encoded certificate",
+ pos + hdr.length, end - pos + hdr.length);
+ end = pos + hdr.length;
+ }
+
+ hash_start = pos;
+ cert->tbs_cert_start = cert->cert_start + (hash_start - buf);
+ if (x509_parse_tbs_certificate(pos, end - pos, cert, &pos)) {
+ x509_certificate_free(cert);
+ return NULL;
+ }
+ cert->tbs_cert_len = pos - hash_start;
+
+ /* signatureAlgorithm AlgorithmIdentifier */
+ if (x509_parse_algorithm_identifier(pos, end - pos,
+ &cert->signature_alg, &pos)) {
+ x509_certificate_free(cert);
+ return NULL;
+ }
+
+ /* signatureValue BIT STRING */
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_BITSTRING) {
+ wpa_printf(MSG_DEBUG, "X509: Expected BITSTRING "
+ "(signatureValue) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ x509_certificate_free(cert);
+ return NULL;
+ }
+ if (hdr.length < 1) {
+ x509_certificate_free(cert);
+ return NULL;
+ }
+ pos = hdr.payload;
+ if (*pos) {
+ wpa_printf(MSG_DEBUG, "X509: BITSTRING - %d unused bits",
+ *pos);
+ /* PKCS #1 v1.5 10.2.1:
+ * It is an error if the length in bits of the signature S is
+ * not a multiple of eight.
+ */
+ x509_certificate_free(cert);
+ return NULL;
+ }
+ os_free(cert->sign_value);
+ cert->sign_value = os_malloc(hdr.length - 1);
+ if (cert->sign_value == NULL) {
+ wpa_printf(MSG_DEBUG, "X509: Failed to allocate memory for "
+ "signatureValue");
+ x509_certificate_free(cert);
+ return NULL;
+ }
+ os_memcpy(cert->sign_value, pos + 1, hdr.length - 1);
+ cert->sign_value_len = hdr.length - 1;
+ wpa_hexdump(MSG_MSGDUMP, "X509: signature",
+ cert->sign_value, cert->sign_value_len);
+
+ return cert;
+}
+
+
+/**
+ * x509_certificate_check_signature - Verify certificate signature
+ * @issuer: Issuer certificate
+ * @cert: Certificate to be verified
+ * Returns: 0 if cert has a valid signature that was signed by the issuer,
+ * -1 if not
+ */
+int x509_certificate_check_signature(struct x509_certificate *issuer,
+ struct x509_certificate *cert)
+{
+ struct crypto_public_key *pk;
+ u8 *data;
+ const u8 *pos, *end, *next, *da_end;
+ size_t data_len;
+ struct asn1_hdr hdr;
+ struct asn1_oid oid;
+ u8 hash[20];
+ size_t hash_len;
+
+ if (!x509_pkcs_oid(&cert->signature.oid) ||
+ cert->signature.oid.len != 7 ||
+ cert->signature.oid.oid[5] != 1 /* pkcs-1 */) {
+ wpa_printf(MSG_DEBUG, "X509: Unrecognized signature "
+ "algorithm");
+ return -1;
+ }
+
+ pk = crypto_public_key_import(issuer->public_key,
+ issuer->public_key_len);
+ if (pk == NULL)
+ return -1;
+
+ data_len = cert->sign_value_len;
+ data = os_malloc(data_len);
+ if (data == NULL) {
+ crypto_public_key_free(pk);
+ return -1;
+ }
+
+ if (crypto_public_key_decrypt_pkcs1(pk, cert->sign_value,
+ cert->sign_value_len, data,
+ &data_len) < 0) {
+ wpa_printf(MSG_DEBUG, "X509: Failed to decrypt signature");
+ crypto_public_key_free(pk);
+ os_free(data);
+ return -1;
+ }
+ crypto_public_key_free(pk);
+
+ wpa_hexdump(MSG_MSGDUMP, "X509: Signature data D", data, data_len);
+
+ /*
+ * PKCS #1 v1.5, 10.1.2:
+ *
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * digest Digest
+ * }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ *
+ */
+ if (asn1_get_next(data, data_len, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+ "(DigestInfo) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ os_free(data);
+ return -1;
+ }
+
+ pos = hdr.payload;
+ end = pos + hdr.length;
+
+ /*
+ * X.509:
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ */
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_SEQUENCE) {
+ wpa_printf(MSG_DEBUG, "X509: Expected SEQUENCE "
+ "(AlgorithmIdentifier) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ os_free(data);
+ return -1;
+ }
+ da_end = hdr.payload + hdr.length;
+
+ if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) {
+ wpa_printf(MSG_DEBUG, "X509: Failed to parse digestAlgorithm");
+ os_free(data);
+ return -1;
+ }
+
+ if (x509_sha1_oid(&oid)) {
+ if (cert->signature.oid.oid[6] !=
+ 5 /* sha-1WithRSAEncryption */) {
+ wpa_printf(MSG_DEBUG, "X509: digestAlgorithm SHA1 "
+ "does not match with certificate "
+ "signatureAlgorithm (%lu)",
+ cert->signature.oid.oid[6]);
+ os_free(data);
+ return -1;
+ }
+ goto skip_digest_oid;
+ }
+
+ if (!x509_digest_oid(&oid)) {
+ wpa_printf(MSG_DEBUG, "X509: Unrecognized digestAlgorithm");
+ os_free(data);
+ return -1;
+ }
+ switch (oid.oid[5]) {
+ case 5: /* md5 */
+ if (cert->signature.oid.oid[6] != 4 /* md5WithRSAEncryption */)
+ {
+ wpa_printf(MSG_DEBUG, "X509: digestAlgorithm MD5 does "
+ "not match with certificate "
+ "signatureAlgorithm (%lu)",
+ cert->signature.oid.oid[6]);
+ os_free(data);
+ return -1;
+ }
+ break;
+ case 2: /* md2 */
+ case 4: /* md4 */
+ default:
+ wpa_printf(MSG_DEBUG, "X509: Unsupported digestAlgorithm "
+ "(%lu)", oid.oid[5]);
+ os_free(data);
+ return -1;
+ }
+
+skip_digest_oid:
+ /* Digest ::= OCTET STRING */
+ pos = da_end;
+ end = data + data_len;
+
+ if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+ hdr.class != ASN1_CLASS_UNIVERSAL ||
+ hdr.tag != ASN1_TAG_OCTETSTRING) {
+ wpa_printf(MSG_DEBUG, "X509: Expected OCTETSTRING "
+ "(Digest) - found class %d tag 0x%x",
+ hdr.class, hdr.tag);
+ os_free(data);
+ return -1;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "X509: Decrypted Digest",
+ hdr.payload, hdr.length);
+
+ switch (cert->signature.oid.oid[6]) {
+ case 4: /* md5WithRSAEncryption */
+ md5_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
+ hash);
+ hash_len = 16;
+ wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (MD5)",
+ hash, hash_len);
+ break;
+ case 5: /* sha-1WithRSAEncryption */
+ sha1_vector(1, &cert->tbs_cert_start, &cert->tbs_cert_len,
+ hash);
+ hash_len = 20;
+ wpa_hexdump(MSG_MSGDUMP, "X509: Certificate hash (SHA1)",
+ hash, hash_len);
+ break;
+ case 2: /* md2WithRSAEncryption */
+ case 11: /* sha256WithRSAEncryption */
+ case 12: /* sha384WithRSAEncryption */
+ case 13: /* sha512WithRSAEncryption */
+ default:
+ wpa_printf(MSG_INFO, "X509: Unsupported certificate signature "
+ "algorithm (%lu)", cert->signature.oid.oid[6]);
+ os_free(data);
+ return -1;
+ }
+
+ if (hdr.length != hash_len ||
+ os_memcmp(hdr.payload, hash, hdr.length) != 0) {
+ wpa_printf(MSG_INFO, "X509: Certificate Digest does not match "
+ "with calculated tbsCertificate hash");
+ os_free(data);
+ return -1;
+ }
+
+ os_free(data);
+
+ wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with "
+ "calculated tbsCertificate hash");
+
+ return 0;
+}
+
+
+static int x509_valid_issuer(const struct x509_certificate *cert)
+{
+ if ((cert->extensions_present & X509_EXT_BASIC_CONSTRAINTS) &&
+ !cert->ca) {
+ wpa_printf(MSG_DEBUG, "X509: Non-CA certificate used as an "
+ "issuer");
+ return -1;
+ }
+
+ if ((cert->extensions_present & X509_EXT_KEY_USAGE) &&
+ !(cert->key_usage & X509_KEY_USAGE_KEY_CERT_SIGN)) {
+ wpa_printf(MSG_DEBUG, "X509: Issuer certificate did not have "
+ "keyCertSign bit in Key Usage");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * x509_certificate_chain_validate - Validate X.509 certificate chain
+ * @trusted: List of trusted certificates
+ * @chain: Certificate chain to be validated (first chain must be issued by
+ * signed by the second certificate in the chain and so on)
+ * @reason: Buffer for returning failure reason (X509_VALIDATE_*)
+ * Returns: 0 if chain is valid, -1 if not
+ */
+int x509_certificate_chain_validate(struct x509_certificate *trusted,
+ struct x509_certificate *chain,
+ int *reason)
+{
+ int idx, chain_trusted = 0;
+ struct x509_certificate *cert, *trust;
+ char buf[128];
+ struct os_time now;
+
+ *reason = X509_VALIDATE_OK;
+
+ wpa_printf(MSG_DEBUG, "X509: Validate certificate chain");
+ os_get_time(&now);
+
+ for (cert = chain, idx = 0; cert; cert = cert->next, idx++) {
+ x509_name_string(&cert->subject, buf, sizeof(buf));
+ wpa_printf(MSG_DEBUG, "X509: %d: %s", idx, buf);
+
+ if (chain_trusted)
+ continue;
+
+ if (now.sec < cert->not_before || now.sec > cert->not_after) {
+ wpa_printf(MSG_INFO, "X509: Certificate not valid "
+ "(now=%lu not_before=%lu not_after=%lu)",
+ now.sec, cert->not_before, cert->not_after);
+ *reason = X509_VALIDATE_CERTIFICATE_EXPIRED;
+ return -1;
+ }
+
+ if (cert->next) {
+ if (x509_name_compare(&cert->issuer,
+ &cert->next->subject) != 0) {
+ wpa_printf(MSG_DEBUG, "X509: Certificate "
+ "chain issuer name mismatch");
+ *reason = X509_VALIDATE_CERTIFICATE_UNKNOWN;
+ return -1;
+ }
+
+ if (x509_valid_issuer(cert->next) < 0) {
+ *reason = X509_VALIDATE_BAD_CERTIFICATE;
+ return -1;
+ }
+
+ /* TODO: validate pathLenConstraint */
+
+ if (x509_certificate_check_signature(cert->next, cert)
+ < 0) {
+ wpa_printf(MSG_DEBUG, "X509: Invalid "
+ "certificate signature within "
+ "chain");
+ *reason = X509_VALIDATE_BAD_CERTIFICATE;
+ return -1;
+ }
+ }
+
+ for (trust = trusted; trust; trust = trust->next) {
+ if (x509_name_compare(&cert->issuer, &trust->subject)
+ == 0)
+ break;
+ }
+
+ if (trust) {
+ wpa_printf(MSG_DEBUG, "X509: Found issuer from the "
+ "list of trusted certificates");
+ if (x509_valid_issuer(trust) < 0) {
+ *reason = X509_VALIDATE_BAD_CERTIFICATE;
+ return -1;
+ }
+
+ if (x509_certificate_check_signature(trust, cert) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "X509: Invalid "
+ "certificate signature");
+ *reason = X509_VALIDATE_BAD_CERTIFICATE;
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "X509: Trusted certificate "
+ "found to complete the chain");
+ chain_trusted = 1;
+ }
+ }
+
+ if (!chain_trusted) {
+ wpa_printf(MSG_DEBUG, "X509: Did not find any of the issuers "
+ "from the list of trusted certificates");
+ if (trusted) {
+ *reason = X509_VALIDATE_UNKNOWN_CA;
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "X509: Certificate chain validation "
+ "disabled - ignore unknown CA issue");
+ }
+
+ wpa_printf(MSG_DEBUG, "X509: Certificate chain valid");
+
+ return 0;
+}
+
+
+/**
+ * x509_certificate_get_subject - Get a certificate based on Subject name
+ * @chain: Certificate chain to search through
+ * @name: Subject name to search for
+ * Returns: Pointer to the certificate with the given Subject name or
+ * %NULL on failure
+ */
+struct x509_certificate *
+x509_certificate_get_subject(struct x509_certificate *chain,
+ struct x509_name *name)
+{
+ struct x509_certificate *cert;
+
+ for (cert = chain; cert; cert = cert->next) {
+ if (x509_name_compare(&cert->subject, name) == 0)
+ return cert;
+ }
+ return NULL;
+}
+
+
+/**
+ * x509_certificate_self_signed - Is the certificate self-signed?
+ * @cert: Certificate
+ * Returns: 1 if certificate is self-signed, 0 if not
+ */
+int x509_certificate_self_signed(struct x509_certificate *cert)
+{
+ return x509_name_compare(&cert->issuer, &cert->subject) == 0;
+}
+
+#endif /* CONFIG_INTERNAL_X509 */
diff --git a/contrib/wpa_supplicant/x509v3.h b/contrib/wpa_supplicant/x509v3.h
new file mode 100644
index 000000000000..a52bcf886453
--- /dev/null
+++ b/contrib/wpa_supplicant/x509v3.h
@@ -0,0 +1,154 @@
+/*
+ * X.509v3 certificate parsing and processing
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef X509V3_H
+#define X509V3_H
+
+#include "asn1.h"
+
+struct x509_algorithm_identifier {
+ struct asn1_oid oid;
+};
+
+struct x509_name {
+ char *cn; /* commonName */
+ char *c; /* countryName */
+ char *l; /* localityName */
+ char *st; /* stateOrProvinceName */
+ char *o; /* organizationName */
+ char *ou; /* organizationalUnitName */
+ char *email; /* emailAddress */
+};
+
+struct x509_certificate {
+ struct x509_certificate *next;
+ enum { X509_CERT_V1 = 0, X509_CERT_V2 = 1, X509_CERT_V3 = 2 } version;
+ unsigned long serial_number;
+ struct x509_algorithm_identifier signature;
+ struct x509_name issuer;
+ struct x509_name subject;
+ os_time_t not_before;
+ os_time_t not_after;
+ struct x509_algorithm_identifier public_key_alg;
+ u8 *public_key;
+ size_t public_key_len;
+ struct x509_algorithm_identifier signature_alg;
+ u8 *sign_value;
+ size_t sign_value_len;
+
+ /* Extensions */
+ unsigned int extensions_present;
+#define X509_EXT_BASIC_CONSTRAINTS (1 << 0)
+#define X509_EXT_PATH_LEN_CONSTRAINT (1 << 1)
+#define X509_EXT_KEY_USAGE (1 << 2)
+
+ /* BasicConstraints */
+ int ca; /* cA */
+ unsigned long path_len_constraint; /* pathLenConstraint */
+
+ /* KeyUsage */
+ unsigned long key_usage;
+#define X509_KEY_USAGE_DIGITAL_SIGNATURE (1 << 0)
+#define X509_KEY_USAGE_NON_REPUDIATION (1 << 1)
+#define X509_KEY_USAGE_KEY_ENCIPHERMENT (1 << 2)
+#define X509_KEY_USAGE_DATA_ENCIPHERMENT (1 << 3)
+#define X509_KEY_USAGE_KEY_AGREEMENT (1 << 4)
+#define X509_KEY_USAGE_KEY_CERT_SIGN (1 << 5)
+#define X509_KEY_USAGE_CRL_SIGN (1 << 6)
+#define X509_KEY_USAGE_ENCIPHER_ONLY (1 << 7)
+#define X509_KEY_USAGE_DECIPHER_ONLY (1 << 8)
+
+ /*
+ * The DER format certificate follows struct x509_certificate. These
+ * pointers point to that buffer.
+ */
+ const u8 *cert_start;
+ size_t cert_len;
+ const u8 *tbs_cert_start;
+ size_t tbs_cert_len;
+};
+
+enum {
+ X509_VALIDATE_OK,
+ X509_VALIDATE_BAD_CERTIFICATE,
+ X509_VALIDATE_UNSUPPORTED_CERTIFICATE,
+ X509_VALIDATE_CERTIFICATE_REVOKED,
+ X509_VALIDATE_CERTIFICATE_EXPIRED,
+ X509_VALIDATE_CERTIFICATE_UNKNOWN,
+ X509_VALIDATE_UNKNOWN_CA
+};
+
+#ifdef CONFIG_INTERNAL_X509
+
+void x509_certificate_free(struct x509_certificate *cert);
+struct x509_certificate * x509_certificate_parse(const u8 *buf, size_t len);
+void x509_name_string(struct x509_name *name, char *buf, size_t len);
+int x509_name_compare(struct x509_name *a, struct x509_name *b);
+void x509_certificate_chain_free(struct x509_certificate *cert);
+int x509_certificate_check_signature(struct x509_certificate *issuer,
+ struct x509_certificate *cert);
+int x509_certificate_chain_validate(struct x509_certificate *trusted,
+ struct x509_certificate *chain,
+ int *reason);
+struct x509_certificate *
+x509_certificate_get_subject(struct x509_certificate *chain,
+ struct x509_name *name);
+int x509_certificate_self_signed(struct x509_certificate *cert);
+
+#else /* CONFIG_INTERNAL_X509 */
+
+static inline void x509_certificate_free(struct x509_certificate *cert)
+{
+}
+
+static inline struct x509_certificate *
+x509_certificate_parse(const u8 *buf, size_t len)
+{
+ return NULL;
+}
+
+static inline void x509_name_string(struct x509_name *name, char *buf,
+ size_t len)
+{
+ if (len)
+ buf[0] = '\0';
+}
+
+static inline void x509_certificate_chain_free(struct x509_certificate *cert)
+{
+}
+
+static inline int
+x509_certificate_chain_validate(struct x509_certificate *trusted,
+ struct x509_certificate *chain,
+ int *reason)
+{
+ return -1;
+}
+
+static inline struct x509_certificate *
+x509_certificate_get_subject(struct x509_certificate *chain,
+ struct x509_name *name)
+{
+ return NULL;
+}
+
+static inline int x509_certificate_self_signed(struct x509_certificate *cert)
+{
+ return -1;
+}
+
+#endif /* CONFIG_INTERNAL_X509 */
+
+#endif /* X509V3_H */