summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2006-03-07 05:26:33 +0000
committersam <sam@FreeBSD.org>2006-03-07 05:26:33 +0000
commit840099f34d8de1ca769f02fae379c4d8e5d6688a (patch)
tree0c0ff34569d807e7bceb062a6210ce68490a8764 /contrib
parent34dbcde8dfa5b3d152d250b6d69965e001238e49 (diff)
downloadFreeBSD-src-840099f34d8de1ca769f02fae379c4d8e5d6688a.zip
FreeBSD-src-840099f34d8de1ca769f02fae379c4d8e5d6688a.tar.gz
Import of WPA supplicant 0.4.8
Diffstat (limited to 'contrib')
-rw-r--r--contrib/wpa_supplicant/ChangeLog294
-rw-r--r--contrib/wpa_supplicant/Makefile196
-rw-r--r--contrib/wpa_supplicant/README209
-rw-r--r--contrib/wpa_supplicant/aes.c555
-rw-r--r--contrib/wpa_supplicant/aes_wrap.c231
-rw-r--r--contrib/wpa_supplicant/aes_wrap.h41
-rw-r--r--contrib/wpa_supplicant/base64.c198
-rw-r--r--contrib/wpa_supplicant/base64.h23
-rw-r--r--contrib/wpa_supplicant/common.c73
-rw-r--r--contrib/wpa_supplicant/common.h88
-rw-r--r--contrib/wpa_supplicant/config.c1272
-rw-r--r--contrib/wpa_supplicant/config.h296
-rw-r--r--contrib/wpa_supplicant/config_file.c695
-rw-r--r--contrib/wpa_supplicant/config_ssid.h703
-rw-r--r--contrib/wpa_supplicant/config_types.h14
-rw-r--r--contrib/wpa_supplicant/crypto.c109
-rw-r--r--contrib/wpa_supplicant/crypto.h117
-rw-r--r--contrib/wpa_supplicant/crypto_gnutls.c163
-rw-r--r--contrib/wpa_supplicant/ctrl_iface.c1105
-rw-r--r--contrib/wpa_supplicant/ctrl_iface.h33
-rw-r--r--contrib/wpa_supplicant/defconfig32
-rw-r--r--contrib/wpa_supplicant/defs.h121
-rw-r--r--contrib/wpa_supplicant/doc/code_structure.doxygen264
-rw-r--r--contrib/wpa_supplicant/doc/ctrl_iface.doxygen409
-rw-r--r--contrib/wpa_supplicant/doc/docbook/Makefile25
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_background.884
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_background.sgml101
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_cli.8202
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml330
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_passphrase.839
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml72
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8544
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5230
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml244
-rw-r--r--contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml761
-rw-r--r--contrib/wpa_supplicant/doc/doxygen.fast243
-rw-r--r--contrib/wpa_supplicant/doc/doxygen.full230
-rw-r--r--contrib/wpa_supplicant/doc/driver_wrapper.doxygen180
-rw-r--r--contrib/wpa_supplicant/doc/eap.doxygen38
-rwxr-xr-xcontrib/wpa_supplicant/doc/kerneldoc2doxygen.pl129
-rw-r--r--contrib/wpa_supplicant/doc/mainpage.doxygen56
-rw-r--r--contrib/wpa_supplicant/doc/porting.doxygen121
-rw-r--r--contrib/wpa_supplicant/doc/testing_tools.doxygen288
-rw-r--r--contrib/wpa_supplicant/doc/wpa_supplicant.fig42
-rw-r--r--contrib/wpa_supplicant/driver.h281
-rw-r--r--contrib/wpa_supplicant/driver_hostap.h153
-rw-r--r--contrib/wpa_supplicant/driver_ndis.c137
-rw-r--r--contrib/wpa_supplicant/driver_ndis.h15
-rw-r--r--contrib/wpa_supplicant/driver_wired.c271
-rw-r--r--contrib/wpa_supplicant/drivers.c8
-rw-r--r--contrib/wpa_supplicant/eap.c705
-rw-r--r--contrib/wpa_supplicant/eap.h222
-rw-r--r--contrib/wpa_supplicant/eap_aka.c93
-rw-r--r--contrib/wpa_supplicant/eap_defs.h31
-rw-r--r--contrib/wpa_supplicant/eap_fast.c343
-rw-r--r--contrib/wpa_supplicant/eap_gtc.c51
-rw-r--r--contrib/wpa_supplicant/eap_i.h182
-rw-r--r--contrib/wpa_supplicant/eap_leap.c82
-rw-r--r--contrib/wpa_supplicant/eap_md5.c45
-rw-r--r--contrib/wpa_supplicant/eap_mschapv2.c251
-rw-r--r--contrib/wpa_supplicant/eap_otp.c28
-rw-r--r--contrib/wpa_supplicant/eap_pax.c510
-rw-r--r--contrib/wpa_supplicant/eap_pax_common.c152
-rw-r--r--contrib/wpa_supplicant/eap_pax_common.h84
-rw-r--r--contrib/wpa_supplicant/eap_peap.c99
-rw-r--r--contrib/wpa_supplicant/eap_psk.c262
-rw-r--r--contrib/wpa_supplicant/eap_psk_common.c57
-rw-r--r--contrib/wpa_supplicant/eap_psk_common.h92
-rw-r--r--contrib/wpa_supplicant/eap_sim.c88
-rw-r--r--contrib/wpa_supplicant/eap_sim_common.c78
-rw-r--r--contrib/wpa_supplicant/eap_sim_common.h35
-rw-r--r--contrib/wpa_supplicant/eap_testing.txt90
-rw-r--r--contrib/wpa_supplicant/eap_tls.c91
-rw-r--r--contrib/wpa_supplicant/eap_tls_common.c315
-rw-r--r--contrib/wpa_supplicant/eap_tls_common.h25
-rw-r--r--contrib/wpa_supplicant/eap_tlv.c28
-rw-r--r--contrib/wpa_supplicant/eap_tlv.h20
-rw-r--r--contrib/wpa_supplicant/eap_ttls.c115
-rw-r--r--contrib/wpa_supplicant/eap_ttls.h14
-rw-r--r--contrib/wpa_supplicant/eapol_sm.c520
-rw-r--r--contrib/wpa_supplicant/eapol_sm.h202
-rw-r--r--contrib/wpa_supplicant/eapol_test.c529
-rw-r--r--contrib/wpa_supplicant/eloop.c21
-rw-r--r--contrib/wpa_supplicant/eloop.h137
-rw-r--r--contrib/wpa_supplicant/events.c759
-rw-r--r--contrib/wpa_supplicant/examples/ieee8021x.conf13
-rw-r--r--contrib/wpa_supplicant/examples/plaintext.conf8
-rw-r--r--contrib/wpa_supplicant/examples/wep.conf11
-rw-r--r--contrib/wpa_supplicant/examples/wpa-psk-tkip.conf12
-rw-r--r--contrib/wpa_supplicant/examples/wpa2-eap-ccmp.conf15
-rw-r--r--contrib/wpa_supplicant/hostapd.h38
-rw-r--r--contrib/wpa_supplicant/l2_packet.h109
-rw-r--r--contrib/wpa_supplicant/main.c250
-rw-r--r--contrib/wpa_supplicant/md5.c146
-rw-r--r--contrib/wpa_supplicant/md5.h46
-rw-r--r--contrib/wpa_supplicant/ms_funcs.c200
-rw-r--r--contrib/wpa_supplicant/ms_funcs.h51
-rw-r--r--contrib/wpa_supplicant/openssl-tls-extensions.patch513
-rw-r--r--contrib/wpa_supplicant/pcsc_funcs.c47
-rw-r--r--contrib/wpa_supplicant/pcsc_funcs.h20
-rw-r--r--contrib/wpa_supplicant/preauth.c934
-rw-r--r--contrib/wpa_supplicant/preauth.h132
-rw-r--r--contrib/wpa_supplicant/preauth_test.c387
-rw-r--r--contrib/wpa_supplicant/radius.c219
-rw-r--r--contrib/wpa_supplicant/radius.h18
-rw-r--r--contrib/wpa_supplicant/radius_client.c845
-rw-r--r--contrib/wpa_supplicant/radius_client.h118
-rw-r--r--contrib/wpa_supplicant/rc4.c32
-rw-r--r--contrib/wpa_supplicant/rc4.h19
-rw-r--r--contrib/wpa_supplicant/sha1.c202
-rw-r--r--contrib/wpa_supplicant/sha1.h45
-rw-r--r--contrib/wpa_supplicant/tls.h317
-rw-r--r--contrib/wpa_supplicant/tls_gnutls.c792
-rw-r--r--contrib/wpa_supplicant/tls_none.c8
-rw-r--r--contrib/wpa_supplicant/tls_openssl.c1614
-rw-r--r--contrib/wpa_supplicant/tls_schannel.c738
-rw-r--r--contrib/wpa_supplicant/todo.txt43
-rw-r--r--contrib/wpa_supplicant/version.h2
-rw-r--r--contrib/wpa_supplicant/wpa.c2721
-rw-r--r--contrib/wpa_supplicant/wpa.h302
-rw-r--r--contrib/wpa_supplicant/wpa_cli.c589
-rw-r--r--contrib/wpa_supplicant/wpa_ctrl.c18
-rw-r--r--contrib/wpa_supplicant/wpa_ctrl.h172
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui125
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui.h41
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/main.cpp30
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui455
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui.h513
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui179
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui.h101
-rwxr-xr-xcontrib/wpa_supplicant/wpa_gui-qt4/setup-mingw-cross-compiling11
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui163
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui.h70
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro41
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui464
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui.h651
-rw-r--r--contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h28
-rw-r--r--contrib/wpa_supplicant/wpa_gui/eventhistory.ui125
-rw-r--r--contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h41
-rw-r--r--contrib/wpa_supplicant/wpa_gui/main.cpp30
-rw-r--r--contrib/wpa_supplicant/wpa_gui/networkconfig.ui455
-rw-r--r--contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h513
-rw-r--r--contrib/wpa_supplicant/wpa_gui/scanresults.ui179
-rw-r--r--contrib/wpa_supplicant/wpa_gui/scanresults.ui.h101
-rw-r--r--contrib/wpa_supplicant/wpa_gui/userdatarequest.ui163
-rw-r--r--contrib/wpa_supplicant/wpa_gui/userdatarequest.ui.h70
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpa_gui.pro31
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpagui.ui464
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpagui.ui.h651
-rw-r--r--contrib/wpa_supplicant/wpa_gui/wpamsg.h27
-rw-r--r--contrib/wpa_supplicant/wpa_i.h197
-rw-r--r--contrib/wpa_supplicant/wpa_passphrase.c31
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.c2009
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.conf199
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant.h235
-rw-r--r--contrib/wpa_supplicant/wpa_supplicant_i.h408
156 files changed, 32479 insertions, 6489 deletions
diff --git a/contrib/wpa_supplicant/ChangeLog b/contrib/wpa_supplicant/ChangeLog
index 09d5b61..4ed9e26 100644
--- a/contrib/wpa_supplicant/ChangeLog
+++ b/contrib/wpa_supplicant/ChangeLog
@@ -1,32 +1,294 @@
ChangeLog for wpa_supplicant
-2005-06-10 - v0.3.9
- * modified the EAP workaround that accepts EAP-Success with incorrect
- Identifier to be even less strict about verification in order to
- interoperate with some authentication servers
- * fixed RSN IE in 4-Way Handshake message 2/4 for the case where
- Authenticator rejects PMKSA caching attempt and the driver is not
- using assoc_info events
- * fixed a possible double free in EAP-TTLS fast-reauthentication when
- identity or password is entered through control interface
- * added -P<pid file> argument for wpa_supplicant to write the current
- process id into a file
- * driver_madwifi: fixed association in plaintext mode
- * driver_madwifi: added preliminary support for compiling against 'BSD'
- branch of madwifi CVS tree
- * added EAP workaround for PEAPv1 session resumption: allow outer,
+2006-02-08 - v0.4.8
+ * 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 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
+ * 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
+
+2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
+ * l2_packet_pcap: fixed wired IEEE 802.1X authentication with libpcap
+ and WinPcap to receive frames sent to PAE group address
+ * disable EAP state machine when IEEE 802.1X authentication is not used
+ in order to get rid of bogus "EAP failed" messages
+ * fixed OpenSSL error reporting to go through all pending errors to
+ avoid confusing reports of old errors being reported at later point
+ during handshake
+ * fixed configuration file updating to not write empty variables
+ (e.g., proto or key_mgmt) that the file parser would not accept
+ * fixed ADD_NETWORK ctrl_iface command to use the same default values
+ for variables as empty network definitions read from config file
+ would get
+ * fixed EAP state machine to not discard EAP-Failure messages in many
+ cases (e.g., during TLS handshake)
+ * fixed a infinite loop in private key reading if the configured file
+ cannot be parsed successfully
+ * driver_madwifi: added support for madwifi-ng
+ * wpa_gui: do not display password/PSK field contents
+ * wpa_gui: added CA certificate configuration
+ * driver_ndis: fixed scan request in ap_scan=2 mode not to change SSID
+ * driver_ndis: include Beacon IEs in AssocInfo in order to notice if
+ the new AP is using different WPA/RSN IE
+ * use longer timeout for IEEE 802.11 association to avoid problems with
+ drivers that may take more than five second to associate
+
+2005-10-27 - v0.4.6
+ * allow fallback to WPA, if mixed WPA+WPA2 networks have mismatch in
+ RSN IE, but WPA IE would match with wpa_supplicant configuration
+ * added support for named configuration blobs in order to avoid having
+ to use file system for external files (e.g., certificates);
+ variables can be set to "blob://<blob name>" instead of file path to
+ use a named blob; supported fields: pac_file, client_cert,
+ private_key
+ * fixed RSN pre-authentication (it was broken in the clean up of WPA
+ state machine interface in v0.4.5)
+ * driver_madwifi: set IEEE80211_KEY_GROUP flag for group keys to make
+ sure the driver configures broadcast decryption correctly
+ * added ca_path (and ca_path2) configuration variables that can be used
+ to configure OpenSSL CA path, e.g., /etc/ssl/certs, for using the
+ system-wide trusted CA list
+ * added support for starting wpa_supplicant without a configuration
+ file (-C argument must be used to set ctrl_interface parameter for
+ this case; in addition, -p argument can be used to provide
+ driver_param; these new arguments can also be used with a
+ configuration to override the values from the configuration)
+ * added global control interface that can be optionally used for adding
+ and removing network interfaces dynamically (-g command line argument
+ for both wpa_supplicant and wpa_cli) without having to restart
+ wpa_supplicant process
+ * wpa_gui:
+ - try to save configuration whenever something is modified
+ - added WEP key configuration
+ - added possibility to edit the current network configuration
+ * driver_ndis: fixed driver polling not to increase frequency on each
+ received EAPOL frame due to incorrectly cancelled timeout
+ * added simple configuration file examples (in examples subdirectory)
+ * fixed driver_wext.c to filter wireless events based on ifindex to
+ avoid interfaces receiving events from other interfaces
+ * delay sending initial EAPOL-Start couple of seconds to speed up
+ authentication for the most common case of Authenticator starting
+ EAP authentication immediately after association
+
+2005-09-25 - v0.4.5
+ * added a workaround for clearing keys with ndiswrapper to allow
+ roaming from WPA enabled AP to plaintext one
+ * added docbook documentation (doc/docbook) that can be used to
+ generate, e.g., man pages
+ * l2_packet_linux: use socket type SOCK_DGRAM instead of SOCK_RAW for
+ PF_PACKET in order to prepare for network devices that do not use
+ Ethernet headers (e.g., network stack with native IEEE 802.11 frames)
+ * use receipt of EAPOL-Key frame as a lower layer success indication
+ for EAP state machine to allow recovery from dropped EAP-Success
+ frame
+ * cleaned up internal EAPOL frame processing by not including link
+ layer (Ethernet) header during WPA and EAPOL/EAP processing; this
+ header is added only when transmitted the frame; this makes it easier
+ to use wpa_supplicant on link layers that use different header than
+ Ethernet
+ * updated EAP-PSK to use draft 9 by default since this can now be
+ tested with hostapd; removed support for draft 3, including
+ server_nai configuration option from network blocks
+ * driver_wired: add PAE address to the multicast address list in order
+ to be able to receive EAPOL frames with drivers that do not include
+ these multicast addresses by default
+ * driver_wext: add support for WE-19
+ * added support for multiple configuration backends (CONFIG_BACKEND
+ option); currently, only 'file' is supported (i.e., the format used
+ in wpa_supplicant.conf)
+ * added support for updating configuration ('wpa_cli save_config');
+ this is disabled by default and can be enabled with global
+ update_config=1 variable in wpa_supplicant.conf; this allows wpa_cli
+ and wpa_gui to store the configuration changes in a permanent store
+ * added GET_NETWORK ctrl_iface command
+ (e.g., 'wpa_cli get_network 0 ssid')
+
+2005-08-21 - v0.4.4
+ * replaced OpenSSL patch for EAP-FAST support
+ (openssl-tls-extensions.patch) with a more generic and correct
+ patch (the new patch is not compatible with the previous one, so the
+ OpenSSL library will need to be patched with the new patch in order
+ to be able to build wpa_supplicant with EAP-FAST support)
+ * added support for using Windows certificate store (through CryptoAPI)
+ for client certificate and private key operations (EAP-TLS)
+ (see wpa_supplicant.conf for more information on how to configure
+ this with private_key)
+ * ported wpa_gui to Windows
+ * added Qt4 version of wpa_gui (wpa_gui-qt4 directory); this can be
+ built with the open source version of the Qt4 for Windows
+ * allow non-WPA modes (e.g., IEEE 802.1X with dynamic WEP) to be used
+ with drivers that do not support WPA
+ * ndis_events: fixed Windows 2000 support
+ * added support for enabling/disabling networks from the list of all
+ configured networks ('wpa_cli enable_network <network id>' and
+ 'wpa_cli disable_network <network id>')
+ * added support for adding and removing network from the current
+ configuration ('wpa_cli add_network' and 'wpa_cli remove_network
+ <network id>'); added networks are disabled by default and they can
+ be enabled with enable_network command once the configuration is done
+ for the new network; note: configuration file is not yet updated, so
+ these new networks are lost when wpa_supplicant is restarted
+ * added support for setting network configuration parameters through
+ the control interface, for example:
+ wpa_cli set_network 0 ssid "\"my network\""
+ * fixed parsing of strings that include both " and # within double
+ quoted area (e.g., "start"#end")
+ * added EAP workaround for PEAP session resumption: allow outer,
i.e., not tunneled, EAP-Success to terminate session since; this can
be disabled with eap_workaround=0
+ (this was allowed for PEAPv1 before, but now it is also allowed for
+ PEAPv0 since at least one RADIUS authentication server seems to be
+ doing this for PEAPv0, too)
+ * wpa_gui: added preliminary support for adding new networks to the
+ wpa_supplicant configuration (double click on the scan results to
+ open network configuration)
+
+2005-06-26 - v0.4.3
+ * removed interface for external EAPOL/EAP supplicant (e.g.,
+ Xsupplicant), (CONFIG_XSUPPLICANT_IFACE) since it is not required
+ anymore and is unlikely to be used by anyone
+ * driver_ndis: fixed WinPcap 3.0 support
+ * fixed build with CONFIG_DNET_PCAP=y on Linux
+ * l2_packet: moved different implementations into separate files
+ (l2_packet_*.c)
+
+2005-06-12 - v0.4.2
* driver_ipw: updated driver structures to match with ipw2200-1.0.4
(note: ipw2100-1.1.0 is likely to require an update to work with
this)
+ * added support for using ap_scan=2 mode with multiple network blocks;
+ wpa_supplicant will go through the networks one by one until the
+ driver reports a successful association; this uses the same order for
+ networks as scan_ssid=1 scans, i.e., the priority field is ignored
+ and the network block order in the file is used instead
+ * fixed a potential issue in RSN pre-authentication ending up using
+ freed memory if pre-authentication times out
+ * added support for matching alternative subject name extensions of the
+ authentication server certificate; new configuration variables
+ altsubject_match and altsubject_match2
+ * driver_ndis: added support for IEEE 802.1X authentication with wired
+ NDIS drivers
+ * added support for querying private key password (EAP-TLS) through the
+ control interface (wpa_cli/wpa_gui) if one is not included in the
+ configuration file
* driver_broadcom: fixed couple of memory leaks in scan result
processing
+ * EAP-PAX is now registered as EAP type 46
+ * fixed EAP-PAX MAC calculation
+ * fixed EAP-PAX CK and ICK key derivation
+ * added support for using password with EAP-PAX (as an alternative to
+ entering key with eappsk); SHA-1 hash of the password will be used as
+ the key in this case
+ * added support for arbitrary driver interface parameters through the
+ configuration file with a new driver_param field; this adds a new
+ driver_ops function set_param()
+ * added possibility to override l2_packet module with driver interface
+ API (new send_eapol handler); this can be used to implement driver
+ specific TX/RX functions for EAPOL frames
+ * fixed ctrl_interface_group processing for the case where gid is
+ entered as a number, not group name
+ * driver_test: added support for testing hostapd with wpa_supplicant
+ by using test driver interface without any kernel drivers or network
+ cards
+
+2005-05-22 - v0.4.1
+ * driver_madwifi: fixed WPA/WPA2 mode configuration to allow EAPOL
+ packets to be encrypted; this was apparently broken by the changed
+ ioctl order in v0.4.0
+ * driver_madwifi: added preliminary support for compiling against 'BSD'
+ branch of madwifi CVS tree
+ * added support for EAP-MSCHAPv2 password retries within the same EAP
+ authentication session
+ * added support for password changes with EAP-MSCHAPv2 (used when the
+ password has expired)
+ * added support for reading additional certificates from PKCS#12 files
+ and adding them to the certificate chain
+ * fixed association with IEEE 802.1X (no WPA) when dynamic WEP keys
+ were used
+ * fixed a possible double free in EAP-TTLS fast-reauthentication when
+ identity or password is entered through control interface
+ * display EAP Notification messages to user through control interface
+ with "CTRL-EVENT-EAP-NOTIFICATION" prefix
+ * added GUI version of wpa_cli, wpa_gui; this is not build
+ automatically with 'make'; use 'make wpa_gui' to build (this requires
+ Qt development tools)
+ * added 'disconnect' command to control interface for setting
+ wpa_supplicant in state where it will not associate before
+ 'reassociate' command has been used
+ * added support for selecting a network from the list of all configured
+ networks ('wpa_cli select_network <network id>'; this disabled all
+ other networks; to re-enable, 'wpa_cli select_network any')
+ * added support for getting scan results through control interface
+ * added EAP workaround for PEAPv1 session resumption: allow outer,
+ i.e., not tunneled, EAP-Success to terminate session since; this can
+ be disabled with eap_workaround=0
-2005-02-13 - v0.3.8
+2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
+ * added a new build time option, CONFIG_NO_STDOUT_DEBUG, that can be
+ used to reduce the size of the wpa_supplicant considerably if
+ debugging code is not needed
* fixed EAPOL-Key validation to drop packets with invalid Key Data
Length; such frames could have crashed wpa_supplicant due to buffer
overflow
+ * added support for wired authentication (IEEE 802.1X on wired
+ Ethernet); driver interface 'wired'
+ * obsoleted set_wpa() handler in the driver interface API (it can be
+ replaced by moving enable/disable functionality into init()/deinit())
+ (calls to set_wpa() are still present for backwards compatibility,
+ but they may be removed in the future)
+ * driver_madwifi: fixed association in plaintext mode
+ * modified the EAP workaround that accepts EAP-Success with incorrect
+ Identifier to be even less strict about verification in order to
+ interoperate with some authentication servers
+ * added support for sending TLS alerts
+ * added support for 'any' SSID wildcard; if ssid is not configured or
+ is set to an empty string, any SSID will be accepted for non-WPA AP
+ * added support for asking PIN (for SIM) from frontends (e.g.,
+ wpa_cli); if a PIN is needed, but not included in the configuration
+ file, a control interface request is sent and EAP processing is
+ delayed until the PIN is available
+ * added support for using external devices (e.g., a smartcard) for
+ private key operations in EAP-TLS (CONFIG_SMARTCARD=y in .config);
+ new wpa_supplicant.conf variables:
+ - global: opensc_engine_path, pkcs11_engine_path, pkcs11_module_path
+ - network: engine, engine_id, key_id
+ * added experimental support for EAP-PAX
+ * added monitor mode for wpa_cli (-a<path to a program to run>) that
+ allows external commands (e.g., shell scripts) to be run based on
+ wpa_supplicant events, e.g., when authentication has been completed
+ and data connection is ready; other related wpa_cli arguments:
+ -B (run in background), -P (write PID file); wpa_supplicant has a new
+ command line argument (-W) that can be used to make it wait until a
+ control interface command is received in order to avoid missing
+ events
+ * added support for opportunistic WPA2 PMKSA key caching (disabled by
+ default, can be enabled with proactive_key_caching=1)
+ * fixed RSN IE in 4-Way Handshake message 2/4 for the case where
+ Authenticator rejects PMKSA caching attempt and the driver is not
+ using assoc_info events
+ * added -P<pid file> argument for wpa_supplicant to write the current
+ process id into a file
2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
* added new phase1 option parameter, include_tls_length=1, to force
diff --git a/contrib/wpa_supplicant/Makefile b/contrib/wpa_supplicant/Makefile
index fa91243..d8fd3ed 100644
--- a/contrib/wpa_supplicant/Makefile
+++ b/contrib/wpa_supplicant/Makefile
@@ -7,7 +7,7 @@ CFLAGS = -MMD -O2 -Wall -g
endif
# Include directories for CVS version
-CFLAGS += -I../driver/modules -I../utils -I../hostapd
+CFLAGS += -I. -I../utils -I../hostapd
ALL=wpa_supplicant wpa_passphrase wpa_cli
@@ -37,7 +37,7 @@ install: all
OBJS = config.o \
eloop.o common.o md5.o \
- rc4.o sha1.o aes_wrap.o
+ rc4.o sha1.o
OBJS_p = wpa_passphrase.o sha1.o md5.o
OBJS_c = wpa_cli.o wpa_ctrl.o
@@ -47,9 +47,18 @@ ifdef CONFIG_EAPOL_TEST
CFLAGS += -Werror -DEAPOL_TEST
endif
+ifndef CONFIG_BACKEND
+CONFIG_BACKEND=file
+endif
+
+ifeq ($(CONFIG_BACKEND), file)
+OBJS += config_file.o base64.o
+CFLAGS += -DCONFIG_BACKEND_FILE
+endif
+
ifdef CONFIG_DRIVER_HOSTAP
CFLAGS += -DCONFIG_DRIVER_HOSTAP
-OBJS += driver_hostap.o
+OBJS_d += driver_hostap.o
CONFIG_WIRELESS_EXTENSION=y
endif
@@ -60,73 +69,88 @@ endif
ifdef CONFIG_DRIVER_PRISM54
CFLAGS += -DCONFIG_DRIVER_PRISM54
-OBJS += driver_prism54.o
+OBJS_d += driver_prism54.o
CONFIG_WIRELESS_EXTENSION=y
endif
ifdef CONFIG_DRIVER_HERMES
CFLAGS += -DCONFIG_DRIVER_HERMES
-OBJS += driver_hermes.o
+OBJS_d += driver_hermes.o
CONFIG_WIRELESS_EXTENSION=y
endif
ifdef CONFIG_DRIVER_MADWIFI
CFLAGS += -DCONFIG_DRIVER_MADWIFI
-OBJS += driver_madwifi.o
+OBJS_d += driver_madwifi.o
CONFIG_WIRELESS_EXTENSION=y
endif
ifdef CONFIG_DRIVER_ATMEL
CFLAGS += -DCONFIG_DRIVER_ATMEL
-OBJS += driver_atmel.o
+OBJS_d += driver_atmel.o
CONFIG_WIRELESS_EXTENSION=y
endif
ifdef CONFIG_DRIVER_NDISWRAPPER
CFLAGS += -DCONFIG_DRIVER_NDISWRAPPER
-OBJS += driver_ndiswrapper.o
+OBJS_d += driver_ndiswrapper.o
CONFIG_WIRELESS_EXTENSION=y
endif
ifdef CONFIG_DRIVER_BROADCOM
CFLAGS += -DCONFIG_DRIVER_BROADCOM
-OBJS += driver_broadcom.o
+OBJS_d += driver_broadcom.o
endif
ifdef CONFIG_DRIVER_IPW
CFLAGS += -DCONFIG_DRIVER_IPW
-OBJS += driver_ipw.o
+OBJS_d += driver_ipw.o
CONFIG_WIRELESS_EXTENSION=y
endif
ifdef CONFIG_DRIVER_BSD
CFLAGS += -DCONFIG_DRIVER_BSD
-OBJS += driver_bsd.o
+OBJS_d += driver_bsd.o
CONFIG_DNET_PCAP=y
+CONFIG_L2_FREEBSD=y
endif
ifdef CONFIG_DRIVER_NDIS
CFLAGS += -DCONFIG_DRIVER_NDIS
-OBJS += driver_ndis.o driver_ndis_.o
+OBJS_d += driver_ndis.o driver_ndis_.o
CONFIG_DNET_PCAP=y
CONFIG_WINPCAP=y
endif
+ifdef CONFIG_DRIVER_WIRED
+CFLAGS += -DCONFIG_DRIVER_WIRED
+OBJS_d += driver_wired.o
+endif
+
ifdef CONFIG_DRIVER_TEST
CFLAGS += -DCONFIG_DRIVER_TEST
-OBJS += driver_test.o
+OBJS_d += driver_test.o
endif
ifdef CONFIG_DNET_PCAP
CFLAGS += -DUSE_DNET_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
+endif
ifdef CONFIG_EAP_TLS
# EAP-TLS
@@ -209,8 +233,9 @@ endif
ifdef CONFIG_EAP_PSK
# EAP-PSK
CFLAGS += -DEAP_PSK
-OBJS += eap_psk.o
+OBJS += eap_psk.o eap_psk_common.o
CONFIG_IEEE8021X_EAPOL=y
+NEED_AES=y
endif
ifdef CONFIG_EAP_AKA
@@ -223,6 +248,7 @@ endif
ifdef CONFIG_EAP_SIM_COMMON
OBJS += eap_sim_common.o
+NEED_AES=y
endif
ifdef CONFIG_EAP_TLV
@@ -238,6 +264,13 @@ OBJS += eap_fast.o
TLS_FUNCS=y
endif
+ifdef CONFIG_EAP_PAX
+# EAP-PAX
+CFLAGS += -DEAP_PAX
+OBJS += eap_pax.o eap_pax_common.o
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
ifdef CONFIG_IEEE8021X_EAPOL
# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication)
CFLAGS += -DIEEE8021X_EAPOL
@@ -252,12 +285,38 @@ OBJS += pcsc_funcs.o
LIBS += -lpcsclite -lpthread
endif
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
ifdef TLS_FUNCS
-# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
CFLAGS += -DEAP_TLS_FUNCS
-OBJS += eap_tls_common.o tls_openssl.o
+OBJS += eap_tls_common.o
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += tls_openssl.o
LIBS += -lssl -lcrypto
LIBS_p += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += tls_gnutls.o
+LIBS += -lgnutls -lgcrypt -lgpg-error
+LIBS_p += -lgcrypt
+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
+ifdef CONFIG_SMARTCARD
+ifndef CONFIG_NATIVE_WINDOWS
+ifndef CONFIG_L2_FREEBSD
+LIBS += -ldl
+endif
+endif
+endif
+NEED_CRYPTO=y
else
OBJS += tls_none.o
endif
@@ -266,16 +325,49 @@ ifdef CONFIG_PKCS12
CFLAGS += -DPKCS12_FUNCS
endif
+ifdef CONFIG_SMARTCARD
+CFLAGS += -DCONFIG_SMARTCARD
+endif
+
ifdef MS_FUNCS
+OBJS += ms_funcs.o
+NEED_CRYPTO=y
+endif
+
+ifdef NEED_CRYPTO
ifndef TLS_FUNCS
+ifeq ($(CONFIG_TLS), openssl)
LIBS += -lcrypto
+LIBS_p += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+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
+endif
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += crypto.o
+OBJS_p += crypto.o
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += crypto_gnutls.o
+OBJS_p += crypto_gnutls.o
+endif
+ifeq ($(CONFIG_TLS), schannel)
+# Using OpenSSL for crypto at the moment; to be replaced
+OBJS += crypto.o
+OBJS_p += crypto.o
endif
-OBJS += ms_funcs.o crypto.o
endif
ifdef CONFIG_WIRELESS_EXTENSION
CFLAGS += -DCONFIG_WIRELESS_EXTENSION
-OBJS += driver_wext.o
+OBJS_d += driver_wext.o
endif
ifdef CONFIG_CTRL_IFACE
@@ -283,10 +375,6 @@ CFLAGS += -DCONFIG_CTRL_IFACE
OBJS += ctrl_iface.o
endif
-ifdef CONFIG_XSUPPLICANT_IFACE
-CFLAGS += -DCONFIG_XSUPPLICANT_IFACE
-endif
-
ifdef CONFIG_READLINE
CFLAGS += -DCONFIG_READLINE
LIBS_c += -lncurses -lreadline
@@ -294,13 +382,34 @@ endif
ifdef CONFIG_NATIVE_WINDOWS
CFLAGS += -DCONFIG_NATIVE_WINDOWS -DCONFIG_CTRL_IFACE_UDP
-LIBS += -lws2_32 -lgdi32
+LIBS += -lws2_32 -lgdi32 -lcrypt32
LIBS_c += -lws2_32
endif
+ifdef CONFIG_NO_STDOUT_DEBUG
+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_IPV6
+# for eapol_test only
+CFLAGS += -DCONFIG_IPV6
+endif
+
+ifndef CONFIG_NO_WPA
+OBJS += wpa.o preauth.o
+NEED_AES=y
+else
+CFLAGS += -DCONFIG_NO_WPA
+endif
+
+ifdef NEED_AES
+OBJS += aes_wrap.o
+endif
+
+OBJS += wpa_supplicant.o events.o
OBJS_t := $(OBJS) eapol_test.o radius.o radius_client.o
-OBJS_t2 := $(OBJS) preauth_test.o l2_packet.o
-OBJS += wpa_supplicant.o wpa.o l2_packet.o drivers.o
+OBJS_t2 := $(OBJS) preauth_test.o
+OBJS += main.o drivers.o $(OBJS_d)
wpa_supplicant: .config $(OBJS)
$(CC) -o wpa_supplicant $(OBJS) $(LIBS)
@@ -342,30 +451,38 @@ wpa_passphrase.exe: wpa_passphrase
mv -f $< $@
win_if_list.exe: win_if_list
mv -f $< $@
+eapol_test.exe: eapol_test
+ mv -f $< $@
WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe
windows-bin: $(WINALL)
$(STRIP) $(WINALL)
+wpa_gui/Makefile:
+ qmake -o wpa_gui/Makefile wpa_gui/wpa_gui.pro
+
+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
+ -DTEST_MAIN_MS_FUNCS -lcrypto -I../hostapd -I.
./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
+ -DTEST_MAIN -I../hostad -I.
./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
+ -DTEST_MAIN -I../hostad -I.
./test-aes_wrap
rm test-aes_wrap
@@ -373,7 +490,7 @@ 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
+ -DTEST_MAIN_EAP_SIM_COMMON -I../hostapd -I.
./test-eap_sim_common
rm test-eap_sim_common
@@ -382,4 +499,25 @@ tests: test-ms_funcs test-sha1 test-aes_wrap test-eap_sim_common
clean:
rm -f core *~ *.o *.d $(ALL) $(WINALL)
+%.eps: %.fig
+ fig2dev -L eps $*.fig $*.eps
+
+%.png: %.fig
+ fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
+ > $*.png
+
+docs-pics: doc/wpa_supplicant.png doc/wpa_supplicant.eps
+
+docs: docs-pics
+ doxygen doc/doxygen.full
+ $(MAKE) -C doc/latex
+ cp doc/latex/refman.pdf wpa_supplicant-devel.pdf
+
+docs-fast: docs-pics
+ doxygen doc/doxygen.fast
+
+clean-docs:
+ rm -rf doc/latex doc/html
+ rm -f doc/wpa_supplicant.{eps,png} wpa_supplicant-devel.pdf
+
-include $(OBJS:%.o=%.d)
diff --git a/contrib/wpa_supplicant/README b/contrib/wpa_supplicant/README
index bab25d5..831756b 100644
--- a/contrib/wpa_supplicant/README
+++ b/contrib/wpa_supplicant/README
@@ -1,7 +1,7 @@
WPA Supplicant
==============
-Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> and
+Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi> and
contributors
All Rights Reserved.
@@ -89,6 +89,7 @@ Supported WPA/IEEE 802.11i features:
* EAP-SIM
* EAP-AKA
* EAP-PSK
+ * EAP-PAX
* LEAP (note: requires special support from the driver for IEEE 802.11
authentication)
(following methods are supported, but since they do not generate keying
@@ -97,8 +98,6 @@ Supported WPA/IEEE 802.11i features:
* EAP-MSCHAPv2
* EAP-GTC
* EAP-OTP
- Alternatively, an external program, e.g., Xsupplicant, can be used for EAP
- authentication.
- key management for CCMP, TKIP, WEP104, WEP40
- RSN/WPA2 (IEEE 802.11i)
* pre-authentication
@@ -112,6 +111,7 @@ Requirements
Current hardware/software requirements:
- Linux kernel 2.4.x or 2.6.x with Linux Wireless Extensions v15 or newer
- FreeBSD 6-CURRENT
+- NetBSD-current
- Microsoft Windows with WinPcap (at least WinXP, may work with other versions)
- drivers:
Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)
@@ -164,8 +164,10 @@ Current hardware/software requirements:
used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
configuration file.
+ Wired Ethernet drivers (with ap_scan=0)
+
BSD net80211 layer (e.g., Atheros driver)
- At the moment, this is for FreeBSD 6-CURRENT branch.
+ At the moment, this is for FreeBSD 6-CURRENT branch and NetBSD-current.
Windows NDIS
The current Windows port requires WinPcap (http://winpcap.polito.it/).
@@ -173,7 +175,8 @@ Current hardware/software requirements:
wpa_supplicant was designed to be portable for different drivers and
operating systems. Hopefully, support for more wlan cards and OSes will be
-added in the future. See developer.txt for more information about the
+added in the future. See developer's documentation
+(http://hostap.epitest.fi/wpa_supplicant/devel/) for more information about the
design of wpa_supplicant and porting to other drivers. One main goal
is to add full WPA/WPA2 support to Linux wireless extensions to allow
new drivers to be supported without having to implement new
@@ -221,8 +224,7 @@ networks that require some kind of security. Task group I (Security)
of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
to address the flaws of the base standard and has in practice
completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
-802.11 standard was approved in June 2004 and this amendment is likely
-to be published in July 2004.
+802.11 standard was approved in June 2004 and published in July 2004.
Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
IEEE 802.11i work (draft 3.0) to define a subset of the security
@@ -277,14 +279,6 @@ robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
to replace TKIP and optimizations for handoff (reduced number of
messages in initial key handshake, pre-authentication, and PMKSA caching).
-Some wireless LAN vendors are already providing support for CCMP in
-their WPA products. There is no "official" interoperability
-certification for CCMP and/or mixed modes using both TKIP and CCMP, so
-some interoperability issues can be expected even though many
-combinations seem to be working with equipment from different vendors.
-Certification for WPA2 is likely to start during the second half of
-2004.
-
wpa_supplicant
@@ -307,9 +301,9 @@ Following steps are used when associating with an AP using WPA:
- wpa_supplicant selects a BSS based on its configuration
- wpa_supplicant requests the kernel driver to associate with the chosen
BSS
-- If WPA-EAP: integrated IEEE 802.1X Supplicant or external Xsupplicant
- completes EAP authentication with the authentication server (proxied
- by the Authenticator in the AP)
+- If WPA-EAP: integrated IEEE 802.1X Supplicant completes EAP
+ authentication with the authentication server (proxied by the
+ Authenticator in the AP)
- If WPA-EAP: master key is received from the IEEE 802.1X Supplicant
- If WPA-PSK: wpa_supplicant uses PSK as the master session key
- wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake
@@ -352,6 +346,7 @@ CONFIG_EAP_OTP=y
CONFIG_EAP_SIM=y
CONFIG_EAP_AKA=y
CONFIG_EAP_PSK=y
+CONFIG_EAP_PAX=y
CONFIG_EAP_LEAP=y
Following option can be used to include GSM SIM/USIM interface for GSM/UMTS
@@ -366,13 +361,12 @@ interface with libpcap/libdnet.
CONFIG_DNET_PCAP=y
Following options can be added to .config to select which driver
-interfaces are included. Prism54.org driver is not yet complete and
-Hermes driver interface needs to be downloaded from Agere (see above).
-Most Linux driver need to include CONFIG_WIRELESS_EXTENSION.
+interfaces are included. Hermes driver interface needs to be downloaded
+from Agere (see above). CONFIG_WIRELESS_EXTENSION will be used
+automatically if any of the selected drivers need it.
CONFIG_WIRELESS_EXTENSION=y
CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_PRISM54=y
CONFIG_DRIVER_HERMES=y
CONFIG_DRIVER_MADWIFI=y
CONFIG_DRIVER_ATMEL=y
@@ -387,7 +381,6 @@ Following example includes all features and driver interfaces that are
included in the wpa_supplicant package:
CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_PRISM54=y
CONFIG_DRIVER_HERMES=y
CONFIG_DRIVER_MADWIFI=y
CONFIG_DRIVER_ATMEL=y
@@ -409,6 +402,7 @@ CONFIG_EAP_OTP=y
CONFIG_EAP_SIM=y
CONFIG_EAP_AKA=y
CONFIG_EAP_PSK=y
+CONFIG_EAP_PAX=y
CONFIG_EAP_LEAP=y
CONFIG_PCSC=y
@@ -463,8 +457,6 @@ options:
-d = increase debugging verbosity (-dd even more)
-K = include keys (passwords, etc.) in debug output
-t = include timestamp in debug messages
- -e = use external IEEE 802.1X Supplicant (e.g., xsupplicant)
- (this disables the internal Supplicant)
-h = show this help text
-L = show license (GPL and BSD)
-q = decrease debugging verbosity (-qq even less)
@@ -475,8 +467,6 @@ options:
drivers:
hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
(this can also be used with Linuxant DriverLoader)
- prism54 = Prism54.org driver (Intersil Prism GT/Duette/Indigo)
- not yet fully implemented
hermes = Agere Systems Inc. driver (Hermes-I/Hermes-II)
madwifi = MADWIFI 802.11 support (Atheros, etc.)
atmel = ATMEL AT76C5XXx (USB, PCMCIA)
@@ -484,6 +474,7 @@ drivers:
ndiswrapper = Linux ndiswrapper
broadcom = Broadcom wl.o driver
ipw = Intel ipw2100/2200 driver
+ wired = wpa_supplicant wired Ethernet driver
bsd = BSD 802.11 support (Atheros, etc.)
ndis = Windows NDIS driver
@@ -647,6 +638,21 @@ network={
}
+6) Authentication for wired Ethernet. This can be used with 'wired' interface
+ (-Dwired on command line).
+
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+ap_scan=0
+network={
+ key_mgmt=IEEE8021X
+ eap=MD5
+ identity="user"
+ password="password"
+ eapol_flags=0
+}
+
+
Certificates
------------
@@ -681,7 +687,7 @@ wpa_supplicant. It is used to query current status, change
configuration, trigger events, and request interactive user input.
wpa_cli can show the current authentication status, selected security
-mode, dot11 and dot1x MIBs, etc. In addition, it can configuring some
+mode, dot11 and dot1x MIBs, etc. In addition, it can configure some
variables like EAPOL state machine parameters and trigger events like
reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user
interface to request authentication information, like username and
@@ -757,11 +763,83 @@ wpa_cli commands
preauthenticate <BSSID> = force preauthentication
identity <network id> <identity> = configure identity for an SSID
password <network id> <password> = configure password for an SSID
+ pin <network id> <pin> = configure pin for an SSID
otp <network id> <password> = configure one-time-password for an SSID
+ passphrase <network id> <passphrase> = configure private key passphrase
+ for an SSID
+ bssid <network id> <BSSID> = set preferred BSSID for an SSID
+ list_networks = list configured networks
+ select_network <network id> = select a network (disable others)
+ enable_network <network id> = enable a network
+ disable_network <network id> = disable a network
+ add_network = add a network
+ remove_network <network id> = remove a network
+ set_network <network id> <variable> <value> = set network variables (shows
+ list of variables when run without arguments)
+ get_network <network id> <variable> = get network variables
+ save_config = save the current configuration
+ disconnect = disconnect and wait for reassociate command before connecting
+ scan = request new BSS scan
+ scan_results = get latest scan results
+ get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = get capabilies
terminate = terminate wpa_supplicant
quit = exit wpa_cli
+wpa_cli command line options
+
+wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] [-a<action file>] \
+ [-P<pid file>] [-g<global ctrl>] [command..]
+ -h = help (show this usage text)
+ -v = shown version information
+ -a = run in daemon mode executing the action file based on events from
+ wpa_supplicant
+ -B = run a daemon in the background
+ default path: /var/run/wpa_supplicant
+ default interface: first interface found in socket path
+
+
+Using wpa_cli to run external program on connect/disconnect
+-----------------------------------------------------------
+
+wpa_cli can used to run external programs whenever wpa_supplicant
+connects or disconnects from a network. This can be used, e.g., to
+update network configuration and/or trigget DHCP client to update IP
+addresses, etc.
+
+One wpa_cli process in "action" mode needs to be started for each
+interface. For example, the following command starts wpa_cli for the
+default ingterface (-i can be used to select the interface in case of
+more than one interface being used at the same time):
+
+wpa_cli -a/sbin/wpa_action.sh -B
+
+The action file (-a option, /sbin/wpa_action.sh in this example) will
+be executed whenever wpa_supplicant completes authentication (connect
+event) or detects disconnection). The action script will be called
+with two command line arguments: interface name and event (CONNECTED
+or DISCONNECTED). If the action script needs to get more information
+about the current network, it can use 'wpa_cli status' to query
+wpa_supplicant for more information.
+
+Following example can be used as a simple template for an action
+script:
+
+#!/bin/sh
+
+IFNAME=$1
+CMD=$2
+
+if [ "$CMD" == "CONNECTED" ]; then
+ SSID=`wpa_cli -i$IFNAME status | grep ^ssid= | cut -f2- -d=`
+ # configure network, signal DHCP client, etc.
+fi
+
+if [ "$CMD" == "DISCONNECTED" ]; then
+ # remove network configuration, if needed
+fi
+
+
Integrating with pcmcia-cs/cardmgr scripts
------------------------------------------
@@ -804,55 +882,38 @@ started--and will then negotiate keys with the AP.
-Optional integration with Xsupplicant
--------------------------------------
-
-wpa_supplicant has an integrated IEEE 802.1X Supplicant that supports
-most commonly used EAP methods. In addition, wpa_supplicant has an
-experimental interface for integrating it with Xsupplicant
-(http://www.open1x.org/) for the WPA with EAP authentication.
-
-When using WPA-EAP, both wpa_supplicant and Xsupplicant must be
-configured with the network security policy. See Xsupplicant documents
-for information about its configuration. Please also note, that a new
-command line option -W (enable WPA) must be used when starting
-xsupplicant.
-
-Example configuration for xsupplicant:
-
-network_list = all
-default_netname = jkm
-
-jkm
-{
- type = wireless
- allow_types = eap_peap
- identity = <BEGIN_ID>jkm<END_ID>
- eap-peap {
- random_file = /dev/urandom
- root_cert = /home/jkm/CA.pem
- chunk_size = 1398
- allow_types = eap_mschapv2
- eap-mschapv2 {
- username = <BEGIN_UNAME>jkm<END_UNAME>
- password = <BEGIN_PASS>jkm<END_PASS>
- }
- }
-}
+Dynamic interface add and operation without configuration files
+---------------------------------------------------------------
+wpa_supplicant can be started without any configuration files or
+network interfaces. When used in this way, a global (i.e., per
+wpa_supplicant process) control interface is used to add and remove
+network interfaces. Each network interface can then be configured
+through a per-network interface control interface. For example,
+following commands show how to start wpa_supplicant without any
+network interfaces and then add a network interface and configure a
+network (SSID):
-Example configuration for wpa_supplicant:
+# Start wpa_supplicant in the background
+wpa_supplicant -g/var/run/wpa_supplicant-global -B
-network={
- ssid="jkm"
- key_mgmt=WPA-EAP
-}
+# Add a new interface (wlan0, no configuration file, driver=wext, and
+# enable control interface)
+wpa_cli -g/var/run/wpa_supplicant-global interface_add wlan0 \
+ "" wext /var/run/wpa_supplicant
+# Configure a network using the newly added network interface:
+wpa_cli -iwlan0 add_network
+wpa_cli -iwlan0 set_network 0 ssid '"test"'
+wpa_cli -iwlan0 set_network 0 key_mgmt WPA-PSK
+wpa_cli -iwlan0 set_network 0 psk '"12345678"'
+wpa_cli -iwlan0 set_network 0 pairwise TKIP
+wpa_cli -iwlan0 set_network 0 group TKIP
+wpa_cli -iwlan0 set_network 0 proto WPA
+wpa_cli -iwlan0 enable_network 0
-Both wpa_supplicant and xsupplicant need to be started. Please remember
-to add '-W' option for xsupplicant in order to provide keying material
-for wpa_supplicant and '-e' option for wpa_supplicant to disable internal
-IEEE 802.1X implementation.
+# At this point, the new network interface should start trying to associate
+# with the WPA-PSK network using SSID test.
-wpa_supplicant -iwlan0 -cwpa_supplicant.conf -e
-xsupplicant -iwlan0 -cxsupplicant.conf -W
+# Remove network interface
+wpa_cli -g/var/run/wpa_supplicant-global interface_remove wlan0
diff --git a/contrib/wpa_supplicant/aes.c b/contrib/wpa_supplicant/aes.c
index eabebd0..ce94778 100644
--- a/contrib/wpa_supplicant/aes.c
+++ b/contrib/wpa_supplicant/aes.c
@@ -1,8 +1,15 @@
/*
+ * AES (Rijndael) cipher
+ *
* Modifications to public domain implementation:
* - support only 128-bit keys
* - cleanup
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * - use C pre-processor to make it easier to change S table access
+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
+ * 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>
*
* 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
@@ -14,7 +21,7 @@
* See README and COPYING for more details.
*/
-/**
+/*
* rijndael-alg-fst.c
*
* @version 3.0 (December 2000)
@@ -40,7 +47,8 @@
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#define FULL_UNROLL
+/* #define FULL_UNROLL */
+#define AES_SMALL_TABLES
/*
@@ -123,6 +131,7 @@ static const u32 Te0[256] = {
0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
};
+#ifndef AES_SMALL_TABLES
static const u32 Te1[256] = {
0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
@@ -388,6 +397,7 @@ static const u32 Te4[256] = {
0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
};
+#endif /* AES_SMALL_TABLES */
static const u32 Td0[256] = {
0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
@@ -454,6 +464,7 @@ static const u32 Td0[256] = {
0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
};
+#ifndef AES_SMALL_TABLES
static const u32 Td1[256] = {
0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
@@ -724,6 +735,116 @@ static const u32 rcon[] = {
0x10000000, 0x20000000, 0x40000000, 0x80000000,
0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
};
+#else /* AES_SMALL_TABLES */
+static const u8 Td4s[256] = {
+ 0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
+ 0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
+ 0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
+ 0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
+ 0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
+ 0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
+ 0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
+ 0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
+ 0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
+ 0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
+ 0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
+ 0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
+ 0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
+ 0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
+ 0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
+ 0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
+ 0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
+ 0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
+ 0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
+ 0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
+ 0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
+ 0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
+ 0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
+ 0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
+ 0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
+ 0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
+ 0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
+ 0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
+ 0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
+ 0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
+ 0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
+ 0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
+};
+static const u8 rcons[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+ /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+#endif /* AES_SMALL_TABLES */
+
+
+#ifndef AES_SMALL_TABLES
+
+#define RCON(i) rcon[(i)]
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) Te1[((i) >> 16) & 0xff]
+#define TE2(i) Te2[((i) >> 8) & 0xff]
+#define TE3(i) Te3[(i) & 0xff]
+#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
+#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff)
+#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000)
+#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff)
+#define TE4(i) (Te4[(i)] & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) Td1[((i) >> 16) & 0xff]
+#define TD2(i) Td2[((i) >> 8) & 0xff]
+#define TD3(i) Td3[(i) & 0xff]
+#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000)
+#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff)
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) Td1[(i) & 0xff]
+#define TD2_(i) Td2[(i) & 0xff]
+#define TD3_(i) Td3[(i) & 0xff]
+
+#else /* AES_SMALL_TABLES */
+
+#define RCON(i) (rcons[(i)] << 24)
+
+static inline u32 rotr(u32 val, int bits)
+{
+ return (val >> bits) | (val << (32 - bits));
+}
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
+#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
+#define TE3(i) rotr(Te0[(i) & 0xff], 24)
+#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
+#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
+#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
+#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
+#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
+#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
+#define TD3(i) rotr(Td0[(i) & 0xff], 24)
+#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
+#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
+#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
+#define TD44(i) (Td4s[(i) & 0xff])
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
+#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
+#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
+
+#endif /* AES_SMALL_TABLES */
#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
@@ -755,11 +876,8 @@ void rijndaelKeySetupEnc(u32 rk[/*44*/], const u8 cipherKey[])
for (i = 0; i < 10; i++) {
temp = rk[3];
rk[4] = rk[0] ^
- (Te4[(temp >> 16) & 0xff] & 0xff000000) ^
- (Te4[(temp >> 8) & 0xff] & 0x00ff0000) ^
- (Te4[(temp ) & 0xff] & 0x0000ff00) ^
- (Te4[(temp >> 24) ] & 0x000000ff) ^
- rcon[i];
+ TE421(temp) ^ TE432(temp) ^ TE443(temp) ^ TE414(temp) ^
+ RCON(i);
rk[5] = rk[1] ^ rk[4];
rk[6] = rk[2] ^ rk[5];
rk[7] = rk[3] ^ rk[6];
@@ -790,33 +908,19 @@ void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
* first and the last: */
for (i = 1; i < Nr; i++) {
rk += 4;
- rk[0] =
- Td0[Te4[(rk[0] >> 24) ] & 0xff] ^
- Td1[Te4[(rk[0] >> 16) & 0xff] & 0xff] ^
- Td2[Te4[(rk[0] >> 8) & 0xff] & 0xff] ^
- Td3[Te4[(rk[0] ) & 0xff] & 0xff];
- rk[1] =
- Td0[Te4[(rk[1] >> 24) ] & 0xff] ^
- Td1[Te4[(rk[1] >> 16) & 0xff] & 0xff] ^
- Td2[Te4[(rk[1] >> 8) & 0xff] & 0xff] ^
- Td3[Te4[(rk[1] ) & 0xff] & 0xff];
- rk[2] =
- Td0[Te4[(rk[2] >> 24) ] & 0xff] ^
- Td1[Te4[(rk[2] >> 16) & 0xff] & 0xff] ^
- Td2[Te4[(rk[2] >> 8) & 0xff] & 0xff] ^
- Td3[Te4[(rk[2] ) & 0xff] & 0xff];
- rk[3] =
- Td0[Te4[(rk[3] >> 24) ] & 0xff] ^
- Td1[Te4[(rk[3] >> 16) & 0xff] & 0xff] ^
- Td2[Te4[(rk[3] >> 8) & 0xff] & 0xff] ^
- Td3[Te4[(rk[3] ) & 0xff] & 0xff];
+ for (j = 0; j < 4; j++) {
+ rk[j] = TD0_(TE4((rk[j] >> 24) )) ^
+ TD1_(TE4((rk[j] >> 16) & 0xff)) ^
+ TD2_(TE4((rk[j] >> 8) & 0xff)) ^
+ TD3_(TE4((rk[j] ) & 0xff));
+ }
}
}
void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
{
u32 s0, s1, s2, s3, t0, t1, t2, t3;
- int Nr = 10;
+ const int Nr = 10;
#ifndef FULL_UNROLL
int r;
#endif /* ?FULL_UNROLL */
@@ -829,153 +933,61 @@ void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
s1 = GETU32(pt + 4) ^ rk[1];
s2 = GETU32(pt + 8) ^ rk[2];
s3 = GETU32(pt + 12) ^ rk[3];
+
+#define ROUND(i,d,s) \
+d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
+d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
+d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
+d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
+
#ifdef FULL_UNROLL
- /* round 1: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[ 4];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[ 5];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[ 6];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[ 7];
- /* round 2: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[ 8];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[ 9];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[10];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[11];
- /* round 3: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[12];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[13];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[14];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[15];
- /* round 4: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[16];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[17];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[18];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[19];
- /* round 5: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[20];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[21];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[22];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[23];
- /* round 6: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[24];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[25];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[26];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[27];
- /* round 7: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[28];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[29];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[30];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[31];
- /* round 8: */
- s0 = Te0[t0 >> 24] ^ Te1[(t1 >> 16) & 0xff] ^ Te2[(t2 >> 8) & 0xff] ^ Te3[t3 & 0xff] ^ rk[32];
- s1 = Te0[t1 >> 24] ^ Te1[(t2 >> 16) & 0xff] ^ Te2[(t3 >> 8) & 0xff] ^ Te3[t0 & 0xff] ^ rk[33];
- s2 = Te0[t2 >> 24] ^ Te1[(t3 >> 16) & 0xff] ^ Te2[(t0 >> 8) & 0xff] ^ Te3[t1 & 0xff] ^ rk[34];
- s3 = Te0[t3 >> 24] ^ Te1[(t0 >> 16) & 0xff] ^ Te2[(t1 >> 8) & 0xff] ^ Te3[t2 & 0xff] ^ rk[35];
- /* round 9: */
- t0 = Te0[s0 >> 24] ^ Te1[(s1 >> 16) & 0xff] ^ Te2[(s2 >> 8) & 0xff] ^ Te3[s3 & 0xff] ^ rk[36];
- t1 = Te0[s1 >> 24] ^ Te1[(s2 >> 16) & 0xff] ^ Te2[(s3 >> 8) & 0xff] ^ Te3[s0 & 0xff] ^ rk[37];
- t2 = Te0[s2 >> 24] ^ Te1[(s3 >> 16) & 0xff] ^ Te2[(s0 >> 8) & 0xff] ^ Te3[s1 & 0xff] ^ rk[38];
- t3 = Te0[s3 >> 24] ^ Te1[(s0 >> 16) & 0xff] ^ Te2[(s1 >> 8) & 0xff] ^ Te3[s2 & 0xff] ^ rk[39];
- rk += Nr << 2;
+
+ ROUND(1,t,s);
+ ROUND(2,s,t);
+ ROUND(3,t,s);
+ ROUND(4,s,t);
+ ROUND(5,t,s);
+ ROUND(6,s,t);
+ ROUND(7,t,s);
+ ROUND(8,s,t);
+ ROUND(9,t,s);
+
+ rk += Nr << 2;
+
#else /* !FULL_UNROLL */
- /*
- * Nr - 1 full rounds:
- */
- r = Nr >> 1;
- for (;;) {
- t0 =
- Te0[(s0 >> 24) ] ^
- Te1[(s1 >> 16) & 0xff] ^
- Te2[(s2 >> 8) & 0xff] ^
- Te3[(s3 ) & 0xff] ^
- rk[4];
- t1 =
- Te0[(s1 >> 24) ] ^
- Te1[(s2 >> 16) & 0xff] ^
- Te2[(s3 >> 8) & 0xff] ^
- Te3[(s0 ) & 0xff] ^
- rk[5];
- t2 =
- Te0[(s2 >> 24) ] ^
- Te1[(s3 >> 16) & 0xff] ^
- Te2[(s0 >> 8) & 0xff] ^
- Te3[(s1 ) & 0xff] ^
- rk[6];
- t3 =
- Te0[(s3 >> 24) ] ^
- Te1[(s0 >> 16) & 0xff] ^
- Te2[(s1 >> 8) & 0xff] ^
- Te3[(s2 ) & 0xff] ^
- rk[7];
- rk += 8;
- if (--r == 0) {
- break;
- }
+ /* Nr - 1 full rounds: */
+ r = Nr >> 1;
+ for (;;) {
+ ROUND(1,t,s);
+ rk += 8;
+ if (--r == 0)
+ break;
+ ROUND(0,s,t);
+ }
- s0 =
- Te0[(t0 >> 24) ] ^
- Te1[(t1 >> 16) & 0xff] ^
- Te2[(t2 >> 8) & 0xff] ^
- Te3[(t3 ) & 0xff] ^
- rk[0];
- s1 =
- Te0[(t1 >> 24) ] ^
- Te1[(t2 >> 16) & 0xff] ^
- Te2[(t3 >> 8) & 0xff] ^
- Te3[(t0 ) & 0xff] ^
- rk[1];
- s2 =
- Te0[(t2 >> 24) ] ^
- Te1[(t3 >> 16) & 0xff] ^
- Te2[(t0 >> 8) & 0xff] ^
- Te3[(t1 ) & 0xff] ^
- rk[2];
- s3 =
- Te0[(t3 >> 24) ] ^
- Te1[(t0 >> 16) & 0xff] ^
- Te2[(t1 >> 8) & 0xff] ^
- Te3[(t2 ) & 0xff] ^
- rk[3];
- }
#endif /* ?FULL_UNROLL */
- /*
+
+#undef ROUND
+
+ /*
* apply last round and
* map cipher state to byte array block:
*/
- s0 =
- (Te4[(t0 >> 24) ] & 0xff000000) ^
- (Te4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t3 ) & 0xff] & 0x000000ff) ^
- rk[0];
+ s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
PUTU32(ct , s0);
- s1 =
- (Te4[(t1 >> 24) ] & 0xff000000) ^
- (Te4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t0 ) & 0xff] & 0x000000ff) ^
- rk[1];
+ s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
PUTU32(ct + 4, s1);
- s2 =
- (Te4[(t2 >> 24) ] & 0xff000000) ^
- (Te4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t1 ) & 0xff] & 0x000000ff) ^
- rk[2];
+ s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
PUTU32(ct + 8, s2);
- s3 =
- (Te4[(t3 >> 24) ] & 0xff000000) ^
- (Te4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
- (Te4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
- (Te4[(t2 ) & 0xff] & 0x000000ff) ^
- rk[3];
+ s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
PUTU32(ct + 12, s3);
}
void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
{
u32 s0, s1, s2, s3, t0, t1, t2, t3;
- int Nr = 10;
+ const int Nr = 10;
#ifndef FULL_UNROLL
int r;
#endif /* ?FULL_UNROLL */
@@ -984,149 +996,110 @@ void rijndaelDecrypt(const u32 rk[/*44*/], const u8 ct[16], u8 pt[16])
* map byte array block to cipher state
* and add initial round key:
*/
- s0 = GETU32(ct ) ^ rk[0];
- s1 = GETU32(ct + 4) ^ rk[1];
- s2 = GETU32(ct + 8) ^ rk[2];
- s3 = GETU32(ct + 12) ^ rk[3];
+ s0 = GETU32(ct ) ^ rk[0];
+ s1 = GETU32(ct + 4) ^ rk[1];
+ s2 = GETU32(ct + 8) ^ rk[2];
+ s3 = GETU32(ct + 12) ^ rk[3];
+
+#define ROUND(i,d,s) \
+d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \
+d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \
+d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \
+d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
+
#ifdef FULL_UNROLL
- /* round 1: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[ 4];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[ 5];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[ 6];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[ 7];
- /* round 2: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[ 8];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[ 9];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[10];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[11];
- /* round 3: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[12];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[13];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[14];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[15];
- /* round 4: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[16];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[17];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[18];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[19];
- /* round 5: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[20];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[21];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[22];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[23];
- /* round 6: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[24];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[25];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[26];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[27];
- /* round 7: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[28];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[29];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[30];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[31];
- /* round 8: */
- s0 = Td0[t0 >> 24] ^ Td1[(t3 >> 16) & 0xff] ^ Td2[(t2 >> 8) & 0xff] ^ Td3[t1 & 0xff] ^ rk[32];
- s1 = Td0[t1 >> 24] ^ Td1[(t0 >> 16) & 0xff] ^ Td2[(t3 >> 8) & 0xff] ^ Td3[t2 & 0xff] ^ rk[33];
- s2 = Td0[t2 >> 24] ^ Td1[(t1 >> 16) & 0xff] ^ Td2[(t0 >> 8) & 0xff] ^ Td3[t3 & 0xff] ^ rk[34];
- s3 = Td0[t3 >> 24] ^ Td1[(t2 >> 16) & 0xff] ^ Td2[(t1 >> 8) & 0xff] ^ Td3[t0 & 0xff] ^ rk[35];
- /* round 9: */
- t0 = Td0[s0 >> 24] ^ Td1[(s3 >> 16) & 0xff] ^ Td2[(s2 >> 8) & 0xff] ^ Td3[s1 & 0xff] ^ rk[36];
- t1 = Td0[s1 >> 24] ^ Td1[(s0 >> 16) & 0xff] ^ Td2[(s3 >> 8) & 0xff] ^ Td3[s2 & 0xff] ^ rk[37];
- t2 = Td0[s2 >> 24] ^ Td1[(s1 >> 16) & 0xff] ^ Td2[(s0 >> 8) & 0xff] ^ Td3[s3 & 0xff] ^ rk[38];
- t3 = Td0[s3 >> 24] ^ Td1[(s2 >> 16) & 0xff] ^ Td2[(s1 >> 8) & 0xff] ^ Td3[s0 & 0xff] ^ rk[39];
+
+ ROUND(1,t,s);
+ ROUND(2,s,t);
+ ROUND(3,t,s);
+ ROUND(4,s,t);
+ ROUND(5,t,s);
+ ROUND(6,s,t);
+ ROUND(7,t,s);
+ ROUND(8,s,t);
+ ROUND(9,t,s);
+
rk += Nr << 2;
+
#else /* !FULL_UNROLL */
- /*
- * Nr - 1 full rounds:
- */
- r = Nr >> 1;
- for (;;) {
- t0 =
- Td0[(s0 >> 24) ] ^
- Td1[(s3 >> 16) & 0xff] ^
- Td2[(s2 >> 8) & 0xff] ^
- Td3[(s1 ) & 0xff] ^
- rk[4];
- t1 =
- Td0[(s1 >> 24) ] ^
- Td1[(s0 >> 16) & 0xff] ^
- Td2[(s3 >> 8) & 0xff] ^
- Td3[(s2 ) & 0xff] ^
- rk[5];
- t2 =
- Td0[(s2 >> 24) ] ^
- Td1[(s1 >> 16) & 0xff] ^
- Td2[(s0 >> 8) & 0xff] ^
- Td3[(s3 ) & 0xff] ^
- rk[6];
- t3 =
- Td0[(s3 >> 24) ] ^
- Td1[(s2 >> 16) & 0xff] ^
- Td2[(s1 >> 8) & 0xff] ^
- Td3[(s0 ) & 0xff] ^
- rk[7];
- rk += 8;
- if (--r == 0) {
- break;
- }
+ /* Nr - 1 full rounds: */
+ r = Nr >> 1;
+ for (;;) {
+ ROUND(1,t,s);
+ rk += 8;
+ if (--r == 0)
+ break;
+ ROUND(0,s,t);
+ }
- s0 =
- Td0[(t0 >> 24) ] ^
- Td1[(t3 >> 16) & 0xff] ^
- Td2[(t2 >> 8) & 0xff] ^
- Td3[(t1 ) & 0xff] ^
- rk[0];
- s1 =
- Td0[(t1 >> 24) ] ^
- Td1[(t0 >> 16) & 0xff] ^
- Td2[(t3 >> 8) & 0xff] ^
- Td3[(t2 ) & 0xff] ^
- rk[1];
- s2 =
- Td0[(t2 >> 24) ] ^
- Td1[(t1 >> 16) & 0xff] ^
- Td2[(t0 >> 8) & 0xff] ^
- Td3[(t3 ) & 0xff] ^
- rk[2];
- s3 =
- Td0[(t3 >> 24) ] ^
- Td1[(t2 >> 16) & 0xff] ^
- Td2[(t1 >> 8) & 0xff] ^
- Td3[(t0 ) & 0xff] ^
- rk[3];
- }
#endif /* ?FULL_UNROLL */
- /*
+
+#undef ROUND
+
+ /*
* apply last round and
* map cipher state to byte array block:
*/
- s0 =
- (Td4[(t0 >> 24) ] & 0xff000000) ^
- (Td4[(t3 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(t2 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(t1 ) & 0xff] & 0x000000ff) ^
- rk[0];
+ s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0];
PUTU32(pt , s0);
- s1 =
- (Td4[(t1 >> 24) ] & 0xff000000) ^
- (Td4[(t0 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(t3 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(t2 ) & 0xff] & 0x000000ff) ^
- rk[1];
+ s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1];
PUTU32(pt + 4, s1);
- s2 =
- (Td4[(t2 >> 24) ] & 0xff000000) ^
- (Td4[(t1 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(t0 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(t3 ) & 0xff] & 0x000000ff) ^
- rk[2];
+ s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2];
PUTU32(pt + 8, s2);
- s3 =
- (Td4[(t3 >> 24) ] & 0xff000000) ^
- (Td4[(t2 >> 16) & 0xff] & 0x00ff0000) ^
- (Td4[(t1 >> 8) & 0xff] & 0x0000ff00) ^
- (Td4[(t0 ) & 0xff] & 0x000000ff) ^
- rk[3];
+ s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3];
PUTU32(pt + 12, s3);
}
+
+
+
+/* Generic wrapper functions for AES functions */
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ u32 *rk;
+ if (len != 16)
+ return NULL;
+ rk = malloc(4 * 44);
+ if (rk == NULL)
+ return NULL;
+ rijndaelKeySetupEnc(rk, key);
+ return rk;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ rijndaelEncrypt(ctx, plain, crypt);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ free(ctx);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ u32 *rk;
+ if (len != 16)
+ return NULL;
+ rk = malloc(4 * 44);
+ if (rk == NULL)
+ return NULL;
+ rijndaelKeySetupDec(rk, key);
+ return rk;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ rijndaelDecrypt(ctx, crypt, plain);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ free(ctx);
+}
diff --git a/contrib/wpa_supplicant/aes_wrap.c b/contrib/wpa_supplicant/aes_wrap.c
index dbcc136..a5925ca 100644
--- a/contrib/wpa_supplicant/aes_wrap.c
+++ b/contrib/wpa_supplicant/aes_wrap.c
@@ -1,10 +1,13 @@
/*
- * AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
- * One-Key CBC MAC (OMAC1) hash with AES-128
- * AES-128 CTR mode encryption
- * AES-128 EAX mode encryption/decryption
- * AES-128 CBC
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * AES-based functions
+ *
+ * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - AES-128 CTR mode encryption
+ * - AES-128 EAX mode encryption/decryption
+ * - AES-128 CBC
+ *
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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,43 +24,26 @@
#include <string.h>
#include "common.h"
#include "aes_wrap.h"
+#include "crypto.h"
-#ifdef EAP_TLS_FUNCS
-
-#include <openssl/aes.h>
-
-#else /* EAP_TLS_FUNCS */
-
+#ifndef EAP_TLS_FUNCS
#include "aes.c"
-
-struct aes_key_st {
- u32 rk[44];
-};
-typedef struct aes_key_st AES_KEY;
-
-#define AES_set_encrypt_key(userKey, bits, key) \
- rijndaelKeySetupEnc((key)->rk, (userKey))
-#define AES_set_decrypt_key(userKey, bits, key) \
- rijndaelKeySetupDec((key)->rk, (userKey))
-#define AES_encrypt(in, out, key) \
- rijndaelEncrypt((key)->rk, in, out)
-#define AES_decrypt(in, out, key) \
- rijndaelDecrypt((key)->rk, in, out)
-
#endif /* EAP_TLS_FUNCS */
-/*
- * @kek: key encryption key (KEK)
- * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
- * @plain: plaintext key to be wrapped, n * 64 bit
- * @cipher: wrapped key, (n + 1) * 64 bit
+/**
+ * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * @kek: Key encryption key (KEK)
+ * @n: Length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
+ * @plain: Plaintext key to be wrapped, n * 64 bit
+ * @cipher: Wrapped key, (n + 1) * 64 bit
+ * Returns: 0 on success, -1 on failure
*/
-void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher)
+int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
{
u8 *a, *r, b[16];
int i, j;
- AES_KEY key;
+ void *ctx;
a = cipher;
r = cipher + 8;
@@ -66,7 +52,9 @@ void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher)
memset(a, 0xa6, 8);
memcpy(r, plain, 8 * n);
- AES_set_encrypt_key(kek, 128, &key);
+ ctx = aes_encrypt_init(kek, 16);
+ if (ctx == NULL)
+ return -1;
/* 2) Calculate intermediate values.
* For j = 0 to 5
@@ -80,40 +68,47 @@ void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher)
for (i = 1; i <= n; i++) {
memcpy(b, a, 8);
memcpy(b + 8, r, 8);
- AES_encrypt(b, b, &key);
+ aes_encrypt(ctx, b, b);
memcpy(a, b, 8);
a[7] ^= n * j + i;
memcpy(r, b + 8, 8);
r += 8;
}
}
+ aes_encrypt_deinit(ctx);
/* 3) Output the results.
*
* These are already in @cipher due to the location of temporary
* variables.
*/
+
+ return 0;
}
-/*
- * @kek: key encryption key (KEK)
- * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
- * @cipher: wrapped key to be unwrapped, (n + 1) * 64 bit
- * @plain: plaintext key, n * 64 bit
+/**
+ * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * @kek: Key encryption key (KEK)
+ * @n: Length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
+ * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bit
+ * @plain: Plaintext key, n * 64 bit
+ * Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
*/
-int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain)
+int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
{
u8 a[8], *r, b[16];
int i, j;
- AES_KEY key;
+ void *ctx;
/* 1) Initialize variables. */
memcpy(a, cipher, 8);
r = plain;
memcpy(r, cipher + 8, 8 * n);
- AES_set_decrypt_key(kek, 128, &key);
+ ctx = aes_decrypt_init(kek, 16);
+ if (ctx == NULL)
+ return -1;
/* 2) Compute intermediate values.
* For j = 5 to 0
@@ -129,12 +124,13 @@ int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain)
b[7] ^= n * j + i;
memcpy(b + 8, r, 8);
- AES_decrypt(b, b, &key);
+ aes_decrypt(ctx, b, b);
memcpy(a, b, 8);
memcpy(r, b + 8, 8);
r -= 8;
}
}
+ aes_decrypt_deinit(ctx);
/* 3) Output results.
*
@@ -165,27 +161,37 @@ static void gf_mulx(u8 *pad)
}
-void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+/**
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128
+ * @key: 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)
+ * Returns: 0 on success, -1 on failure
+ */
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
{
- AES_KEY akey;
+ void *ctx;
u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
const u8 *pos = data;
int i;
size_t left = data_len;
- AES_set_encrypt_key(key, 128, &akey);
+ ctx = aes_encrypt_init(key, 16);
+ if (ctx == NULL)
+ return -1;
memset(cbc, 0, BLOCK_SIZE);
while (left >= BLOCK_SIZE) {
for (i = 0; i < BLOCK_SIZE; i++)
cbc[i] ^= *pos++;
if (left > BLOCK_SIZE)
- AES_encrypt(cbc, cbc, &akey);
+ aes_encrypt(ctx, cbc, cbc);
left -= BLOCK_SIZE;
}
memset(pad, 0, BLOCK_SIZE);
- AES_encrypt(pad, pad, &akey);
+ aes_encrypt(ctx, pad, pad);
gf_mulx(pad);
if (left || data_len == 0) {
@@ -197,32 +203,55 @@ void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
for (i = 0; i < BLOCK_SIZE; i++)
pad[i] ^= cbc[i];
- AES_encrypt(pad, mac, &akey);
+ aes_encrypt(ctx, pad, mac);
+ aes_encrypt_deinit(ctx);
+ return 0;
}
-void aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
+/**
+ * aes_128_encrypt_block - Perform one AES 128-bit block operation
+ * @key: Key for AES
+ * @in: Input data (16 bytes)
+ * @out: Output of the AES block operation (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
{
- AES_KEY akey;
- AES_set_encrypt_key(key, 128, &akey);
- AES_encrypt(in, out, &akey);
+ void *ctx;
+ ctx = aes_encrypt_init(key, 16);
+ if (ctx == NULL)
+ return -1;
+ aes_encrypt(ctx, in, out);
+ aes_encrypt_deinit(ctx);
+ return 0;
}
-void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
- u8 *data, size_t data_len)
+/**
+ * aes_128_ctr_encrypt - AES-128 CTR mode encryption
+ * @key: Key for encryption (16 bytes)
+ * @nonce: Nonce for counter mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+ u8 *data, size_t data_len)
{
- AES_KEY akey;
+ void *ctx;
size_t len, left = data_len;
int i;
u8 *pos = data;
u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE];
- AES_set_encrypt_key(key, 128, &akey);
+ ctx = aes_encrypt_init(key, 16);
+ if (ctx == NULL)
+ return -1;
memcpy(counter, nonce, BLOCK_SIZE);
while (left > 0) {
- AES_encrypt(counter, buf, &akey);
+ aes_encrypt(ctx, counter, buf);
len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE;
for (i = 0; i < len; i++)
@@ -236,9 +265,23 @@ void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
break;
}
}
+ aes_encrypt_deinit(ctx);
+ return 0;
}
+/**
+ * aes_128_eax_encrypt - AES-128 EAX mode encryption
+ * @key: Key for encryption (16 bytes)
+ * @nonce: Nonce for counter mode
+ * @nonce_len: Nonce length in bytes
+ * @hdr: Header data to be authenticity protected
+ * @hdr_len: Length of the header data bytes
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * @tag: 16-byte tag value
+ * Returns: 0 on success, -1 on failure
+ */
int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, u8 *tag)
@@ -284,6 +327,18 @@ int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
}
+/**
+ * aes_128_eax_decrypt - AES-128 EAX mode decryption
+ * @key: Key for decryption (16 bytes)
+ * @nonce: Nonce for counter mode
+ * @nonce_len: Nonce length in bytes
+ * @hdr: Header data to be authenticity protected
+ * @hdr_len: Length of the header data bytes
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * @tag: 16-byte tag value
+ * Returns: 0 on success, -1 on failure, -2 if tag does not match
+ */
int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, const u8 *tag)
@@ -332,48 +387,70 @@ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
}
-void aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
- size_t data_len)
+/**
+ * aes_128_cbc_encrypt - AES-128 CBC encryption
+ * @key: Encryption key
+ * @iv: Encryption IV for CBC mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes (must be divisible by 16)
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
- AES_KEY akey;
+ void *ctx;
u8 cbc[BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
- AES_set_encrypt_key(key, 128, &akey);
+ ctx = aes_encrypt_init(key, 16);
+ if (ctx == NULL)
+ return -1;
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(cbc, cbc, &akey);
+ aes_encrypt(ctx, cbc, cbc);
memcpy(pos, cbc, BLOCK_SIZE);
pos += BLOCK_SIZE;
}
+ aes_encrypt_deinit(ctx);
+ return 0;
}
-void aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
- size_t data_len)
+/**
+ * aes_128_cbc_decrypt - AES-128 CBC decryption
+ * @key: Decryption key
+ * @iv: Decryption IV for CBC mode (16 bytes)
+ * @data: Data to decrypt in-place
+ * @data_len: Length of data in bytes (must be divisible by 16)
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
{
- AES_KEY akey;
+ void *ctx;
u8 cbc[BLOCK_SIZE], tmp[BLOCK_SIZE];
u8 *pos = data;
int i, j, blocks;
- AES_set_decrypt_key(key, 128, &akey);
+ ctx = aes_decrypt_init(key, 16);
+ if (ctx == NULL)
+ return -1;
memcpy(cbc, iv, BLOCK_SIZE);
blocks = data_len / BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
memcpy(tmp, pos, BLOCK_SIZE);
- AES_decrypt(pos, pos, &akey);
+ aes_decrypt(ctx, pos, pos);
for (j = 0; j < BLOCK_SIZE; j++)
pos[j] ^= cbc[j];
memcpy(cbc, tmp, BLOCK_SIZE);
pos += BLOCK_SIZE;
}
+ aes_decrypt_deinit(ctx);
+ return 0;
}
@@ -388,25 +465,28 @@ static void test_aes_perf(void)
const int num_iters = 10;
int i;
unsigned int start, end;
- AES_KEY akey;
u8 key[16], pt[16], ct[16];
+ void *ctx;
printf("keySetupEnc:");
for (i = 0; i < num_iters; i++) {
rdtscll(start);
- AES_set_encrypt_key(key, 128, &akey);
+ 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(pt, ct, &akey);
+ aes_encrypt(ctx, pt, ct);
rdtscll(end);
printf(" %d", end - start);
}
+ aes_encrypt_deinit(ctx);
printf("\n");
}
#endif /* __i386__ */
@@ -599,7 +679,10 @@ int main(int argc, char *argv[])
int ret = 0, i;
struct omac1_test_vector *tv;
- aes_wrap(kek, 2, plain, result);
+ 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++;
diff --git a/contrib/wpa_supplicant/aes_wrap.h b/contrib/wpa_supplicant/aes_wrap.h
index 70e83ea..cb1a539 100644
--- a/contrib/wpa_supplicant/aes_wrap.h
+++ b/contrib/wpa_supplicant/aes_wrap.h
@@ -1,21 +1,42 @@
+/*
+ * AES-based functions
+ *
+ * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - AES-128 CTR mode encryption
+ * - AES-128 EAX mode encryption/decryption
+ * - AES-128 CBC
+ *
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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_WRAP_H
#define AES_WRAP_H
-void aes_wrap(u8 *kek, int n, u8 *plain, u8 *cipher);
-int aes_unwrap(u8 *kek, int n, u8 *cipher, u8 *plain);
-void omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
-void aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
-void aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
- u8 *data, size_t data_len);
+int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
+int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac);
+int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
+int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+ u8 *data, size_t data_len);
int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, u8 *tag);
int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
const u8 *hdr, size_t hdr_len,
u8 *data, size_t data_len, const u8 *tag);
-void aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
- size_t data_len);
-void aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
- size_t data_len);
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len);
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
+ size_t data_len);
#endif /* AES_WRAP_H */
diff --git a/contrib/wpa_supplicant/base64.c b/contrib/wpa_supplicant/base64.c
new file mode 100644
index 0000000..2717e30
--- /dev/null
+++ b/contrib/wpa_supplicant/base64.c
@@ -0,0 +1,198 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <string.h>
+
+#include "base64.h"
+
+static const unsigned char base64_table[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode - Base64 encode
+ * @src: Data to be encoded
+ * @len: Length of the data to be encoded
+ * @out_len: Pointer to output length variable, or %NULL if not used
+ * Returns: Allocated buffer of out_len bytes of encoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer. Returned buffer is
+ * nul terminated to make it easier to use as a C string. The nul terminator is
+ * not included in out_len.
+ */
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+ size_t *out_len)
+{
+ unsigned char *out, *pos;
+ const unsigned char *end, *in;
+ size_t olen;
+ int line_len;
+
+ olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
+ olen += olen / 72; /* line feeds */
+ olen++; /* nul termination */
+ out = malloc(olen);
+ if (out == NULL)
+ return NULL;
+
+ end = src + len;
+ in = src;
+ pos = out;
+ line_len = 0;
+ while (end - in >= 3) {
+ *pos++ = base64_table[in[0] >> 2];
+ *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+ *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+ *pos++ = base64_table[in[2] & 0x3f];
+ in += 3;
+ line_len += 4;
+ if (line_len >= 72) {
+ *pos++ = '\n';
+ line_len = 0;
+ }
+ }
+
+ if (end - in) {
+ *pos++ = base64_table[in[0] >> 2];
+ if (end - in == 1) {
+ *pos++ = base64_table[(in[0] & 0x03) << 4];
+ *pos++ = '=';
+ } else {
+ *pos++ = base64_table[((in[0] & 0x03) << 4) |
+ (in[1] >> 4)];
+ *pos++ = base64_table[(in[1] & 0x0f) << 2];
+ }
+ *pos++ = '=';
+ line_len += 4;
+ }
+
+ if (line_len)
+ *pos++ = '\n';
+
+ *pos = '\0';
+ if (out_len)
+ *out_len = pos - out;
+ return out;
+}
+
+
+/**
+ * base64_decode - Base64 decode
+ * @src: Data to be decoded
+ * @len: Length of the data to be decoded
+ * @out_len: Pointer to output length variable
+ * Returns: Allocated buffer of out_len bytes of decoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+ size_t *out_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;
+ dtable['='] = 0;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ if (dtable[src[i]] != 0x80)
+ count++;
+ }
+
+ if (count % 4)
+ return NULL;
+
+ olen = count / 4 * 3;
+ pos = out = malloc(count);
+ if (out == NULL)
+ return NULL;
+
+ count = 0;
+ for (i = 0; i < len; i++) {
+ tmp = dtable[src[i]];
+ if (tmp == 0x80)
+ continue;
+
+ in[count] = src[i];
+ block[count] = tmp;
+ count++;
+ if (count == 4) {
+ *pos++ = (block[0] << 2) | (block[1] >> 4);
+ *pos++ = (block[1] << 4) | (block[2] >> 2);
+ *pos++ = (block[2] << 6) | block[3];
+ count = 0;
+ }
+ }
+
+ if (pos > out) {
+ if (in[2] == '=')
+ pos -= 2;
+ else if (in[3] == '=')
+ pos--;
+ }
+
+ *out_len = pos - out;
+ return out;
+}
+
+
+#ifdef TEST_MAIN
+#include <stdio.h>
+
+int main(int argc, char *argv[])
+{
+ FILE *f;
+ size_t len, elen;
+ unsigned char *buf, *e;
+
+ if (argc != 4) {
+ printf("Usage: base64 <encode|decode> <in file> <out file>\n");
+ 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);
+ return -1;
+ }
+ fread(buf, 1, len, f);
+ fclose(f);
+
+ if (strcmp(argv[1], "encode") == 0)
+ e = base64_encode(buf, len, &elen);
+ else
+ e = base64_decode(buf, len, &elen);
+ if (e == NULL)
+ return -2;
+ f = fopen(argv[3], "w");
+ if (f == NULL)
+ return -3;
+ fwrite(e, 1, elen, f);
+ fclose(f);
+ free(e);
+
+ return 0;
+}
+#endif /* TEST_MAIN */
diff --git a/contrib/wpa_supplicant/base64.h b/contrib/wpa_supplicant/base64.h
new file mode 100644
index 0000000..7043328
--- /dev/null
+++ b/contrib/wpa_supplicant/base64.h
@@ -0,0 +1,23 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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 BASE64_H
+#define BASE64_h
+
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+ size_t *out_len);
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+ size_t *out_len);
+
+#endif /* BASE64_H */
diff --git a/contrib/wpa_supplicant/common.c b/contrib/wpa_supplicant/common.c
index 071ffe8..4b756d8 100644
--- a/contrib/wpa_supplicant/common.c
+++ b/contrib/wpa_supplicant/common.c
@@ -1,6 +1,5 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / common helper functions, etc.
+ * wpa_supplicant/hostapd / common helper functions, etc.
* Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -22,6 +21,10 @@
#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 "common.h"
@@ -34,12 +37,17 @@ int wpa_debug_timestamp = 0;
int hostapd_get_rand(u8 *buf, size_t len)
{
#ifdef CONFIG_NATIVE_WINDOWS
- int i;
- /* FIX: use more secure pseudo random number generator */
- for (i = 0; i < len; i++) {
- buf[i] = rand();
- }
- return 0;
+ 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;
@@ -93,6 +101,12 @@ static int hex2byte(const char *hex)
}
+/**
+ * hwaddr_aton - Convert ASCII string to MAC address
+ * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
int hwaddr_aton(const char *txt, u8 *addr)
{
int i;
@@ -115,6 +129,14 @@ int hwaddr_aton(const char *txt, u8 *addr)
}
+/**
+ * hexstr2bin - Convert ASCII hex string into binary data
+ * @hex: ASCII hex string (e.g., "01ab")
+ * @buf: Buffer for the binary data
+ * @len: Length of the text to convert in bytes (of buf); hex will be double
+ * this size
+ * Returns: 0 on success, -1 on failure (invalid hex string)
+ */
int hexstr2bin(const char *hex, u8 *buf, size_t len)
{
int i, a;
@@ -171,6 +193,15 @@ char * rel2abs_path(const char *rel_path)
}
+/**
+ * inc_byte_array - Increment arbitrary length byte array by one
+ * @counter: Pointer to byte array
+ * @len: Length of the counter in bytes
+ *
+ * This function increments the last byte of the counter by one and continues
+ * rolling over to more significant bytes if the byte was incremented from
+ * 0xff to 0x00.
+ */
void inc_byte_array(u8 *counter, size_t len)
{
int pos = len - 1;
@@ -201,7 +232,9 @@ void fprint_char(FILE *f, char c)
}
-static void wpa_debug_print_timestamp(void)
+#ifndef CONFIG_NO_STDOUT_DEBUG
+
+void wpa_debug_print_timestamp(void)
{
struct timeval tv;
char buf[16];
@@ -218,6 +251,17 @@ static void wpa_debug_print_timestamp(void)
}
+/**
+ * wpa_printf - conditional printf
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration.
+ *
+ * Note: New line '\n' is added to the end of the text when printing to stdout.
+ */
void wpa_printf(int level, char *fmt, ...)
{
va_list ap;
@@ -240,7 +284,9 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
return;
wpa_debug_print_timestamp();
printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
- if (show) {
+ if (buf == NULL) {
+ printf(" [NULL]");
+ } else if (show) {
for (i = 0; i < len; i++)
printf(" %02x", buf[i]);
} else {
@@ -276,6 +322,11 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
title, (unsigned long) len);
return;
}
+ if (buf == NULL) {
+ printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
+ title, (unsigned long) len);
+ return;
+ }
printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
while (len) {
llen = len > line_len ? line_len : len;
@@ -312,6 +363,8 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
#ifdef CONFIG_NATIVE_WINDOWS
diff --git a/contrib/wpa_supplicant/common.h b/contrib/wpa_supplicant/common.h
index 0f154e9..4bece7f 100644
--- a/contrib/wpa_supplicant/common.h
+++ b/contrib/wpa_supplicant/common.h
@@ -1,11 +1,26 @@
+/*
+ * wpa_supplicant/hostapd / common helper functions, etc.
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 COMMON_H
#define COMMON_H
#ifdef __linux__
#include <endian.h>
#include <byteswap.h>
-#endif
-#ifdef __FreeBSD__
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__)
#include <sys/types.h>
#include <sys/endian.h>
#define __BYTE_ORDER _BYTE_ORDER
@@ -14,10 +29,9 @@
#define bswap_16 bswap16
#define bswap_32 bswap32
#define bswap_64 bswap64
-#endif
+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) */
#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock.h>
#include <winsock2.h>
static inline int daemon(int nochdir, int noclose)
@@ -54,6 +68,18 @@ struct timezone {
int gettimeofday(struct timeval *tv, struct timezone *tz);
+static inline long int random(void)
+{
+ return rand();
+}
+
+typedef int gid_t;
+typedef int socklen_t;
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0 /* not supported */
+#endif
+
#endif /* CONFIG_NATIVE_WINDOWS */
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
@@ -104,6 +130,21 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#endif /* __CYGWIN__ */
+/* Macros for handling unaligned 16-bit variables */
+#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
+#define WPA_PUT_BE16(a, val) \
+ do { \
+ (a)[0] = ((u16) (val)) >> 8; \
+ (a)[1] = ((u16) (val)) & 0xff; \
+ } while (0)
+
+#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
+#define WPA_PUT_LE16(a, val) \
+ do { \
+ (a)[1] = ((u16) (val)) >> 8; \
+ (a)[0] = ((u16) (val)) & 0xff; \
+ } while (0)
+
#ifndef ETH_ALEN
#define ETH_ALEN 6
@@ -134,6 +175,26 @@ void fprint_char(FILE *f, char c);
enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
+#ifdef CONFIG_NO_STDOUT_DEBUG
+
+#define wpa_debug_print_timestamp() do { } while (0)
+#define wpa_printf(args...) do { } while (0)
+#define wpa_hexdump(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)
+
+#else /* CONFIG_NO_STDOUT_DEBUG */
+
+/**
+ * wpa_debug_printf_timestamp - Print timestamp for debug output
+ *
+ * This function prints a timestamp in <seconds from 1970>.<microsoconds>
+ * format if debug output has been configured to include timestamps in debug
+ * messages.
+ */
+void wpa_debug_print_timestamp(void);
+
/**
* wpa_printf - conditional printf
* @level: priority level (MSG_*) of the message
@@ -153,11 +214,11 @@ __attribute__ ((format (printf, 2, 3)));
* @level: priority level (MSG_*) of the message
* @title: title of for the message
* @buf: data buffer to be dumped
- * @len: length of the @buf
+ * @len: length of the buf
*
* This function is used to print conditional debugging and error messages. The
* output may be directed to stdout, stderr, and/or syslog based on
- * configuration. The contents of @buf is printed out has hex dump.
+ * configuration. The contents of buf is printed out has hex dump.
*/
void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
@@ -166,11 +227,11 @@ void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
* @level: priority level (MSG_*) of the message
* @title: title of for the message
* @buf: data buffer to be dumped
- * @len: length of the @buf
+ * @len: length of the buf
*
* This function is used to print conditional debugging and error messages. The
* output may be directed to stdout, stderr, and/or syslog based on
- * configuration. The contents of @buf is printed out has hex dump. This works
+ * configuration. The contents of buf is printed out has hex dump. This works
* like wpa_hexdump(), but by default, does not include secret keys (passwords,
* etc.) in debug output.
*/
@@ -181,11 +242,11 @@ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
* @level: priority level (MSG_*) of the message
* @title: title of for the message
* @buf: data buffer to be dumped
- * @len: length of the @buf
+ * @len: length of the buf
*
* This function is used to print conditional debugging and error messages. The
* output may be directed to stdout, stderr, and/or syslog based on
- * configuration. The contents of @buf is printed out has hex dump with both
+ * configuration. The contents of buf is printed out has hex dump with both
* the hex numbers and ASCII characters (for printable range) are shown. 16
* bytes per line will be shown.
*/
@@ -197,11 +258,11 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
* @level: priority level (MSG_*) of the message
* @title: title of for the message
* @buf: data buffer to be dumped
- * @len: length of the @buf
+ * @len: length of the buf
*
* This function is used to print conditional debugging and error messages. The
* output may be directed to stdout, stderr, and/or syslog based on
- * configuration. The contents of @buf is printed out has hex dump with both
+ * configuration. The contents of buf is printed out has hex dump with both
* the hex numbers and ASCII characters (for printable range) are shown. 16
* bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
* default, does not include secret keys (passwords, etc.) in debug output.
@@ -209,6 +270,9 @@ void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
size_t len);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
#ifdef EAPOL_TEST
#define WPA_ASSERT(a) \
do { \
diff --git a/contrib/wpa_supplicant/config.c b/contrib/wpa_supplicant/config.c
index 26307cf..2bba4ab 100644
--- a/contrib/wpa_supplicant/config.c
+++ b/contrib/wpa_supplicant/config.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant / Configuration file parser
+ * WPA Supplicant / Configuration parser and common functions
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -18,63 +18,40 @@
#include "common.h"
#include "wpa.h"
-#include "config.h"
#include "sha1.h"
#include "wpa_supplicant.h"
#include "eapol_sm.h"
#include "eap.h"
+#include "l2_packet.h"
#include "config.h"
+/*
+ * Structure for network configuration parsing. This data is used to implement
+ * a generic parser for each network block variable. The table of configuration
+ * variables is defined below in this file (ssid_fields[]).
+ */
struct parse_data {
+ /* Configuration variable name */
char *name;
- int (*parser)(struct parse_data *data, int line, const char *value);
- void *param1, *param2, *param3, *param4;
- struct wpa_ssid *ssid;
- int key_data;
-};
+ /* Parser function for this variable */
+ int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
+ int line, const char *value);
-static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line)
-{
- char *pos, *end, *sstart;
-
- while (fgets(s, size, stream)) {
- (*line)++;
- s[size - 1] = '\0';
- pos = s;
-
- while (*pos == ' ' || *pos == '\t' || *pos == '\r')
- pos++;
- if (*pos == '#' || *pos == '\n' || *pos == '\0' ||
- *pos == '\r')
- continue;
-
- /* Remove # comments unless they are within a double quoted
- * string. Remove trailing white space. */
- sstart = strchr(pos, '"');
- if (sstart)
- sstart = strchr(sstart + 1, '"');
- if (!sstart)
- sstart = pos;
- end = strchr(sstart, '#');
- if (end)
- *end-- = '\0';
- else
- end = pos + strlen(pos) - 1;
- while (end > pos &&
- (*end == '\n' || *end == ' ' || *end == '\t' ||
- *end == '\r')) {
- *end-- = '\0';
- }
- if (*pos == '\0')
- continue;
+ /* Writer function (i.e., to get the variable in text format from
+ * internal presentation). */
+ char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
- return pos;
- }
+ /* Variable specific parameters for the parser. */
+ void *param1, *param2, *param3, *param4;
- return NULL;
-}
+ /* 0 = this variable can be included in debug output
+ * 1 = this variable contains key/private data and it must not be
+ * included in debug output unless explicitly requested
+ */
+ int key_data;
+};
static char * wpa_config_parse_string(const char *value, size_t *len)
@@ -90,7 +67,7 @@ static char * wpa_config_parse_string(const char *value, size_t *len)
return strdup(value);
} else {
u8 *str;
- int hlen = strlen(value);
+ size_t hlen = strlen(value);
if (hlen % 1)
return NULL;
*len = hlen / 2;
@@ -106,14 +83,15 @@ static char * wpa_config_parse_string(const char *value, size_t *len)
}
-static int wpa_config_parse_str(struct parse_data *data,
+static int wpa_config_parse_str(const struct parse_data *data,
+ struct wpa_ssid *ssid,
int line, const char *value)
{
size_t res_len, *dst_len;
char **dst;
- dst = (char **) (((u8 *) data->ssid) + (long) data->param1);
- dst_len = (size_t *) (((u8 *) data->ssid) + (long) data->param2);
+ 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);
@@ -155,12 +133,91 @@ static int wpa_config_parse_str(struct parse_data *data,
}
-static int wpa_config_parse_int(struct parse_data *data,
+static int is_hex(const u8 *data, size_t len)
+{
+ int i;
+
+ for (i = 0; i < len; i++) {
+ if (data[i] < 32 || data[i] >= 127)
+ return 1;
+ }
+ return 0;
+}
+
+
+static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
+{
+ int i;
+ char *buf, *pos, *end;
+
+ pos = buf = 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, "\"");
+
+ return buf;
+}
+
+
+static char * wpa_config_write_string_hex(const u8 *value, size_t len)
+{
+ int i;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(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]);
+
+ return buf;
+}
+
+
+static char * wpa_config_write_string(const u8 *value, size_t len)
+{
+ if (value == NULL)
+ return NULL;
+
+ if (is_hex(value, len))
+ return wpa_config_write_string_hex(value, len);
+ else
+ return wpa_config_write_string_ascii(value, len);
+}
+
+
+static char * wpa_config_write_str(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ size_t len;
+ char **src;
+
+ src = (char **) (((u8 *) ssid) + (long) data->param1);
+ if (*src == NULL)
+ return NULL;
+
+ if (data->param2)
+ len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
+ else
+ len = strlen(*src);
+
+ return wpa_config_write_string((const u8 *) *src, len);
+}
+
+
+static int wpa_config_parse_int(const struct parse_data *data,
+ struct wpa_ssid *ssid,
int line, const char *value)
{
int *dst;
- dst = (int *) (((u8 *) data->ssid) + (long) data->param1);
+ dst = (int *) (((u8 *) ssid) + (long) data->param1);
*dst = atoi(value);
wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
@@ -184,26 +241,60 @@ static int wpa_config_parse_int(struct parse_data *data,
}
-static int wpa_config_parse_bssid(struct parse_data *data, int line,
+static char * wpa_config_write_int(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int *src;
+ char *value;
+
+ src = (int *) (((u8 *) ssid) + (long) data->param1);
+
+ value = malloc(20);
+ if (value == NULL)
+ return NULL;
+ snprintf(value, 20, "%d", *src);
+ return value;
+}
+
+
+static int wpa_config_parse_bssid(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- if (hwaddr_aton(value, data->ssid->bssid)) {
+ if (hwaddr_aton(value, ssid->bssid)) {
wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
line, value);
return -1;
}
- data->ssid->bssid_set = 1;
- wpa_hexdump(MSG_MSGDUMP, "BSSID", data->ssid->bssid, ETH_ALEN);
+ ssid->bssid_set = 1;
+ wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
return 0;
}
-static int wpa_config_parse_psk(struct parse_data *data, int line,
+static char * wpa_config_write_bssid(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (!ssid->bssid_set)
+ return NULL;
+
+ value = malloc(20);
+ if (value == NULL)
+ return NULL;
+ snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
+ return value;
+}
+
+
+static int wpa_config_parse_psk(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
if (*value == '"') {
char *pos;
- int len;
+ size_t len;
value++;
pos = strrchr(value, '"');
@@ -212,29 +303,45 @@ static int wpa_config_parse_psk(struct parse_data *data, int line,
len = strlen(value);
if (len < 8 || len > 63) {
wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
- "length %d (expected: 8..63) '%s'.",
- line, len, value);
+ "length %lu (expected: 8..63) '%s'.",
+ line, (unsigned long) len, value);
return -1;
}
wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
(u8 *) value, len);
- data->ssid->passphrase = strdup(value);
- return data->ssid->passphrase == NULL ? -1 : 0;
+ ssid->passphrase = strdup(value);
+ return ssid->passphrase == NULL ? -1 : 0;
}
- if (hexstr2bin(value, data->ssid->psk, PMK_LEN) ||
+ if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
value[PMK_LEN * 2] != '\0') {
wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
line, value);
return -1;
}
- data->ssid->psk_set = 1;
- wpa_hexdump_key(MSG_MSGDUMP, "PSK", data->ssid->psk, PMK_LEN);
+ ssid->psk_set = 1;
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
return 0;
}
-static int wpa_config_parse_proto(struct parse_data *data, int line,
+static char * wpa_config_write_psk(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ if (ssid->passphrase)
+ return wpa_config_write_string_ascii(
+ (const u8 *) ssid->passphrase,
+ strlen(ssid->passphrase));
+
+ if (ssid->psk_set)
+ return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
+
+ return NULL;
+}
+
+
+static int wpa_config_parse_proto(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val = 0, last, errors = 0;
@@ -279,12 +386,39 @@ static int wpa_config_parse_proto(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
- data->ssid->proto = val;
+ ssid->proto = val;
return errors ? -1 : 0;
}
-static int wpa_config_parse_key_mgmt(struct parse_data *data, int line,
+static char * wpa_config_write_proto(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(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 ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->proto & WPA_PROTO_RSN) {
+ pos += snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
+ first = 0;
+ }
+
+ return buf;
+}
+
+
+static int wpa_config_parse_key_mgmt(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val = 0, last, errors = 0;
@@ -334,11 +468,54 @@ static int wpa_config_parse_key_mgmt(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
- data->ssid->key_mgmt = val;
+ ssid->key_mgmt = val;
return errors ? -1 : 0;
}
+static char * wpa_config_write_key_mgmt(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(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;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+ pos += snprintf(pos, end - pos, "%sWPA-EAP", first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ pos += snprintf(pos, end - pos, "%sIEEE8021X",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
+ pos += snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
+ pos += snprintf(pos, end - pos, "%sWPA-NONE",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ return buf;
+}
+
+
static int wpa_config_parse_cipher(int line, const char *value)
{
int val = 0, last;
@@ -391,7 +568,48 @@ static int wpa_config_parse_cipher(int line, const char *value)
}
-static int wpa_config_parse_pairwise(struct parse_data *data, int line,
+static char * wpa_config_write_cipher(int cipher)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(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;
+ }
+
+ if (cipher & WPA_CIPHER_TKIP) {
+ pos += snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
+ first = 0;
+ }
+
+ if (cipher & WPA_CIPHER_WEP104) {
+ pos += snprintf(pos, end - pos, "%sWEP104", first ? "" : " ");
+ first = 0;
+ }
+
+ if (cipher & WPA_CIPHER_WEP40) {
+ pos += snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
+ first = 0;
+ }
+
+ if (cipher & WPA_CIPHER_NONE) {
+ pos += snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
+ first = 0;
+ }
+
+ return buf;
+}
+
+
+static int wpa_config_parse_pairwise(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val;
@@ -405,12 +623,20 @@ static int wpa_config_parse_pairwise(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
- data->ssid->pairwise_cipher = val;
+ ssid->pairwise_cipher = val;
return 0;
}
-static int wpa_config_parse_group(struct parse_data *data, int line,
+static char * wpa_config_write_pairwise(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_cipher(ssid->pairwise_cipher);
+}
+
+
+static int wpa_config_parse_group(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val;
@@ -425,12 +651,20 @@ static int wpa_config_parse_group(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
- data->ssid->group_cipher = val;
+ ssid->group_cipher = val;
return 0;
}
-static int wpa_config_parse_auth_alg(struct parse_data *data, int line,
+static char * wpa_config_write_group(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_cipher(ssid->group_cipher);
+}
+
+
+static int wpa_config_parse_auth_alg(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int val = 0, last, errors = 0;
@@ -476,12 +710,44 @@ static int wpa_config_parse_auth_alg(struct parse_data *data, int line,
}
wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
- data->ssid->auth_alg = val;
+ ssid->auth_alg = val;
return errors ? -1 : 0;
}
-static int wpa_config_parse_eap(struct parse_data *data, int line,
+static char * wpa_config_write_auth_alg(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+
+ pos = buf = malloc(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;
+ }
+
+ if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
+ pos += snprintf(pos, end - pos, "%sSHARED", first ? "" : " ");
+ first = 0;
+ }
+
+ if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
+ pos += snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
+ first = 0;
+ }
+
+ return buf;
+}
+
+
+static int wpa_config_parse_eap(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
int last, errors = 0;
@@ -520,9 +786,9 @@ static int wpa_config_parse_eap(struct parse_data *data, int line,
"See README for more information.");
errors++;
} else if (methods[num_methods] == EAP_TYPE_LEAP)
- data->ssid->leap++;
+ ssid->leap++;
else
- data->ssid->non_leap++;
+ ssid->non_leap++;
num_methods++;
if (last)
break;
@@ -540,11 +806,41 @@ static int wpa_config_parse_eap(struct parse_data *data, int line,
num_methods++;
wpa_hexdump(MSG_MSGDUMP, "eap methods", methods, num_methods);
- data->ssid->eap_methods = methods;
+ ssid->eap_methods = methods;
return errors ? -1 : 0;
}
+static char * wpa_config_write_eap(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ int first = 1;
+ char *buf, *pos, *end;
+ const u8 *eap_methods = ssid->eap_methods;
+ const char *name;
+
+ if (eap_methods == NULL)
+ return NULL;
+
+ pos = buf = malloc(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++;
+ }
+
+ return buf;
+}
+
+
static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
const char *value, int idx)
{
@@ -570,54 +866,140 @@ static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
}
-static int wpa_config_parse_wep_key0(struct parse_data *data, int line,
+static int wpa_config_parse_wep_key0(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- return wpa_config_parse_wep_key(data->ssid->wep_key[0],
- &data->ssid->wep_key_len[0], line,
+ return wpa_config_parse_wep_key(ssid->wep_key[0],
+ &ssid->wep_key_len[0], line,
value, 0);
}
-static int wpa_config_parse_wep_key1(struct parse_data *data, int line,
+static int wpa_config_parse_wep_key1(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- return wpa_config_parse_wep_key(data->ssid->wep_key[1],
- &data->ssid->wep_key_len[1], line,
+ return wpa_config_parse_wep_key(ssid->wep_key[1],
+ &ssid->wep_key_len[1], line,
value, 1);
}
-static int wpa_config_parse_wep_key2(struct parse_data *data, int line,
+static int wpa_config_parse_wep_key2(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- return wpa_config_parse_wep_key(data->ssid->wep_key[2],
- &data->ssid->wep_key_len[2], line,
+ return wpa_config_parse_wep_key(ssid->wep_key[2],
+ &ssid->wep_key_len[2], line,
value, 2);
}
-static int wpa_config_parse_wep_key3(struct parse_data *data, int line,
+static int wpa_config_parse_wep_key3(const struct parse_data *data,
+ struct wpa_ssid *ssid, int line,
const char *value)
{
- return wpa_config_parse_wep_key(data->ssid->wep_key[3],
- &data->ssid->wep_key_len[3], line,
+ return wpa_config_parse_wep_key(ssid->wep_key[3],
+ &ssid->wep_key_len[3], line,
value, 3);
}
+static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
+{
+ if (ssid->wep_key_len[idx] == 0)
+ return NULL;
+ return wpa_config_write_string(ssid->wep_key[idx],
+ ssid->wep_key_len[idx]);
+}
+
+
+static char * wpa_config_write_wep_key0(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_wep_key(ssid, 0);
+}
+
+
+static char * wpa_config_write_wep_key1(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_wep_key(ssid, 1);
+}
+
+
+static char * wpa_config_write_wep_key2(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_wep_key(ssid, 2);
+}
+
+
+static char * wpa_config_write_wep_key3(const struct parse_data *data,
+ struct wpa_ssid *ssid)
+{
+ return wpa_config_write_wep_key(ssid, 3);
+}
+
+
+/* Helper macros for network block parser */
+
+/* OFFSET: Get offset of a variable within the wpa_ssid structure */
#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
-#define STR(f) .name = #f, .parser = wpa_config_parse_str, .param1 = OFFSET(f)
+
+/* 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)
+
+/* 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)
+
+/* 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)
+
+
+/* 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
+
+/* INT: Define an integer variable with allowed value range */
#define INT_RANGE(f, min, max) INT(f), .param3 = (void *) (min), \
.param4 = (void *) (max)
-#define FUNC(f) .name = #f, .parser = wpa_config_parse_ ## f
-static struct parse_data ssid_fields[] = {
+/* 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
+
+/*
+ * 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.
+ *
+ * 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
+ * into .name and for STR and INT types, the offset of the target buffer within
+ * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
+ * offset to the field containing the length of the configuration variable.
+ * .param3 and .param4 can be used to mark the allowed range (length for STR
+ * and value for INT).
+ *
+ * For each configuration line in wpa_supplicant.conf, the parser goes through
+ * this table and select the entry that matches with the field name. The parser
+ * 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.
+ */
+static const struct parse_data ssid_fields[] = {
{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
{ INT_RANGE(scan_ssid, 0, 1) },
{ FUNC(bssid) },
@@ -632,24 +1014,30 @@ static struct parse_data ssid_fields[] = {
{ STR_LEN(anonymous_identity) },
{ STR_RANGE(eappsk, EAP_PSK_LEN, EAP_PSK_LEN), .key_data = 1 },
{ STR_LEN(nai) },
- { STR_LEN(server_nai) },
{ STR_LEN(password), .key_data = 1 },
{ STR(ca_cert) },
+ { STR(ca_path) },
{ STR(client_cert) },
{ STR(private_key) },
{ STR(private_key_passwd), .key_data = 1 },
{ 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), .key_data = 1 },
{ STR(dh_file2) },
{ STR(subject_match2) },
+ { STR(altsubject_match2) },
{ STR(phase1) },
{ STR(phase2) },
{ STR(pcsc) },
{ STR(pin), .key_data = 1 },
+ { STR(engine_id) },
+ { STR(key_id) },
+ { INT(engine) },
{ INT(eapol_flags) },
{ FUNC(wep_key0), .key_data = 1 },
{ FUNC(wep_key1), .key_data = 1 },
@@ -660,6 +1048,8 @@ static struct parse_data ssid_fields[] = {
{ INT(eap_workaround) },
{ STR(pac_file) },
{ INT_RANGE(mode, 0, 1) },
+ { INT_RANGE(proactive_key_caching, 0, 1) },
+ { INT_RANGE(disabled, 0, 1) },
};
#undef OFFSET
@@ -672,119 +1062,18 @@ static struct parse_data ssid_fields[] = {
#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
-static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
-{
- struct wpa_ssid *ssid;
- int errors = 0, i, end = 0;
- char buf[256], *pos, *pos2;
-
- wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
- *line);
- ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
- if (ssid == NULL)
- return NULL;
- memset(ssid, 0, sizeof(*ssid));
- ssid->id = id;
-
- ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
- ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
- ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
- WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
- ssid->key_mgmt = WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X;
- ssid->eapol_flags = EAPOL_FLAG_REQUIRE_KEY_UNICAST |
- EAPOL_FLAG_REQUIRE_KEY_BROADCAST;
- ssid->eap_workaround = (unsigned int) -1;
-
- while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
- if (strcmp(pos, "}") == 0) {
- end = 1;
- break;
- }
-
- pos2 = strchr(pos, '=');
- if (pos2 == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
- "'%s'.", *line, pos);
- errors++;
- continue;
- }
-
- *pos2++ = '\0';
- if (*pos2 == '"') {
- if (strchr(pos2 + 1, '"') == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: invalid "
- "quotation '%s'.", *line, pos2);
- errors++;
- continue;
- }
- }
-
- for (i = 0; i < NUM_SSID_FIELDS; i++) {
- struct parse_data *field = &ssid_fields[i];
- if (strcmp(pos, field->name) != 0)
- continue;
-
- field->ssid = ssid;
- if (field->parser(field, *line, pos2)) {
- wpa_printf(MSG_ERROR, "Line %d: failed to "
- "parse %s '%s'.", *line, pos, pos2);
- errors++;
- }
- break;
- }
- if (i == NUM_SSID_FIELDS) {
- wpa_printf(MSG_ERROR, "Line %d: unknown network field "
- "'%s'.", *line, pos);
- errors++;
- }
- }
-
- if (!end) {
- wpa_printf(MSG_ERROR, "Line %d: network block was not "
- "terminated properly.", *line);
- errors++;
- }
-
- if (ssid->passphrase) {
- if (ssid->psk_set) {
- wpa_printf(MSG_ERROR, "Line %d: both PSK and "
- "passphrase configured.", *line);
- errors++;
- }
- pbkdf2_sha1(ssid->passphrase,
- (char *) ssid->ssid, ssid->ssid_len, 4096,
- ssid->psk, PMK_LEN);
- wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
- ssid->psk, PMK_LEN);
- ssid->psk_set = 1;
- }
-
- 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;
- }
-
- if (errors) {
- free(ssid);
- ssid = NULL;
- }
-
- return ssid;
-}
-
-
-static int wpa_config_add_prio_network(struct wpa_config *config,
- struct wpa_ssid *ssid)
+/**
+ * wpa_config_add_prio_network - Add a network to priority lists
+ * @config: Configuration data from wpa_config_read()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to add a network block to the priority list of
+ * networks. This must be called for each network when reading in the full
+ * configuration. In addition, this can be used indirectly when updating
+ * priorities by calling wpa_config_update_prio_list().
+ */
+int wpa_config_add_prio_network(struct wpa_config *config,
+ struct wpa_ssid *ssid)
{
int prio;
struct wpa_ssid *prev, **nlist;
@@ -821,181 +1110,125 @@ static int wpa_config_add_prio_network(struct wpa_config *config,
}
-struct wpa_config * wpa_config_read(const char *config_file)
+/**
+ * wpa_config_update_prio_list - Update network priority list
+ * @config: Configuration data from wpa_config_read()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to update the priority list of networks in the
+ * configuration when a network is being added or removed. This is also called
+ * if a priority for a network is changed.
+ */
+static int wpa_config_update_prio_list(struct wpa_config *config)
{
- FILE *f;
- char buf[256], *pos;
- int errors = 0, line = 0;
- struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
- struct wpa_config *config;
- int id = 0, prio;
-
- config = malloc(sizeof(*config));
- if (config == NULL)
- return NULL;
- memset(config, 0, sizeof(*config));
- config->eapol_version = 1;
- config->ap_scan = 1;
- config->fast_reauth = 1;
- wpa_printf(MSG_DEBUG, "Reading configuration file '%s'",
- config_file);
- f = fopen(config_file, "r");
- if (f == NULL) {
- free(config);
- return NULL;
- }
+ struct wpa_ssid *ssid;
+ int ret = 0;
- while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) {
- if (strcmp(pos, "network={") == 0) {
- ssid = wpa_config_read_network(f, &line, id++);
- if (ssid == NULL) {
- wpa_printf(MSG_ERROR, "Line %d: failed to "
- "parse network block.", line);
- 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, "Line %d: failed to add "
- "network block to priority list.",
- line);
- errors++;
- continue;
- }
-#ifdef CONFIG_CTRL_IFACE
- } else if (strncmp(pos, "ctrl_interface=", 15) == 0) {
- free(config->ctrl_interface);
- config->ctrl_interface = 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;
- }
+ free(config->pssid);
+ config->pssid = NULL;
+ config->num_prio = 0;
- /* 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;
- }
- wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
- (int) config->ctrl_interface_gid);
-#endif /* CONFIG_CTRL_IFACE_UDP */
-#endif /* CONFIG_CTRL_IFACE */
- } else if (strncmp(pos, "eapol_version=", 14) == 0) {
- config->eapol_version = atoi(pos + 14);
- if (config->eapol_version < 1 ||
- config->eapol_version > 2) {
- wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL "
- "version (%d): '%s'.",
- line, config->eapol_version, pos);
- errors++;
- continue;
- }
- wpa_printf(MSG_DEBUG, "eapol_version=%d",
- config->eapol_version);
- } else if (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) {
- config->fast_reauth = atoi(pos + 12);
- wpa_printf(MSG_DEBUG, "fast_reauth=%d",
- config->fast_reauth);
- } else {
- wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
- "line '%s'.", line, pos);
- errors++;
- continue;
- }
+ ssid = config->ssid;
+ while (ssid) {
+ ssid->pnext = NULL;
+ if (wpa_config_add_prio_network(config, ssid) < 0)
+ ret = -1;
+ ssid = ssid->next;
}
- fclose(f);
+ return ret;
+}
- 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;
- }
- }
- if (errors) {
- wpa_config_free(config);
- config = NULL;
- head = NULL;
- }
- return 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
+ * 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);
}
+/**
+ * wpa_config_free - Free configuration data
+ * @config: Configuration data from wpa_config_read()
+ *
+ * This function frees all resources allocated for the configuration data by
+ * wpa_config_read().
+ */
void wpa_config_free(struct wpa_config *config)
{
+ struct wpa_config_blob *blob, *prevblob;
struct wpa_ssid *ssid, *prev = NULL;
ssid = config->ssid;
while (ssid) {
prev = ssid;
ssid = ssid->next;
- free(prev->ssid);
- free(prev->passphrase);
- free(prev->eap_methods);
- free(prev->identity);
- free(prev->anonymous_identity);
- free(prev->eappsk);
- free(prev->nai);
- free(prev->server_nai);
- free(prev->password);
- free(prev->ca_cert);
- free(prev->client_cert);
- free(prev->private_key);
- free(prev->private_key_passwd);
- free(prev->dh_file);
- free(prev->subject_match);
- free(prev->ca_cert2);
- free(prev->client_cert2);
- free(prev->private_key2);
- free(prev->private_key2_passwd);
- free(prev->dh_file2);
- free(prev->subject_match2);
- free(prev->phase1);
- free(prev->phase2);
- free(prev->pcsc);
- free(prev->pin);
- free(prev->otp);
- free(prev->pending_req_otp);
- free(prev->pac_file);
- free(prev);
+ wpa_config_free_ssid(prev);
}
+
+ blob = config->blobs;
+ prevblob = NULL;
+ while (blob) {
+ prevblob = blob;
+ blob = blob->next;
+ 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);
}
+/**
+ * wpa_config_allowed_eap_method - Check whether EAP method is allowed
+ * @ssid: Pointer to a configuration data
+ * @method: EAP type
+ * Returns: 1 = allowed EAP method, 0 = not allowed
+ */
int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method)
{
u8 *pos;
@@ -1013,39 +1246,306 @@ int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method)
}
-const char * wpa_cipher_txt(int cipher)
+/**
+ * wpa_config_get_network - Get configured network based on id
+ * @config: Configuration data from wpa_config_read()
+ * @id: Unique network id to search for
+ * Returns: Network configuration or %NULL if not found
+ */
+struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
{
- switch (cipher) {
- case WPA_CIPHER_NONE:
- return "NONE";
- case WPA_CIPHER_WEP40:
- return "WEP-40";
- case WPA_CIPHER_WEP104:
- return "WEP-104";
- case WPA_CIPHER_TKIP:
- return "TKIP";
- case WPA_CIPHER_CCMP:
- return "CCMP";
- default:
- return "UNKNOWN";
+ struct wpa_ssid *ssid;
+
+ ssid = config->ssid;
+ while (ssid) {
+ if (id == ssid->id)
+ break;
+ ssid = ssid->next;
}
+
+ return ssid;
}
-const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
+/**
+ * wpa_config_add_network - Add a new network with empty configuration
+ * @config: Configuration data from wpa_config_read()
+ * Returns: The new network configuration or %NULL if operation failed
+ */
+struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
{
- switch (key_mgmt) {
- case WPA_KEY_MGMT_IEEE8021X:
- return proto == WPA_PROTO_RSN ?
- "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
- case WPA_KEY_MGMT_PSK:
- return proto == WPA_PROTO_RSN ?
- "WPA2-PSK" : "WPA-PSK";
- case WPA_KEY_MGMT_NONE:
- return "NONE";
- case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
- return "IEEE 802.1X (no WPA)";
- default:
- return "UNKNOWN";
+ int id;
+ struct wpa_ssid *ssid, *last = NULL;
+
+ id = -1;
+ ssid = config->ssid;
+ while (ssid) {
+ if (ssid->id > id)
+ id = ssid->id;
+ last = ssid;
+ ssid = ssid->next;
}
+ id++;
+
+ ssid = malloc(sizeof(*ssid));
+ if (ssid == NULL)
+ return NULL;
+ memset(ssid, 0, sizeof(*ssid));
+ ssid->id = id;
+ if (last)
+ last->next = ssid;
+ else
+ config->ssid = ssid;
+
+ wpa_config_update_prio_list(config);
+
+ return ssid;
+}
+
+
+/**
+ * wpa_config_remove_network - Remove a configured network based on id
+ * @config: Configuration data from wpa_config_read()
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found
+ */
+int wpa_config_remove_network(struct wpa_config *config, int id)
+{
+ struct wpa_ssid *ssid, *prev = NULL;
+
+ ssid = config->ssid;
+ while (ssid) {
+ if (id == ssid->id)
+ break;
+ prev = ssid;
+ ssid = ssid->next;
+ }
+
+ if (ssid == NULL)
+ return -1;
+
+ if (prev)
+ prev->next = ssid->next;
+ else
+ config->ssid = ssid->next;
+
+ wpa_config_update_prio_list(config);
+ wpa_config_free_ssid(ssid);
+ return 0;
+}
+
+
+/**
+ * wpa_config_set_network_defaults - Set network default values
+ * @ssid: Pointer to a network configuration data
+ */
+void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
+{
+ ssid->proto = DEFAULT_PROTO;
+ ssid->pairwise_cipher = DEFAULT_PAIRWISE;
+ ssid->group_cipher = DEFAULT_GROUP;
+ ssid->key_mgmt = DEFAULT_KEY_MGMT;
+ ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
+ ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
+}
+
+
+/**
+ * wpa_config_set - Set a variable in network configuration
+ * @ssid: Pointer to a network configuration data
+ * @var: Variable name, e.g., "ssid"
+ * @value: Variable value
+ * @line: Line number in configuration file or 0 if not used
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to set network configuration variables based on
+ * both the configuration file and management interface input. The value
+ * parameter must be in the same format as the text-based configuration file is
+ * using. For example, strings are using double quotation marks.
+ */
+int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
+ int line)
+{
+ int i, 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)
+ continue;
+
+ if (field->parser(field, ssid, line, value)) {
+ if (line) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse %s '%s'.", line, var, value);
+ }
+ ret = -1;
+ }
+ break;
+ }
+ if (i == NUM_SSID_FIELDS) {
+ if (line) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown network field "
+ "'%s'.", line, var);
+ }
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_config_get - Get a variable in network configuration
+ * @ssid: Pointer to a 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 variables. 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(struct wpa_ssid *ssid, const char *var)
+{
+ int 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)
+ return field->writer(field, ssid);
+ }
+
+ return NULL;
+}
+
+
+/**
+ * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
+ * @ssid: Pointer to a network configuration data
+ *
+ * This function must be called to update WPA PSK when either SSID or the
+ * passphrase has changed for the network configuration.
+ */
+void wpa_config_update_psk(struct wpa_ssid *ssid)
+{
+ pbkdf2_sha1(ssid->passphrase,
+ (char *) ssid->ssid, ssid->ssid_len, 4096,
+ ssid->psk, PMK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+ ssid->psk, PMK_LEN);
+ ssid->psk_set = 1;
+}
+
+
+/**
+ * wpa_config_get_blob - Get a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
+ const char *name)
+{
+ struct wpa_config_blob *blob = config->blobs;
+
+ while (blob) {
+ if (strcmp(blob->name, name) == 0)
+ return blob;
+ blob = blob->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * wpa_config_set_blob - Set or add a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an existing
+ * blob.
+ */
+void wpa_config_set_blob(struct wpa_config *config,
+ struct wpa_config_blob *blob)
+{
+ wpa_config_remove_blob(config, blob->name);
+ blob->next = config->blobs;
+ config->blobs = blob;
+}
+
+
+/**
+ * wpa_config_free_blob - Free blob data
+ * @blob: Pointer to blob to be freed
+ */
+void wpa_config_free_blob(struct wpa_config_blob *blob)
+{
+ if (blob) {
+ free(blob->name);
+ free(blob->data);
+ free(blob);
+ }
+}
+
+
+/**
+ * wpa_config_remove_blob - Remove a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @name: Name of the blob to remove
+ * Returns: 0 if blob was removed or -1 if blob was not found
+ */
+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 (prev)
+ prev->next = pos->next;
+ else
+ config->blobs = pos->next;
+ wpa_config_free_blob(pos);
+ return 0;
+ }
+ prev = pos;
+ pos = pos->next;
+ }
+
+ return -1;
+}
+
+
+/**
+ * wpa_config_alloc_empty - Allocate an empty configuration
+ * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
+ * socket
+ * @driver_param: Driver parameters
+ * Returns: Pointer to allocated configuration data or %NULL on failure
+ */
+struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
+ const char *driver_param)
+{
+ struct wpa_config *config;
+
+ config = malloc(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);
+ if (driver_param)
+ config->driver_param = strdup(driver_param);
+
+ return config;
}
diff --git a/contrib/wpa_supplicant/config.h b/contrib/wpa_supplicant/config.h
index 13deb3e..bd479b6 100644
--- a/contrib/wpa_supplicant/config.h
+++ b/contrib/wpa_supplicant/config.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / Configuration file structures
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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_H
#define CONFIG_H
@@ -7,27 +21,297 @@
#endif /* CONFIG_CTRL_IFACE_UDP */
#endif /* CONFIG_CTRL_IFACE */
+#define DEFAULT_EAPOL_VERSION 1
+#define DEFAULT_AP_SCAN 1
+#define DEFAULT_FAST_REAUTH 1
+
#include "config_ssid.h"
+/**
+ * struct wpa_config_blob - Named configuration blob
+ *
+ * This data structure is used to provide storage for binary objects to store
+ * abstract information like certificates and private keys inlined with the
+ * configuration data.
+ */
+struct wpa_config_blob {
+ /**
+ * name - Blob name
+ */
+ char *name;
+
+ /**
+ * data - Pointer to binary data
+ */
+ u8 *data;
+
+ /**
+ * len - Length of binary data
+ */
+ size_t len;
+
+ /**
+ * next - Pointer to next blob in the configuration
+ */
+ struct wpa_config_blob *next;
+};
+
+
+/**
+ * struct wpa_config - wpa_supplicant configuration data
+ *
+ * This data structure is presents the per-interface (radio) configuration
+ * data. In many cases, there is only one struct wpa_config instance, but if
+ * more than one network interface is being controlled, one instance is used
+ * for each.
+ */
struct wpa_config {
- struct wpa_ssid *ssid; /* global network list */
- struct wpa_ssid **pssid; /* per priority network lists (in priority
- * order) */
- int num_prio; /* number of different priorities */
+ /**
+ * ssid - Head of the global network list
+ *
+ * This is the head for the list of all the configured networks.
+ */
+ struct wpa_ssid *ssid;
+
+ /**
+ * pssid - Per-priority network lists (in priority order)
+ */
+ struct wpa_ssid **pssid;
+
+ /**
+ * num_prio - Number of different priorities used in the pssid lists
+ *
+ * This indicates how many per-priority network lists are included in
+ * pssid.
+ */
+ int num_prio;
+
+ /**
+ * eapol_version - IEEE 802.1X/EAPOL version number
+ *
+ * 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 to 1 by default. This
+ * configuration value can be used to set it to the new version (2).
+ */
int eapol_version;
+
+ /**
+ * ap_scan - AP scanning/selection
+ *
+ * By default, wpa_supplicant requests driver to perform AP
+ * scanning and then uses the scan results to select a
+ * suitable AP. Another alternative is to allow the driver to
+ * take care of AP scanning and selection and use
+ * wpa_supplicant just to process EAPOL frames based on IEEE
+ * 802.11 association information from the driver.
+ *
+ * 1: wpa_supplicant initiates scanning and AP selection (default).
+ *
+ * 0: Driver takes care of scanning, AP selection, and IEEE 802.11
+ * association parameters (e.g., WPA IE generation); this mode can
+ * also be used with non-WPA drivers when using IEEE 802.1X mode;
+ * do not try to associate with APs (i.e., external program needs
+ * to control association). This mode must also be used when using
+ * wired Ethernet drivers.
+ *
+ * 2: like 0, but associate with APs using security policy and SSID
+ * (but not BSSID); this can be used, e.g., with ndiswrapper and NDIS
+ * drivers to enable operation with hidden SSIDs and optimized roaming;
+ * in this mode, the network blocks in the configuration are tried
+ * one by one until the driver reports successful association; each
+ * network block should have explicit security policy (i.e., only one
+ * option in the lists) for key_mgmt, pairwise, group, proto variables.
+ */
int ap_scan;
- char *ctrl_interface; /* directory for UNIX domain sockets */
+
+ /**
+ * ctrl_interface - Directory for UNIX domain sockets
+ *
+ * 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
+ *
+ * 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
+ * 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
+ * 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.
+ */
gid_t ctrl_interface_gid;
#endif /* CONFIG_CTRL_IFACE_UDP */
+ /**
+ * ctrl_interface_gid_set - Whether ctrl_interface_gid is used
+ *
+ * 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.
+ */
int ctrl_interface_gid_set;
#endif /* CONFIG_CTRL_IFACE */
+
+ /**
+ * fast_reauth - EAP fast re-authentication (session resumption)
+ *
+ * By default, fast re-authentication is enabled for all EAP methods
+ * that support it. This variable can be used to disable fast
+ * re-authentication (by setting fast_reauth=0). Normally, there is no
+ * need to disable fast re-authentication.
+ */
int fast_reauth;
+
+ /**
+ * opensc_engine_path - Path to the OpenSSL engine for opensc
+ *
+ * This is an OpenSSL specific configuration option for loading OpenSC
+ * engine (engine_opensc.so); if %NULL, this engine is not loaded.
+ */
+ char *opensc_engine_path;
+
+ /**
+ * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11
+ *
+ * This is an OpenSSL specific configuration option for loading PKCS#11
+ * engine (engine_pkcs11.so); if %NULL, this engine is not loaded.
+ */
+ char *pkcs11_engine_path;
+
+ /**
+ * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module
+ *
+ * This is an OpenSSL specific configuration option for configuring
+ * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this
+ * module is not loaded.
+ */
+ char *pkcs11_module_path;
+
+ /**
+ * driver_param - Driver interface parameters
+ *
+ * This text string is passed to the selected driver interface with the
+ * optional struct wpa_driver_ops::set_param() handler. This can be
+ * used to configure driver specific options without having to add new
+ * driver interface functionality.
+ */
+ char *driver_param;
+
+ /**
+ * dot11RSNAConfigPMKLifetime - Maximum lifetime of a PMK
+ *
+ * dot11 MIB variable for the maximum lifetime of a PMK in the PMK
+ * cache (unit: seconds).
+ */
+ unsigned int dot11RSNAConfigPMKLifetime;
+
+ /**
+ * dot11RSNAConfigPMKReauthThreshold - PMK re-authentication threshold
+ *
+ * dot11 MIB variable for the percentage of the PMK lifetime
+ * that should expire before an IEEE 802.1X reauthentication occurs.
+ */
+ unsigned int dot11RSNAConfigPMKReauthThreshold;
+
+ /**
+ * dot11RSNAConfigSATimeout - Security association timeout
+ *
+ * dot11 MIB variable for the maximum time a security association
+ * shall take to set up (unit: seconds).
+ */
+ unsigned int dot11RSNAConfigSATimeout;
+
+ /**
+ * update_config - Is wpa_supplicant allowed to update configuration
+ *
+ * This variable control whether wpa_supplicant is allow to re-write
+ * its configuration with wpa_config_write(). If this is zero,
+ * configuration data is only changed in memory and the external data
+ * is not overriden. If this is non-zero, wpa_supplicant will update
+ * the configuration data (e.g., a file) whenever configuration is
+ * changed. This update may replace the old configuration which can
+ * remove comments from it in case of a text file configuration.
+ */
+ int update_config;
+
+ /**
+ * blobs - Configuration blobs
+ */
+ struct wpa_config_blob *blobs;
};
-struct wpa_config * wpa_config_read(const char *config_file);
+/* Protypes for common functions from config.c */
+
void wpa_config_free(struct wpa_config *ssid);
+void wpa_config_free_ssid(struct wpa_ssid *ssid);
+struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id);
+struct wpa_ssid * wpa_config_add_network(struct wpa_config *config);
+int wpa_config_remove_network(struct wpa_config *config, int id);
+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);
+void wpa_config_update_psk(struct wpa_ssid *ssid);
+int wpa_config_add_prio_network(struct wpa_config *config,
+ struct wpa_ssid *ssid);
+
+const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
+ const char *name);
+void wpa_config_set_blob(struct wpa_config *config,
+ struct wpa_config_blob *blob);
+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);
+
+
+/* Prototypes for backend specific functions from the selected config_*.c */
+
+/**
+ * wpa_config_read - Read and parse configuration database
+ * @name: Name of the configuration (e.g., path and file name for the
+ * configuration file)
+ * Returns: Pointer to allocated configuration data or %NULL on failure
+ *
+ * This function reads configuration data, parses its contents, and allocates
+ * data structures needed for storing configuration information. The allocated
+ * data can be freed with wpa_config_free().
+ *
+ * Each configuration backend needs to implement this function.
+ */
+struct wpa_config * wpa_config_read(const char *name);
+
+/**
+ * wpa_config_write - Write or update configuration data
+ * @name: Name of the configuration (e.g., path and file name for the
+ * configuration file)
+ * @config: Configuration data from wpa_config_read()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function write all configuration data into an external database (e.g.,
+ * a text file) in a format that can be read with wpa_config_read(). This can
+ * be used to allow wpa_supplicant to update its configuration, e.g., when a
+ * new network is added or a password is changed.
+ *
+ * Each configuration backend needs to implement this function.
+ */
+int wpa_config_write(const char *name, struct wpa_config *config);
#endif /* CONFIG_H */
diff --git a/contrib/wpa_supplicant/config_file.c b/contrib/wpa_supplicant/config_file.c
new file mode 100644
index 0000000..b203893
--- /dev/null
+++ b/contrib/wpa_supplicant/config_file.c
@@ -0,0 +1,695 @@
+/*
+ * WPA Supplicant / Configuration backend: text file
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 text files. All the
+ * configuration information is stored in a text file that uses a format
+ * described in the sample configuration file, wpa_supplicant.conf.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.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)
+{
+ char *pos, *end, *sstart;
+
+ while (fgets(s, size, stream)) {
+ (*line)++;
+ s[size - 1] = '\0';
+ pos = s;
+
+ while (*pos == ' ' || *pos == '\t' || *pos == '\r')
+ pos++;
+ if (*pos == '#' || *pos == '\n' || *pos == '\0' ||
+ *pos == '\r')
+ continue;
+
+ /* Remove # comments unless they are within a double quoted
+ * string. Remove trailing white space. */
+ sstart = strchr(pos, '"');
+ if (sstart)
+ sstart = strrchr(sstart + 1, '"');
+ if (!sstart)
+ sstart = pos;
+ end = strchr(sstart, '#');
+ if (end)
+ *end-- = '\0';
+ else
+ end = pos + strlen(pos) - 1;
+ while (end > pos &&
+ (*end == '\n' || *end == ' ' || *end == '\t' ||
+ *end == '\r')) {
+ *end-- = '\0';
+ }
+ if (*pos == '\0')
+ continue;
+
+ return pos;
+ }
+
+ return NULL;
+}
+
+
+static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
+{
+ struct wpa_ssid *ssid;
+ int errors = 0, end = 0;
+ char buf[256], *pos, *pos2;
+
+ wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
+ *line);
+ ssid = (struct wpa_ssid *) malloc(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) {
+ end = 1;
+ break;
+ }
+
+ pos2 = strchr(pos, '=');
+ if (pos2 == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
+ "'%s'.", *line, pos);
+ errors++;
+ continue;
+ }
+
+ *pos2++ = '\0';
+ if (*pos2 == '"') {
+ if (strchr(pos2 + 1, '"') == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "quotation '%s'.", *line, pos2);
+ errors++;
+ continue;
+ }
+ }
+
+ if (wpa_config_set(ssid, pos, pos2, *line) < 0)
+ errors++;
+ }
+
+ if (!end) {
+ wpa_printf(MSG_ERROR, "Line %d: network block was not "
+ "terminated properly.", *line);
+ 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;
+ }
+
+ if (errors) {
+ free(ssid);
+ ssid = NULL;
+ }
+
+ return ssid;
+}
+
+
+static struct wpa_config_blob * wpa_config_read_blob(FILE *f, int *line,
+ const char *name)
+{
+ struct wpa_config_blob *blob;
+ char buf[256], *pos;
+ unsigned char *encoded = NULL, *nencoded;
+ int end = 0;
+ size_t encoded_len = 0, len;
+
+ 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) {
+ end = 1;
+ break;
+ }
+
+ len = strlen(pos);
+ nencoded = realloc(encoded, encoded_len + len);
+ if (nencoded == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: not enough memory for "
+ "blob", *line);
+ free(encoded);
+ return NULL;
+ }
+ encoded = nencoded;
+ 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);
+ return NULL;
+ }
+
+ blob = malloc(sizeof(*blob));
+ if (blob == NULL) {
+ free(encoded);
+ return NULL;
+ }
+ memset(blob, 0, sizeof(*blob));
+ blob->name = strdup(name);
+ blob->data = base64_decode(encoded, encoded_len, &blob->len);
+ free(encoded);
+
+ if (blob->name == NULL || blob->data == NULL) {
+ wpa_config_free_blob(blob);
+ return NULL;
+ }
+
+ return blob;
+}
+
+
+struct wpa_config * wpa_config_read(const char *name)
+{
+ FILE *f;
+ char buf[256], *pos;
+ int errors = 0, line = 0;
+ struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+ struct wpa_config *config;
+ int id = 0, prio;
+
+ config = wpa_config_alloc_empty(NULL, NULL);
+ if (config == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "Reading configuration file '%s'", name);
+ f = fopen(name, "r");
+ if (f == NULL) {
+ free(config);
+ return NULL;
+ }
+
+ while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) {
+ if (strcmp(pos, "network={") == 0) {
+ ssid = wpa_config_read_network(f, &line, id++);
+ if (ssid == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse network block.", line);
+ 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, "Line %d: failed to add "
+ "network block to priority list.",
+ line);
+ errors++;
+ continue;
+ }
+ } else if (strncmp(pos, "blob-base64-", 12) == 0) {
+ char *name = pos + 12, *name_end;
+ struct wpa_config_blob *blob;
+
+ name_end = strchr(name, '=');
+ if (name_end == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: no blob name "
+ "terminator", line);
+ errors++;
+ continue;
+ }
+ *name_end = '\0';
+
+ blob = wpa_config_read_blob(f, &line, name);
+ if (blob == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to read"
+ " blob %s", line, name);
+ 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);
+ 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 */
+#endif /* CONFIG_CTRL_IFACE */
+ } else if (strncmp(pos, "eapol_version=", 14) == 0) {
+ config->eapol_version = atoi(pos + 14);
+ if (config->eapol_version < 1 ||
+ config->eapol_version > 2) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL "
+ "version (%d): '%s'.",
+ line, config->eapol_version, pos);
+ errors++;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "eapol_version=%d",
+ config->eapol_version);
+ } else if (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) {
+ 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);
+ 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);
+ 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);
+ 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);
+ wpa_printf(MSG_DEBUG, "driver_param='%s'",
+ config->driver_param);
+ } else if (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) {
+ config->dot11RSNAConfigPMKReauthThreshold =
+ atoi(pos + 34);
+ wpa_printf(MSG_DEBUG,
+ "dot11RSNAConfigPMKReauthThreshold=%d",
+ config->dot11RSNAConfigPMKReauthThreshold);
+ } else if (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) {
+ config->update_config = atoi(pos + 14);
+ wpa_printf(MSG_DEBUG, "update_config=%d",
+ config->update_config);
+ } else {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
+ "line '%s'.", line, pos);
+ errors++;
+ continue;
+ }
+ }
+
+ 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;
+ }
+ }
+ if (errors) {
+ wpa_config_free(config);
+ config = NULL;
+ head = NULL;
+ }
+
+ return config;
+}
+
+
+static void write_str(FILE *f, const char *field, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, field);
+ if (value == NULL)
+ return;
+ fprintf(f, "\t%s=%s\n", field, value);
+ free(value);
+}
+
+
+static void write_int(FILE *f, const char *field, int value, int def)
+{
+ if (value == def)
+ return;
+ fprintf(f, "\t%s=%d\n", field, value);
+}
+
+
+static void write_bssid(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "bssid");
+ if (value == NULL)
+ return;
+ fprintf(f, "\tbssid=%s\n", value);
+ free(value);
+}
+
+
+static void write_psk(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "psk");
+ if (value == NULL)
+ return;
+ fprintf(f, "\tpsk=%s\n", value);
+ free(value);
+}
+
+
+static void write_proto(FILE *f, 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])
+ fprintf(f, "\tproto=%s\n", value);
+ free(value);
+}
+
+
+static void write_key_mgmt(FILE *f, 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])
+ fprintf(f, "\tkey_mgmt=%s\n", value);
+ free(value);
+}
+
+
+static void write_pairwise(FILE *f, 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])
+ fprintf(f, "\tpairwise=%s\n", value);
+ free(value);
+}
+
+
+static void write_group(FILE *f, 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])
+ fprintf(f, "\tgroup=%s\n", value);
+ free(value);
+}
+
+
+static void write_auth_alg(FILE *f, 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])
+ fprintf(f, "\tauth_alg=%s\n", value);
+ free(value);
+}
+
+
+static void write_eap(FILE *f, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ value = wpa_config_get(ssid, "eap");
+ if (value == NULL)
+ return;
+
+ if (value[0])
+ fprintf(f, "\teap=%s\n", value);
+ free(value);
+}
+
+
+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);
+ value = wpa_config_get(ssid, field);
+ if (value) {
+ fprintf(f, "\t%s=%s\n", field, value);
+ free(value);
+ }
+}
+
+
+static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
+{
+ int i;
+
+#define STR(t) write_str(f, #t, ssid)
+#define INT(t) write_int(f, #t, ssid->t, 0)
+#define INT_DEF(t, def) write_int(f, #t, ssid->t, def)
+
+ STR(ssid);
+ INT(scan_ssid);
+ write_bssid(f, ssid);
+ write_psk(f, ssid);
+ write_proto(f, ssid);
+ write_key_mgmt(f, ssid);
+ write_pairwise(f, ssid);
+ write_group(f, ssid);
+ write_auth_alg(f, ssid);
+ write_eap(f, ssid);
+ STR(identity);
+ STR(anonymous_identity);
+ STR(eappsk);
+ STR(nai);
+ STR(password);
+ STR(ca_cert);
+ STR(client_cert);
+ STR(private_key);
+ STR(private_key_passwd);
+ STR(dh_file);
+ STR(subject_match);
+ STR(altsubject_match);
+ STR(ca_cert2);
+ 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);
+ for (i = 0; i < 4; i++)
+ write_wep_key(f, i, ssid);
+ INT(wep_tx_keyidx);
+ INT(priority);
+ INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
+ STR(pac_file);
+ INT(mode);
+ INT(proactive_key_caching);
+ INT(disabled);
+
+#undef STR
+#undef INT
+#undef INT_DEF
+}
+
+
+static int wpa_config_write_blob(FILE *f, struct wpa_config_blob *blob)
+{
+ unsigned char *encoded;
+
+ encoded = base64_encode(blob->data, blob->len, NULL);
+ if (encoded == NULL)
+ return -1;
+
+ fprintf(f, "\nblob-base64-%s={\n%s}\n", blob->name, encoded);
+ free(encoded);
+ return 0;
+}
+
+
+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;
+ }
+
+#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 */
+#endif /* CONFIG_CTRL_IFACE */
+ if (config->eapol_version != DEFAULT_EAPOL_VERSION)
+ fprintf(f, "eapol_version=%d\n", config->eapol_version);
+ if (config->ap_scan != DEFAULT_AP_SCAN)
+ fprintf(f, "ap_scan=%d\n", config->ap_scan);
+ if (config->fast_reauth != DEFAULT_FAST_REAUTH)
+ fprintf(f, "fast_reauth=%d\n", config->fast_reauth);
+ if (config->opensc_engine_path)
+ fprintf(f, "opensc_engine_path=%s\n",
+ config->opensc_engine_path);
+ if (config->pkcs11_engine_path)
+ fprintf(f, "pkcs11_engine_path=%s\n",
+ config->pkcs11_engine_path);
+ if (config->pkcs11_module_path)
+ fprintf(f, "pkcs11_module_path=%s\n",
+ config->pkcs11_module_path);
+ if (config->driver_param)
+ fprintf(f, "driver_param=%s\n", config->driver_param);
+ if (config->dot11RSNAConfigPMKLifetime)
+ fprintf(f, "dot11RSNAConfigPMKLifetime=%d\n",
+ config->dot11RSNAConfigPMKLifetime);
+ if (config->dot11RSNAConfigPMKReauthThreshold)
+ fprintf(f, "dot11RSNAConfigPMKReauthThreshold=%d\n",
+ config->dot11RSNAConfigPMKReauthThreshold);
+ if (config->dot11RSNAConfigSATimeout)
+ fprintf(f, "dot11RSNAConfigSATimeout=%d\n",
+ config->dot11RSNAConfigSATimeout);
+ if (config->update_config)
+ fprintf(f, "update_config=%d\n", config->update_config);
+
+ for (ssid = config->ssid; ssid; ssid = ssid->next) {
+ fprintf(f, "\nnetwork={\n");
+ wpa_config_write_network(f, ssid);
+ fprintf(f, "}\n");
+ }
+
+ for (blob = config->blobs; blob; blob = blob->next) {
+ ret = wpa_config_write_blob(f, blob);
+ if (ret)
+ break;
+ }
+
+ fclose(f);
+
+ wpa_printf(MSG_DEBUG, "Configuration file '%s' written %ssuccessfully",
+ name, ret ? "un" : "");
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/config_ssid.h b/contrib/wpa_supplicant/config_ssid.h
index 44bc989..14dc0f4 100644
--- a/contrib/wpa_supplicant/config_ssid.h
+++ b/contrib/wpa_supplicant/config_ssid.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / Network configuration structures
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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_SSID_H
#define CONFIG_SSID_H
@@ -24,86 +38,731 @@
#define PMK_LEN 32
#define EAP_PSK_LEN 16
+
+#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
+#define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \
+ EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
+#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
+#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
+#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
+#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \
+ WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
+
+/**
+ * struct wpa_ssid - Network configuration data
+ *
+ * This structure includes all the configuration variables for a network. This
+ * data is included in the per-interface configuration data as an element of
+ * the network list, struct wpa_config::ssid. Each network block in the
+ * configuration is mapped to a struct wpa_ssid instance.
+ */
struct wpa_ssid {
- struct wpa_ssid *next; /* next network in global list */
- struct wpa_ssid *pnext; /* next network in per-priority list */
- int id; /* unique id for ctrl_iface */
+ /**
+ * next - Next network in global list
+ *
+ * This pointer can be used to iterate over all networks. The head of
+ * this list is stored in the ssid field of struct wpa_config.
+ */
+ struct wpa_ssid *next;
+
+ /**
+ * pnext - Next network in per-priority list
+ *
+ * This pointer can be used to iterate over all networks in the same
+ * priority class. The heads of these list are stored in the pssid
+ * fields of struct wpa_config.
+ */
+ struct wpa_ssid *pnext;
+
+ /**
+ * id - Unique id for the network
+ *
+ * This identifier is used as a unique identifier for each network
+ * block when using the control interface. Each network is allocated an
+ * id when it is being created, either when reading the configuration
+ * file or when a new network is added through the control interface.
+ */
+ int id;
+
+ /**
+ * priority - Priority group
+ *
+ * By default, all networks will get same priority group (0). If some
+ * of the networks are more desirable, this field can be used to change
+ * the order in which wpa_supplicant goes through the networks when
+ * selecting a BSS. The priority groups will be iterated in decreasing
+ * priority (i.e., the larger the priority value, the sooner the
+ * network is matched against the scan results). Within each priority
+ * group, networks will be selected based on security policy, signal
+ * strength, etc.
+ *
+ * Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are
+ * not using this priority to select the order for scanning. Instead,
+ * they try the networks in the order that used in the configuration
+ * file.
+ */
int priority;
+
+ /**
+ * ssid - Service set identifier (network name)
+ *
+ * This is the SSID for the network. For wireless interfaces, this is
+ * used to select which network will be used. If set to %NULL (or
+ * ssid_len=0), any SSID can be used. For wired interfaces, this must
+ * be set to %NULL. Note: SSID may contain any characters, even nul
+ * (ASCII 0) and as such, this should not be assumed to be a nul
+ * terminated string. ssid_len defines how many characters are valid
+ * and the ssid field is not guaranteed to be nul terminated.
+ */
u8 *ssid;
+
+ /**
+ * ssid_len - Length of the SSID
+ */
size_t ssid_len;
+
+ /**
+ * bssid - BSSID
+ *
+ * If set, this network block is used only when associating with the AP
+ * using the configured BSSID
+ */
u8 bssid[ETH_ALEN];
+
+ /**
+ * bssid_set - Whether BSSID is configured for this network
+ */
int bssid_set;
+
+ /**
+ * psk - WPA pre-shared key (256 bits)
+ */
u8 psk[PMK_LEN];
+
+ /**
+ * psk_set - Whether PSK field is configured
+ */
int psk_set;
+
+ /**
+ * passphrase - WPA ASCII passphrase
+ *
+ * If this is set, psk will be generated using the SSID and passphrase
+ * configured for the network. ASCII passphrase must be between 8 and
+ * 63 characters (inclusive).
+ */
char *passphrase;
- /* Bitfields of allowed Pairwise/Group Ciphers, WPA_CIPHER_* */
+
+ /**
+ * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
+ */
int pairwise_cipher;
+
+ /**
+ * group_cipher - Bitfield of allowed group ciphers, WPA_CIPHER_*
+ */
int group_cipher;
+
+ /**
+ * key_mgmt - Bitfield of allowed key management protocols
+ *
+ * WPA_KEY_MGMT_*
+ */
int key_mgmt;
- int proto; /* Bitfield of allowed protocols (WPA_PROTO_*) */
- int auth_alg; /* Bitfield of allow authentication algorithms
- * (WPA_AUTH_ALG_*) */
- int scan_ssid; /* scan this SSID with Probe Requests */
- u8 *identity; /* EAP Identity */
+
+ /**
+ * proto - Bitfield of allowed protocols, WPA_PROTO_*
+ */
+ int proto;
+
+ /**
+ * auth_alg - Bitfield of allowed authentication algorithms
+ *
+ * WPA_AUTH_ALG_*
+ */
+ int auth_alg;
+
+ /**
+ * scan_ssid - Scan this SSID with Probe Requests
+ *
+ * scan_ssid can be used to scan for APs using hidden SSIDs.
+ * Note: Many drivers do not support this. ap_mode=2 can be used with
+ * such drivers to use hidden SSIDs.
+ */
+ int scan_ssid;
+
+ /**
+ * identity - EAP Identity
+ */
+ u8 *identity;
+
+ /**
+ * identity_len - EAP Identity length
+ */
size_t identity_len;
- u8 *anonymous_identity; /* Anonymous EAP Identity (for unencrypted use
- * with EAP types that support different
- * tunnelled identity, e.g., EAP-TTLS) */
+
+ /**
+ * anonymous_identity - Anonymous EAP Identity
+ *
+ * This field is used for unencrypted use with EAP types that support
+ * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
+ * real identity (identity field) only to the authentication server.
+ */
+ u8 *anonymous_identity;
+
+ /**
+ * anonymous_identity_len - Length of anonymous_identity
+ */
size_t anonymous_identity_len;
+
+ /**
+ * eappsk - EAP-PSK pre-shared key
+ */
u8 *eappsk;
+
+ /**
+ * eappsk_len - EAP-PSK pre-shared key length
+ *
+ * This field is always 16 for the current version of EAP-PSK.
+ */
size_t eappsk_len;
+
+ /**
+ * nai - User NAI (for EAP-PSK)
+ */
u8 *nai;
+
+ /**
+ * nai_len - Length of nai field
+ */
size_t nai_len;
- u8 *server_nai;
- size_t server_nai_len;
+
+ /**
+ * password - Password string for EAP
+ */
u8 *password;
+
+ /**
+ * password_len - Length of password field
+ */
size_t password_len;
+
+ /**
+ * ca_cert - File path to CA certificate file (PEM/DER)
+ *
+ * This file can have one or more trusted CA certificates. If ca_cert
+ * and ca_path are not included, server certificate will not be
+ * verified. This is insecure and a trusted CA certificate should
+ * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the
+ * file should be used since working directory may change when
+ * wpa_supplicant is run in the background.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://<blob name>.
+ *
+ * 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".
+ */
u8 *ca_cert;
+
+ /**
+ * ca_path - Directory path for CA certificate files (PEM)
+ *
+ * This path may contain multiple CA certificates in OpenSSL format.
+ * Common use for this is to point to system trusted CA list which is
+ * often installed into directory like /etc/ssl/certs. If configured,
+ * these certificates are added to the list of trusted CAs. ca_cert
+ * may also be included in that case, but it is not required.
+ */
+ u8 *ca_path;
+
+ /**
+ * client_cert - File path to client certificate file (PEM/DER)
+ *
+ * This field is used with EAP method that use TLS authentication.
+ * Usually, this is only configured for EAP-TLS, even though this could
+ * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the
+ * file should be used since working directory may change when
+ * wpa_supplicant is run in the background.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://<blob name>.
+ */
u8 *client_cert;
+
+ /**
+ * private_key - File path to client private key file (PEM/DER/PFX)
+ *
+ * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+ * commented out. Both the private key and certificate will be read
+ * from the PKCS#12 file in this case. Full path to the file should be
+ * used since working directory may change when wpa_supplicant is run
+ * in the background.
+ *
+ * Windows certificate store can be used by leaving client_cert out and
+ * configuring private_key in one of the following formats:
+ *
+ * cert://substring_to_match
+ *
+ * hash://certificate_thumbprint_in_hex
+ *
+ * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://<blob name>.
+ */
u8 *private_key;
+
+ /**
+ * private_key_passwd - Password for private key file
+ *
+ * If left out, this will be asked through control interface.
+ */
u8 *private_key_passwd;
+
+ /**
+ * dh_file - File path to DH/DSA parameters file (in PEM format)
+ *
+ * This is an optional configuration file for setting parameters for an
+ * ephemeral DH key exchange. In most cases, the default RSA
+ * authentication does not use this configuration. However, it is
+ * possible setup RSA to use ephemeral DH key exchange. In addition,
+ * ciphers with DSA keys always use ephemeral DH keys. This can be used
+ * to achieve forward secrecy. If the file is in DSA parameters format,
+ * it will be automatically converted into DH params. Full path to the
+ * file should be used since working directory may change when
+ * wpa_supplicant is run in the background.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://<blob name>.
+ */
u8 *dh_file;
+
+ /**
+ * subject_match - Constraint for server certificate subject
+ *
+ * This substring is matched against the subject of the authentication
+ * server certificate. If this string is set, the server sertificate is
+ * only accepted if it contains this string in the subject. The subject
+ * string is in following format:
+ *
+ * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com
+ */
u8 *subject_match;
+
+ /**
+ * 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.
+ *
+ * altSubjectName string is in following format: TYPE:VALUE
+ *
+ * Example: DNS:server.example.com
+ *
+ * Following types are supported: EMAIL, DNS, URI
+ */
+ u8 *altsubject_match;
+
+ /**
+ * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
+ *
+ * This file can have one or more trusted CA certificates. If ca_cert2
+ * and ca_path2 are not included, server certificate will not be
+ * verified. This is insecure and a trusted CA certificate should
+ * always be configured. Full path to the file should be used since
+ * working directory may change when wpa_supplicant is run in the
+ * background.
+ *
+ * This field is like ca_cert, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://<blob name>.
+ */
u8 *ca_cert2;
+
+ /**
+ * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
+ *
+ * This path may contain multiple CA certificates in OpenSSL format.
+ * Common use for this is to point to system trusted CA list which is
+ * often installed into directory like /etc/ssl/certs. If configured,
+ * these certificates are added to the list of trusted CAs. ca_cert
+ * may also be included in that case, but it is not required.
+ *
+ * This field is like ca_path, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
+ u8 *ca_path2;
+
+ /**
+ * client_cert2 - File path to client certificate file
+ *
+ * This field is like client_cert, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
+ * file should be used since working directory may change when
+ * wpa_supplicant is run in the background.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://<blob name>.
+ */
u8 *client_cert2;
+
+ /**
+ * private_key2 - File path to client private key file
+ *
+ * This field is like private_key, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
+ * file should be used since working directory may change when
+ * wpa_supplicant is run in the background.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://<blob name>.
+ */
u8 *private_key2;
+
+ /**
+ * private_key2_passwd - Password for private key file
+ *
+ * This field is like private_key_passwd, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
u8 *private_key2_passwd;
+
+ /**
+ * dh_file2 - File path to DH/DSA parameters file (in PEM format)
+ *
+ * This field is like dh_file, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
+ * file should be used since working directory may change when
+ * wpa_supplicant is run in the background.
+ *
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://<blob name>.
+ */
u8 *dh_file2;
+
+ /**
+ * subject_match2 - Constraint for server certificate subject
+ *
+ * This field is like subject_match, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
u8 *subject_match2;
- u8 *eap_methods; /* zero (EAP_TYPE_NONE) terminated list of allowed
- * EAP methods or NULL = any */
+
+ /**
+ * altsubject_match2 - Constraint for server certificate alt. subject
+ *
+ * This field is like altsubject_match, but used for phase 2 (inside
+ * EAP-TTLS/PEAP/FAST tunnel) authentication.
+ */
+ u8 *altsubject_match2;
+
+ /**
+ * eap_methods - Allowed EAP methods
+ *
+ * Zero (EAP_TYPE_NONE) terminated list of allowed EAP methods or %NULL
+ * if all methods are accepted.
+ */
+ u8 *eap_methods;
+
+ /**
+ * phase1 - Phase 1 (outer authentication) parameters
+ *
+ * String with field-value pairs, e.g., "peapver=0" or
+ * "peapver=1 peaplabel=1".
+ *
+ * 'peapver' can be used to force which PEAP version (0 or 1) is used.
+ *
+ * 'peaplabel=1' can be used to force new label, "client PEAP
+ * encryption", to be used during key derivation when PEAPv1 or newer.
+ *
+ * Most existing PEAPv1 implementation seem to be using the old label,
+ * "client EAP encryption", and wpa_supplicant is now using that as the
+ * default value.
+ *
+ * Some servers, e.g., Radiator, may require peaplabel=1 configuration
+ * to interoperate with PEAPv1; see eap_testing.txt for more details.
+ *
+ * 'peap_outer_success=0' can be used to terminate PEAP authentication
+ * on tunneled EAP-Success. This is required with some RADIUS servers
+ * that implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g.,
+ * Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode).
+ *
+ * include_tls_length=1 can be used to force wpa_supplicant to include
+ * TLS Message Length field in all TLS messages even if they are not
+ * fragmented.
+ *
+ * sim_min_num_chal=3 can be used to configure EAP-SIM to require three
+ * challenges (by default, it accepts 2 or 3).
+ *
+ * fast_provisioning=1 can be used to enable in-line provisioning of
+ * EAP-FAST credentials (PAC)
+ */
char *phase1;
+
+ /**
+ * phase2 - Phase2 (inner authentication with TLS tunnel) parameters
+ *
+ * String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
+ * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS.
+ */
char *phase2;
+
+ /**
+ * pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
+ *
+ * This field is used to configure PC/SC smartcard interface.
+ * Currently, the only configuration is whether this field is %NULL (do
+ * not use PC/SC) or non-NULL (e.g., "") to enable PC/SC.
+ *
+ * This field is used for EAP-SIM and EAP-AKA.
+ */
char *pcsc;
+
+ /**
+ * pin - PIN for USIM, GSM SIM, and smartcards
+ *
+ * This field is used to configure PIN for SIM and smartcards for
+ * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
+ * smartcard is used for private key operations.
+ *
+ * If left out, this will be asked through control interface.
+ */
char *pin;
+ /**
+ * engine - Enable OpenSSL engine (e.g., for smartcard access)
+ *
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
+ */
+ int engine;
+
+ /**
+ * engine_id - Engine ID for OpenSSL engine
+ *
+ * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
+ * engine.
+ *
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
+ */
+ char *engine_id;
+
+ /**
+ * key_id - Key ID for OpenSSL engine
+ *
+ * This is used if private key operations for EAP-TLS are performed
+ * using a smartcard.
+ */
+ char *key_id;
+
#define EAPOL_FLAG_REQUIRE_KEY_UNICAST BIT(0)
#define EAPOL_FLAG_REQUIRE_KEY_BROADCAST BIT(1)
- int eapol_flags; /* bit field of IEEE 802.1X/EAPOL options */
+ /**
+ * eapol_flags - Bit field of IEEE 802.1X/EAPOL options (EAPOL_FLAG_*)
+ */
+ int eapol_flags;
#define NUM_WEP_KEYS 4
#define MAX_WEP_KEY_LEN 16
+ /**
+ * wep_key - WEP keys
+ */
u8 wep_key[NUM_WEP_KEYS][MAX_WEP_KEY_LEN];
+
+ /**
+ * wep_key_len - WEP key lengths
+ */
size_t wep_key_len[NUM_WEP_KEYS];
+
+ /**
+ * wep_tx_keyidx - Default key index for TX frames using WEP
+ */
int wep_tx_keyidx;
- /* Per SSID variables that are not read from the configuration file */
+ /**
+ * proactive_key_caching - Enable proactive key caching
+ *
+ * This field can be used to enable proactive key caching which is also
+ * known as opportunistic PMKSA caching for WPA2. This is disabled (0)
+ * by default. Enable by setting this to 1.
+ *
+ * Proactive key caching is used to make supplicant assume that the APs
+ * are using the same PMK and generate PMKSA cache entries without
+ * doing RSN pre-authentication. This requires support from the AP side
+ * and is normally used with wireless switches that co-locate the
+ * authenticator.
+ */
+ int proactive_key_caching;
+
+ /**
+ * otp - One-time-password
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when OTP is entered through the control interface.
+ */
u8 *otp;
+
+ /**
+ * otp_len - Length of the otp field
+ */
size_t otp_len;
- int pending_req_identity, pending_req_password;
+
+ /**
+ * pending_req_identity - Whether there is a pending identity request
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request needed
+ * information.
+ */
+ int pending_req_identity;
+
+ /**
+ * pending_req_password - Whether there is a pending password request
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request needed
+ * information.
+ */
+ int pending_req_password;
+
+ /**
+ * pending_req_pin - Whether there is a pending PIN request
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request needed
+ * information.
+ */
+ int pending_req_pin;
+
+ /**
+ * pending_req_new_password - Pending password update request
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request needed
+ * information.
+ */
+ int pending_req_new_password;
+
+ /**
+ * pending_req_passphrase - Pending passphrase request
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request needed
+ * information.
+ */
+ int pending_req_passphrase;
+
+ /**
+ * pending_req_otp - Whether there is a pending OTP request
+ *
+ * This field should not be set in configuration step. It is only used
+ * internally when control interface is used to request needed
+ * information.
+ */
char *pending_req_otp;
+
+ /**
+ * pending_req_otp_len - Length of the pending OTP request
+ */
size_t pending_req_otp_len;
- int leap, non_leap;
+ /**
+ * leap - Number of EAP methods using LEAP
+ *
+ * This field should be set to 1 if LEAP is enabled. This is used to
+ * select IEEE 802.11 authentication algorithm.
+ */
+ int leap;
+
+ /**
+ * non_leap - Number of EAP methods not using LEAP
+ *
+ * This field should be set to >0 if any EAP method other than LEAP is
+ * enabled. This is used to select IEEE 802.11 authentication
+ * algorithm.
+ */
+ int non_leap;
+
+ /**
+ * eap_workaround - EAP workarounds enabled
+ *
+ * wpa_supplicant supports number of "EAP workarounds" to work around
+ * interoperability issues with incorrectly behaving authentication
+ * servers. This is recommended to be enabled by default because some
+ * of the issues are present in large number of authentication servers.
+ *
+ * Strict EAP conformance mode can be configured by disabling
+ * workarounds with eap_workaround = 0.
+ */
unsigned int eap_workaround;
+ /**
+ * pac_file - File path or blob name for the PAC entries (EAP-FAST)
+ *
+ * wpa_supplicant will need to be able to create this file and write
+ * updates to it when PAC is being provisioned or refreshed. Full path
+ * to the file should be used since working directory may change when
+ * wpa_supplicant is run in the background.
+ * Alternatively, a named configuration blob can be used by setting
+ * this to blob://<blob name>.
+ */
char *pac_file;
+ /**
+ * mode - IEEE 802.11 operation mode (Infrastucture/IBSS)
+ *
+ * 0 = infrastructure (Managed) mode, i.e., associate with an AP.
+ *
+ * 1 = IBSS (ad-hoc, peer-to-peer)
+ *
+ * Note: IBSS can only be used with key_mgmt NONE (plaintext and
+ * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
+ * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires
+ * following network block options: proto=WPA, key_mgmt=WPA-NONE,
+ * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also
+ * be set (either directly or using ASCII passphrase).
+ */
int mode;
+
+ /**
+ * mschapv2_retry - MSCHAPv2 retry in progress
+ *
+ * This field is used internally by EAP-MSCHAPv2 and should not be set
+ * as part of configuration.
+ */
+ int mschapv2_retry;
+
+ /**
+ * new_password - New password for password update
+ *
+ * This field is used during MSCHAPv2 password update. This is normally
+ * requested from the user through the control interface and not set
+ * from configuration.
+ */
+ u8 *new_password;
+
+ /**
+ * new_password_len - Length of new_password field
+ */
+ size_t new_password_len;
+
+ /**
+ * disabled - Whether this network is currently disabled
+ *
+ * 0 = this network can be used (default).
+ * 1 = this network block is disabled (can be enabled through
+ * ctrl_iface, e.g., with wpa_cli or wpa_gui).
+ */
+ int disabled;
};
int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method);
-const char * wpa_cipher_txt(int cipher);
-const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
#endif /* CONFIG_SSID_H */
diff --git a/contrib/wpa_supplicant/config_types.h b/contrib/wpa_supplicant/config_types.h
new file mode 100644
index 0000000..12b57cb
--- /dev/null
+++ b/contrib/wpa_supplicant/config_types.h
@@ -0,0 +1,14 @@
+#ifndef CONFIG_TYPES_H
+#define CONFIG_TYPES_H
+
+struct hostapd_ip_addr {
+ union {
+ struct in_addr v4;
+#ifdef CONFIG_IPV6
+ struct in6_addr v6;
+#endif /* CONFIG_IPV6 */
+ } u;
+ int af; /* AF_INET / AF_INET6 */
+};
+
+#endif /* CONFIG_TYPES_H */
diff --git a/contrib/wpa_supplicant/crypto.c b/contrib/wpa_supplicant/crypto.c
index cd278e0..b4c8189 100644
--- a/contrib/wpa_supplicant/crypto.c
+++ b/contrib/wpa_supplicant/crypto.c
@@ -12,11 +12,17 @@
* See README and COPYING for more details.
*/
+#include <string.h>
+#include <sys/types.h>
+
#include <openssl/md4.h>
+#include <openssl/md5.h>
+#include <openssl/sha.h>
#include <openssl/des.h>
+#include <openssl/aes.h>
#include "common.h"
-
+#include "crypto.h"
#if OPENSSL_VERSION_NUMBER < 0x00907000
#define DES_key_schedule des_key_schedule
@@ -27,7 +33,7 @@
#endif /* openssl < 0.9.7 */
-void md4_vector(size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
+void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD4_CTX ctx;
int i;
@@ -39,17 +45,6 @@ void md4_vector(size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
}
-void md4(const u8 *addr, size_t len, u8 *mac)
-{
- md4_vector(1, &addr, &len, mac);
-}
-
-
-/**
- * @clear: 8 octets (in)
- * @key: 7 octets (in) (no parity bits included)
- * @cypher: 8 octets (out)
- */
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
{
u8 pkey[8], next, tmp;
@@ -69,3 +64,91 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
DES_ENCRYPT);
}
+
+
+#ifdef EAP_TLS_FUNCS
+void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ MD5_CTX ctx;
+ int i;
+
+ MD5_Init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ MD5_Update(&ctx, addr[i], len[i]);
+ MD5_Final(mac, &ctx);
+}
+
+
+void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ SHA_CTX ctx;
+ int i;
+
+ SHA1_Init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ SHA1_Update(&ctx, addr[i], len[i]);
+ SHA1_Final(mac, &ctx);
+}
+
+
+void sha1_transform(u8 *state, const u8 data[64])
+{
+ SHA_CTX context;
+ memset(&context, 0, sizeof(context));
+ memcpy(&context.h0, state, 5 * 4);
+ SHA1_Transform(&context, data);
+ memcpy(state, &context.h0, 5 * 4);
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ AES_KEY *ak;
+ ak = malloc(sizeof(*ak));
+ if (ak == NULL)
+ return NULL;
+ if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
+ free(ak);
+ return NULL;
+ }
+ return ak;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ AES_encrypt(plain, crypt, ctx);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ free(ctx);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ AES_KEY *ak;
+ ak = malloc(sizeof(*ak));
+ if (ak == NULL)
+ return NULL;
+ if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
+ free(ak);
+ return NULL;
+ }
+ return ak;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ AES_decrypt(crypt, plain, ctx);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ free(ctx);
+}
+#endif /* EAP_TLS_FUNCS */
diff --git a/contrib/wpa_supplicant/crypto.h b/contrib/wpa_supplicant/crypto.h
index 3e1a0e5..e664861 100644
--- a/contrib/wpa_supplicant/crypto.h
+++ b/contrib/wpa_supplicant/crypto.h
@@ -1,8 +1,123 @@
+/*
+ * WPA Supplicant / wrapper functions for crypto libraries
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 defines the cryptographic functions that need to be implemented
+ * for wpa_supplicant and hostapd. When TLS is not used, internal
+ * implementation of MD5, SHA1, and AES is used and no external libraries are
+ * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the
+ * crypto library used by the TLS implementation is expected to be used for
+ * non-TLS needs, too, in order to save space by not implementing these
+ * functions twice.
+ *
+ * Wrapper code for using each crypto library is in its own file (crypto*.c)
+ * and one of these files is build and linked in to provide the functions
+ * defined here.
+ */
+
#ifndef CRYPTO_H
#define CRYPTO_H
+/**
+ * md4_vector - MD4 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ */
void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
-void md4(const u8 *addr, size_t len, u8 *mac);
+
+/**
+ * md5_vector - MD5 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ */
+void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
+
+/**
+ * sha1_vector - SHA-1 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ */
+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
+ *
+ * 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]);
+
+/**
+ * des_encrypt - Encrypt one block with DES
+ * @clear: 8 octets (in)
+ * @key: 7 octets (in) (no parity bits included)
+ * @cypher: 8 octets (out)
+ */
void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
+/**
+ * aes_encrypt_init - Initialize AES for encryption
+ * @key: Encryption key
+ * @len: Key length in bytes (usually 16, i.e., 128 bits)
+ * Returns: Pointer to context data or %NULL on failure
+ */
+void * aes_encrypt_init(const u8 *key, size_t len);
+
+/**
+ * aes_encrypt - Encrypt one AES block
+ * @ctx: Context pointer from aes_encrypt_init()
+ * @plain: Plaintext data to be encrypted (16 bytes)
+ * @crypt: Buffer for the encrypted data (16 bytes)
+ */
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+
+/**
+ * aes_encrypt_deinit - Deinitialize AES encryption
+ * @ctx: Context pointer from aes_encrypt_init()
+ */
+void aes_encrypt_deinit(void *ctx);
+
+/**
+ * aes_decrypt_init - Initialize AES for decryption
+ * @key: Decryption key
+ * @len: Key length in bytes (usually 16, i.e., 128 bits)
+ * Returns: Pointer to context data or %NULL on failure
+ */
+void * aes_decrypt_init(const u8 *key, size_t len);
+
+/**
+ * aes_decrypt - Decrypt one AES block
+ * @ctx: Context pointer from aes_encrypt_init()
+ * @crypt: Encrypted data (16 bytes)
+ * @plain: Buffer for the decrypted data (16 bytes)
+ */
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+
+/**
+ * aes_decrypt_deinit - Deinitialize AES decryption
+ * @ctx: Context pointer from aes_encrypt_init()
+ */
+void aes_decrypt_deinit(void *ctx);
+
+
#endif /* CRYPTO_H */
diff --git a/contrib/wpa_supplicant/crypto_gnutls.c b/contrib/wpa_supplicant/crypto_gnutls.c
new file mode 100644
index 0000000..15f9b54
--- /dev/null
+++ b/contrib/wpa_supplicant/crypto_gnutls.c
@@ -0,0 +1,163 @@
+/*
+ * WPA Supplicant / wrapper functions for libgcrypt
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdio.h>
+#include <sys/types.h>
+#include <gcrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+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;
+
+ if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
+ return;
+ for (i = 0; i < num_elem; i++)
+ gcry_md_write(hd, addr[i], len[i]);
+ p = gcry_md_read(hd, GCRY_MD_MD4);
+ if (p)
+ memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
+ gcry_md_close(hd);
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ gcry_cipher_hd_t hd;
+ u8 pkey[8], next, tmp;
+ int i;
+
+ /* 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;
+
+ gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ gcry_err_code(gcry_cipher_setkey(hd, pkey, 8));
+ gcry_cipher_encrypt(hd, cypher, 8, clear, 8);
+ gcry_cipher_close(hd);
+}
+
+
+#ifdef EAP_TLS_FUNCS
+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;
+
+ if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
+ return;
+ for (i = 0; i < num_elem; i++)
+ gcry_md_write(hd, addr[i], len[i]);
+ p = gcry_md_read(hd, GCRY_MD_MD5);
+ if (p)
+ memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
+ gcry_md_close(hd);
+}
+
+
+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;
+
+ if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
+ return;
+ for (i = 0; i < num_elem; i++)
+ gcry_md_write(hd, addr[i], len[i]);
+ p = gcry_md_read(hd, GCRY_MD_SHA1);
+ if (p)
+ memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
+ gcry_md_close(hd);
+}
+
+
+void sha1_transform(u8 *state, const u8 data[64])
+{
+ /* FIX: how to do this with libgcrypt? */
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+ gcry_cipher_hd_t hd;
+
+ if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
+ GPG_ERR_NO_ERROR) {
+ printf("cipher open failed\n");
+ return NULL;
+ }
+ if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
+ printf("setkey failed\n");
+ gcry_cipher_close(hd);
+ return NULL;
+ }
+
+ return hd;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+ gcry_cipher_hd_t hd = ctx;
+ gcry_cipher_encrypt(hd, crypt, 16, plain, 16);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+ gcry_cipher_hd_t hd = ctx;
+ gcry_cipher_close(hd);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+ gcry_cipher_hd_t hd;
+
+ if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
+ GPG_ERR_NO_ERROR)
+ return NULL;
+ if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
+ gcry_cipher_close(hd);
+ return NULL;
+ }
+
+ return hd;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+ gcry_cipher_hd_t hd = ctx;
+ gcry_cipher_decrypt(hd, plain, 16, crypt, 16);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+ gcry_cipher_hd_t hd = ctx;
+ gcry_cipher_close(hd);
+}
+#endif /* EAP_TLS_FUNCS */
diff --git a/contrib/wpa_supplicant/ctrl_iface.c b/contrib/wpa_supplicant/ctrl_iface.c
index 25cf0db..01ea456 100644
--- a/contrib/wpa_supplicant/ctrl_iface.c
+++ b/contrib/wpa_supplicant/ctrl_iface.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant / UNIX domain socket -based control interface
+ * WPA Supplicant / UNIX domain and UDP socket -based control interface
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -21,6 +21,8 @@
#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 */
@@ -34,12 +36,11 @@
#include "wpa_supplicant_i.h"
#include "ctrl_iface.h"
#include "l2_packet.h"
+#include "preauth.h"
+#include "wpa_ctrl.h"
+#include "eap.h"
-#ifdef CONFIG_NATIVE_WINDOWS
-typedef int socklen_t;
-#endif /* CONFIG_NATIVE_WINDOWS */
-
#ifdef CONFIG_CTRL_IFACE_UDP
#define CTRL_IFACE_SOCK struct sockaddr_in
#else /* CONFIG_CTRL_IFACE_UDP */
@@ -47,6 +48,13 @@ typedef int socklen_t;
#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;
@@ -56,33 +64,11 @@ struct wpa_ctrl_dst {
};
-static const char * wpa_state_txt(int state)
-{
- switch (state) {
- case WPA_DISCONNECTED:
- return "DISCONNECTED";
- case WPA_SCANNING:
- return "SCANNING";
- case WPA_ASSOCIATING:
- return "ASSOCIATING";
- case WPA_ASSOCIATED:
- return "ASSOCIATED";
- case WPA_4WAY_HANDSHAKE:
- return "4WAY_HANDSHAKE";
- case WPA_GROUP_HANDSHAKE:
- return "GROUP_HANDSHAKE";
- case WPA_COMPLETED:
- return "COMPLETED";
- default:
- return "UNKNOWN";
- }
-}
-
-
static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
char *cmd)
{
char *value;
+ int ret = 0;
value = strchr(cmd, ' ');
if (value == NULL)
@@ -102,9 +88,21 @@ static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
} else if (strcasecmp(cmd, "EAPOL::maxStart") == 0) {
eapol_sm_configure(wpa_s->eapol,
-1, -1, -1, atoi(value));
+ } else if (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) {
+ if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
+ atoi(value)))
+ ret = -1;
+ } else if (strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
+ if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
+ ret = -1;
} else
- return -1;
- return 0;
+ ret = -1;
+
+ return ret;
}
@@ -120,8 +118,8 @@ static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
}
wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
- rsn_preauth_deinit(wpa_s);
- if (rsn_preauth_init(wpa_s, bssid))
+ rsn_preauth_deinit(wpa_s->wpa);
+ if (rsn_preauth_init(wpa_s->wpa, bssid, wpa_s->current_ssid))
return -1;
return 0;
@@ -252,13 +250,7 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
(u8 *) pos, strlen(pos));
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- if (id == ssid->id)
- break;
- ssid = ssid->next;
- }
-
+ ssid = wpa_config_get_network(wpa_s->conf, id);
if (ssid == NULL) {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
"to update", id);
@@ -279,6 +271,19 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
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);
+ 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);
+ 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);
@@ -286,6 +291,12 @@ static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
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);
+ ssid->pending_req_passphrase = 0;
+ if (ssid == wpa_s->current_ssid)
+ wpa_s->reassociate = 1;
} else {
wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
return -1;
@@ -299,46 +310,626 @@ static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
const char *params,
char *buf, size_t buflen)
{
- char *pos, *end;
+ char *pos, *end, tmp[30];
int res, verbose;
verbose = strcmp(params, "-VERBOSE") == 0;
pos = buf;
end = buf + buflen;
- 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));
- }
- pos += snprintf(pos, end - pos,
- "pairwise_cipher=%s\n"
- "group_cipher=%s\n"
- "key_mgmt=%s\n"
- "wpa_state=%s\n",
- wpa_cipher_txt(wpa_s->pairwise_cipher),
- wpa_cipher_txt(wpa_s->group_cipher),
- wpa_key_mgmt_txt(wpa_s->key_mgmt, wpa_s->proto),
- wpa_state_txt(wpa_s->wpa_state));
-
- res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos, verbose);
- if (res >= 0)
- pos += res;
+ 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));
+ }
+
+ 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));
+
+ 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);
- if (wpa_s->preauth_eapol) {
- pos += snprintf(pos, end - pos, "Pre-authentication "
- "EAPOL state machines:\n");
- res = eapol_sm_get_status(wpa_s->preauth_eapol,
- pos, end - pos, verbose);
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
+ verbose);
if (res >= 0)
pos += res;
}
+ res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
+ if (res >= 0)
+ pos += res;
+
+ return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
+ char *cmd)
+{
+ char *pos;
+ int id;
+ struct wpa_ssid *ssid;
+ u8 bssid[ETH_ALEN];
+
+ /* cmd: "<network id> <BSSID>" */
+ pos = strchr(cmd, ' ');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
+ if (hwaddr_aton(pos, bssid)) {
+ wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
+ return -1;
+ }
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+ "to update", id);
+ return -1;
+ }
+
+ memcpy(ssid->bssid, bssid, ETH_ALEN);
+ ssid->bssid_set =
+ memcmp(bssid, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) != 0;
+
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_list_networks(
+ struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+ char *pos, *end;
+ struct wpa_ssid *ssid;
+
+ pos = buf;
+ end = buf + buflen;
+ pos += snprintf(pos, end - pos, "network id / ssid / bssid / flags\n");
+
+ 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));
+ if (ssid->bssid_set) {
+ pos += snprintf(pos, end - pos, "\t" MACSTR,
+ MAC2STR(ssid->bssid));
+ } else {
+ pos += 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");
+
+ ssid = ssid->next;
+ }
+
return pos - buf;
}
+static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
+{
+ int first = 1;
+ pos += snprintf(pos, end - pos, "-");
+ if (cipher & WPA_CIPHER_NONE) {
+ pos += snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
+ first = 0;
+ }
+ if (cipher & WPA_CIPHER_WEP40) {
+ pos += snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
+ first = 0;
+ }
+ if (cipher & WPA_CIPHER_WEP104) {
+ pos += snprintf(pos, end - pos, "%sWEP104", first ? "" : "+");
+ first = 0;
+ }
+ if (cipher & WPA_CIPHER_TKIP) {
+ pos += snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
+ first = 0;
+ }
+ if (cipher & WPA_CIPHER_CCMP) {
+ pos += snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
+ first = 0;
+ }
+ return pos;
+}
+
+
+static char * wpa_supplicant_ie_txt(struct wpa_supplicant *wpa_s,
+ char *pos, char *end, const char *proto,
+ const u8 *ie, size_t ie_len)
+{
+ struct wpa_ie_data data;
+ int first;
+
+ pos += snprintf(pos, end - pos, "[%s-", proto);
+
+ if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
+ pos += snprintf(pos, end - pos, "?]");
+ return pos;
+ }
+
+ first = 1;
+ if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+ pos += snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
+ first = 0;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
+ pos += snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
+ first = 0;
+ }
+ if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
+ pos += snprintf(pos, end - pos, "%sNone", first ? "" : "+");
+ first = 0;
+ }
+
+ pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
+
+ if (data.capabilities & WPA_CAPABILITY_PREAUTH)
+ pos += snprintf(pos, end - pos, "-preauth");
+
+ pos += snprintf(pos, end - pos, "]");
+
+ return pos;
+}
+
+
+static int wpa_supplicant_ctrl_iface_scan_results(
+ struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+ char *pos, *end;
+ struct wpa_scan_result *res;
+ int i;
+
+ if (wpa_s->scan_results == NULL &&
+ wpa_supplicant_get_scan_results(wpa_s) < 0)
+ return 0;
+
+ pos = buf;
+ end = buf + buflen;
+ pos += snprintf(pos, end - pos, "bssid / frequency / signal level / "
+ "flags / ssid\n");
+
+ 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);
+ if (res->wpa_ie_len) {
+ pos = wpa_supplicant_ie_txt(wpa_s, 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",
+ 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]");
+
+ pos += snprintf(pos, end - pos, "\t%s",
+ wpa_ssid_txt(res->ssid, res->ssid_len));
+
+ pos += snprintf(pos, end - pos, "\n");
+ }
+
+ return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_select_network(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int id;
+ struct wpa_ssid *ssid;
+
+ /* cmd: "<network id>" or "any" */
+ if (strcmp(cmd, "any") == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
+ 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);
+ return 0;
+ }
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+ "id=%d", id);
+ return -1;
+ }
+
+ 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 = id != ssid->id;
+ ssid = ssid->next;
+ }
+ wpa_s->reassociate = 1;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_enable_network(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int id;
+ struct wpa_ssid *ssid;
+
+ /* cmd: "<network id>" */
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+ "id=%d", id);
+ return -1;
+ }
+
+ 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 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_disable_network(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int id;
+ struct wpa_ssid *ssid;
+
+ /* cmd: "<network id>" */
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+ "id=%d", id);
+ return -1;
+ }
+
+ if (ssid == wpa_s->current_ssid)
+ wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
+ ssid->disabled = 1;
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_add_network(
+ struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+ struct wpa_ssid *ssid;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
+
+ ssid = wpa_config_add_network(wpa_s->conf);
+ if (ssid == NULL)
+ return -1;
+ ssid->disabled = 1;
+ wpa_config_set_network_defaults(ssid);
+
+ return snprintf(buf, buflen, "%d\n", ssid->id);
+}
+
+
+static int wpa_supplicant_ctrl_iface_remove_network(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int id;
+ struct wpa_ssid *ssid;
+
+ /* cmd: "<network id>" */
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL ||
+ wpa_config_remove_network(wpa_s->conf, id) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+ "id=%d", id);
+ return -1;
+ }
+
+ if (ssid == wpa_s->current_ssid)
+ wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_set_network(
+ struct wpa_supplicant *wpa_s, char *cmd)
+{
+ int id;
+ struct wpa_ssid *ssid;
+ char *name, *value;
+
+ /* cmd: "<network id> <variable name> <value>" */
+ name = strchr(cmd, ' ');
+ if (name == NULL)
+ return -1;
+ *name++ = '\0';
+
+ value = 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);
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+ "id=%d", id);
+ return -1;
+ }
+
+ 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);
+ return -1;
+ }
+
+ if ((strcmp(name, "psk") == 0 && value[0] == '"' && ssid->ssid_len) ||
+ (strcmp(name, "ssid") == 0 && ssid->passphrase))
+ wpa_config_update_psk(ssid);
+
+ return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_get_network(
+ struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
+{
+ int id;
+ struct wpa_ssid *ssid;
+ char *name, *value;
+
+ /* cmd: "<network id> <variable name>" */
+ name = strchr(cmd, ' ');
+ if (name == NULL)
+ return -1;
+ *name++ = '\0';
+
+ id = atoi(cmd);
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
+ id, name);
+
+ ssid = wpa_config_get_network(wpa_s->conf, id);
+ if (ssid == NULL) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+ "id=%d", id);
+ return -1;
+ }
+
+ value = wpa_config_get(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);
+
+ free(value);
+
+ return strlen(buf);
+}
+
+
+static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
+{
+ int ret;
+
+ if (!wpa_s->conf->update_config) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
+ "to update configuration (update_config=0)");
+ return -1;
+ }
+
+ ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
+ "update configuration");
+ } else {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
+ " updated");
+ }
+
+ return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_get_capability(
+ 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;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s'", field);
+
+ if (strcmp(field, "eap") == 0) {
+ return eap_get_names(buf, buflen);
+ }
+
+ res = wpa_drv_get_capa(wpa_s, &capa);
+
+ pos = buf;
+ end = pos + buflen;
+
+ if (strcmp(field, "pairwise") == 0) {
+ if (res < 0)
+ return snprintf(buf, buflen, "CCMP TKIP NONE");
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+ pos += snprintf(pos, end - pos, "%sCCMP",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+ pos += snprintf(pos, end - pos, "%sTKIP",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+ pos += snprintf(pos, end - pos, "%sNONE",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ return pos - buf;
+ }
+
+ if (strcmp(field, "group") == 0) {
+ if (res < 0)
+ return snprintf(buf, buflen, "CCMP TKIP WEP104 WEP40");
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+ pos += snprintf(pos, end - pos, "%sCCMP",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+ pos += snprintf(pos, end - pos, "%sTKIP",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
+ pos += snprintf(pos, end - pos, "%sWEP104",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
+ pos += snprintf(pos, end - pos, "%sWEP40",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ return pos - buf;
+ }
+
+ if (strcmp(field, "key_mgmt") == 0) {
+ if (res < 0) {
+ return snprintf(buf, buflen, "WPA-PSK WPA-EAP "
+ "IEEE8021X WPA-NONE NONE");
+ }
+
+ pos += snprintf(pos, end - pos, "NONE IEEE8021X");
+
+ if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2))
+ pos += snprintf(pos, end - pos, " WPA-EAP");
+
+ 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");
+
+ if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE)
+ pos += snprintf(pos, end - pos, " WPA-NONE");
+
+ return pos - buf;
+ }
+
+ if (strcmp(field, "proto") == 0) {
+ if (res < 0)
+ return snprintf(buf, buflen, "RSN WPA");
+
+ if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ pos += snprintf(pos, end - pos, "%sRSN",
+ first ? "" : " ");
+ 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 ? "" : " ");
+ first = 0;
+ }
+
+ return pos - buf;
+ }
+
+ if (strcmp(field, "auth_alg") == 0) {
+ if (res < 0)
+ return snprintf(buf, buflen, "OPEN SHARED LEAP");
+
+ if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
+ pos += snprintf(pos, end - pos, "%sOPEN",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
+ pos += snprintf(pos, end - pos, "%sSHARED",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
+ pos += snprintf(pos, end - pos, "%sLEAP",
+ first ? "" : " ");
+ first = 0;
+ }
+
+ return pos - buf;
+ }
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
+ field);
+
+ return -1;
+}
+
+
static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
@@ -359,7 +950,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
return;
}
buf[res] = '\0';
- if (strncmp(buf, "CTRL-RSP-", 9) == 0) {
+ if (strncmp(buf, WPA_CTRL_RSP, strlen(WPA_CTRL_RSP)) == 0) {
wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
(u8 *) buf, res);
} else {
@@ -380,7 +971,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
memcpy(reply, "PONG\n", 5);
reply_len = 5;
} else if (strcmp(buf, "MIB") == 0) {
- reply_len = wpa_get_mib(wpa_s, reply, reply_size);
+ reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
if (reply_len >= 0) {
res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
reply_size - reply_len);
@@ -393,7 +984,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len = wpa_supplicant_ctrl_iface_status(
wpa_s, buf + 6, reply, reply_size);
} else if (strcmp(buf, "PMKSA") == 0) {
- reply_len = pmksa_cache_list(wpa_s, reply, reply_size);
+ reply_len = pmksa_cache_list(wpa_s->wpa, reply, reply_size);
} else if (strncmp(buf, "SET ", 4) == 0) {
if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
reply_len = -1;
@@ -402,6 +993,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (strcmp(buf, "LOGOFF") == 0) {
eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
} else if (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) {
@@ -419,8 +1011,9 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
if (wpa_supplicant_ctrl_iface_level(wpa_s, &from, fromlen,
buf + 6))
reply_len = -1;
- } else if (strncmp(buf, "CTRL-RSP-", 9) == 0) {
- if (wpa_supplicant_ctrl_iface_ctrl_rsp(wpa_s, buf + 9))
+ } else if (strncmp(buf, WPA_CTRL_RSP, strlen(WPA_CTRL_RSP)) == 0) {
+ if (wpa_supplicant_ctrl_iface_ctrl_rsp(
+ wpa_s, buf + strlen(WPA_CTRL_RSP)))
reply_len = -1;
else
ctrl_rsp = 1;
@@ -429,6 +1022,48 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
reply_len = -1;
} else if (strcmp(buf, "TERMINATE") == 0) {
eloop_terminate();
+ } else if (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) {
+ reply_len = wpa_supplicant_ctrl_iface_list_networks(
+ wpa_s, reply, reply_size);
+ } else if (strcmp(buf, "DISCONNECT") == 0) {
+ wpa_s->disconnected = 1;
+ wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
+ } else if (strcmp(buf, "SCAN") == 0) {
+ wpa_s->scan_req = 2;
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ } else if (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) {
+ if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
+ reply_len = -1;
+ } else if (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) {
+ if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
+ reply_len = -1;
+ } else if (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) {
+ if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
+ reply_len = -1;
+ } else if (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) {
+ reply_len = wpa_supplicant_ctrl_iface_get_network(
+ wpa_s, buf + 12, reply, reply_size);
+ } else if (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) {
+ reply_len = wpa_supplicant_ctrl_iface_get_capability(
+ wpa_s, buf + 15, reply, reply_size);
} else {
memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -448,6 +1083,7 @@ static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
}
+#ifndef CONFIG_CTRL_IFACE_UDP
static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
{
char *buf;
@@ -477,13 +1113,24 @@ static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
#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;
@@ -500,9 +1147,9 @@ int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl((127 << 24) | 1);
- addr.sin_port = htons(9877);
+ addr.sin_port = htons(WPA_CTRL_IFACE_PORT);
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(AF_UNIX)");
+ perror("bind(AF_INET)");
goto fail;
}
#else /* CONFIG_CTRL_IFACE_UDP */
@@ -592,20 +1239,31 @@ int wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
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) {
/*
@@ -619,6 +1277,7 @@ void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s)
}
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);
@@ -633,6 +1292,7 @@ void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s)
perror("rmdir[ctrl_interface]");
}
}
+#endif /* CONFIG_CTRL_IFACE_UDP */
}
dst = wpa_s->ctrl_dst;
@@ -644,6 +1304,15 @@ void wpa_supplicant_ctrl_iface_deinit(struct wpa_supplicant *wpa_s)
}
+/**
+ * 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)
{
@@ -678,9 +1347,7 @@ void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
if (sendto(wpa_s->ctrl_sock, sbuf, llen + len, 0,
(struct sockaddr *) &dst->addr,
sizeof(dst->addr)) < 0) {
- fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
- idx);
- perror("sendto");
+ perror("sendto(CTRL_IFACE monitor)");
dst->errors++;
if (dst->errors > 10) {
wpa_supplicant_ctrl_iface_detach(
@@ -720,9 +1387,7 @@ void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
msg.msg_name = &dst->addr;
msg.msg_namelen = dst->addrlen;
if (sendmsg(wpa_s->ctrl_sock, &msg, 0) < 0) {
- fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
- idx);
- perror("sendmsg");
+ perror("sendmsg(CTRL_IFACE monitor)");
dst->errors++;
if (dst->errors > 10) {
wpa_supplicant_ctrl_iface_detach(
@@ -737,3 +1402,287 @@ void wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
}
#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);
+}
+
+
+static int wpa_supplicant_global_iface_add(struct wpa_global *global,
+ char *cmd)
+{
+ struct wpa_interface iface;
+ char *pos;
+
+ /*
+ * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
+ */
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
+
+ memset(&iface, 0, sizeof(iface));
+
+ do {
+ iface.ifname = pos = cmd;
+ pos = strchr(pos, '\t');
+ if (pos)
+ *pos++ = '\0';
+ if (iface.ifname[0] == '\0')
+ return -1;
+ if (pos == NULL)
+ break;
+
+ iface.confname = pos;
+ pos = strchr(pos, '\t');
+ if (pos)
+ *pos++ = '\0';
+ if (iface.confname[0] == '\0')
+ iface.confname = NULL;
+ if (pos == NULL)
+ break;
+
+ iface.driver = pos;
+ pos = strchr(pos, '\t');
+ if (pos)
+ *pos++ = '\0';
+ if (iface.driver[0] == '\0')
+ iface.driver = NULL;
+ if (pos == NULL)
+ break;
+
+ iface.ctrl_interface = pos;
+ pos = strchr(pos, '\t');
+ if (pos)
+ *pos++ = '\0';
+ if (iface.ctrl_interface[0] == '\0')
+ iface.ctrl_interface = NULL;
+ if (pos == NULL)
+ break;
+
+ iface.driver_param = pos;
+ pos = strchr(pos, '\t');
+ if (pos)
+ *pos++ = '\0';
+ if (iface.driver_param[0] == '\0')
+ iface.driver_param = NULL;
+ if (pos == NULL)
+ break;
+ } while (0);
+
+ if (wpa_supplicant_get_iface(global, iface.ifname))
+ return -1;
+
+ return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
+}
+
+
+static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
+ char *cmd)
+{
+ struct wpa_supplicant *wpa_s;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
+
+ wpa_s = wpa_supplicant_get_iface(global, cmd);
+ if (wpa_s == NULL)
+ return -1;
+ return wpa_supplicant_remove_iface(global, wpa_s);
+}
+
+
+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;
+ CTRL_IFACE_SOCK from;
+ socklen_t fromlen = sizeof(from);
+ 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);
+
+ reply = malloc(reply_size);
+ if (reply == NULL) {
+ sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+ fromlen);
+ return;
+ }
+
+ memcpy(reply, "OK\n", 3);
+ reply_len = 3;
+
+ if (strcmp(buf, "PING") == 0) {
+ memcpy(reply, "PONG\n", 5);
+ reply_len = 5;
+ } else if (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) {
+ if (wpa_supplicant_global_iface_remove(global, buf + 17))
+ reply_len = -1;
+ } else {
+ memcpy(reply, "UNKNOWN COMMAND\n", 16);
+ reply_len = 16;
+ }
+
+ if (reply_len < 0) {
+ 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 */
+}
diff --git a/contrib/wpa_supplicant/ctrl_iface.h b/contrib/wpa_supplicant/ctrl_iface.h
index d7ad6df..affa604 100644
--- a/contrib/wpa_supplicant/ctrl_iface.h
+++ b/contrib/wpa_supplicant/ctrl_iface.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 CTRL_IFACE_H
#define CTRL_IFACE_H
@@ -7,6 +21,9 @@ 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);
#else /* CONFIG_CTRL_IFACE */
@@ -26,6 +43,22 @@ wpa_supplicant_ctrl_iface_send(struct wpa_supplicant *wpa_s, int level,
{
}
+static inline void
+wpa_supplicant_ctrl_iface_wait(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+ return 0;
+}
+
+static inline void
+wpa_supplicant_global_ctrl_iface_deinit(struct wpa_global *global)
+{
+}
+
#endif /* CONFIG_CTRL_IFACE */
#endif /* CTRL_IFACE_H */
diff --git a/contrib/wpa_supplicant/defconfig b/contrib/wpa_supplicant/defconfig
index 7e8e381..be013b4 100644
--- a/contrib/wpa_supplicant/defconfig
+++ b/contrib/wpa_supplicant/defconfig
@@ -50,7 +50,9 @@ CONFIG_DRIVER_HOSTAP=y
#CFLAGS += -I../madwifi/wpa
# Driver interface for Prism54 driver
-CONFIG_DRIVER_PRISM54=y
+# (Note: Prism54 is not yet supported, i.e., this will not work as-is and is
+# for developers only)
+#CONFIG_DRIVER_PRISM54=y
# Driver interface for ndiswrapper
#CONFIG_DRIVER_NDISWRAPPER=y
@@ -88,6 +90,9 @@ CONFIG_DRIVER_WEXT=y
# Driver interface for development testing
#CONFIG_DRIVER_TEST=y
+# Driver interface for wired Ethernet drivers
+CONFIG_DRIVER_WIRED=y
+
# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
# included)
CONFIG_IEEE8021X_EAPOL=y
@@ -119,6 +124,9 @@ CONFIG_EAP_OTP=y
# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
+# EAP-PAX
+#CONFIG_EAP_PAX=y
+
# LEAP
CONFIG_EAP_LEAP=y
@@ -129,6 +137,10 @@ CONFIG_EAP_LEAP=y
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+CONFIG_SMARTCARD=y
+
# PC/SC interface for smartcards (USIM, GSM SIM)
# Enable this if EAP-SIM or EAP-AKA is included
#CONFIG_PCSC=y
@@ -143,12 +155,22 @@ CONFIG_PKCS12=y
# Include control interface for external programs, e.g, wpa_cli
CONFIG_CTRL_IFACE=y
-# Include interface for using external supplicant (Xsupplicant) for EAP
-# authentication
-#CONFIG_XSUPPLICANT_IFACE=y
-
# Include support for GNU Readline and History Libraries in wpa_cli.
# When building a wpa_cli binary for distribution, please note that these
# libraries are licensed under GPL and as such, BSD license may not apply for
# the resulting binary.
#CONFIG_READLINE=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf)
+CONFIG_BACKEND=file
diff --git a/contrib/wpa_supplicant/defs.h b/contrib/wpa_supplicant/defs.h
index a5a515c..6f9881d 100644
--- a/contrib/wpa_supplicant/defs.h
+++ b/contrib/wpa_supplicant/defs.h
@@ -1,14 +1,131 @@
+/*
+ * WPA Supplicant - Common definitions
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 DEFS_H
#define DEFS_H
-#ifdef CONFIG_NATIVE_WINDOWS
#ifdef FALSE
#undef FALSE
#endif
#ifdef TRUE
#undef TRUE
#endif
-#endif /* CONFIG_NATIVE_WINDOWS */
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 { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
+ CIPHER_WEP104 } wpa_cipher;
+typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
+ KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt;
+
+/**
+ * enum wpa_states - wpa_supplicant state
+ *
+ * These enumeration values are used to indicate the current wpa_supplicant
+ * state (wpa_s->wpa_state). The current state can be retrieved with
+ * wpa_supplicant_get_state() function and the state can be changed by calling
+ * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the
+ * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used
+ * to access the state variable.
+ */
+typedef enum {
+ /**
+ * WPA_DISCONNECTED - Disconnected state
+ *
+ * This state indicates that client is not associated, but is likely to
+ * start looking for an access point. This state is entered when a
+ * connection is lost.
+ */
+ WPA_DISCONNECTED,
+
+ /**
+ * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
+ *
+ * This state is entered if there are no enabled networks in the
+ * configuration. wpa_supplicant is not trying to associate with a new
+ * network and external interaction (e.g., ctrl_iface call to add or
+ * enable a network) is needed to start association.
+ */
+ WPA_INACTIVE,
+
+ /**
+ * WPA_SCANNING - Scanning for a network
+ *
+ * This state is entered when wpa_supplicant starts scanning for a
+ * network.
+ */
+ WPA_SCANNING,
+
+ /**
+ * WPA_ASSOCIATING - Trying to associate with a BSS/SSID
+ *
+ * This state is entered when wpa_supplicant has found a suitable BSS
+ * to associate with and the driver is configured to try to associate
+ * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
+ * state is entered when the driver is configured to try to associate
+ * with a network using the configured SSID and security policy.
+ */
+ WPA_ASSOCIATING,
+
+ /**
+ * WPA_ASSOCIATED - Association completed
+ *
+ * This state is entered when the driver reports that association has
+ * been successfully completed with an AP. If IEEE 802.1X is used
+ * (with or without WPA/WPA2), wpa_supplicant remains in this state
+ * until the IEEE 802.1X/EAPOL authentication has been completed.
+ */
+ WPA_ASSOCIATED,
+
+ /**
+ * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
+ *
+ * This state is entered when WPA/WPA2 4-Way Handshake is started. In
+ * case of WPA-PSK, this happens when receiving the first EAPOL-Key
+ * frame after association. In case of WPA-EAP, this state is entered
+ * when the IEEE 802.1X/EAPOL authentication has been completed.
+ */
+ WPA_4WAY_HANDSHAKE,
+
+ /**
+ * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
+ *
+ * This state is entered when 4-Way Key Handshake has been completed
+ * (i.e., when the supplicant sends out message 4/4) and when Group
+ * Key rekeying is started by the AP (i.e., when supplicant receives
+ * message 1/2).
+ */
+ WPA_GROUP_HANDSHAKE,
+
+ /**
+ * WPA_COMPLETED - All authentication completed
+ *
+ * This state is entered when the full authentication process is
+ * completed. In case of WPA2, this happens when the 4-Way Handshake is
+ * successfully completed. With WPA, this state is entered after the
+ * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
+ * completed after dynamic keys are received (or if not used, after
+ * the EAP authentication has been completed). With static WEP keys and
+ * plaintext connections, this state is entered when an association
+ * has been completed.
+ *
+ * This state indicates that the supplicant has completed its
+ * processing for the association phase and that data connection is
+ * fully configured.
+ */
+ WPA_COMPLETED
+} wpa_states;
+
#endif /* DEFS_H */
diff --git a/contrib/wpa_supplicant/doc/code_structure.doxygen b/contrib/wpa_supplicant/doc/code_structure.doxygen
new file mode 100644
index 0000000..6a32e59
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/code_structure.doxygen
@@ -0,0 +1,264 @@
+/**
+\page code_structure Structure of the source code
+
+[ \ref wpa_supplicant_core "wpa_supplicant core functionality" |
+\ref generic_helper_func "Generic helper functions" |
+\ref crypto_func "Cryptographic functions" |
+\ref configuration "Configuration" |
+\ref ctrl_iface "Control interface" |
+\ref wpa_code "WPA supplicant" |
+\ref eap_peer "EAP peer" |
+\ref eapol_supp "EAPOL supplicant" |
+\ref win_port "Windows port" |
+\ref test_programs "Test programs" ]
+
+%wpa_supplicant implementation is divided into number of independent
+modules. Core code includes functionality for controlling the network
+selection, association, and configuration. Independent modules include
+WPA code (key handshake, PMKSA caching, pre-authentication), EAPOL
+state machine, and EAP state machine and methods. In addition, there
+are number of separate files for generic helper functions.
+
+Both WPA and EAPOL/EAP state machines can be used separately in other
+programs than %wpa_supplicant. As an example, the included test
+programs eapol_test and preauth_test are using these modules.
+
+\ref driver_wrapper "Driver interface API" is defined in driver.h and
+all hardware/driver dependent functionality is implemented in
+driver_*.c.
+
+
+\section wpa_supplicant_core wpa_supplicant core functionality
+
+wpa_supplicant.c
+ Program initialization, main control loop
+
+main.c
+ main() for UNIX-like operating systems and MinGW (Windows); this
+ uses command line arguments to configure wpa_supplicant
+
+events.c
+ Driver event processing; wpa_supplicant_event() and related functions
+
+wpa_supplicant_i.h
+ Internal definitions for %wpa_supplicant core; should not be
+ included into independent modules
+
+wpa_supplicant.h
+ Definitions for driver event data and message logging
+
+
+\section generic_helper_func Generic helper functions
+
+%wpa_supplicant uses generic helper functions some of which are shared
+with with hostapd. The following C files are currently used:
+
+eloop.c and eloop.h
+ Event loop (select() loop with registerable timeouts, socket read
+ callbacks, and signal callbacks)
+
+common.c and common.h
+ Common helper functions
+
+defs.h
+ Definitions shared by multiple files
+
+l2_packet.h, l2_packet_linux.c, and l2_packet_pcap.c
+ Layer 2 (link) access wrapper (includes native Linux implementation
+ and wrappers for libdnet/libpcap). A new l2_packet implementation
+ may need to be added when porting to new operating systems that are
+ not supported by libdnet/libpcap. Makefile can be used to select which
+ l2_packet implementation is included. l2_packet_linux.c uses Linux
+ packet sockets and l2_packet_pcap.c has a more portable version using
+ libpcap and libdnet.
+
+pcsc_funcs.c and pcsc_funcs.h
+ Wrapper for PC/SC lite SIM and smart card readers
+
+priv_netlink.h
+ Private version of netlink definitions from Linux kernel header files;
+ this could be replaced with C library header file once suitable
+ version becomes commonly available
+
+version.h
+ Version number definitions
+
+wireless_copy.h
+ Private version of Linux wireless extensions definitions from kernel
+ header files; this could be replaced with C library header file once
+ suitable version becomes commonly available
+
+
+\section crypto_func Cryptographic functions
+
+md5.c and md5.h
+ MD5 (replaced with a crypto library if TLS support is included)
+ HMAC-MD5 (keyed checksum for message authenticity validation)
+
+rc4.c and rc4.h
+ RC4 (broadcast/default key encryption)
+
+sha1.c and sha1.h
+ SHA-1 (replaced with a crypto library if TLS support is included)
+ HMAC-SHA-1 (keyed checksum for message authenticity validation)
+ PRF-SHA-1 (pseudorandom (key/nonce generation) function)
+ PBKDF2-SHA-1 (ASCII passphrase to shared secret)
+ T-PRF (for EAP-FAST)
+ TLS-PRF (RFC 2246)
+
+aes_wrap.c, aes_wrap.h, aes.c
+ AES (replaced with a crypto library if TLS support is included),
+ AES Key Wrap Algorithm with 128-bit KEK, RFC3394 (broadcast/default
+ key encryption),
+ One-Key CBC MAC (OMAC1) hash with AES-128,
+ AES-128 CTR mode encryption,
+ AES-128 EAX mode encryption/decryption,
+ AES-128 CBC
+
+crypto.h
+ Definition of crypto library wrapper
+
+crypto.c
+ Wrapper functions for libcrypto (OpenSSL)
+
+crypto_gnutls.c
+ Wrapper functions for libgcrypt (used by GnuTLS)
+
+ms_funcs.c and ms_funcs.h
+ Helper functions for MSCHAPV2 and LEAP
+
+tls.h
+ Definition of TLS library wrapper
+
+tls_none.c
+ Dummy implementation of TLS library wrapper for cases where TLS
+ functionality is not included.
+
+tls_openssl.c
+ TLS library wrapper for openssl
+
+tls_gnutls.c
+ TLS library wrapper for GnuTLS
+
+
+\section configuration Configuration
+
+config_ssid.h
+ Definition of per network configuration items
+
+config.h
+ Definition of the %wpa_supplicant configuration
+
+config.c
+ Configuration parser and common functions
+
+config_file.c
+ Configuration backend for text files (e.g., wpa_supplicant.conf)
+
+
+\section ctrl_iface Control interface
+
+%wpa_supplicant has a \ref ctrl_iface_page "control interface"
+that can be used to get status
+information and manage operations from external programs. An example
+command line interface (wpa_cli) and GUI (wpa_gui) for this interface
+are included in the %wpa_supplicant distribution.
+
+ctrl_iface.c and ctrl_iface.h
+ %wpa_supplicant-side of the control interface
+
+wpa_ctrl.c and wpa_ctrl.h
+ Library functions for external programs to provide access to the
+ %wpa_supplicant control interface
+
+wpa_cli.c
+ Example program for using %wpa_supplicant control interface
+
+
+\section wpa_code WPA supplicant
+
+wpa.c and wpa.h
+ WPA state machine and 4-Way/Group Key Handshake processing
+
+preauth.c and preauth.h
+ PMKSA caching and pre-authentication (RSN/WPA2)
+
+wpa_i.h
+ Internal definitions for WPA code; not to be included to other modules.
+
+\section eap_peer EAP peer
+
+\ref eap_module "EAP peer implementation" is a separate module that
+can be used by other programs than just %wpa_supplicant.
+
+eap.c and eap.h
+ EAP state machine and method interface
+
+eap_defs.h
+ Common EAP definitions
+
+eap_i.h
+ Internal definitions for EAP state machine and EAP methods; not to be
+ included in other modules
+
+eap_sim_common.c and eap_sim_common.h
+ Common code for EAP-SIM and EAP-AKA
+
+eap_tls_common.c and eap_tls_common.h
+ Common code for EAP-PEAP, EAP-TTLS, and EAP-FAST
+
+eap_tlv.c and eap_tlv.h
+ EAP-TLV code for EAP-PEAP and EAP-FAST
+
+eap_ttls.c and eap_ttls.h
+ EAP-TTLS
+
+eap_pax.c, eap_pax_common.h, eap_pax_common.c
+ EAP-PAX
+
+eap_psk.c, eap_psk_common.h, eap_psk_common.c
+ EAP-PSK (note: this is not needed for WPA-PSK)
+
+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
+
+
+\section eapol_supp EAPOL supplicant
+
+eapol_sm.c and eapol_sm.h
+ EAPOL supplicant state machine and IEEE 802.1X processing
+
+
+\section win_port Windows port
+
+ndis_events.cpp
+ External program for receiving NdisMIndicateStatus() events and
+ delivering them to %wpa_supplicant in more easier to use form
+
+win_if_list.c
+ External program for listing current network interface
+
+
+\section test_programs Test programs
+
+radius_client.c and radius_client.h
+ RADIUS authentication client implementation for eapol_test
+
+radius.c and radius.h
+ RADIUS message processing for eapol_test
+
+config_types.h and hostapd.h
+ Minimal version of hostapd header files for eapol_test
+
+eapol_test.c
+ Standalone EAP testing tool with integrated RADIUS authentication
+ client
+
+preauth_test.c
+ Standalone RSN pre-authentication tool
+
+wpa_passphrase.c
+ WPA ASCII passphrase to PSK conversion
+
+*/
diff --git a/contrib/wpa_supplicant/doc/ctrl_iface.doxygen b/contrib/wpa_supplicant/doc/ctrl_iface.doxygen
new file mode 100644
index 0000000..fd1b9c4
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/ctrl_iface.doxygen
@@ -0,0 +1,409 @@
+/**
+\page ctrl_iface_page Control interface
+
+%wpa_supplicant implements a control interface that can be used by
+external programs to control the operations of the %wpa_supplicant
+daemon and to get status information and event notifications. There is
+a small C library, in a form of a single C file, wpa_ctrl.c, that
+provides helper functions to facilitate the use of the control
+interface. External programs can link this file into them and then use
+the library functions documented in wpa_ctrl.h to interact with
+%wpa_supplicant. This library can also be used with C++. wpa_cli.c and
+wpa_gui are example programs using this library.
+
+There are multiple mechanisms for inter-process communication. For
+example, Linux version of %wpa_supplicant is using UNIX domain sockets
+for the control interface and Windows version UDP sockets. The use of
+the functions defined in wpa_ctrl.h can be used to hide the details of
+the used IPC from external programs.
+
+
+\section using_ctrl_iface Using the control interface
+
+External programs, e.g., a GUI or a configuration utility, that need to
+communicate with %wpa_supplicant should link in wpa_ctrl.c. This
+allows them to use helper functions to open connection to the control
+interface with wpa_ctrl_open() and to send commands with
+wpa_ctrl_request().
+
+%wpa_supplicant uses the control interface for two types of communication:
+commands and unsolicited event messages. Commands are a pair of
+messages, a request from the external program and a response from
+%wpa_supplicant. These can be executed using wpa_ctrl_request().
+Unsolicited event messages are sent by %wpa_supplicant to the control
+interface connection without specific request from the external program
+for receiving each message. However, the external program needs to
+attach to the control interface with wpa_ctrl_attach() to receive these
+unsolicited messages.
+
+If the control interface connection is used both for commands and
+unsolicited event messages, there is potential for receiving an
+unsolicited message between the command request and response.
+wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+for processing these messages. Often it is easier to open two
+control interface connections by calling wpa_ctrl_open() twice and
+then use one of the connections for commands and the other one for
+unsolicited messages. This way command request/response pairs will
+not be broken by unsolicited messages. wpa_cli is an example of how
+to use only one connection for both purposes and wpa_gui demonstrates
+how to use two separate connections.
+
+Once the control interface connection is not needed anymore, it should
+be closed by calling wpa_ctrl_close(). If the connection was used for
+unsolicited event messages, it should be first detached by calling
+wpa_ctrl_detach().
+
+
+\section ctrl_iface_cmds Control interface commands
+
+Following commands can be used with wpa_ctrl_request():
+
+\subsection ctrl_iface_PING PING
+
+This command can be used to test whether %wpa_supplicant is replying
+to the control interface commands. The expected reply is \c PONG if the
+connection is open and %wpa_supplicant is processing commands.
+
+
+\subsection ctrl_iface_MIB MIB
+
+Request a list of MIB variables (dot1x, dot11). The output is a text
+block with each line in \c variable=value format. For example:
+
+\verbatim
+dot11RSNAOptionImplemented=TRUE
+dot11RSNAPreauthenticationImplemented=TRUE
+dot11RSNAEnabled=FALSE
+dot11RSNAPreauthenticationEnabled=FALSE
+dot11RSNAConfigVersion=1
+dot11RSNAConfigPairwiseKeysSupported=5
+dot11RSNAConfigGroupCipherSize=128
+dot11RSNAConfigPMKLifetime=43200
+dot11RSNAConfigPMKReauthThreshold=70
+dot11RSNAConfigNumberOfPTKSAReplayCounters=1
+dot11RSNAConfigSATimeout=60
+dot11RSNAAuthenticationSuiteSelected=00-50-f2-2
+dot11RSNAPairwiseCipherSelected=00-50-f2-4
+dot11RSNAGroupCipherSelected=00-50-f2-4
+dot11RSNAPMKIDUsed=
+dot11RSNAAuthenticationSuiteRequested=00-50-f2-2
+dot11RSNAPairwiseCipherRequested=00-50-f2-4
+dot11RSNAGroupCipherRequested=00-50-f2-4
+dot11RSNAConfigNumberOfGTKSAReplayCounters=0
+dot11RSNA4WayHandshakeFailures=0
+dot1xSuppPaeState=5
+dot1xSuppHeldPeriod=60
+dot1xSuppAuthPeriod=30
+dot1xSuppStartPeriod=30
+dot1xSuppMaxStart=3
+dot1xSuppSuppControlledPortStatus=Authorized
+dot1xSuppBackendPaeState=2
+dot1xSuppEapolFramesRx=0
+dot1xSuppEapolFramesTx=440
+dot1xSuppEapolStartFramesTx=2
+dot1xSuppEapolLogoffFramesTx=0
+dot1xSuppEapolRespFramesTx=0
+dot1xSuppEapolReqIdFramesRx=0
+dot1xSuppEapolReqFramesRx=0
+dot1xSuppInvalidEapolFramesRx=0
+dot1xSuppEapLengthErrorFramesRx=0
+dot1xSuppLastEapolFrameVersion=0
+dot1xSuppLastEapolFrameSource=00:00:00:00:00:00
+\endverbatim
+
+
+\subsection ctrl_iface_STATUS STATUS
+
+Request current WPA/EAPOL/EAP status information. The output is a text
+block with each line in \c variable=value format. For example:
+
+\verbatim
+bssid=02:00:01:02:03:04
+ssid=test network
+pairwise_cipher=CCMP
+group_cipher=CCMP
+key_mgmt=WPA-PSK
+wpa_state=COMPLETED
+ip_address=192.168.1.21
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+EAP state=SUCCESS
+\endverbatim
+
+
+\subsection ctrl_iface_STATUS-VERBOSE STATUS-VERBOSE
+
+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
+pairwise_cipher=CCMP
+group_cipher=CCMP
+key_mgmt=WPA-PSK
+wpa_state=COMPLETED
+ip_address=192.168.1.21
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+heldPeriod=60
+authPeriod=30
+startPeriod=30
+maxStart=3
+portControl=Auto
+Supplicant Backend state=IDLE
+EAP state=SUCCESS
+reqMethod=0
+methodState=NONE
+decision=COND_SUCC
+ClientTimeout=60
+\endverbatim
+
+
+\subsection ctrl_iface_PMKSA PMKSA
+
+Show PMKSA cache
+
+\verbatim
+Index / AA / PMKID / expiration (in seconds) / opportunistic
+1 / 02:00:01:02:03:04 / 000102030405060708090a0b0c0d0e0f / 41362 / 0
+2 / 02:00:01:33:55:77 / 928389281928383b34afb34ba4212345 / 362 / 1
+\endverbatim
+
+
+\subsection ctrl_iface_SET SET <variable> <value>
+
+Set variables:
+- EAPOL::heldPeriod
+- EAPOL::authPeriod
+- EAPOL::startPeriod
+- EAPOL::maxStart
+- dot11RSNAConfigPMKLifetime
+- dot11RSNAConfigPMKReauthThreshold
+- dot11RSNAConfigSATimeout
+
+Example command:
+\verbatim
+SET EAPOL::heldPeriod 45
+\endverbatim
+
+
+\subsection ctrl_iface_LOGON LOGON
+
+IEEE 802.1X EAPOL state machine logon.
+
+
+\subsection ctrl_iface_LOGOFF LOGOFF
+
+IEEE 802.1X EAPOL state machine logoff.
+
+
+\subsection ctrl_iface_REASSOCIATE REASSOCIATE
+
+Force reassociation.
+
+
+\subsection ctrl_iface_PREAUTH PREAUTH <BSSID>
+
+Start pre-authentication with the given BSSID.
+
+
+\subsection ctrl_iface_ATTACH ATTACH
+
+Attach the connection as a monitor for unsolicited events. This can
+be done with wpa_ctrl_attach().
+
+
+\subsection ctrl_iface_DETACH DETACH
+
+Detach the connection as a monitor for unsolicited events. This can
+be done with wpa_ctrl_detach().
+
+
+\subsection ctrl_iface_LEVEL LEVEL <debug level>
+
+Change debug level.
+
+
+\subsection ctrl_iface_RECONFIGURE RECONFIGURE
+
+Force %wpa_supplicant to re-read its configuration data.
+
+
+\subsection ctrl_iface_TERMINATE TERMINATE
+
+Terminate %wpa_supplicant process.
+
+
+\subsection ctrl_iface_BSSID BSSID <network id> <BSSID>
+
+Set preferred BSSID for a network. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_LIST_NETWORKS LIST_NETWORKS
+
+List configured networks.
+
+\verbatim
+network id / ssid / bssid / flags
+0 example network any [CURRENT]
+\endverbatim
+
+(note: fields are separated with tabs)
+
+
+\subsection ctrl_iface_DISCONNECT DISCONNECT
+
+Disconnect and wait for \c REASSOCIATE command before connecting.
+
+
+\subsection ctrl_iface_SCAN SCAN
+
+Request a new BSS scan.
+
+
+\subsection ctrl_iface_SCAN_RESULTS SCAN_RESULTS
+
+Get the latest scan results.
+
+\verbatim
+bssid / frequency / signal level / flags / ssid
+00:09:5b:95:e0:4e 2412 208 [WPA-PSK-CCMP] jkm private
+02:55:24:33:77:a3 2462 187 [WPA-PSK-TKIP] testing
+00:09:5b:95:e0:4f 2412 209 jkm guest
+\endverbatim
+
+(note: fields are separated with tabs)
+
+
+\subsection ctrl_iface_SELECT_NETWORK SELECT_NETWORK <network id>
+
+Select a network (disable others). Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_ENABLE_NETWORK ENABLE_NETWORK <network id>
+
+Enable a network. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_DISABLE_NETWORK DISABLE_NETWORK <network id>
+
+Disable a network. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_ADD_NETWORK ADD_NETWORK
+
+Add a new network. This command creates a new network with empty
+configuration. The new network is disabled and once it has been
+configured it can be enabled with \c ENABLE_NETWORK command. \c ADD_NETWORK
+returns the network id of the new network or FAIL on failure.
+
+
+\subsection ctrl_iface_REMOVE_NETWORK REMOVE_NETWORK <network id>
+
+Remove a network. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_SET_NETWORK SET_NETWORK <network id> <variable> <value>
+
+Set network variables. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+This command uses the same variables and data formats as the
+configuration file. See example wpa_supplicant.conf for more details.
+
+- ssid (network name, SSID)
+- psk (WPA passphrase or pre-shared key)
+- key_mgmt (key management protocol)
+- identity (EAP identity)
+- password (EAP password)
+- ...
+
+
+\subsection ctrl_iface_GET_NETWORK GET_NETWORK <network id> <variable>
+
+Get network variables. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_SAVE_CONFIG SAVE_CONFIG
+
+Save the current configuration.
+
+
+\section ctrl_iface_interactive Interactive requests
+
+If %wpa_supplicant needs additional information during authentication
+(e.g., password), it will use a specific prefix, \c CTRL-REQ-
+(\a WPA_CTRL_REQ macro) in an unsolicited event message. An external
+program, e.g., a GUI, can provide such information by using
+\c CTRL-RSP- (\a WPA_CTRL_RSP macro) prefix in a command with matching
+field name.
+
+The following fields can be requested in this way from the user:
+- IDENTITY (EAP identity/user name)
+- PASSWORD (EAP password)
+- NEW_PASSWORD (New password if the server is requesting password change)
+- PIN (PIN code for accessing a SIM or smartcard)
+- OTP (one-time password; like password, but the value is used only once)
+- PASSPHRASE (passphrase for a private key file)
+
+\verbatim
+CTRL-REQ-<field name>-<network id>-<human readable text>
+CTRL-RSP-<field name>-<network id>-<value>
+\endverbatim
+
+For example, request from %wpa_supplicant:
+\verbatim
+CTRL-REQ-PASSWORD-1-Password needed for SSID test-network
+\endverbatim
+
+And a matching reply from the GUI:
+\verbatim
+CTRL-RSP-PASSWORD-1-secret
+\endverbatim
+
+
+\subsection ctrl_iface_GET_CAPABILITY GET_CAPABILITY <option>
+
+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.
+
+Example request/reply pairs:
+
+\verbatim
+GET_CAPABILITY eap
+AKA FAST GTC LEAP MD5 MSCHAPV2 OTP PAX PEAP PSK SIM TLS TTLS
+\endverbatim
+
+\verbatim
+GET_CAPABILITY pairwise
+CCMP TKIP NONE
+\endverbatim
+
+\verbatim
+GET_CAPABILITY group
+CCMP TKIP WEP104 WEP40
+\endverbatim
+
+\verbatim
+GET_CAPABILITY key_mgmt
+WPA-PSK WPA-EAP IEEE8021X NONE
+\endverbatim
+
+\verbatim
+GET_CAPABILITY proto
+RSN WPA
+\endverbatim
+
+\verbatim
+GET_CAPABILITY auth_alg
+OPEN SHARED LEAP
+\endverbatim
+
+*/
diff --git a/contrib/wpa_supplicant/doc/docbook/Makefile b/contrib/wpa_supplicant/doc/docbook/Makefile
new file mode 100644
index 0000000..15c019c
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/Makefile
@@ -0,0 +1,25 @@
+all: man html pdf
+
+FILES += wpa_background
+FILES += wpa_cli
+FILES += wpa_passphrase
+FILES += wpa_supplicant.conf
+FILES += wpa_supplicant
+
+man:
+ for i in $(FILES); do docbook2man $$i.sgml; done
+
+html:
+ for i in $(FILES); do docbook2html $$i.sgml && \
+ mv index.html $$i.html; done
+
+pdf:
+ for i in $(FILES); do docbook2pdf $$i.sgml; done
+
+
+clean:
+ rm -f wpa_background.8 wpa_cli.8 wpa_passphrase.8 wpa_supplicant.8
+ rm -f wpa_supplicant.conf.5
+ rm -f manpage.links manpage.refs
+ rm -f $(FILES:%=%.pdf)
+ rm -f $(FILES:%=%.html)
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_background.8 b/contrib/wpa_supplicant/doc/docbook/wpa_background.8
new file mode 100644
index 0000000..3a7be28
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_background.8
@@ -0,0 +1,84 @@
+.\" This manpage has been automatically generated by docbook2man
+.\" from a DocBook document. This tool can be found at:
+.\" <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" "" ""
+
+.SH NAME
+wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i
+.SH "WPA"
+.PP
+The original security mechanism of IEEE 802.11 standard was
+not designed to be strong and has proven to be insufficient for
+most networks that require some kind of security. Task group I
+(Security) of IEEE 802.11 working group
+(http://www.ieee802.org/11/) has worked to address the flaws of
+the base standard and has in practice completed its work in May
+2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was
+approved in June 2004 and published in July 2004.
+.PP
+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version
+of the IEEE 802.11i work (draft 3.0) to define a subset of the
+security enhancements that can be implemented with existing wlan
+hardware. This is called Wi-Fi Protected Access<TM> (WPA). This
+has now become a mandatory component of interoperability testing
+and certification done by Wi-Fi Alliance. Wi-Fi provides
+information about WPA at its web site
+(http://www.wi-fi.org/OpenSection/protected_access.asp).
+.PP
+IEEE 802.11 standard defined wired equivalent privacy (WEP)
+algorithm for protecting wireless networks. WEP uses RC4 with
+40-bit keys, 24-bit initialization vector (IV), and CRC32 to
+protect against packet forgery. All these choices have proven to
+be insufficient: key space is too small against current attacks,
+RC4 key scheduling is insufficient (beginning of the pseudorandom
+stream should be skipped), IV space is too small and IV reuse
+makes attacks easier, there is no replay protection, and non-keyed
+authentication does not protect against bit flipping packet
+data.
+.PP
+WPA is an intermediate solution for the security issues. It
+uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP
+is a compromise on strong security and possibility to use existing
+hardware. It still uses RC4 for the encryption like WEP, but with
+per-packet RC4 keys. In addition, it implements replay protection,
+keyed packet authentication mechanism (Michael MIC).
+.PP
+Keys can be managed using two different mechanisms. WPA can
+either use an external authentication server (e.g., RADIUS) and
+EAP just like IEEE 802.1X is using or pre-shared keys without need
+for additional servers. Wi-Fi calls these "WPA-Enterprise" and
+"WPA-Personal", respectively. Both mechanisms will generate a
+master session key for the Authenticator (AP) and Supplicant
+(client station).
+.PP
+WPA implements a new key handshake (4-Way Handshake and
+Group Key Handshake) for generating and exchanging data encryption
+keys between the Authenticator and Supplicant. This handshake is
+also used to verify that both Authenticator and Supplicant know
+the master session key. These handshakes are identical regardless
+of the selected key management mechanism (only the method for
+generating master session key changes).
+.SH "IEEE 802.11I / WPA2"
+.PP
+The design for parts of IEEE 802.11i that were not included
+in WPA has finished (May 2004) and this amendment to IEEE 802.11
+was approved in June 2004. Wi-Fi Alliance is using the final IEEE
+802.11i as a new version of WPA called WPA2. This includes, e.g.,
+support for more robust encryption algorithm (CCMP: AES in Counter
+mode with CBC-MAC) to replace TKIP and optimizations for handoff
+(reduced number of messages in initial key handshake,
+pre-authentication, and PMKSA caching).
+.SH "SEE ALSO"
+.PP
+\fBwpa_supplicant\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2005,
+Jouni Malinen <jkmaline@cc.hut.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is dual-licensed under both the GPL version 2
+and BSD license. Either license may be used at your option.
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_background.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_background.sgml
new file mode 100644
index 0000000..dc64360
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_background.sgml
@@ -0,0 +1,101 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refmeta>
+ <refentrytitle>wpa_background</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_background</refname>
+ <refpurpose>Background information on Wi-Fi Protected Access and IEEE 802.11i</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>WPA</title>
+
+ <para>The original security mechanism of IEEE 802.11 standard was
+ not designed to be strong and has proven to be insufficient for
+ most networks that require some kind of security. Task group I
+ (Security) of IEEE 802.11 working group
+ (http://www.ieee802.org/11/) has worked to address the flaws of
+ the base standard and has in practice completed its work in May
+ 2004. The IEEE 802.11i amendment to the IEEE 802.11 standard was
+ approved in June 2004 and published in July 2004.</para>
+
+ <para>Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version
+ of the IEEE 802.11i work (draft 3.0) to define a subset of the
+ security enhancements that can be implemented with existing wlan
+ hardware. This is called Wi-Fi Protected Access&lt;TM&gt; (WPA). This
+ has now become a mandatory component of interoperability testing
+ and certification done by Wi-Fi Alliance. Wi-Fi provides
+ information about WPA at its web site
+ (http://www.wi-fi.org/OpenSection/protected_access.asp).</para>
+
+ <para>IEEE 802.11 standard defined wired equivalent privacy (WEP)
+ algorithm for protecting wireless networks. WEP uses RC4 with
+ 40-bit keys, 24-bit initialization vector (IV), and CRC32 to
+ protect against packet forgery. All these choices have proven to
+ be insufficient: key space is too small against current attacks,
+ RC4 key scheduling is insufficient (beginning of the pseudorandom
+ stream should be skipped), IV space is too small and IV reuse
+ makes attacks easier, there is no replay protection, and non-keyed
+ authentication does not protect against bit flipping packet
+ data.</para>
+
+ <para>WPA is an intermediate solution for the security issues. It
+ uses Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP
+ is a compromise on strong security and possibility to use existing
+ hardware. It still uses RC4 for the encryption like WEP, but with
+ per-packet RC4 keys. In addition, it implements replay protection,
+ keyed packet authentication mechanism (Michael MIC).</para>
+
+ <para>Keys can be managed using two different mechanisms. WPA can
+ either use an external authentication server (e.g., RADIUS) and
+ EAP just like IEEE 802.1X is using or pre-shared keys without need
+ for additional servers. Wi-Fi calls these "WPA-Enterprise" and
+ "WPA-Personal", respectively. Both mechanisms will generate a
+ master session key for the Authenticator (AP) and Supplicant
+ (client station).</para>
+
+ <para>WPA implements a new key handshake (4-Way Handshake and
+ Group Key Handshake) for generating and exchanging data encryption
+ keys between the Authenticator and Supplicant. This handshake is
+ also used to verify that both Authenticator and Supplicant know
+ the master session key. These handshakes are identical regardless
+ of the selected key management mechanism (only the method for
+ generating master session key changes).</para>
+ </refsect1>
+
+ <refsect1>
+ <title>IEEE 802.11i / WPA2</title>
+
+ <para>The design for parts of IEEE 802.11i that were not included
+ in WPA has finished (May 2004) and this amendment to IEEE 802.11
+ was approved in June 2004. Wi-Fi Alliance is using the final IEEE
+ 802.11i as a new version of WPA called WPA2. This includes, e.g.,
+ support for more robust encryption algorithm (CCMP: AES in Counter
+ mode with CBC-MAC) to replace TKIP and optimizations for handoff
+ (reduced number of messages in initial key handshake,
+ pre-authentication, and PMKSA caching).</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2005,
+ Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is dual-licensed under both the GPL version 2
+ and BSD license. Either license may be used at your option.</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_cli.8 b/contrib/wpa_supplicant/doc/docbook/wpa_cli.8
new file mode 100644
index 0000000..ad039b5
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_cli.8
@@ -0,0 +1,202 @@
+.\" This manpage has been automatically generated by docbook2man
+.\" from a DocBook document. This tool can be found at:
+.\" <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" "" ""
+
+.SH NAME
+wpa_cli \- WPA command line client
+.SH SYNOPSIS
+
+\fBwpa_cli\fR [ \fB-p \fIpath to ctrl sockets\fB\fR ] [ \fB-i \fIifname\fB\fR ] [ \fB-hvB\fR ] [ \fB-a \fIaction file\fB\fR ] [ \fB-P \fIpid file\fB\fR ] [ \fB\fIcommand ...\fB\fR ]
+
+.SH "OVERVIEW"
+.PP
+wpa_cli is a text-based frontend program for interacting
+with wpa_supplicant. It is used to query current status, change
+configuration, trigger events, and request interactive user
+input.
+.PP
+wpa_cli can show the current authentication status, selected
+security mode, dot11 and dot1x MIBs, etc. In addition, it can
+configure some variables like EAPOL state machine parameters and
+trigger events like reassociation and IEEE 802.1X
+logoff/logon. wpa_cli provides a user interface to request
+authentication information, like username and password, if these
+are not included in the configuration. This can be used to
+implement, e.g., one-time-passwords or generic token card
+authentication where the authentication is based on a
+challenge-response that uses an external device for generating the
+response.
+.PP
+The control interface of wpa_supplicant can be configured to
+allow non-root user access (ctrl_interface_group in the
+configuration file). This makes it possible to run wpa_cli with a
+normal user account.
+.PP
+wpa_cli supports two modes: interactive and command
+line. Both modes share the same command set and the main
+difference is in interactive mode providing access to unsolicited
+messages (event messages, username/password requests).
+.PP
+Interactive mode is started when wpa_cli is executed without
+including the command as a command line parameter. Commands are
+then entered on the wpa_cli prompt. In command line mode, the same
+commands are entered as command line arguments for wpa_cli.
+.SH "INTERACTIVE AUTHENTICATION PARAMETERS REQUEST"
+.PP
+When wpa_supplicant need authentication parameters, like
+username and password, which are not present in the configuration
+file, it sends a request message to all attached frontend programs,
+e.g., wpa_cli in interactive mode. wpa_cli shows these requests
+with "CTRL-REQ-<type>-<id>:<text>"
+prefix. <type> is IDENTITY, PASSWORD, or OTP
+(one-time-password). <id> is a unique identifier for the
+current network. <text> is description of the request. In
+case of OTP request, it includes the challenge from the
+authentication server.
+.PP
+The reply to these requests can be given with 'identity',
+'password', and 'otp' commands. <id> needs to be copied from the
+the matching request. 'password' and 'otp' commands can be used
+regardless of whether the request was for PASSWORD or OTP. The
+main difference between these two commands is that values given
+with 'password' are remembered as long as wpa_supplicant is
+running whereas values given with 'otp' are used only once and
+then forgotten, i.e., wpa_supplicant will ask frontend for a new
+value for every use. This can be used to implement
+one-time-password lists and generic token card -based
+authentication.
+.PP
+Example request for password and a matching reply:
+.sp
+.RS
+
+.nf
+CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
+> password 1 mysecretpassword
+.fi
+.RE
+.PP
+Example request for generic token card challenge-response:
+.sp
+.RS
+
+.nf
+CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
+> otp 2 9876
+.fi
+.RE
+.SH "COMMAND ARGUMENTS"
+.TP
+\fB-p path\fR
+Change the path where control sockets should
+be found.
+.TP
+\fB-i ifname\fR
+Specify the interface that is being
+configured. By default, choose the first interface found with
+a control socket in the socket path.
+.TP
+\fB-h\fR
+Help. Show a usage message.
+.TP
+\fB-v\fR
+Show version information.
+.TP
+\fB-B\fR
+Run as a daemon in the background.
+.TP
+\fB-a file\fR
+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
+.TP
+\fB-P file\fR
+Set the location of the PID
+file.
+.TP
+\fBcommand\fR
+Run a command. The available commands are
+listed in the next section.
+.SH "COMMANDS"
+.PP
+The following commands are available:
+.TP
+\fBstatus\fR
+get current WPA/EAPOL/EAP status
+.TP
+\fBmib\fR
+get MIB variables (dot1x, dot11)
+.TP
+\fBhelp\fR
+show this usage help
+.TP
+\fBinterface [ifname]\fR
+show interfaces/select interface
+.TP
+\fBlevel <debug level>\fR
+change debug level
+.TP
+\fBlicense\fR
+show full wpa_cli license
+.TP
+\fBlogoff\fR
+IEEE 802.1X EAPOL state machine logoff
+.TP
+\fBlogon\fR
+IEEE 802.1X EAPOL state machine logon
+.TP
+\fBset\fR
+set variables (shows list of variables when run without arguments)
+.TP
+\fBpmksa\fR
+show PMKSA cache
+.TP
+\fBreassociate\fR
+force reassociation
+.TP
+\fBreconfigure\fR
+force wpa_supplicant to re-read its configuration file
+.TP
+\fBpreauthenticate <BSSID>\fR
+force preauthentication
+.TP
+\fBidentity <network id> <identity>\fR
+configure identity for an SSID
+.TP
+\fBpassword <network id> <password>\fR
+configure password for an SSID
+.TP
+\fBpin <network id> <pin>\fR
+configure pin for an SSID
+.TP
+\fBotp <network id> <password>\fR
+configure one-time-password for an SSID
+.TP
+\fBbssid *lt;network id> <BSSID>\fR
+set preferred BSSID for an SSID
+.TP
+\fBlist_networks\fR
+list configured networks
+.TP
+\fBterminate\fR
+terminate \fBwpa_supplicant\fR
+.TP
+\fBquit\fR
+exit wpa_cli
+.SH "SEE ALSO"
+.PP
+\fBwpa_supplicant\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2005,
+Jouni Malinen <jkmaline@cc.hut.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is dual-licensed under both the GPL version 2
+and BSD license. Either license may be used at your option.
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml
new file mode 100644
index 0000000..e804239
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml
@@ -0,0 +1,330 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refmeta>
+ <refentrytitle>wpa_cli</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_cli</refname>
+
+ <refpurpose>WPA command line client</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>wpa_cli</command>
+ <arg>-p <replaceable>path to ctrl sockets</replaceable></arg>
+ <arg>-i <replaceable>ifname</replaceable></arg>
+ <arg>-hvB</arg>
+ <arg>-a <replaceable>action file</replaceable></arg>
+ <arg>-P <replaceable>pid file</replaceable></arg>
+ <arg><replaceable>command ...</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Overview</title>
+
+ <para>wpa_cli is a text-based frontend program for interacting
+ with wpa_supplicant. It is used to query current status, change
+ configuration, trigger events, and request interactive user
+ input.</para>
+
+ <para>wpa_cli can show the current authentication status, selected
+ security mode, dot11 and dot1x MIBs, etc. In addition, it can
+ configure some variables like EAPOL state machine parameters and
+ trigger events like reassociation and IEEE 802.1X
+ logoff/logon. wpa_cli provides a user interface to request
+ authentication information, like username and password, if these
+ are not included in the configuration. This can be used to
+ implement, e.g., one-time-passwords or generic token card
+ authentication where the authentication is based on a
+ challenge-response that uses an external device for generating the
+ response.</para>
+
+ <para>The control interface of wpa_supplicant can be configured to
+ allow non-root user access (ctrl_interface_group in the
+ configuration file). This makes it possible to run wpa_cli with a
+ normal user account.</para>
+
+ <para>wpa_cli supports two modes: interactive and command
+ line. Both modes share the same command set and the main
+ difference is in interactive mode providing access to unsolicited
+ messages (event messages, username/password requests).</para>
+
+ <para>Interactive mode is started when wpa_cli is executed without
+ including the command as a command line parameter. Commands are
+ then entered on the wpa_cli prompt. In command line mode, the same
+ commands are entered as command line arguments for wpa_cli.</para>
+ </refsect1>
+ <refsect1>
+ <title>Interactive authentication parameters request</title>
+
+ <para>When wpa_supplicant need authentication parameters, like
+ username and password, which are not present in the configuration
+ file, it sends a request message to all attached frontend programs,
+ e.g., wpa_cli in interactive mode. wpa_cli shows these requests
+ with "CTRL-REQ-&lt;type&gt;-&lt;id&gt;:&lt;text&gt;"
+ prefix. &lt;type&gt; is IDENTITY, PASSWORD, or OTP
+ (one-time-password). &lt;id&gt; is a unique identifier for the
+ current network. &lt;text&gt; is description of the request. In
+ case of OTP request, it includes the challenge from the
+ authentication server.</para>
+
+ <para>The reply to these requests can be given with 'identity',
+ 'password', and 'otp' commands. &lt;id&gt; needs to be copied from the
+ the matching request. 'password' and 'otp' commands can be used
+ regardless of whether the request was for PASSWORD or OTP. The
+ main difference between these two commands is that values given
+ with 'password' are remembered as long as wpa_supplicant is
+ running whereas values given with 'otp' are used only once and
+ then forgotten, i.e., wpa_supplicant will ask frontend for a new
+ value for every use. This can be used to implement
+ one-time-password lists and generic token card -based
+ authentication.</para>
+
+ <para>Example request for password and a matching reply:</para>
+
+<blockquote><programlisting>
+CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
+> password 1 mysecretpassword
+</programlisting></blockquote>
+
+ <para>Example request for generic token card challenge-response:</para>
+
+<blockquote><programlisting>
+CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
+> otp 2 9876
+</programlisting></blockquote>
+
+ </refsect1>
+ <refsect1>
+ <title>Command Arguments</title>
+ <variablelist>
+ <varlistentry>
+ <term>-p path</term>
+
+ <listitem><para>Change the path where control sockets should
+ be found.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i ifname</term>
+
+ <listitem><para>Specify the interface that is being
+ configured. By default, choose the first interface found with
+ a control socket in the socket path.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem><para>Help. Show a usage message.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-v</term>
+ <listitem><para>Show version information.</para></listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term>-B</term>
+ <listitem><para>Run as a daemon in the background.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-a file</term>
+
+ <listitem><para>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 </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-P file</term>
+
+ <listitem><para>Set the location of the PID
+ file.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>command</term>
+
+ <listitem><para>Run a command. The available commands are
+ listed in the next section.</para></listitem>
+
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>Commands</title>
+ <para>The following commands are available:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>status</term>
+ <listitem>
+ <para>get current WPA/EAPOL/EAP status</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>mib</term>
+ <listitem>
+ <para>get MIB variables (dot1x, dot11)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>help</term>
+ <listitem>
+ <para>show this usage help</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>interface [ifname]</term>
+ <listitem>
+ <para>show interfaces/select interface</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>level &lt;debug level&gt;</term>
+ <listitem>
+ <para>change debug level</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>license</term>
+ <listitem>
+ <para>show full wpa_cli license</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>logoff</term>
+ <listitem>
+ <para>IEEE 802.1X EAPOL state machine logoff</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>logon</term>
+ <listitem>
+ <para>IEEE 802.1X EAPOL state machine logon</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>set</term>
+ <listitem>
+ <para>set variables (shows list of variables when run without arguments)</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>pmksa</term>
+ <listitem>
+ <para>show PMKSA cache</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>reassociate</term>
+ <listitem>
+ <para>force reassociation</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>reconfigure</term>
+ <listitem>
+ <para>force wpa_supplicant to re-read its configuration file</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>preauthenticate &lt;BSSID&gt;</term>
+ <listitem>
+ <para>force preauthentication</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>identity &lt;network id&gt; &lt;identity&gt;</term>
+ <listitem>
+ <para>configure identity for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>password &lt;network id&gt; &lt;password&gt;</term>
+ <listitem>
+ <para>configure password for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>pin &lt;network id&gt; &lt;pin&gt;</term>
+ <listitem>
+ <para>configure pin for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>otp &lt;network id&gt; &lt;password&gt;</term>
+ <listitem>
+ <para>configure one-time-password for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>bssid *lt;network id&gt; &lt;BSSID&gt;</term>
+ <listitem>
+ <para>set preferred BSSID for an SSID</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>list_networks</term>
+ <listitem>
+ <para>list configured networks</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>terminate</term>
+ <listitem>
+ <para>terminate <command>wpa_supplicant</command></para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>quit</term>
+ <listitem><para>exit wpa_cli</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2005,
+ Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is dual-licensed under both the GPL version 2
+ and BSD license. Either license may be used at your option.</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8 b/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8
new file mode 100644
index 0000000..11e0f85
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8
@@ -0,0 +1,39 @@
+.\" This manpage has been automatically generated by docbook2man
+.\" from a DocBook document. This tool can be found at:
+.\" <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" "" ""
+
+.SH NAME
+wpa_passphrase \- Set WPA passphrase for a SSID
+.SH SYNOPSIS
+
+\fBwpa_passphrase\fR [ \fB\fIssid\fB\fR ] [ \fB\fIpassphrase\fB\fR ]
+
+.SH "OVERVIEW"
+.PP
+\fBwpa_passphrase\fR pre-computes PSK entries for
+network configuration blocks of a
+\fIwpa_supplicant.conf\fR file.
+.SH "OPTIONS"
+.TP
+\fBssid\fR
+The SSID whose passphrase should be derived.
+.TP
+\fBpassphrase\fR
+The passphrase to use. If not included on the command line,
+passphrase will be read from standard input.
+.SH "SEE ALSO"
+.PP
+\fBwpa_supplicant.conf\fR(5)
+\fBwpa_supplicant\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2005,
+Jouni Malinen <jkmaline@cc.hut.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is dual-licensed under both the GPL version 2
+and BSD license. Either license may be used at your option.
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
new file mode 100644
index 0000000..1380a74
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml
@@ -0,0 +1,72 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refmeta>
+ <refentrytitle>wpa_passphrase</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_passphrase</refname>
+ <refpurpose>Set WPA passphrase for a SSID</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>wpa_passphrase</command>
+ <arg><replaceable>ssid</replaceable></arg>
+ <arg><replaceable>passphrase</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Overview</title>
+
+ <para><command>wpa_passphrase</command> pre-computes PSK entries for
+ network configuration blocks of a
+ <filename>wpa_supplicant.conf</filename> file.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Options</title>
+ <variablelist>
+ <varlistentry>
+ <term>ssid</term>
+ <listitem>
+ <para>The SSID whose passphrase should be derived.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>passphrase</term>
+ <listitem>
+ <para>The passphrase to use. If not included on the command line,
+ passphrase will be read from standard input.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2005,
+ Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is dual-licensed under both the GPL version 2
+ and BSD license. Either license may be used at your option.</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8 b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8
new file mode 100644
index 0000000..fcd738b
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8
@@ -0,0 +1,544 @@
+.\" This manpage has been automatically generated by docbook2man
+.\" from a DocBook document. This tool can be found at:
+.\" <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" "" ""
+
+.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 ]
+
+.SH "OVERVIEW"
+.PP
+Wireless networks do not require physical access to the network equipment
+in the same way as wired networks. This makes it easier for unauthorized
+users to passively monitor a network and capture all transmitted frames.
+In addition, unauthorized use of the network is much easier. In many cases,
+this can happen even without user's explicit knowledge since the wireless
+LAN adapter may have been configured to automatically join any available
+network.
+.PP
+Link-layer encryption can be used to provide a layer of security for
+wireless networks. The original wireless LAN standard, IEEE 802.11,
+included a simple encryption mechanism, WEP. However, that proved to
+be flawed in many areas and network protected with WEP cannot be consider
+secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys
+can be used to improve the network security, but even that has inherited
+security issues due to the use of WEP for encryption. Wi-Fi Protected
+Access and IEEE 802.11i amendment to the wireless LAN standard introduce
+a much improvement mechanism for securing wireless networks. IEEE 802.11i
+enabled networks that are using CCMP (encryption mechanism based on strong
+cryptographic algorithm AES) can finally be called secure used for
+applications which require efficient protection against unauthorized
+access.
+.PP
+\fBwpa_supplicant\fR is an implementation of
+the WPA Supplicant component, i.e., the part that runs in the
+client stations. It implements WPA key negotiation with a WPA
+Authenticator and EAP authentication with Authentication
+Server. In addition, it controls the roaming and IEEE 802.11
+authentication/association of the wireless LAN driver.
+.PP
+\fBwpa_supplicant\fR is designed to be a
+"daemon" program that runs in the background and acts as the
+backend component controlling the wireless
+connection. \fBwpa_supplicant\fR supports separate
+frontend programs and an example text-based frontend,
+\fBwpa_cli\fR, is included with
+wpa_supplicant.
+.PP
+Before wpa_supplicant can do its work, the network interface
+must be available. That means that the physical device must be
+present and enabled, and the driver for the device must have be
+loaded. Note, however, that the '-w' option of the wpa_supplicant
+daemon instructs the daemon to continue running and to wait for
+the interface to become available. Without the '-w' option, the
+daemon will exit immediately if the device is not already
+available.
+.PP
+After \fBwpa_supplicant\fR has configured the
+network device, higher level configuration such as DHCP may
+proceed. There are a variety of ways to integrate wpa_supplicant
+into a machine's networking scripts, a few of which are described
+in sections below.
+.PP
+The following steps are used when associating with an AP
+using WPA:
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR requests the kernel
+driver to scan neighboring BSSes
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR selects a BSS based on
+its configuration
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR requests the kernel
+driver to associate with the chosen BSS
+.TP 0.2i
+\(bu
+If WPA-EAP: integrated IEEE 802.1X Supplicant or
+external Xsupplicant completes EAP authentication with the
+authentication server (proxied by the Authenticator in the
+AP)
+.TP 0.2i
+\(bu
+If WPA-EAP: master key is received from the IEEE 802.1X
+Supplicant
+.TP 0.2i
+\(bu
+If WPA-PSK: \fBwpa_supplicant\fR uses PSK
+as the master session key
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR completes WPA 4-Way
+Handshake and Group Key Handshake with the Authenticator
+(AP)
+.TP 0.2i
+\(bu
+\fBwpa_supplicant\fR configures encryption
+keys for unicast and broadcast
+.TP 0.2i
+\(bu
+normal data packets can be transmitted and received
+.SH "SUPPORTED FEATURES"
+.PP
+Supported WPA/IEEE 802.11i features:
+.TP 0.2i
+\(bu
+WPA-PSK ("WPA-Personal")
+.TP 0.2i
+\(bu
+WPA with EAP (e.g., with RADIUS authentication server)
+("WPA-Enterprise") Following authentication methods are
+supported with an integrate IEEE 802.1X Supplicant:
+.RS
+.TP 0.2i
+\(bu
+EAP-TLS
+.RE
+.RS
+.TP 0.2i
+\(bu
+EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-PEAP/TLS (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-PEAP/GTC (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-PEAP/OTP (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-MD5-Challenge
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-GTC
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-OTP
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-MSCHAPv2
+.TP 0.2i
+\(bu
+EAP-TTLS/EAP-TLS
+.TP 0.2i
+\(bu
+EAP-TTLS/MSCHAPv2
+.TP 0.2i
+\(bu
+EAP-TTLS/MSCHAP
+.TP 0.2i
+\(bu
+EAP-TTLS/PAP
+.TP 0.2i
+\(bu
+EAP-TTLS/CHAP
+.TP 0.2i
+\(bu
+EAP-SIM
+.TP 0.2i
+\(bu
+EAP-AKA
+.TP 0.2i
+\(bu
+EAP-PSK
+.TP 0.2i
+\(bu
+EAP-PAX
+.TP 0.2i
+\(bu
+LEAP (note: requires special support from
+the driver for IEEE 802.11 authentication)
+.TP 0.2i
+\(bu
+(following methods are supported, but since
+they do not generate keying material, they cannot be used
+with WPA or IEEE 802.1X WEP keying)
+.TP 0.2i
+\(bu
+EAP-MD5-Challenge
+.TP 0.2i
+\(bu
+EAP-MSCHAPv2
+.TP 0.2i
+\(bu
+EAP-GTC
+.TP 0.2i
+\(bu
+EAP-OTP
+.RE
+.TP 0.2i
+\(bu
+key management for CCMP, TKIP, WEP104, WEP40
+.TP 0.2i
+\(bu
+RSN/WPA2 (IEEE 802.11i)
+.RS
+.TP 0.2i
+\(bu
+pre-authentication
+.TP 0.2i
+\(bu
+PMKSA caching
+.RE
+.SH "AVAILABLE DRIVERS"
+.PP
+The available drivers to specify with the -D option are:
+.TP
+\fBhostap\fR
+(default) Host AP driver (Intersil Prism2/2.5/3).
+(this can also be used with Linuxant DriverLoader).
+.TP
+\fBhermes\fR
+Agere Systems Inc. driver (Hermes-I/Hermes-II).
+.TP
+\fBmadwifi\fR
+MADWIFI 802.11 support (Atheros, etc.).
+.TP
+\fBatmel\fR
+ATMEL AT76C5XXx (USB, PCMCIA).
+.TP
+\fBwext\fR
+Linux wireless extensions (generic).
+.TP
+\fBndiswrapper\fR
+Linux ndiswrapper.
+.TP
+\fBbroadcom\fR
+Broadcom wl.o driver.
+.TP
+\fBipw\fR
+Intel ipw2100/2200 driver.
+.TP
+\fBwired\fR
+wpa_supplicant wired Ethernet driver
+.TP
+\fBbsd\fR
+BSD 802.11 support (Atheros, etc.).
+.TP
+\fBndis\fR
+Windows NDIS driver.
+.SH "COMMAND LINE OPTIONS"
+.TP
+\fB-B\fR
+Run daemon in the background.
+.TP
+\fB-i ifname\fR
+Interface to listen on.
+.TP
+\fB-c filename\fR
+Path to configuration file.
+.TP
+\fB-D driver\fR
+Driver to use. See the available options below.
+.TP
+\fB-d\fR
+Increase debugging verbosity (-dd even more).
+.TP
+\fB-K\fR
+Include keys (passwords, etc.) in debug output.
+.TP
+\fB-t\fR
+Include timestamp in debug messages.
+.TP
+\fB-e\fR
+Use external IEEE 802.1X Supplicant (e.g.,
+\fBxsupplicant\fR) (this disables the internal
+Supplicant).
+.TP
+\fB-h\fR
+Help. Show a usage message.
+.TP
+\fB-L\fR
+Show license (GPL and BSD).
+.TP
+\fB-q\fR
+Decrease debugging verbosity (-qq even less).
+.TP
+\fB-v\fR
+Show version.
+.TP
+\fB-w\fR
+wait for interface to be added, if needed. normally,
+\fBwpa_supplicant\fR will exit if the interface
+is not there yet.
+.TP
+\fB-N\fR
+Start describing new interface.
+.SH "EXAMPLES"
+.PP
+In most common cases, \fBwpa_supplicant\fR is
+started with:
+.sp
+.RS
+
+.nf
+wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -iwlan0
+.fi
+.RE
+.PP
+This makes the process fork into background and wait for the wlan0
+interface if it is not available at startup time.
+.PP
+The easiest way to debug problems, and to get debug log for
+bug reports, is to start \fBwpa_supplicant\fR on
+foreground with debugging enabled:
+.sp
+.RS
+
+.nf
+wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
+.fi
+.RE
+.PP
+\fBwpa_supplicant\fR can control multiple
+interfaces (radios) either by running one process for each
+interface separately or by running just one process and list of
+options at command line. Each interface is separated with -N
+argument. As an example, following command would start
+wpa_supplicant for two interfaces:
+.sp
+.RS
+
+.nf
+wpa_supplicant \\
+ -c wpa1.conf -i wlan0 -D hostap -N \\
+ -c wpa2.conf -i ath0 -D madwifi
+.fi
+.RE
+.SH "OS REQUIREMENTS"
+.PP
+Current hardware/software requirements:
+.TP 0.2i
+\(bu
+Linux kernel 2.4.x or 2.6.x with Linux Wireless
+Extensions v15 or newer
+.TP 0.2i
+\(bu
+FreeBSD 6-CURRENT
+.TP 0.2i
+\(bu
+Microsoft Windows with WinPcap (at least WinXP, may work
+with other versions)
+.SH "SUPPORTED DRIVERS"
+.TP
+\fBHost AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)\fR
+(http://hostap.epitest.fi/) Driver needs to be set in
+Managed mode ('iwconfig wlan0 mode managed'). Please note
+that station firmware version needs to be 1.7.0 or newer to
+work in WPA mode.
+.TP
+\fBLinuxant DriverLoader\fR
+(http://www.linuxant.com/driverloader/)
+with Windows NDIS driver for your wlan card supporting WPA.
+.TP
+\fBAgere Systems Inc. Linux Driver\fR
+(http://www.agere.com/support/drivers/) Please note
+that the driver interface file (driver_hermes.c) and hardware
+specific include files are not included in the wpa_supplicant
+distribution. You will need to copy these from the source
+package of the Agere driver.
+.TP
+\fBmadwifi driver for cards based on Atheros chip set (ar521x)\fR
+(http://sourceforge.net/projects/madwifi/) Please
+note that you will need to modify the wpa_supplicant .config
+file to use the correct path for the madwifi driver root
+directory (CFLAGS += -I../madwifi/wpa line in example
+defconfig).
+.TP
+\fBATMEL AT76C5XXx driver for USB and PCMCIA cards\fR
+(http://atmelwlandriver.sourceforge.net/).
+.TP
+\fBLinux ndiswrapper\fR
+(http://ndiswrapper.sourceforge.net/) with Windows
+NDIS driver.
+.TP
+\fBBroadcom wl.o driver\fR
+This is a generic Linux driver for Broadcom IEEE
+802.11a/g cards. However, it is proprietary driver that is
+not publicly available except for couple of exceptions, mainly
+Broadcom-based APs/wireless routers that use Linux. The driver
+binary can be downloaded, e.g., from Linksys support site
+(http://www.linksys.com/support/gpl.asp) for Linksys
+WRT54G. The GPL tarball includes cross-compiler and the needed
+header file, wlioctl.h, for compiling wpa_supplicant. This
+driver support in wpa_supplicant is expected to work also with
+other devices based on Broadcom driver (assuming the driver
+includes client mode support).
+.TP
+\fB Intel ipw2100 driver\fR
+(http://sourceforge.net/projects/ipw2100/)
+.TP
+\fBIntel ipw2200 driver\fR
+(http://sourceforge.net/projects/ipw2200/)
+.TP
+\fBLinux wireless extensions\fR
+In theory, any driver that supports Linux wireless
+extensions can be used with IEEE 802.1X (i.e., not WPA) when
+using ap_scan=0 option in configuration file.
+.TP
+\fBWired Ethernet drivers\fR
+Use ap_scan=0.
+.TP
+\fBBSD net80211 layer (e.g., Atheros driver)\fR
+At the moment, this is for FreeBSD 6-CURRENT branch.
+.TP
+\fBWindows NDIS\fR
+The current Windows port requires WinPcap
+(http://winpcap.polito.it/). See README-Windows.txt for more
+information.
+.PP
+wpa_supplicant was designed to be portable for different
+drivers and operating systems. Hopefully, support for more wlan
+cards and OSes will be added in the future. See developer.txt for
+more information about the design of wpa_supplicant and porting to
+other drivers. One main goal is to add full WPA/WPA2 support to
+Linux wireless extensions to allow new drivers to be supported
+without having to implement new driver-specific interface code in
+wpa_supplicant.
+.SH "ARCHITECTURE"
+.PP
+The
+\fBwpa_supplicant\fR system consists of the following
+components:
+.TP
+\fB\fIwpa_supplicant.conf\fB \fR
+the configuration file describing all networks that the
+user wants the computer to connect to.
+.TP
+\fBwpa_supplicant\fR
+the program that directly interacts with the
+network interface.
+.TP
+\fBwpa_cli\fR
+the
+client program that provides a high-level interface to the
+functionality of the daemon.
+.TP
+\fBwpa_passphrase\fR
+a utility needed to construct
+\fIwpa_supplicant.conf\fR files that include
+encrypted passwords.
+.SH "QUICK START"
+.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)
+for details.
+.PP
+Once the configuration is ready, you can test whether the
+configuration works by running \fBwpa_supplicant\fR
+with following command to start it on foreground with debugging
+enabled:
+.sp
+.RS
+
+.nf
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
+
+.fi
+.RE
+.PP
+Assuming everything goes fine, you can start using following
+command to start \fBwpa_supplicant\fR on background
+without debugging:
+.sp
+.RS
+
+.nf
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
+
+.fi
+.RE
+.PP
+Please note that if you included more than one driver
+interface in the build time configuration (.config), you may need
+to specify which interface to use by including -D<driver
+name> option on the command line.
+.SH "INTERFACE TO PCMCIA-CS/CARDMRG"
+.PP
+For example, following small changes to pcmcia-cs scripts
+can be used to enable WPA support:
+.PP
+Add MODE="Managed" and WPA="y" to the network scheme in
+\fI/etc/pcmcia/wireless.opts\fR\&.
+.PP
+Add the following block to the end of 'start' action handler
+in \fI/etc/pcmcia/wireless\fR:
+.sp
+.RS
+
+.nf
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+ /usr/local/bin/wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -i$DEVICE
+fi
+
+.fi
+.RE
+.PP
+Add the following block to the end of 'stop' action handler
+(may need to be separated from other actions) in
+\fI/etc/pcmcia/wireless\fR:
+.sp
+.RS
+
+.nf
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+ killall wpa_supplicant
+fi
+
+.fi
+.RE
+.PP
+This will make \fBcardmgr\fR start
+\fBwpa_supplicant\fR when the card is plugged
+in. \fBwpa_supplicant\fR will wait until the
+interface is set up--either when a static IP address is configured
+or when DHCP client is started--and will then negotiate keys with
+the AP.
+.SH "SEE ALSO"
+.PP
+\fBwpa_background\fR(8)
+\fBwpa_supplicant.conf\fR(5)
+\fBwpa_cli\fR(8)
+\fBwpa_passphrase\fR(8)
+.SH "LEGAL"
+.PP
+wpa_supplicant is copyright (c) 2003-2005,
+Jouni Malinen <jkmaline@cc.hut.fi> and
+contributors.
+All Rights Reserved.
+.PP
+This program is dual-licensed under both the GPL version 2
+and BSD license. Either license may be used at your option.
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
new file mode 100644
index 0000000..d5e5c62
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
@@ -0,0 +1,230 @@
+.\" This manpage has been automatically generated by docbook2man
+.\" from a DocBook document. This tool can be found at:
+.\" <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" "" ""
+
+.SH NAME
+wpa_supplicant.conf \- configuration file for wpa_supplicant
+.SH "OVERVIEW"
+.PP
+\fBwpa_supplicant\fR is configured using a text
+file that lists all accepted networks and security policies,
+including pre-shared keys. See the example configuration file,
+probably in \fB/usr/share/doc/wpa_supplicant/\fR, for
+detailed information about the configuration format and supported
+fields.
+.PP
+All file paths in this configuration file should use full
+(absolute, not relative to working directory) path in order to allow
+working directory to be changed. This can happen if wpa_supplicant is
+run in the background.
+.PP
+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.
+.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
+the configuration file, network security level (WPA/WPA2 is
+prefered), and signal strength.
+.SH "QUICK EXAMPLES"
+.TP 3
+1.
+WPA-Personal (PSK) as home network and WPA-Enterprise with
+EAP-TLS as work network.
+.sp
+.RS
+
+.nf
+# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+#
+# home network; allow all valid ciphers
+network={
+ ssid="home"
+ scan_ssid=1
+ key_mgmt=WPA-PSK
+ psk="very secret passphrase"
+}
+#
+# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
+network={
+ ssid="work"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ pairwise=CCMP TKIP
+ group=CCMP TKIP
+ eap=TLS
+ identity="user@example.com"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+}
+.fi
+.RE
+.TP 3
+2.
+WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that
+use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse
+Aegis, Interlink RAD-Series)
+.sp
+.RS
+
+.nf
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ eap=PEAP
+ identity="user@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ phase1="peaplabel=0"
+ phase2="auth=MSCHAPV2"
+}
+.fi
+.RE
+.TP 3
+3.
+EAP-TTLS/EAP-MD5-Challenge configuration with anonymous
+identity for the unencrypted use. Real identity is sent only
+within an encrypted TLS tunnel.
+.sp
+.RS
+
+.nf
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ eap=TTLS
+ identity="user@example.com"
+ anonymous_identity="anonymous@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ phase2="auth=MD5"
+}
+.fi
+.RE
+.TP 3
+4.
+IEEE 802.1X (i.e., no WPA) with dynamic WEP keys
+(require both unicast and broadcast); use EAP-TLS for
+authentication
+.sp
+.RS
+
+.nf
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="1x-test"
+ scan_ssid=1
+ key_mgmt=IEEE8021X
+ eap=TLS
+ identity="user@example.com"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+ eapol_flags=3
+}
+.fi
+.RE
+.TP 3
+5.
+Catch all example that allows more or less all
+configuration modes. The configuration options are used based
+on what security policy is used in the selected SSID. This is
+mostly for testing and is not recommended for normal
+use.
+.sp
+.RS
+
+.nf
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
+ pairwise=CCMP TKIP
+ group=CCMP TKIP WEP104 WEP40
+ psk="very secret passphrase"
+ eap=TTLS PEAP TLS
+ identity="user@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+ phase1="peaplabel=0"
+ ca_cert2="/etc/cert/ca2.pem"
+ client_cert2="/etc/cer/user.pem"
+ private_key2="/etc/cer/user.prv"
+ private_key2_passwd="password"
+}
+.fi
+.RE
+.TP 3
+6.
+Authentication for wired Ethernet. This can be used with
+'wired' interface (-Dwired on command line).
+.sp
+.RS
+
+.nf
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+ap_scan=0
+network={
+ key_mgmt=IEEE8021X
+ eap=MD5
+ identity="user"
+ password="password"
+ eapol_flags=0
+}
+.fi
+.RE
+.SH "CERTIFICATES"
+.PP
+Some EAP authentication methods require use of
+certificates. EAP-TLS uses both server side and client
+certificates whereas EAP-PEAP and EAP-TTLS only require the server
+side certificate. When client certificate is used, a matching
+private key file has to also be included in configuration. If the
+private key uses a passphrase, this has to be configured in
+wpa_supplicant.conf ("private_key_passwd").
+.PP
+wpa_supplicant supports X.509 certificates in PEM and DER
+formats. User certificate and private key can be included in the
+same file.
+.PP
+If the user certificate and private key is received in
+PKCS#12/PFX format, they need to be converted to suitable PEM/DER
+format for wpa_supplicant. This can be done, e.g., with following
+commands:
+.sp
+.RS
+
+.nf
+# convert client certificate and private key to PEM format
+openssl pkcs12 -in example.pfx -out user.pem -clcerts
+# convert CA certificate (if included in PFX file) to PEM format
+openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
+.fi
+.RE
+.SH "SEE ALSO"
+.PP
+\fBwpa_supplicant\fR(8)
+\fBopenssl\fR(1)
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
new file mode 100644
index 0000000..dbd9e37
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml
@@ -0,0 +1,244 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+<refentry>
+ <refmeta>
+ <refentrytitle>wpa_supplicant.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_supplicant.conf</refname>
+ <refpurpose>configuration file for wpa_supplicant</refpurpose>
+ </refnamediv>
+ <refsect1>
+ <title>Overview</title>
+
+ <para><command>wpa_supplicant</command> is configured using a text
+ file that lists all accepted networks and security policies,
+ including pre-shared keys. See the example configuration file,
+ probably in <command>/usr/share/doc/wpa_supplicant/</command>, for
+ detailed information about the configuration format and supported
+ fields.</para>
+
+ <para>All file paths in this configuration file should use full
+ (absolute, not relative to working directory) path in order to allow
+ working directory to be changed. This can happen if wpa_supplicant is
+ run in the background.</para>
+
+ <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>
+
+ <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
+ the configuration file, network security level (WPA/WPA2 is
+ prefered), and signal strength.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Quick Examples</title>
+
+ <orderedlist>
+ <listitem>
+
+ <para>WPA-Personal (PSK) as home network and WPA-Enterprise with
+ EAP-TLS as work network.</para>
+
+<blockquote><programlisting>
+# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+#
+# home network; allow all valid ciphers
+network={
+ ssid="home"
+ scan_ssid=1
+ key_mgmt=WPA-PSK
+ psk="very secret passphrase"
+}
+#
+# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
+network={
+ ssid="work"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ pairwise=CCMP TKIP
+ group=CCMP TKIP
+ eap=TLS
+ identity="user@example.com"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+}
+</programlisting></blockquote>
+ </listitem>
+
+ <listitem>
+ <para>WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that
+ use old peaplabel (e.g., Funk Odyssey and SBR, Meetinghouse
+ Aegis, Interlink RAD-Series)</para>
+
+<blockquote><programlisting>
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ eap=PEAP
+ identity="user@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ phase1="peaplabel=0"
+ phase2="auth=MSCHAPV2"
+}
+</programlisting></blockquote>
+ </listitem>
+
+ <listitem>
+ <para>EAP-TTLS/EAP-MD5-Challenge configuration with anonymous
+ identity for the unencrypted use. Real identity is sent only
+ within an encrypted TLS tunnel.</para>
+
+
+<blockquote><programlisting>
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP
+ eap=TTLS
+ identity="user@example.com"
+ anonymous_identity="anonymous@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ phase2="auth=MD5"
+}
+</programlisting></blockquote>
+
+ </listitem>
+
+ <listitem>
+ <para>IEEE 802.1X (i.e., no WPA) with dynamic WEP keys
+ (require both unicast and broadcast); use EAP-TLS for
+ authentication</para>
+
+<blockquote><programlisting>
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="1x-test"
+ scan_ssid=1
+ key_mgmt=IEEE8021X
+ eap=TLS
+ identity="user@example.com"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+ eapol_flags=3
+}
+</programlisting></blockquote>
+ </listitem>
+
+
+ <listitem>
+ <para>Catch all example that allows more or less all
+ configuration modes. The configuration options are used based
+ on what security policy is used in the selected SSID. This is
+ mostly for testing and is not recommended for normal
+ use.</para>
+
+<blockquote><programlisting>
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+network={
+ ssid="example"
+ scan_ssid=1
+ key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
+ pairwise=CCMP TKIP
+ group=CCMP TKIP WEP104 WEP40
+ psk="very secret passphrase"
+ eap=TTLS PEAP TLS
+ identity="user@example.com"
+ password="foobar"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+ private_key="/etc/cert/user.prv"
+ private_key_passwd="password"
+ phase1="peaplabel=0"
+ ca_cert2="/etc/cert/ca2.pem"
+ client_cert2="/etc/cer/user.pem"
+ private_key2="/etc/cer/user.prv"
+ private_key2_passwd="password"
+}
+</programlisting></blockquote>
+ </listitem>
+
+ <listitem>
+ <para>Authentication for wired Ethernet. This can be used with
+ 'wired' interface (-Dwired on command line).</para>
+
+<blockquote><programlisting>
+ctrl_interface=/var/run/wpa_supplicant
+ctrl_interface_group=wheel
+ap_scan=0
+network={
+ key_mgmt=IEEE8021X
+ eap=MD5
+ identity="user"
+ password="password"
+ eapol_flags=0
+}
+</programlisting></blockquote>
+ </listitem>
+ </orderedlist>
+
+
+
+
+
+ </refsect1>
+ <refsect1>
+ <title>Certificates</title>
+
+ <para>Some EAP authentication methods require use of
+ certificates. EAP-TLS uses both server side and client
+ certificates whereas EAP-PEAP and EAP-TTLS only require the server
+ side certificate. When client certificate is used, a matching
+ private key file has to also be included in configuration. If the
+ private key uses a passphrase, this has to be configured in
+ wpa_supplicant.conf ("private_key_passwd").</para>
+
+ <para>wpa_supplicant supports X.509 certificates in PEM and DER
+ formats. User certificate and private key can be included in the
+ same file.</para>
+
+ <para>If the user certificate and private key is received in
+ PKCS#12/PFX format, they need to be converted to suitable PEM/DER
+ format for wpa_supplicant. This can be done, e.g., with following
+ commands:</para>
+<blockquote><programlisting>
+# convert client certificate and private key to PEM format
+openssl pkcs12 -in example.pfx -out user.pem -clcerts
+# convert CA certificate (if included in PFX file) to PEM format
+openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
+</programlisting></blockquote>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>openssl</refentrytitle>
+ <manvolnum>1</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
new file mode 100644
index 0000000..cb35abf
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -0,0 +1,761 @@
+<!doctype refentry PUBLIC "-//OASIS//DTD DocBook V4.1//EN">
+
+<refentry>
+ <refmeta>
+ <refentrytitle>wpa_supplicant</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </refmeta>
+ <refnamediv>
+ <refname>wpa_supplicant</refname>
+ <refpurpose>Wi-Fi Protected Access client and IEEE 802.1X supplicant</refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>wpa_supplicant</command>
+ <arg>-BddehLqqvw</arg>
+ <arg>-i<replaceable>ifname</replaceable></arg>
+ <arg>-c<replaceable>config file</replaceable></arg>
+ <arg>-D<replaceable>driver</replaceable></arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+ <refsect1>
+ <title>Overview</title>
+
+ <para>
+ Wireless networks do not require physical access to the network equipment
+ in the same way as wired networks. This makes it easier for unauthorized
+ users to passively monitor a network and capture all transmitted frames.
+ In addition, unauthorized use of the network is much easier. In many cases,
+ this can happen even without user's explicit knowledge since the wireless
+ LAN adapter may have been configured to automatically join any available
+ network.
+ </para>
+
+ <para>
+ Link-layer encryption can be used to provide a layer of security for
+ wireless networks. The original wireless LAN standard, IEEE 802.11,
+ included a simple encryption mechanism, WEP. However, that proved to
+ be flawed in many areas and network protected with WEP cannot be consider
+ secure. IEEE 802.1X authentication and frequently changed dynamic WEP keys
+ can be used to improve the network security, but even that has inherited
+ security issues due to the use of WEP for encryption. Wi-Fi Protected
+ Access and IEEE 802.11i amendment to the wireless LAN standard introduce
+ a much improvement mechanism for securing wireless networks. IEEE 802.11i
+ enabled networks that are using CCMP (encryption mechanism based on strong
+ cryptographic algorithm AES) can finally be called secure used for
+ applications which require efficient protection against unauthorized
+ access.
+ </para>
+
+ <para><command>wpa_supplicant</command> is an implementation of
+ the WPA Supplicant component, i.e., the part that runs in the
+ client stations. It implements WPA key negotiation with a WPA
+ Authenticator and EAP authentication with Authentication
+ Server. In addition, it controls the roaming and IEEE 802.11
+ authentication/association of the wireless LAN driver.</para>
+
+ <para><command>wpa_supplicant</command> is designed to be a
+ "daemon" program that runs in the background and acts as the
+ backend component controlling the wireless
+ connection. <command>wpa_supplicant</command> supports separate
+ frontend programs and an example text-based frontend,
+ <command>wpa_cli</command>, is included with
+ wpa_supplicant.</para>
+
+ <para>Before wpa_supplicant can do its work, the network interface
+ must be available. That means that the physical device must be
+ present and enabled, and the driver for the device must have be
+ loaded. Note, however, that the '-w' option of the wpa_supplicant
+ daemon instructs the daemon to continue running and to wait for
+ the interface to become available. Without the '-w' option, the
+ daemon will exit immediately if the device is not already
+ available.</para>
+
+ <para>After <command>wpa_supplicant</command> has configured the
+ network device, higher level configuration such as DHCP may
+ proceed. There are a variety of ways to integrate wpa_supplicant
+ into a machine's networking scripts, a few of which are described
+ in sections below.</para>
+
+ <para>The following steps are used when associating with an AP
+ using WPA:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para><command>wpa_supplicant</command> requests the kernel
+ driver to scan neighboring BSSes</para>
+ </listitem>
+
+ <listitem>
+ <para><command>wpa_supplicant</command> selects a BSS based on
+ its configuration</para>
+ </listitem>
+
+ <listitem>
+ <para><command>wpa_supplicant</command> requests the kernel
+ driver to associate with the chosen BSS</para>
+ </listitem>
+
+ <listitem>
+ <para>If WPA-EAP: integrated IEEE 802.1X Supplicant or
+ external Xsupplicant completes EAP authentication with the
+ authentication server (proxied by the Authenticator in the
+ AP)</para>
+ </listitem>
+
+ <listitem>
+ <para>If WPA-EAP: master key is received from the IEEE 802.1X
+ Supplicant</para>
+ </listitem>
+
+ <listitem>
+ <para>If WPA-PSK: <command>wpa_supplicant</command> uses PSK
+ as the master session key</para>
+ </listitem>
+
+ <listitem>
+ <para><command>wpa_supplicant</command> completes WPA 4-Way
+ Handshake and Group Key Handshake with the Authenticator
+ (AP)</para>
+ </listitem>
+
+ <listitem>
+ <para><command>wpa_supplicant</command> configures encryption
+ keys for unicast and broadcast</para>
+ </listitem>
+
+ <listitem>
+ <para>normal data packets can be transmitted and received</para>
+ </listitem>
+ </itemizedlist>
+ </refsect1>
+
+ <refsect1>
+ <title>Supported Features</title>
+ <para>Supported WPA/IEEE 802.11i features:</para>
+ <itemizedlist>
+ <listitem>
+ <para>WPA-PSK ("WPA-Personal")</para>
+ </listitem>
+
+ <listitem>
+ <para>WPA with EAP (e.g., with RADIUS authentication server)
+ ("WPA-Enterprise") Following authentication methods are
+ supported with an integrate IEEE 802.1X Supplicant:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>EAP-TLS</para>
+ </listitem>
+ </itemizedlist>
+
+ <itemizedlist>
+ <listitem>
+ <para>EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+
+ <listitem>
+ <para>EAP-PEAP/TLS (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-PEAP/GTC (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-PEAP/OTP (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-TTLS/EAP-MD5-Challenge</para>
+ </listitem>
+
+ <listitem>
+ <para>EAP-TTLS/EAP-GTC</para>
+ </listitem>
+
+ <listitem><para>EAP-TTLS/EAP-OTP</para></listitem>
+
+ <listitem><para>EAP-TTLS/EAP-MSCHAPv2</para></listitem>
+
+ <listitem><para>EAP-TTLS/EAP-TLS</para></listitem>
+
+ <listitem><para>EAP-TTLS/MSCHAPv2</para></listitem>
+
+ <listitem><para>EAP-TTLS/MSCHAP</para></listitem>
+
+ <listitem><para>EAP-TTLS/PAP</para></listitem>
+
+ <listitem><para>EAP-TTLS/CHAP</para></listitem>
+
+ <listitem><para>EAP-SIM</para></listitem>
+
+ <listitem><para>EAP-AKA</para></listitem>
+
+ <listitem><para>EAP-PSK</para></listitem>
+
+ <listitem><para>EAP-PAX</para></listitem>
+
+ <listitem><para>LEAP (note: requires special support from
+ the driver for IEEE 802.11 authentication)</para></listitem>
+
+ <listitem><para>(following methods are supported, but since
+ they do not generate keying material, they cannot be used
+ with WPA or IEEE 802.1X WEP keying)</para></listitem>
+
+ <listitem><para>EAP-MD5-Challenge </para></listitem>
+
+ <listitem><para>EAP-MSCHAPv2</para></listitem>
+
+ <listitem><para>EAP-GTC</para></listitem>
+
+ <listitem><para>EAP-OTP</para></listitem>
+ </itemizedlist>
+ </listitem>
+
+ <listitem>
+ <para>key management for CCMP, TKIP, WEP104, WEP40</para>
+ </listitem>
+
+ <listitem>
+ <para>RSN/WPA2 (IEEE 802.11i)</para>
+ <itemizedlist>
+ <listitem>
+ <para>pre-authentication</para>
+ </listitem>
+
+ <listitem>
+ <para>PMKSA caching</para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </refsect1>
+
+ <refsect1>
+ <title>Available Drivers</title>
+ <para>The available drivers to specify with the -D option are:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term>hostap</term>
+ <listitem>
+ <para>(default) Host AP driver (Intersil Prism2/2.5/3).
+ (this can also be used with Linuxant DriverLoader).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>hermes</term>
+ <listitem>
+ <para>Agere Systems Inc. driver (Hermes-I/Hermes-II).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>madwifi</term>
+ <listitem>
+ <para>MADWIFI 802.11 support (Atheros, etc.).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>atmel</term>
+ <listitem>
+ <para>ATMEL AT76C5XXx (USB, PCMCIA).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>wext</term>
+ <listitem>
+ <para>Linux wireless extensions (generic).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ndiswrapper</term>
+ <listitem>
+ <para>Linux ndiswrapper.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>broadcom</term>
+ <listitem>
+ <para>Broadcom wl.o driver.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ipw</term>
+ <listitem>
+ <para>Intel ipw2100/2200 driver.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>wired</term>
+ <listitem>
+ <para>wpa_supplicant wired Ethernet driver</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>bsd</term>
+ <listitem>
+ <para>BSD 802.11 support (Atheros, etc.).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ndis</term>
+ <listitem>
+ <para>Windows NDIS driver.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Command Line Options</title>
+ <variablelist>
+ <varlistentry>
+ <term>-B</term>
+ <listitem>
+ <para>Run daemon in the background.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-i ifname</term>
+ <listitem>
+ <para>Interface to listen on.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-c filename</term>
+ <listitem>
+ <para>Path to configuration file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-D driver</term>
+ <listitem>
+ <para>Driver to use. See the available options below.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-d</term>
+ <listitem>
+ <para>Increase debugging verbosity (-dd even more).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-K</term>
+ <listitem>
+ <para>Include keys (passwords, etc.) in debug output.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-t</term>
+ <listitem>
+ <para>Include timestamp in debug messages.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-e</term>
+ <listitem>
+ <para>Use external IEEE 802.1X Supplicant (e.g.,
+ <command>xsupplicant</command>) (this disables the internal
+ Supplicant).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-h</term>
+ <listitem>
+ <para>Help. Show a usage message.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-L</term>
+ <listitem>
+ <para>Show license (GPL and BSD).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-q</term>
+ <listitem>
+ <para>Decrease debugging verbosity (-qq even less).</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>-v</term>
+ <listitem>
+ <para>Show version.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-w</term>
+ <listitem>
+ <para>wait for interface to be added, if needed. normally,
+ <command>wpa_supplicant</command> will exit if the interface
+ is not there yet.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>-N</term>
+ <listitem>
+ <para>Start describing new interface.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>In most common cases, <command>wpa_supplicant</command> is
+ started with:</para>
+
+<blockquote><programlisting>
+wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -iwlan0
+</programlisting></blockquote>
+
+ <para>This makes the process fork into background and wait for the wlan0
+ interface if it is not available at startup time.</para>
+
+ <para>The easiest way to debug problems, and to get debug log for
+ bug reports, is to start <command>wpa_supplicant</command> on
+ foreground with debugging enabled:</para>
+
+<blockquote><programlisting>
+wpa_supplicant -c/etc/wpa_supplicant.conf -iwlan0 -d
+</programlisting></blockquote>
+
+ <para><command>wpa_supplicant</command> can control multiple
+ interfaces (radios) either by running one process for each
+ interface separately or by running just one process and list of
+ options at command line. Each interface is separated with -N
+ argument. As an example, following command would start
+ wpa_supplicant for two interfaces:</para>
+
+<blockquote><programlisting>
+wpa_supplicant \
+ -c wpa1.conf -i wlan0 -D hostap -N \
+ -c wpa2.conf -i ath0 -D madwifi
+</programlisting></blockquote>
+ </refsect1>
+
+ <refsect1>
+ <title>OS Requirements</title>
+ <para>Current hardware/software requirements:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>Linux kernel 2.4.x or 2.6.x with Linux Wireless
+ Extensions v15 or newer</para>
+ </listitem>
+
+
+ <listitem>
+ <para>FreeBSD 6-CURRENT</para>
+ </listitem>
+
+ <listitem>
+ <para>Microsoft Windows with WinPcap (at least WinXP, may work
+ with other versions)</para>
+ </listitem>
+ </itemizedlist>
+ </refsect1>
+
+ <refsect1>
+ <title>Supported Drivers</title>
+ <variablelist>
+ <varlistentry>
+ <term>Host AP driver for Prism2/2.5/3 (development
+ snapshot/v0.2.x)</term>
+ <listitem>
+ <para> (http://hostap.epitest.fi/) Driver needs to be set in
+ Managed mode ('iwconfig wlan0 mode managed'). Please note
+ that station firmware version needs to be 1.7.0 or newer to
+ work in WPA mode.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Linuxant DriverLoader</term>
+ <listitem>
+ <para>(http://www.linuxant.com/driverloader/)
+ with Windows NDIS driver for your wlan card supporting WPA.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Agere Systems Inc. Linux Driver</term>
+ <listitem>
+ <para> (http://www.agere.com/support/drivers/) Please note
+ that the driver interface file (driver_hermes.c) and hardware
+ specific include files are not included in the wpa_supplicant
+ distribution. You will need to copy these from the source
+ package of the Agere driver.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>madwifi driver for cards based on Atheros chip set (ar521x)</term>
+ <listitem>
+ <para> (http://sourceforge.net/projects/madwifi/) Please
+ note that you will need to modify the wpa_supplicant .config
+ file to use the correct path for the madwifi driver root
+ directory (CFLAGS += -I../madwifi/wpa line in example
+ defconfig).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>ATMEL AT76C5XXx driver for USB and PCMCIA cards</term>
+ <listitem>
+ <para> (http://atmelwlandriver.sourceforge.net/).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Linux ndiswrapper</term>
+ <listitem>
+ <para> (http://ndiswrapper.sourceforge.net/) with Windows
+ NDIS driver.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Broadcom wl.o driver</term>
+ <listitem>
+ <para> This is a generic Linux driver for Broadcom IEEE
+ 802.11a/g cards. However, it is proprietary driver that is
+ not publicly available except for couple of exceptions, mainly
+ Broadcom-based APs/wireless routers that use Linux. The driver
+ binary can be downloaded, e.g., from Linksys support site
+ (http://www.linksys.com/support/gpl.asp) for Linksys
+ WRT54G. The GPL tarball includes cross-compiler and the needed
+ header file, wlioctl.h, for compiling wpa_supplicant. This
+ driver support in wpa_supplicant is expected to work also with
+ other devices based on Broadcom driver (assuming the driver
+ includes client mode support).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term> Intel ipw2100 driver</term>
+ <listitem>
+ <para> (http://sourceforge.net/projects/ipw2100/)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Intel ipw2200 driver</term>
+ <listitem>
+ <para> (http://sourceforge.net/projects/ipw2200/)</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Linux wireless extensions</term>
+ <listitem>
+ <para>In theory, any driver that supports Linux wireless
+ extensions can be used with IEEE 802.1X (i.e., not WPA) when
+ using ap_scan=0 option in configuration file.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Wired Ethernet drivers</term>
+ <listitem>
+ <para>Use ap_scan=0.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>BSD net80211 layer (e.g., Atheros driver)</term>
+ <listitem>
+ <para>At the moment, this is for FreeBSD 6-CURRENT branch.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>Windows NDIS</term>
+ <listitem>
+ <para>The current Windows port requires WinPcap
+ (http://winpcap.polito.it/). See README-Windows.txt for more
+ information.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+
+ <para>wpa_supplicant was designed to be portable for different
+ drivers and operating systems. Hopefully, support for more wlan
+ cards and OSes will be added in the future. See developer.txt for
+ more information about the design of wpa_supplicant and porting to
+ other drivers. One main goal is to add full WPA/WPA2 support to
+ Linux wireless extensions to allow new drivers to be supported
+ without having to implement new driver-specific interface code in
+ wpa_supplicant.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>Architecture</title> <para>The
+ <command>wpa_supplicant</command> system consists of the following
+ components:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><filename>wpa_supplicant.conf</filename> </term>
+ <listitem>
+ <para>the configuration file describing all networks that the
+ user wants the computer to connect to. </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>wpa_supplicant</command></term>
+ <listitem><para>the program that directly interacts with the
+ network interface. </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>wpa_cli</command></term> <listitem><para> the
+ client program that provides a high-level interface to the
+ functionality of the daemon. </para></listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><command>wpa_passphrase</command></term>
+ <listitem><para>a utility needed to construct
+ <filename>wpa_supplicant.conf</filename> files that include
+ encrypted passwords.</para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Quick Start</title>
+
+ <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>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ for details.</para>
+
+ <para>Once the configuration is ready, you can test whether the
+ configuration works by running <command>wpa_supplicant</command>
+ with following command to start it on foreground with debugging
+ enabled:</para>
+
+ <blockquote><programlisting>
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
+ </programlisting></blockquote>
+
+ <para>Assuming everything goes fine, you can start using following
+ command to start <command>wpa_supplicant</command> on background
+ without debugging:</para>
+
+ <blockquote><programlisting>
+wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
+ </programlisting></blockquote>
+
+ <para>Please note that if you included more than one driver
+ interface in the build time configuration (.config), you may need
+ to specify which interface to use by including -D&lt;driver
+ name&gt; option on the command line.</para>
+
+ <!-- XXX at this point, the page could include a little script
+ based on wpa_cli to wait for a connection and then run
+ dhclient -->
+
+ </refsect1>
+
+ <refsect1>
+ <title>Interface to pcmcia-cs/cardmrg</title>
+
+ <para>For example, following small changes to pcmcia-cs scripts
+ can be used to enable WPA support:</para>
+
+ <para>Add MODE="Managed" and WPA="y" to the network scheme in
+ <filename>/etc/pcmcia/wireless.opts</filename>.</para>
+
+ <para>Add the following block to the end of 'start' action handler
+ in <filename>/etc/pcmcia/wireless</filename>:</para>
+
+ <blockquote><programlisting>
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+ /usr/local/bin/wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -i$DEVICE
+fi
+ </programlisting></blockquote>
+
+
+ <para>Add the following block to the end of 'stop' action handler
+ (may need to be separated from other actions) in
+ <filename>/etc/pcmcia/wireless</filename>:</para>
+
+ <blockquote><programlisting>
+if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
+ killall wpa_supplicant
+fi
+ </programlisting></blockquote>
+
+ <para>This will make <command>cardmgr</command> start
+ <command>wpa_supplicant</command> when the card is plugged
+ in. <command>wpa_supplicant</command> will wait until the
+ interface is set up--either when a static IP address is configured
+ or when DHCP client is started--and will then negotiate keys with
+ the AP.</para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+ <para>
+ <citerefentry>
+ <refentrytitle>wpa_background</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>wpa_supplicant.conf</refentrytitle>
+ <manvolnum>5</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>wpa_cli</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ <citerefentry>
+ <refentrytitle>wpa_passphrase</refentrytitle>
+ <manvolnum>8</manvolnum>
+ </citerefentry>
+ </para>
+ </refsect1>
+ <refsect1>
+ <title>Legal</title>
+ <para>wpa_supplicant is copyright (c) 2003-2005,
+ Jouni Malinen <email>jkmaline@cc.hut.fi</email> and
+ contributors.
+ All Rights Reserved.</para>
+
+ <para>This program is dual-licensed under both the GPL version 2
+ and BSD license. Either license may be used at your option.</para>
+ </refsect1>
+</refentry>
diff --git a/contrib/wpa_supplicant/doc/doxygen.fast b/contrib/wpa_supplicant/doc/doxygen.fast
new file mode 100644
index 0000000..2eb9d27
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/doxygen.fast
@@ -0,0 +1,243 @@
+# Doxyfile 1.4.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = wpa_supplicant
+PROJECT_NUMBER = 0.4.x
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = . \
+ ../hostapd/aes.c \
+ ../hostapd/rc4.c \
+ ../hostapd/rc4.h \
+ ../hostapd/md5.c \
+ ../hostapd/md5.h \
+ ../hostapd/sha1.c \
+ ../hostapd/sha1.h \
+ ../hostapd/common.c \
+ ../hostapd/common.h \
+ ../hostapd/eloop.c \
+ ../hostapd/eloop.h \
+ ../hostapd/aes_wrap.c \
+ ../hostapd/aes_wrap.h
+FILE_PATTERNS = *.c *.h *.doxygen
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH = doc
+INPUT_FILTER = kerneldoc2doxygen.pl
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 3
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = IEEE8021X_EAPOL
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/contrib/wpa_supplicant/doc/doxygen.full b/contrib/wpa_supplicant/doc/doxygen.full
new file mode 100644
index 0000000..69cec65
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/doxygen.full
@@ -0,0 +1,230 @@
+# Doxyfile 1.4.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = wpa_supplicant
+PROJECT_NUMBER = 0.4.x
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = .
+FILE_PATTERNS = *.c *.h *.doxygen
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH = doc
+INPUT_FILTER = kerneldoc2doxygen.pl
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 3
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = IEEE8021X_EAPOL
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = YES
diff --git a/contrib/wpa_supplicant/doc/driver_wrapper.doxygen b/contrib/wpa_supplicant/doc/driver_wrapper.doxygen
new file mode 100644
index 0000000..232739a
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/driver_wrapper.doxygen
@@ -0,0 +1,180 @@
+/**
+\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
+
+All hardware and driver dependent functionality is in separate C files
+that implement defined wrapper functions. Other parts
+of the %wpa_supplicant are designed to be hardware, driver, and operating
+system independent.
+
+Driver wrappers need to implement whatever calls are used in the
+target operating system/driver for controlling wireless LAN
+devices. As an example, in case of Linux, these are mostly some glue
+code and ioctl() calls and netlink message parsing for Linux Wireless
+Extensions (WE). Since features required for WPA were added only recently to
+Linux Wireless Extensions (in version 18), some driver specific code is used
+in number of driver interface implementations. These driver dependent parts
+can be replaced with generic code in driver_wext.c once the target driver
+includes full support for WE-18. After that, all Linux drivers, at
+least in theory, could use the same driver wrapper code.
+
+A driver wrapper needs to implement some or all of the functions
+defined in driver.h. These functions are registered by filling struct
+wpa_driver_ops with function pointers. Hardware independent parts of
+%wpa_supplicant will call these functions to control the driver/wlan
+card. In addition, support for driver events is required. The event
+callback function, wpa_supplicant_event(), and its parameters are
+documented in wpa_supplicant.h. In addition, a pointer to the 'struct
+wpa_driver_ops' needs to be registered in drivers.c file.
+
+When porting to other operating systems, the driver wrapper should be
+modified to use the native interface of the target OS. It is possible
+that some extra requirements for the interface between the driver
+wrapper and generic %wpa_supplicant code are discovered during porting
+to a new operating system. These will be addressed on case by case
+basis by modifying the interface and updating the other driver
+wrappers for this. The goal is to avoid changing this interface
+without very good reasons in order to limit the number of changes
+needed to other wrappers and hardware independent parts of
+%wpa_supplicant. When changes are required, recommended way is to
+make them in backwards compatible way that allows existing driver
+interface implementations to be compiled without any modification.
+
+Generic Linux Wireless Extensions functions are implemented in
+driver_wext.c. All Linux driver wrappers can use these when the kernel
+driver supports the generic ioctl()s and wireless events. Driver
+specific functions are implemented in separate C files, e.g.,
+driver_hostap.c. These files need to define struct wpa_driver_ops
+entry that will be used in wpa_supplicant.c when calling driver
+functions. struct wpa_driver_ops entries are registered in drivers.c.
+
+In general, it is likely to be useful to first take a look at couple
+of driver interface examples before starting on implementing a new
+one. driver_hostap.c and driver_wext.c include a complete
+implementation for Linux drivers that use %wpa_supplicant-based control
+of WPA IE and roaming. driver_ndis.c (with help from driver_ndis_.c)
+is an example of a complete interface for Windows NDIS interface for
+drivers that generate WPA IE themselves and decide when to roam. These
+example implementations include full support for all security modes.
+
+
+\section driver_req Driver requirements for WPA
+
+WPA introduces new requirements for the device driver. At least some
+of these need to be implemented in order to provide enough support for
+%wpa_supplicant.
+
+\subsection driver_tkip_ccmp TKIP/CCMP
+
+WPA requires that the pairwise cipher suite (encryption algorithm for
+unicast data packets) is TKIP or CCMP. These are new encryption
+protocols and thus, the driver will need to be modified to support
+them. Depending on the used wlan hardware, some parts of these may be
+implemented by the hardware/firmware.
+
+Specification for both TKIP and CCMP is available from IEEE (IEEE
+802.11i amendment). Fully functional, hardware independent
+implementation of both encryption protocols is also available in Host
+AP driver (driver/modules/hostap_{tkip,ccmp}.c). In addition, Linux 2.6
+kernel tree has generic implementations for WEP, TKIP, and CCMP that can
+be used in Linux drivers.
+
+The driver will also need to provide configuration mechanism to allow
+user space programs to configure TKIP and CCMP. Linux Wireless Extensions
+v18 added support for configuring these algorithms and
+individual/non-default keys. If the target kernel does not include WE-18,
+private ioctls can be used to provide similar functionality.
+
+\subsection driver_roaming Roaming control and scanning support
+
+%wpa_supplicant can optionally control AP selection based on the
+information received from Beacon and/or Probe Response frames
+(ap_scan=1 mode in configuration). This means that the driver should
+support external control for scan process. In case of Linux, use of
+new Wireless Extensions scan support (i.e., 'iwlist wlan0 scan') is
+recommended. The current driver wrapper (driver_wext.c) uses this for
+scan results.
+
+Scan results must also include the WPA information element. Support for
+this was added in WE-18. With older versions, a custom event can be used
+to provide the full WPA IE (including element id and length) as a hex
+string that is included in the scan results.
+
+%wpa_supplicant needs to also be able to request the driver to
+associate with a specific BSS. Current Host AP driver and matching
+driver_hostap.c wrapper uses following sequence for this
+request. Similar/identical mechanism should be usable also with other
+drivers.
+
+- set WPA IE for AssocReq with private ioctl
+- set SSID with SIOCSIWESSID
+- set channel/frequency with SIOCSIWFREQ
+- set BSSID with SIOCSIWAP
+ (this last ioctl will trigger the driver to request association)
+
+\subsection driver_wpa_ie WPA IE generation
+
+%wpa_supplicant selects which cipher suites and key management suites
+are used. Based on this information, it generates a WPA IE. This is
+provided to the driver interface in the associate call. This does not
+match with Windows NDIS drivers which generate the WPA IE
+themselves.
+
+%wpa_supplicant allows Windows NDIS-like behavior by providing the
+selected cipher and key management suites in the associate call. If
+the driver generates its own WPA IE and that differs from the one
+generated by %wpa_supplicant, the driver has to inform %wpa_supplicant
+about the used WPA IE (i.e., the one it used in (Re)Associate
+Request). This notification is done using EVENT_ASSOCINFO event (see
+wpa_supplicant.h). %wpa_supplicant is normally configured to use
+ap_scan=2 mode with drivers that control WPA IE generation and roaming.
+
+\subsection driver_events Driver events
+
+%wpa_supplicant needs to receive event callbacks when certain events
+occur (association, disassociation, Michael MIC failure, scan results
+available, PMKSA caching candidate). These events and the callback
+details are defined in wpa_supplicant.h (wpa_supplicant_event() function
+and enum wpa_event_type).
+
+On Linux, association and disassociation can use existing Wireless
+Extensions event that is reporting new AP with SIOCGIWAP
+event. Similarly, completion of a scan can be reported with SIOCGIWSCAN
+event.
+
+Michael MIC failure event was added in WE-18. Older versions of Wireless
+Extensions will need to use a custom event. Host AP driver used a custom
+event with following contents: MLME-MICHAELMICFAILURE.indication(keyid=#
+broadcast/unicast addr=addr2). This is the recommended format until
+the driver can be moved to use WE-18 mechanism.
+
+\subsection driver_wext_summary Summary of Linux Wireless Extensions use
+
+AP selection depends on ap_scan configuration:
+
+ap_scan=1:
+
+- %wpa_supplicant requests scan with SIOCSIWSCAN
+- driver reports scan complete with wireless event SIOCGIWSCAN
+- %wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
+ a larget buffer is needed)
+- %wpa_supplicant decides which AP to use based on scan results
+- %wpa_supplicant configures driver to associate with the selected BSS
+ (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ,
+ SIOCSIWESSID, SIOCSIWAP)
+
+ap_scan=2:
+
+- %wpa_supplicant configures driver to associate with an SSID
+ (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWESSID)
+
+
+After this, both modes use similar steps:
+
+- optionally (or required for drivers that generate WPA/RSN IE for
+ (Re)AssocReq), driver reports association parameters (AssocReq IEs)
+ with wireless event IWEVASSOCREQIE (and optionally IWEVASSOCRESPIE)
+- driver reports association with wireless event SIOCGIWAP
+- %wpa_supplicant takes care of EAPOL frame handling (validating
+ information from associnfo and if needed, from scan results if WPA/RSN
+ IE from the Beacon frame is not reported through associnfo)
+*/
diff --git a/contrib/wpa_supplicant/doc/eap.doxygen b/contrib/wpa_supplicant/doc/eap.doxygen
new file mode 100644
index 0000000..e1ae9c0
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/eap.doxygen
@@ -0,0 +1,38 @@
+/**
+\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
+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
+machine and methods. As such, this RFC provides useful information for
+understanding the EAP peer implementation in %wpa_supplicant.
+
+Some of the terminology used in EAP state machine is referring to
+EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
+layer being IEEE 802.1X if EAP module is built for other programs than
+%wpa_supplicant. These terms should be understood to refer to the
+lower layer as defined in RFC 4137.
+
+
+\section adding_eap_methods Adding EAP methods
+
+Each EAP method is implemented as a separate module, usually as one C
+file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+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
+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.
+
+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.
+*/
diff --git a/contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl b/contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl
new file mode 100755
index 0000000..d46f7bd
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl
@@ -0,0 +1,129 @@
+#!/usr/bin/perl -w
+#
+##########################################################################
+# Convert kernel-doc style comments to Doxygen comments.
+##########################################################################
+#
+# This script reads a C source file from stdin, and writes
+# to stdout. Normal usage:
+#
+# $ mv file.c file.c.gtkdoc
+# $ kerneldoc2doxygen.pl <file.c.gtkdoc >file.c
+#
+# Or to do the same thing with multiple files:
+# $ perl -i.gtkdoc kerneldoc2doxygen.pl *.c *.h
+#
+# This script may also be suitable for use as a Doxygen input filter,
+# but that has not been tested.
+#
+# Back up your source files before using this script!!
+#
+##########################################################################
+# Copyright (C) 2003 Jonathan Foster <jon@jon-foster.co.uk>
+# Copyright (C) 2005 Jouni Malinen <jkmaline@cc.hut.fi>
+# (modified for kerneldoc format used in wpa_supplicant)
+#
+# 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# 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
+# or look at http://www.gnu.org/licenses/gpl.html
+##########################################################################
+
+
+##########################################################################
+#
+# This function converts a single comment from gtk-doc to Doxygen format.
+# The parameter does not include the opening or closing lines
+# (i.e. given a comment like this:
+# "/**\n"
+# " * FunctionName:\n"
+# " * @foo: This describes the foo parameter\n"
+# " * @bar: This describes the bar parameter\n"
+# " * @Returns: This describes the return value\n"
+# " *\n"
+# " * This describes the function.\n"
+# " */\n"
+# This function gets:
+# " * FunctionName:\n"
+# " * @foo: This describes the foo parameter\n"
+# " * @bar: This describes the bar parameter\n"
+# " * @Returns: This describes the return value\n"
+# " *\n"
+# " * This describes the function.\n"
+# And it returns:
+# " * This describes the function.\n"
+# " *\n"
+# " * @param foo This describes the foo parameter\n"
+# " * @param bar This describes the bar parameter\n"
+# " * @return This describes the return value\n"
+# )
+#
+sub fixcomment {
+ $t = $_[0];
+
+ # " * func: foo" --> "\brief foo\n"
+ # " * struct bar: foo" --> "\brief foo\n"
+ # If this fails, not a kernel-doc comment ==> return unmodified.
+ ($t =~ s/^[\t ]*\*[\t ]*(struct )?([^ \t\n]*) - ([^\n]*)/\\brief $3\n/s)
+ or return $t;
+
+ # " * Returns: foo" --> "\return foo"
+ $t =~ s/\n[\t ]*\*[\t ]*Returns:/\n\\return/sig;
+
+ # " * @foo: bar" --> "\param foo bar"
+ # Handle two common typos: No ":", or "," instead of ":".
+ $t =~ s/\n[\t ]*\*[\t ]*\@([^ :,]*)[:,]?[\t ]*/\n\\param $1 /sg;
+
+ return $t;
+}
+
+##########################################################################
+# Start of main code
+
+# Read entire stdin into memory - one multi-line string.
+$_ = do { local $/; <> };
+
+s{^/\*\n \*}{/\*\* \\file\n\\brief};
+s{ \* Copyright}{\\par Copyright\nCopyright};
+
+# Fix any comments like "/*************" so they don't match.
+# "/***" ===> "/* *"
+s{/\*\*\*}{/\* \*}gs;
+
+# The main comment-detection code.
+s{
+ ( # $1 = Open comment
+ /\*\* # Open comment
+ (?!\*) # Do not match /*** (redundant due to fixup above).
+ [\t ]*\n? # If 1st line is whitespace, match the lot (including the newline).
+ )
+ (.*?) # $2 = Body of comment (multi-line)
+ ( # $3 = Close comment
+ ( # If possible, match the whitespace before the close-comment
+ (?<=\n) # This part only matches after a newline
+ [\t ]* # Eat whitespace
+ )?
+ \*/ # Close comment
+ )
+ }
+ {
+ $1 . fixcomment($2) . $3
+ }gesx;
+# ^^^^ Modes: g - Global, match all occurances.
+# e - Evaluate the replacement as an expression.
+# s - Single-line - allows the pattern to match across newlines.
+# x - eXtended pattern, ignore embedded whitespace
+# and allow comments.
+
+# Write results to stdout
+print $_;
+
diff --git a/contrib/wpa_supplicant/doc/mainpage.doxygen b/contrib/wpa_supplicant/doc/mainpage.doxygen
new file mode 100644
index 0000000..56882f4
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/mainpage.doxygen
@@ -0,0 +1,56 @@
+/**
+\mainpage Developers' documentation for %wpa_supplicant
+
+%wpa_supplicant is a WPA Supplicant for Linux, BSD and Windows with
+support for WPA and WPA2 (IEEE 802.11i / RSN). Supplicant is the IEEE
+802.1X/WPA component that is used in the client stations. It
+implements key negotiation with a WPA Authenticator and it can optionally
+control roaming and IEEE 802.11 authentication/association of the wlan
+driver.
+
+The goal of this documentation and comments in the source code is to
+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
+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
+%wpa_supplicant are expected to use compatible licensing terms.
+
+The source code and read-only access to %wpa_supplicant CVS repository
+is available from the project home page at
+http://hostap.epitest.fi/wpa_supplicant/. This developers' documentation
+is also available as a PDF file from
+http://hostap.epitest.fi/wpa_supplicant/wpa_supplicant-devel.pdf .
+
+The design goal for %wpa_supplicant was to use hardware, driver, and
+OS independent, portable C code for all WPA functionality. The source
+code is divided into separate C files as shown on the \ref
+code_structure "code structure page". All hardware/driver specific
+functionality is in separate files that implement a \ref
+driver_wrapper "well-defined driver API". Information about porting
+to different target boards and operating systems is available on
+the \ref porting "porting page".
+
+EAPOL (IEEE 802.1X) state machines are implemented as a separate
+module that interacts with \ref eap_module "EAP peer implementation".
+In addition to programs aimed at normal production use,
+%wpa_supplicant source tree includes number of \ref testing_tools
+"testing and development tools" that make it easier to test the
+programs without having to setup a full test setup with wireless
+cards. These tools can also be used to implement automatic test
+suites.
+
+%wpa_supplicant implements a
+\ref ctrl_iface_page "control interface" that can be used by
+external programs to control the operations of the %wpa_supplicant
+daemon and to get status information and event notifications. There is
+a small C library that provides helper functions to facilitate the use of the
+control interface. This library can also be used with C++.
+
+\image html wpa_supplicant.png "wpa_supplicant modules"
+\image latex wpa_supplicant.eps "wpa_supplicant modules" width=15cm
+
+*/
diff --git a/contrib/wpa_supplicant/doc/porting.doxygen b/contrib/wpa_supplicant/doc/porting.doxygen
new file mode 100644
index 0000000..db64a11
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/porting.doxygen
@@ -0,0 +1,121 @@
+/**
+\page porting Porting to different target boards and operating systems
+
+%wpa_supplicant was designed to be easily portable to different
+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
+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 driver_iface_porting Driver interface
+
+Unless the target OS and driver is already supported, most porting
+projects have to implement a driver wrapper. This may be done by
+adding a new driver interface module or modifying an existing module
+(driver_*.c) if the new target is similar to one of them. \ref
+driver_wrapper "Driver wrapper implementation" describes the details
+of the driver interface and discusses the tasks involved in porting
+this part of %wpa_supplicant.
+
+
+\section l2_packet_porting l2_packet (link layer access)
+
+%wpa_supplicant needs to have access to sending and receiving layer 2
+(link layer) packets with two Ethertypes: EAP-over-LAN (EAPOL) 0x888e
+and RSN pre-authentication 0x88c7. l2_packet.h defines the interfaces
+used for this in the core %wpa_supplicant implementation.
+
+If the target operating system supports a generic mechanism for link
+layer access, that is likely the best mechanism for providing the
+needed functionality for %wpa_supplicant. Linux packet socket is an
+example of such a generic mechanism. If this is not available, a
+separate interface may need to be implemented to the network stack or
+driver. This is usually an intermediate or protocol driver that is
+operating between the device driver and the OS network stack. If such
+a mechanism is not feasible, the interface can also be implemented
+directly in the device driver.
+
+The main %wpa_supplicant repository includes l2_packet implementations
+for Linux using packet sockets (l2_packet_linux.c), more portable
+version using libpcap/libdnet libraries (l2_packet_pcap.c; this
+supports WinPcap, too), and FreeBSD specific version of libpcap
+interface (l2_packet_freebsd.c).
+
+If the target operating system is supported by libpcap (receiving) and
+libdnet (sending), l2_packet_pcap.c can likely be used with minimal or
+no changes. If this is not a case or a proprietary interface for link
+layer is required, a new l2_packet module may need to be
+added. Alternatively, struct wpa_driver_ops::send_eapol() handler can
+be used to override the l2_packet library if the link layer access is
+integrated with the driver interface implementation.
+
+
+\section eloop_porting Event loop
+
+%wpa_supplicant uses a single process/thread model and an event loop
+to provide callbacks on events (registered timeout, received packet,
+signal). eloop.h defines the event loop interface. eloop.c is an
+implementation of such an event loop using select() and sockets. This
+is suitable for most UNIX/POSIX systems. When porting to other
+operating systems, it may be necessary to replace that implementation
+with OS specific mechanisms that provide similar functionality.
+
+
+\section ctrl_iface_porting Control interface
+
+%wpa_supplicant uses a \ref ctrl_iface_page "control interface"
+to allow external processed
+to get status information and to control the operations. Currently,
+this is implemented with socket based communication; both UNIX domain
+sockets and UDP sockets are supported. If the target OS does not
+support sockets, this interface will likely need to be modified to use
+another mechanism like message queues. The control interface is
+optional component, so it is also possible to run %wpa_supplicant
+without porting this part.
+
+The %wpa_supplicant side of the control interface is implemented in
+ctrl_iface.c. Matching client side is implemented as a control
+interface library in wpa_ctrl.c.
+
+
+\section entry_point Program entry point
+
+%wpa_supplicant defines a set of functions that can be used to
+initialize main supplicant processing. Each operating system has a
+mechanism for starting new processing or threads. This is usually a
+function with a specific set of arguments and calling convention. This
+function is responsible on initializing %wpa_supplicant.
+
+main.c includes an entry point for UNIX-like operating system, i.e.,
+main() function that uses command line arguments for setting
+parameters for %wpa_supplicant. When porting to other operating
+systems, similar OS-specific entry point implementation is needed. It
+can be implemented in a new file that is then linked with
+%wpa_supplicant instead of main.o. main.c is also a good example on
+how the initialization process should be done.
+
+The supplicant initialization functions are defined in
+wpa_supplicant_i.h. In most cases, the entry point function should
+start by fetching configuration parameters. After this, a global
+%wpa_supplicant context is initialized with a call to
+wpa_supplicant_init(). After this, existing network interfaces can be
+added with wpa_supplicant_add_iface(). wpa_supplicant_run() is then
+used to start the main event loop. Once this returns at program
+termination time, wpa_supplicant_deinit() is used to release global
+context data.
+
+wpa_supplicant_add_iface() and wpa_supplicant_remove_iface() can be
+used dynamically to add and remove interfaces based on when
+%wpa_supplicant processing is needed for them. This can be done, e.g.,
+when hotplug network adapters are being inserted and ejected. It is
+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.
+
+*/
diff --git a/contrib/wpa_supplicant/doc/testing_tools.doxygen b/contrib/wpa_supplicant/doc/testing_tools.doxygen
new file mode 100644
index 0000000..c1e2408
--- /dev/null
+++ b/contrib/wpa_supplicant/doc/testing_tools.doxygen
@@ -0,0 +1,288 @@
+/**
+\page testing_tools Testing and development tools
+
+[ \ref eapol_test "eapol_test" |
+\ref preauth_test "preauth_test" |
+\ref driver_test "driver_test" |
+\ref unit_tests "Unit tests" ]
+
+%wpa_supplicant source tree includes number of testing and development
+tools that make it easier to test the programs without having to setup
+a full test setup with wireless cards. In addition, these tools can be
+used to implement automatic tests suites.
+
+\section eapol_test eapol_test - EAP peer and RADIUS client testing
+
+eapol_test is a program that links together the same EAP peer
+implementation that %wpa_supplicant is using and the RADIUS
+authentication client code from hostapd. In addition, it has minimal
+glue code to combine these two components in similar ways to IEEE
+802.1X/EAPOL Authenticator state machines. In other words, it
+integrates IEEE 802.1X Authenticator (normally, an access point) and
+IEEE 802.1X Supplicant (normally, a wireless client) together to
+generate a single program that can be used to test EAP methods without
+having to setup an access point and a wireless client.
+
+The main uses for eapol_test are in interoperability testing of EAP
+methods against RADIUS servers and in development testing for new EAP
+methods. It can be easily used to automate EAP testing for
+interoperability and regression since the program can be run from
+shell scripts without require additional test components apart from a
+RADIUS server. For example, the automated EAP tests described in
+eap_testing.txt are implemented with eapol_test. Similarly, eapol_test
+could be used to implement an automated regression test suite for a
+RADIUS authentication server.
+
+eapol_test uses the same build time configuration file, .config, as
+%wpa_supplicant. This file is used to select which EAP methods are
+included in eapol_test. This program is not built with the default
+Makefile target, so a separate make command needs to be used to
+compile the tool:
+
+\verbatim
+make eapol_test
+\endverbatim
+
+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 scard
+eapol_test sim <PIN> <num triplets> [debug]
+
+options:
+ -c<conf> = configuration file
+ -a<AS IP> = IP address of the authentication server, default 127.0.0.1
+ -p<AS port> = UDP port of the authentication server, default 1812
+ -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
+ -n = no MPPE keys expected
+\endverbatim
+
+
+As an example,
+\verbatim
+eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
+\endverbatim
+tries to complete EAP authentication based on the network
+configuration from test.conf against the RADIUS server running on the
+local host. A re-authentication is triggered to test fast
+re-authentication. The configuration file uses the same format for
+network blocks as %wpa_supplicant.
+
+
+\section preauth_test preauth_test - WPA2 pre-authentication and EAP peer testing
+
+preauth_test is similar to eapol_test in the sense that in combines
+EAP peer implementation with something else, in this case, with WPA2
+pre-authentication. This tool can be used to test pre-authentication
+based on the code that %wpa_supplicant is using. As such, it tests
+both the %wpa_supplicant implementation and the functionality of an
+access point.
+
+preauth_test is built with:
+
+\verbatim
+make preauth_test
+\endverbatim
+
+and it uses following command line arguments:
+
+\verbatim
+usage: preauth_test <conf> <target MAC address> <ifname>
+\endverbatim
+
+For example,
+\verbatim
+preauth_test test.conf 02:11:22:33:44:55 eth0
+\endverbatim
+would use network configuration from test.conf to try to complete
+pre-authentication with AP using BSSID 02:11:22:33:44:55. The
+pre-authentication packets would be sent using the eth0 interface.
+
+
+\section driver_test driver_test - driver interface for testing wpa_supplicant
+
+%wpa_supplicant was designed to support number of different ways to
+communicate with a network device driver. This design uses \ref
+driver_wrapper "driver interface API" and number of driver interface
+implementations. One of these is driver_test.c, i.e., a test driver
+interface that is actually not using any drivers. Instead, it provides
+a mechanism for running %wpa_supplicant without having to have a
+device driver or wireless LAN hardware for that matter.
+
+driver_test can be used to talk directly with hostapd's driver_test
+component to create a test setup where one or more clients and access
+points can be tested within one test host and without having to have
+multiple wireless cards. This makes it easier to test the core code in
+%wpa_supplicant, and hostapd for that matter. Since driver_test uses
+the same driver API than any other driver interface implementation,
+the core code of %wpa_supplicant and hostapd can be tested with the
+same coverage as one would get when using real wireless cards. The
+only area that is not tested is the driver interface implementation
+(driver_*.c).
+
+Having the possibility to use simulated network components makes it
+much easier to do development testing while adding new features and to
+reproduce reported bugs. As such, it is often easiest to just do most
+of the development and bug fixing without using real hardware. Once
+the driver_test setup has been used to implement a new feature or fix
+a bug, the end result can be verified with wireless LAN cards. In many
+cases, this may even be unnecessary, depending on what area the
+feature/bug is relating to. Of course, changes to driver interfaces
+will still require use of real hardware.
+
+Since multiple components can be run within a single host, testing of
+complex network configuration, e.g., large number of clients
+association with an access point, becomes quite easy. All the tests
+can also be automated without having to resort to complex test setup
+using remote access to multiple computers.
+
+driver_test can be included in the %wpa_supplicant build in the same
+way as any other driver interface, i.e., by adding the following line
+into .config:
+
+\verbatim
+CONFIG_DRIVER_TEST=y
+\endverbatim
+
+When running %wpa_supplicant, the test interface is selected by using
+\a -Dtest command line argument. The interface name (\a -i argument)
+can be selected arbitrarily, i.e., it does not need to match with any
+existing network interface. The interface name is used to generate a
+MAC address, so when using multiple clients, each should use a
+different interface, e.g., \a sta1, \a sta2, and so on.
+
+%wpa_supplicant and hostapd are configured in the same way as they
+would be for normal use. Following example shows a simple test setup
+for WPA-PSK.
+
+hostapd is configured with following psk-test.conf configuration file:
+
+\verbatim
+driver=test
+
+interface=ap1
+logger_stdout=-1
+logger_stdout_level=0
+debug=2
+dump_file=/tmp/hostapd.dump
+
+test_socket=/tmp/Test/ap1
+
+ssid=jkm-test-psk
+
+wpa=1
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=TKIP
+wpa_passphrase=12345678
+\endverbatim
+
+and started with following command:
+
+\verbatim
+hostapd psk-test.conf
+\endverbatim
+
+%wpa_supplicant uses following configuration file:
+
+\verbatim
+driver_param=test_socket=/tmp/Test/ap1
+
+network={
+ ssid="jkm-test-psk"
+ key_mgmt=WPA-PSK
+ psk="12345678"
+}
+\endverbatim
+
+%wpa_supplicant can then be started with following command:
+
+\verbatim
+wpa_supplicant -Dtest -cpsk-test.conf -ista1 -ddK
+\endverbatim
+
+If run without debug information, i.e., with
+
+\verbatim
+wpa_supplicant -Dtest -cpsk-test.conf -ista1
+\endverbatim
+
+%wpa_supplicant completes authentication and prints following events:
+
+\verbatim
+Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
+Associated with 02:b8:a6:62:08:5a
+WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
+CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
+\endverbatim
+
+If test setup is using multiple clients, it is possible to run
+multiple %wpa_supplicant processes. Alternatively, the support for
+multiple interfaces can be used with just one process to save some
+resources on single-CPU systems. For example, following command runs
+two clients:
+
+\verbatim
+./wpa_supplicant -Dtest -cpsk-test.conf -ista1 \
+ -N -Dtest -cpsk-test.conf -ista2
+\endverbatim
+
+This shows following event log:
+
+\verbatim
+Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
+Associated with 02:b8:a6:62:08:5a
+WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
+CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
+Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
+Associated with 02:b8:a6:62:08:5a
+WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
+CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
+\endverbatim
+
+hostapd shows this with following events:
+
+\verbatim
+ap1: STA 02:b5:64:63:30:63 IEEE 802.11: associated
+ap1: STA 02:b5:64:63:30:63 WPA: pairwise key handshake completed (WPA)
+ap1: STA 02:b5:64:63:30:63 WPA: group key handshake completed (WPA)
+ap1: STA 02:2a:c4:18:5b:f3 IEEE 802.11: associated
+ap1: STA 02:2a:c4:18:5b:f3 WPA: pairwise key handshake completed (WPA)
+ap1: STA 02:2a:c4:18:5b:f3 WPA: group key handshake completed (WPA)
+\endverbatim
+
+By default, driver_param is simulating a driver that uses the WPA/RSN
+IE generated by %wpa_supplicant. Driver-generated IE and AssocInfo
+events can be tested by adding \a use_associnfo=1 to the \a driver_param
+line in the configuration file. For example:
+
+\verbatim
+driver_param=test_socket=/tmp/Test/ap1 use_associnfo=1
+\endverbatim
+
+
+\section unit_tests Unit tests
+
+Number of the components (.c files) used in %wpa_supplicant define
+their own unit tests for automated validation of the basic
+functionality. Most of the tests for cryptographic algorithms are
+using standard test vectors to validate functionality. These tests can
+be useful especially when verifying port to a new CPU target.
+
+In most cases, these tests are implemented in the end of the same file
+with functions that are normally commented out, but ca be included by
+defining a pre-processor variable when building the file separately.
+The details of the needed build options are included in the Makefile
+(test-* targets). All automated unit tests can be run with
+
+\verbatim
+make tests
+\endverbatim
+
+This make target builds and runs each test and terminates with zero
+exit code if all tests were completed successfully.
+
+*/
diff --git a/contrib/wpa_supplicant/doc/wpa_supplicant.fig b/contrib/wpa_supplicant/doc/wpa_supplicant.fig
index dc1d9df..06abfb5 100644
--- a/contrib/wpa_supplicant/doc/wpa_supplicant.fig
+++ b/contrib/wpa_supplicant/doc/wpa_supplicant.fig
@@ -117,7 +117,7 @@ Single
9600 3000 10275 3000 10275 3300 9600 3300 9600 3000
4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3225 TLS\001
-6
-6 8100 4425 10425 6975
+6 8100 4425 10425 7350
6 8175 4725 9225 5025
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
@@ -153,11 +153,6 @@ Single
8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
-6
-6 8175 6600 9675 6900
-2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
- 8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
-4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
--6
6 9300 6225 10350 6525
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
9300 6225 10350 6225 10350 6525 9300 6525 9300 6225
@@ -173,10 +168,35 @@ Single
9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
-6
+6 8175 6975 9675 7275
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 6975 9675 6975 9675 7275 8175 7275 8175 6975
+4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 7200 EAP-MSCHAPv2\001
+-6
+6 9300 6600 10350 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 6600 10350 6600 10350 6900 9300 6900 9300 6600
+4 0 0 50 -1 0 12 0.0000 4 135 870 9375 6825 EAP-FAST\001
+-6
+6 8175 6600 9225 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 6600 9225 6600 9225 6900 8175 6900 8175 6600
+4 0 0 50 -1 0 12 0.0000 4 135 795 8250 6825 EAP-PAX\001
+-6
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
- 8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
+ 8100 7350 10425 7350 10425 4425 8100 4425 8100 7350
4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
-6
+6 2775 5025 4050 5325
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 2775 5025 4050 5025 4050 5325 2775 5325 2775 5025
+4 0 0 50 -1 0 12 0.0000 4 135 990 2925 5250 driver events\001
+-6
+6 2775 3150 4050 3450
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
+4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
+-6
2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
1275 4200 1875 4200
2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
@@ -213,9 +233,15 @@ Single
1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
9900 4425 9900 3300
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
+ 4350 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4350 3900 4050 3450
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4350 4425 4050 5025
4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
-4 0 0 50 -1 2 14 0.0000 4 195 1425 1637 2371 wpa_supplicant\001
+4 0 0 50 -1 2 14 0.0000 4 210 1440 1637 2371 wpa_supplicant\001
diff --git a/contrib/wpa_supplicant/driver.h b/contrib/wpa_supplicant/driver.h
index da28014..9864e9b 100644
--- a/contrib/wpa_supplicant/driver.h
+++ b/contrib/wpa_supplicant/driver.h
@@ -1,13 +1,23 @@
+/*
+ * WPA Supplicant - driver interface definition
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 DRIVER_H
#define DRIVER_H
#define WPA_SUPPLICANT_DRIVER_VERSION 2
-typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } 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,
- KEY_MGMT_802_1X_NO_WPA, KEY_MGMT_WPA_NONE } wpa_key_mgmt;
+#include "defs.h"
#define AUTH_ALG_OPEN_SYSTEM 0x01
#define AUTH_ALG_SHARED_KEY 0x02
@@ -16,7 +26,31 @@ typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
#define IEEE80211_MODE_INFRA 0
#define IEEE80211_MODE_IBSS 1
+#define IEEE80211_CAP_ESS 0x0001
+#define IEEE80211_CAP_IBSS 0x0002
+#define IEEE80211_CAP_PRIVACY 0x0010
+
#define SSID_MAX_WPA_IE_LEN 40
+/**
+ * struct wpa_scan_result - Scan results
+ * @bssid: BSSID
+ * @ssid: SSID
+ * @ssid_len: length of the ssid
+ * @wpa_ie: WPA IE
+ * @wpa_ie_len: length of the wpa_ie
+ * @rsn_ie: RSN IE
+ * @rsn_ie_len: length of the RSN IE
+ * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
+ * @caps: capability information field in host byte order
+ * @qual: signal quality
+ * @noise: noise level
+ * @level: signal level
+ * @maxrate: maximum supported rate
+ *
+ * This structure is used as a generic format for scan results from the
+ * driver. Each driver interface implementation is responsible for converting
+ * the driver or OS specific scan results into this format.
+ */
struct wpa_scan_result {
u8 bssid[ETH_ALEN];
u8 ssid[32];
@@ -25,40 +59,57 @@ struct wpa_scan_result {
size_t wpa_ie_len;
u8 rsn_ie[SSID_MAX_WPA_IE_LEN];
size_t rsn_ie_len;
- int freq; /* MHz */
- int caps; /* e.g. privacy */
- int qual; /* signal quality */
+ int freq;
+ u16 caps;
+ int qual;
int noise;
int level;
int maxrate;
};
-/* Parameters for associate driver_ops. */
+/**
+ * struct wpa_driver_associate_params - Association parameters
+ * Data for struct wpa_driver_ops::associate().
+ */
struct wpa_driver_associate_params {
- /* BSSID of the selected AP */
+ /**
+ * bssid - BSSID of the selected AP
+ * This can be %NULL, if ap_scan=2 mode is used and the driver is
+ * responsible for selecting with which BSS to associate. */
const u8 *bssid;
- /* The selected SSID and its length in bytes */
+ /**
+ * ssid - The selected SSID
+ */
const u8 *ssid;
size_t ssid_len;
- /* frequency that the selected AP is using (in MHz as
- * reported in the scan results) */
+ /**
+ * freq - Frequency of the channel the selected AP is using
+ * Frequency that the selected AP is using (in MHz as
+ * reported in the scan results)
+ */
int freq;
- /* WPA information element to be included in (Re)Association
+ /**
+ * wpa_ie - WPA information element for (Re)Association Request
+ * WPA information element to be included in (Re)Association
* Request (including information element id and length). Use
* of this WPA IE is optional. If the driver generates the WPA
- * IE, it can use @pairwise_suite, @group_suite, and
- * @key_mgmt_suite to select proper algorithms. In this case,
+ * IE, it can use pairwise_suite, group_suite, and
+ * key_mgmt_suite to select proper algorithms. In this case,
* the driver has to notify wpa_supplicant about the used WPA
* IE by generating an event that the interface code will
* convert into EVENT_ASSOCINFO data (see wpa_supplicant.h).
- * When using WPA2/IEEE 802.11i, @wpa_ie is used for RSN IE
+ * When using WPA2/IEEE 802.11i, wpa_ie is used for RSN IE
* instead. The driver can determine which version is used by
* looking at the first byte of the IE (0xdd for WPA, 0x30 for
- * WPA2/RSN). @wpa_ie_len: length of the @wpa_ie */
+ * WPA2/RSN).
+ */
const u8 *wpa_ie;
+ /**
+ * wpa_ie_len - length of the wpa_ie
+ */
size_t wpa_ie_len;
/* The selected pairwise/group cipher and key management
@@ -67,10 +118,21 @@ struct wpa_driver_associate_params {
wpa_cipher group_suite;
wpa_key_mgmt key_mgmt_suite;
- int auth_alg; /* bit field of AUTH_ALG_* */
- int mode; /* IEEE80211_MODE_* */
+ /**
+ * auth_alg - Allowed authentication algorithms
+ * Bit field of AUTH_ALG_*
+ */
+ int auth_alg;
+
+ /**
+ * mode - Operation mode (infra/ibss) IEEE80211_MODE_*
+ */
+ int mode;
};
+/**
+ * struct wpa_driver_capa - Driver capability information
+ */
struct wpa_driver_capa {
#define WPA_DRIVER_CAPA_KEY_MGMT_WPA 0x00000001
#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2 0x00000002
@@ -97,33 +159,40 @@ struct wpa_driver_capa {
};
+/**
+ * struct wpa_driver_ops - Driver interface API definition
+ *
+ * This structure defines the API that each driver interface needs to implement
+ * for core wpa_supplicant code. All driver specific functionality is captured
+ * in this wrapper.
+ */
struct wpa_driver_ops {
- /* name of the driver interface */
+ /** Name of the driver interface */
const char *name;
- /* one line description of the driver interface */
+ /** One line description of the driver interface */
const char *desc;
/**
- * get_bssid - get the current BSSID
+ * get_bssid - Get the current BSSID
* @priv: private driver interface data
* @bssid: buffer for BSSID (ETH_ALEN = 6 bytes)
*
* Returns: 0 on success, -1 on failure
*
- * Query kernel driver for the current BSSID and copy it to @bssid.
- * Setting @bssid to 00:00:00:00:00:00 is recommended if the STA is not
+ * Query kernel driver for the current BSSID and copy it to bssid.
+ * Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not
* associated.
*/
int (*get_bssid)(void *priv, u8 *bssid);
/**
- * get_ssid - get the current SSID
+ * get_ssid - Get the current SSID
* @priv: private driver interface data
* @ssid: buffer for SSID (at least 32 bytes)
*
- * Returns: length of the SSID on success, -1 on failure
+ * Returns: Length of the SSID on success, -1 on failure
*
- * Query kernel driver for the current SSID and copy it to @ssid.
+ * Query kernel driver for the current SSID and copy it to ssid.
* Returning zero is recommended if the STA is not associated.
*
* Note: SSID is an array of octets, i.e., it is not nul terminated and
@@ -134,35 +203,44 @@ struct wpa_driver_ops {
int (*get_ssid)(void *priv, u8 *ssid);
/**
- * set_wpa - enable/disable WPA support
+ * set_wpa - Enable/disable WPA support (OBSOLETE)
* @priv: private driver interface data
* @enabled: 1 = enable, 0 = disable
*
* Returns: 0 on success, -1 on failure
*
+ * Note: This function is included for backwards compatibility. This is
+ * called only just after init and just before deinit, so these
+ * functions can be used to implement same functionality and the driver
+ * interface need not define this function.
+ *
* Configure the kernel driver to enable/disable WPA support. This may
* be empty function, if WPA support is always enabled. Common
* configuration items are WPA IE (clearing it when WPA support is
- * disabled), Privacy flag for capability field, roaming mode (need to
- * allow wpa_supplicant to control roaming).
+ * disabled), Privacy flag configuration for capability field (note:
+ * this the value need to set in associate handler to allow plaintext
+ * mode to be used) when trying to associate with, roaming mode (can
+ * allow wpa_supplicant to control roaming if ap_scan=1 is used;
+ * however, drivers can also implement roaming if desired, especially
+ * ap_scan=2 mode is used for this).
*/
int (*set_wpa)(void *priv, int enabled);
/**
- * set_key - configure encryption key
+ * 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.
* @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
* broadcast/default keys
- * @key_idx: key index (0..3), always 0 for unicast keys
+ * @key_idx: key index (0..3), usually 0 for unicast keys
* @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
+ * @seq: sequence number/packet number, seq_len octets, the next
* packet number to be used for in replay protection; configured
* 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:
+ * @seq_len: length of the seq, depends on the algorithm:
* TKIP: 6 octets, CCMP: 6 octets
* @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
* 8-byte Rx Mic Key
@@ -173,25 +251,33 @@ struct wpa_driver_ops {
*
* Configure the given key for the kernel driver. If the driver
* supports separate individual keys (4 default keys + 1 individual),
- * @addr can be used to determine whether the key is default or
+ * addr can be used to determine whether the key is default or
* individual. If only 4 keys are supported, the default key with key
* index 0 is used as the individual key. STA must be configured to use
- * it as the default Tx key (@set_tx is set) and accept Rx for all the
+ * it as the default Tx key (set_tx is set) and accept Rx for all the
* key indexes. In most cases, WPA uses only key indexes 1 and 2 for
* broadcast keys, so key index 0 is available for this kind of
* configuration.
+ *
+ * Please note that TKIP keys include separate TX and RX MIC keys and
+ * some drivers may expect them in different order than wpa_supplicant
+ * is using. If the TX/RX keys are swapped, all TKIP encrypted packets
+ * will tricker Michael MIC errors. This can be fixed by changing the
+ * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
+ * in driver_*.c set_key() implementation, see driver_ndis.c for an
+ * example on how this can be done.
*/
int (*set_key)(void *priv, wpa_alg alg, const u8 *addr,
int key_idx, int set_tx, const u8 *seq, size_t seq_len,
const u8 *key, size_t key_len);
/**
- * init - initialize driver interface
+ * init - Initialize driver interface
* @ctx: context to be used when calling wpa_supplicant functions,
* e.g., wpa_supplicant_event()
* @ifname: interface name, e.g., wlan0
*
- * Return: pointer to private data, %NULL on failure
+ * Returns: Pointer to private data, %NULL on failure
*
* Initialize driver interface, including event processing for kernel
* driver events (e.g., associated, scan results, Michael MIC failure).
@@ -211,9 +297,8 @@ struct wpa_driver_ops {
void * (*init)(void *ctx, const char *ifname);
/**
- * deinit - deinitialize driver interface
- * @priv: pointer to private data (from matching
- * wpa_driver_events_init())
+ * deinit - Deinitialize driver interface
+ * @priv: private driver interface data from init()
*
* Shut down driver interface and processing of driver events. Free
* private data buffer if one was allocated in init() handler.
@@ -221,11 +306,23 @@ struct wpa_driver_ops {
void (*deinit)(void *priv);
/**
- * set_countermeasures - enable/disable TKIP countermeasures
+ * set_param - Set driver configuration parameters
+ * @priv: private driver interface data from init()
+ * @param: driver specific configuration parameters
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Optional handler for notifying driver interface about configuration
+ * parameters (driver_param).
+ */
+ int (*set_param)(void *priv, const char *param);
+
+ /**
+ * set_countermeasures - Enable/disable TKIP countermeasures
* @priv: private driver interface data
* @enabled: 1 = countermeasures enabled, 0 = disabled
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*
* Configure TKIP countermeasures. When these are enabled, the driver
* should drop all received and queued frames that are using TKIP.
@@ -233,11 +330,11 @@ struct wpa_driver_ops {
int (*set_countermeasures)(void *priv, int enabled);
/**
- * set_drop_unencrypted - enable/disable unencrypted frame filtering
+ * set_drop_unencrypted - Enable/disable unencrypted frame filtering
* @priv: private driver interface data
* @enabled: 1 = unencrypted Tx/Rx frames will be dropped, 0 = disabled
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*
* Configure the driver to drop all non-EAPOL frames (both receive and
* transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must
@@ -246,14 +343,14 @@ struct wpa_driver_ops {
int (*set_drop_unencrypted)(void *priv, int enabled);
/**
- * scan - request the driver to initiate scan
+ * scan - Request the driver to initiate scan
* @priv: private driver interface data
* @ssid: specific SSID to scan for (ProbeReq) or %NULL to scan for
* all SSIDs (either active scan with broadcast SSID or passive
* scan
* @ssid_len: length of the SSID
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*
* Once the scan results are ready, the driver should report scan
* results event for wpa_supplicant which will eventually request the
@@ -262,14 +359,15 @@ struct wpa_driver_ops {
int (*scan)(void *priv, const u8 *ssid, size_t ssid_len);
/**
- * get_scan_results - fetch the latest scan results
+ * get_scan_results - Fetch the latest scan results
* @priv: private driver interface data
* @results: pointer to buffer for scan results
* @max_size: maximum number of entries (buffer size)
*
- * Return: number of scan result entries used on success, -1 on failure
+ * Returns: Number of scan result entries used on success, -1 on
+ * failure
*
- * If scan results include more than @max_size BSSes, @max_size will be
+ * If scan results include more than max_size BSSes, max_size will be
* returned and the remaining entries will not be included in the
* buffer.
*/
@@ -278,39 +376,39 @@ struct wpa_driver_ops {
size_t max_size);
/**
- * deauthenticate - request driver to deauthenticate
+ * deauthenticate - Request driver to deauthenticate
* @priv: private driver interface data
* @addr: peer address (BSSID of the AP)
* @reason_code: 16-bit reason code to be sent in the deauthentication
* frame
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*/
int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
/**
- * disassociate - request driver to disassociate
+ * disassociate - Request driver to disassociate
* @priv: private driver interface data
* @addr: peer address (BSSID of the AP)
* @reason_code: 16-bit reason code to be sent in the disassociation
* frame
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*/
int (*disassociate)(void *priv, const u8 *addr, int reason_code);
/**
- * associate - request driver to associate
+ * associate - Request driver to associate
* @priv: private driver interface data
* @params: association parameters
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*/
int (*associate)(void *priv,
struct wpa_driver_associate_params *params);
/**
- * set_auth_alg - set IEEE 802.11 authentication algorithm
+ * set_auth_alg - Set IEEE 802.11 authentication algorithm
* @priv: private driver interface data
* @auth_alg: bit field of AUTH_ALG_*
*
@@ -326,43 +424,43 @@ struct wpa_driver_ops {
* associate() params, so set_auth_alg may not be needed in case of
* most drivers.
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*/
int (*set_auth_alg)(void *priv, int auth_alg);
/**
- * add_pmkid - add PMKSA cache entry to the driver
+ * add_pmkid - Add PMKSA cache entry to the driver
* @priv: private driver interface data
* @bssid: BSSID for the PMKSA cache entry
* @pmkid: PMKID for the PMKSA cache entry
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*
* This function is called when a new PMK is received, as a result of
* either normal authentication or RSN pre-authentication.
*
- * If the driver generates RSN IE, i.e., it does not use @wpa_ie in
+ * If the driver generates RSN IE, i.e., it does not use wpa_ie in
* associate(), add_pmkid() can be used to add new PMKSA cache entries
- * in the driver. If the driver uses @wpa_ie from wpa_supplicant, this
+ * in the driver. If the driver uses wpa_ie from wpa_supplicant, this
* driver_ops function does not need to be implemented. Likewise, if
* the driver does not support WPA, this function is not needed.
*/
int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
/**
- * remove_pmkid - remove PMKSA cache entry to the driver
+ * remove_pmkid - Remove PMKSA cache entry to the driver
* @priv: private driver interface data
* @bssid: BSSID for the PMKSA cache entry
* @pmkid: PMKID for the PMKSA cache entry
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*
* This function is called when the supplicant drops a PMKSA cache
* entry for any reason.
*
- * If the driver generates RSN IE, i.e., it does not use @wpa_ie in
+ * If the driver generates RSN IE, i.e., it does not use wpa_ie in
* associate(), remove_pmkid() can be used to synchronize PMKSA caches
- * between the driver and wpa_supplicant. If the driver uses @wpa_ie
+ * between the driver and wpa_supplicant. If the driver uses wpa_ie
* from wpa_supplicant, this driver_ops function does not need to be
* implemented. Likewise, if the driver does not support WPA, this
* function is not needed.
@@ -370,17 +468,17 @@ struct wpa_driver_ops {
int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
/**
- * flush_pmkid - flush PMKSA cache
+ * flush_pmkid - Flush PMKSA cache
* @priv: private driver interface data
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*
* This function is called when the supplicant drops all PMKSA cache
* entries for any reason.
*
- * If the driver generates RSN IE, i.e., it does not use @wpa_ie in
+ * If the driver generates RSN IE, i.e., it does not use wpa_ie in
* associate(), remove_pmkid() can be used to synchronize PMKSA caches
- * between the driver and wpa_supplicant. If the driver uses @wpa_ie
+ * between the driver and wpa_supplicant. If the driver uses wpa_ie
* from wpa_supplicant, this driver_ops function does not need to be
* implemented. Likewise, if the driver does not support WPA, this
* function is not needed.
@@ -388,17 +486,17 @@ struct wpa_driver_ops {
int (*flush_pmkid)(void *priv);
/**
- * flush_pmkid - flush PMKSA cache
+ * flush_pmkid - Flush PMKSA cache
* @priv: private driver interface data
*
- * Return: 0 on success, -1 on failure
+ * Returns: 0 on success, -1 on failure
*
* Get driver/firmware/hardware capabilities.
*/
int (*get_capa)(void *priv, struct wpa_driver_capa *capa);
/**
- * poll - poll driver for association information
+ * poll - Poll driver for association information
* @priv: private driver interface data
*
* This is an option callback that can be used when the driver does not
@@ -412,25 +510,50 @@ struct wpa_driver_ops {
void (*poll)(void *priv);
/**
- * get_ifname - get interface name
+ * get_ifname - Get interface name
+ * @priv: private driver interface data
+ *
+ * Returns: Pointer to the interface name. This can differ from the
+ * interface name used in init() call.
*
* This optional function can be used to allow the driver interface to
* replace the interface name with something else, e.g., based on an
* interface mapping from a more descriptive name.
- *
- * Returns a pointer to the interface name. This can differ from the
- * interface name used in init() call.
*/
const char * (*get_ifname)(void *priv);
/**
- * get_mac_addr - get own MAC address
+ * get_mac_addr - Get own MAC address
+ * @priv: private driver interface data
+ *
+ * Returns: Pointer to own MAC address or %NULL on failure
*
* This optional function can be used to get the own MAC address of the
* device from the driver interface code. This is only needed if the
* l2_packet implementation for the OS does not provide easy access to
* a MAC address. */
const u8 * (*get_mac_addr)(void *priv);
+
+ /**
+ * send_eapol - Optional function for sending EAPOL packets
+ * @priv: private driver interface data
+ * @dest: Destination MAC address
+ * @proto: Ethertype
+ * @data: EAPOL packet starting with IEEE 802.1X header
+ * @data_len: Size of the EAPOL packet
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * This optional function can be used to override l2_packet operations
+ * with driver specific functionality. If this function pointer is set,
+ * l2_packet module is not used at all and the driver interface code is
+ * responsible for receiving and sending all EAPOL packets. The
+ * received EAPOL packets are sent to core code by calling
+ * wpa_supplicant_rx_eapol(). The driver interface is required to
+ * implement get_mac_addr() handler if send_eapol() is used.
+ */
+ int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
+ const u8 *data, size_t data_len);
};
#endif /* DRIVER_H */
diff --git a/contrib/wpa_supplicant/driver_hostap.h b/contrib/wpa_supplicant/driver_hostap.h
new file mode 100644
index 0000000..7679105
--- /dev/null
+++ b/contrib/wpa_supplicant/driver_hostap.h
@@ -0,0 +1,153 @@
+/*
+ * WPA Supplicant - driver interaction with Linux Host AP driver
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 HOSTAP_DRIVER_H
+#define HOSTAP_DRIVER_H
+
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
+#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
+enum {
+ /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_TXRATECTRL = 2,
+ PRISM2_PARAM_BEACON_INT = 3,
+ PRISM2_PARAM_PSEUDO_IBSS = 4,
+ PRISM2_PARAM_ALC = 5,
+ /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_DUMP = 7,
+ PRISM2_PARAM_OTHER_AP_POLICY = 8,
+ PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
+ PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
+ PRISM2_PARAM_DTIM_PERIOD = 11,
+ PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
+ PRISM2_PARAM_MAX_WDS = 13,
+ PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
+ PRISM2_PARAM_AP_AUTH_ALGS = 15,
+ PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
+ PRISM2_PARAM_HOST_ENCRYPT = 17,
+ PRISM2_PARAM_HOST_DECRYPT = 18,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
+ PRISM2_PARAM_HOST_ROAMING = 21,
+ PRISM2_PARAM_BCRX_STA_KEY = 22,
+ PRISM2_PARAM_IEEE_802_1X = 23,
+ PRISM2_PARAM_ANTSEL_TX = 24,
+ PRISM2_PARAM_ANTSEL_RX = 25,
+ PRISM2_PARAM_MONITOR_TYPE = 26,
+ PRISM2_PARAM_WDS_TYPE = 27,
+ PRISM2_PARAM_HOSTSCAN = 28,
+ PRISM2_PARAM_AP_SCAN = 29,
+ PRISM2_PARAM_ENH_SEC = 30,
+ PRISM2_PARAM_IO_DEBUG = 31,
+ PRISM2_PARAM_BASIC_RATES = 32,
+ PRISM2_PARAM_OPER_RATES = 33,
+ PRISM2_PARAM_HOSTAPD = 34,
+ PRISM2_PARAM_HOSTAPD_STA = 35,
+ PRISM2_PARAM_WPA = 36,
+ PRISM2_PARAM_PRIVACY_INVOKED = 37,
+ PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
+ PRISM2_PARAM_DROP_UNENCRYPTED = 39,
+ PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
+};
+
+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+ PRISM2_HOSTAPD_FLUSH = 1,
+ PRISM2_HOSTAPD_ADD_STA = 2,
+ PRISM2_HOSTAPD_REMOVE_STA = 3,
+ PRISM2_HOSTAPD_GET_INFO_STA = 4,
+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+ PRISM2_SET_ENCRYPTION = 6,
+ PRISM2_GET_ENCRYPTION = 7,
+ PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
+ PRISM2_HOSTAPD_GET_RID = 9,
+ PRISM2_HOSTAPD_SET_RID = 10,
+ PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+ PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+ PRISM2_HOSTAPD_MLME = 13,
+ PRISM2_HOSTAPD_SCAN_REQ = 14,
+ PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
+};
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_RID_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((int) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
+ */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+
+struct prism2_hostapd_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u16 aid;
+ u16 capability;
+ u8 tx_supp_rates;
+ } add_sta;
+ struct {
+ u32 inactive_sec;
+ } get_info_sta;
+ struct {
+ u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+ u32 flags;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+ struct {
+ u32 flags_and;
+ u32 flags_or;
+ } set_flags_sta;
+ struct {
+ u16 rid;
+ u16 len;
+ u8 data[0];
+ } rid;
+ struct {
+ u8 len;
+ u8 data[0];
+ } generic_elem;
+ struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+ u16 cmd;
+ u16 reason_code;
+ } mlme;
+ struct {
+ u8 ssid_len;
+ u8 ssid[32];
+ } scan_req;
+ } u;
+};
+
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY 0x01
+#define HOSTAP_CRYPT_FLAG_PERMANENT 0x02
+
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
+#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
+#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
+
+#endif /* HOSTAP_DRIVER_H */
diff --git a/contrib/wpa_supplicant/driver_ndis.c b/contrib/wpa_supplicant/driver_ndis.c
index 1dba95a..5ad2a31 100644
--- a/contrib/wpa_supplicant/driver_ndis.c
+++ b/contrib/wpa_supplicant/driver_ndis.c
@@ -393,6 +393,20 @@ static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
{
struct wpa_driver_ndis_data *drv = priv;
+ if (drv->wired) {
+ /*
+ * Report PAE group address as the "BSSID" for wired
+ * connection.
+ */
+ bssid[0] = 0x01;
+ bssid[1] = 0x80;
+ bssid[2] = 0xc2;
+ bssid[3] = 0x00;
+ bssid[4] = 0x00;
+ bssid[5] = 0x03;
+ return 0;
+ }
+
return ndis_get_oid(drv, OID_802_11_BSSID, bssid, ETH_ALEN) < 0 ?
-1 : 0;
}
@@ -406,8 +420,13 @@ static int wpa_driver_ndis_get_ssid(void *priv, u8 *ssid)
int res;
res = ndis_get_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
- if (!res) {
+ if (res < 4) {
wpa_printf(MSG_DEBUG, "NDIS: Failed to get SSID");
+ if (drv->wired) {
+ wpa_printf(MSG_DEBUG, "NDIS: Allow get_ssid failure "
+ "with a wired interface");
+ return 0;
+ }
return -1;
}
memcpy(ssid, buf.Ssid, buf.SsidLength);
@@ -423,6 +442,12 @@ static int wpa_driver_ndis_set_ssid(struct wpa_driver_ndis_data *drv,
memset(&buf, 0, sizeof(buf));
buf.SsidLength = ssid_len;
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
+ * that point.
+ */
+ drv->radio_enabled = 1;
return ndis_set_oid(drv, OID_802_11_SSID, (char *) &buf, sizeof(buf));
}
@@ -562,7 +587,7 @@ static int wpa_driver_ndis_get_scan_results(void *priv,
memcpy(results[i].ssid, bss->Ssid.Ssid, bss->Ssid.SsidLength);
results[i].ssid_len = bss->Ssid.SsidLength;
if (bss->Privacy)
- results[i].caps = 1; /* FIX? */
+ results[i].caps |= IEEE80211_CAP_PRIVACY;
results[i].level = (int) bss->Rssi;
results[i].freq = bss->Configuration.DSConfig / 1000;
for (j = 0; j < sizeof(bss->SupportedRates); j++) {
@@ -574,6 +599,8 @@ static int wpa_driver_ndis_get_scan_results(void *priv,
}
wpa_driver_ndis_get_ies(&results[i], bss->IEs, bss->IELength);
pos += bss->Length;
+ if (pos > (char *) b + blen)
+ break;
}
free(b);
@@ -928,10 +955,12 @@ static int wpa_driver_ndis_flush_pmkid(void *priv)
static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
{
- char buf[512];
+ char buf[512], *pos;
NDIS_802_11_ASSOCIATION_INFORMATION *ai;
- int len;
+ int len, i;
union wpa_event_data data;
+ NDIS_802_11_BSSID_LIST_EX *b;
+ size_t blen;
len = ndis_get_oid(drv, OID_802_11_ASSOCIATION_INFORMATION, buf,
sizeof(buf));
@@ -990,8 +1019,47 @@ static int wpa_driver_ndis_get_associnfo(struct wpa_driver_ndis_data *drv)
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);
+ 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);
+ b = NULL;
+ goto skip_scan_results;
+ }
+ wpa_printf(MSG_DEBUG, "NDIS: %d BSSID items to process for AssocInfo",
+ (unsigned int) b->NumberOfItems);
+
+ 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 &&
+ bss->IELength > sizeof(NDIS_802_11_FIXED_IEs)) {
+ data.assoc_info.beacon_ies =
+ ((u8 *) bss->IEs) +
+ sizeof(NDIS_802_11_FIXED_IEs);
+ data.assoc_info.beacon_ies_len =
+ bss->IELength - sizeof(NDIS_802_11_FIXED_IEs);
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: Beacon IEs",
+ data.assoc_info.beacon_ies,
+ data.assoc_info.beacon_ies_len);
+ break;
+ }
+ pos += bss->Length;
+ if (pos > (char *) b + blen)
+ break;
+ }
+
+skip_scan_results:
wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+ free(b);
+
return 0;
}
@@ -1001,6 +1069,9 @@ 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];
+ 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)
@@ -1339,39 +1410,63 @@ static const u8 * wpa_driver_ndis_get_mac_addr(void *priv)
static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
{
- PTSTR names, pos;
+ PTSTR names, pos, pos2;
ULONG len;
BOOLEAN res;
- const int MAX_ADAPTERS = 16;
+ const int MAX_ADAPTERS = 32;
char *name[MAX_ADAPTERS];
char *desc[MAX_ADAPTERS];
int num_name, num_desc, i, found_name, found_desc;
size_t dlen;
- len = 1024;
+ wpa_printf(MSG_DEBUG, "NDIS: Packet.dll version: %s",
+ PacketGetVersion());
+
+ len = 8192;
names = malloc(len);
if (names == NULL)
return -1;
memset(names, 0, len);
res = PacketGetAdapterNames(names, &len);
- if (!res && len > 1024) {
+ if (!res && len > 8192) {
free(names);
names = malloc(len);
if (names == NULL)
return -1;
memset(names, 0, len);
res = PacketGetAdapterNames(names, &len);
- if (!res) {
- free(names);
- return -1;
- }
+ }
+
+ if (!res) {
+ wpa_printf(MSG_ERROR, "NDIS: Failed to get adapter list "
+ "(PacketGetAdapterNames)");
+ free(names);
+ return -1;
}
/* wpa_hexdump_ascii(MSG_DEBUG, "NDIS: AdapterNames", names, len); */
+ if (names[0] && names[1] == '\0' && names[2] && names[3] == '\0') {
+ wpa_printf(MSG_DEBUG, "NDIS: Looks like adapter names are in "
+ "UNICODE");
+ /* Convert to ASCII */
+ pos2 = pos = names;
+ while (pos2 < names + len) {
+ if (pos2[0] == '\0' && pos2[1] == '\0' &&
+ pos2[2] == '\0' && pos2[3] == '\0') {
+ pos2 += 4;
+ break;
+ }
+ *pos++ = pos2[0];
+ pos2 += 2;
+ }
+ memcpy(pos + 2, names, pos - names);
+ pos += 2;
+ } else
+ pos = names;
+
num_name = 0;
- pos = names;
while (pos < names + len) {
name[num_name] = pos;
while (*pos && pos < names + len)
@@ -1420,6 +1515,13 @@ static int wpa_driver_ndis_get_names(struct wpa_driver_ndis_data *drv)
}
}
+ /*
+ * Windows 98 with Packet.dll 3.0 alpha3 does not include adapter
+ * descriptions. Fill in dummy descriptors to work around this.
+ */
+ while (num_desc < num_name)
+ desc[num_desc++] = "dummy description";
+
if (num_name != num_desc) {
wpa_printf(MSG_DEBUG, "NDIS: mismatch in adapter name and "
"description counts (%d != %d)",
@@ -1537,6 +1639,13 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
"OID_802_11_INFRASTRUCTURE_MODE (%d)",
(int) mode);
/* Try to continue anyway */
+
+ if (!drv->has_capability && drv->capa.enc == 0) {
+ wpa_printf(MSG_DEBUG, "NDIS: Driver did not provide "
+ "any wireless capabilities - assume it is "
+ "a wired interface");
+ drv->wired = 1;
+ }
}
return drv;
@@ -1565,7 +1674,7 @@ static void wpa_driver_ndis_deinit(void *priv)
}
-struct wpa_driver_ops wpa_driver_ndis_ops = {
+const struct wpa_driver_ops wpa_driver_ndis_ops = {
.name = "ndis",
.desc = "Windows NDIS driver",
.init = wpa_driver_ndis_init,
diff --git a/contrib/wpa_supplicant/driver_ndis.h b/contrib/wpa_supplicant/driver_ndis.h
index a79afcb..7906fdc 100644
--- a/contrib/wpa_supplicant/driver_ndis.h
+++ b/contrib/wpa_supplicant/driver_ndis.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant - Windows/NDIS driver interface
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 DRIVER_NDIS_H
#define DRIVER_NDIS_H
@@ -21,6 +35,7 @@ struct wpa_driver_ndis_data {
struct ndis_pmkid_entry *pmkid;
int event_sock;
char *adapter_desc;
+ int wired;
};
#endif /* DRIVER_NDIS_H */
diff --git a/contrib/wpa_supplicant/driver_wired.c b/contrib/wpa_supplicant/driver_wired.c
new file mode 100644
index 0000000..359a21b
--- /dev/null
+++ b/contrib/wpa_supplicant/driver_wired.c
@@ -0,0 +1,271 @@
+/*
+ * WPA Supplicant - wired Ethernet driver interface
+ * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netpacket/packet.h>
+#include <net/if.h>
+
+#include "common.h"
+#include "driver.h"
+#include "wpa_supplicant.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
+struct wpa_driver_wired_data {
+ void *ctx;
+ int pf_sock;
+ char ifname[IFNAMSIZ + 1];
+ int membership, multi, iff_allmulti, iff_up;
+};
+
+
+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;
+ return 0;
+}
+
+
+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);
+ return 0;
+}
+
+
+static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
+ memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+
+ if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOC{ADD/DEL}MULTI]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int wpa_driver_wired_membership(struct wpa_driver_wired_data *drv,
+ const u8 *addr, int add)
+{
+#ifdef __linux__
+ struct packet_mreq mreq;
+
+ if (drv->pf_sock == -1)
+ return -1;
+
+ 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);
+
+ if (setsockopt(drv->pf_sock, SOL_PACKET,
+ add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ perror("setsockopt");
+ return -1;
+ }
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+static void * wpa_driver_wired_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_wired_data *drv;
+ int flags;
+
+ drv = malloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ memset(drv, 0, sizeof(*drv));
+ 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
+ drv->pf_sock = -1;
+#endif
+
+ if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
+ !(flags & IFF_UP) &&
+ wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
+ drv->iff_up = 1;
+ }
+
+ if (wpa_driver_wired_membership(drv, pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
+ "packet socket", __func__);
+ drv->membership = 1;
+ } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
+ "SIOCADDMULTI", __func__);
+ drv->multi = 1;
+ } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
+ wpa_printf(MSG_INFO, "%s: Could not get interface "
+ "flags", __func__);
+ free(drv);
+ return NULL;
+ } else if (flags & IFF_ALLMULTI) {
+ wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
+ "for multicast", __func__);
+ } else if (wpa_driver_wired_set_ifflags(ifname,
+ flags | IFF_ALLMULTI) < 0) {
+ wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
+ __func__);
+ free(drv);
+ return NULL;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
+ __func__);
+ drv->iff_allmulti = 1;
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_wired_deinit(void *priv)
+{
+ struct wpa_driver_wired_data *drv = priv;
+ int flags;
+
+ if (drv->membership &&
+ wpa_driver_wired_membership(drv, pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
+ "group (PACKET)", __func__);
+ }
+
+ if (drv->multi &&
+ wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
+ "group (SIOCDELMULTI)", __func__);
+ }
+
+ if (drv->iff_allmulti &&
+ (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
+ wpa_driver_wired_set_ifflags(drv->ifname,
+ flags & ~IFF_ALLMULTI) < 0)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
+ __func__);
+ }
+
+ if (drv->iff_up &&
+ wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
+ (flags & IFF_UP) &&
+ wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
+ __func__);
+ }
+
+ if (drv->pf_sock != -1)
+ close(drv->pf_sock);
+
+ 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,
+ .deinit = wpa_driver_wired_deinit,
+};
diff --git a/contrib/wpa_supplicant/drivers.c b/contrib/wpa_supplicant/drivers.c
index cb016ba..4fd0509 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, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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
@@ -49,6 +49,9 @@ extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
#ifdef CONFIG_DRIVER_NDIS
extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_WIRED
+extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
+#endif /* CONFIG_DRIVER_WIRED */
#ifdef CONFIG_DRIVER_TEST
extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
#endif /* CONFIG_DRIVER_TEST */
@@ -89,6 +92,9 @@ struct wpa_driver_ops *wpa_supplicant_drivers[] =
#ifdef CONFIG_DRIVER_NDIS
&wpa_driver_ndis_ops,
#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_WIRED
+ &wpa_driver_wired_ops,
+#endif /* CONFIG_DRIVER_WIRED */
#ifdef CONFIG_DRIVER_TEST
&wpa_driver_test_ops,
#endif /* CONFIG_DRIVER_TEST */
diff --git a/contrib/wpa_supplicant/eap.c b/contrib/wpa_supplicant/eap.c
index 267907c..5d81870 100644
--- a/contrib/wpa_supplicant/eap.c
+++ b/contrib/wpa_supplicant/eap.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant / EAP state machines
+ * WPA Supplicant / EAP state machines (RFC 4137)
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -15,13 +15,16 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <ctype.h>
#include "common.h"
#include "eap_i.h"
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "tls.h"
-#include "md5.h"
+#include "crypto.h"
+#include "pcsc_funcs.h"
+#include "wpa_ctrl.h"
#define EAP_MAX_AUTH_ROUNDS 50
@@ -63,6 +66,9 @@ extern const struct eap_method eap_method_aka;
#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[] =
{
@@ -102,10 +108,18 @@ static const struct eap_method *eap_methods[] =
#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;
@@ -119,10 +133,11 @@ const struct eap_method * eap_sm_get_eap_methods(int method)
static Boolean eap_sm_allowMethod(struct eap_sm *sm, 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, u8 *req, size_t len);
-static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, 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_parseEapReq(struct eap_sm *sm, u8 *req, 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);
@@ -219,12 +234,14 @@ SM_STATE(EAP, INITIALIZE)
eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
sm->lastId = -1; /* new session - make sure this does not match with
* the first EAP-Packet */
- /* draft-ietf-eap-statemachine-02.pdf does not reset eapResp and
- * eapNoResp here. However, this seemed to be able to trigger cases
- * where both were set and if EAPOL state machine uses eapNoResp first,
- * it may end up not sending a real reply correctly. This occurred
- * when the workaround in FAIL state set eapNoResp = TRUE.. Maybe that
- * workaround needs to be fixed to do something else(?) */
+ /*
+ * RFC 4137 does not reset eapResp and eapNoResp here. However, this
+ * seemed to be able to trigger cases where both were set and if EAPOL
+ * state machine uses eapNoResp first, it may end up not sending a real
+ * reply correctly. This occurred when the workaround in FAIL state set
+ * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
+ * something else(?)
+ */
eapol_set_bool(sm, EAPOL_eapResp, FALSE);
eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
sm->num_rounds = 0;
@@ -246,7 +263,7 @@ SM_STATE(EAP, IDLE)
SM_STATE(EAP, RECEIVED)
{
- u8 *eapReqData;
+ const u8 *eapReqData;
size_t eapReqDataLen;
SM_ENTRY(EAP, RECEIVED);
@@ -284,14 +301,35 @@ SM_STATE(EAP, GET_METHOD)
else
sm->eap_method_priv = sm->m->init(sm);
if (sm->eap_method_priv == NULL) {
- wpa_printf(MSG_DEBUG, "EAP: Failed to "
- "initialize EAP method %d",
- sm->selectedMethod);
+ 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;
}
}
@@ -381,7 +419,7 @@ SM_STATE(EAP, DISCARD)
SM_STATE(EAP, IDENTITY)
{
- u8 *eapReqData;
+ const u8 *eapReqData;
size_t eapReqDataLen;
SM_ENTRY(EAP, IDENTITY);
@@ -395,7 +433,7 @@ SM_STATE(EAP, IDENTITY)
SM_STATE(EAP, NOTIFICATION)
{
- u8 *eapReqData;
+ const u8 *eapReqData;
size_t eapReqDataLen;
SM_ENTRY(EAP, NOTIFICATION);
@@ -429,15 +467,24 @@ SM_STATE(EAP, SUCCESS)
if (sm->eapKeyData != NULL)
sm->eapKeyAvailable = TRUE;
eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
- /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
- * this seems to be required to avoid processing the same request
- * twice when state machine is initialized. */
+
+ /*
+ * RFC 4137 does not clear eapReq here, but this seems to be required
+ * to avoid processing the same request twice when state machine is
+ * initialized.
+ */
eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here, but
- * this seems to be required to get EAPOL Supplicant backend state
- * machine into SUCCESS state. In addition, either eapResp or eapNoResp
- * is required to be set after processing the received EAP frame. */
+
+ /*
+ * RFC 4137 does not set eapNoResp here, but this seems to be required
+ * to get EAPOL Supplicant backend state machine into SUCCESS state. In
+ * addition, either eapResp or eapNoResp is required to be set after
+ * processing the received EAP frame.
+ */
eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ "EAP authentication completed successfully");
}
@@ -445,14 +492,23 @@ SM_STATE(EAP, FAILURE)
{
SM_ENTRY(EAP, FAILURE);
eapol_set_bool(sm, EAPOL_eapFail, TRUE);
- /* draft-ietf-eap-statemachine-02.pdf does not clear eapReq here, but
- * this seems to be required to avoid processing the same request
- * twice when state machine is initialized. */
+
+ /*
+ * RFC 4137 does not clear eapReq here, but this seems to be required
+ * to avoid processing the same request twice when state machine is
+ * initialized.
+ */
eapol_set_bool(sm, EAPOL_eapReq, FALSE);
- /* draft-ietf-eap-statemachine-02.pdf does not set eapNoResp here.
- * However, either eapResp or eapNoResp is required to be set after
- * processing the received EAP frame. */
+
+ /*
+ * RFC 4137 does not set eapNoResp here. However, either eapResp or
+ * eapNoResp is required to be set after processing the received EAP
+ * frame.
+ */
eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+ "EAP authentication failed");
}
@@ -461,9 +517,8 @@ static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
/*
* At least Microsoft IAS and Meetinghouse Aegis seem to be sending
* EAP-Success/Failure with lastId + 1 even though RFC 3748 and
- * draft-ietf-eap-statemachine-05.pdf require that reqId == lastId.
- * In addition, it looks like Ringmaster v2.1.2.0 would be using
- * lastId + 2 in EAP-Success.
+ * RFC 4137 require that reqId == lastId. In addition, it looks like
+ * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
*
* Accept this kind of Id if EAP workarounds are enabled. These are
* unauthenticated plaintext messages, so this should have minimal
@@ -490,13 +545,13 @@ SM_STEP(EAP)
if (eapol_get_bool(sm, EAPOL_eapRestart) &&
eapol_get_bool(sm, EAPOL_portEnabled))
SM_ENTER_GLOBAL(EAP, INITIALIZE);
- else if (!eapol_get_bool(sm, EAPOL_portEnabled))
+ 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) {
if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
- wpa_printf(MSG_DEBUG, "EAP: more than %d "
- "authentication rounds - abort",
- EAP_MAX_AUTH_ROUNDS);
+ wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
+ "authentication rounds - abort",
+ EAP_MAX_AUTH_ROUNDS);
sm->num_rounds++;
SM_ENTER_GLOBAL(EAP, FAILURE);
}
@@ -505,7 +560,8 @@ SM_STEP(EAP)
SM_ENTER(EAP, IDLE);
break;
case EAP_DISABLED:
- if (eapol_get_bool(sm, EAPOL_portEnabled))
+ if (eapol_get_bool(sm, EAPOL_portEnabled) &&
+ !sm->force_disabled)
SM_ENTER(EAP, INITIALIZE);
break;
case EAP_IDLE:
@@ -533,16 +589,18 @@ SM_STEP(EAP)
SM_ENTER(EAP, SUCCESS);
break;
case EAP_RECEIVED:
- duplicate = sm->reqId == sm->lastId;
+ duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
if (sm->workaround && duplicate &&
memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
- /* draft-ietf-eap-statemachine-05.txt uses
- * (reqId == lastId) as the only verification for
- * duplicate EAP requests. However, this misses cases
- * where the AS is incorrectly using the same id again;
- * and unfortunately, such implementations exist. Use
- * MD5 hash as an extra verification for the packets
- * being duplicate to workaround these issues. */
+ /*
+ * RFC 4137 uses (reqId == lastId) as the only
+ * verification for duplicate EAP requests. However,
+ * this misses cases where the AS is incorrectly using
+ * the same id again; and unfortunately, such
+ * implementations exist. Use MD5 hash as an extra
+ * verification for the packets being duplicate to
+ * workaround these issues.
+ */
wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again,"
" but EAP packets were not identical");
wpa_printf(MSG_DEBUG, "EAP: workaround - assume this "
@@ -558,7 +616,9 @@ SM_STEP(EAP)
else if (sm->methodState != METHOD_CONT &&
((sm->rxFailure &&
sm->decision != DECISION_UNCOND_SUCC) ||
- (sm->rxSuccess && sm->decision == DECISION_FAIL)) &&
+ (sm->rxSuccess && sm->decision == DECISION_FAIL &&
+ (sm->selectedMethod != EAP_TYPE_LEAP ||
+ sm->methodState != METHOD_MAY_CONT))) &&
(sm->reqId == sm->lastId ||
eap_success_workaround(sm, sm->reqId, sm->lastId)))
SM_ENTER(EAP, FAILURE);
@@ -657,7 +717,8 @@ static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
*pos++ = EAP_TYPE_NAK;
for (i = 0; i < NUM_EAP_METHODS; i++) {
- if (wpa_config_allowed_eap_method(config,
+ if (eap_methods[i]->method != sm->reqMethod &&
+ wpa_config_allowed_eap_method(config,
eap_methods[i]->method)) {
*pos++ = eap_methods[i]->method;
(*len)++;
@@ -677,11 +738,16 @@ static u8 *eap_sm_buildNak(struct eap_sm *sm, int id, size_t *len)
}
-static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len)
+static void eap_sm_processIdentity(struct eap_sm *sm, const u8 *req,
+ size_t len)
{
- struct eap_hdr *hdr = (struct eap_hdr *) req;
- u8 *pos = (u8 *) (hdr + 1);
+ const struct eap_hdr *hdr = (const struct eap_hdr *) req;
+ const u8 *pos = (const u8 *) (hdr + 1);
pos++;
+
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
+ "EAP authentication started");
+
/* 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",
@@ -689,8 +755,77 @@ static void eap_sm_processIdentity(struct eap_sm *sm, u8 *req, size_t len)
}
-u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
- int encrypted)
+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;
+
+ imsi_len = sizeof(imsi);
+ if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
+ wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
+ return -1;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
+
+ while (pos && *pos != EAP_TYPE_NONE) {
+ if (*pos == EAP_TYPE_AKA) {
+ aka = 1;
+ break;
+ }
+ pos++;
+ }
+
+ free(ssid->identity);
+ ssid->identity = malloc(1 + imsi_len);
+ if (ssid->identity == NULL) {
+ wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
+ "IMSI-based identity");
+ return -1;
+ }
+
+ ssid->identity[0] = aka ? '0' : '1';
+ memcpy(ssid->identity + 1, imsi, imsi_len);
+ ssid->identity_len = 1 + imsi_len;
+ return 0;
+}
+
+
+static int eap_sm_get_scard_identity(struct eap_sm *sm, struct wpa_ssid *ssid)
+{
+ 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);
+ ssid->pin = NULL;
+
+ wpa_printf(MSG_WARNING, "PIN validation failed");
+ eap_sm_request_pin(sm, ssid);
+ return -1;
+ }
+
+ return eap_sm_imsi_identity(sm, 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)
+ * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
+ * failure
+ *
+ * This function allocates and builds an EAP-Identity/Response packet for the
+ * current network. The caller is responsible for freeing the returned data.
+ */
+u8 * eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
+ int encrypted)
{
struct wpa_ssid *config = eap_get_config(sm);
struct eap_hdr *resp;
@@ -724,8 +859,17 @@ u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
if (identity == NULL) {
wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
"configuration was not available");
- eap_sm_request_identity(sm, config);
- return NULL;
+ if (config->pcsc) {
+ if (eap_sm_get_scard_identity(sm, config) < 0)
+ return NULL;
+ identity = config->identity;
+ identity_len = config->identity_len;
+ wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
+ "IMSI", identity, identity_len);
+ } else {
+ eap_sm_request_identity(sm, config);
+ return NULL;
+ }
}
@@ -745,14 +889,33 @@ u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
}
-static void eap_sm_processNotify(struct eap_sm *sm, u8 *req, size_t len)
+static void eap_sm_processNotify(struct eap_sm *sm, const u8 *req, size_t len)
{
- struct eap_hdr *hdr = (struct eap_hdr *) req;
- u8 *pos = (u8 *) (hdr + 1);
+ const struct eap_hdr *hdr = (const struct eap_hdr *) req;
+ const u8 *pos;
+ char *msg;
+ size_t msg_len;
+ int i;
+
+ pos = (const u8 *) (hdr + 1);
pos++;
- /* TODO: log the Notification Request and make it available for UI */
+
+ msg_len = be_to_host16(hdr->length);
+ if (msg_len < 5)
+ return;
+ msg_len -= 5;
wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
- pos, be_to_host16(hdr->length) - 5);
+ pos, msg_len);
+
+ msg = malloc(msg_len + 1);
+ if (msg == NULL)
+ return;
+ for (i = 0; i < msg_len; i++)
+ msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
+ msg[msg_len] = '\0';
+ wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
+ WPA_EVENT_EAP_NOTIFICATION, msg);
+ free(msg);
}
@@ -777,11 +940,10 @@ static u8 *eap_sm_buildNotify(struct eap_sm *sm, int id, size_t *len)
}
-static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
+static void eap_sm_parseEapReq(struct eap_sm *sm, const u8 *req, size_t len)
{
- struct eap_hdr *hdr;
+ const struct eap_hdr *hdr;
size_t plen;
- MD5_CTX context;
sm->rxReq = sm->rxSuccess = sm->rxFailure = FALSE;
sm->reqId = 0;
@@ -790,7 +952,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
if (req == NULL || len < sizeof(*hdr))
return;
- hdr = (struct eap_hdr *) req;
+ hdr = (const struct eap_hdr *) req;
plen = be_to_host16(hdr->length);
if (plen > len) {
wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
@@ -802,9 +964,7 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
sm->reqId = hdr->identifier;
if (sm->workaround) {
- MD5Init(&context);
- MD5Update(&context, req, len);
- MD5Final(sm->req_md5, &context);
+ md5_vector(1, (const u8 **) &req, &len, sm->req_md5);
}
switch (hdr->code) {
@@ -843,10 +1003,22 @@ static void eap_sm_parseEapReq(struct eap_sm *sm, u8 *req, size_t len)
}
-struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
- void *msg_ctx)
+/**
+ * eap_sm_init - Allocate and initialize EAP state machine
+ * @eapol_ctx: Context data to be used with eapol_cb calls
+ * @eapol_cb: Pointer to EAPOL callback functions
+ * @msg_ctx: Context data for wpa_msg() calls
+ * @conf: EAP configuration
+ * 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.
+ */
+struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx, struct eap_config *conf)
{
struct eap_sm *sm;
+ struct tls_config tlsconf;
sm = malloc(sizeof(*sm));
if (sm == NULL)
@@ -857,7 +1029,11 @@ struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
sm->msg_ctx = msg_ctx;
sm->ClientTimeout = 60;
- sm->ssl_ctx = tls_init();
+ 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;
+ sm->ssl_ctx = tls_init(&tlsconf);
if (sm->ssl_ctx == NULL) {
wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
"context.");
@@ -869,6 +1045,13 @@ struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
}
+/**
+ * eap_sm_deinit - Deinitialize and free an EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function deinitializes EAP state machine and frees all allocated
+ * resources.
+ */
void eap_sm_deinit(struct eap_sm *sm)
{
if (sm == NULL)
@@ -882,6 +1065,15 @@ void eap_sm_deinit(struct eap_sm *sm)
}
+/**
+ * eap_sm_step - Step EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * Returns: 1 if EAP state was changed or 0 if not
+ *
+ * This function advances EAP state machine to a new state to match with the
+ * current variables. This should be called whenever variables used by the EAP
+ * state machine have changed.
+ */
int eap_sm_step(struct eap_sm *sm)
{
int res = 0;
@@ -895,10 +1087,15 @@ int eap_sm_step(struct eap_sm *sm)
}
+/**
+ * eap_sm_abort - Abort EAP authentication
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * Release system resources that have been allocated for the authentication
+ * session without fully deinitializing the EAP state machine.
+ */
void eap_sm_abort(struct eap_sm *sm)
{
- /* release system resources that may have been allocated for the
- * authentication session */
free(sm->eapRespData);
sm->eapRespData = NULL;
free(sm->eapKeyData);
@@ -975,6 +1172,19 @@ static const char * eap_sm_decision_txt(int decision)
}
+/**
+ * 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.
+ *
+ * Query EAP state machine for status information. This function fills in a
+ * text area with current status information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, status information will be truncated
+ * to fit the buffer.
+ */
int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
{
int len;
@@ -1025,10 +1235,14 @@ int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
}
-typedef enum { TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP } eap_ctrl_req_type;
+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, char *msg, size_t msglen)
+ eap_ctrl_req_type type, const char *msg,
+ size_t msglen)
{
char *buf;
size_t buflen;
@@ -1050,6 +1264,16 @@ static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
txt = "Password";
config->pending_req_password++;
break;
+ case TYPE_NEW_PASSWORD:
+ field = "NEW_PASSWORD";
+ txt = "New Password";
+ config->pending_req_new_password++;
+ break;
+ case TYPE_PIN:
+ field = "PIN";
+ txt = "PIN";
+ config->pending_req_pin++;
+ break;
case TYPE_OTP:
field = "OTP";
if (msg) {
@@ -1070,6 +1294,11 @@ static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
txt = config->pending_req_otp;
}
break;
+ case TYPE_PASSPHRASE:
+ field = "PASSPHRASE";
+ txt = "Private key passphrase";
+ config->pending_req_passphrase++;
+ break;
default:
return;
}
@@ -1078,37 +1307,123 @@ static void eap_sm_request(struct eap_sm *sm, struct wpa_ssid *config,
buf = malloc(buflen);
if (buf == NULL)
return;
- len = snprintf(buf, buflen, "CTRL-REQ-%s-%d:%s needed for SSID ",
+ len = snprintf(buf, buflen, WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
field, config->id, txt);
if (config->ssid && buflen > len + config->ssid_len) {
memcpy(buf + len, config->ssid, config->ssid_len);
len += config->ssid_len;
buf[len] = '\0';
}
- wpa_msg(sm->msg_ctx, MSG_INFO, buf);
+ wpa_msg(sm->msg_ctx, MSG_INFO, "%s", buf);
free(buf);
}
+/**
+ * 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)
{
eap_sm_request(sm, config, 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)
{
eap_sm_request(sm, config, 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)
+{
+ eap_sm_request(sm, config, 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)
+{
+ eap_sm_request(sm, config, 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
+ *
+ * EAP methods can call this function to request open time password (OTP) for
+ * 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,
- char *msg, size_t msg_len)
+ const char *msg, size_t msg_len)
{
eap_sm_request(sm, config, 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)
+{
+ eap_sm_request(sm, config, TYPE_PASSPHRASE, NULL, 0);
+}
+
+
+/**
+ * eap_sm_notify_ctrl_attached - Notification of attached monitor
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * Notify EAP state machines that a monitor was attached to the control
+ * interface to trigger re-sending of pending requests for user input.
+ */
void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
{
struct wpa_ssid *config = eap_get_config(sm);
@@ -1124,11 +1439,25 @@ void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
eap_sm_request_identity(sm, config);
if (config->pending_req_password)
eap_sm_request_password(sm, config);
+ if (config->pending_req_new_password)
+ eap_sm_request_new_password(sm, config);
if (config->pending_req_otp)
eap_sm_request_otp(sm, config, NULL, 0);
+ if (config->pending_req_pin)
+ eap_sm_request_pin(sm, config);
+ if (config->pending_req_passphrase)
+ eap_sm_request_passphrase(sm, config);
}
+/**
+ * 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;
@@ -1140,6 +1469,49 @@ u8 eap_get_type(const char *name)
}
+/**
+ * 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)
{
return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
@@ -1147,6 +1519,15 @@ 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
+ * 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)
{
u8 type = eap_get_type(name);
@@ -1156,6 +1537,15 @@ 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
+ * 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)
{
u8 *buf, method;
@@ -1181,30 +1571,59 @@ 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
+ */
void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
{
sm->fast_reauth = enabled;
}
+/**
+ * eap_set_workaround - Update EAP workarounds setting
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds
+ */
void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
{
sm->workaround = 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
+ */
struct wpa_ssid * eap_get_config(struct eap_sm *sm)
{
return sm->eapol_cb->get_config(sm->eapol_ctx);
}
+/**
+ * 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
+ */
int eap_key_available(struct eap_sm *sm)
{
return sm ? sm->eapKeyAvailable : 0;
}
+/**
+ * eap_notify_success - Notify EAP state machine about external success trigger
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function is called when external event, e.g., successful completion of
+ * WPA-PSK key handshake, is indicating that EAP state machine should move to
+ * success state. This is mainly used with security modes that do not use EAP
+ * state machine (e.g., WPA-PSK).
+ */
void eap_notify_success(struct eap_sm *sm)
{
if (sm) {
@@ -1212,9 +1631,45 @@ 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()
+ *
+ * Notify EAP state machines that a lower layer has detected a successful
+ * authentication. This is used to recover from dropped EAP-Success messages.
+ */
+void eap_notify_lower_layer_success(struct eap_sm *sm)
+{
+ if (sm == NULL)
+ return;
+ if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
+ sm->decision == DECISION_FAIL ||
+ (sm->methodState != METHOD_MAY_CONT &&
+ sm->methodState != METHOD_DONE))
+ return;
-u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
+ if (sm->eapKeyData != NULL)
+ sm->eapKeyAvailable = TRUE;
+ eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+ wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+ "EAP authentication completed successfully (based on lower "
+ "layer success)");
+}
+
+
+/**
+ * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the key
+ * Returns: Pointer to the EAP keying data or %NULL on failure
+ *
+ * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
+ * key is available only after a successful authentication. EAP state machine
+ * continues to manage the key data and the caller must not change or free the
+ * returned data.
+ */
+const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
{
if (sm == NULL || sm->eapKeyData == NULL) {
*len = 0;
@@ -1226,6 +1681,17 @@ u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
}
+/**
+ * eap_get_eapKeyData - Get EAP response data
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @len: Pointer to variable that will be set to the length of the response
+ * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
+ *
+ * Fetch EAP response (eapRespData) from the EAP state machine. This data is
+ * available when EAP state machine has processed an incoming EAP request. The
+ * EAP state machine does not maintain a reference to the response after this
+ * function is called and the caller is responsible for freeing the data.
+ */
u8 * eap_get_eapRespData(struct eap_sm *sm, size_t *len)
{
u8 *resp;
@@ -1244,8 +1710,91 @@ 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
+ *
+ * Notify EAP state machines of context data for smart card operations. This
+ * context data will be used as a parameter for scard_*() functions.
+ */
void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
{
if (sm)
sm->scard_ctx = ctx;
}
+
+
+/**
+ * eap_hdr_validate - Validate EAP header
+ * @eap_type: Expected EAP type number
+ * @msg: EAP frame (starting with EAP header)
+ * @msglen: Length of msg
+ * @plen: Pointer for return 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.
+ */
+const u8 * eap_hdr_validate(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");
+ 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;
+}
+
+
+/**
+ * eap_set_config_blob - Set or add a named configuration blob
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an existing
+ * blob.
+ */
+void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
+{
+ sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
+}
+
+
+/**
+ * eap_get_config_blob - Get a named configuration blob
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
+ const char *name)
+{
+ return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
+}
+
+
+/**
+ * eap_set_force_disabled - Set force_disabled flag
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @disabled: 1 = EAP disabled, 0 = EAP enabled
+ *
+ * This function is used to force EAP state machine to be disabled when it is
+ * not in use (e.g., with WPA-PSK or plaintext connections).
+ */
+void eap_set_force_disabled(struct eap_sm *sm, int disabled)
+{
+ sm->force_disabled = disabled;
+}
diff --git a/contrib/wpa_supplicant/eap.h b/contrib/wpa_supplicant/eap.h
index 3d7cc72..e00e29b 100644
--- a/contrib/wpa_supplicant/eap.h
+++ b/contrib/wpa_supplicant/eap.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / EAP state machine functions (RFC 4137)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_H
#define EAP_H
@@ -6,55 +20,237 @@
struct eap_sm;
struct wpa_ssid;
+struct wpa_config_blob;
#ifdef IEEE8021X_EAPOL
+/**
+ * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine
+ *
+ * These variables are used in the interface between EAP peer state machine and
+ * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
+ * expected to maintain these variables and register a callback functions for
+ * EAP state machine to get and set the variables.
+ */
enum eapol_bool_var {
- EAPOL_eapSuccess, EAPOL_eapRestart, EAPOL_eapFail, EAPOL_eapResp,
- EAPOL_eapNoResp, EAPOL_eapReq, EAPOL_portEnabled, EAPOL_altAccept,
+ /**
+ * EAPOL_eapSuccess - EAP SUCCESS state reached
+ *
+ * EAP state machine reads and writes this value.
+ */
+ EAPOL_eapSuccess,
+
+ /**
+ * EAPOL_eapRestart - Lower layer request to restart authentication
+ *
+ * Set to TRUE in lower layer, FALSE in EAP state machine.
+ */
+ EAPOL_eapRestart,
+
+ /**
+ * EAPOL_eapFail - EAP FAILURE state reached
+ *
+ * EAP state machine writes this value.
+ */
+ EAPOL_eapFail,
+
+ /**
+ * EAPOL_eapResp - Response to send
+ *
+ * Set to TRUE in EAP state machine, FALSE in lower layer.
+ */
+ EAPOL_eapResp,
+
+ /**
+ * EAPOL_eapNoResp - Request has been process; no response to send
+ *
+ * Set to TRUE in EAP state machine, FALSE in lower layer.
+ */
+ EAPOL_eapNoResp,
+
+ /**
+ * EAPOL_eapReq - EAP request available from lower layer
+ *
+ * Set to TRUE in lower layer, FALSE in EAP state machine.
+ */
+ EAPOL_eapReq,
+
+ /**
+ * EAPOL_portEnabled - Lower layer is ready for communication
+ *
+ * EAP state machines reads this value.
+ */
+ EAPOL_portEnabled,
+
+ /**
+ * EAPOL_altAccept - Alternate indication of success (RFC3748)
+ *
+ * EAP state machines reads this value.
+ */
+ EAPOL_altAccept,
+
+ /**
+ * EAPOL_altReject - Alternate indication of failure (RFC3748)
+ *
+ * EAP state machines reads this value.
+ */
EAPOL_altReject
};
+/**
+ * enum eapol_int_var - EAPOL integer state variables for EAP state machine
+ *
+ * These variables are used in the interface between EAP peer state machine and
+ * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
+ * expected to maintain these variables and register a callback functions for
+ * EAP state machine to get and set the variables.
+ */
enum eapol_int_var {
+ /**
+ * EAPOL_idleWhile - Outside time for EAP peer timeout
+ *
+ * This integer variable is used to provide an outside timer that the
+ * external (to EAP state machine) code must decrement by one every
+ * second until the value reaches zero. This is used in the same way as
+ * EAPOL state machine timers. EAP state machine reads and writes this
+ * value.
+ */
EAPOL_idleWhile
};
+/**
+ * struct eapol_callbacks - Callback functions from EAP to lower layer
+ *
+ * This structure defines the callback functions that EAP state machine
+ * requires from the lower layer (usually EAPOL state machine) for updating
+ * state variables and requesting information. eapol_ctx from eap_sm_init()
+ * call will be used as the ctx parameter for these callback functions.
+ */
struct eapol_callbacks {
+ /**
+ * get_config - Get pointer to the current network configuration
+ * @ctx: eapol_ctx from eap_sm_init() call
+ */
struct wpa_ssid * (*get_config)(void *ctx);
+
+ /**
+ * get_bool - Get a boolean EAPOL state variable
+ * @variable: EAPOL boolean variable to get
+ * Returns: Value of the EAPOL variable
+ */
Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
+
+ /**
+ * set_bool - Set a boolean EAPOL state variable
+ * @ctx: eapol_ctx from eap_sm_init() call
+ * @variable: EAPOL boolean variable to set
+ * @value: Value for the EAPOL variable
+ */
void (*set_bool)(void *ctx, enum eapol_bool_var variable,
Boolean value);
+
+ /**
+ * get_int - Get an integer EAPOL state variable
+ * @ctx: eapol_ctx from eap_sm_init() call
+ * @variable: EAPOL integer variable to get
+ * Returns: Value of the EAPOL variable
+ */
unsigned int (*get_int)(void *ctx, enum eapol_int_var variable);
+
+ /**
+ * set_int - Set an integer EAPOL state variable
+ * @ctx: eapol_ctx from eap_sm_init() call
+ * @variable: EAPOL integer variable to set
+ * @value: Value for the EAPOL variable
+ */
void (*set_int)(void *ctx, enum eapol_int_var variable,
unsigned int value);
+
+ /**
+ * get_eapReqData - Get EAP-Request data
+ * @ctx: eapol_ctx from eap_sm_init() call
+ * @len: Pointer to variable that will be set to eapReqDataLen
+ * Returns: Reference to eapReqData (EAP state machine will not free
+ * this) or %NULL if eapReqData not available.
+ */
u8 * (*get_eapReqData)(void *ctx, size_t *len);
+
+ /**
+ * set_config_blob - Set named configuration blob
+ * @ctx: eapol_ctx from eap_sm_init() call
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an
+ * existing blob.
+ */
+ void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
+
+ /**
+ * get_config_blob - Get a named configuration blob
+ * @ctx: eapol_ctx from eap_sm_init() call
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+ const struct wpa_config_blob * (*get_config_blob)(void *ctx,
+ const char *name);
+};
+
+/**
+ * struct eap_config - Configuration for EAP state machine
+ */
+struct eap_config {
+ /**
+ * opensc_engine_path - OpenSC engine for OpenSSL engine support
+ *
+ * Usually, path to engine_opensc.so.
+ */
+ const char *opensc_engine_path;
+ /**
+ * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support
+ *
+ * Usually, path to engine_pkcs11.so.
+ */
+ const char *pkcs11_engine_path;
+ /**
+ * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine
+ *
+ * Usually, path to opensc-pkcs11.so.
+ */
+ const char *pkcs11_module_path;
};
-struct eap_sm *eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
- void *msg_ctx);
+struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
+ void *msg_ctx, struct eap_config *conf);
void eap_sm_deinit(struct eap_sm *sm);
int eap_sm_step(struct eap_sm *sm);
void eap_sm_abort(struct eap_sm *sm);
int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen,
int verbose);
-u8 *eap_sm_buildIdentity(struct eap_sm *sm, int id, size_t *len,
- int encrypted);
+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,
- char *msg, size_t msg_len);
+ const char *msg, size_t msg_len);
+void eap_sm_request_passphrase(struct eap_sm *sm, struct wpa_ssid *config);
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);
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);
-u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
+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);
@@ -65,6 +261,16 @@ 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;
+}
+
#endif /* IEEE8021X_EAPOL */
#endif /* EAP_H */
diff --git a/contrib/wpa_supplicant/eap_aka.c b/contrib/wpa_supplicant/eap_aka.c
index 7fe6449..b05cc72 100644
--- a/contrib/wpa_supplicant/eap_aka.c
+++ b/contrib/wpa_supplicant/eap_aka.c
@@ -20,7 +20,7 @@
#include "eap_i.h"
#include "wpa_supplicant.h"
#include "config_ssid.h"
-#include "sha1.h"
+#include "crypto.h"
#include "pcsc_funcs.h"
#include "eap_sim_common.h"
@@ -211,7 +211,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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen, int err)
{
struct eap_sim_msg *msg;
@@ -229,7 +229,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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen)
{
struct eap_sim_msg *msg;
@@ -249,7 +249,7 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen)
{
struct eap_sim_msg *msg;
@@ -271,7 +271,7 @@ static u8 * eap_aka_synchronization_failure(struct eap_sm *sm,
static u8 * eap_aka_response_identity(struct eap_sm *sm,
struct eap_aka_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen,
enum eap_sim_id_req id_req)
{
@@ -300,7 +300,7 @@ static u8 * eap_aka_response_identity(struct eap_sm *sm,
eap_aka_clear_identities(data, CLEAR_EAP_ID);
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Identity (id=%d)",
- req->identifier);
+ req->identifier);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
EAP_TYPE_AKA, EAP_AKA_SUBTYPE_IDENTITY);
@@ -317,13 +317,13 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen)
{
struct eap_sim_msg *msg;
wpa_printf(MSG_DEBUG, "Generating EAP-AKA Challenge (id=%d)",
- req->identifier);
+ req->identifier);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
EAP_TYPE_AKA, EAP_AKA_SUBTYPE_CHALLENGE);
wpa_printf(MSG_DEBUG, " AT_RES");
@@ -337,7 +337,7 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen, int counter_too_small)
{
struct eap_sim_msg *msg;
@@ -377,7 +377,7 @@ static u8 * eap_aka_response_reauth(struct eap_sm *sm,
static u8 * eap_aka_response_notification(struct eap_sm *sm,
struct eap_aka_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen,
u16 notification)
{
@@ -416,7 +416,8 @@ 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,
- struct eap_hdr *req, size_t reqDataLen,
+ const struct eap_hdr *req,
+ size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
@@ -458,7 +459,8 @@ static u8 * eap_aka_process_identity(struct eap_sm *sm,
static u8 * eap_aka_process_challenge(struct eap_sm *sm,
struct eap_aka_data *data,
- struct eap_hdr *req, size_t reqDataLen,
+ const struct eap_hdr *req,
+ size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
@@ -512,8 +514,8 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
"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);
- if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
- (u8 *) "", 0)) {
+ 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,
@@ -527,14 +529,17 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
CLEAR_EAP_ID);
if (attr->encr_data) {
- if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
- attr->encr_data_len, attr->iv, &eattr,
- 0)) {
+ u8 *decrypted;
+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv,
+ &eattr, 0);
+ if (decrypted == NULL) {
return eap_aka_client_error(
sm, data, req, respDataLen,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
eap_aka_learn_ids(data, &eattr);
+ free(decrypted);
}
if (data->state != FAILURE)
@@ -551,11 +556,12 @@ static u8 * eap_aka_process_challenge(struct eap_sm *sm,
static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t reqDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
+ u8 *decrypted;
if (attr->encr_data == NULL || attr->iv == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: Notification message after "
@@ -563,8 +569,10 @@ static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
return -1;
}
- if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
- attr->encr_data_len, attr->iv, &eattr, 0)) {
+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr,
+ 0);
+ if (decrypted == NULL) {
wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
"data from notification message");
return -1;
@@ -574,15 +582,17 @@ static int eap_aka_process_notification_reauth(struct eap_aka_data *data,
wpa_printf(MSG_WARNING, "EAP-AKA: Counter in notification "
"message does not match with counter in reauth "
"message");
+ free(decrypted);
return -1;
}
+ free(decrypted);
return 0;
}
static int eap_aka_process_notification_auth(struct eap_aka_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t reqDataLen,
struct eap_sim_attrs *attr)
{
@@ -592,8 +602,8 @@ static int eap_aka_process_notification_auth(struct eap_aka_data *data,
return -1;
}
- if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
- (u8 *) "", 0)) {
+ if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
+ attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Notification message "
"used invalid AT_MAC");
return -1;
@@ -612,7 +622,7 @@ static int eap_aka_process_notification_auth(struct eap_aka_data *data,
static u8 * eap_aka_process_notification(struct eap_sm *sm,
struct eap_aka_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
@@ -649,12 +659,13 @@ static u8 * eap_aka_process_notification(struct eap_sm *sm,
static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
struct eap_aka_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
+ u8 *decrypted;
wpa_printf(MSG_DEBUG, "EAP-AKA: subtype Reauthentication");
@@ -666,7 +677,7 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
}
data->reauth = 1;
- if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen,
+ if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
"did not have valid AT_MAC");
@@ -681,8 +692,10 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
- if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
- attr->encr_data_len, attr->iv, &eattr, 0)) {
+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr,
+ 0);
+ 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,
@@ -693,6 +706,7 @@ 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,
EAP_AKA_UNABLE_TO_PROCESS_PACKET);
}
@@ -711,6 +725,7 @@ static u8 * eap_aka_process_reauthentication(struct eap_sm *sm,
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);
}
data->counter = eattr.counter;
@@ -735,19 +750,21 @@ 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);
}
static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_aka_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_hdr *req;
- u8 *pos, subtype, *res;
+ const struct eap_hdr *req;
+ u8 subtype, *res;
+ const u8 *pos;
struct eap_sim_attrs attr;
size_t len;
@@ -759,21 +776,19 @@ static u8 * eap_aka_process(struct eap_sm *sm, void *priv,
return NULL;
}
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_AKA ||
- (len = be_to_host16(req->length)) > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
+ pos = eap_hdr_validate(EAP_TYPE_AKA, reqData, reqDataLen, &len);
+ if (pos == NULL || len < 1) {
ret->ignore = TRUE;
return NULL;
}
+ req = (const struct eap_hdr *) reqData;
+ len = be_to_host16(req->length);
ret->ignore = FALSE;
- ret->methodState = METHOD_CONT;
+ ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
- pos++;
subtype = *pos++;
wpa_printf(MSG_DEBUG, "EAP-AKA: Subtype=%d", subtype);
pos += 2; /* Reserved */
@@ -818,7 +833,7 @@ done:
ret->decision = DECISION_FAIL;
ret->methodState = METHOD_DONE;
} else if (data->state == SUCCESS) {
- ret->decision = DECISION_UNCOND_SUCC;
+ ret->decision = DECISION_COND_SUCC;
ret->methodState = METHOD_DONE;
}
diff --git a/contrib/wpa_supplicant/eap_defs.h b/contrib/wpa_supplicant/eap_defs.h
index effe665..9cd4490 100644
--- a/contrib/wpa_supplicant/eap_defs.h
+++ b/contrib/wpa_supplicant/eap_defs.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant/hostapd / Shared EAP definitions
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_DEFS_H
#define EAP_DEFS_H
@@ -6,7 +20,7 @@
struct eap_hdr {
u8 code;
u8 identifier;
- u16 length; /* including code and identifier */
+ u16 length; /* including code and identifier; network byte order */
/* followed by length-4 octets of data */
} __attribute__ ((packed));
@@ -18,12 +32,12 @@ enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
typedef enum {
EAP_TYPE_NONE = 0,
- EAP_TYPE_IDENTITY = 1,
- EAP_TYPE_NOTIFICATION = 2,
- EAP_TYPE_NAK = 3 /* Response only */,
- EAP_TYPE_MD5 = 4,
- EAP_TYPE_OTP = 5 /* RFC 2284 */,
- EAP_TYPE_GTC = 6, /* RFC 2284 */
+ EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
+ EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
+ EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */,
+ EAP_TYPE_MD5 = 4, /* RFC 3748 */
+ EAP_TYPE_OTP = 5 /* RFC 3748 */,
+ EAP_TYPE_GTC = 6, /* RFC 3748 */
EAP_TYPE_TLS = 13 /* RFC 2716 */,
EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
EAP_TYPE_SIM = 18 /* draft-haverinen-pppext-eap-sim-12.txt */,
@@ -33,9 +47,10 @@ typedef enum {
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-03 */
+ * draft-bersani-eap-psk-09 */
} EapType;
#endif /* EAP_DEFS_H */
diff --git a/contrib/wpa_supplicant/eap_fast.c b/contrib/wpa_supplicant/eap_fast.c
index 1c9c3ff..ff8f76c 100644
--- a/contrib/wpa_supplicant/eap_fast.c
+++ b/contrib/wpa_supplicant/eap_fast.c
@@ -24,10 +24,12 @@
#include "tls.h"
#include "eap_tlv.h"
#include "sha1.h"
+#include "config.h"
/* TODO:
* - encrypt PAC-Key in the PAC file
* - test session resumption and enable it if it interoperates
+ * - password change (pending mschapv2 packet; replay decrypted packet)
*/
#define EAP_FAST_VERSION 1
@@ -36,7 +38,8 @@
#define TLS_EXT_PAC_OPAQUE 35
-static char *pac_file_hdr = "wpa_supplicant EAP-FAST PAC file - version 1";
+static const char *pac_file_hdr =
+ "wpa_supplicant EAP-FAST PAC file - version 1";
static void eap_fast_deinit(struct eap_sm *sm, void *priv);
@@ -58,28 +61,18 @@ struct pac_tlv_hdr {
};
-/* draft-cam-winget-eap-fast-00.txt, 6.2 EAP-FAST Authentication Phase 1 */
+/* draft-cam-winget-eap-fast-02.txt:
+ * 6.2 EAP-FAST Authentication Phase 1: Key Derivations */
struct eap_fast_key_block_auth {
- /* RC4-128-SHA */
- u8 client_write_MAC_secret[20];
- u8 server_write_MAC_secret[20];
- u8 client_write_key[16];
- u8 server_write_key[16];
- /* u8 client_write_IV[0]; */
- /* u8 server_write_IV[0]; */
+ /* Extra key material after TLS key_block */
u8 session_key_seed[40];
};
-/* draft-cam-winget-eap-fast-00.txt, 7.3 EAP-FAST Provisioning Exchange */
+/* 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 {
- /* AES128-SHA */
- u8 client_write_MAC_secret[20];
- u8 server_write_MAC_secret[20];
- u8 client_write_key[16];
- u8 server_write_key[16];
- u8 client_write_IV[16];
- u8 server_write_IV[16];
+ /* Extra key material after TLS key_block */
u8 session_key_seed[40];
u8 server_challenge[16];
u8 client_challenge[16];
@@ -249,12 +242,34 @@ static int eap_fast_add_pac(struct eap_fast_data *data,
}
-static int eap_fast_read_line(FILE *f, char *buf, size_t buf_len)
+struct eap_fast_read_ctx {
+ FILE *f;
+ const char *pos;
+ const char *end;
+};
+
+static int eap_fast_read_line(struct eap_fast_read_ctx *rc, char *buf,
+ size_t buf_len)
{
char *pos;
- if (fgets(buf, buf_len, f) == NULL) {
- return -1;
+ if (rc->f) {
+ if (fgets(buf, buf_len, rc->f) == NULL)
+ return -1;
+ } else {
+ const char *l_end;
+ size_t len;
+ if (rc->pos >= rc->end)
+ return -1;
+ l_end = rc->pos;
+ while (l_end < rc->end && *l_end != '\n')
+ l_end++;
+ len = l_end - rc->pos;
+ if (len >= buf_len)
+ len = buf_len - 1;
+ memcpy(buf, rc->pos, len);
+ buf[len] = '\0';
+ rc->pos = l_end + 1;
}
buf[buf_len - 1] = '\0';
@@ -293,9 +308,10 @@ static u8 * eap_fast_parse_hex(const char *value, size_t *len)
}
-static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
+static int eap_fast_load_pac(struct eap_sm *sm, struct eap_fast_data *data,
+ const char *pac_file)
{
- FILE *f;
+ struct eap_fast_read_ctx rc;
struct eap_fast_pac *pac = NULL;
int count = 0;
char *buf, *pos;
@@ -305,11 +321,27 @@ static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
if (pac_file == NULL)
return -1;
- f = fopen(pac_file, "r");
- if (f == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - assume no "
- "PAC entries have been provisioned", pac_file);
- return 0;
+ memset(&rc, 0, sizeof(rc));
+
+ if (strncmp(pac_file, "blob://", 7) == 0) {
+ const struct wpa_config_blob *blob;
+ blob = eap_get_config_blob(sm, pac_file + 7);
+ if (blob == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC blob '%s' - "
+ "assume no PAC entries have been "
+ "provisioned", pac_file + 7);
+ return 0;
+ }
+ rc.pos = (char *) blob->data;
+ rc.end = (char *) blob->data + blob->len;
+ } else {
+ rc.f = fopen(pac_file, "r");
+ if (rc.f == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: No PAC file '%s' - "
+ "assume no PAC entries have been "
+ "provisioned", pac_file);
+ return 0;
+ }
}
buf = malloc(buf_len);
@@ -318,16 +350,17 @@ static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
}
line++;
- if (eap_fast_read_line(f, buf, buf_len) < 0 ||
+ if (eap_fast_read_line(&rc, buf, buf_len) < 0 ||
strcmp(pac_file_hdr, buf) != 0) {
wpa_printf(MSG_INFO, "EAP-FAST: Unrecognized header line in "
"PAC file '%s'", pac_file);
free(buf);
- fclose(f);
+ if (rc.f)
+ fclose(rc.f);
return -1;
}
- while (eap_fast_read_line(f, buf, buf_len) == 0) {
+ while (eap_fast_read_line(&rc, buf, buf_len) == 0) {
line++;
pos = strchr(buf, '=');
if (pos) {
@@ -423,7 +456,8 @@ static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
}
free(buf);
- fclose(f);
+ if (rc.f)
+ fclose(rc.f);
if (ret == 0) {
wpa_printf(MSG_DEBUG, "EAP-FAST: read %d PAC entries from "
@@ -434,67 +468,124 @@ static int eap_fast_load_pac(struct eap_fast_data *data, const char *pac_file)
}
-static void eap_fast_write(FILE *f, const char *field, const u8 *data,
+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;
- if (data == NULL)
+ if (data == NULL || *buf == NULL)
return;
- fprintf(f, "%s=", field);
+ need = strlen(field) + len * 2 + 30;
+ if (txt)
+ need += strlen(field) + len + 20;
+
+ if (*pos - *buf + need > *buf_len) {
+ char *nbuf = realloc(*buf, *buf_len + need);
+ if (nbuf == NULL) {
+ free(*buf);
+ *buf = NULL;
+ return;
+ }
+ *buf = nbuf;
+ *buf_len += need;
+ }
+
+ *pos += snprintf(*pos, *buf + *buf_len - *pos, "%s=", field);
for (i = 0; i < len; i++) {
- fprintf(f, "%02x", data[i]);
+ *pos += snprintf(*pos, *buf + *buf_len - *pos,
+ "%02x", data[i]);
}
- fprintf(f, "\n");
+ *pos += snprintf(*pos, *buf + *buf_len - *pos, "\n");
if (txt) {
- fprintf(f, "%s-txt=", field);
+ *pos += snprintf(*pos, *buf + *buf_len - *pos,
+ "%s-txt=", field);
for (i = 0; i < len; i++) {
- fprintf(f, "%c", data[i]);
+ *pos += snprintf(*pos, *buf + *buf_len - *pos,
+ "%c", data[i]);
}
- fprintf(f, "\n");
+ *pos += snprintf(*pos, *buf + *buf_len - *pos, "\n");
}
}
-static int eap_fast_save_pac(struct eap_fast_data *data, const char *pac_file)
+static int eap_fast_save_pac(struct eap_sm *sm, struct eap_fast_data *data,
+ const char *pac_file)
{
FILE *f;
struct eap_fast_pac *pac;
int count = 0;
+ char *buf, *pos;
+ size_t buf_len;
if (pac_file == NULL)
return -1;
- f = fopen(pac_file, "w");
- if (f == NULL) {
- wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC file '%s' "
- "for writing", pac_file);
+ buf_len = 1024;
+ pos = buf = malloc(buf_len);
+ if (buf == NULL)
return -1;
- }
- fprintf(f, "%s\n", pac_file_hdr);
+ pos += snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
pac = data->pac;
while (pac) {
- fprintf(f, "START\n");
- eap_fast_write(f, "PAC-Key", pac->pac_key,
+ pos += snprintf(pos, buf + buf_len - pos, "START\n");
+ eap_fast_write(&buf, &pos, &buf_len, "PAC-Key", pac->pac_key,
EAP_FAST_PAC_KEY_LEN, 0);
- eap_fast_write(f, "PAC-Opaque", pac->pac_opaque,
- pac->pac_opaque_len, 0);
- eap_fast_write(f, "PAC-Info", pac->pac_info,
+ eap_fast_write(&buf, &pos, &buf_len, "PAC-Opaque",
+ pac->pac_opaque, pac->pac_opaque_len, 0);
+ eap_fast_write(&buf, &pos, &buf_len, "PAC-Info", pac->pac_info,
pac->pac_info_len, 0);
- eap_fast_write(f, "A-ID", pac->a_id, pac->a_id_len, 0);
- eap_fast_write(f, "I-ID", pac->i_id, pac->i_id_len, 1);
- eap_fast_write(f, "A-ID-Info", pac->a_id_info,
- pac->a_id_info_len, 1);
- fprintf(f, "END\n");
+ eap_fast_write(&buf, &pos, &buf_len, "A-ID", pac->a_id,
+ pac->a_id_len, 0);
+ eap_fast_write(&buf, &pos, &buf_len, "I-ID", pac->i_id,
+ 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;
+ }
}
- fclose(f);
+ if (strncmp(pac_file, "blob://", 7) == 0) {
+ struct wpa_config_blob *blob;
+ blob = malloc(sizeof(*blob));
+ if (blob == NULL) {
+ 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);
+ if (blob->name == NULL) {
+ wpa_config_free_blob(blob);
+ return -1;
+ }
+ eap_set_config_blob(sm, blob);
+ } else {
+ f = fopen(pac_file, "w");
+ if (f == NULL) {
+ wpa_printf(MSG_INFO, "EAP-FAST: Failed to open PAC "
+ "file '%s' for writing", pac_file);
+ free(buf);
+ return -1;
+ }
+ fprintf(f, "%s", buf);
+ free(buf);
+ fclose(f);
+ }
wpa_printf(MSG_DEBUG, "EAP-FAST: wrote %d PAC entries into '%s'",
count, pac_file);
@@ -590,7 +681,7 @@ static void * eap_fast_init(struct eap_sm *sm)
* TODO: consider making this configurable */
tls_connection_enable_workaround(sm->ssl_ctx, data->ssl.conn);
- if (eap_fast_load_pac(data, config->pac_file) < 0) {
+ if (eap_fast_load_pac(sm, data, config->pac_file) < 0) {
eap_fast_deinit(sm, data);
return NULL;
}
@@ -632,7 +723,7 @@ static void eap_fast_deinit(struct eap_sm *sm, void *priv)
static int eap_fast_encrypt(struct eap_sm *sm, struct eap_fast_data *data,
- int id, u8 *plain, size_t plain_len,
+ int id, const u8 *plain, size_t plain_len,
u8 **out_data, size_t *out_len)
{
int res;
@@ -799,32 +890,37 @@ 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 *random;
+ u8 *rnd;
u8 *out;
+ int block_size;
if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
return NULL;
- out = malloc(len);
- random = malloc(keys.client_random_len + keys.server_random_len);
- if (out == NULL || random == 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(random);
+ free(rnd);
return NULL;
}
- memcpy(random, keys.server_random, keys.server_random_len);
- memcpy(random + keys.server_random_len, keys.client_random,
+ memcpy(rnd, keys.server_random, keys.server_random_len);
+ 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, random, keys.client_random_len +
- keys.server_random_len, out, len)) {
- free(random);
+ label, rnd, keys.client_random_len +
+ keys.server_random_len, out, block_size + len)) {
+ free(rnd);
free(out);
return NULL;
}
- free(random);
+ free(rnd);
+ memmove(out, out + block_size, len);
return out;
}
@@ -836,6 +932,11 @@ static void eap_fast_derive_key_auth(struct eap_sm *sm,
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) {
+ 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));
@@ -878,7 +979,7 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -1333,7 +1434,7 @@ static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
}
eap_fast_add_pac(data, &entry);
- eap_fast_save_pac(data, config->pac_file);
+ eap_fast_save_pac(sm, data, config->pac_file);
if (data->provisioning) {
/* EAP-FAST provisioning does not provide keying material and
@@ -1356,12 +1457,13 @@ static u8 * eap_fast_process_pac(struct eap_sm *sm, struct eap_fast_data *data,
static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
- struct eap_method_ret *ret, struct eap_hdr *req,
- u8 *in_data, size_t in_len,
+ struct eap_method_ret *ret,
+ const struct eap_hdr *req,
+ const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted, *pos, *end;
- int buf_len, len_decrypted, len, res;
+ int buf_len, len_decrypted, len;
struct eap_hdr *hdr;
u8 *resp = NULL;
size_t resp_len;
@@ -1371,13 +1473,17 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
int iresult = 0, result = 0;
struct eap_tlv_crypto_binding__tlv *crypto_binding = NULL;
size_t crypto_binding_len = 0;
+ const u8 *msg;
+ size_t msg_len;
+ int need_more_input;
wpa_printf(MSG_DEBUG, "EAP-FAST: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
- res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
- if (res < 0 || res == 1)
- return res;
+ msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
+ &msg_len, &need_more_input);
+ if (msg == NULL)
+ return need_more_input ? 1 : -1;
buf_len = in_len;
if (data->ssl.tls_in_total > buf_len)
@@ -1393,7 +1499,7 @@ 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,
- in_data, in_len,
+ msg, msg_len,
in_decrypted, buf_len);
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
@@ -1417,11 +1523,12 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
pos = in_decrypted;
end = in_decrypted + len_decrypted;
- while (pos < end) {
+ while (pos + 4 < end) {
mandatory = pos[0] & 0x80;
- tlv_type = ((pos[0] & 0x3f) << 8) | pos[1];
- len = (pos[2] << 8) | pos[3];
- pos += 4;
+ tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+ pos += 2;
+ len = WPA_GET_BE16(pos);
+ pos += 2;
if (pos + len > end) {
free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-FAST: TLV overflow");
@@ -1447,7 +1554,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
result = EAP_TLV_RESULT_FAILURE;
break;
}
- result = (pos[0] << 16) | pos[1];
+ result = WPA_GET_BE16(pos);
if (result != EAP_TLV_RESULT_SUCCESS &&
result != EAP_TLV_RESULT_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
@@ -1467,7 +1574,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
iresult = EAP_TLV_RESULT_FAILURE;
break;
}
- iresult = (pos[0] << 16) | pos[1];
+ iresult = WPA_GET_BE16(pos);
if (iresult != EAP_TLV_RESULT_SUCCESS &&
iresult != EAP_TLV_RESULT_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-FAST: Unknown "
@@ -1584,7 +1691,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
if (!resp && pac && result != EAP_TLV_RESULT_SUCCESS) {
wpa_printf(MSG_DEBUG, "EAP-FAST: PAC TLV without Result TLV "
- "acnowledging success");
+ "acknowledging success");
resp = eap_fast_tlv_result(EAP_TLV_RESULT_FAILURE, 0,
&resp_len);
if (!resp) {
@@ -1607,7 +1714,7 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
if (resp == NULL) {
wpa_printf(MSG_DEBUG, "EAP-FAST: No recognized TLVs - send "
"empty response packet");
- resp = malloc(0);
+ resp = malloc(1);
if (resp == NULL)
return 0;
resp_len = 0;
@@ -1628,65 +1735,25 @@ static int eap_fast_decrypt(struct eap_sm *sm, struct eap_fast_data *data,
static u8 * eap_fast_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct eap_hdr *req;
- int left, res;
- unsigned int tls_msg_len;
- u8 flags, *pos, *resp, id;
+ const struct eap_hdr *req;
+ size_t left;
+ int res;
+ u8 flags, *resp, id;
+ const u8 *pos;
struct eap_fast_data *data = priv;
- if (tls_get_errors(sm->ssl_ctx)) {
- wpa_printf(MSG_INFO, "EAP-FAST: TLS errors detected");
- ret->ignore = TRUE;
- return NULL;
- }
-
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_FAST ||
- (left = host_to_be16(req->length)) > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-FAST: Invalid frame");
- ret->ignore = TRUE;
+ pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_FAST, ret,
+ reqData, reqDataLen, &left, &flags);
+ if (pos == NULL)
return NULL;
- }
- left -= sizeof(struct eap_hdr);
+ req = (const struct eap_hdr *) reqData;
id = req->identifier;
- pos++;
- flags = *pos++;
- left -= 2;
- wpa_printf(MSG_DEBUG, "EAP-FAST: Received packet(len=%lu) - "
- "Flags 0x%02x", (unsigned long) reqDataLen, flags);
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-FAST: Short frame with TLS "
- "length");
- ret->ignore = TRUE;
- return NULL;
- }
- tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
- pos[3];
- wpa_printf(MSG_DEBUG, "EAP-FAST: TLS Message Length: %d",
- tls_msg_len);
- if (data->ssl.tls_in_left == 0) {
- data->ssl.tls_in_total = tls_msg_len;
- data->ssl.tls_in_left = tls_msg_len;
- free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
-
- ret->ignore = FALSE;
- ret->methodState = METHOD_CONT;
- ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
if (flags & EAP_TLS_FLAGS_START) {
- u8 *a_id;
+ const u8 *a_id;
size_t a_id_len;
struct pac_tlv_hdr *hdr;
diff --git a/contrib/wpa_supplicant/eap_gtc.c b/contrib/wpa_supplicant/eap_gtc.c
index 42a7a49..3665746 100644
--- a/contrib/wpa_supplicant/eap_gtc.c
+++ b/contrib/wpa_supplicant/eap_gtc.c
@@ -53,29 +53,27 @@ static void eap_gtc_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_gtc_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_hdr *req, *resp;
- u8 *pos, *password;
- size_t password_len, len, msg_len;
-
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_GTC ||
- (len = be_to_host16(req->length)) > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
+ const struct eap_hdr *req;
+ struct eap_hdr *resp;
+ const u8 *pos, *password;
+ u8 *rpos;
+ size_t password_len, len;
+
+ pos = eap_hdr_validate(EAP_TYPE_GTC, reqData, reqDataLen, &len);
+ if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
- pos++;
- msg_len = len - sizeof(*req) - 1;
- wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message",
- pos, msg_len);
+ req = (const struct eap_hdr *) reqData;
+
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len);
if (data->prefix &&
- (msg_len < 10 || memcmp(pos, "CHALLENGE=", 10) != 0)) {
+ (len < 10 || memcmp(pos, "CHALLENGE=", 10) != 0)) {
wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with "
"expected prefix");
@@ -90,16 +88,15 @@ static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(*respDataLen);
- pos = (u8 *) (resp + 1);
- *pos++ = EAP_TYPE_GTC;
+ rpos = (u8 *) (resp + 1);
+ *rpos++ = EAP_TYPE_GTC;
return (u8 *) resp;
}
if (config == NULL ||
(config->password == NULL && config->otp == NULL)) {
wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
- eap_sm_request_otp(sm, config, (char *) pos,
- len - sizeof(*req) - 1);
+ eap_sm_request_otp(sm, config, (const char *) pos, len);
ret->ignore = TRUE;
return NULL;
}
@@ -128,16 +125,16 @@ static u8 * eap_gtc_process(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(*respDataLen);
- pos = (u8 *) (resp + 1);
- *pos++ = EAP_TYPE_GTC;
+ rpos = (u8 *) (resp + 1);
+ *rpos++ = EAP_TYPE_GTC;
if (data->prefix) {
- memcpy(pos, "RESPONSE=", 9);
- pos += 9;
- memcpy(pos, config->identity, config->identity_len);
- pos += config->identity_len;
- *pos++ = '\0';
+ memcpy(rpos, "RESPONSE=", 9);
+ rpos += 9;
+ memcpy(rpos, config->identity, config->identity_len);
+ rpos += config->identity_len;
+ *rpos++ = '\0';
}
- memcpy(pos, password, password_len);
+ memcpy(rpos, password, password_len);
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response",
(u8 *) (resp + 1) + 1,
*respDataLen - sizeof(struct eap_hdr) - 1);
diff --git a/contrib/wpa_supplicant/eap_i.h b/contrib/wpa_supplicant/eap_i.h
index c719812..d134548 100644
--- a/contrib/wpa_supplicant/eap_i.h
+++ b/contrib/wpa_supplicant/eap_i.h
@@ -1,9 +1,23 @@
+/*
+ * WPA Supplicant / EAP state machines internal structures (RFC 4137)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_I_H
#define EAP_I_H
#include "eap.h"
-/* draft-ietf-eap-statemachine-05.pdf - Peer state machine */
+/* RFC 4137 - EAP Peer state machine */
typedef enum {
DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC
@@ -13,37 +27,190 @@ typedef enum {
METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE
} EapMethodState;
+/**
+ * struct eap_method_ret - EAP return values from struct eap_method::process()
+ *
+ * These structure contains OUT variables for the interface between peer state
+ * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as
+ * the return value of struct eap_method::process() so it is not included in
+ * this structure.
+ */
struct eap_method_ret {
+ /**
+ * ignore - Whether method decided to drop the current packed (OUT)
+ */
Boolean ignore;
+
+ /**
+ * methodState - Method-specific state (IN/OUT)
+ */
EapMethodState methodState;
+
+ /**
+ * decision - Authentication decision (OUT)
+ */
EapDecision decision;
+
+ /**
+ * allowNotifications - Whether method allows notifications (OUT)
+ */
Boolean allowNotifications;
};
+/**
+ * struct eap_method - EAP method interface
+ * This structure defines the EAP method interface. Each method will need to
+ * register its own EAP type, EAP name, and set of function pointers for method
+ * specific operations. This interface is based on section 4.4 of RFC 4137.
+ */
struct eap_method {
+ /**
+ * method - EAP type number (EAP_TYPE_*)
+ */
EapType method;
+
+ /**
+ * name - Name of the method (e.g., "TLS")
+ */
const char *name;
+ /**
+ * init - Initialize an EAP method
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * Returns: Pointer to allocated private data, or %NULL on failure
+ *
+ * This function is used to initialize the EAP method explicitly
+ * instead of using METHOD_INIT state as specific in RFC 4137. The
+ * method is expected to initialize it method-specific state and return
+ * a pointer that will be used as the priv argument to other calls.
+ */
void * (*init)(struct eap_sm *sm);
+
+ /**
+ * deinit - Deinitialize an EAP method
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ *
+ * Deinitialize the EAP method and free any allocated private data.
+ */
void (*deinit)(struct eap_sm *sm, void *priv);
+
+ /**
+ * process - Process an EAP request
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @ret: Return values from EAP request validation and processing
+ * @reqData: EAP request to be processed (eapReqData)
+ * @reqDataLen: Length of the EAP request
+ * @respDataLen: Length of the returned EAP response
+ * Returns: Pointer to allocated EAP response packet (eapRespData)
+ *
+ * This function is a combination of m.check(), m.process(), and
+ * m.buildResp() procedures defined in section 4.4 of RFC 4137 In other
+ * words, this function validates the incoming request, processes it,
+ * and build a response packet. m.check() and m.process() return values
+ * are returned through struct eap_method_ret *ret variable. Caller is
+ * responsible for freeing the returned EAP response packet.
+ */
u8 * (*process)(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen);
+
+ /**
+ * isKeyAvailable - Find out whether EAP method has keying material
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * Returns: %TRUE if key material (eapKeyData) is available
+ */
Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv);
+
+ /**
+ * getKey - Get EAP method specific keying material (eapKeyData)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @len: Pointer to variable to store key length (eapKeyDataLen)
+ * Returns: Keying material (eapKeyData) or %NULL if not available
+ *
+ * This function can be used to get the keying material from the EAP
+ * method. The key may already be stored in the method-specific private
+ * data or this function may derive the key.
+ */
u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
+
+ /**
+ * get_status - Get EAP method status
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @buf: Buffer for status information
+ * @buflen: Maximum buffer length
+ * @verbose: Whether to include verbose status information
+ * Returns: Number of bytes written to buf
+ *
+ * Query EAP method for status information. This function fills in a
+ * text area with current status information from the EAP method. If
+ * the buffer (buf) is not large enough, status information will be
+ * truncated to fit the buffer.
+ */
int (*get_status)(struct eap_sm *sm, void *priv, char *buf,
size_t buflen, int verbose);
- /* Optional handlers for fast re-authentication */
+ /**
+ * has_reauth_data - Whether method is ready for fast reauthentication
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * Returns: %TRUE or %FALSE based on whether fast reauthentication is
+ * possible
+ *
+ * This function is an optional handler that only EAP methods
+ * supporting fast re-authentication need to implement.
+ */
Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv);
+
+ /**
+ * deinit_for_reauth - Release data that is not needed for fast re-auth
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ *
+ * This function is an optional handler that only EAP methods
+ * supporting fast re-authentication need to implement. This is called
+ * when authentication has been completed and EAP state machine is
+ * requesting that enough state information is maintained for fast
+ * re-authentication
+ */
void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);
+
+ /**
+ * init_for_reauth - Prepare for start of fast re-authentication
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ *
+ * This function is an optional handler that only EAP methods
+ * supporting fast re-authentication need to implement. This is called
+ * when EAP authentication is started and EAP state machine is
+ * requesting fast re-authentication to be used.
+ */
void * (*init_for_reauth)(struct eap_sm *sm, void *priv);
+
+ /**
+ * get_identity - Get method specific identity for re-authentication
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @len: Length of the returned identity
+ * Returns: Pointer to the method specific identity or %NULL if default
+ * identity is to be used
+ *
+ * This function is an optional handler that only EAP methods
+ * that use method specific identity need to implement.
+ */
const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
};
+/**
+ * struct eap_sm - EAP state machine data
+ */
struct eap_sm {
enum {
EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED,
@@ -76,7 +243,7 @@ struct eap_sm {
u8 *eapKeyData; /* peer to lower layer */
size_t eapKeyDataLen; /* peer to lower layer */
const struct eap_method *m; /* selected EAP method */
- /* not defined in draft-ietf-eap-statemachine-02 */
+ /* not defined in RFC 4137 */
Boolean changed;
void *eapol_ctx;
struct eapol_callbacks *eapol_cb;
@@ -101,6 +268,13 @@ struct eap_sm {
u8 *peer_challenge, *auth_challenge;
int num_rounds;
+ int force_disabled;
};
+const u8 * eap_hdr_validate(EapType eap_type, const u8 *msg, size_t msglen,
+ size_t *plen);
+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);
+
#endif /* EAP_I_H */
diff --git a/contrib/wpa_supplicant/eap_leap.c b/contrib/wpa_supplicant/eap_leap.c
index 6409a68..d0e5aab 100644
--- a/contrib/wpa_supplicant/eap_leap.c
+++ b/contrib/wpa_supplicant/eap_leap.c
@@ -21,7 +21,7 @@
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "ms_funcs.h"
-#include "md5.h"
+#include "crypto.h"
#define LEAP_VERSION 1
#define LEAP_CHALLENGE_LEN 8
@@ -68,18 +68,20 @@ static void eap_leap_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_leap_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_hdr *req, *resp;
- u8 *pos, *challenge, challenge_len;
+ const struct eap_hdr *req;
+ struct eap_hdr *resp;
+ const u8 *pos, *challenge;
+ u8 challenge_len, *rpos;
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Request");
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
+ req = (const struct eap_hdr *) reqData;
+ pos = (const u8 *) (req + 1);
if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_LEAP) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Request frame");
ret->ignore = TRUE;
@@ -121,17 +123,18 @@ static u8 * eap_leap_process_request(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
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_RESPONSE_LEN;
+ 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, pos);
- memcpy(data->peer_response, pos, LEAP_RESPONSE_LEN);
- wpa_hexdump(MSG_MSGDUMP, "EAP-LEAP: Response", pos, LEAP_RESPONSE_LEN);
- pos += LEAP_RESPONSE_LEN;
- memcpy(pos, config->identity, config->identity_len);
+ config->password, config->password_len, rpos);
+ 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);
data->state = LEAP_WAIT_SUCCESS;
@@ -141,12 +144,13 @@ 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,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_leap_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_hdr *req, *resp;
+ const struct eap_hdr *req;
+ struct eap_hdr *resp;
u8 *pos;
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Success");
@@ -158,7 +162,7 @@ static u8 * eap_leap_process_success(struct eap_sm *sm, void *priv,
return NULL;
}
- req = (struct eap_hdr *) reqData;
+ req = (const struct eap_hdr *) reqData;
*respDataLen = sizeof(struct eap_hdr) + 1 + 3 + LEAP_CHALLENGE_LEN +
config->identity_len;
@@ -194,19 +198,20 @@ 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,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_leap_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_hdr *resp;
- u8 *pos, response_len, pw_hash[16], pw_hash_hash[16],
+ const struct eap_hdr *resp;
+ const u8 *pos;
+ u8 response_len, pw_hash[16], pw_hash_hash[16],
expected[LEAP_RESPONSE_LEN];
wpa_printf(MSG_DEBUG, "EAP-LEAP: Processing EAP-Response");
- resp = (struct eap_hdr *) reqData;
- pos = (u8 *) (resp + 1);
+ resp = (const struct eap_hdr *) reqData;
+ pos = (const u8 *) (resp + 1);
if (reqDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_LEAP) {
wpa_printf(MSG_INFO, "EAP-LEAP: Invalid EAP-Response frame");
ret->ignore = TRUE;
@@ -270,11 +275,11 @@ static u8 * eap_leap_process_response(struct eap_sm *sm, void *priv,
static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_hdr *eap;
+ const struct eap_hdr *eap;
size_t len;
if (config == NULL || config->password == NULL) {
@@ -284,7 +289,7 @@ static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
return NULL;
}
- eap = (struct eap_hdr *) reqData;
+ eap = (const struct eap_hdr *) reqData;
if (reqDataLen < sizeof(*eap) ||
(len = be_to_host16(eap->length)) > reqDataLen) {
@@ -295,7 +300,7 @@ static u8 * eap_leap_process(struct eap_sm *sm, void *priv,
ret->ignore = FALSE;
ret->allowNotifications = TRUE;
- ret->methodState = METHOD_CONT;
+ ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
sm->leap_done = FALSE;
@@ -331,7 +336,8 @@ 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];
- MD5_CTX context;
+ const u8 *addr[5];
+ size_t elen[5];
if (data->state != LEAP_DONE)
return NULL;
@@ -353,13 +359,17 @@ static u8 * eap_leap_getKey(struct eap_sm *sm, void *priv, size_t *len)
wpa_hexdump(MSG_DEBUG, "EAP-LEAP: ap_response",
data->ap_response, LEAP_RESPONSE_LEN);
- MD5Init(&context);
- MD5Update(&context, pw_hash_hash, 16);
- MD5Update(&context, data->ap_challenge, LEAP_CHALLENGE_LEN);
- MD5Update(&context, data->ap_response, LEAP_RESPONSE_LEN);
- MD5Update(&context, data->peer_challenge, LEAP_CHALLENGE_LEN);
- MD5Update(&context, data->peer_response, LEAP_RESPONSE_LEN);
- MD5Final(key, &context);
+ addr[0] = pw_hash_hash;
+ elen[0] = 16;
+ addr[1] = data->ap_challenge;
+ elen[1] = LEAP_CHALLENGE_LEN;
+ addr[2] = data->ap_response;
+ elen[2] = LEAP_RESPONSE_LEN;
+ addr[3] = data->peer_challenge;
+ elen[3] = LEAP_CHALLENGE_LEN;
+ addr[4] = data->peer_response;
+ elen[4] = LEAP_RESPONSE_LEN;
+ md5_vector(5, addr, elen, key);
wpa_hexdump_key(MSG_DEBUG, "EAP-LEAP: master key", key, LEAP_KEY_LEN);
*len = LEAP_KEY_LEN;
diff --git a/contrib/wpa_supplicant/eap_md5.c b/contrib/wpa_supplicant/eap_md5.c
index bcb5558..46a5f55 100644
--- a/contrib/wpa_supplicant/eap_md5.c
+++ b/contrib/wpa_supplicant/eap_md5.c
@@ -20,6 +20,7 @@
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "md5.h"
+#include "crypto.h"
static void * eap_md5_init(struct eap_sm *sm)
@@ -35,15 +36,18 @@ static void eap_md5_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_hdr *req, *resp;
- u8 *pos, *challenge;
+ const struct eap_hdr *req;
+ struct eap_hdr *resp;
+ const u8 *pos, *challenge;
+ u8 *rpos;
int challenge_len;
- MD5_CTX context;
size_t len;
+ const u8 *addr[3];
+ size_t elen[3];
if (config == NULL || config->password == NULL) {
wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
@@ -52,18 +56,15 @@ static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
return NULL;
}
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_MD5 ||
- (len = be_to_host16(req->length)) > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
+ pos = eap_hdr_validate(EAP_TYPE_MD5, reqData, reqDataLen, &len);
+ if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
- pos++;
+ req = (const struct eap_hdr *) reqData;
challenge_len = *pos++;
if (challenge_len == 0 ||
- challenge_len > len - sizeof(*req) - 2) {
+ challenge_len > len - 1) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
"(challenge_len=%d len=%lu",
challenge_len, (unsigned long) len);
@@ -87,16 +88,18 @@ static u8 * eap_md5_process(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(*respDataLen);
- pos = (u8 *) (resp + 1);
- *pos++ = EAP_TYPE_MD5;
- *pos++ = MD5_MAC_LEN; /* Value-Size */
-
- MD5Init(&context);
- MD5Update(&context, &resp->identifier, 1);
- MD5Update(&context, config->password, config->password_len);
- MD5Update(&context, challenge, challenge_len);
- MD5Final(pos, &context);
- wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, MD5_MAC_LEN);
+ rpos = (u8 *) (resp + 1);
+ *rpos++ = EAP_TYPE_MD5;
+ *rpos++ = MD5_MAC_LEN; /* Value-Size */
+
+ addr[0] = &resp->identifier;
+ elen[0] = 1;
+ addr[1] = config->password;
+ elen[1] = config->password_len;
+ addr[2] = challenge;
+ elen[2] = challenge_len;
+ md5_vector(3, addr, elen, rpos);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, MD5_MAC_LEN);
return (u8 *) resp;
}
diff --git a/contrib/wpa_supplicant/eap_mschapv2.c b/contrib/wpa_supplicant/eap_mschapv2.c
index 35c391c..9fcd480 100644
--- a/contrib/wpa_supplicant/eap_mschapv2.c
+++ b/contrib/wpa_supplicant/eap_mschapv2.c
@@ -21,6 +21,7 @@
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "ms_funcs.h"
+#include "wpa_ctrl.h"
struct eap_mschapv2_hdr {
@@ -71,6 +72,9 @@ struct eap_mschapv2_data {
u8 master_key[16];
int master_key_valid;
int success;
+
+ u8 *prev_challenge;
+ size_t prev_challenge_len;
};
@@ -114,6 +118,7 @@ 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);
}
@@ -121,7 +126,7 @@ static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
- struct eap_mschapv2_hdr *req,
+ const struct eap_mschapv2_hdr *req,
size_t *respDataLen)
{
struct wpa_ssid *config = eap_get_config(sm);
@@ -131,6 +136,9 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
struct eap_mschapv2_hdr *resp;
u8 password_hash[16], password_hash_hash[16];
+ if (config == NULL)
+ return NULL;
+
/* MSCHAPv2 does not include optional domain name in the
* challenge-response calculation, so remove domain prefix
* (if present). */
@@ -150,26 +158,31 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
challenge_len = *pos++;
if (challenge_len != 16) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
- "%d", challenge_len);
+ "%lu", (unsigned long) challenge_len);
ret->ignore = TRUE;
return NULL;
}
if (len < 10 || len - 10 < challenge_len) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
- " packet: len=%lu challenge_len=%d",
- (unsigned long) len, challenge_len);
+ " packet: len=%lu challenge_len=%lu",
+ (unsigned long) len, (unsigned long) challenge_len);
ret->ignore = TRUE;
return NULL;
}
- challenge = pos;
+ if (data->passwd_change_challenge_valid) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
+ "failure message");
+ challenge = data->passwd_change_challenge;
+ } else
+ challenge = pos;
pos += challenge_len;
wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
pos, len - challenge_len - 10);
ret->ignore = FALSE;
- ret->methodState = METHOD_CONT;
+ ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
@@ -187,9 +200,17 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
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;
- resp->ms_length[0] = ms_len >> 8;
- resp->ms_length[1] = ms_len & 0xff;
+ WPA_PUT_BE16(resp->ms_length, ms_len);
pos = (u8 *) (resp + 1);
*pos++ = MSCHAPV2_RESP_LEN; /* Value-Size */
@@ -243,6 +264,8 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
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;
}
@@ -250,16 +273,17 @@ static u8 * eap_mschapv2_challenge(struct eap_sm *sm,
static u8 * eap_mschapv2_success(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
- struct eap_mschapv2_hdr *req,
+ const struct eap_mschapv2_hdr *req,
size_t *respDataLen)
{
struct eap_mschapv2_hdr *resp;
- u8 *pos, recv_response[20];
+ const u8 *pos;
+ u8 recv_response[20];
int len, left;
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
len = be_to_host16(req->length);
- pos = (u8 *) (req + 1);
+ pos = (const u8 *) (req + 1);
if (!data->auth_response_valid || len < sizeof(*req) + 42 ||
pos[0] != 'S' || pos[1] != '=' ||
hexstr2bin((char *) (pos + 2), recv_response, 20) ||
@@ -299,6 +323,21 @@ static u8 * eap_mschapv2_success(struct eap_sm *sm,
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;
+ }
+ }
+
return (u8 *) resp;
}
@@ -382,27 +421,152 @@ static int eap_mschapv2_failure_txt(struct eap_sm *sm,
"EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
"%d)",
msg, retry == 1 ? "" : "not ", data->prev_error);
- if (retry == 1 && config) {
+ if (data->prev_error == ERROR_PASSWD_EXPIRED &&
+ data->passwd_change_version == 3 && config) {
+ if (config->new_password == NULL) {
+ wpa_msg(sm->msg_ctx, MSG_INFO,
+ "EAP-MSCHAPV2: Password expired - password "
+ "change required");
+ eap_sm_request_new_password(sm, config);
+ }
+ } else if (retry == 1 && config) {
/* TODO: could prevent the current password from being used
* again at least for some period of time */
- eap_sm_request_identity(sm, config);
+ if (!config->mschapv2_retry)
+ eap_sm_request_identity(sm, config);
eap_sm_request_password(sm, config);
+ config->mschapv2_retry = 1;
} else if (config) {
/* TODO: prevent retries using same username/password */
+ config->mschapv2_retry = 0;
}
return retry == 1;
}
+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)
+{
+ 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)
+ 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;
+ }
+ }
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_COND_SUCC;
+ ret->allowNotifications = TRUE;
+
+ *respDataLen = 591;
+ resp = malloc(*respDataLen);
+ 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);
+
+ /* 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;
+
+ /* 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;
+
+ /* Peer-Challenge */
+ peer_challenge = pos;
+ if (hostapd_get_rand(peer_challenge, 16)) {
+ free(resp);
+ return NULL;
+ }
+ pos += 16;
+
+ /* Reserved, must be zero */
+ memset(pos, 0, 8);
+ pos += 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);
+ 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,
+ username, username_len,
+ config->new_password, config->new_password_len,
+ pos);
+ wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-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->new_password,
+ config->new_password_len,
+ peer_challenge,
+ data->passwd_change_challenge,
+ username, username_len, pos,
+ data->auth_response);
+ data->auth_response_valid = 1;
+
+ pos += 24;
+
+ /* Flags */
+ *pos++ = 0;
+ *pos++ = 0;
+
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
+ "(change pw)", resp->identifier, resp->mschapv2_id);
+
+ return (u8 *) resp;
+}
+
+
static u8 * eap_mschapv2_failure(struct eap_sm *sm,
struct eap_mschapv2_data *data,
struct eap_method_ret *ret,
- struct eap_mschapv2_hdr *req,
+ const struct eap_mschapv2_hdr *req,
size_t *respDataLen)
{
struct eap_mschapv2_hdr *resp;
- u8 *msdata = (u8 *) (req + 1);
+ const u8 *msdata = (const u8 *) (req + 1);
char *buf;
int len = be_to_host16(req->length) - sizeof(*req);
int retry = 0;
@@ -423,10 +587,19 @@ static u8 * eap_mschapv2_failure(struct eap_sm *sm,
ret->decision = DECISION_FAIL;
ret->allowNotifications = FALSE;
- if (retry) {
+ if (data->prev_error == ERROR_PASSWD_EXPIRED &&
+ data->passwd_change_version == 3) {
+ struct wpa_ssid *config = eap_get_config(sm);
+ if (config && config->new_password)
+ return eap_mschapv2_change_password(sm, data, ret, req,
+ respDataLen);
+ if (config && config->pending_req_new_password)
+ return NULL;
+ } else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
/* TODO: could try to retry authentication, e.g, after having
* changed the username/password. In this case, EAP MS-CHAP-v2
* Failure Response would not be sent here. */
+ return NULL;
}
*respDataLen = 6;
@@ -447,13 +620,15 @@ static u8 * eap_mschapv2_failure(struct eap_sm *sm,
static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_mschapv2_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_mschapv2_hdr *req;
- int ms_len, len;
+ const struct eap_mschapv2_hdr *req;
+ int ms_len, 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");
@@ -469,19 +644,28 @@ static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
return NULL;
}
- req = (struct eap_mschapv2_hdr *) reqData;
- len = be_to_host16(req->length);
- if (len < sizeof(*req) + 2 || req->type != EAP_TYPE_MSCHAPV2 ||
- len > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
+ if (config->mschapv2_retry && data->prev_challenge &&
+ data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet "
+ "with the previous challenge");
+
+ reqData = data->prev_challenge;
+ reqDataLen = data->prev_challenge_len;
+ using_prev_challenge = 1;
+ config->mschapv2_retry = 0;
+ }
+
+ pos = eap_hdr_validate(EAP_TYPE_MSCHAPV2, reqData, reqDataLen, &len);
+ if (pos == NULL || len < 5) {
ret->ignore = TRUE;
return NULL;
}
-
- ms_len = ((int) req->ms_length[0] << 8) | req->ms_length[1];
+ 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=%d "
- "ms_len=%d", len, ms_len);
+ 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. */
@@ -493,8 +677,19 @@ static u8 * eap_mschapv2_process(struct eap_sm *sm, void *priv,
}
}
+ wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
+ req->identifier, req->mschapv2_id);
+
switch (req->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);
case MSCHAPV2_OP_SUCCESS:
return eap_mschapv2_success(sm, data, ret, req, respDataLen);
diff --git a/contrib/wpa_supplicant/eap_otp.c b/contrib/wpa_supplicant/eap_otp.c
index e50de63..e7ec44c 100644
--- a/contrib/wpa_supplicant/eap_otp.c
+++ b/contrib/wpa_supplicant/eap_otp.c
@@ -35,31 +35,29 @@ static void eap_otp_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_otp_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_hdr *req, *resp;
- u8 *pos, *password;
+ const struct eap_hdr *req;
+ struct eap_hdr *resp;
+ const u8 *pos, *password;
+ u8 *rpos;
size_t password_len, len;
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_OTP ||
- (len = be_to_host16(req->length)) > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-OTP: Invalid frame");
+ pos = eap_hdr_validate(EAP_TYPE_OTP, reqData, reqDataLen, &len);
+ if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
- pos++;
+ req = (const struct eap_hdr *) reqData;
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-OTP: Request message",
- pos, len - sizeof(*req) - 1);
+ pos, len);
if (config == NULL ||
(config->password == NULL && config->otp == NULL)) {
wpa_printf(MSG_INFO, "EAP-OTP: Password not configured");
- eap_sm_request_otp(sm, config, (char *) pos,
- len - sizeof(*req) - 1);
+ eap_sm_request_otp(sm, config, (const char *) pos, len);
ret->ignore = TRUE;
return NULL;
}
@@ -85,9 +83,9 @@ static u8 * eap_otp_process(struct eap_sm *sm, void *priv,
resp->code = EAP_CODE_RESPONSE;
resp->identifier = req->identifier;
resp->length = host_to_be16(*respDataLen);
- pos = (u8 *) (resp + 1);
- *pos++ = EAP_TYPE_OTP;
- memcpy(pos, password, password_len);
+ rpos = (u8 *) (resp + 1);
+ *rpos++ = EAP_TYPE_OTP;
+ memcpy(rpos, password, password_len);
wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-OTP: Response",
password, password_len);
diff --git a/contrib/wpa_supplicant/eap_pax.c b/contrib/wpa_supplicant/eap_pax.c
new file mode 100644
index 0000000..b590b90
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_pax.c
@@ -0,0 +1,510 @@
+/*
+ * WPA Supplicant / EAP-PAX (draft-clancy-eap-pax-04.txt)
+ * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "eap_i.h"
+#include "wpa_supplicant.h"
+#include "config_ssid.h"
+#include "eap_pax_common.h"
+#include "sha1.h"
+#include "crypto.h"
+
+/*
+ * Note: only PAX_STD subprotocol is currently supported
+ */
+
+struct eap_pax_data {
+ enum { PAX_INIT, PAX_STD_2_SENT, PAX_DONE } state;
+ u8 mac_id, dh_group_id, public_key_id;
+ union {
+ u8 e[2 * EAP_PAX_RAND_LEN];
+ struct {
+ u8 x[EAP_PAX_RAND_LEN]; /* server rand */
+ u8 y[EAP_PAX_RAND_LEN]; /* client rand */
+ } r;
+ } rand;
+ char *cid;
+ size_t cid_len;
+ u8 ak[EAP_PAX_AK_LEN];
+ u8 mk[EAP_PAX_MK_LEN];
+ u8 ck[EAP_PAX_CK_LEN];
+ u8 ick[EAP_PAX_ICK_LEN];
+};
+
+
+static void eap_pax_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_pax_init(struct eap_sm *sm)
+{
+ struct wpa_ssid *config = eap_get_config(sm);
+ struct eap_pax_data *data;
+
+ if (config == NULL || !config->nai ||
+ (!config->eappsk && !config->password)) {
+ wpa_printf(MSG_INFO, "EAP-PAX: CID (nai) or key "
+ "(eappsk/password) not configured");
+ return NULL;
+ }
+
+ if (config->eappsk && config->eappsk_len != EAP_PAX_AK_LEN) {
+ wpa_printf(MSG_INFO, "EAP-PAX: incorrect key length (eappsk); "
+ "expected %d", EAP_PAX_AK_LEN);
+ return NULL;
+ }
+
+ data = malloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ memset(data, 0, sizeof(*data));
+ data->state = PAX_INIT;
+
+ data->cid = malloc(config->nai_len);
+ if (data->cid == NULL) {
+ eap_pax_deinit(sm, data);
+ return NULL;
+ }
+ 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);
+ } else {
+ u8 hash[SHA1_MAC_LEN];
+ const unsigned char *addr[1];
+ size_t len[1];
+ addr[0] = config->password;
+ len[0] = config->password_len;
+ sha1_vector(1, addr, len, hash);
+ memcpy(data->ak, hash, EAP_PAX_AK_LEN);
+ }
+
+ return data;
+}
+
+
+static void eap_pax_deinit(struct eap_sm *sm, void *priv)
+{
+ struct eap_pax_data *data = priv;
+ free(data->cid);
+ free(data);
+}
+
+
+static struct eap_pax_hdr * eap_pax_alloc_resp(const struct eap_pax_hdr *req,
+ u16 resp_len, u8 op_code)
+{
+ struct eap_pax_hdr *resp;
+
+ resp = malloc(resp_len);
+ if (resp == NULL)
+ return NULL;
+ resp->code = EAP_CODE_RESPONSE;
+ resp->identifier = req->identifier;
+ resp->length = host_to_be16(resp_len);
+ resp->type = EAP_TYPE_PAX;
+ resp->op_code = op_code;
+ resp->flags = 0;
+ resp->mac_id = req->mac_id;
+ resp->dh_group_id = req->dh_group_id;
+ resp->public_key_id = req->public_key_id;
+ return resp;
+}
+
+
+static u8 * eap_pax_process_std_1(struct eap_sm *sm, struct eap_pax_data *data,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ const struct eap_pax_hdr *req;
+ struct eap_pax_hdr *resp;
+ const u8 *pos;
+ u8 *rpos;
+ size_t left;
+
+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-1 (received)");
+ req = (const struct eap_pax_hdr *) reqData;
+
+ if (data->state != PAX_INIT) {
+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 received in "
+ "unexpected state (%d) - ignored", data->state);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (req->flags & EAP_PAX_FLAGS_CE) {
+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with CE flag set - "
+ "ignored");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ left = reqDataLen - sizeof(*req);
+
+ if (left < 2 + EAP_PAX_RAND_LEN) {
+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with too short "
+ "payload");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ pos = (const u8 *) (req + 1);
+ if (WPA_GET_BE16(pos) != EAP_PAX_RAND_LEN) {
+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-1 with incorrect A "
+ "length %d (expected %d)",
+ WPA_GET_BE16(pos), EAP_PAX_RAND_LEN);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ pos += 2;
+ left -= 2;
+ 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;
+ left -= EAP_PAX_RAND_LEN;
+
+ if (left > 0) {
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
+ pos, left);
+ }
+
+ if (hostapd_get_rand(data->rand.r.y, EAP_PAX_RAND_LEN)) {
+ wpa_printf(MSG_ERROR, "EAP-PAX: Failed to get random data");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: Y (client rand)",
+ data->rand.r.y, EAP_PAX_RAND_LEN);
+
+ if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e,
+ data->mk, data->ck, data->ick) < 0)
+ {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-2 (sending)");
+
+ *respDataLen = sizeof(*resp) + 2 + EAP_PAX_RAND_LEN +
+ 2 + data->cid_len + 2 + EAP_PAX_MAC_LEN + EAP_PAX_ICV_LEN;
+ resp = eap_pax_alloc_resp(req, *respDataLen, EAP_PAX_OP_STD_2);
+ if (resp == NULL)
+ return NULL;
+
+ rpos = (u8 *) (resp + 1);
+ *rpos++ = 0;
+ *rpos++ = EAP_PAX_RAND_LEN;
+ 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);
+ wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID", rpos, data->cid_len);
+ rpos += data->cid_len;
+
+ *rpos++ = 0;
+ *rpos++ = EAP_PAX_MAC_LEN;
+ eap_pax_mac(req->mac_id, data->ck, EAP_PAX_CK_LEN,
+ data->rand.r.x, EAP_PAX_RAND_LEN,
+ data->rand.r.y, EAP_PAX_RAND_LEN,
+ (u8 *) data->cid, data->cid_len, rpos);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(A, B, CID)",
+ rpos, EAP_PAX_MAC_LEN);
+ rpos += EAP_PAX_MAC_LEN;
+
+ eap_pax_mac(req->mac_id, data->ick, EAP_PAX_ICK_LEN,
+ (u8 *) resp, *respDataLen - EAP_PAX_ICV_LEN,
+ NULL, 0, NULL, 0, rpos);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
+ rpos += EAP_PAX_ICV_LEN;
+
+ data->state = PAX_STD_2_SENT;
+ data->mac_id = req->mac_id;
+ data->dh_group_id = req->dh_group_id;
+ data->public_key_id = req->public_key_id;
+
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_pax_process_std_3(struct eap_sm *sm, struct eap_pax_data *data,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ const struct eap_pax_hdr *req;
+ struct eap_pax_hdr *resp;
+ u8 *rpos, mac[EAP_PAX_MAC_LEN];
+ const u8 *pos;
+ size_t left;
+
+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX_STD-3 (received)");
+ req = (const struct eap_pax_hdr *) reqData;
+
+ if (data->state != PAX_STD_2_SENT) {
+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 received in "
+ "unexpected state (%d) - ignored", data->state);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (req->flags & EAP_PAX_FLAGS_CE) {
+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with CE flag set - "
+ "ignored");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ left = reqDataLen - sizeof(*req);
+
+ if (left < 2 + EAP_PAX_MAC_LEN) {
+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with too short "
+ "payload");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ pos = (const u8 *) (req + 1);
+ if (WPA_GET_BE16(pos) != EAP_PAX_MAC_LEN) {
+ wpa_printf(MSG_INFO, "EAP-PAX: PAX_STD-3 with incorrect "
+ "MAC_CK length %d (expected %d)",
+ WPA_GET_BE16(pos), EAP_PAX_MAC_LEN);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ pos += 2;
+ left -= 2;
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
+ pos, EAP_PAX_MAC_LEN);
+ 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) {
+ wpa_printf(MSG_INFO, "EAP-PAX: Invalid MAC_CK(B, CID) "
+ "received");
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected MAC_CK(B, CID)",
+ mac, EAP_PAX_MAC_LEN);
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+
+ pos += EAP_PAX_MAC_LEN;
+ left -= EAP_PAX_MAC_LEN;
+
+ if (left > 0) {
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ignored extra payload",
+ pos, left);
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-PAX: PAX-ACK (sending)");
+
+ *respDataLen = sizeof(*resp) + EAP_PAX_ICV_LEN;
+ resp = eap_pax_alloc_resp(req, *respDataLen, EAP_PAX_OP_ACK);
+ if (resp == NULL)
+ return NULL;
+
+ rpos = (u8 *) (resp + 1);
+ eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
+ (u8 *) resp, *respDataLen - EAP_PAX_ICV_LEN,
+ NULL, 0, NULL, 0, rpos);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", rpos, EAP_PAX_ICV_LEN);
+
+ data->state = PAX_DONE;
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_UNCOND_SUCC;
+ ret->allowNotifications = FALSE;
+
+ return (u8 *) resp;
+}
+
+
+static u8 * eap_pax_process(struct eap_sm *sm, void *priv,
+ struct eap_method_ret *ret,
+ const u8 *reqData, size_t reqDataLen,
+ size_t *respDataLen)
+{
+ struct eap_pax_data *data = priv;
+ const struct eap_pax_hdr *req;
+ u8 *resp, icvbuf[EAP_PAX_ICV_LEN];
+ const u8 *icv, *pos;
+ size_t len;
+ u16 flen;
+
+ pos = eap_hdr_validate(EAP_TYPE_PAX, reqData, reqDataLen, &len);
+ if (pos == NULL || len < EAP_PAX_ICV_LEN) {
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ req = (const struct eap_pax_hdr *) reqData;
+ flen = be_to_host16(req->length) - EAP_PAX_ICV_LEN;
+
+ wpa_printf(MSG_DEBUG, "EAP-PAX: received frame: op_code 0x%x "
+ "flags 0x%x mac_id 0x%x dh_group_id 0x%x "
+ "public_key_id 0x%x",
+ req->op_code, req->flags, req->mac_id, req->dh_group_id,
+ req->public_key_id);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: received payload",
+ pos, len - EAP_PAX_ICV_LEN);
+
+ if (data->state != PAX_INIT && data->mac_id != req->mac_id) {
+ wpa_printf(MSG_INFO, "EAP-PAX: MAC ID changed during "
+ "authentication (was 0x%d, is 0x%d)",
+ data->mac_id, req->mac_id);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (data->state != PAX_INIT && data->dh_group_id != req->dh_group_id) {
+ wpa_printf(MSG_INFO, "EAP-PAX: DH Group ID changed during "
+ "authentication (was 0x%d, is 0x%d)",
+ data->dh_group_id, req->dh_group_id);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (data->state != PAX_INIT &&
+ data->public_key_id != req->public_key_id) {
+ wpa_printf(MSG_INFO, "EAP-PAX: Public Key ID changed during "
+ "authentication (was 0x%d, is 0x%d)",
+ data->public_key_id, req->public_key_id);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ /* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_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);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (req->dh_group_id != EAP_PAX_DH_GROUP_NONE) {
+ wpa_printf(MSG_INFO, "EAP-PAX: Unsupported DH Group ID 0x%x",
+ req->dh_group_id);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (req->public_key_id != EAP_PAX_PUBLIC_KEY_NONE) {
+ wpa_printf(MSG_INFO, "EAP-PAX: Unsupported Public Key ID 0x%x",
+ req->public_key_id);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (req->flags & EAP_PAX_FLAGS_MF) {
+ /* TODO: add support for reassembling fragments */
+ wpa_printf(MSG_INFO, "EAP-PAX: fragmentation not supported - "
+ "ignored packet");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ icv = pos + len - EAP_PAX_ICV_LEN;
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: ICV", icv, EAP_PAX_ICV_LEN);
+ if (req->op_code == EAP_PAX_OP_STD_1) {
+ eap_pax_mac(req->mac_id, (u8 *) "", 0,
+ reqData, flen, NULL, 0, NULL, 0, icvbuf);
+ } else {
+ 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) {
+ wpa_printf(MSG_DEBUG, "EAP-PAX: invalid ICV - ignoring the "
+ "message");
+ wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: expected ICV",
+ icvbuf, EAP_PAX_ICV_LEN);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ switch (req->op_code) {
+ case EAP_PAX_OP_STD_1:
+ resp = eap_pax_process_std_1(sm, data, ret, reqData, flen,
+ respDataLen);
+ break;
+ case EAP_PAX_OP_STD_3:
+ resp = eap_pax_process_std_3(sm, data, ret, reqData, flen,
+ respDataLen);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-PAX: ignoring message with unknown "
+ "op_code %d", req->op_code);
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ if (ret->methodState == METHOD_DONE) {
+ ret->allowNotifications = FALSE;
+ }
+
+ return resp;
+}
+
+
+static Boolean eap_pax_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+ struct eap_pax_data *data = priv;
+ return data->state == PAX_DONE;
+}
+
+
+static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pax_data *data = priv;
+ u8 *key;
+
+ if (data->state != PAX_DONE)
+ return NULL;
+
+ key = malloc(EAP_PAX_MSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_PAX_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);
+
+ return key;
+}
+
+
+const struct eap_method eap_method_pax =
+{
+ .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,
+};
diff --git a/contrib/wpa_supplicant/eap_pax_common.c b/contrib/wpa_supplicant/eap_pax_common.c
new file mode 100644
index 0000000..d8f4016
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_pax_common.c
@@ -0,0 +1,152 @@
+/*
+ * WPA Supplicant / EAP-PAX shared routines
+ * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "sha1.h"
+#include "eap_pax_common.h"
+
+
+/**
+ * eap_pax_kdf - PAX Key Derivation Function
+ * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
+ * @key: Secret key (X)
+ * @key_len: Length of the secret key in bytes
+ * @identifier: Public identifier for the key (Y)
+ * @entropy: Exchanged entropy to seed the KDF (Z)
+ * @entropy_len: Length of the entropy in bytes
+ * @output_len: Output len in bytes (W)
+ * @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)
+ */
+int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
+ const char *identifier,
+ const u8 *entropy, size_t entropy_len,
+ size_t output_len, u8 *output)
+{
+ u8 mac[SHA1_MAC_LEN];
+ u8 counter, *pos;
+ const u8 *addr[3];
+ size_t len[3];
+ size_t num_blocks, left;
+
+ num_blocks = (output_len + EAP_PAX_MAC_LEN - 1) / EAP_PAX_MAC_LEN;
+ if (identifier == NULL || num_blocks >= 255)
+ return -1;
+
+ /* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
+ if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
+ return -1;
+
+ addr[0] = (const u8 *) identifier;
+ len[0] = strlen(identifier);
+ addr[1] = entropy;
+ len[1] = entropy_len;
+ addr[2] = &counter;
+ len[2] = 1;
+
+ pos = output;
+ left = output_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);
+ pos += clen;
+ left -= clen;
+ }
+
+ return 0;
+}
+
+
+/**
+ * eap_pax_mac - EAP-PAX MAC
+ * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
+ * @key: Secret key
+ * @key_len: Length of the secret key in bytes
+ * @data1: Optional data, first block; %NULL if not used
+ * @data1_len: Length of data1 in bytes
+ * @data2: Optional data, second block; %NULL if not used
+ * @data2_len: Length of data2 in bytes
+ * @data3: Optional data, third block; %NULL if not used
+ * @data3_len: Length of data3 in bytes
+ * @mac: Buffer for the MAC value (EAP_PAX_MAC_LEN = 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Wrapper function to calculate EAP-PAX MAC.
+ */
+int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
+ const u8 *data1, size_t data1_len,
+ const u8 *data2, size_t data2_len,
+ const u8 *data3, size_t data3_len,
+ u8 *mac)
+{
+ u8 hash[SHA1_MAC_LEN];
+ const u8 *addr[3];
+ size_t len[3];
+ size_t count;
+
+ /* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
+ if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
+ return -1;
+
+ addr[0] = data1;
+ len[0] = data1_len;
+ addr[1] = data2;
+ len[1] = data2_len;
+ addr[2] = data3;
+ len[2] = data3_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);
+
+ return 0;
+}
+
+
+/**
+ * eap_pax_initial_key_derivation - EAP-PAX initial key derivation
+ * @mac_id: MAC ID (EAP_PAX_MAC_*) / currently, only HMAC_SHA1_128 is supported
+ * @ak: Authentication Key
+ * @e: Entropy
+ * @mk: Buffer for the derived Master Key
+ * @ck: Buffer for the derived Confirmation Key
+ * @ick: Buffer for the derived Integrity Check Key
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
+ u8 *mk, u8 *ck, u8 *ick)
+{
+ wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation");
+ if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key",
+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MK_LEN, mk) ||
+ eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key",
+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) ||
+ eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key",
+ e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick))
+ return -1;
+
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN);
+
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/eap_pax_common.h b/contrib/wpa_supplicant/eap_pax_common.h
new file mode 100644
index 0000000..b5ad6af
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_pax_common.h
@@ -0,0 +1,84 @@
+/*
+ * WPA Supplicant / EAP-PAX shared routines
+ * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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_PAX_COMMON_H
+#define EAP_PAX_COMMON_H
+
+struct eap_pax_hdr {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PAX */
+ u8 op_code;
+ u8 flags;
+ u8 mac_id;
+ u8 dh_group_id;
+ u8 public_key_id;
+ /* Followed by variable length payload and ICV */
+} __attribute__ ((packed));
+
+
+/* op_code: */
+enum {
+ EAP_PAX_OP_STD_1 = 0x01,
+ EAP_PAX_OP_STD_2 = 0x02,
+ EAP_PAX_OP_STD_3 = 0x03,
+ EAP_PAX_OP_SEC_1 = 0x11,
+ EAP_PAX_OP_SEC_2 = 0x12,
+ EAP_PAX_OP_SEC_3 = 0x13,
+ EAP_PAX_OP_SEC_4 = 0x14,
+ EAP_PAX_OP_SEC_5 = 0x15,
+ EAP_PAX_OP_ACK = 0x21
+};
+
+/* flags: */
+#define EAP_PAX_FLAGS_MF 0x01
+#define EAP_PAX_FLAGS_CE 0x02
+
+/* mac_id: */
+#define EAP_PAX_MAC_HMAC_SHA1_128 0x01
+#define EAP_PAX_MAC_AES_CBC_MAC_128 0x02
+
+/* dh_group_id: */
+#define EAP_PAX_DH_GROUP_NONE 0x00
+#define EAP_PAX_DH_GROUP_3072_MODP 0x01
+
+/* public_key_id: */
+#define EAP_PAX_PUBLIC_KEY_NONE 0x00
+#define EAP_PAX_PUBLIC_KEY_RSA_OAEP_2048 0x01
+
+
+#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
+#define EAP_PAX_MK_LEN 16
+#define EAP_PAX_CK_LEN 16
+#define EAP_PAX_ICK_LEN 16
+
+
+int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
+ const char *identifier,
+ const u8 *entropy, size_t entropy_len,
+ size_t output_len, u8 *output);
+int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
+ const u8 *data1, size_t data1_len,
+ const u8 *data2, size_t data2_len,
+ const u8 *data3, size_t data3_len,
+ u8 *mac);
+int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
+ u8 *mk, u8 *ck, u8 *ick);
+
+#endif /* EAP_PAX_COMMON_H */
diff --git a/contrib/wpa_supplicant/eap_peap.c b/contrib/wpa_supplicant/eap_peap.c
index 8ca8ab2..efbb867 100644
--- a/contrib/wpa_supplicant/eap_peap.c
+++ b/contrib/wpa_supplicant/eap_peap.c
@@ -193,7 +193,7 @@ static void eap_peap_deinit(struct eap_sm *sm, void *priv)
static int eap_peap_encrypt(struct eap_sm *sm, struct eap_peap_data *data,
- int id, u8 *plain, size_t plain_len,
+ int id, const u8 *plain, size_t plain_len,
u8 **out_data, size_t *out_len)
{
int res;
@@ -263,7 +263,7 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -348,7 +348,7 @@ 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_otp || config->pending_req_new_password)) {
free(data->pending_phase2_req);
data->pending_phase2_req = malloc(len);
if (data->pending_phase2_req) {
@@ -361,18 +361,20 @@ static int eap_peap_phase2_request(struct eap_sm *sm,
}
-static int eap_peap_decrypt(struct eap_sm *sm,
- struct eap_peap_data *data,
+static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
struct eap_method_ret *ret,
- struct eap_hdr *req,
- u8 *in_data, size_t in_len,
+ const struct eap_hdr *req,
+ const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted;
- int buf_len, len_decrypted, len, skip_change = 0, res;
+ int buf_len, len_decrypted, len, skip_change = 0;
struct eap_hdr *hdr, *rhdr;
u8 *resp = NULL;
size_t resp_len;
+ const u8 *msg;
+ size_t msg_len;
+ int need_more_input;
wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -393,9 +395,10 @@ static int eap_peap_decrypt(struct eap_sm *sm,
goto continue_req;
}
- res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
- if (res < 0 || res == 1)
- return res;
+ msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
+ &msg_len, &need_more_input);
+ if (msg == NULL)
+ return need_more_input ? 1 : -1;
if (in_len == 0 && sm->workaround && data->phase2_success) {
/*
@@ -424,7 +427,7 @@ static int eap_peap_decrypt(struct eap_sm *sm,
}
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
- in_data, in_len,
+ msg, msg_len,
in_decrypted, buf_len);
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
@@ -613,62 +616,22 @@ continue_req:
static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct eap_hdr *req;
- int left, res;
- unsigned int tls_msg_len;
- u8 flags, *pos, *resp, id;
+ const struct eap_hdr *req;
+ size_t left;
+ int res;
+ u8 flags, *resp, id;
+ const u8 *pos;
struct eap_peap_data *data = priv;
- if (tls_get_errors(sm->ssl_ctx)) {
- wpa_printf(MSG_INFO, "EAP-PEAP: TLS errors detected");
- ret->ignore = TRUE;
+ pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
+ reqData, reqDataLen, &left, &flags);
+ if (pos == NULL)
return NULL;
- }
-
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_PEAP ||
- (left = be_to_host16(req->length)) > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
- ret->ignore = TRUE;
- return NULL;
- }
- left -= sizeof(struct eap_hdr);
+ req = (const struct eap_hdr *) reqData;
id = req->identifier;
- pos++;
- flags = *pos++;
- left -= 2;
- wpa_printf(MSG_DEBUG, "EAP-PEAP: Received packet(len=%lu) - "
- "Flags 0x%02x", (unsigned long) reqDataLen, flags);
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-PEAP: Short frame with TLS "
- "length");
- ret->ignore = TRUE;
- return NULL;
- }
- tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
- pos[3];
- wpa_printf(MSG_DEBUG, "EAP-PEAP: TLS Message Length: %d",
- tls_msg_len);
- if (data->ssl.tls_in_left == 0) {
- data->ssl.tls_in_total = tls_msg_len;
- data->ssl.tls_in_left = tls_msg_len;
- free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
-
- ret->ignore = FALSE;
- ret->methodState = METHOD_CONT;
- ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
if (flags & EAP_TLS_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
@@ -733,12 +696,12 @@ static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
"derive key");
}
- if (sm->workaround && data->peap_version == 1 &&
- data->resuming) {
+ if (sm->workaround && data->resuming) {
/*
- * At least one RADIUS server (Aegis v1.1.6;
- * but not v1.1.4) seems to be terminating
- * PEAPv1 session resumption with outer
+ * At least few RADIUS servers (Aegis v1.1.6;
+ * but not v1.1.4; and Cisco ACS) seem to be
+ * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
+ * ACS) session resumption with outer
* EAP-Success. This does not seem to follow
* draft-josefsson-pppext-eap-tls-eap-05.txt
* section 4.2, so only allow this if EAP
@@ -746,7 +709,7 @@ static u8 * eap_peap_process(struct eap_sm *sm, void *priv,
*/
wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
"allow outer EAP-Success to "
- "terminate PEAPv1 resumption");
+ "terminate PEAP resumption");
ret->decision = DECISION_COND_SUCC;
data->phase2_success = 1;
}
diff --git a/contrib/wpa_supplicant/eap_psk.c b/contrib/wpa_supplicant/eap_psk.c
index 3b325b5..853c79a 100644
--- a/contrib/wpa_supplicant/eap_psk.c
+++ b/contrib/wpa_supplicant/eap_psk.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-05.txt)
+ * WPA Supplicant / EAP-PSK (draft-bersani-eap-psk-09.txt)
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -10,6 +10,9 @@
* license.
*
* See README and COPYING for more details.
+ *
+ * Note: EAP-PSK is an EAP authentication method and as such, completely
+ * different from WPA-PSK. This file is not needed for WPA-PSK functionality.
*/
#include <stdlib.h>
@@ -22,128 +25,19 @@
#include "config_ssid.h"
#include "md5.h"
#include "aes_wrap.h"
-
-
-/* draft-bersani-eap-psk-03.txt mode. This is retained for interop testing and
- * will be removed once an AS that supports draft5 becomes available. */
-#define EAP_PSK_DRAFT3
-
-#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_R_FLAG_CONT 1
-#define EAP_PSK_R_FLAG_DONE_SUCCESS 2
-#define EAP_PSK_R_FLAG_DONE_FAILURE 3
-
-/* EAP-PSK First Message (AS -> Supplicant) */
-struct eap_psk_hdr_1 {
- u8 code;
- u8 identifier;
- u16 length; /* including code, identifier, and length */
- u8 type; /* EAP_TYPE_PSK */
-#ifndef EAP_PSK_DRAFT3
- u8 flags;
-#endif /* EAP_PSK_DRAFT3 */
- u8 rand_s[EAP_PSK_RAND_LEN];
-#ifndef EAP_PSK_DRAFT3
- /* Followed by variable length ID_S */
-#endif /* EAP_PSK_DRAFT3 */
-} __attribute__ ((packed));
-
-/* EAP-PSK Second Message (Supplicant -> AS) */
-struct eap_psk_hdr_2 {
- u8 code;
- u8 identifier;
- u16 length; /* including code, identifier, and length */
- u8 type; /* EAP_TYPE_PSK */
-#ifndef EAP_PSK_DRAFT3
- u8 flags;
- u8 rand_s[EAP_PSK_RAND_LEN];
-#endif /* EAP_PSK_DRAFT3 */
- u8 rand_p[EAP_PSK_RAND_LEN];
- u8 mac_p[EAP_PSK_MAC_LEN];
- /* Followed by variable length ID_P */
-} __attribute__ ((packed));
-
-/* EAP-PSK Third Message (AS -> Supplicant) */
-struct eap_psk_hdr_3 {
- u8 code;
- u8 identifier;
- u16 length; /* including code, identifier, and length */
- u8 type; /* EAP_TYPE_PSK */
-#ifndef EAP_PSK_DRAFT3
- u8 flags;
- u8 rand_s[EAP_PSK_RAND_LEN];
-#endif /* EAP_PSK_DRAFT3 */
- u8 mac_s[EAP_PSK_MAC_LEN];
- /* Followed by variable length PCHANNEL */
-} __attribute__ ((packed));
-
-/* EAP-PSK Fourth Message (Supplicant -> AS) */
-struct eap_psk_hdr_4 {
- u8 code;
- u8 identifier;
- u16 length; /* including code, identifier, and length */
- u8 type; /* EAP_TYPE_PSK */
-#ifndef EAP_PSK_DRAFT3
- u8 flags;
- u8 rand_s[EAP_PSK_RAND_LEN];
-#endif /* EAP_PSK_DRAFT3 */
- /* Followed by variable length PCHANNEL */
-} __attribute__ ((packed));
-
+#include "eap_psk_common.h"
struct eap_psk_data {
enum { PSK_INIT, PSK_MAC_SENT, PSK_DONE } state;
- u8 rand_s[EAP_PSK_RAND_LEN];
u8 rand_p[EAP_PSK_RAND_LEN];
- u8 ak[16], kdk[16], tek[EAP_PSK_TEK_LEN];
+ 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];
};
-#define aes_block_size 16
-
-
-static void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
-{
- memset(ak, 0, aes_block_size);
- aes_128_encrypt_block(psk, ak, ak);
- 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);
- aes_128_encrypt_block(psk, kdk, kdk);
-}
-
-
-static void eap_psk_derive_keys(const u8 *kdk, const u8 *rb, u8 *tek, u8 *msk)
-{
- u8 hash[aes_block_size];
- u8 counter = 1;
- int i;
-
- aes_128_encrypt_block(kdk, rb, hash);
-
- hash[aes_block_size - 1] ^= counter;
- aes_128_encrypt_block(kdk, hash, tek);
- hash[aes_block_size - 1] ^= counter;
- counter++;
-
- for (i = 0; i < EAP_PSK_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++;
- }
-}
-
-
static void * eap_psk_init(struct eap_sm *sm)
{
struct wpa_ssid *config = eap_get_config(sm);
@@ -159,8 +53,8 @@ static void * eap_psk_init(struct eap_sm *sm)
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, 16);
- wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: KDK", data->kdk, 16);
+ 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) {
@@ -175,22 +69,6 @@ static void * eap_psk_init(struct eap_sm *sm)
return NULL;
}
-#ifdef EAP_PSK_DRAFT3
- if (config->server_nai) {
- data->id_s = malloc(config->server_nai_len);
- if (data->id_s)
- memcpy(data->id_s, config->server_nai,
- config->server_nai_len);
- data->id_s_len = config->server_nai_len;
- }
- if (data->id_s == NULL) {
- wpa_printf(MSG_INFO, "EAP-PSK: could not get server identity");
- free(data->id_p);
- free(data);
- return NULL;
- }
-#endif /* EAP_PSK_DRAFT3 */
-
return data;
}
@@ -206,17 +84,17 @@ static void eap_psk_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct eap_psk_hdr_1 *hdr1;
+ const struct eap_psk_hdr_1 *hdr1;
struct eap_psk_hdr_2 *hdr2;
u8 *resp, *buf, *pos;
size_t buflen;
wpa_printf(MSG_DEBUG, "EAP-PSK: in INIT state");
- hdr1 = (struct eap_psk_hdr_1 *) reqData;
+ hdr1 = (const struct eap_psk_hdr_1 *) reqData;
if (reqDataLen < sizeof(*hdr1) ||
be_to_host16(hdr1->length) < sizeof(*hdr1) ||
be_to_host16(hdr1->length) > reqDataLen) {
@@ -228,7 +106,6 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
ret->ignore = TRUE;
return NULL;
}
-#ifndef EAP_PSK_DRAFT3
wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr1->flags);
if ((hdr1->flags & 0x03) != 0) {
wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 0)",
@@ -237,24 +114,20 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
ret->decision = DECISION_FAIL;
return NULL;
}
-#endif /* EAP_PSK_DRAFT3 */
wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr1->rand_s,
EAP_PSK_RAND_LEN);
- memcpy(data->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
-#ifndef EAP_PSK_DRAFT3
free(data->id_s);
data->id_s_len = be_to_host16(hdr1->length) - sizeof(*hdr1);
data->id_s = malloc(data->id_s_len);
if (data->id_s == NULL) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to allocate memory for "
- "ID_S (len=%d)", data->id_s_len);
+ "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);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-PSK: ID_S",
data->id_s, data->id_s_len);
-#endif /* EAP_PSK_DRAFT3 */
if (hostapd_get_rand(data->rand_p, EAP_PSK_RAND_LEN)) {
wpa_printf(MSG_ERROR, "EAP-PSK: Failed to get random data");
@@ -271,10 +144,8 @@ 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;
-#ifndef EAP_PSK_DRAFT3
hdr2->flags = 1; /* T=1 */
memcpy(hdr2->rand_s, hdr1->rand_s, EAP_PSK_RAND_LEN);
-#endif /* EAP_PSK_DRAFT3 */
memcpy(hdr2->rand_p, data->rand_p, EAP_PSK_RAND_LEN);
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) */
@@ -288,7 +159,7 @@ static u8 * eap_psk_process_1(struct eap_sm *sm, struct eap_psk_data *data,
pos = buf + data->id_p_len;
memcpy(pos, data->id_s, data->id_s_len);
pos += data->id_s_len;
- memcpy(pos, data->rand_s, EAP_PSK_RAND_LEN);
+ memcpy(pos, hdr1->rand_s, EAP_PSK_RAND_LEN);
pos += EAP_PSK_RAND_LEN;
memcpy(pos, data->rand_p, EAP_PSK_RAND_LEN);
omac1_aes_128(data->ak, buf, buflen, hdr2->mac_p);
@@ -307,19 +178,20 @@ 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,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct eap_psk_hdr_3 *hdr3;
+ const struct eap_psk_hdr_3 *hdr3;
struct eap_psk_hdr_4 *hdr4;
- u8 *resp, *buf, *pchannel, *tag, *msg, nonce[16];
+ u8 *resp, *buf, *rpchannel, nonce[16], *decrypted;
+ const u8 *pchannel, *tag, *msg;
u8 mac[EAP_PSK_MAC_LEN];
- size_t buflen, left;
+ size_t buflen, left, data_len;
int failed = 0;
wpa_printf(MSG_DEBUG, "EAP-PSK: in MAC_SENT state");
- hdr3 = (struct eap_psk_hdr_3 *) reqData;
+ hdr3 = (const struct eap_psk_hdr_3 *) reqData;
left = be_to_host16(hdr3->length);
if (left < sizeof(*hdr3) || reqDataLen < left) {
wpa_printf(MSG_INFO, "EAP-PSK: Invalid third message "
@@ -331,8 +203,7 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
return NULL;
}
left -= sizeof(*hdr3);
- pchannel = (u8 *) (hdr3 + 1);
-#ifndef EAP_PSK_DRAFT3
+ pchannel = (const u8 *) (hdr3 + 1);
wpa_printf(MSG_DEBUG, "EAP-PSK: Flags=0x%x", hdr3->flags);
if ((hdr3->flags & 0x03) != 2) {
wpa_printf(MSG_INFO, "EAP-PSK: Unexpected T=%d (expected 2)",
@@ -343,16 +214,6 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
}
wpa_hexdump(MSG_DEBUG, "EAP-PSK: RAND_S", hdr3->rand_s,
EAP_PSK_RAND_LEN);
- /* TODO: would not need to store RAND_S since it is available in this
- * message. For now, since we store this anyway, verify that it matches
- * with whatever the server is sending. */
- if (memcmp(hdr3->rand_s, data->rand_s, EAP_PSK_RAND_LEN) != 0) {
- wpa_printf(MSG_ERROR, "EAP-PSK: RAND_S did not match");
- ret->methodState = METHOD_DONE;
- ret->decision = DECISION_FAIL;
- return NULL;
- }
-#endif /* EAP_PSK_DRAFT3 */
wpa_hexdump(MSG_DEBUG, "EAP-PSK: MAC_S", hdr3->mac_s, EAP_PSK_MAC_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-PSK: PCHANNEL", pchannel, left);
@@ -404,25 +265,29 @@ 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);
-#ifdef EAP_PSK_DRAFT3
- if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
- reqData, 5, msg, left, tag))
-#else /* EAP_PSK_DRAFT3 */
+ decrypted = malloc(left);
+ if (decrypted == NULL) {
+ ret->methodState = METHOD_DONE;
+ ret->decision = DECISION_FAIL;
+ return NULL;
+ }
+ memcpy(decrypted, msg, left);
+
if (aes_128_eax_decrypt(data->tek, nonce, sizeof(nonce),
- reqData, 22, msg, left, tag))
-#endif /* EAP_PSK_DRAFT3 */
- {
+ reqData, 22, decrypted, left, tag)) {
wpa_printf(MSG_WARNING, "EAP-PSK: PCHANNEL decryption failed");
+ free(decrypted);
return NULL;
}
wpa_hexdump(MSG_DEBUG, "EAP-PSK: Decrypted PCHANNEL message",
- msg, left);
+ decrypted, left);
/* Verify R flag */
- switch (msg[0] >> 6) {
+ switch (decrypted[0] >> 6) {
case EAP_PSK_R_FLAG_CONT:
wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - CONT - unsupported");
- return NULL;
+ failed = 1;
+ break;
case EAP_PSK_R_FLAG_DONE_SUCCESS:
wpa_printf(MSG_DEBUG, "EAP-PSK: R flag - DONE_SUCCESS");
break;
@@ -435,37 +300,48 @@ static u8 * eap_psk_process_3(struct eap_sm *sm, struct eap_psk_data *data,
}
*respDataLen = sizeof(*hdr4) + 4 + 16 + 1;
- resp = malloc(*respDataLen);
- if (resp == NULL)
+ resp = malloc(*respDataLen + 1);
+ if (resp == NULL) {
+ free(decrypted);
return NULL;
+ }
hdr4 = (struct eap_psk_hdr_4 *) resp;
hdr4->code = EAP_CODE_RESPONSE;
hdr4->identifier = hdr3->identifier;
hdr4->length = host_to_be16(*respDataLen);
hdr4->type = EAP_TYPE_PSK;
-#ifndef EAP_PSK_DRAFT3
hdr4->flags = 3; /* T=3 */
memcpy(hdr4->rand_s, hdr3->rand_s, EAP_PSK_RAND_LEN);
-#endif /* EAP_PSK_DRAFT3 */
- pchannel = (u8 *) (hdr4 + 1);
+ rpchannel = (u8 *) (hdr4 + 1);
/* nonce++ */
inc_byte_array(nonce, sizeof(nonce));
- memcpy(pchannel, nonce + 12, 4);
+ memcpy(rpchannel, nonce + 12, 4);
- pchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
+ data_len = 1;
+ if (decrypted[0] & EAP_PSK_E_FLAG) {
+ wpa_printf(MSG_DEBUG, "EAP-PSK: Unsupported E (Ext) flag");
+ failed = 1;
+ rpchannel[4 + 16] = (EAP_PSK_R_FLAG_DONE_FAILURE << 6) |
+ EAP_PSK_E_FLAG;
+ if (left > 1) {
+ /* Add empty EXT_Payload with same EXT_Type */
+ (*respDataLen)++;
+ hdr4->length = host_to_be16(*respDataLen);
+ rpchannel[4 + 16 + 1] = decrypted[1];
+ data_len++;
+ }
+ } else if (failed)
+ rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_FAILURE << 6;
+ else
+ rpchannel[4 + 16] = EAP_PSK_R_FLAG_DONE_SUCCESS << 6;
wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (plaintext)",
- pchannel + 4 + 16, 1);
-#ifdef EAP_PSK_DRAFT3
- aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 5,
- pchannel + 4 + 16, 1, pchannel + 4);
-#else /* EAP_PSK_DRAFT3 */
+ rpchannel + 4 + 16, data_len);
aes_128_eax_encrypt(data->tek, nonce, sizeof(nonce), resp, 22,
- pchannel + 4 + 16, 1, pchannel + 4);
-#endif /* EAP_PSK_DRAFT3 */
+ rpchannel + 4 + 16, data_len, rpchannel + 4);
wpa_hexdump(MSG_DEBUG, "EAP-PSK: reply message (PCHANNEL)",
- pchannel, 4 + 16 + 1);
+ rpchannel, 4 + 16 + data_len);
wpa_printf(MSG_DEBUG, "EAP-PSK: Completed %ssuccessfully",
failed ? "un" : "");
@@ -473,31 +349,31 @@ 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);
+
return resp;
}
static u8 * eap_psk_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_psk_data *data = priv;
- struct eap_hdr *req;
- u8 *pos, *resp = NULL;
+ const u8 *pos;
+ u8 *resp = NULL;
size_t len;
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 1 || *pos != EAP_TYPE_PSK ||
- (len = be_to_host16(req->length)) > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
+ pos = eap_hdr_validate(EAP_TYPE_PSK, reqData, reqDataLen, &len);
+ if (pos == NULL) {
ret->ignore = TRUE;
return NULL;
}
+ len += sizeof(struct eap_hdr) + 1;
ret->ignore = FALSE;
- ret->methodState = METHOD_CONT;
+ ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
diff --git a/contrib/wpa_supplicant/eap_psk_common.c b/contrib/wpa_supplicant/eap_psk_common.c
new file mode 100644
index 0000000..24de66c
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_psk_common.c
@@ -0,0 +1,57 @@
+/*
+ * WPA Supplicant / EAP-PSK shared routines
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "aes_wrap.h"
+#include "eap_psk_common.h"
+
+#define aes_block_size 16
+
+
+void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
+{
+ memset(ak, 0, aes_block_size);
+ aes_128_encrypt_block(psk, ak, ak);
+ 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);
+ aes_128_encrypt_block(psk, kdk, kdk);
+}
+
+
+void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk)
+{
+ u8 hash[aes_block_size];
+ u8 counter = 1;
+ int i;
+
+ aes_128_encrypt_block(kdk, rand_p, hash);
+
+ hash[aes_block_size - 1] ^= counter;
+ aes_128_encrypt_block(kdk, hash, tek);
+ hash[aes_block_size - 1] ^= counter;
+ counter++;
+
+ for (i = 0; i < EAP_PSK_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++;
+ }
+}
diff --git a/contrib/wpa_supplicant/eap_psk_common.h b/contrib/wpa_supplicant/eap_psk_common.h
new file mode 100644
index 0000000..5dd3a10
--- /dev/null
+++ b/contrib/wpa_supplicant/eap_psk_common.h
@@ -0,0 +1,92 @@
+/*
+ * WPA Supplicant / EAP-PSK shared routines
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_PSK_COMMON_H
+#define EAP_PSK_COMMON_H
+
+
+#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
+
+#define EAP_PSK_R_FLAG_CONT 1
+#define EAP_PSK_R_FLAG_DONE_SUCCESS 2
+#define EAP_PSK_R_FLAG_DONE_FAILURE 3
+#define EAP_PSK_E_FLAG 0x20
+
+/* Shared prefix for all EAP-PSK frames */
+struct eap_psk_hdr {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PSK */
+ u8 flags;
+} __attribute__ ((packed));
+
+/* EAP-PSK First Message (AS -> Supplicant) */
+struct eap_psk_hdr_1 {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PSK */
+ u8 flags;
+ u8 rand_s[EAP_PSK_RAND_LEN];
+ /* Followed by variable length ID_S */
+} __attribute__ ((packed));
+
+/* EAP-PSK Second Message (Supplicant -> AS) */
+struct eap_psk_hdr_2 {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PSK */
+ u8 flags;
+ u8 rand_s[EAP_PSK_RAND_LEN];
+ u8 rand_p[EAP_PSK_RAND_LEN];
+ u8 mac_p[EAP_PSK_MAC_LEN];
+ /* Followed by variable length ID_P */
+} __attribute__ ((packed));
+
+/* EAP-PSK Third Message (AS -> Supplicant) */
+struct eap_psk_hdr_3 {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PSK */
+ u8 flags;
+ u8 rand_s[EAP_PSK_RAND_LEN];
+ u8 mac_s[EAP_PSK_MAC_LEN];
+ /* Followed by variable length PCHANNEL */
+} __attribute__ ((packed));
+
+/* EAP-PSK Fourth Message (Supplicant -> AS) */
+struct eap_psk_hdr_4 {
+ u8 code;
+ u8 identifier;
+ u16 length; /* including code, identifier, and length */
+ u8 type; /* EAP_TYPE_PSK */
+ u8 flags;
+ u8 rand_s[EAP_PSK_RAND_LEN];
+ /* Followed by variable length PCHANNEL */
+} __attribute__ ((packed));
+
+
+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);
+
+#endif /* EAP_PSK_COMMON_H */
diff --git a/contrib/wpa_supplicant/eap_sim.c b/contrib/wpa_supplicant/eap_sim.c
index f7ce191..ca9d737 100644
--- a/contrib/wpa_supplicant/eap_sim.c
+++ b/contrib/wpa_supplicant/eap_sim.c
@@ -20,7 +20,7 @@
#include "eap_i.h"
#include "wpa_supplicant.h"
#include "config_ssid.h"
-#include "sha1.h"
+#include "crypto.h"
#include "pcsc_funcs.h"
#include "eap_sim_common.h"
@@ -198,8 +198,7 @@ static void eap_sim_derive_mk(struct eap_sim_data *data,
addr[4] = sel_ver;
len[4] = 2;
- sel_ver[0] = data->selected_version >> 8;
- sel_ver[1] = data->selected_version & 0xff;
+ 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);
@@ -277,7 +276,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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen, int err)
{
struct eap_sim_msg *msg;
@@ -295,7 +294,7 @@ static u8 * eap_sim_client_error(struct eap_sm *sm, struct eap_sim_data *data,
static u8 * eap_sim_response_start(struct eap_sm *sm,
struct eap_sim_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen,
enum eap_sim_id_req id_req)
{
@@ -324,7 +323,7 @@ static u8 * eap_sim_response_start(struct eap_sm *sm,
eap_sim_clear_identities(data, CLEAR_EAP_ID);
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Start (id=%d)",
- req->identifier);
+ req->identifier);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
EAP_TYPE_SIM, EAP_SIM_SUBTYPE_START);
wpa_hexdump(MSG_DEBUG, " AT_NONCE_MT",
@@ -349,13 +348,13 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen)
{
struct eap_sim_msg *msg;
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Challenge (id=%d)",
- req->identifier);
+ req->identifier);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, req->identifier,
EAP_TYPE_SIM, EAP_SIM_SUBTYPE_CHALLENGE);
wpa_printf(MSG_DEBUG, " AT_MAC");
@@ -368,7 +367,7 @@ static u8 * eap_sim_response_challenge(struct eap_sm *sm,
static u8 * eap_sim_response_reauth(struct eap_sm *sm,
struct eap_sim_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen, int counter_too_small)
{
struct eap_sim_msg *msg;
@@ -408,7 +407,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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t *respDataLen,
u16 notification)
{
@@ -446,7 +445,7 @@ 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,
- struct eap_hdr *req, size_t reqDataLen,
+ const struct eap_hdr *req, size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
@@ -524,7 +523,8 @@ static u8 * eap_sim_process_start(struct eap_sm *sm, struct eap_sim_data *data,
static u8 * eap_sim_process_challenge(struct eap_sm *sm,
struct eap_sim_data *data,
- struct eap_hdr *req, size_t reqDataLen,
+ const struct eap_hdr *req,
+ size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
@@ -595,8 +595,9 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
"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);
- if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen, attr->mac,
- data->nonce_mt, EAP_SIM_NONCE_MT_LEN)) {
+ 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,
@@ -610,14 +611,17 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
CLEAR_EAP_ID);
if (attr->encr_data) {
- if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
- attr->encr_data_len, attr->iv, &eattr,
- 0)) {
+ u8 *decrypted;
+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv,
+ &eattr, 0);
+ if (decrypted == NULL) {
return eap_sim_client_error(
sm, data, req, respDataLen,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
eap_sim_learn_ids(data, &eattr);
+ free(decrypted);
}
if (data->state != FAILURE)
@@ -634,11 +638,12 @@ static u8 * eap_sim_process_challenge(struct eap_sm *sm,
static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t reqDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
+ u8 *decrypted;
if (attr->encr_data == NULL || attr->iv == NULL) {
wpa_printf(MSG_WARNING, "EAP-SIM: Notification message after "
@@ -646,8 +651,10 @@ static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
return -1;
}
- if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
- attr->encr_data_len, attr->iv, &eattr, 0)) {
+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr,
+ 0);
+ if (decrypted == NULL) {
wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
"data from notification message");
return -1;
@@ -657,15 +664,17 @@ static int eap_sim_process_notification_reauth(struct eap_sim_data *data,
wpa_printf(MSG_WARNING, "EAP-SIM: Counter in notification "
"message does not match with counter in reauth "
"message");
+ free(decrypted);
return -1;
}
+ free(decrypted);
return 0;
}
static int eap_sim_process_notification_auth(struct eap_sim_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t reqDataLen,
struct eap_sim_attrs *attr)
{
@@ -695,7 +704,7 @@ static int eap_sim_process_notification_auth(struct eap_sim_data *data,
static u8 * eap_sim_process_notification(struct eap_sm *sm,
struct eap_sim_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
@@ -732,12 +741,13 @@ static u8 * eap_sim_process_notification(struct eap_sm *sm,
static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
struct eap_sim_data *data,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
size_t reqDataLen,
size_t *respDataLen,
struct eap_sim_attrs *attr)
{
struct eap_sim_attrs eattr;
+ u8 *decrypted;
wpa_printf(MSG_DEBUG, "EAP-SIM: subtype Reauthentication");
@@ -749,7 +759,7 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
}
data->reauth = 1;
- if (eap_sim_verify_mac(data->k_aut, (u8 *) req, reqDataLen,
+ if (eap_sim_verify_mac(data->k_aut, (const u8 *) req, reqDataLen,
attr->mac, (u8 *) "", 0)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
"did not have valid AT_MAC");
@@ -764,8 +774,10 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
- if (eap_sim_parse_encr(data->k_encr, attr->encr_data,
- attr->encr_data_len, attr->iv, &eattr, 0)) {
+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr,
+ 0);
+ 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,
@@ -776,6 +788,7 @@ 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,
EAP_SIM_UNABLE_TO_PROCESS_PACKET);
}
@@ -794,6 +807,7 @@ static u8 * eap_sim_process_reauthentication(struct eap_sm *sm,
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);
}
data->counter = eattr.counter;
@@ -818,19 +832,21 @@ 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);
}
static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
struct eap_sim_data *data = priv;
struct wpa_ssid *config = eap_get_config(sm);
- struct eap_hdr *req;
- u8 *pos, subtype, *res;
+ const struct eap_hdr *req;
+ u8 subtype, *res;
+ const u8 *pos;
struct eap_sim_attrs attr;
size_t len;
@@ -842,21 +858,19 @@ static u8 * eap_sim_process(struct eap_sm *sm, void *priv,
return NULL;
}
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 4 || *pos != EAP_TYPE_SIM ||
- (len = be_to_host16(req->length)) > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
+ pos = eap_hdr_validate(EAP_TYPE_SIM, reqData, reqDataLen, &len);
+ if (pos == NULL || len < 1) {
ret->ignore = TRUE;
return NULL;
}
+ req = (const struct eap_hdr *) reqData;
+ len = be_to_host16(req->length);
ret->ignore = FALSE;
- ret->methodState = METHOD_CONT;
+ ret->methodState = METHOD_MAY_CONT;
ret->decision = DECISION_FAIL;
ret->allowNotifications = TRUE;
- pos++;
subtype = *pos++;
wpa_printf(MSG_DEBUG, "EAP-SIM: Subtype=%d", subtype);
pos += 2; /* Reserved */
@@ -901,7 +915,7 @@ done:
ret->decision = DECISION_FAIL;
ret->methodState = METHOD_DONE;
} else if (data->state == SUCCESS) {
- ret->decision = DECISION_UNCOND_SUCC;
+ ret->decision = DECISION_COND_SUCC;
ret->methodState = METHOD_DONE;
}
diff --git a/contrib/wpa_supplicant/eap_sim_common.c b/contrib/wpa_supplicant/eap_sim_common.c
index 98f4fb7..75947b7 100644
--- a/contrib/wpa_supplicant/eap_sim_common.c
+++ b/contrib/wpa_supplicant/eap_sim_common.c
@@ -19,14 +19,11 @@
#include "common.h"
#include "eap_i.h"
#include "sha1.h"
+#include "crypto.h"
#include "aes_wrap.h"
#include "eap_sim_common.h"
-#define MSK_LEN 8
-#define EMSK_LEN 8
-
-
static void eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
{
u8 xkey[64];
@@ -86,22 +83,17 @@ void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk)
memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
pos += EAP_SIM_K_AUT_LEN;
memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
- pos += MSK_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: MSK",
- msk, MSK_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: Ext. MSK",
- msk + MSK_LEN, EMSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material",
- msk, EAP_SIM_KEYING_DATA_LEN);
+ msk, EAP_SIM_KEYING_DATA_LEN);
}
-void eap_sim_derive_keys_reauth(unsigned int _counter,
+void eap_sim_derive_keys_reauth(u16 _counter,
const u8 *identity, size_t identity_len,
const u8 *nonce_s, const u8 *mk, u8 *msk)
{
@@ -119,8 +111,7 @@ void eap_sim_derive_keys_reauth(unsigned int _counter,
addr[3] = mk;
len[3] = EAP_SIM_MK_LEN;
- counter[0] = _counter >> 8;
- counter[1] = _counter & 0xff;
+ WPA_PUT_BE16(counter, _counter);
wpa_printf(MSG_DEBUG, "EAP-SIM: Deriving keying data from reauth");
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
@@ -135,34 +126,37 @@ void eap_sim_derive_keys_reauth(unsigned int _counter,
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: MSK", msk, MSK_LEN);
- wpa_hexdump(MSG_DEBUG, "EAP-SIM: Ext. MSK", msk + MSK_LEN, EMSK_LEN);
wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material",
msk, EAP_SIM_KEYING_DATA_LEN);
}
-int eap_sim_verify_mac(const u8 *k_aut, u8 *req, size_t req_len, u8 *mac,
- u8 *extra, size_t extra_len)
+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)
{
unsigned char hmac[SHA1_MAC_LEN];
const u8 *addr[2];
size_t len[2];
- u8 rx_mac[EAP_SIM_MAC_LEN];
+ u8 *tmp;
+
+ if (mac == NULL || req_len < EAP_SIM_MAC_LEN || mac < req ||
+ mac > req + req_len - EAP_SIM_MAC_LEN)
+ return -1;
- if (mac == NULL)
+ tmp = malloc(req_len);
+ if (tmp == NULL)
return -1;
- addr[0] = req;
+ addr[0] = tmp;
len[0] = req_len;
addr[1] = extra;
len[1] = extra_len;
/* HMAC-SHA1-128 */
- memcpy(rx_mac, mac, EAP_SIM_MAC_LEN);
- memset(mac, 0, EAP_SIM_MAC_LEN);
+ memcpy(tmp, req, req_len);
+ memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
- memcpy(mac, rx_mac, EAP_SIM_MAC_LEN);
+ free(tmp);
return (memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
}
@@ -187,10 +181,10 @@ void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
}
-int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr, int aka,
- int encr)
+int eap_sim_parse_attr(const u8 *start, const u8 *end,
+ struct eap_sim_attrs *attr, int aka, int encr)
{
- u8 *pos = start, *apos;
+ const u8 *pos = start, *apos;
size_t alen, plen;
int list_len, i;
@@ -473,25 +467,35 @@ int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr, int aka,
}
-int eap_sim_parse_encr(const u8 *k_encr, u8 *encr_data, size_t encr_data_len,
- const u8 *iv, struct eap_sim_attrs *attr, int aka)
+u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
+ size_t encr_data_len, const u8 *iv,
+ struct eap_sim_attrs *attr, int aka)
{
+ u8 *decrypted;
+
if (!iv) {
wpa_printf(MSG_INFO, "EAP-SIM: Encrypted data, but no IV");
- return -1;
+ return NULL;
}
- aes_128_cbc_decrypt(k_encr, iv, encr_data, encr_data_len);
+
+ decrypted = malloc(encr_data_len);
+ if (decrypted == NULL)
+ return NULL;
+ 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",
- encr_data, encr_data_len);
+ decrypted, encr_data_len);
- if (eap_sim_parse_attr(encr_data, encr_data + encr_data_len, attr,
+ if (eap_sim_parse_attr(decrypted, decrypted + encr_data_len, attr,
aka, 1)) {
wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
"decrypted AT_ENCR_DATA");
- return -1;
+ free(decrypted);
+ return NULL;
}
- return 0;
+ return decrypted;
}
@@ -628,8 +632,8 @@ u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
start = pos = msg->buf + msg->used;
*pos++ = attr;
*pos++ = attr_len / 4;
- *pos++ = value >> 8;
- *pos++ = value & 0xff;
+ WPA_PUT_BE16(pos, value);
+ pos += 2;
if (data)
memcpy(pos, data, len);
if (pad_len) {
@@ -709,7 +713,9 @@ int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
{
+#ifndef CONFIG_NO_STDOUT_DEBUG
const char *type = aka ? "AKA" : "SIM";
+#endif /* CONFIG_NO_STDOUT_DEBUG */
switch (notification) {
case EAP_SIM_GENERAL_FAILURE_AFTER_AUTH:
diff --git a/contrib/wpa_supplicant/eap_sim_common.h b/contrib/wpa_supplicant/eap_sim_common.h
index c89e04e..6715c36 100644
--- a/contrib/wpa_supplicant/eap_sim_common.h
+++ b/contrib/wpa_supplicant/eap_sim_common.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / EAP-SIM/AKA shared routines
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_SIM_COMMON_H
#define EAP_SIM_COMMON_H
@@ -16,11 +30,11 @@
#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(unsigned int _counter,
+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_verify_mac(const u8 *k_aut, u8 *req, size_t req_len, u8 *mac,
- u8 *extra, size_t extra_len);
+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,
const u8 *extra, size_t extra_len);
@@ -65,19 +79,20 @@ enum eap_sim_id_req {
struct eap_sim_attrs {
- u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
- u8 *next_pseudonym, *next_reauth_id;
- u8 *nonce_mt, *identity;
+ const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
+ const u8 *next_pseudonym, *next_reauth_id;
+ const u8 *nonce_mt, *identity;
size_t num_chal, version_list_len, encr_data_len;
size_t next_pseudonym_len, next_reauth_id_len, identity_len;
enum eap_sim_id_req id_req;
int notification, counter, selected_version, client_error_code;
};
-int eap_sim_parse_attr(u8 *start, u8 *end, struct eap_sim_attrs *attr,
- int aka, int encr);
-int eap_sim_parse_encr(const u8 *k_encr, u8 *encr_data, size_t encr_data_len,
- const u8 *iv, struct eap_sim_attrs *attr, int aka);
+int eap_sim_parse_attr(const u8 *start, const u8 *end,
+ struct eap_sim_attrs *attr, int aka, int encr);
+u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
+ size_t encr_data_len, const u8 *iv,
+ struct eap_sim_attrs *attr, int aka);
struct eap_sim_msg;
diff --git a/contrib/wpa_supplicant/eap_testing.txt b/contrib/wpa_supplicant/eap_testing.txt
index 03ef285..a4d1e0a 100644
--- a/contrib/wpa_supplicant/eap_testing.txt
+++ b/contrib/wpa_supplicant/eap_testing.txt
@@ -35,48 +35,50 @@ F) failed
-) server did not support
?) not tested
-hostapd --------------------------------------------------------.
-Cisco Aironet 1200 AP (local RADIUS server) ----------------. |
-Corriente Elektron -------------------------------------. | |
-Lucent NavisRadiator -------------------------------. | | |
-Interlink RAD-Series ---------------------------. | | | |
-Radiator -----------------------------------. | | | | |
-Meetinghouse Aegis ---------------------. | | | | | |
-Funk Steel-Belted ------------------. | | | | | | |
-Funk Odyssey -------------------. | | | | | | | |
-Microsoft IAS --------------. | | | | | | | | |
-FreeRADIUS -------------. | | | | | | | | | |
- | | | | | | | | | | |
+Cisco ACS ----------------------------------------------------------.
+hostapd --------------------------------------------------------. |
+Cisco Aironet 1200 AP (local RADIUS server) ----------------. | |
+Corriente Elektron -------------------------------------. | | |
+Lucent NavisRadius ---------------------------------. | | | |
+Interlink RAD-Series ---------------------------. | | | | |
+Radiator -----------------------------------. | | | | | |
+Meetinghouse Aegis ---------------------. | | | | | | |
+Funk Steel-Belted ------------------. | | | | | | | |
+Funk Odyssey -------------------. | | | | | | | | |
+Microsoft IAS --------------. | | | | | | | | | |
+FreeRADIUS -------------. | | | | | | | | | | |
+ | | | | | | | | | | | |
-EAP-MD5 + - - + + + + + - - +
-EAP-GTC + - - ? + + + + - - +
-EAP-OTP - - - - - + - - - - -
-EAP-MSCHAPv2 + - - + + + + + - - +
-EAP-TLS + + + + + + + + - - +
-EAP-PEAPv0/MSCHAPv2 + + + + + + + + + - +
-EAP-PEAPv0/GTC + - + - + + + + - - +
-EAP-PEAPv0/OTP - - - - - + - - - - -
-EAP-PEAPv0/MD5 + - - + + + + + - - +
-EAP-PEAPv0/TLS - + - + + + F + - - -
-EAP-PEAPv1/MSCHAPv2 - - + + + +1 + +5 +8 - +
-EAP-PEAPv1/GTC - - + + + +1 + +5 - - +
-EAP-PEAPv1/OTP - - - - - +1 - - - - -
-EAP-PEAPv1/MD5 - - - + + +1 + +5 - - +
-EAP-PEAPv1/TLS - - - + + +1 F +5 - - -
-EAP-TTLS/CHAP + - +2 + + + + + + - +
-EAP-TTLS/MSCHAP + - + + + + + + + - +
-EAP-TTLS/MSCHAPv2 + - + + + + + + + - +
-EAP-TTLS/PAP + - + + + + + + + - +
-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-PSK +7 - - - - - - - - - -
-EAP-FAST - - - - - - - - - + -
-LEAP + - + + + + F +6 - + -
+EAP-MD5 + - - + + + + + - - + +
+EAP-GTC + - - ? + + + + - - + -
+EAP-OTP - - - - - + - - - - - -
+EAP-MSCHAPv2 + - - + + + + + - - + -
+EAP-TLS + + + + + + + + - - + +
+EAP-PEAPv0/MSCHAPv2 + + + + + + + + + - + +
+EAP-PEAPv0/GTC + - + - + + + + - - + +
+EAP-PEAPv0/OTP - - - - - + - - - - - -
+EAP-PEAPv0/MD5 + - - + + + + + - - + -
+EAP-PEAPv0/TLS - + - + + + F + - - - -
+EAP-PEAPv1/MSCHAPv2 - - + + + +1 + +5 +8 - + +
+EAP-PEAPv1/GTC - - + + + +1 + +5 - - + +
+EAP-PEAPv1/OTP - - - - - +1 - - - - - -
+EAP-PEAPv1/MD5 - - - + + +1 + +5 - - + -
+EAP-PEAPv1/TLS - - - + + +1 F +5 - - - -
+EAP-TTLS/CHAP + - +2 + + + + + + - + -
+EAP-TTLS/MSCHAP + - + + + + + + + - + -
+EAP-TTLS/MSCHAPv2 + - + + + + + + + - + -
+EAP-TTLS/PAP + - + + + + + + + - + -
+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-PSK +7 - - - - - - - - - + -
+EAP-PAX - - - - - - - - - - + -
+EAP-FAST - - - - - - - - - + - +
+LEAP + - + + + + F +6 - + - +
1) PEAPv1 required new label, "client PEAP encryption" instead of "client EAP
encryption", during key derivation (requires phase1="peaplabel=1" in the
@@ -309,7 +311,13 @@ hostapd v0.3.3
- EAP-TTLS / EAP-GTC
- EAP-TTLS / EAP-MSCHAPv2
- EAP-SIM
+- EAP-PAX
+Cisco Secure ACS 3.3(1) for Windows Server
+- PEAPv1/GTC worked, but PEAPv0/GTC failed in the end after password was
+ sent successfully; ACS is replying with empty PEAP packet (TLS ACK);
+ wpa_supplicant tries to decrypt this.. Replying with TLS ACK and and
+ marking the connection completed was enough to make this work.
PEAPv1:
diff --git a/contrib/wpa_supplicant/eap_tls.c b/contrib/wpa_supplicant/eap_tls.c
index 4b02cca..d1452df 100644
--- a/contrib/wpa_supplicant/eap_tls.c
+++ b/contrib/wpa_supplicant/eap_tls.c
@@ -38,8 +38,8 @@ static void * eap_tls_init(struct eap_sm *sm)
struct eap_tls_data *data;
struct wpa_ssid *config = eap_get_config(sm);
if (config == NULL ||
- (sm->init_phase2 ? config->private_key2 : config->private_key)
- == NULL) {
+ ((sm->init_phase2 ? config->private_key2 : config->private_key)
+ == NULL && config->engine == 0)) {
wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
return NULL;
}
@@ -52,6 +52,18 @@ static void * eap_tls_init(struct eap_sm *sm)
if (eap_tls_ssl_init(sm, &data->ssl, config)) {
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
eap_tls_deinit(sm, data);
+ if (config->engine) {
+ wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
+ "PIN");
+ eap_sm_request_pin(sm, config);
+ 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);
+ sm->ignore = TRUE;
+ }
return NULL;
}
@@ -72,61 +84,23 @@ static void eap_tls_deinit(struct eap_sm *sm, void *priv)
static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct eap_hdr *req;
- int left, res;
- unsigned int tls_msg_len;
- u8 flags, *pos, *resp, id;
+ struct wpa_ssid *config = eap_get_config(sm);
+ const struct eap_hdr *req;
+ size_t left;
+ int res;
+ u8 flags, *resp, id;
+ const u8 *pos;
struct eap_tls_data *data = priv;
- if (tls_get_errors(sm->ssl_ctx)) {
- wpa_printf(MSG_INFO, "EAP-TLS: TLS errors detected");
- ret->ignore = TRUE;
- return NULL;
- }
-
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_TLS) {
- wpa_printf(MSG_INFO, "EAP-TLS: Invalid frame");
- ret->ignore = TRUE;
+ pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_TLS, ret,
+ reqData, reqDataLen, &left, &flags);
+ if (pos == NULL)
return NULL;
- }
+ req = (const struct eap_hdr *) reqData;
id = req->identifier;
- pos++;
- flags = *pos++;
- left = be_to_host16(req->length) - sizeof(struct eap_hdr) - 2;
- wpa_printf(MSG_DEBUG, "EAP-TLS: Received packet(len=%lu) - "
- "Flags 0x%02x", (unsigned long) reqDataLen, flags);
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-TLS: Short frame with TLS "
- "length");
- ret->ignore = TRUE;
- return NULL;
- }
- tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
- pos[3];
- wpa_printf(MSG_DEBUG, "EAP-TLS: TLS Message Length: %d",
- tls_msg_len);
- if (data->ssl.tls_in_left == 0) {
- data->ssl.tls_in_total = tls_msg_len;
- data->ssl.tls_in_left = tls_msg_len;
- free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
-
- ret->ignore = FALSE;
-
- ret->methodState = METHOD_CONT;
- ret->decision = DECISION_COND_SUCC;
- ret->allowNotifications = TRUE;
if (flags & EAP_TLS_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
@@ -142,6 +116,11 @@ static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
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);
}
@@ -166,6 +145,16 @@ static u8 * eap_tls_process(struct eap_sm *sm, void *priv,
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;
}
diff --git a/contrib/wpa_supplicant/eap_tls_common.c b/contrib/wpa_supplicant/eap_tls_common.c
index a56538c..cb3fb28 100644
--- a/contrib/wpa_supplicant/eap_tls_common.c
+++ b/contrib/wpa_supplicant/eap_tls_common.c
@@ -24,69 +24,108 @@
#include "md5.h"
#include "sha1.h"
#include "tls.h"
+#include "config.h"
+
+
+static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
+ const u8 **data, size_t *data_len)
+{
+ const struct wpa_config_blob *blob;
+
+ if (*name == NULL || strncmp(*name, "blob://", 7) != 0)
+ return 0;
+
+ blob = eap_get_config_blob(sm, *name + 7);
+ if (blob == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
+ "found", __func__, *name + 7);
+ return -1;
+ }
+
+ *name = NULL;
+ *data = blob->data;
+ *data_len = blob->len;
+
+ return 0;
+}
int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
struct wpa_ssid *config)
{
- int ret = -1;
- char *ca_cert, *client_cert, *private_key, *private_key_passwd,
- *dh_file, *subject_match;
+ int ret = -1, res;
+ struct tls_connection_params params;
data->eap = sm;
data->phase2 = sm->init_phase2;
+ memset(&params, 0, sizeof(params));
+ params.engine = config->engine;
if (config == NULL) {
- ca_cert = NULL;
- client_cert = NULL;
- private_key = NULL;
- private_key_passwd = NULL;
- dh_file = NULL;
- subject_match = NULL;
} else if (data->phase2) {
- ca_cert = (char *) config->ca_cert2;
- client_cert = (char *) config->client_cert2;
- private_key = (char *) config->private_key2;
- private_key_passwd = (char *) config->private_key2_passwd;
- dh_file = (char *) config->dh_file2;
- subject_match = (char *) config->subject_match2;
+ 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 {
- ca_cert = (char *) config->ca_cert;
- client_cert = (char *) config->client_cert;
- private_key = (char *) config->private_key;
- private_key_passwd = (char *) config->private_key_passwd;
- dh_file = (char *) config->dh_file;
- subject_match = (char *) config->subject_match;
- }
- 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;
+ 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 (tls_connection_ca_cert(sm->ssl_ctx, data->conn, ca_cert,
- subject_match)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load root certificate "
- "'%s'", ca_cert);
+ 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;
}
- if (tls_connection_client_cert(sm->ssl_ctx, data->conn, client_cert)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load client certificate "
- "'%s'", client_cert);
+ 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;
}
- if (tls_connection_private_key(sm->ssl_ctx, data->conn, private_key,
- private_key_passwd)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
- private_key);
+ 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);
+ config->pin = NULL;
+ } else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
+ 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);
+ config->pin = NULL;
+ eap_sm_request_pin(sm, config);
+ sm->ignore = TRUE;
goto done;
- }
-
- if (dh_file && tls_connection_dh(sm->ssl_ctx, data->conn, dh_file)) {
- wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
- dh_file);
+ } else if (res) {
+ wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
+ "parameters");
goto done;
}
@@ -126,93 +165,131 @@ u8 * eap_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
char *label, size_t len)
{
struct tls_keys keys;
- u8 *random;
+ u8 *rnd;
u8 *out;
if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
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);
+ return out;
+ }
+
+ if (keys.client_random == NULL || keys.server_random == NULL ||
+ keys.master_key == NULL)
+ return NULL;
+
out = malloc(len);
- random = malloc(keys.client_random_len + keys.server_random_len);
- if (out == NULL || random == NULL) {
+ rnd = malloc(keys.client_random_len + keys.server_random_len);
+ if (out == NULL || rnd == NULL) {
free(out);
- free(random);
+ free(rnd);
return NULL;
}
- memcpy(random, keys.client_random, keys.client_random_len);
- memcpy(random + keys.client_random_len, keys.server_random,
+ memcpy(rnd, keys.client_random, keys.client_random_len);
+ memcpy(rnd + keys.client_random_len, keys.server_random,
keys.server_random_len);
if (tls_prf(keys.master_key, keys.master_key_len,
- label, random, keys.client_random_len +
+ label, rnd, keys.client_random_len +
keys.server_random_len, out, len)) {
- free(random);
+ free(rnd);
free(out);
return NULL;
}
- free(random);
+ free(rnd);
return out;
}
-int eap_tls_data_reassemble(struct eap_sm *sm, struct eap_ssl_data *data,
- u8 **in_data, size_t *in_len)
+/**
+ * eap_tls_data_reassemble - Reassemble TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @data: Data for TLS processing
+ * @in_data: Next incoming TLS segment
+ * @in_len: Length of in_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
+ *
+ * This function reassembles TLS fragments.
+ */
+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)
{
u8 *buf;
- if (data->tls_in_left > *in_len || data->tls_in) {
- if (data->tls_in_len + *in_len == 0) {
+ *need_more_input = 0;
+
+ if (data->tls_in_left > in_len || data->tls_in) {
+ if (data->tls_in_len + in_len == 0) {
free(data->tls_in);
data->tls_in = NULL;
data->tls_in_len = 0;
wpa_printf(MSG_WARNING, "SSL: Invalid reassembly "
- "state: tls_in_left=%d tls_in_len=%d "
- "*in_len=%d",
- data->tls_in_left, data->tls_in_len,
- *in_len);
- return -1;
+ "state: tls_in_left=%lu tls_in_len=%lu "
+ "in_len=%lu",
+ (unsigned long) data->tls_in_left,
+ (unsigned long) data->tls_in_len,
+ (unsigned long) in_len);
+ return NULL;
}
- buf = realloc(data->tls_in, data->tls_in_len + *in_len);
+ buf = realloc(data->tls_in, data->tls_in_len + in_len);
if (buf == NULL) {
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 -1;
+ return NULL;
}
- memcpy(buf + data->tls_in_len, *in_data, *in_len);
+ 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) {
+ data->tls_in_len += in_len;
+ if (in_len > data->tls_in_left) {
wpa_printf(MSG_INFO, "SSL: more data than TLS message "
"length indicated");
data->tls_in_left = 0;
- return -1;
+ return NULL;
}
- data->tls_in_left -= *in_len;
+ data->tls_in_left -= in_len;
if (data->tls_in_left > 0) {
wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
"data", (unsigned long) data->tls_in_left);
- return 1;
+ *need_more_input = 1;
+ return NULL;
}
-
- *in_data = data->tls_in;
- *in_len = data->tls_in_len;
- } else
+ } else {
data->tls_in_left = 0;
+ data->tls_in = malloc(in_len);
+ if (data->tls_in == NULL)
+ return NULL;
+ memcpy(data->tls_in, in_data, in_len);
+ data->tls_in_len = in_len;
+ }
- return 0;
+ *out_len = data->tls_in_len;
+ return data->tls_in;
}
int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
int eap_type, int peap_version,
- u8 id, u8 *in_data, size_t in_len,
+ 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;
@@ -220,9 +297,15 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
if (data->tls_out_len == 0) {
/* No more data to send out - expect to receive more data from
* the AS. */
- int res = eap_tls_data_reassemble(sm, data, &in_data, &in_len);
- if (res < 0 || res == 1)
- return res;
+ 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) {
@@ -235,7 +318,7 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
}
data->tls_out = tls_connection_handshake(sm->ssl_ctx,
data->conn,
- in_data, in_len,
+ msg, msg_len,
&data->tls_out_len);
/* Clear reassembled input data (if the buffer was needed). */
@@ -248,6 +331,13 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
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");
+ ret = -1;
+ /* TODO: clean pin if engine used? */
+ }
+
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
@@ -303,7 +393,7 @@ int eap_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
data->tls_out = NULL;
}
- return 0;
+ return ret;
}
@@ -330,6 +420,13 @@ u8 * eap_tls_build_ack(struct eap_ssl_data *data, size_t *respDataLen, u8 id,
int eap_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
{
+ 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);
+ data->tls_out = NULL;
+ data->tls_out_len = data->tls_out_pos = 0;
+
return tls_connection_shutdown(sm->ssl_ctx, data->conn);
}
@@ -347,3 +444,61 @@ int eap_tls_status(struct eap_sm *sm, struct eap_ssl_data *data, char *buf,
return len;
}
+
+
+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;
+
+ if (tls_get_errors(sm->ssl_ctx)) {
+ wpa_printf(MSG_INFO, "SSL: TLS errors detected");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+
+ pos = eap_hdr_validate(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) - "
+ "Flags 0x%02x", (unsigned long) reqDataLen, *flags);
+ if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+ if (left < 4) {
+ wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
+ "length");
+ ret->ignore = TRUE;
+ return NULL;
+ }
+ tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
+ pos[3];
+ 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);
+ data->tls_in = NULL;
+ data->tls_in_len = 0;
+ }
+ pos += 4;
+ left -= 4;
+ }
+
+ ret->ignore = FALSE;
+ ret->methodState = METHOD_MAY_CONT;
+ ret->decision = DECISION_FAIL;
+ ret->allowNotifications = TRUE;
+
+ *len = (size_t) left;
+ return pos;
+}
diff --git a/contrib/wpa_supplicant/eap_tls_common.h b/contrib/wpa_supplicant/eap_tls_common.h
index 499cae4..d1dfff5 100644
--- a/contrib/wpa_supplicant/eap_tls_common.h
+++ b/contrib/wpa_supplicant/eap_tls_common.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_TLS_COMMON_H
#define EAP_TLS_COMMON_H
@@ -36,16 +50,21 @@ int eap_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
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);
-int eap_tls_data_reassemble(struct eap_sm *sm, struct eap_ssl_data *data,
- u8 **in_data, size_t *in_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,
- u8 id, u8 *in_data, size_t in_len,
+ 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);
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);
+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);
#endif /* EAP_TLS_COMMON_H */
diff --git a/contrib/wpa_supplicant/eap_tlv.c b/contrib/wpa_supplicant/eap_tlv.c
index 5571d8b..4070c6f 100644
--- a/contrib/wpa_supplicant/eap_tlv.c
+++ b/contrib/wpa_supplicant/eap_tlv.c
@@ -22,7 +22,7 @@
#include "eap_tlv.h"
-u8 * eap_tlv_build_nak(int id, int nak_type, size_t *resp_len)
+u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len)
{
struct eap_hdr *hdr;
u8 *pos;
@@ -48,14 +48,13 @@ u8 * eap_tlv_build_nak(int id, int nak_type, size_t *resp_len)
*pos++ = 0;
*pos++ = 0;
/* NAK-Type */
- *pos++ = nak_type >> 8;
- *pos++ = nak_type & 0xff;
+ WPA_PUT_BE16(pos, nak_type);
return (u8 *) hdr;
}
-u8 * eap_tlv_build_result(int id, int status, size_t *resp_len)
+u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len)
{
struct eap_hdr *hdr;
u8 *pos;
@@ -76,33 +75,32 @@ u8 * eap_tlv_build_result(int id, int status, size_t *resp_len)
*pos++ = 0;
*pos++ = 2;
/* Status */
- *pos++ = status >> 8;
- *pos++ = status & 0xff;
+ WPA_PUT_BE16(pos, status);
return (u8 *) hdr;
}
int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
- struct eap_hdr *hdr, u8 **resp, size_t *resp_len)
+ const struct eap_hdr *hdr, u8 **resp, size_t *resp_len)
{
size_t left;
- u8 *pos;
- u8 *result_tlv = NULL;
+ const u8 *pos;
+ const u8 *result_tlv = NULL;
size_t result_tlv_len = 0;
int tlv_type, mandatory, tlv_len;
/* Parse TLVs */
left = be_to_host16(hdr->length) - sizeof(struct eap_hdr) - 1;
- pos = (u8 *) (hdr + 1);
+ pos = (const u8 *) (hdr + 1);
pos++;
wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
while (left >= 4) {
mandatory = !!(pos[0] & 0x80);
- tlv_type = pos[0] & 0x3f;
- tlv_type = (tlv_type << 8) | pos[1];
- tlv_len = ((int) pos[2] << 8) | pos[3];
- pos += 4;
+ tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+ pos += 2;
+ tlv_len = WPA_GET_BE16(pos);
+ pos += 2;
left -= 4;
if (tlv_len > left) {
wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
@@ -150,7 +148,7 @@ int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
(unsigned long) result_tlv_len);
return -1;
}
- status = ((int) result_tlv[0] << 8) | result_tlv[1];
+ status = WPA_GET_BE16(result_tlv);
if (status == EAP_TLV_RESULT_SUCCESS) {
wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
"- EAP-TLV/Phase2 Completed");
diff --git a/contrib/wpa_supplicant/eap_tlv.h b/contrib/wpa_supplicant/eap_tlv.h
index 4391552..6a5afe0 100644
--- a/contrib/wpa_supplicant/eap_tlv.h
+++ b/contrib/wpa_supplicant/eap_tlv.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / EAP-TLV (draft-josefsson-pppext-eap-tls-eap-07.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_TLV_H
#define EAP_TLV_H
@@ -65,9 +79,9 @@ struct eap_tlv_pac_ack_tlv {
#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
-u8 * eap_tlv_build_nak(int id, int nak_type, size_t *resp_len);
-u8 * eap_tlv_build_result(int id, int status, size_t *resp_len);
+u8 * eap_tlv_build_nak(int id, u16 nak_type, size_t *resp_len);
+u8 * eap_tlv_build_result(int id, u16 status, size_t *resp_len);
int eap_tlv_process(struct eap_sm *sm, struct eap_method_ret *ret,
- struct eap_hdr *hdr, u8 **resp, size_t *resp_len);
+ const struct eap_hdr *hdr, u8 **resp, size_t *resp_len);
#endif /* EAP_TLV_H */
diff --git a/contrib/wpa_supplicant/eap_ttls.c b/contrib/wpa_supplicant/eap_ttls.c
index 733f136..0b1ff8f 100644
--- a/contrib/wpa_supplicant/eap_ttls.c
+++ b/contrib/wpa_supplicant/eap_ttls.c
@@ -22,7 +22,7 @@
#include "wpa_supplicant.h"
#include "config_ssid.h"
#include "ms_funcs.h"
-#include "md5.h"
+#include "crypto.h"
#include "tls.h"
#include "eap_ttls.h"
@@ -183,7 +183,7 @@ static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
static int eap_ttls_encrypt(struct eap_sm *sm, struct eap_ttls_data *data,
- int id, u8 *plain, size_t plain_len,
+ int id, const u8 *plain, size_t plain_len,
u8 **out_data, size_t *out_len)
{
int res;
@@ -312,7 +312,7 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -400,7 +400,7 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -506,7 +506,7 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -576,7 +576,7 @@ 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,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -624,13 +624,14 @@ 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,
- struct eap_hdr *req,
+ 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;
- MD5_CTX context;
+ const u8 *addr[3];
+ size_t len[3];
wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
@@ -665,11 +666,13 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
*pos++ = data->ident;
/* MD5(Ident + Password + Challenge) */
- MD5Init(&context);
- MD5Update(&context, &data->ident, 1);
- MD5Update(&context, config->password, config->password_len);
- MD5Update(&context, challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
- MD5Final(pos, &context);
+ addr[0] = &data->ident;
+ len[0] = 1;
+ addr[1] = config->password;
+ len[1] = config->password_len;
+ addr[2] = challenge;
+ len[2] = EAP_TTLS_CHAP_CHALLENGE_LEN;
+ md5_vector(3, addr, len, pos);
wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
config->identity, config->identity_len);
@@ -698,7 +701,7 @@ static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
static int eap_ttls_phase2_request(struct eap_sm *sm,
struct eap_ttls_data *data,
struct eap_method_ret *ret,
- struct eap_hdr *req,
+ const struct eap_hdr *req,
struct eap_hdr *hdr,
u8 **resp, size_t *resp_len)
{
@@ -763,12 +766,13 @@ static int eap_ttls_phase2_request(struct eap_sm *sm,
static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
- struct eap_method_ret *ret, struct eap_hdr *req,
- u8 *in_data, size_t in_len,
+ struct eap_method_ret *ret,
+ const struct eap_hdr *req,
+ const u8 *in_data, size_t in_len,
u8 **out_data, size_t *out_len)
{
u8 *in_decrypted = NULL, *pos;
- int buf_len, len_decrypted = 0, len, left, retval = 0, res;
+ int buf_len, len_decrypted = 0, len, left, retval = 0;
struct eap_hdr *hdr = NULL;
u8 *resp = NULL, *mschapv2 = NULL, *eapdata = NULL;
size_t resp_len, eap_len = 0;
@@ -776,6 +780,9 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
u8 recv_response[20];
int mschapv2_error = 0;
struct wpa_ssid *config = eap_get_config(sm);
+ const u8 *msg;
+ size_t msg_len;
+ int need_more_input;
wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -839,11 +846,10 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
goto process_eap;
}
- res = eap_tls_data_reassemble(sm, &data->ssl, &in_data, &in_len);
- if (res < 0 || res == 1) {
- retval = res;
- goto done;
- }
+ msg = eap_tls_data_reassemble(sm, &data->ssl, in_data, in_len,
+ &msg_len, &need_more_input);
+ if (msg == NULL)
+ return need_more_input ? 1 : -1;
buf_len = in_len;
if (data->ssl.tls_in_total > buf_len)
@@ -860,7 +866,7 @@ static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
}
len_decrypted = tls_connection_decrypt(sm->ssl_ctx, data->ssl.conn,
- in_data, in_len,
+ msg, msg_len,
in_decrypted, buf_len);
free(data->ssl.tls_in);
data->ssl.tls_in = NULL;
@@ -1117,7 +1123,8 @@ continue_req:
free(resp);
} else if (config->pending_req_identity ||
config->pending_req_password ||
- config->pending_req_otp) {
+ config->pending_req_otp ||
+ config->pending_req_new_password) {
free(data->pending_phase2_req);
data->pending_phase2_req = malloc(len_decrypted);
if (data->pending_phase2_req) {
@@ -1142,62 +1149,22 @@ done:
static u8 * eap_ttls_process(struct eap_sm *sm, void *priv,
struct eap_method_ret *ret,
- u8 *reqData, size_t reqDataLen,
+ const u8 *reqData, size_t reqDataLen,
size_t *respDataLen)
{
- struct eap_hdr *req;
- int left, res;
- unsigned int tls_msg_len;
- u8 flags, *pos, *resp, id;
+ const struct eap_hdr *req;
+ size_t left;
+ int res;
+ u8 flags, *resp, id;
+ const u8 *pos;
struct eap_ttls_data *data = priv;
- if (tls_get_errors(sm->ssl_ctx)) {
- wpa_printf(MSG_INFO, "EAP-TTLS: TLS errors detected");
- ret->ignore = TRUE;
- return NULL;
- }
-
- req = (struct eap_hdr *) reqData;
- pos = (u8 *) (req + 1);
- if (reqDataLen < sizeof(*req) + 2 || *pos != EAP_TYPE_TTLS ||
- (left = be_to_host16(req->length)) > reqDataLen) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Invalid frame");
- ret->ignore = TRUE;
+ pos = eap_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret,
+ reqData, reqDataLen, &left, &flags);
+ if (pos == NULL)
return NULL;
- }
- left -= sizeof(struct eap_hdr);
+ req = (const struct eap_hdr *) reqData;
id = req->identifier;
- pos++;
- flags = *pos++;
- left -= 2;
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Received packet(len=%lu) - "
- "Flags 0x%02x", (unsigned long) reqDataLen, flags);
- if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
- if (left < 4) {
- wpa_printf(MSG_INFO, "EAP-TTLS: Short frame with TLS "
- "length");
- ret->ignore = TRUE;
- return NULL;
- }
- tls_msg_len = (pos[0] << 24) | (pos[1] << 16) | (pos[2] << 8) |
- pos[3];
- wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS Message Length: %d",
- tls_msg_len);
- if (data->ssl.tls_in_left == 0) {
- data->ssl.tls_in_total = tls_msg_len;
- data->ssl.tls_in_left = tls_msg_len;
- free(data->ssl.tls_in);
- data->ssl.tls_in = NULL;
- data->ssl.tls_in_len = 0;
- }
- pos += 4;
- left -= 4;
- }
-
- ret->ignore = FALSE;
- ret->methodState = METHOD_CONT;
- ret->decision = DECISION_FAIL;
- ret->allowNotifications = TRUE;
if (flags & EAP_TLS_FLAGS_START) {
wpa_printf(MSG_DEBUG, "EAP-TTLS: Start");
diff --git a/contrib/wpa_supplicant/eap_ttls.h b/contrib/wpa_supplicant/eap_ttls.h
index a187db4..f35f5a9 100644
--- a/contrib/wpa_supplicant/eap_ttls.h
+++ b/contrib/wpa_supplicant/eap_ttls.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / EAP-TTLS (draft-ietf-pppext-eap-ttls-03.txt)
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_TTLS_H
#define EAP_TTLS_H
diff --git a/contrib/wpa_supplicant/eapol_sm.c b/contrib/wpa_supplicant/eapol_sm.c
index 1424b7d..95a6031 100644
--- a/contrib/wpa_supplicant/eapol_sm.c
+++ b/contrib/wpa_supplicant/eapol_sm.c
@@ -20,15 +20,17 @@
#include "eapol_sm.h"
#include "eap.h"
#include "eloop.h"
-#include "wpa_supplicant.h"
#include "l2_packet.h"
#include "wpa.h"
#include "md5.h"
#include "rc4.h"
-/* IEEE 802.1aa/D6.1 - Supplicant */
+/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
+/**
+ * struct eapol_sm - Internal data for EAPOL state machines
+ */
struct eapol_sm {
/* Timers */
unsigned int authWhile;
@@ -118,7 +120,7 @@ struct eapol_sm {
unsigned int dot1xSuppLastEapolFrameVersion;
unsigned char dot1xSuppLastEapolFrameSource[6];
- /* Miscellaneous variables (not defined in IEEE 802.1aa/D6.1) */
+ /* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
Boolean changed;
struct eap_sm *eap;
struct wpa_ssid *config;
@@ -141,6 +143,38 @@ struct eapol_sm {
};
+#define IEEE8021X_REPLAY_COUNTER_LEN 8
+#define IEEE8021X_KEY_SIGN_LEN 16
+#define IEEE8021X_KEY_IV_LEN 16
+
+#define IEEE8021X_KEY_INDEX_FLAG 0x80
+#define IEEE8021X_KEY_INDEX_MASK 0x03
+
+struct ieee802_1x_eapol_key {
+ u8 type;
+ /* Note: key_length is unaligned */
+ u8 key_length[2];
+ /* does not repeat within the life of the keying material used to
+ * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
+ u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
+ u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
+ u8 key_index; /* key flag in the most significant bit:
+ * 0 = broadcast (default key),
+ * 1 = unicast (key mapping key); key index is in the
+ * 7 least significant bits */
+ /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
+ * the key */
+ u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
+
+ /* followed by key: if packet body length = 44 + key length, then the
+ * key field (of key_length bytes) contains the key in encrypted form;
+ * if packet body length = 44, key field is absent and key_length
+ * 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));
+
+
static void eapol_sm_txLogoff(struct eapol_sm *sm);
static void eapol_sm_txStart(struct eapol_sm *sm);
static void eapol_sm_processKey(struct eapol_sm *sm);
@@ -150,8 +184,6 @@ static void eapol_sm_abortSupp(struct eapol_sm *sm);
static void eapol_sm_abort_cached(struct eapol_sm *sm);
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
-static struct eapol_callbacks eapol_cb;
-
/* Definitions for clarifying state machine implementation */
#define SM_STATE(machine, state) \
@@ -182,17 +214,26 @@ static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
{
struct eapol_sm *sm = timeout_ctx;
- if (sm->authWhile > 0)
+ if (sm->authWhile > 0) {
sm->authWhile--;
- if (sm->heldWhile > 0)
+ if (sm->authWhile == 0)
+ wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
+ }
+ if (sm->heldWhile > 0) {
sm->heldWhile--;
- if (sm->startWhen > 0)
+ if (sm->heldWhile == 0)
+ wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
+ }
+ if (sm->startWhen > 0) {
sm->startWhen--;
- if (sm->idleWhile > 0)
+ if (sm->startWhen == 0)
+ wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
+ }
+ if (sm->idleWhile > 0) {
sm->idleWhile--;
- wpa_printf(MSG_MSGDUMP, "EAPOL: Port Timers tick - authWhile=%d "
- "heldWhile=%d startWhen=%d idleWhile=%d",
- sm->authWhile, sm->heldWhile, sm->startWhen, sm->idleWhile);
+ if (sm->idleWhile == 0)
+ wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
+ }
eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, sm);
eapol_sm_step(sm);
@@ -224,11 +265,24 @@ SM_STATE(SUPP_PAE, DISCONNECTED)
SM_STATE(SUPP_PAE, CONNECTING)
{
+ int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
SM_ENTRY(SUPP_PAE, CONNECTING);
- sm->startWhen = sm->startPeriod;
- sm->startCount++;
+ if (send_start) {
+ sm->startWhen = sm->startPeriod;
+ sm->startCount++;
+ } else {
+ /*
+ * Do not send EAPOL-Start immediately since in most cases,
+ * Authenticator is going to start authentication immediately
+ * after association and an extra EAPOL-Start is just going to
+ * delay authentication. Use a short timeout to send the first
+ * EAPOL-Start if Authenticator does not start authentication.
+ */
+ sm->startWhen = 3;
+ }
sm->eapolEap = FALSE;
- eapol_sm_txStart(sm);
+ if (send_start)
+ eapol_sm_txStart(sm);
}
@@ -532,8 +586,8 @@ SM_STEP(SUPP_BE)
static void eapol_sm_txLogoff(struct eapol_sm *sm)
{
wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
- sm->ctx->eapol_send(sm->ctx->ctx, IEEE802_1X_TYPE_EAPOL_LOGOFF,
- (u8 *) "", 0);
+ sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
+ IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
sm->dot1xSuppEapolLogoffFramesTx++;
sm->dot1xSuppEapolFramesTx++;
}
@@ -542,8 +596,8 @@ static void eapol_sm_txLogoff(struct eapol_sm *sm)
static void eapol_sm_txStart(struct eapol_sm *sm)
{
wpa_printf(MSG_DEBUG, "EAPOL: txStart");
- sm->ctx->eapol_send(sm->ctx->ctx, IEEE802_1X_TYPE_EAPOL_START,
- (u8 *) "", 0);
+ sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
+ IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
sm->dot1xSuppEapolStartFramesTx++;
sm->dot1xSuppEapolFramesTx++;
}
@@ -566,6 +620,7 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
int key_len, res, sign_key_len, encr_key_len;
+ u16 rx_key_length;
wpa_printf(MSG_DEBUG, "EAPOL: processKey");
if (sm->last_rx_key == NULL)
@@ -584,11 +639,13 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
return;
}
+ rx_key_length = WPA_GET_BE16(key->key_length);
wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
"EAPOL-Key: type=%d key_length=%d key_index=0x%x",
hdr->version, hdr->type, be_to_host16(hdr->length),
- key->type, be_to_host16(key->key_length), key->key_index);
+ key->type, rx_key_length, key->key_index);
+ eapol_sm_notify_lower_layer_success(sm);
sign_key_len = IEEE8021X_SIGN_KEY_LEN;
encr_key_len = IEEE8021X_ENCR_KEY_LEN;
res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
@@ -645,12 +702,12 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
key_len = be_to_host16(hdr->length) - sizeof(*key);
- if (key_len > 32 || be_to_host16(key->key_length) > 32) {
+ if (key_len > 32 || rx_key_length > 32) {
wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
- key_len ? key_len : be_to_host16(key->key_length));
+ key_len ? key_len : rx_key_length);
return;
}
- if (key_len == be_to_host16(key->key_length)) {
+ 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);
@@ -660,22 +717,23 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
datakey, key_len);
} else if (key_len == 0) {
- /* IEEE 802.1X-REV specifies that least significant Key Length
+ /*
+ * IEEE 802.1X-2004 specifies that least significant Key Length
* octets from MS-MPPE-Send-Key are used as the key if the key
* data is not present. This seems to be meaning the beginning
* of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
* Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
* Anyway, taking the beginning of the keying material from EAP
- * seems to interoperate with Authenticators. */
- key_len = be_to_host16(key->key_length);
+ * seems to interoperate with Authenticators.
+ */
+ key_len = rx_key_length;
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);
} else {
wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
- "(key_length=%d)", key_len,
- be_to_host16(key->key_length));
+ "(key_length=%d)", key_len, rx_key_length);
return;
}
@@ -741,8 +799,8 @@ static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
}
/* Send EAP-Packet from the EAP layer to the Authenticator */
- sm->ctx->eapol_send(sm->ctx->ctx, IEEE802_1X_TYPE_EAP_PACKET,
- resp, resp_len);
+ sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
+ IEEE802_1X_TYPE_EAP_PACKET, resp, resp_len);
/* eapRespData is not used anymore, so free it here */
free(resp);
@@ -768,63 +826,20 @@ static void eapol_sm_abortSupp(struct eapol_sm *sm)
}
-struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
-{
- struct eapol_sm *sm;
- sm = malloc(sizeof(*sm));
- if (sm == NULL)
- return NULL;
- memset(sm, 0, sizeof(*sm));
- sm->ctx = ctx;
-
- sm->portControl = Auto;
-
- /* Supplicant PAE state machine */
- sm->heldPeriod = 60;
- sm->startPeriod = 30;
- sm->maxStart = 3;
-
- /* Supplicant Backend state machine */
- sm->authPeriod = 30;
-
- sm->eap = eap_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx);
- if (sm->eap == NULL) {
- free(sm);
- return NULL;
- }
-
- /* Initialize EAPOL state machines */
- sm->initialize = TRUE;
- eapol_sm_step(sm);
- sm->initialize = FALSE;
- eapol_sm_step(sm);
-
- eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
-
- return sm;
-}
-
-
-void eapol_sm_deinit(struct eapol_sm *sm)
-{
- if (sm == NULL)
- return;
- 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);
-}
-
-
static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
{
eapol_sm_step(timeout_ctx);
}
+/**
+ * eapol_sm_step - EAPOL state machine step function
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * This function is called to notify the state machine about changed external
+ * variables. It will step through the EAPOL state machines in loop to process
+ * all triggered state changes.
+ */
void eapol_sm_step(struct eapol_sm *sm)
{
int i;
@@ -929,6 +944,17 @@ static const char * eapol_port_control(PortControl ctrl)
}
+/**
+ * eapol_sm_configure - Set EAPOL variables
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @heldPeriod: dot1xSuppHeldPeriod
+ * @authPeriod: dot1xSuppAuthPeriod
+ * @startPeriod: dot1xSuppStartPeriod
+ * @maxStart: dot1xSuppMaxStart
+ *
+ * Set configurable EAPOL state machine variables. Each variable can be set to
+ * the given value or ignored if set to -1 (to set only some of the variables).
+ */
void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
int startPeriod, int maxStart)
{
@@ -945,6 +971,19 @@ void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
}
+/**
+ * eapol_sm_get_status - Get EAPOL state machine status
+ * @sm: Pointer to EAPOL state machine allocated with eapol_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.
+ *
+ * Query EAPOL state machine for status information. This function fills in a
+ * text area with current status information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, status information will be truncated
+ * to fit the buffer.
+ */
int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
int verbose)
{
@@ -960,10 +999,10 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
if (verbose) {
len += snprintf(buf + len, buflen - len,
- "heldPeriod=%d\n"
- "authPeriod=%d\n"
- "startPeriod=%d\n"
- "maxStart=%d\n"
+ "heldPeriod=%u\n"
+ "authPeriod=%u\n"
+ "startPeriod=%u\n"
+ "maxStart=%u\n"
"portControl=%s\n"
"Supplicant Backend state=%s\n",
sm->heldPeriod,
@@ -980,6 +1019,18 @@ int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
}
+/**
+ * eapol_sm_get_mib - Get EAPOL state machine MIBs
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @buf: Buffer for MIB information
+ * @buflen: Maximum buffer length
+ * Returns: Number of bytes written to buf.
+ *
+ * Query EAPOL state machine for MIB information. This function fills in a
+ * text area with current MIB information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, MIB information will be truncated to
+ * fit the buffer.
+ */
int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
{
int len;
@@ -987,22 +1038,22 @@ int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
return 0;
len = snprintf(buf, buflen,
"dot1xSuppPaeState=%d\n"
- "dot1xSuppHeldPeriod=%d\n"
- "dot1xSuppAuthPeriod=%d\n"
- "dot1xSuppStartPeriod=%d\n"
- "dot1xSuppMaxStart=%d\n"
+ "dot1xSuppHeldPeriod=%u\n"
+ "dot1xSuppAuthPeriod=%u\n"
+ "dot1xSuppStartPeriod=%u\n"
+ "dot1xSuppMaxStart=%u\n"
"dot1xSuppSuppControlledPortStatus=%s\n"
"dot1xSuppBackendPaeState=%d\n"
- "dot1xSuppEapolFramesRx=%d\n"
- "dot1xSuppEapolFramesTx=%d\n"
- "dot1xSuppEapolStartFramesTx=%d\n"
- "dot1xSuppEapolLogoffFramesTx=%d\n"
- "dot1xSuppEapolRespFramesTx=%d\n"
- "dot1xSuppEapolReqIdFramesRx=%d\n"
- "dot1xSuppEapolReqFramesRx=%d\n"
- "dot1xSuppInvalidEapolFramesRx=%d\n"
- "dot1xSuppEapLengthErrorFramesRx=%d\n"
- "dot1xSuppLastEapolFrameVersion=%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,
@@ -1027,20 +1078,31 @@ int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
}
-void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len)
+/**
+ * eapol_sm_rx_eapol - Process received EAPOL frames
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @src: Source MAC address of the EAPOL packet
+ * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
+ * @len: Length of the EAPOL frame
+ * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
+ * -1 failure
+ */
+int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
+ size_t len)
{
- struct ieee802_1x_hdr *hdr;
- struct ieee802_1x_eapol_key *key;
+ const struct ieee802_1x_hdr *hdr;
+ const struct ieee802_1x_eapol_key *key;
int plen, data_len;
+ int res = 1;
if (sm == NULL)
- return;
+ return 0;
sm->dot1xSuppEapolFramesRx++;
if (len < sizeof(*hdr)) {
sm->dot1xSuppInvalidEapolFramesRx++;
- return;
+ return 0;
}
- hdr = (struct ieee802_1x_hdr *) buf;
+ hdr = (const struct ieee802_1x_hdr *) buf;
sm->dot1xSuppLastEapolFrameVersion = hdr->version;
memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
if (hdr->version < EAPOL_VERSION) {
@@ -1049,7 +1111,7 @@ void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len)
plen = be_to_host16(hdr->length);
if (plen > len - sizeof(*hdr)) {
sm->dot1xSuppEapLengthErrorFramesRx++;
- return;
+ return 0;
}
data_len = plen + sizeof(*hdr);
@@ -1080,12 +1142,13 @@ void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len)
"frame received");
break;
}
- key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+ key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
if (key->type == EAPOL_KEY_TYPE_WPA ||
key->type == EAPOL_KEY_TYPE_RSN) {
/* WPA Supplicant takes care of this frame. */
wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
"frame in EAPOL state machines");
+ res = 0;
break;
}
if (key->type != EAPOL_KEY_TYPE_RC4) {
@@ -1110,9 +1173,18 @@ void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len)
sm->dot1xSuppInvalidEapolFramesRx++;
break;
}
+
+ return res;
}
+/**
+ * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL station machine about transmitted EAPOL packet from an external
+ * component, e.g., WPA. This will update the statistics.
+ */
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
{
if (sm)
@@ -1120,6 +1192,13 @@ void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
}
+/**
+ * eapol_sm_notify_portEnabled - Notification about portEnabled change
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @enabled: New portEnabled value
+ *
+ * Notify EAPOL station machine about new portEnabled value.
+ */
void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
{
if (sm == NULL)
@@ -1131,6 +1210,13 @@ void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
}
+/**
+ * eapol_sm_notify_portValid - Notification about portValid change
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @valid: New portValid value
+ *
+ * Notify EAPOL station machine about new portValid value.
+ */
void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
{
if (sm == NULL)
@@ -1142,6 +1228,17 @@ void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
}
+/**
+ * eapol_sm_notify_eap_success - Notification of external EAP success trigger
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @success: %TRUE = set success, %FALSE = clear success
+ *
+ * Notify EAPOL station machine that external event has forced EAP state to
+ * success (success = %TRUE). This can be cleared by setting success = %FALSE.
+ *
+ * This function is called to update EAP state when WPA-PSK key handshake has
+ * been completed successfully since WPA-PSK does not use EAP state machine.
+ */
void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
{
if (sm == NULL)
@@ -1156,6 +1253,14 @@ void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
}
+/**
+ * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @fail: %TRUE = set failure, %FALSE = clear failure
+ *
+ * Notify EAPOL station machine that external event has forced EAP state to
+ * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
+ */
void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
{
if (sm == NULL)
@@ -1168,8 +1273,20 @@ void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
}
+/**
+ * eapol_sm_notify_config - Notification of EAPOL configuration change
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @config: Pointer to current network configuration
+ * @conf: Pointer to EAPOL configuration data
+ *
+ * Notify EAPOL station machine that configuration has changed. config will be
+ * stored as a backpointer to network configuration. This can be %NULL to clear
+ * the stored pointed. conf will be copied to local EAPOL/EAP configuration
+ * data. If conf is %NULL, this part of the configuration change will be
+ * skipped.
+ */
void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
- struct eapol_config *conf)
+ const struct eapol_config *conf)
{
if (sm == NULL)
return;
@@ -1185,13 +1302,25 @@ void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
if (sm->eap) {
eap_set_fast_reauth(sm->eap, conf->fast_reauth);
eap_set_workaround(sm->eap, conf->workaround);
+ eap_set_force_disabled(sm->eap, conf->eap_disabled);
}
}
+/**
+ * eapol_sm_get_key - Get master session key (MSK) from EAP
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @key: Pointer for key buffer
+ * @len: Number of bytes to copy to key
+ * Returns: 0 on success (len of key available), maximum available key len
+ * (>0) if key is available but it is shorter than len, or -1 on failure.
+ *
+ * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
+ * is available only after a successful authentication.
+ */
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
{
- u8 *eap_key;
+ const u8 *eap_key;
size_t eap_len;
if (sm == NULL || !eap_key_available(sm->eap))
@@ -1206,6 +1335,13 @@ int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
}
+/**
+ * eapol_sm_notify_logoff - Notification of logon/logoff commands
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @logoff: Whether command was logoff
+ *
+ * Notify EAPOL state machines that user requested logon/logoff.
+ */
void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
{
if (sm) {
@@ -1215,6 +1351,13 @@ void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
}
+/**
+ * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machines that PMKSA caching was successful. This is used
+ * to move EAPOL and EAP state machines into authenticated/successful state.
+ */
void eapol_sm_notify_cached(struct eapol_sm *sm)
{
if (sm == NULL)
@@ -1225,6 +1368,13 @@ void eapol_sm_notify_cached(struct eapol_sm *sm)
}
+/**
+ * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @attempt: Whether PMKSA caching is tried
+ *
+ * Notify EAPOL state machines whether PMKSA caching is used.
+ */
void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
{
if (sm == NULL)
@@ -1252,6 +1402,14 @@ static void eapol_sm_abort_cached(struct eapol_sm *sm)
}
+/**
+ * eapol_sm_register_scard_ctx - Notification of smart card context
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @ctx: Context data for smart card operations
+ *
+ * Notify EAPOL state machines of context data for smart card operations. This
+ * context data will be used as a parameter for scard_*() functions.
+ */
void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
{
if (sm) {
@@ -1261,6 +1419,13 @@ void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
}
+/**
+ * eapol_sm_notify_portControl - Notification of portControl changes
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @portControl: New value for portControl variable
+ *
+ * Notify EAPOL state machines that portControl variable has changed.
+ */
void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
{
if (sm == NULL)
@@ -1272,6 +1437,13 @@ void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
}
+/**
+ * eapol_sm_notify_ctrl_attached - Notification of attached monitor
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machines that a monitor was attached to the control
+ * interface to trigger re-sending of pending requests for user input.
+ */
void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
{
if (sm == NULL)
@@ -1280,6 +1452,13 @@ void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
}
+/**
+ * eapol_sm_notify_ctrl_response - Notification of received user input
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machines that a control response, i.e., user
+ * input, was received in order to trigger retrying of a pending EAP request.
+ */
void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
{
if (sm == NULL)
@@ -1295,6 +1474,37 @@ void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
}
+/**
+ * eapol_sm_request_reauth - Request reauthentication
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * This function can be used to request EAPOL reauthentication, e.g., when the
+ * current PMKSA entry is nearing expiration.
+ */
+void eapol_sm_request_reauth(struct eapol_sm *sm)
+{
+ if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
+ return;
+ eapol_sm_txStart(sm);
+}
+
+
+/**
+ * eapol_sm_notify_lower_layer_success - Notification of lower layer success
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL (and EAP) state machines that a lower layer has detected a
+ * successful authentication. This is used to recover from dropped EAP-Success
+ * messages.
+ */
+void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm)
+{
+ if (sm == NULL)
+ return;
+ eap_notify_lower_layer_success(sm->eap);
+}
+
+
static struct wpa_ssid * eapol_sm_get_config(void *ctx)
{
struct eapol_sm *sm = ctx;
@@ -1409,6 +1619,25 @@ static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
}
+static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
+{
+ struct eapol_sm *sm = ctx;
+ if (sm && sm->ctx && sm->ctx->set_config_blob)
+ sm->ctx->set_config_blob(sm->ctx->ctx, blob);
+}
+
+
+static const struct wpa_config_blob *
+eapol_sm_get_config_blob(void *ctx, const char *name)
+{
+ struct eapol_sm *sm = ctx;
+ if (sm && sm->ctx && sm->ctx->get_config_blob)
+ return sm->ctx->get_config_blob(sm->ctx->ctx, name);
+ else
+ return NULL;
+}
+
+
static struct eapol_callbacks eapol_cb =
{
.get_config = eapol_sm_get_config,
@@ -1417,4 +1646,77 @@ static struct eapol_callbacks eapol_cb =
.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_init - Initialize EAPOL state machine
+ * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
+ * and EAPOL state machine will free it in eapol_sm_deinit()
+ * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
+ *
+ * Allocate and initialize an EAPOL state machine.
+ */
+struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
+{
+ struct eapol_sm *sm;
+ struct eap_config conf;
+ sm = malloc(sizeof(*sm));
+ if (sm == NULL)
+ return NULL;
+ memset(sm, 0, sizeof(*sm));
+ sm->ctx = ctx;
+
+ sm->portControl = Auto;
+
+ /* Supplicant PAE state machine */
+ sm->heldPeriod = 60;
+ sm->startPeriod = 30;
+ sm->maxStart = 3;
+
+ /* Supplicant Backend state machine */
+ sm->authPeriod = 30;
+
+ 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);
+ return NULL;
+ }
+
+ /* Initialize EAPOL state machines */
+ sm->initialize = TRUE;
+ eapol_sm_step(sm);
+ sm->initialize = FALSE;
+ eapol_sm_step(sm);
+
+ eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+
+ return sm;
+}
+
+
+/**
+ * eapol_sm_deinit - Deinitialize EAPOL state machine
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Deinitialize and free EAPOL state machine.
+ */
+void eapol_sm_deinit(struct eapol_sm *sm)
+{
+ if (sm == NULL)
+ return;
+ 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);
+}
diff --git a/contrib/wpa_supplicant/eapol_sm.h b/contrib/wpa_supplicant/eapol_sm.h
index b941203..1d44a54 100644
--- a/contrib/wpa_supplicant/eapol_sm.h
+++ b/contrib/wpa_supplicant/eapol_sm.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / EAPOL state machines
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 EAPOL_SM_H
#define EAPOL_SM_H
@@ -6,28 +20,177 @@
typedef enum { Unauthorized, Authorized } PortStatus;
typedef enum { Auto, ForceUnauthorized, ForceAuthorized } PortControl;
+/**
+ * struct eapol_config - Per network configuration for EAPOL state machines
+ */
struct eapol_config {
+ /**
+ * accept_802_1x_keys - Accept IEEE 802.1X (non-WPA) EAPOL-Key frames
+ *
+ * This variable should be set to 1 when using EAPOL state machines
+ * with non-WPA security policy to generate dynamic WEP keys. When
+ * using WPA, this should be set to 0 so that WPA state machine can
+ * process the EAPOL-Key frames.
+ */
int accept_802_1x_keys;
+
#define EAPOL_REQUIRE_KEY_UNICAST BIT(0)
#define EAPOL_REQUIRE_KEY_BROADCAST BIT(1)
- int required_keys; /* which EAPOL-Key packets are required before
- * marking connection authenticated */
- int fast_reauth; /* whether fast EAP reauthentication is enabled */
- int workaround; /* whether EAP workarounds are enabled */
+ /**
+ * required_keys - Which EAPOL-Key packets are required
+ *
+ * This variable determines which EAPOL-Key packets are required before
+ * marking connection authenticated. This is a bit field of
+ * EAPOL_REQUIRE_KEY_UNICAST and EAPOL_REQUIRE_KEY_BROADCAST flags.
+ */
+ int required_keys;
+
+ /**
+ * fast_reauth - Whether fast EAP reauthentication is enabled
+ */
+ int fast_reauth;
+
+ /**
+ * workaround - Whether EAP workarounds are enabled
+ */
+ unsigned int workaround;
+
+ /**
+ * eap_disabled - Whether EAP is disabled
+ */
+ int eap_disabled;
};
struct eapol_sm;
+struct wpa_config_blob;
+/**
+ * struct eapol_ctx - Global (for all networks) EAPOL state machine context
+ */
struct eapol_ctx {
- void *ctx; /* pointer to arbitrary upper level context */
- int preauth; /* This EAPOL state machine is used for IEEE 802.11i/RSN
- * pre-authentication */
+ /**
+ * ctx - Pointer to arbitrary upper level context
+ */
+ void *ctx;
+
+ /**
+ * preauth - IEEE 802.11i/RSN pre-authentication
+ *
+ * This EAPOL state machine is used for IEEE 802.11i/RSN
+ * pre-authentication
+ */
+ int preauth;
+
+ /**
+ * cb - Function to be called when EAPOL negotiation has been completed
+ * @eapol: Pointer to EAPOL state machine data
+ * @success: Whether the authentication was completed successfully
+ * @ctx: Pointer to context data (cb_ctx)
+ *
+ * This optional callback function will be called when the EAPOL
+ * authentication has been completed. This allows the owner of the
+ * EAPOL state machine to process the key and terminate the EAPOL state
+ * machine. Currently, this is used only in RSN pre-authentication.
+ */
void (*cb)(struct eapol_sm *eapol, int success, void *ctx);
- void *cb_ctx, *msg_ctx, *scard_ctx;
+
+ /**
+ * cb_ctx - Callback context for cb()
+ */
+ void *cb_ctx;
+
+ /**
+ * msg_ctx - Callback context for wpa_msg() calls
+ */
+ void *msg_ctx;
+
+ /**
+ * scard_ctx - Callback context for PC/SC scard_*() function calls
+ *
+ * This context can be updated with eapol_sm_register_scard_ctx().
+ */
+ void *scard_ctx;
+
+ /**
+ * eapol_send_ctx - Callback context for eapol_send() calls
+ */
+ void *eapol_send_ctx;
+
+ /**
+ * eapol_done_cb - Function to be called at successful completion
+ * @ctx: Callback context (ctx)
+ *
+ * This function is called at the successful completion of EAPOL
+ * authentication. If dynamic WEP keys are used, this is called only
+ * after all the expected keys have been received.
+ */
void (*eapol_done_cb)(void *ctx);
- int (*eapol_send)(void *ctx, int type, u8 *buf, size_t len);
+
+ /**
+ * eapol_send - Send EAPOL packets
+ * @ctx: Callback context (eapol_send_ctx)
+ * @type: EAPOL type (IEEE802_1X_TYPE_*)
+ * @buf: Pointer to EAPOL payload
+ * @len: Length of the EAPOL payload
+ * Returns: 0 on success, -1 on failure
+ */
+ int (*eapol_send)(void *ctx, int type, const u8 *buf, size_t len);
+
+ /**
+ * set_wep_key - Configure WEP keys
+ * @ctx: Callback context (ctx)
+ * @unicast: Non-zero = unicast, 0 = multicast/broadcast key
+ * @keyidx: Key index (0..3)
+ * @key: WEP key
+ * @keylen: Length of the WEP key
+ * Returns: 0 on success, -1 on failure
+ */
int (*set_wep_key)(void *ctx, int unicast, int keyidx,
- u8 *key, size_t keylen);
+ const u8 *key, size_t keylen);
+
+ /**
+ * set_config_blob - Set or add a named configuration blob
+ * @ctx: Callback context (ctx)
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an
+ * existing blob.
+ */
+ void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
+
+ /**
+ * get_config_blob - Get a named configuration blob
+ * @ctx: Callback context (ctx)
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+ const struct wpa_config_blob * (*get_config_blob)(void *ctx,
+ const char *name);
+
+ /**
+ * opensc_engine_path - Path to the OpenSSL engine for opensc
+ *
+ * This is an OpenSSL specific configuration option for loading OpenSC
+ * engine (engine_opensc.so); if %NULL, this engine is not loaded.
+ */
+ const char *opensc_engine_path;
+
+ /**
+ * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11
+ *
+ * This is an OpenSSL specific configuration option for loading PKCS#11
+ * engine (engine_pkcs11.so); if %NULL, this engine is not loaded.
+ */
+ const char *pkcs11_engine_path;
+
+ /**
+ * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module
+ *
+ * This is an OpenSSL specific configuration option for configuring
+ * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this
+ * module is not loaded.
+ */
+ const char *pkcs11_module_path;
};
@@ -42,14 +205,15 @@ 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);
void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
int startPeriod, int maxStart);
-void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf, size_t len);
+int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
+ size_t len);
void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm);
void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled);
void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid);
void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success);
void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail);
void eapol_sm_notify_config(struct eapol_sm *sm, struct wpa_ssid *config,
- struct eapol_config *conf);
+ const struct eapol_config *conf);
int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len);
void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff);
void eapol_sm_notify_cached(struct eapol_sm *sm);
@@ -58,9 +222,12 @@ void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx);
void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl);
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);
#else /* IEEE8021X_EAPOL */
static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
{
+ free(ctx);
return (struct eapol_sm *) 1;
}
static inline void eapol_sm_deinit(struct eapol_sm *sm)
@@ -84,9 +251,10 @@ static inline void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod,
int maxStart)
{
}
-static inline void eapol_sm_rx_eapol(struct eapol_sm *sm, u8 *src, u8 *buf,
- size_t len)
+static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src,
+ const u8 *buf, size_t len)
{
+ return 0;
}
static inline void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
{
@@ -133,6 +301,12 @@ static inline void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
static inline void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
{
}
+static inline void eapol_sm_request_reauth(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_notify_lower_layer_success(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 061ae89..1bc34a3 100644
--- a/contrib/wpa_supplicant/eapol_test.c
+++ b/contrib/wpa_supplicant/eapol_test.c
@@ -1,6 +1,15 @@
/*
* WPA Supplicant - test code
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.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.
*
* IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
* Not used in production version.
@@ -13,9 +22,11 @@
#include <ctype.h>
#include <string.h>
#include <signal.h>
+#ifndef CONFIG_NATIVE_WINDOWS
#include <netinet/in.h>
-#include <assert.h>
#include <arpa/inet.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+#include <assert.h>
#include "common.h"
#include "config.h"
@@ -34,139 +45,147 @@
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
-static int eapol_test_num_reauths = 0;
-static int no_mppe_keys = 0;
-static int num_mppe_ok = 0, num_mppe_mismatch = 0;
-static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx);
+struct wpa_driver_ops *wpa_supplicant_drivers[] = { };
-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);
-}
+struct eapol_test_data {
+ struct wpa_supplicant *wpa_s;
+ int eapol_test_num_reauths;
+ int no_mppe_keys;
+ int num_mppe_ok, num_mppe_mismatch;
-void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
- union wpa_event_data *data)
-{
-}
+ u8 radius_identifier;
+ struct radius_msg *last_recv_radius;
+ struct in_addr own_ip_addr;
+ struct radius_client_data *radius;
+ struct hostapd_radius_servers *radius_conf;
+ u8 *last_eap_radius; /* last received EAP Response from Authentication
+ * Server */
+ size_t last_eap_radius_len;
-int rsn_preauth_init(struct wpa_supplicant *wpa_s, u8 *dst)
-{
- return -1;
-}
+ u8 authenticator_pmk[PMK_LEN];
+ size_t authenticator_pmk_len;
+ int radius_access_accept_received;
+ int radius_access_reject_received;
+ int auth_timed_out;
+ u8 *eap_identity;
+ size_t eap_identity_len;
+};
-void rsn_preauth_deinit(struct wpa_supplicant *wpa_s)
-{
-}
+static struct eapol_test_data eapol_test;
-int pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, size_t len)
-{
- return 0;
-}
+static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx);
-int wpa_get_mib(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+void hostapd_logger(void *ctx, u8 *addr, unsigned int module, int level,
+ char *fmt, ...)
{
- return 0;
-}
+ char *format;
+ int maxlen;
+ va_list ap;
+ maxlen = strlen(fmt) + 100;
+ format = malloc(maxlen);
+ if (!format)
+ return;
-void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
-{
-}
+ va_start(ap, fmt);
-const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
-{
- return NULL;
+ if (addr)
+ snprintf(format, maxlen, "STA " MACSTR ": %s",
+ MAC2STR(addr), fmt);
+ else
+ snprintf(format, maxlen, "%s", fmt);
+
+ vprintf(format, ap);
+ printf("\n");
+
+ free(format);
+
+ va_end(ap);
}
-int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
+const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
+ size_t buflen)
{
- return -1;
+ if (buflen == 0 || addr == NULL)
+ return NULL;
+
+ if (addr->af == AF_INET) {
+ snprintf(buf, buflen, "%s", inet_ntoa(addr->u.v4));
+ } else {
+ buf[0] = '\0';
+ }
+#ifdef CONFIG_IPV6
+ if (addr->af == AF_INET6) {
+ if (inet_ntop(AF_INET6, &addr->u.v6, buf, buflen) == NULL)
+ buf[0] = '\0';
+ }
+#endif /* CONFIG_IPV6 */
+
+ return buf;
}
-static void ieee802_1x_encapsulate_radius(struct wpa_supplicant *wpa_s,
- u8 *eap, size_t len)
+static void ieee802_1x_encapsulate_radius(struct eapol_test_data *e,
+ const u8 *eap, size_t len)
{
struct radius_msg *msg;
char buf[128];
- struct eap_hdr *hdr;
- u8 *pos;
+ const struct eap_hdr *hdr;
+ const u8 *pos;
wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
"packet");
- wpa_s->radius_identifier = radius_client_get_id(wpa_s);
+ e->radius_identifier = radius_client_get_id(e->radius);
msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
- wpa_s->radius_identifier);
+ e->radius_identifier);
if (msg == NULL) {
printf("Could not create net RADIUS packet\n");
return;
}
- radius_msg_make_authenticator(msg, (u8 *) wpa_s, sizeof(*wpa_s));
+ radius_msg_make_authenticator(msg, (u8 *) e, sizeof(*e));
- hdr = (struct eap_hdr *) eap;
- pos = (u8 *) (hdr + 1);
+ hdr = (const struct eap_hdr *) eap;
+ pos = (const u8 *) (hdr + 1);
if (len > sizeof(*hdr) && hdr->code == EAP_CODE_RESPONSE &&
pos[0] == EAP_TYPE_IDENTITY) {
pos++;
- free(wpa_s->eap_identity);
- wpa_s->eap_identity_len = len - sizeof(*hdr) - 1;
- wpa_s->eap_identity = malloc(wpa_s->eap_identity_len);
- if (wpa_s->eap_identity) {
- memcpy(wpa_s->eap_identity, pos,
- wpa_s->eap_identity_len);
+ free(e->eap_identity);
+ e->eap_identity_len = len - sizeof(*hdr) - 1;
+ e->eap_identity = malloc(e->eap_identity_len);
+ if (e->eap_identity) {
+ memcpy(e->eap_identity, pos, e->eap_identity_len);
wpa_hexdump(MSG_DEBUG, "Learned identity from "
"EAP-Response-Identity",
- wpa_s->eap_identity,
- wpa_s->eap_identity_len);
+ e->eap_identity, e->eap_identity_len);
}
}
- if (wpa_s->eap_identity &&
+ if (e->eap_identity &&
!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
- wpa_s->eap_identity,
- wpa_s->eap_identity_len)) {
+ e->eap_identity, e->eap_identity_len)) {
printf("Could not add User-Name\n");
goto fail;
}
if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
- (u8 *) &wpa_s->own_ip_addr, 4)) {
+ (u8 *) &e->own_ip_addr, 4)) {
printf("Could not add NAS-IP-Address\n");
goto fail;
}
snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
- MAC2STR(wpa_s->own_addr));
+ MAC2STR(e->wpa_s->own_addr));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
(u8 *) buf, strlen(buf))) {
printf("Could not add Calling-Station-Id\n");
@@ -201,9 +220,9 @@ static void ieee802_1x_encapsulate_radius(struct wpa_supplicant *wpa_s,
/* State attribute must be copied if and only if this packet is
* Access-Request reply to the previous Access-Challenge */
- if (wpa_s->last_recv_radius && wpa_s->last_recv_radius->hdr->code ==
+ if (e->last_recv_radius && e->last_recv_radius->hdr->code ==
RADIUS_CODE_ACCESS_CHALLENGE) {
- int res = radius_msg_copy_attr(msg, wpa_s->last_recv_radius,
+ int res = radius_msg_copy_attr(msg, e->last_recv_radius,
RADIUS_ATTR_STATE);
if (res < 0) {
printf("Could not copy State attribute from previous "
@@ -216,7 +235,7 @@ static void ieee802_1x_encapsulate_radius(struct wpa_supplicant *wpa_s,
}
}
- radius_client_send(wpa_s, msg, RADIUS_AUTH, wpa_s->own_addr);
+ radius_client_send(e->radius, msg, RADIUS_AUTH, e->wpa_s->own_addr);
return;
fail:
@@ -225,18 +244,35 @@ static void ieee802_1x_encapsulate_radius(struct wpa_supplicant *wpa_s,
}
-static int eapol_test_eapol_send(void *ctx, int type, u8 *buf, size_t len)
+static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf,
+ size_t len)
{
- struct wpa_supplicant *wpa_s = ctx;
- printf("WPA: wpa_eapol_send(type=%d len=%d)\n", type, len);
+ /* struct wpa_supplicant *wpa_s = ctx; */
+ printf("WPA: eapol_test_eapol_send(type=%d len=%d)\n", type, len);
if (type == IEEE802_1X_TYPE_EAP_PACKET) {
wpa_hexdump(MSG_DEBUG, "TX EAP -> RADIUS", buf, len);
- ieee802_1x_encapsulate_radius(wpa_s, buf, len);
+ ieee802_1x_encapsulate_radius(&eapol_test, buf, len);
}
return 0;
}
+static void eapol_test_set_config_blob(void *ctx,
+ struct wpa_config_blob *blob)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ wpa_config_set_blob(wpa_s->conf, blob);
+}
+
+
+static const struct wpa_config_blob *
+eapol_test_get_config_blob(void *ctx, const char *name)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ return wpa_config_get_blob(wpa_s->conf, name);
+}
+
+
static void eapol_test_eapol_done_cb(void *ctx)
{
printf("WPA: EAPOL processing complete\n");
@@ -245,40 +281,40 @@ static void eapol_test_eapol_done_cb(void *ctx)
static void eapol_sm_reauth(void *eloop_ctx, void *timeout_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct eapol_test_data *e = eloop_ctx;
printf("\n\n\n\n\neapol_test: Triggering EAP reauthentication\n\n");
- wpa_s->radius_access_accept_received = 0;
- send_eap_request_identity(eloop_ctx, timeout_ctx);
+ e->radius_access_accept_received = 0;
+ send_eap_request_identity(e->wpa_s, NULL);
}
-static int eapol_test_compare_pmk(struct wpa_supplicant *wpa_s)
+static int eapol_test_compare_pmk(struct eapol_test_data *e)
{
u8 pmk[PMK_LEN];
int ret = 1;
- if (eapol_sm_get_key(wpa_s->eapol, pmk, PMK_LEN) == 0) {
+ 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, wpa_s->authenticator_pmk, PMK_LEN) != 0)
+ if (memcmp(pmk, e->authenticator_pmk, PMK_LEN) != 0)
printf("WARNING: PMK mismatch\n");
- else if (wpa_s->radius_access_accept_received)
+ else if (e->radius_access_accept_received)
ret = 0;
- } else if (wpa_s->authenticator_pmk_len == 16 &&
- eapol_sm_get_key(wpa_s->eapol, pmk, 16) == 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, wpa_s->authenticator_pmk, 16) != 0)
+ if (memcmp(pmk, e->authenticator_pmk, 16) != 0)
printf("WARNING: PMK mismatch\n");
- else if (wpa_s->radius_access_accept_received)
+ else if (e->radius_access_accept_received)
ret = 0;
- } else if (wpa_s->radius_access_accept_received && no_mppe_keys) {
+ } else if (e->radius_access_accept_received && e->no_mppe_keys) {
/* No keying material expected */
ret = 0;
}
if (ret)
- num_mppe_mismatch++;
- else if (!no_mppe_keys)
- num_mppe_ok++;
+ e->num_mppe_mismatch++;
+ else if (!e->no_mppe_keys)
+ e->num_mppe_ok++;
return ret;
}
@@ -286,20 +322,20 @@ static int eapol_test_compare_pmk(struct wpa_supplicant *wpa_s)
static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
{
- struct wpa_supplicant *wpa_s = ctx;
+ struct eapol_test_data *e = ctx;
printf("eapol_sm_cb: success=%d\n", success);
- eapol_test_num_reauths--;
- if (eapol_test_num_reauths < 0)
+ e->eapol_test_num_reauths--;
+ if (e->eapol_test_num_reauths < 0)
eloop_terminate();
else {
- eapol_test_compare_pmk(wpa_s);
- eloop_register_timeout(0, 100000, eapol_sm_reauth,
- wpa_s, NULL);
+ eapol_test_compare_pmk(e);
+ eloop_register_timeout(0, 100000, eapol_sm_reauth, e, NULL);
}
}
-static int test_eapol(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+static int test_eapol(struct eapol_test_data *e, struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
struct eapol_config eapol_conf;
struct eapol_ctx *ctx;
@@ -314,10 +350,16 @@ static int test_eapol(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
ctx->msg_ctx = wpa_s;
ctx->scard_ctx = wpa_s->scard;
ctx->cb = eapol_sm_cb;
- ctx->cb_ctx = wpa_s;
+ ctx->cb_ctx = e;
+ ctx->eapol_send_ctx = wpa_s;
ctx->preauth = 0;
ctx->eapol_done_cb = eapol_test_eapol_done_cb;
ctx->eapol_send = eapol_test_eapol_send;
+ ctx->set_config_blob = eapol_test_set_config_blob;
+ ctx->get_config_blob = eapol_test_get_config_blob;
+ 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) {
@@ -344,22 +386,25 @@ static int test_eapol(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
}
-static void test_eapol_clean(struct wpa_supplicant *wpa_s)
+static void test_eapol_clean(struct eapol_test_data *e,
+ struct wpa_supplicant *wpa_s)
{
- radius_client_deinit(wpa_s);
- free(wpa_s->last_eap_radius);
- if (wpa_s->last_recv_radius) {
- radius_msg_free(wpa_s->last_recv_radius);
- free(wpa_s->last_recv_radius);
- }
- free(wpa_s->eap_identity);
- wpa_s->eap_identity = NULL;
+ radius_client_deinit(e->radius);
+ free(e->last_eap_radius);
+ if (e->last_recv_radius) {
+ radius_msg_free(e->last_recv_radius);
+ free(e->last_recv_radius);
+ }
+ free(e->eap_identity);
+ e->eap_identity = NULL;
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
- if (wpa_s->auth_server) {
- free(wpa_s->auth_server->shared_secret);
- free(wpa_s->auth_server);
+ if (e->radius_conf && e->radius_conf->auth_server) {
+ free(e->radius_conf->auth_server->shared_secret);
+ free(e->radius_conf->auth_server);
}
+ free(e->radius_conf);
+ e->radius_conf = NULL;
scard_deinit(wpa_s->scard);
wpa_supplicant_ctrl_iface_deinit(wpa_s);
wpa_config_free(wpa_s->conf);
@@ -393,9 +438,9 @@ static void send_eap_request_identity(void *eloop_ctx, void *timeout_ctx)
static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct eapol_test_data *e = eloop_ctx;
printf("EAPOL test timed out\n");
- wpa_s->auth_timed_out = 1;
+ e->auth_timed_out = 1;
eloop_terminate();
}
@@ -418,7 +463,7 @@ static char *eap_type_text(u8 type)
}
-static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
+static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
{
u8 *eap;
size_t len;
@@ -427,10 +472,10 @@ static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
char buf[64];
struct radius_msg *msg;
- if (wpa_s->last_recv_radius == NULL)
+ if (e->last_recv_radius == NULL)
return;
- msg = wpa_s->last_recv_radius;
+ msg = e->last_recv_radius;
eap = radius_msg_get_eap(msg, &len);
if (eap == NULL) {
@@ -439,9 +484,9 @@ static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
* attribute */
wpa_printf(MSG_DEBUG, "could not extract "
"EAP-Message from RADIUS message");
- free(wpa_s->last_eap_radius);
- wpa_s->last_eap_radius = NULL;
- wpa_s->last_eap_radius_len = 0;
+ free(e->last_eap_radius);
+ e->last_eap_radius = NULL;
+ e->last_eap_radius_len = 0;
return;
}
@@ -487,10 +532,9 @@ static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
/* sta->eapol_sm->be_auth.idFromServer = hdr->identifier; */
- if (wpa_s->last_eap_radius)
- free(wpa_s->last_eap_radius);
- wpa_s->last_eap_radius = eap;
- wpa_s->last_eap_radius_len = len;
+ free(e->last_eap_radius);
+ e->last_eap_radius = eap;
+ e->last_eap_radius_len = len;
{
struct ieee802_1x_hdr *hdr;
@@ -500,14 +544,14 @@ static void ieee802_1x_decapsulate_radius(struct wpa_supplicant *wpa_s)
hdr->type = IEEE802_1X_TYPE_EAP_PACKET;
hdr->length = htons(len);
memcpy((u8 *) (hdr + 1), eap, len);
- eapol_sm_rx_eapol(wpa_s->eapol, wpa_s->bssid,
+ eapol_sm_rx_eapol(e->wpa_s->eapol, e->wpa_s->bssid,
(u8 *) hdr, sizeof(*hdr) + len);
free(hdr);
}
}
-static void ieee802_1x_get_keys(struct wpa_supplicant *wpa_s,
+static void ieee802_1x_get_keys(struct eapol_test_data *e,
struct radius_msg *msg, struct radius_msg *req,
u8 *shared_secret, size_t shared_secret_len)
{
@@ -529,11 +573,11 @@ static void ieee802_1x_get_keys(struct wpa_supplicant *wpa_s,
if (keys->recv) {
wpa_hexdump(MSG_DEBUG, "MS-MPPE-Recv-Key (crypt)",
keys->recv, keys->recv_len);
- wpa_s->authenticator_pmk_len =
+ e->authenticator_pmk_len =
keys->recv_len > PMK_LEN ? PMK_LEN :
keys->recv_len;
- memcpy(wpa_s->authenticator_pmk, keys->recv,
- wpa_s->authenticator_pmk_len);
+ memcpy(e->authenticator_pmk, keys->recv,
+ e->authenticator_pmk_len);
}
free(keys->send);
@@ -545,11 +589,12 @@ static void ieee802_1x_get_keys(struct wpa_supplicant *wpa_s,
/* Process the RADIUS frames from Authentication Server */
static RadiusRxResult
-ieee802_1x_receive_auth(struct wpa_supplicant *wpa_s,
- struct radius_msg *msg, struct radius_msg *req,
+ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
u8 *shared_secret, size_t shared_secret_len,
void *data)
{
+ struct eapol_test_data *e = data;
+
/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
* present when packet contains an EAP-Message attribute */
if (msg->hdr->code == RADIUS_CODE_ACCESS_REJECT &&
@@ -560,7 +605,7 @@ ieee802_1x_receive_auth(struct wpa_supplicant *wpa_s,
"Access-Reject without Message-Authenticator "
"since it does not include EAP-Message\n");
} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
- req)) {
+ req, 1)) {
printf("Incoming RADIUS packet did not have correct "
"Message-Authenticator - dropped\n");
return RADIUS_RX_UNKNOWN;
@@ -573,31 +618,31 @@ ieee802_1x_receive_auth(struct wpa_supplicant *wpa_s,
return RADIUS_RX_UNKNOWN;
}
- wpa_s->radius_identifier = -1;
+ e->radius_identifier = -1;
wpa_printf(MSG_DEBUG, "RADIUS packet matching with station");
- if (wpa_s->last_recv_radius) {
- radius_msg_free(wpa_s->last_recv_radius);
- free(wpa_s->last_recv_radius);
+ if (e->last_recv_radius) {
+ radius_msg_free(e->last_recv_radius);
+ free(e->last_recv_radius);
}
- wpa_s->last_recv_radius = msg;
+ e->last_recv_radius = msg;
switch (msg->hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
- wpa_s->radius_access_accept_received = 1;
- ieee802_1x_get_keys(wpa_s, msg, req, shared_secret,
+ e->radius_access_accept_received = 1;
+ ieee802_1x_get_keys(e, msg, req, shared_secret,
shared_secret_len);
break;
case RADIUS_CODE_ACCESS_REJECT:
- wpa_s->radius_access_reject_received = 1;
+ e->radius_access_reject_received = 1;
break;
}
- ieee802_1x_decapsulate_radius(wpa_s);
+ ieee802_1x_decapsulate_radius(e);
if ((msg->hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
- eapol_test_num_reauths < 0) ||
+ e->eapol_test_num_reauths < 0) ||
msg->hdr->code == RADIUS_CODE_ACCESS_REJECT) {
eloop_terminate();
}
@@ -606,77 +651,8 @@ ieee802_1x_receive_auth(struct wpa_supplicant *wpa_s,
}
-static void wpa_supplicant_imsi_identity(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- int aka = 0;
- u8 *pos = ssid->eap_methods;
-
- while (pos && *pos != EAP_TYPE_NONE) {
- if (*pos == EAP_TYPE_AKA) {
- aka = 1;
- break;
- }
- pos++;
- }
-
- if (ssid->identity == NULL && wpa_s->imsi) {
- ssid->identity = malloc(1 + wpa_s->imsi_len);
- if (ssid->identity) {
- ssid->identity[0] = aka ? '0' : '1';
- memcpy(ssid->identity + 1, wpa_s->imsi,
- wpa_s->imsi_len);
- ssid->identity_len = 1 + wpa_s->imsi_len;
- wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
- "IMSI", ssid->identity,
- ssid->identity_len);
- }
- }
-}
-
-
-static void wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- char buf[100];
- size_t len;
-
- if (ssid->pcsc == NULL)
- return;
- if (wpa_s->scard != NULL) {
- wpa_supplicant_imsi_identity(wpa_s, ssid);
- return;
- }
- wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM - "
- "initialize PCSC");
- wpa_s->scard = scard_init(SCARD_TRY_BOTH, ssid->pin);
- if (wpa_s->scard == NULL) {
- wpa_printf(MSG_WARNING, "Failed to initialize SIM "
- "(pcsc-lite)");
- /* TODO: what to do here? */
- return;
- }
- eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
-
- len = sizeof(buf);
- if (scard_get_imsi(wpa_s->scard, buf, &len)) {
- wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
- /* TODO: what to do here? */
- return;
- }
-
- wpa_hexdump(MSG_DEBUG, "IMSI", (u8 *) buf, len);
- free(wpa_s->imsi);
- wpa_s->imsi = malloc(len);
- if (wpa_s->imsi) {
- memcpy(wpa_s->imsi, buf, len);
- wpa_s->imsi_len = len;
- wpa_supplicant_imsi_identity(wpa_s, ssid);
- }
-}
-
-
-static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *authsrv,
+static void wpa_init_conf(struct eapol_test_data *e,
+ struct wpa_supplicant *wpa_s, const char *authsrv,
int port, const char *secret)
{
struct hostapd_radius_server *as;
@@ -684,24 +660,43 @@ static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *authsrv,
wpa_s->bssid[5] = 1;
wpa_s->own_addr[5] = 2;
- wpa_s->own_ip_addr.s_addr = htonl((127 << 24) | 1);
+ e->own_ip_addr.s_addr = htonl((127 << 24) | 1);
strncpy(wpa_s->ifname, "test", sizeof(wpa_s->ifname));
- wpa_s->num_auth_servers = 1;
+ e->radius_conf = malloc(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));
assert(as != NULL);
- inet_aton(authsrv, &as->addr);
+ memset(as, 0, sizeof(*as));
+#ifdef CONFIG_NATIVE_WINDOWS
+ {
+ int a[4];
+ u8 *pos;
+ sscanf(authsrv, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+ pos = (u8 *) &as->addr.u.v4;
+ *pos++ = a[0];
+ *pos++ = a[1];
+ *pos++ = a[2];
+ *pos++ = a[3];
+ }
+#else /* CONFIG_NATIVE_WINDOWS */
+ inet_aton(authsrv, &as->addr.u.v4);
+#endif /* CONFIG_NATIVE_WINDOWS */
+ as->addr.af = AF_INET;
as->port = port;
as->shared_secret = (u8 *) strdup(secret);
as->shared_secret_len = strlen(secret);
- wpa_s->auth_server = wpa_s->auth_servers = as;
+ e->radius_conf->auth_server = as;
+ e->radius_conf->auth_servers = as;
+ e->radius_conf->msg_dumps = 1;
+ e->radius = radius_client_init(wpa_s, e->radius_conf);
+ assert(e->radius != NULL);
- res = radius_client_init(wpa_s);
- assert(res == 0);
-
- res = radius_client_register(wpa_s, RADIUS_AUTH,
- ieee802_1x_receive_auth, NULL);
+ res = radius_client_register(e->radius, RADIUS_AUTH,
+ ieee802_1x_receive_auth, e);
assert(res == 0);
}
@@ -736,9 +731,14 @@ static int scard_test(void)
unsigned char aka_ik[IK_LEN];
unsigned char aka_ck[CK_LEN];
- scard = scard_init(SCARD_TRY_BOTH, "1234");
+ scard = scard_init(SCARD_TRY_BOTH);
if (scard == NULL)
return -1;
+ if (scard_set_pin(scard, "1234")) {
+ wpa_printf(MSG_WARNING, "PIN validation failed");
+ scard_deinit(scard);
+ return -1;
+ }
len = sizeof(imsi);
if (scard_get_imsi(scard, imsi, &len))
@@ -827,11 +827,16 @@ static int scard_get_triplets(int argc, char *argv[])
wpa_debug_level = 99;
}
- scard = scard_init(SCARD_GSM_SIM_ONLY, argv[0]);
+ scard = scard_init(SCARD_GSM_SIM_ONLY);
if (scard == NULL) {
printf("Failed to open smartcard connection\n");
return -1;
}
+ if (scard_set_pin(scard, argv[0])) {
+ wpa_printf(MSG_WARNING, "PIN validation failed");
+ scard_deinit(scard);
+ return -1;
+ }
len = sizeof(imsi);
if (scard_get_imsi(scard, imsi, &len)) {
@@ -877,7 +882,7 @@ static void eapol_test_terminate(int sig, void *eloop_ctx,
static void usage(void)
{
printf("usage:\n"
- "eapol_test [-n] -c<conf> [-a<AS IP>] [-p<AS port>] "
+ "eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
"[-s<AS secret>] [-r<count>]\n"
"eapol_test scard\n"
"eapol_test sim <PIN> <num triplets> [debug]\n"
@@ -891,6 +896,8 @@ static void usage(void)
" -s<AS secret> = shared secret with the authentication "
"server, default 'radius'\n"
" -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");
}
@@ -898,17 +905,27 @@ static void usage(void)
int main(int argc, char *argv[])
{
struct wpa_supplicant wpa_s;
- int c, ret = 1;
+ int c, ret = 1, wait_for_monitor = 0, save_config = 0;
char *as_addr = "127.0.0.1";
int as_port = 1812;
char *as_secret = "radius";
char *conf = NULL;
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
+ printf("Could not find a usable WinSock.dll\n");
+ return -1;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ memset(&eapol_test, 0, sizeof(eapol_test));
+
wpa_debug_level = 0;
wpa_debug_show_keys = 1;
for (;;) {
- c = getopt(argc, argv, "a:c:np:r:s:");
+ c = getopt(argc, argv, "a:c:np:r:s:SW");
if (c < 0)
break;
switch (c) {
@@ -919,17 +936,23 @@ int main(int argc, char *argv[])
conf = optarg;
break;
case 'n':
- no_mppe_keys++;
+ eapol_test.no_mppe_keys++;
break;
case 'p':
as_port = atoi(optarg);
break;
case 'r':
- eapol_test_num_reauths = atoi(optarg);
+ eapol_test.eapol_test_num_reauths = atoi(optarg);
break;
case 's':
as_secret = optarg;
break;
+ case 'S':
+ save_config++;
+ break;
+ case 'W':
+ wait_for_monitor++;
+ break;
default:
usage();
return -1;
@@ -954,6 +977,7 @@ int main(int argc, char *argv[])
eloop_init(&wpa_s);
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) {
printf("Failed to parse configuration file '%s'.\n", conf);
@@ -964,7 +988,7 @@ int main(int argc, char *argv[])
return -1;
}
- wpa_init_conf(&wpa_s, as_addr, as_port, as_secret);
+ wpa_init_conf(&eapol_test, &wpa_s, as_addr, as_port, as_secret);
if (wpa_supplicant_ctrl_iface_init(&wpa_s)) {
printf("Failed to initialize control interface '%s'.\n"
"You may have another eapol_test process already "
@@ -976,37 +1000,50 @@ int main(int argc, char *argv[])
wpa_s.conf->ctrl_interface);
return -1;
}
- wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid);
+ if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid))
+ return -1;
- if (test_eapol(&wpa_s, wpa_s.conf->ssid))
+ if (test_eapol(&eapol_test, &wpa_s, wpa_s.conf->ssid))
return -1;
- eloop_register_timeout(30, 0, eapol_test_timeout, &wpa_s, NULL);
+ if (wait_for_monitor)
+ wpa_supplicant_ctrl_iface_wait(&wpa_s);
+
+ eloop_register_timeout(30, 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_run();
- if (eapol_test_compare_pmk(&wpa_s) == 0)
+ if (eapol_test_compare_pmk(&eapol_test) == 0)
ret = 0;
- if (wpa_s.auth_timed_out)
+ if (eapol_test.auth_timed_out)
ret = -2;
- if (wpa_s.radius_access_reject_received)
+ if (eapol_test.radius_access_reject_received)
ret = -3;
- test_eapol_clean(&wpa_s);
+ if (save_config)
+ wpa_config_write(conf, wpa_s.conf);
+
+ test_eapol_clean(&eapol_test, &wpa_s);
eloop_destroy();
printf("MPPE keys OK: %d mismatch: %d\n",
- num_mppe_ok, num_mppe_mismatch);
- if (num_mppe_mismatch)
+ eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch);
+ if (eapol_test.num_mppe_mismatch)
ret = -4;
if (ret)
printf("FAILURE\n");
else
printf("SUCCESS\n");
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
return ret;
}
diff --git a/contrib/wpa_supplicant/eloop.c b/contrib/wpa_supplicant/eloop.c
index 6071508..39fccb8 100644
--- a/contrib/wpa_supplicant/eloop.c
+++ b/contrib/wpa_supplicant/eloop.c
@@ -1,5 +1,5 @@
/*
- * Event loop
+ * Event loop based on select() loop
* Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -294,10 +294,16 @@ int eloop_register_signal(int sig,
void eloop_run(void)
{
- fd_set rfds;
+ fd_set *rfds;
int i, res;
struct timeval tv, now;
+ rfds = malloc(sizeof(*rfds));
+ if (rfds == NULL) {
+ printf("eloop_run - malloc failed\n");
+ return;
+ }
+
while (!eloop.terminate &&
(eloop.timeout || eloop.reader_count > 0)) {
if (eloop.timeout) {
@@ -312,13 +318,14 @@ void eloop_run(void)
#endif
}
- FD_ZERO(&rfds);
+ 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,
+ 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) {
perror("select");
+ free(rfds);
return;
}
eloop_process_pending_signals();
@@ -342,7 +349,7 @@ void eloop_run(void)
continue;
for (i = 0; i < eloop.reader_count; i++) {
- if (FD_ISSET(eloop.readers[i].sock, &rfds)) {
+ if (FD_ISSET(eloop.readers[i].sock, rfds)) {
eloop.readers[i].handler(
eloop.readers[i].sock,
eloop.readers[i].eloop_data,
@@ -350,6 +357,8 @@ void eloop_run(void)
}
}
}
+
+ free(rfds);
}
diff --git a/contrib/wpa_supplicant/eloop.h b/contrib/wpa_supplicant/eloop.h
index f5b8847..c57e682 100644
--- a/contrib/wpa_supplicant/eloop.h
+++ b/contrib/wpa_supplicant/eloop.h
@@ -1,53 +1,152 @@
+/*
+ * Event loop
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 defines an event loop interface that supports processing events
+ * from registered timeouts (i.e., do something after N seconds), sockets
+ * (e.g., a new packet available for reading), and signals. eloop.c is an
+ * implementation of this interface using select() and sockets. This is
+ * suitable for most UNIX/POSIX systems. When porting to other operating
+ * systems, it may be necessary to replace that implementation with OS specific
+ * mechanisms.
+ */
+
#ifndef ELOOP_H
#define ELOOP_H
/* Magic number for eloop_cancel_timeout() */
#define ELOOP_ALL_CTX (void *) -1
-/* Initialize global event loop data - must be called before any other eloop_*
- * function. user_data is a pointer to global data structure and will be passed
- * as eloop_ctx to signal handlers. */
+/**
+ * eloop_init() - Initialize global event loop data
+ * @user_data: Pointer to global data passed as eloop_ctx to signal handlers
+ *
+ * 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);
-/* Register handler for read event */
+/**
+ * eloop_register_read_sock - Register handler for read events
+ * @sock: File descriptor number for the socket
+ * @handler: Callback function to be called when data is available for reading
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a read socket notifier for the given file descriptor. The handler
+ * function will be called whenever data is available for reading from the
+ * socket.
+ */
int eloop_register_read_sock(int sock,
void (*handler)(int sock, void *eloop_ctx,
void *sock_ctx),
void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_read_sock - Unregister handler for read events
+ * @sock: File descriptor number for the socket
+ *
+ * Unregister a read socket notifier that was previously registered with
+ * eloop_register_read_sock().
+ */
void eloop_unregister_read_sock(int sock);
-/* Register timeout */
+/**
+ * eloop_register_timeout - Register timeout
+ * @secs: Number of seconds to the timeout
+ * @usecs: Number of microseconds to the timeout
+ * @handler: Callback function to be called when timeout occurs
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a timeout that will cause the handler function to be called after
+ * given time.
+ */
int eloop_register_timeout(unsigned int secs, unsigned int usecs,
void (*handler)(void *eloop_ctx, void *timeout_ctx),
void *eloop_data, void *user_data);
-/* Cancel timeouts matching <handler,eloop_data,user_data>.
- * ELOOP_ALL_CTX can be used as a wildcard for cancelling all timeouts
- * regardless of eloop_data/user_data. */
+/**
+ * eloop_cancel_timeout - Cancel timeouts
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all
+ * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all
+ * Returns: Number of cancelled timeouts
+ *
+ * Cancel matching <handler,eloop_data,user_data> timeouts registered with
+ * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
+ * cancelling all timeouts regardless of eloop_data/user_data.
+ */
int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
void *eloop_data, void *user_data);
-/* Register handler for signal.
- * Note: signals are 'global' events and there is no local eloop_data pointer
- * like with other handlers. The (global) pointer given to eloop_init() will be
- * used as eloop_ctx for signal handlers. */
-int eloop_register_signal(int sock,
+/**
+ * eloop_register_signal - Register handler for signals
+ * @sig: Signal number (e.g., SIGHUP)
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a signal is received.
+ * The 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.
+ *
+ * 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),
void *user_data);
-/* Start event loop and continue running as long as there are any registered
- * event handlers. */
+/**
+ * eloop_run - Start the event loop
+ *
+ * Start the event loop and continue running as long as there are any
+ * registered event handlers. This function is run after event loop has been
+ * initialized with event_init() and one or more events have been registered.
+ */
void eloop_run(void);
-/* Terminate event loop even if there are registered events. */
+/**
+ * eloop_terminate - Terminate event loop
+ *
+ * Terminate event loop even if there are registered events. This can be used
+ * to request the program to be terminated cleanly.
+ */
void eloop_terminate(void);
-/* Free any reserved resources. After calling eloop_destoy(), other eloop_*
- * functions must not be called before re-running eloop_init(). */
+/**
+ * eloop_destroy - Free any resources allocated for the event loop
+ *
+ * After calling eloop_destoy(), other eloop_* functions must not be called
+ * before re-running eloop_init().
+ */
void eloop_destroy(void);
-/* Check whether event loop has been terminated. */
+/**
+ * eloop_terminated - Check whether event loop has been terminated
+ * Returns: 1 = event loop terminate, 0 = event loop still running
+ *
+ * This function can be used to check whether eloop_terminate() has been called
+ * to request termination of the event loop. This is normally used to abort
+ * operations that may still be queued to be run when eloop_terminate() was
+ * called.
+ */
int eloop_terminated(void);
#endif /* ELOOP_H */
diff --git a/contrib/wpa_supplicant/events.c b/contrib/wpa_supplicant/events.c
new file mode 100644
index 0000000..d8762e9
--- /dev/null
+++ b/contrib/wpa_supplicant/events.c
@@ -0,0 +1,759 @@
+/*
+ * WPA Supplicant - Driver event processing
+ * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include "common.h"
+#include "eapol_sm.h"
+#include "wpa.h"
+#include "eloop.h"
+#include "wpa_supplicant.h"
+#include "config.h"
+#include "l2_packet.h"
+#include "wpa_supplicant_i.h"
+#include "pcsc_funcs.h"
+#include "preauth.h"
+#include "wpa_ctrl.h"
+#include "eap.h"
+
+
+static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ssid *ssid;
+
+ if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
+ return 0;
+
+ ssid = wpa_supplicant_get_ssid(wpa_s);
+ if (ssid == NULL) {
+ wpa_printf(MSG_INFO, "No network configuration found for the "
+ "current AP");
+ return -1;
+ }
+
+ if (ssid->disabled) {
+ wpa_printf(MSG_DEBUG, "Selected network is disabled");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "Network configuration found for the current "
+ "AP");
+ if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
+ WPA_KEY_MGMT_WPA_NONE)) {
+ u8 wpa_ie[80];
+ size_t wpa_ie_len = sizeof(wpa_ie);
+ wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+ wpa_ie, &wpa_ie_len);
+ } else {
+ wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+ }
+
+ wpa_s->current_ssid = ssid;
+ wpa_sm_set_config(wpa_s->wpa, wpa_s->current_ssid);
+ wpa_supplicant_initiate_eapol(wpa_s);
+
+ return 0;
+}
+
+
+static void wpa_supplicant_stop_countermeasures(void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+
+ if (wpa_s->countermeasures) {
+ wpa_s->countermeasures = 0;
+ wpa_drv_set_countermeasures(wpa_s, 0);
+ wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped");
+ wpa_supplicant_req_scan(wpa_s, 0, 0);
+ }
+}
+
+
+static 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);
+ 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)
+ eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+}
+
+
+static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
+{
+ struct wpa_ie_data ie;
+ int i, pmksa_set = -1;
+
+ if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
+ ie.pmkid == NULL)
+ return;
+
+ for (i = 0; i < ie.num_pmkid; i++) {
+ pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
+ ie.pmkid + i * PMKID_LEN,
+ NULL, NULL, 0);
+ if (pmksa_set == 0) {
+ eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+ break;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from PMKSA "
+ "cache", pmksa_set == 0 ? "" : "not ");
+}
+
+
+static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ if (data == NULL) {
+ wpa_printf(MSG_DEBUG, "RSN: No data in PMKID candidate event");
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR
+ " index=%d preauth=%d",
+ MAC2STR(data->pmkid_candidate.bssid),
+ data->pmkid_candidate.index,
+ data->pmkid_candidate.preauth);
+
+ pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid,
+ data->pmkid_candidate.index,
+ data->pmkid_candidate.preauth);
+}
+
+
+static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
+ return 0;
+
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+ wpa_s->current_ssid &&
+ !(wpa_s->current_ssid->eapol_flags &
+ (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+ EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
+ /* IEEE 802.1X, but not using dynamic WEP keys (i.e., either
+ * plaintext or static WEP keys). */
+ return 0;
+ }
+
+ return 1;
+}
+
+
+/**
+ * wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC
+ * @wpa_s: pointer to wpa_supplicant data
+ * @ssid: Configuration data for the network
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when starting authentication with a network that is
+ * configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA).
+ */
+int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
+{
+ int aka = 0, sim = 0, type;
+
+ if (ssid->pcsc == NULL || wpa_s->scard != NULL)
+ return 0;
+
+ if (ssid->eap_methods == NULL) {
+ 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;
+ eap++;
+ }
+ }
+
+#ifndef EAP_SIM
+ sim = 0;
+#endif /* EAP_SIM */
+#ifndef EAP_AKA
+ aka = 0;
+#endif /* EAP_AKA */
+
+ if (!sim && !aka) {
+ wpa_printf(MSG_DEBUG, "Selected network is configured to use "
+ "SIM, but neither EAP-SIM nor EAP-AKA are enabled");
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM "
+ "(sim=%d aka=%d) - initialize PCSC", sim, aka);
+ if (sim && aka)
+ type = SCARD_TRY_BOTH;
+ else if (aka)
+ type = SCARD_USIM_ONLY;
+ else
+ type = SCARD_GSM_SIM_ONLY;
+
+ wpa_s->scard = scard_init(type);
+ if (wpa_s->scard == NULL) {
+ wpa_printf(MSG_WARNING, "Failed to initialize SIM "
+ "(pcsc-lite)");
+ return -1;
+ }
+ wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+ eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+
+ return 0;
+}
+
+
+static int wpa_supplicant_match_privacy(struct wpa_scan_result *bss,
+ struct wpa_ssid *ssid)
+{
+ int i, privacy = 0;
+
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ if (ssid->wep_key_len[i]) {
+ privacy = 1;
+ break;
+ }
+ }
+ 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;
+
+ if (bss->caps & IEEE80211_CAP_PRIVACY)
+ return privacy;
+ return !privacy;
+}
+
+
+static int wpa_supplicant_ssid_bss_match(struct wpa_ssid *ssid,
+ struct wpa_scan_result *bss)
+{
+ struct wpa_ie_data ie;
+ int proto_match = 0;
+
+ while ((ssid->proto & WPA_PROTO_RSN) && bss->rsn_ie_len > 0) {
+ proto_match++;
+
+ if (wpa_parse_wpa_ie(bss->rsn_ie, bss->rsn_ie_len, &ie)) {
+ wpa_printf(MSG_DEBUG, " skip RSN IE - parse failed");
+ break;
+ }
+ if (!(ie.proto & ssid->proto)) {
+ wpa_printf(MSG_DEBUG, " skip RSN IE - proto "
+ "mismatch");
+ break;
+ }
+
+ if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
+ wpa_printf(MSG_DEBUG, " skip RSN IE - PTK cipher "
+ "mismatch");
+ break;
+ }
+
+ if (!(ie.group_cipher & ssid->group_cipher)) {
+ wpa_printf(MSG_DEBUG, " skip RSN IE - GTK cipher "
+ "mismatch");
+ break;
+ }
+
+ if (!(ie.key_mgmt & ssid->key_mgmt)) {
+ wpa_printf(MSG_DEBUG, " skip RSN IE - key mgmt "
+ "mismatch");
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, " selected based on RSN IE");
+ return 1;
+ }
+
+ while ((ssid->proto & WPA_PROTO_WPA) && bss->wpa_ie_len > 0) {
+ proto_match++;
+
+ if (wpa_parse_wpa_ie(bss->wpa_ie, bss->wpa_ie_len, &ie)) {
+ wpa_printf(MSG_DEBUG, " skip WPA IE - parse failed");
+ break;
+ }
+ if (!(ie.proto & ssid->proto)) {
+ wpa_printf(MSG_DEBUG, " skip WPA IE - proto "
+ "mismatch");
+ break;
+ }
+
+ if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
+ wpa_printf(MSG_DEBUG, " skip WPA IE - PTK cipher "
+ "mismatch");
+ break;
+ }
+
+ if (!(ie.group_cipher & ssid->group_cipher)) {
+ wpa_printf(MSG_DEBUG, " skip WPA IE - GTK cipher "
+ "mismatch");
+ break;
+ }
+
+ if (!(ie.key_mgmt & ssid->key_mgmt)) {
+ wpa_printf(MSG_DEBUG, " skip WPA IE - key mgmt "
+ "mismatch");
+ break;
+ }
+
+ wpa_printf(MSG_DEBUG, " selected based on WPA IE");
+ return 1;
+ }
+
+ if (proto_match == 0)
+ wpa_printf(MSG_DEBUG, " skip - no WPA/RSN proto match");
+
+ return 0;
+}
+
+
+static struct wpa_scan_result *
+wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
+ struct wpa_scan_result *results, int num,
+ struct wpa_ssid **selected_ssid)
+{
+ struct wpa_ssid *ssid;
+ struct wpa_scan_result *bss, *selected = NULL;
+ int i;
+ struct wpa_blacklist *e;
+
+ wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d",
+ group->priority);
+
+ bss = NULL;
+ ssid = NULL;
+ /* First, try to find WPA-enabled AP */
+ for (i = 0; i < num && !selected; i++) {
+ bss = &results[i];
+ 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);
+ if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
+ e->count > 1) {
+ wpa_printf(MSG_DEBUG, " skip - blacklisted");
+ continue;
+ }
+
+ if (bss->wpa_ie_len == 0 && bss->rsn_ie_len == 0) {
+ wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE");
+ continue;
+ }
+
+ for (ssid = group; ssid; ssid = ssid->pnext) {
+ if (ssid->disabled)
+ continue;
+ if (bss->ssid_len != ssid->ssid_len ||
+ 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) {
+ wpa_printf(MSG_DEBUG, " skip - "
+ "BSSID mismatch");
+ continue;
+ }
+ if (wpa_supplicant_ssid_bss_match(ssid, bss)) {
+ selected = bss;
+ *selected_ssid = ssid;
+ break;
+ }
+ }
+ }
+
+ /* If no WPA-enabled AP found, try to find non-WPA AP, if configuration
+ * allows this. */
+ for (i = 0; i < num && !selected; i++) {
+ bss = &results[i];
+ if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
+ e->count > 1) {
+ 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))
+ {
+ 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;
+ }
+ }
+ }
+
+ return selected;
+}
+
+
+static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
+{
+ int num, prio;
+ struct wpa_scan_result *selected = NULL;
+ struct wpa_ssid *ssid = NULL;
+ struct wpa_scan_result *results;
+
+ if (wpa_supplicant_get_scan_results(wpa_s) < 0) {
+ if (wpa_s->conf->ap_scan == 2)
+ return;
+ wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
+ "scanning again");
+ wpa_supplicant_req_scan(wpa_s, 1, 0);
+ return;
+ }
+ if (wpa_s->conf->ap_scan == 2)
+ return;
+ results = wpa_s->scan_results;
+ num = wpa_s->num_scan_results;
+
+ while (selected == NULL) {
+ for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
+ selected = wpa_supplicant_select_bss(
+ wpa_s, wpa_s->conf->pssid[prio], results, num,
+ &ssid);
+ if (selected)
+ break;
+ }
+
+ if (selected == NULL && wpa_s->blacklist) {
+ wpa_printf(MSG_DEBUG, "No APs found - clear blacklist "
+ "and try again");
+ wpa_blacklist_clear(wpa_s);
+ } else if (selected == NULL) {
+ break;
+ }
+ }
+
+ if (selected) {
+ if (wpa_s->reassociate ||
+ memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+ if (wpa_supplicant_scard_init(wpa_s, ssid)) {
+ wpa_supplicant_req_scan(wpa_s, 10, 0);
+ return;
+ }
+ wpa_supplicant_associate(wpa_s, selected, ssid);
+ } else {
+ wpa_printf(MSG_DEBUG, "Already associated with the "
+ "selected AP.");
+ }
+ 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);
+ }
+}
+
+
+static void wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ int l, len, found = 0, wpa_found, rsn_found;
+ u8 *p;
+
+ wpa_printf(MSG_DEBUG, "Association info event");
+ if (data->assoc_info.req_ies)
+ wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
+ data->assoc_info.req_ies_len);
+ if (data->assoc_info.resp_ies)
+ wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies,
+ data->assoc_info.resp_ies_len);
+ if (data->assoc_info.beacon_ies)
+ wpa_hexdump(MSG_DEBUG, "beacon_ies",
+ data->assoc_info.beacon_ies,
+ data->assoc_info.beacon_ies_len);
+
+ p = data->assoc_info.req_ies;
+ l = data->assoc_info.req_ies_len;
+
+ /* Go through the IEs and make a copy of the WPA/RSN IE, if present. */
+ while (p && l >= 2) {
+ len = p[1] + 2;
+ if (len > l) {
+ wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
+ p, l);
+ break;
+ }
+ if ((p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
+ (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;
+ found = 1;
+ wpa_find_assoc_pmkid(wpa_s);
+ break;
+ }
+ l -= len;
+ p += len;
+ }
+ if (!found && data->assoc_info.req_ies)
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+
+ /* WPA/RSN IE from Beacon/ProbeResp */
+ p = data->assoc_info.beacon_ies;
+ l = data->assoc_info.beacon_ies_len;
+
+ /* Go through the IEs and make a copy of the WPA/RSN IEs, if present.
+ */
+ wpa_found = rsn_found = 0;
+ while (p && l >= 2) {
+ len = p[1] + 2;
+ if (len > l) {
+ wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies",
+ p, l);
+ break;
+ }
+ if (!wpa_found &&
+ p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
+ 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);
+ }
+
+ if (!rsn_found &&
+ p[0] == RSN_INFO_ELEM && p[1] >= 2) {
+ rsn_found = 1;
+ wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
+ }
+
+ l -= len;
+ p += len;
+ }
+
+ if (!wpa_found && data->assoc_info.beacon_ies)
+ wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
+ if (!rsn_found && data->assoc_info.beacon_ies)
+ wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+}
+
+
+static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ u8 bssid[ETH_ALEN];
+
+ if (data)
+ 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) {
+ wpa_msg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
+ MACSTR, MAC2STR(bssid));
+ memcpy(wpa_s->bssid, bssid, ETH_ALEN);
+ if (wpa_supplicant_dynamic_keys(wpa_s)) {
+ wpa_clear_keys(wpa_s, bssid);
+ }
+ if (wpa_supplicant_select_config(wpa_s) < 0) {
+ wpa_supplicant_disassociate(wpa_s,
+ REASON_DEAUTH_LEAVING);
+ return;
+ }
+ }
+
+ wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid));
+ if (wpa_s->current_ssid) {
+ /* When using scanning (ap_scan=1), SIM PC/SC interface can be
+ * initialized before association, but for other modes,
+ * initialize PC/SC here, if the current configuration needs
+ * smartcard or SIM/USIM. */
+ wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid);
+ }
+ wpa_sm_notify_assoc(wpa_s->wpa, bssid);
+ l2_packet_notify_auth_start(wpa_s->l2);
+
+ /*
+ * Set portEnabled first to FALSE in order to get EAP state machine out
+ * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
+ * state machine may transit to AUTHENTICATING state based on obsolete
+ * eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
+ * AUTHENTICATED without ever giving chance to EAP state machine to
+ * reset the state.
+ */
+ 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)
+ eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+ /* 802.1X::portControl = Auto */
+ eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+ wpa_s->eapol_received = 0;
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ } else {
+ /* Timeout for receiving the first EAPOL packet */
+ wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
+ }
+}
+
+
+static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s)
+{
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+ /*
+ * At least Host AP driver and a Prism3 card seemed to be
+ * generating streams of disconnected events when configuring
+ * IBSS for WPA-None. Ignore them for now.
+ */
+ wpa_printf(MSG_DEBUG, "Disconnect event - ignore in "
+ "IBSS/WPA-None mode");
+ return;
+ }
+
+ if (wpa_s->wpa_state == WPA_4WAY_HANDSHAKE &&
+ wpa_s->key_mgmt == WPA_KEY_MGMT_PSK) {
+ wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
+ "pre-shared key may be incorrect");
+ }
+ if (wpa_s->wpa_state >= WPA_ASSOCIATED)
+ wpa_supplicant_req_scan(wpa_s, 0, 100000);
+ wpa_blacklist_add(wpa_s, 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);
+ }
+}
+
+
+static void
+wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
+ union wpa_event_data *data)
+{
+ int pairwise;
+ time_t now;
+
+ 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);
+ if (wpa_s->last_michael_mic_error &&
+ now - wpa_s->last_michael_mic_error <= 60) {
+ /* initialize countermeasures */
+ wpa_s->countermeasures = 1;
+ wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
+
+ /*
+ * 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);
+
+ wpa_drv_set_countermeasures(wpa_s, 1);
+ wpa_supplicant_deauthenticate(wpa_s,
+ REASON_MICHAEL_MIC_FAILURE);
+ eloop_cancel_timeout(wpa_supplicant_stop_countermeasures,
+ wpa_s, NULL);
+ eloop_register_timeout(60, 0,
+ wpa_supplicant_stop_countermeasures,
+ wpa_s, NULL);
+ /* TODO: mark the AP rejected for 60 second. STA is
+ * allowed to associate with another AP.. */
+ }
+ wpa_s->last_michael_mic_error = now;
+}
+
+
+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)
+ return;
+
+ switch (data->interface_status.ievent) {
+ case EVENT_INTERFACE_ADDED:
+ if (!wpa_s->interface_removed)
+ break;
+ wpa_s->interface_removed = 0;
+ wpa_printf(MSG_DEBUG, "Configured interface was added.");
+ if (wpa_supplicant_driver_init(wpa_s, 1) < 0) {
+ wpa_printf(MSG_INFO, "Failed to initialize the driver "
+ "after interface was added.");
+ }
+ break;
+ case EVENT_INTERFACE_REMOVED:
+ wpa_printf(MSG_DEBUG, "Configured interface was removed.");
+ wpa_s->interface_removed = 1;
+ wpa_supplicant_mark_disassoc(wpa_s);
+ l2_packet_deinit(wpa_s->l2);
+ wpa_s->l2 = NULL;
+ break;
+ }
+}
+
+
+void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
+ union wpa_event_data *data)
+{
+ switch (event) {
+ case EVENT_ASSOC:
+ wpa_supplicant_event_assoc(wpa_s, data);
+ break;
+ case EVENT_DISASSOC:
+ wpa_supplicant_event_disassoc(wpa_s);
+ break;
+ case EVENT_MICHAEL_MIC_FAILURE:
+ wpa_supplicant_event_michael_mic_failure(wpa_s, data);
+ break;
+ case EVENT_SCAN_RESULTS:
+ wpa_supplicant_event_scan_results(wpa_s);
+ break;
+ case EVENT_ASSOCINFO:
+ wpa_supplicant_event_associnfo(wpa_s, data);
+ break;
+ case EVENT_INTERFACE_STATUS:
+ wpa_supplicant_event_interface_status(wpa_s, data);
+ break;
+ case EVENT_PMKID_CANDIDATE:
+ wpa_supplicant_event_pmkid_candidate(wpa_s, data);
+ break;
+ default:
+ wpa_printf(MSG_INFO, "Unknown event %d", event);
+ break;
+ }
+}
diff --git a/contrib/wpa_supplicant/examples/ieee8021x.conf b/contrib/wpa_supplicant/examples/ieee8021x.conf
new file mode 100644
index 0000000..e8a5503
--- /dev/null
+++ b/contrib/wpa_supplicant/examples/ieee8021x.conf
@@ -0,0 +1,13 @@
+# IEEE 802.1X with dynamic WEP keys using EAP-PEAP/MSCHAPv2
+
+ctrl_interface=/var/run/wpa_supplicant
+
+network={
+ ssid="example 802.1x network"
+ key_mgmt=IEEE8021X
+ eap=PEAP
+ phase2="auth=MSCHAPV2"
+ identity="user name"
+ password="password"
+ ca_cert="/etc/cert/ca.pem"
+}
diff --git a/contrib/wpa_supplicant/examples/plaintext.conf b/contrib/wpa_supplicant/examples/plaintext.conf
new file mode 100644
index 0000000..542ac1d
--- /dev/null
+++ b/contrib/wpa_supplicant/examples/plaintext.conf
@@ -0,0 +1,8 @@
+# Plaintext (no encryption) network
+
+ctrl_interface=/var/run/wpa_supplicant
+
+network={
+ ssid="example open network"
+ key_mgmt=NONE
+}
diff --git a/contrib/wpa_supplicant/examples/wep.conf b/contrib/wpa_supplicant/examples/wep.conf
new file mode 100644
index 0000000..9c7b55f
--- /dev/null
+++ b/contrib/wpa_supplicant/examples/wep.conf
@@ -0,0 +1,11 @@
+# Static WEP keys
+
+ctrl_interface=/var/run/wpa_supplicant
+
+network={
+ ssid="example wep network"
+ key_mgmt=NONE
+ wep_key0="abcde"
+ wep_key1=0102030405
+ wep_tx_keyidx=0
+}
diff --git a/contrib/wpa_supplicant/examples/wpa-psk-tkip.conf b/contrib/wpa_supplicant/examples/wpa-psk-tkip.conf
new file mode 100644
index 0000000..93d7fc2
--- /dev/null
+++ b/contrib/wpa_supplicant/examples/wpa-psk-tkip.conf
@@ -0,0 +1,12 @@
+# WPA-PSK/TKIP
+
+ctrl_interface=/var/run/wpa_supplicant
+
+network={
+ ssid="example wpa-psk network"
+ key_mgmt=WPA-PSK
+ proto=WPA
+ pairwise=TKIP
+ group=TKIP
+ psk="secret passphrase"
+}
diff --git a/contrib/wpa_supplicant/examples/wpa2-eap-ccmp.conf b/contrib/wpa_supplicant/examples/wpa2-eap-ccmp.conf
new file mode 100644
index 0000000..d7a64d8
--- /dev/null
+++ b/contrib/wpa_supplicant/examples/wpa2-eap-ccmp.conf
@@ -0,0 +1,15 @@
+# WPA2-EAP/CCMP using EAP-TLS
+
+ctrl_interface=/var/run/wpa_supplicant
+
+network={
+ ssid="example wpa2-eap network"
+ key_mgmt=WPA-EAP
+ proto=WPA2
+ pairwise=CCMP
+ group=CCMP
+ eap=TLS
+ ca_cert="/etc/cert/ca.pem"
+ private_key="/etc/cert/user.p12"
+ private_key_passwd="PKCS#12 passhrase"
+}
diff --git a/contrib/wpa_supplicant/hostapd.h b/contrib/wpa_supplicant/hostapd.h
new file mode 100644
index 0000000..ce1fae9
--- /dev/null
+++ b/contrib/wpa_supplicant/hostapd.h
@@ -0,0 +1,38 @@
+#ifndef HOSTAPD_H
+#define HOSTAPD_H
+
+/*
+ * Minimal version of hostapd header files for eapol_test to build
+ * radiusclient.c.
+ */
+
+#include "common.h"
+
+void hostapd_logger(void *ctx, u8 *addr, unsigned int module, int level,
+ char *fmt, ...) __attribute__ ((format (printf, 5, 6)));
+
+struct hostapd_ip_addr;
+
+const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
+ size_t buflen);;
+
+enum {
+ HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
+ HOSTAPD_LEVEL_DEBUG = 1,
+ HOSTAPD_LEVEL_INFO = 2,
+ HOSTAPD_LEVEL_NOTICE = 3,
+ HOSTAPD_LEVEL_WARNING = 4
+};
+
+#ifndef BIT
+#define BIT(n) (1 << (n))
+#endif
+
+#define HOSTAPD_MODULE_IEEE80211 BIT(0)
+#define HOSTAPD_MODULE_IEEE8021X BIT(1)
+#define HOSTAPD_MODULE_RADIUS BIT(2)
+#define HOSTAPD_MODULE_WPA BIT(3)
+#define HOSTAPD_MODULE_DRIVER BIT(4)
+#define HOSTAPD_MODULE_IAPP BIT(5)
+
+#endif /* HOSTAPD_H */
diff --git a/contrib/wpa_supplicant/l2_packet.h b/contrib/wpa_supplicant/l2_packet.h
index 3e3914c..eb966d3 100644
--- a/contrib/wpa_supplicant/l2_packet.h
+++ b/contrib/wpa_supplicant/l2_packet.h
@@ -1,3 +1,23 @@
+/*
+ * WPA Supplicant - Layer2 packet interface definition
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 defines an interface for layer 2 (link layer) packet sending and
+ * receiving. l2_packet_linux.c is one implementation for such a layer 2
+ * implementation using Linux packet sockets and l2_packet_pcap.c another one
+ * using libpcap and libdnet. When porting %wpa_supplicant to other operating
+ * systems, a new l2_packet implementation may need to be added.
+ */
+
#ifndef L2_PACKET_H
#define L2_PACKET_H
@@ -12,6 +32,14 @@
#define ETH_P_RSN_PREAUTH 0x88c7
#endif
+/**
+ * struct l2_packet_data - Internal l2_packet data structure
+ *
+ * This structure is used by the l2_packet implementation to store its private
+ * data. Other files use a pointer to this data when calling the l2_packet
+ * functions, but the contents of this structure should not be used directly
+ * outside l2_packet implementation.
+ */
struct l2_packet_data;
struct l2_ethhdr {
@@ -20,15 +48,86 @@ struct l2_ethhdr {
u16 h_proto;
} __attribute__ ((packed));
+/**
+ * l2_packet_init - Initialize l2_packet interface
+ * @ifname: Interface name
+ * @own_addr: Optional own MAC address if available from driver interface or
+ * %NULL if not available
+ * @protocol: Ethernet protocol number in host byte order
+ * @rx_callback: Callback function that will be called for each received packet
+ * @rx_callback_ctx: Callback data (ctx) for calls to rx_callback()
+ * @l2_hdr: 1 = include layer 2 header, 0 = do not include header
+ * Returns: Pointer to internal data or %NULL on failure
+ *
+ * rx_callback function will be called with src_addr pointing to the source
+ * address (MAC address) of the the packet. If l2_hdr is set to 0, buf
+ * points to len bytes of the payload after the layer 2 header and similarly,
+ * TX buffers start with payload. This behavior can be changed by setting
+ * l2_hdr=1 to include the layer 2 header in the data buffer.
+ */
struct l2_packet_data * l2_packet_init(
const char *ifname, const u8 *own_addr, unsigned short protocol,
- void (*rx_callback)(void *ctx, unsigned char *src_addr,
- unsigned char *buf, size_t len),
- void *rx_callback_ctx);
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr);
+
+/**
+ * l2_packet_deinit - Deinitialize l2_packet interface
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ */
void l2_packet_deinit(struct l2_packet_data *l2);
+/**
+ * l2_packet_get_own_addr - Get own layer 2 address
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @addr: Buffer for the own address (6 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr);
-int l2_packet_send(struct l2_packet_data *l2, u8 *buf, size_t len);
-void l2_packet_set_rx_l2_hdr(struct l2_packet_data *l2, int rx_l2_hdr);
+
+/**
+ * l2_packet_send - Send a packet
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @dst_addr: Destination address for the packet (only used if l2_hdr == 0)
+ * @proto: Protocol/ethertype for the packet in host byte order (only used if
+ * l2_hdr == 0)
+ * @buf: Packet contents to be sent; including layer 2 header if l2_hdr was
+ * set to 1 in l2_packet_init() call. Otherwise, only the payload of the packet
+ * is included.
+ * @len: Length of the buffer (including l2 header only if l2_hdr == 1)
+ * Returns: >=0 on success, <0 on failure
+ */
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len);
+
+/**
+ * l2_packet_get_ip_addr - Get the current IP address from the interface
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @buf: Buffer for the IP address in text format
+ * @len: Maximum buffer length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to get the current IP address from the interface
+ * bound to the l2_packet. This is mainly for status information and the IP
+ * address will be stored as an ASCII string. This function is not essential
+ * for %wpa_supplicant operation, so full implementation is not required.
+ * l2_packet implementation will need to define the function, but it can return
+ * -1 if the IP address information is not available.
+ */
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len);
+
+
+/**
+ * l2_packet_notify_auth_start - Notify l2_packet about start of authentication
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ *
+ * This function is called when authentication is expected to start, e.g., when
+ * association has been completed, in order to prepare l2_packet implementation
+ * for EAPOL frames. This function is used mainly if the l2_packet code needs
+ * to do polling in which case it can increasing polling frequency. This can
+ * also be an empty function if the l2_packet implementation does not benefit
+ * from knowing about the starting authentication.
+ */
+void l2_packet_notify_auth_start(struct l2_packet_data *l2);
#endif /* L2_PACKET_H */
diff --git a/contrib/wpa_supplicant/main.c b/contrib/wpa_supplicant/main.c
new file mode 100644
index 0000000..8d82666
--- /dev/null
+++ b/contrib/wpa_supplicant/main.c
@@ -0,0 +1,250 @@
+/*
+ * WPA Supplicant / main() function for UNIX like OSes and MinGW
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+
+
+extern const char *wpa_supplicant_version;
+extern const char *wpa_supplicant_license;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+extern const char *wpa_supplicant_full_license;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+extern struct wpa_driver_ops *wpa_supplicant_drivers[];
+
+
+static void usage(void)
+{
+ int i;
+ printf("%s\n\n%s\n"
+ "usage:\n"
+ " wpa_supplicant [-BddehLqqvwW] [-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"
+ "\n"
+ "drivers:\n",
+ wpa_supplicant_version, wpa_supplicant_license);
+
+ for (i = 0; wpa_supplicant_drivers[i]; i++) {
+ printf(" %s = %s\n",
+ wpa_supplicant_drivers[i]->name,
+ wpa_supplicant_drivers[i]->desc);
+ }
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ printf("options:\n"
+ " -B = run daemon in the background\n"
+ " -c = Configuration file\n"
+ " -C = ctrl_interface parameter (only used if -c is not)\n"
+ " -i = interface name\n"
+ " -d = increase debugging verbosity (-dd even more)\n"
+ " -D = driver name\n"
+ " -g = global ctrl_interface\n"
+ " -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"
+ " -P = PID file\n"
+ " -q = decrease debugging verbosity (-qq even less)\n"
+ " -v = show version\n"
+ " -w = wait for interface to be added, if needed\n"
+ " -W = wait for a control interface monitor before starting\n"
+ " -N = start describing new interface\n");
+
+ printf("example:\n"
+ " wpa_supplicant -Dwext -iwlan0 -c/etc/wpa_supplicant.conf\n");
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static void license(void)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ printf("%s\n\n%s\n",
+ wpa_supplicant_version, wpa_supplicant_full_license);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static void wpa_supplicant_fd_workaround(void)
+{
+ 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
+ * places in wpa_supplicant are still printing out to stdout. As a
+ * workaround, make sure that fd's 0, 1, and 2 are not used for other
+ * sockets. */
+ for (i = 0; i < 3; i++) {
+ s = open("/dev/null", O_RDWR);
+ if (s > 2) {
+ close(s);
+ break;
+ }
+ }
+}
+
+
+int main(int argc, char *argv[])
+{
+ int c, i;
+ struct wpa_interface *ifaces, *iface;
+ int iface_count, exitcode;
+ 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");
+ return -1;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ memset(&params, 0, sizeof(params));
+ params.wpa_debug_level = MSG_INFO;
+
+ iface = ifaces = malloc(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");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'B':
+ params.daemonize++;
+ break;
+ case 'c':
+ iface->confname = optarg;
+ break;
+ case 'C':
+ iface->ctrl_interface = optarg;
+ break;
+ case 'D':
+ iface->driver = optarg;
+ break;
+ case 'd':
+#ifdef CONFIG_NO_STDOUT_DEBUG
+ printf("Debugging disabled with "
+ "CONFIG_NO_STDOUT_DEBUG=y build time "
+ "option.\n");
+ return -1;
+#else /* CONFIG_NO_STDOUT_DEBUG */
+ params.wpa_debug_level--;
+ break;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+ case 'g':
+ params.ctrl_interface = optarg;
+ break;
+ case 'h':
+ usage();
+ return -1;
+ case 'i':
+ iface->ifname = optarg;
+ break;
+ case 'K':
+ params.wpa_debug_show_keys++;
+ break;
+ case 'L':
+ license();
+ return -1;
+ case 'p':
+ iface->driver_param = optarg;
+ break;
+ case 'P':
+ params.pid_file = rel2abs_path(optarg);
+ break;
+ case 'q':
+ params.wpa_debug_level++;
+ break;
+ case 't':
+ params.wpa_debug_timestamp++;
+ break;
+ case 'v':
+ printf("%s\n", wpa_supplicant_version);
+ return -1;
+ case 'w':
+ params.wait_for_interface++;
+ break;
+ case 'W':
+ params.wait_for_monitor++;
+ break;
+ case 'N':
+ iface_count++;
+ iface = realloc(ifaces, iface_count *
+ sizeof(struct wpa_interface));
+ if (iface == NULL) {
+ free(ifaces);
+ return -1;
+ }
+ ifaces = iface;
+ iface = &ifaces[iface_count - 1];
+ memset(iface, 0, sizeof(*iface));
+ break;
+ default:
+ usage();
+ return -1;
+ }
+ }
+
+ exitcode = 0;
+ global = wpa_supplicant_init(&params);
+ if (global == NULL) {
+ printf("Failed to initialize wpa_supplicant\n");
+ exitcode = -1;
+ }
+
+ 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)
+ break;
+ usage();
+ return -1;
+ }
+ if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+ exitcode = -1;
+ }
+
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_run(global);
+
+ wpa_supplicant_deinit(global);
+
+ free(ifaces);
+ free(params.pid_file);
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ return exitcode;
+}
diff --git a/contrib/wpa_supplicant/md5.c b/contrib/wpa_supplicant/md5.c
index 1564e8f..82388e0 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-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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,36 +18,38 @@
#include "common.h"
#include "md5.h"
+#include "crypto.h"
-void md5_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
- u8 *mac)
-{
- MD5_CTX context;
- MD5Init(&context);
- MD5Update(&context, key, key_len);
- MD5Update(&context, data, data_len);
- MD5Update(&context, key, key_len);
- MD5Final(mac, &context);
-}
-
-
-/* HMAC code is based on RFC 2104 */
+/**
+ * hmac_md5_vector - HMAC-MD5 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 (16 bytes)
+ */
void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
- MD5_CTX context;
- u8 k_ipad[65]; /* inner padding - key XORd with ipad */
- u8 k_opad[65]; /* outer padding - key XORd with opad */
+ u8 k_pad[64]; /* padding - key XORd with ipad/opad */
u8 tk[16];
int i;
+ const u8 *_addr[6];
+ size_t _len[6];
+
+ 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 = MD5(key) */
if (key_len > 64) {
- MD5Init(&context);
- MD5Update(&context, key, key_len);
- MD5Final(tk, &context);
-
+ md5_vector(1, &key, &key_len, tk);
key = tk;
key_len = 16;
}
@@ -61,35 +63,46 @@ void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected */
- /* start out by storing key in pads */
- memset(k_ipad, 0, sizeof(k_ipad));
- memset(k_opad, 0, sizeof(k_opad));
- memcpy(k_ipad, key, key_len);
- memcpy(k_opad, key, key_len);
+ /* start out by storing key in ipad */
+ memset(k_pad, 0, sizeof(k_pad));
+ memcpy(k_pad, key, key_len);
- /* XOR key with ipad and opad values */
- for (i = 0; i < 64; i++) {
- k_ipad[i] ^= 0x36;
- k_opad[i] ^= 0x5c;
- }
+ /* XOR key with ipad values */
+ for (i = 0; i < 64; i++)
+ k_pad[i] ^= 0x36;
/* perform inner MD5 */
- MD5Init(&context); /* init context for 1st pass */
- MD5Update(&context, k_ipad, 64); /* start with inner pad */
- /* then text of datagram; all fragments */
+ _addr[0] = k_pad;
+ _len[0] = 64;
for (i = 0; i < num_elem; i++) {
- MD5Update(&context, addr[i], len[i]);
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
}
- MD5Final(mac, &context); /* finish up 1st pass */
+ md5_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 MD5 */
- MD5Init(&context); /* init context for 2nd pass */
- MD5Update(&context, k_opad, 64); /* start with outer pad */
- MD5Update(&context, mac, 16); /* then results of 1st hash */
- MD5Final(mac, &context); /* finish up 2nd pass */
+ _addr[0] = k_pad;
+ _len[0] = 64;
+ _addr[1] = mac;
+ _len[1] = MD5_MAC_LEN;
+ md5_vector(2, _addr, _len, mac);
}
+/**
+ * hmac_md5 - HMAC-MD5 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 (16 bytes)
+ */
void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac)
{
@@ -99,6 +112,40 @@ void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
#ifndef EAP_TLS_FUNCS
+struct MD5Context {
+ u32 buf[4];
+ u32 bits[2];
+ u8 in[64];
+};
+
+static void MD5Init(struct MD5Context *context);
+static void MD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+static void MD5Final(unsigned char digest[16], struct MD5Context *context);
+static void MD5Transform(u32 buf[4], u32 const in[16]);
+
+typedef struct MD5Context MD5_CTX;
+
+
+/**
+ * md5_vector - MD5 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ */
+void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+ MD5_CTX ctx;
+ int i;
+
+ MD5Init(&ctx);
+ for (i = 0; i < num_elem; i++)
+ MD5Update(&ctx, addr[i], len[i]);
+ MD5Final(mac, &ctx);
+}
+
+
/* ===== start - public domain MD5 implementation ===== */
/*
* This code implements the MD5 message-digest algorithm.
@@ -120,13 +167,10 @@ void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
#ifndef WORDS_BIGENDIAN
#define byteReverse(buf, len) /* Nothing */
#else
-void byteReverse(unsigned char *buf, unsigned longs);
-
-#ifndef ASM_MD5
/*
* Note: this code is harmless on little-endian machines.
*/
-void byteReverse(unsigned char *buf, unsigned longs)
+static void byteReverse(unsigned char *buf, unsigned longs)
{
u32 t;
do {
@@ -137,13 +181,12 @@ void byteReverse(unsigned char *buf, unsigned longs)
} while (--longs);
}
#endif
-#endif
/*
* Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
* initialization constants.
*/
-void MD5Init(struct MD5Context *ctx)
+static void MD5Init(struct MD5Context *ctx)
{
ctx->buf[0] = 0x67452301;
ctx->buf[1] = 0xefcdab89;
@@ -158,7 +201,8 @@ void MD5Init(struct MD5Context *ctx)
* Update context to reflect the concatenation of another buffer full
* of bytes.
*/
-void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+static void MD5Update(struct MD5Context *ctx, unsigned char const *buf,
+ unsigned len)
{
u32 t;
@@ -206,7 +250,7 @@ void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
* Final wrapup - pad to 64-byte boundary with the bit pattern
* 1 0* (64-bit count of bits processed, MSB-first)
*/
-void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
{
unsigned count;
unsigned char *p;
@@ -247,8 +291,6 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
}
-#ifndef ASM_MD5
-
/* The four core functions - F1 is optimized somewhat */
/* #define F1(x, y, z) (x & y | ~x & z) */
@@ -266,7 +308,7 @@ void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
* reflect the addition of 16 longwords of new data. MD5Update blocks
* the data and converts bytes into longwords for this routine.
*/
-void MD5Transform(u32 buf[4], u32 const in[16])
+static void MD5Transform(u32 buf[4], u32 const in[16])
{
register u32 a, b, c, d;
@@ -348,8 +390,6 @@ void MD5Transform(u32 buf[4], u32 const in[16])
buf[2] += c;
buf[3] += d;
}
-
-#endif
/* ===== end - public domain MD5 implementation ===== */
#endif /* !EAP_TLS_FUNCS */
diff --git a/contrib/wpa_supplicant/md5.h b/contrib/wpa_supplicant/md5.h
index cc3eb95..a724804 100644
--- a/contrib/wpa_supplicant/md5.h
+++ b/contrib/wpa_supplicant/md5.h
@@ -1,40 +1,22 @@
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 MD5_H
#define MD5_H
-#ifdef EAP_TLS_FUNCS
-
-#include <openssl/md5.h>
-
-#define MD5Init MD5_Init
-#define MD5Update MD5_Update
-#define MD5Final MD5_Final
-#define MD5Transform MD5_Transform
-
-#define MD5_MAC_LEN MD5_DIGEST_LENGTH
-
-#else /* EAP_TLS_FUNCS */
-
#define MD5_MAC_LEN 16
-struct MD5Context {
- u32 buf[4];
- u32 bits[2];
- u8 in[64];
-};
-
-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);
-void MD5Transform(u32 buf[4], u32 const in[16]);
-
-typedef struct MD5Context MD5_CTX;
-
-#endif /* EAP_TLS_FUNCS */
-
-
-void md5_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
- u8 *mac);
void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
diff --git a/contrib/wpa_supplicant/ms_funcs.c b/contrib/wpa_supplicant/ms_funcs.c
index 590b589..c26cddf 100644
--- a/contrib/wpa_supplicant/ms_funcs.c
+++ b/contrib/wpa_supplicant/ms_funcs.c
@@ -20,10 +20,19 @@
#include "sha1.h"
#include "ms_funcs.h"
#include "crypto.h"
+#include "rc4.h"
-static void challenge_hash(u8 *peer_challenge, u8 *auth_challenge,
- u8 *username, size_t username_len,
+/**
+ * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @challenge: 8-octet Challenge (OUT)
+ */
+static void challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
+ const u8 *username, size_t username_len,
u8 *challenge)
{
u8 hash[SHA1_MAC_LEN];
@@ -42,10 +51,18 @@ static void challenge_hash(u8 *peer_challenge, u8 *auth_challenge,
}
-void nt_password_hash(u8 *password, size_t password_len, u8 *password_hash)
+/**
+ * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
+ * @password: 0-to-256-unicode-char Password (IN)
+ * @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;
/* Convert password into unicode */
buf = malloc(password_len * 2);
@@ -55,18 +72,32 @@ void nt_password_hash(u8 *password, size_t password_len, u8 *password_hash)
for (i = 0; i < password_len; i++)
buf[2 * i] = password[i];
- md4(buf, password_len * 2, password_hash);
+ len = password_len * 2;
+ md4_vector(1, (const u8 **) &buf, &len, password_hash);
free(buf);
}
-void hash_nt_password_hash(u8 *password_hash, u8 *password_hash_hash)
+/**
+ * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @password_hash_hash: 16-octet PaswordHashHash (OUT)
+ */
+void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
{
- md4(password_hash, 16, password_hash_hash);
+ size_t len = 16;
+ md4_vector(1, &password_hash, &len, password_hash_hash);
}
-void challenge_response(u8 *challenge, u8 *password_hash, u8 *response)
+/**
+ * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
+ * @challenge: 8-octet Challenge (IN)
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @response: 24-octet Response (OUT)
+ */
+void challenge_response(const u8 *challenge, const u8 *password_hash,
+ u8 *response)
{
u8 zpwd[7];
des_encrypt(challenge, password_hash, response);
@@ -78,9 +109,19 @@ void challenge_response(u8 *challenge, u8 *password_hash, u8 *response)
}
-void generate_nt_response(u8 *auth_challenge, u8 *peer_challenge,
- u8 *username, size_t username_len,
- u8 *password, size_t password_len,
+/**
+ * generate_nt_response - 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: 0-to-256-unicode-char Password (IN)
+ * @password_len: Length of password
+ * @response: 24-octet Response (OUT)
+ */
+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)
{
u8 challenge[8];
@@ -93,11 +134,22 @@ void generate_nt_response(u8 *auth_challenge, u8 *peer_challenge,
}
-void generate_authenticator_response(u8 *password, size_t password_len,
- u8 *peer_challenge,
- u8 *auth_challenge,
- u8 *username, size_t username_len,
- u8 *nt_response, u8 *response)
+/**
+ * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password: 0-to-256-unicode-char Password (IN)
+ * @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: 42-octet AuthenticatorResponse (OUT)
+ */
+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)
{
static const u8 magic1[39] = {
0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
@@ -137,8 +189,15 @@ void generate_authenticator_response(u8 *password, size_t password_len,
}
-void nt_challenge_response(u8 *challenge, u8 *password, size_t password_len,
- u8 *response)
+/**
+ * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
+ * @challenge: 8-octet Challenge (IN)
+ * @password: 0-to-256-unicode-char Password (IN)
+ * @password_len: Length of password
+ * @response: 24-octet Response (OUT)
+ */
+void nt_challenge_response(const u8 *challenge, const u8 *password,
+ size_t password_len, u8 *response)
{
u8 password_hash[16];
nt_password_hash(password, password_len, password_hash);
@@ -146,8 +205,12 @@ void nt_challenge_response(u8 *challenge, u8 *password, size_t password_len,
}
-/* IN: 16-octet password_hash_hash and 24-octet nt_response
- * OUT: 16-octet master_key */
+/**
+ * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
+ * @password_hash_hash: 16-octet PasswordHashHash (IN)
+ * @nt_response: 24-octet NTResponse (IN)
+ * @master_key: 16-octet MasterKey (OUT)
+ */
void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
u8 *master_key)
{
@@ -169,6 +232,14 @@ 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)
+ * @is_send: IsSend (IN, BOOLEAN)
+ * @is_server: IsServer (IN, BOOLEAN)
+ */
void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
size_t session_key_len, int is_send,
int is_server)
@@ -229,7 +300,98 @@ void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
}
+#define PWBLOCK_LEN 516
+
+/**
+ * encrypt_pw_block_with_password_hash - EncryptPwBlobkWithPasswordHash() - RFC 2759, Sect. 8.10
+ * @password: 0-to-256-unicode-char Password (IN)
+ * @password_len: Length of password
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @pw_block: 516-byte PwBlock (OUT)
+ */
+static void encrypt_pw_block_with_password_hash(
+ const u8 *password, size_t password_len,
+ const u8 *password_hash, u8 *pw_block)
+{
+ size_t i, offset;
+ u8 *pos;
+
+ if (password_len > 256)
+ return;
+
+ memset(pw_block, 0, PWBLOCK_LEN);
+ offset = (256 - password_len) * 2;
+ for (i = 0; i < password_len; i++)
+ pw_block[offset + i * 2] = password[i];
+ pos = &pw_block[2 * 256];
+ WPA_PUT_LE16(pos, password_len * 2);
+ rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
+}
+
+
+/**
+ * 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_len: Length of new_password
+ * @old_password: 0-to-256-unicode-char OldPassword (IN)
+ * @old_password_len: Length of old_password
+ * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
+ */
+void new_password_encrypted_with_old_nt_password_hash(
+ const u8 *new_password, size_t new_password_len,
+ const u8 *old_password, size_t old_password_len,
+ u8 *encrypted_pw_block)
+{
+ u8 password_hash[16];
+
+ nt_password_hash(old_password, old_password_len, password_hash);
+ encrypt_pw_block_with_password_hash(new_password, new_password_len,
+ password_hash, encrypted_pw_block);
+}
+
+
+/**
+ * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
+ * @password_hash: 16-octer PasswordHash (IN)
+ * @block: 16-octet Block (IN)
+ * @cypher: 16-octer Cypher (OUT)
+ */
+static void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+ const u8 *block,
+ u8 *cypher)
+{
+ des_encrypt(password_hash, block, cypher);
+ des_encrypt(password_hash + 8, block + 7, cypher + 8);
+}
+
+
+/**
+ * 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_len: Length of new_password
+ * @old_password: 0-to-256-unicode-char OldPassword (IN)
+ * @old_password_len: Length of old_password
+ * @encrypted_password_ash: 16-octet EncryptedPasswordHash (OUT)
+ */
+void old_nt_password_hash_encrypted_with_new_nt_password_hash(
+ const u8 *new_password, size_t new_password_len,
+ const u8 *old_password, size_t old_password_len,
+ u8 *encrypted_password_hash)
+{
+ u8 old_password_hash[16], new_password_hash[16];
+
+ nt_password_hash(old_password, old_password_len, old_password_hash);
+ nt_password_hash(new_password, new_password_len, new_password_hash);
+ nt_password_hash_encrypted_with_block(old_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 */
diff --git a/contrib/wpa_supplicant/ms_funcs.h b/contrib/wpa_supplicant/ms_funcs.h
index a08ab06..38d1bd6 100644
--- a/contrib/wpa_supplicant/ms_funcs.h
+++ b/contrib/wpa_supplicant/ms_funcs.h
@@ -1,25 +1,50 @@
+/*
+ * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 MS_FUNCS_H
#define MS_FUNCS_H
-void generate_nt_response(u8 *auth_challenge, u8 *peer_challenge,
- u8 *username, size_t username_len,
- u8 *password, size_t password_len,
+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_authenticator_response(u8 *password, size_t password_len,
- u8 *peer_challenge,
- u8 *auth_challenge,
- u8 *username, size_t username_len,
- u8 *nt_response, u8 *response);
-void nt_challenge_response(u8 *challenge, u8 *password, size_t password_len,
- 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 nt_challenge_response(const u8 *challenge, const u8 *password,
+ size_t password_len, u8 *response);
-void challenge_response(u8 *challenge, u8 *password_hash, u8 *response);
-void nt_password_hash(u8 *password, size_t password_len, u8 *password_hash);
-void hash_nt_password_hash(u8 *password_hash, u8 *password_hash_hash);
+void challenge_response(const u8 *challenge, const u8 *password_hash,
+ u8 *response);
+void nt_password_hash(const u8 *password, size_t password_len,
+ u8 *password_hash);
+void hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
void get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
u8 *master_key);
void get_asymetric_start_key(const u8 *master_key, u8 *session_key,
size_t session_key_len, int is_send,
int is_server);
+void new_password_encrypted_with_old_nt_password_hash(
+ const u8 *new_password, size_t new_password_len,
+ const u8 *old_password, size_t old_password_len,
+ u8 *encrypted_pw_block);
+void old_nt_password_hash_encrypted_with_new_nt_password_hash(
+ const u8 *new_password, size_t new_password_len,
+ const u8 *old_password, size_t old_password_len,
+ u8 *encrypted_password_hash);
+
#endif /* MS_FUNCS_H */
diff --git a/contrib/wpa_supplicant/openssl-tls-extensions.patch b/contrib/wpa_supplicant/openssl-tls-extensions.patch
index 77e9a41..44490cc 100644
--- a/contrib/wpa_supplicant/openssl-tls-extensions.patch
+++ b/contrib/wpa_supplicant/openssl-tls-extensions.patch
@@ -1,166 +1,429 @@
-This is a quick hack for testing EAP-FAST with openssl.
+This patch is adding support for TLS hello extensions and externally
+generated pre-shared key material to OpenSSL 0.9.8. 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).
-Addition of TLS extensions to ClientHello/ServerHello is more or less
-ok, though not very clean in the way that the caller needs to take
-care of constructing set of all extensions. In addition there is not
-mechanism for reading the TLS extensions, i.e., this would not be
-enough for EAP-FAST authenticator.
-Rest of the changes are obviously ugly and/or incorrect for most
-parts, but it demonstrates the minimum set of changes to skip some of
-the error cases that prevented completion of TLS handshake without
-certificates. In other words, this is just a proof-of-concept type of
-example to make it possible to experiment with EAP-FAST. Cleaner patch
-for the needed functionality would be welcome..
-
-diff -upr openssl-0.9.7e.orig/include/openssl/ssl.h openssl-0.9.7e/include/openssl/ssl.h
---- openssl-0.9.7e.orig/include/openssl/ssl.h 2004-07-27 11:28:49.000000000 -0700
-+++ openssl-0.9.7e/include/openssl/ssl.h 2004-12-24 20:29:01.000000000 -0800
-@@ -929,6 +929,11 @@ struct ssl_st
+diff -uprN openssl-0.9.8.orig/include/openssl/ssl.h openssl-0.9.8/include/openssl/ssl.h
+--- openssl-0.9.8.orig/include/openssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
++++ openssl-0.9.8/include/openssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
+@@ -340,6 +340,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
+@@ -361,6 +362,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
+ {
+@@ -968,6 +971,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
-+ /* Optional ClientHello/ServerHello extension to be added to the end
-+ * of the SSLv3/TLS hello message. */
-+ char *hello_extension;
-+ int hello_extension_len;
++ /* 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
-diff -upr openssl-0.9.7e.orig/ssl/s3_both.c openssl-0.9.7e/ssl/s3_both.c
---- openssl-0.9.7e.orig/ssl/s3_both.c 2003-02-12 09:05:17.000000000 -0800
-+++ openssl-0.9.7e/ssl/s3_both.c 2004-12-31 21:18:15.556846272 -0800
-@@ -199,6 +199,12 @@ int ssl3_get_finished(SSL *s, int a, int
- 64, /* should actually be 36+4 :-) */
- &ok);
-
-+ if (!ok && s->hello_extension)
-+ {
-+ /* Quick hack to test EAP-FAST. */
-+ return(1);
-+ }
-+
- if (!ok) return((int)n);
+@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
- /* If this occurs, we have missed a message */
-diff -upr openssl-0.9.7e.orig/ssl/s3_clnt.c openssl-0.9.7e/ssl/s3_clnt.c
---- openssl-0.9.7e.orig/ssl/s3_clnt.c 2004-05-15 09:39:22.000000000 -0700
-+++ openssl-0.9.7e/ssl/s3_clnt.c 2004-12-31 21:16:38.617583280 -0800
-@@ -588,6 +588,12 @@ static int ssl3_client_hello(SSL *s)
- *(p++)=comp->id;
- }
- *(p++)=0; /* Add the NULL method */
++/* 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);
+
-+ if (s->hello_extension)
-+ {
-+ memcpy(p,s->hello_extension,s->hello_extension_len);
-+ p+=s->hello_extension_len;
-+ }
-
- l=(p-d);
- d=buf;
-@@ -779,6 +785,11 @@ static int ssl3_get_server_certificate(S
++/* 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.
+@@ -1714,6 +1733,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
- if (s->s3->tmp.message_type != SSL3_MT_CERTIFICATE)
- {
-+ if (s->hello_extension)
-+ {
-+ /* Quick hack to test EAP-FAST. */
-+ return(1);
-+ }
- al=SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_SSL3_GET_SERVER_CERTIFICATE,SSL_R_BAD_MESSAGE_TYPE);
- goto f_err;
-@@ -951,6 +962,12 @@ static int ssl3_get_key_exchange(SSL *s)
- DH *dh=NULL;
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE 100
+diff -uprN openssl-0.9.8.orig/include/openssl/tls1.h openssl-0.9.8/include/openssl/tls1.h
+--- openssl-0.9.8.orig/include/openssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
++++ openssl-0.9.8/include/openssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
+@@ -282,6 +282,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
-+ if (s->hello_extension)
-+ {
-+ /* Quick hack to test EAP-FAST. */
-+ return(1);
-+ }
++/* TLS extension struct */
++struct tls_extension_st
++{
++ unsigned short type;
++ unsigned short length;
++ void *data;
++};
+
- /* use same message size as in ssl3_get_certificate_request()
- * as ServerKeyExchange message may be skipped */
- n=ssl3_get_message(s,
-@@ -1264,6 +1281,12 @@ static int ssl3_get_certificate_request(
- unsigned char *p,*d,*q;
- STACK_OF(X509_NAME) *ca_sk=NULL;
-
-+ if (s->hello_extension)
+ #ifdef __cplusplus
+ }
+ #endif
+diff -uprN openssl-0.9.8.orig/ssl/Makefile openssl-0.9.8/ssl/Makefile
+--- openssl-0.9.8.orig/ssl/Makefile 2005-05-30 16:20:30.000000000 -0700
++++ openssl-0.9.8/ssl/Makefile 2005-07-19 20:02:15.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.8.orig/ssl/s3_clnt.c openssl-0.9.8/ssl/s3_clnt.c
+--- openssl-0.9.8.orig/ssl/s3_clnt.c 2005-05-16 03:11:03.000000000 -0700
++++ openssl-0.9.8/ssl/s3_clnt.c 2005-07-19 20:02:15.000000000 -0700
+@@ -606,6 +606,20 @@ int ssl3_client_hello(SSL *s)
+ }
+ *(p++)=0; /* Add the NULL method */
+
++ /* send client hello extensions if any */
++ if (s->version >= TLS1_VERSION && s->tls_extension)
+ {
-+ /* Quick hack to test EAP-FAST. */
-+ return(1);
++ // 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;
+ }
+
- n=ssl3_get_message(s,
- SSL3_ST_CR_CERT_REQ_A,
- SSL3_ST_CR_CERT_REQ_B,
-@@ -1407,6 +1430,12 @@ static int ssl3_get_server_done(SSL *s)
- int ok,ret=0;
+ l=(p-d);
+ d=buf;
+ *(d++)=SSL3_MT_CLIENT_HELLO;
+@@ -628,7 +642,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;
+ SSL_COMP *comp;
+@@ -693,7 +707,24 @@ int ssl3_get_server_hello(SSL *s)
+ goto f_err;
+ }
-+ if (s->hello_extension)
+- 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))
+ {
-+ /* Quick hack to test EAP-FAST. */
-+ return(1);
++ 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;
+ }
++ }
+
- n=ssl3_get_message(s,
- SSL3_ST_CR_SRVR_DONE_A,
- SSL3_ST_CR_SRVR_DONE_B,
-@@ -1439,6 +1468,12 @@ static int ssl3_send_client_key_exchange
- KSSL_ERR kssl_err;
- #endif /* OPENSSL_NO_KRB5 */
++ 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.8.orig/ssl/s3_srvr.c openssl-0.9.8/ssl/s3_srvr.c
+--- openssl-0.9.8.orig/ssl/s3_srvr.c 2005-05-22 17:32:55.000000000 -0700
++++ openssl-0.9.8/ssl/s3_srvr.c 2005-07-19 20:02:15.000000000 -0700
+@@ -955,6 +955,75 @@ int ssl3_get_client_hello(SSL *s)
+ }
+ #endif
-+ if (s->hello_extension)
++ /* Check for TLS client hello extension here */
++ if (p < (d+n) && s->version >= TLS1_VERSION)
++ {
++ if (s->tls_extension_cb)
+ {
-+ /* Quick hack to test EAP-FAST. */
-+ return(1);
++ 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;
++ }
+ }
++ }
+
- if (s->state == SSL3_ST_CW_KEY_EXCH_A)
- {
- d=(unsigned char *)s->init_buf->data;
-@@ -1880,6 +1915,12 @@ static int ssl3_check_cert_and_algorithm
- DH *dh;
- #endif
-
-+ if (s->hello_extension)
++ /* 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))
+ {
-+ /* Quick hack to test EAP-FAST. */
-+ return(1);
++ 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);
+ }
++ }
+
- sc=s->session->sess_cert;
+ /* Given s->session->ciphers and SSL_get_ciphers, we must
+ * pick a cipher */
- if (sc == NULL)
-diff -upr openssl-0.9.7e.orig/ssl/ssl.h openssl-0.9.7e/ssl/ssl.h
---- openssl-0.9.7e.orig/ssl/ssl.h 2004-07-27 11:28:49.000000000 -0700
-+++ openssl-0.9.7e/ssl/ssl.h 2004-12-24 20:29:01.000000000 -0800
-@@ -929,6 +929,11 @@ struct ssl_st
+diff -uprN openssl-0.9.8.orig/ssl/ssl_err.c openssl-0.9.8/ssl/ssl_err.c
+--- openssl-0.9.8.orig/ssl/ssl_err.c 2005-06-10 12:51:16.000000000 -0700
++++ openssl-0.9.8/ssl/ssl_err.c 2005-07-19 20:02:15.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.8.orig/ssl/ssl.h openssl-0.9.8/ssl/ssl.h
+--- openssl-0.9.8.orig/ssl/ssl.h 2005-06-10 12:51:16.000000000 -0700
++++ openssl-0.9.8/ssl/ssl.h 2005-07-19 20:02:15.000000000 -0700
+@@ -340,6 +340,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
+@@ -361,6 +362,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
+ {
+@@ -968,6 +971,15 @@ struct ssl_st
int first_packet;
int client_version; /* what was passed, used for
* SSLv3/TLS rollback check */
+
-+ /* Optional ClientHello/ServerHello extension to be added to the end
-+ * of the SSLv3/TLS hello message. */
-+ char *hello_extension;
-+ int hello_extension_len;
++ /* 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
-diff -upr openssl-0.9.7e.orig/ssl/ssl_lib.c openssl-0.9.7e/ssl/ssl_lib.c
---- openssl-0.9.7e.orig/ssl/ssl_lib.c 2004-05-11 05:46:12.000000000 -0700
-+++ openssl-0.9.7e/ssl/ssl_lib.c 2004-12-24 20:35:22.000000000 -0800
-@@ -478,6 +478,7 @@ void SSL_free(SSL *s)
- kssl_ctx_free(s->kssl_ctx);
- #endif /* OPENSSL_NO_KRB5 */
-
-+ OPENSSL_free(s->hello_extension);
- OPENSSL_free(s);
+@@ -1533,6 +1545,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.
+@@ -1714,6 +1733,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.8.orig/ssl/ssl_sess.c openssl-0.9.8/ssl/ssl_sess.c
+--- openssl-0.9.8.orig/ssl/ssl_sess.c 2005-04-29 13:10:06.000000000 -0700
++++ openssl-0.9.8/ssl/ssl_sess.c 2005-07-19 20:02:15.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.8.orig/ssl/t1_ext.c openssl-0.9.8/ssl/t1_ext.c
+--- openssl-0.9.8.orig/ssl/t1_ext.c 1969-12-31 16:00:00.000000000 -0800
++++ openssl-0.9.8/ssl/t1_ext.c 2005-07-19 20:03:29.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.8.orig/ssl/t1_lib.c openssl-0.9.8/ssl/t1_lib.c
+--- openssl-0.9.8.orig/ssl/t1_lib.c 2005-04-26 09:02:40.000000000 -0700
++++ openssl-0.9.8/ssl/t1_lib.c 2005-07-19 20:02:15.000000000 -0700
+@@ -131,6 +131,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.8.orig/ssl/tls1.h openssl-0.9.8/ssl/tls1.h
+--- openssl-0.9.8.orig/ssl/tls1.h 2003-07-22 05:34:21.000000000 -0700
++++ openssl-0.9.8/ssl/tls1.h 2005-07-19 20:02:15.000000000 -0700
+@@ -282,6 +282,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.8.orig/util/ssleay.num openssl-0.9.8/util/ssleay.num
+--- openssl-0.9.8.orig/util/ssleay.num 2005-05-08 17:22:02.000000000 -0700
++++ openssl-0.9.8/util/ssleay.num 2005-07-19 20:02:15.000000000 -0700
+@@ -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/pcsc_funcs.c b/contrib/wpa_supplicant/pcsc_funcs.c
index 541661f..2ccfd00 100644
--- a/contrib/wpa_supplicant/pcsc_funcs.c
+++ b/contrib/wpa_supplicant/pcsc_funcs.c
@@ -86,8 +86,8 @@ struct scard_data {
long ctx;
long card;
unsigned long protocol;
- SCARD_IO_REQUEST recv_pci;
sim_types sim_type;
+ int pin1_required;
};
@@ -96,7 +96,7 @@ static int _scard_select_file(struct scard_data *scard, unsigned short file_id,
sim_types sim_type, unsigned char *aid);
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, char *pin);
+static int scard_verify_pin(struct scard_data *scard, const char *pin);
static int scard_parse_fsp_templ(unsigned char *buf, size_t buf_len,
@@ -183,7 +183,7 @@ static int scard_pin_needed(struct scard_data *scard,
}
-struct scard_data * scard_init(scard_sim_type sim_type, char *pin)
+struct scard_data * scard_init(scard_sim_type sim_type)
{
long ret, len;
struct scard_data *scard;
@@ -294,28 +294,39 @@ struct scard_data * scard_init(scard_sim_type sim_type, char *pin)
/* Verify whether CHV1 (PIN1) is needed to access the card. */
if (scard_pin_needed(scard, buf, blen)) {
+ scard->pin1_required = 1;
wpa_printf(MSG_DEBUG, "PIN1 needed for SIM access");
+ }
+
+ return scard;
+
+failed:
+ free(readers);
+ scard_deinit(scard);
+ return NULL;
+}
+
+
+int scard_set_pin(struct scard_data *scard, const char *pin)
+{
+ if (scard == NULL)
+ return -1;
+
+ /* Verify whether CHV1 (PIN1) is needed to access the card. */
+ if (scard->pin1_required) {
if (pin == NULL) {
- wpa_printf(MSG_INFO, "No PIN configured for SIM "
+ wpa_printf(MSG_DEBUG, "No PIN configured for SIM "
"access");
- /* TODO: ask PIN from user through a frontend (e.g.,
- * wpa_cli) */
- goto failed;
+ return -1;
}
if (scard_verify_pin(scard, pin)) {
wpa_printf(MSG_INFO, "PIN verification failed for "
"SIM access");
- /* TODO: what to do? */
- goto failed;
+ return -1;
}
}
- return scard;
-
-failed:
- free(readers);
- scard_deinit(scard);
- return NULL;
+ return 0;
}
@@ -360,7 +371,7 @@ static long scard_transmit(struct scard_data *scard,
scard->protocol == SCARD_PROTOCOL_T1 ?
SCARD_PCI_T1 : SCARD_PCI_T0,
send, (unsigned long) send_len,
- &scard->recv_pci, recv, &rlen);
+ NULL, recv, &rlen);
*recv_len = rlen;
if (ret == SCARD_S_SUCCESS) {
wpa_hexdump(MSG_DEBUG, "SCARD: scard_transmit: recv",
@@ -498,7 +509,7 @@ static int scard_read_file(struct scard_data *scard,
}
-static int scard_verify_pin(struct scard_data *scard, char *pin)
+static int scard_verify_pin(struct scard_data *scard, const char *pin)
{
long ret;
unsigned char resp[3];
@@ -621,7 +632,7 @@ int scard_gsm_auth(struct scard_data *scard, unsigned char *rand,
memcpy(cmd + 6, rand, 16);
}
len = sizeof(resp);
- ret = scard_transmit(scard, cmd, sizeof(cmd), resp, &len);
+ ret = scard_transmit(scard, cmd, cmdlen, resp, &len);
if (ret != SCARD_S_SUCCESS)
return -2;
diff --git a/contrib/wpa_supplicant/pcsc_funcs.h b/contrib/wpa_supplicant/pcsc_funcs.h
index 1b64fa2..47ac66c 100644
--- a/contrib/wpa_supplicant/pcsc_funcs.h
+++ b/contrib/wpa_supplicant/pcsc_funcs.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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 PCSC_FUNCS_H
#define PCSC_FUNCS_H
@@ -27,9 +41,10 @@ typedef enum {
#ifdef PCSC_FUNCS
-struct scard_data * scard_init(scard_sim_type sim_type, char *pin);
+struct scard_data * scard_init(scard_sim_type sim_type);
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,
unsigned char *sres, unsigned char *kc);
@@ -39,8 +54,9 @@ int scard_umts_auth(struct scard_data *scard, unsigned char *rand,
#else /* PCSC_FUNCS */
-#define scard_init(s, p) NULL
+#define scard_init(s) NULL
#define scard_deinit(s) do { } while (0)
+#define scard_set_pin(s, p) -1
#define scard_get_imsi(s, i, l) -1
#define scard_gsm_auth(s, r, s2, k) -1
#define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1
diff --git a/contrib/wpa_supplicant/preauth.c b/contrib/wpa_supplicant/preauth.c
new file mode 100644
index 0000000..74a4b0c
--- /dev/null
+++ b/contrib/wpa_supplicant/preauth.c
@@ -0,0 +1,934 @@
+/*
+ * WPA Supplicant - RSN pre-authentication and PMKSA caching
+ * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.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 <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 "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 "wpa_i.h"
+
+
+#define PMKID_CANDIDATE_PRIO_SCAN 1000
+static const int pmksa_cache_max_entries = 32;
+
+
+struct rsn_pmksa_candidate {
+ struct rsn_pmksa_candidate *next;
+ u8 bssid[ETH_ALEN];
+ int priority;
+};
+
+
+/**
+ * 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()
+ */
+void pmksa_candidate_free(struct wpa_sm *sm)
+{
+ struct rsn_pmksa_candidate *entry, *prev;
+
+ if (sm == NULL)
+ return;
+
+ entry = sm->pmksa_candidates;
+ sm->pmksa_candidates = NULL;
+ while (entry) {
+ prev = entry;
+ entry = entry->next;
+ free(prev);
+ }
+}
+
+
+#ifdef IEEE8021X_EAPOL
+
+static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_sm *sm = ctx;
+
+ wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(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) {
+ wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
+ "unexpected source " MACSTR " - dropped",
+ MAC2STR(src_addr));
+ return;
+ }
+
+ eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
+}
+
+
+static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
+ void *ctx)
+{
+ struct wpa_sm *sm = ctx;
+ u8 pmk[PMK_LEN];
+
+ if (success) {
+ int res, pmk_len;
+ pmk_len = PMK_LEN;
+ res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
+#ifdef EAP_LEAP
+ if (res) {
+ 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,
+ sm->preauth_bssid, sm->own_addr,
+ sm->cur_ssid);
+ } else {
+ wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: failed to get "
+ "master session key from pre-auth EAPOL state "
+ "machines");
+ success = 0;
+ }
+ }
+
+ wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: pre-authentication with " MACSTR
+ " %s", MAC2STR(sm->preauth_bssid),
+ success ? "completed successfully" : "failed");
+
+ rsn_preauth_deinit(sm);
+ rsn_preauth_candidate_process(sm);
+}
+
+
+static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_sm *sm = eloop_ctx;
+
+ wpa_msg(sm->ctx->ctx, MSG_INFO, "RSN: pre-authentication with " MACSTR
+ " timed out", MAC2STR(sm->preauth_bssid));
+ rsn_preauth_deinit(sm);
+ rsn_preauth_candidate_process(sm);
+}
+
+
+static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
+ size_t len)
+{
+ struct wpa_sm *sm = ctx;
+ u8 *msg;
+ size_t msglen;
+ int res;
+
+ /* TODO: could add l2_packet_sendmsg that allows fragments to avoid
+ * extra copy here */
+
+ if (sm->l2_preauth == NULL)
+ return -1;
+
+ msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL);
+ if (msg == NULL)
+ return -1;
+
+ 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);
+ return res;
+}
+
+
+/**
+ * rsn_preauth_init - Start new RSN pre-authentication
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @dst: Authenticator address (BSSID) with which to preauthenticate
+ * @config: Current network configuration
+ * Returns: 0 on success, -1 on another pre-authentication is in progress,
+ * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
+ * initialization failure, -4 on memory allocation failure
+ *
+ * This function request an RSN pre-authentication with a given destination
+ * address. This is usually called for PMKSA candidates found from scan results
+ * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
+ * pre-authentication.
+ */
+int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst, struct wpa_ssid *config)
+{
+ struct eapol_config eapol_conf;
+ struct eapol_ctx *ctx;
+
+ if (sm->preauth_eapol)
+ return -1;
+
+ wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: starting pre-authentication "
+ "with " MACSTR, MAC2STR(dst));
+
+ sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr,
+ ETH_P_RSN_PREAUTH,
+ rsn_preauth_receive, sm, 0);
+ if (sm->l2_preauth == NULL) {
+ wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
+ "processing for pre-authentication");
+ return -2;
+ }
+
+ ctx = malloc(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;
+ ctx->cb = rsn_preauth_eapol_cb;
+ ctx->cb_ctx = sm;
+ ctx->scard_ctx = sm->scard_ctx;
+ ctx->eapol_send = rsn_preauth_eapol_send;
+ ctx->eapol_send_ctx = sm;
+ ctx->set_config_blob = sm->ctx->set_config_blob;
+ ctx->get_config_blob = sm->ctx->get_config_blob;
+
+ sm->preauth_eapol = eapol_sm_init(ctx);
+ if (sm->preauth_eapol == NULL) {
+ 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));
+ eapol_conf.accept_802_1x_keys = 0;
+ eapol_conf.required_keys = 0;
+ eapol_conf.fast_reauth = sm->fast_reauth;
+ if (config)
+ eapol_conf.workaround = config->eap_workaround;
+ eapol_sm_notify_config(sm->preauth_eapol, config, &eapol_conf);
+ /*
+ * Use a shorter startPeriod with preauthentication since the first
+ * preauth EAPOL-Start frame may end up being dropped due to race
+ * condition in the AP between the data receive and key configuration
+ * after the 4-Way Handshake.
+ */
+ eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
+ memcpy(sm->preauth_bssid, dst, ETH_ALEN);
+
+ eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
+ /* 802.1X::portControl = Auto */
+ eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
+
+ eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
+ rsn_preauth_timeout, sm, NULL);
+
+ return 0;
+}
+
+
+/**
+ * rsn_preauth_deinit - Abort RSN pre-authentication
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * This function aborts the current RSN pre-authentication (if one is started)
+ * and frees resources allocated for it.
+ */
+void rsn_preauth_deinit(struct wpa_sm *sm)
+{
+ if (sm == NULL || !sm->preauth_eapol)
+ return;
+
+ 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);
+
+ l2_packet_deinit(sm->l2_preauth);
+ sm->l2_preauth = NULL;
+}
+
+
+/**
+ * rsn_preauth_candidate_process - Process PMKSA candidates
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * Go through the PMKSA candidates and start pre-authentication if a candidate
+ * without an existing PMKSA cache entry is found. Processed candidates will be
+ * removed from the list.
+ */
+void rsn_preauth_candidate_process(struct wpa_sm *sm)
+{
+ struct rsn_pmksa_candidate *candidate;
+
+ if (sm->pmksa_candidates == NULL)
+ return;
+
+ /* TODO: drop priority for old candidate entries */
+
+ wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: processing PMKSA candidate "
+ "list");
+ if (sm->preauth_eapol ||
+ sm->proto != WPA_PROTO_RSN ||
+ wpa_sm_get_state(sm) != WPA_COMPLETED ||
+ sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X) {
+ wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: not in suitable state "
+ "for new pre-authentication");
+ return; /* invalid state for new pre-auth */
+ }
+
+ while (sm->pmksa_candidates) {
+ struct rsn_pmksa_cache *p = NULL;
+ candidate = sm->pmksa_candidates;
+ p = pmksa_cache_get(sm, candidate->bssid, NULL);
+ if (memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
+ (p == NULL || p->opportunistic)) {
+ wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA "
+ "candidate " MACSTR
+ " selected for pre-authentication",
+ MAC2STR(candidate->bssid));
+ sm->pmksa_candidates = candidate->next;
+ rsn_preauth_init(sm, candidate->bssid, sm->cur_ssid);
+ free(candidate);
+ return;
+ }
+ wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: PMKSA candidate "
+ MACSTR " does not need pre-authentication anymore",
+ MAC2STR(candidate->bssid));
+ /* Some drivers (e.g., NDIS) expect to get notified about the
+ * PMKIDs again, so report the existing data now. */
+ if (p) {
+ wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
+ }
+
+ sm->pmksa_candidates = candidate->next;
+ free(candidate);
+ }
+ wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
+ "candidates");
+}
+
+
+/**
+ * pmksa_candidate_add - Add a new PMKSA candidate
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @bssid: BSSID (authenticator address) of the candidate
+ * @prio: Priority (the smaller number, the higher priority)
+ * @preauth: Whether the candidate AP advertises support for pre-authentication
+ *
+ * This function is used to add PMKSA candidates for RSN pre-authentication. It
+ * is called from scan result processing and from driver events for PMKSA
+ * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
+ */
+void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
+ int prio, int preauth)
+{
+ 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);
+
+ if (!preauth) {
+ wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
+ "preauth flag");
+ return;
+ }
+
+ /* If BSSID already on candidate list, update the priority of the old
+ * entry. Do not override priority based on normal scan results. */
+ prev = NULL;
+ cand = sm->pmksa_candidates;
+ while (cand) {
+ if (memcmp(cand->bssid, bssid, ETH_ALEN) == 0) {
+ if (prev)
+ prev->next = cand->next;
+ else
+ sm->pmksa_candidates = cand->next;
+ break;
+ }
+ prev = cand;
+ cand = cand->next;
+ }
+
+ if (cand) {
+ if (prio < PMKID_CANDIDATE_PRIO_SCAN)
+ cand->priority = prio;
+ } else {
+ cand = malloc(sizeof(*cand));
+ if (cand == NULL)
+ return;
+ memset(cand, 0, sizeof(*cand));
+ memcpy(cand->bssid, bssid, ETH_ALEN);
+ cand->priority = prio;
+ }
+
+ /* Add candidate to the list; order by increasing priority value. i.e.,
+ * highest priority (smallest value) first. */
+ prev = NULL;
+ pos = sm->pmksa_candidates;
+ while (pos) {
+ if (cand->priority <= pos->priority)
+ break;
+ prev = pos;
+ pos = pos->next;
+ }
+ cand->next = pos;
+ if (prev)
+ prev->next = cand;
+ else
+ sm->pmksa_candidates = cand;
+
+ wpa_msg(sm->ctx->ctx, MSG_DEBUG, "RSN: added PMKSA cache "
+ "candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
+ rsn_preauth_candidate_process(sm);
+}
+
+
+/* TODO: schedule periodic scans if current AP supports preauth */
+
+/**
+ * rsn_preauth_scan_results - Process scan results to find PMKSA candidates
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @results: Scan results
+ * @count: Number of BSSes in scan results
+ *
+ * This functions goes through the scan results and adds all suitable APs
+ * (Authenticators) into PMKSA candidate list.
+ */
+void rsn_preauth_scan_results(struct wpa_sm *sm,
+ struct wpa_scan_result *results, int count)
+{
+ struct wpa_scan_result *r;
+ struct wpa_ie_data ie;
+ int i;
+ struct rsn_pmksa_cache *pmksa;
+
+ if (sm->cur_ssid == NULL)
+ return;
+
+ /*
+ * TODO: is it ok to free all candidates? What about the entries
+ * received from EVENT_PMKID_CANDIDATE?
+ */
+ pmksa_candidate_free(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)
+ continue;
+
+ if (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);
+ if (pmksa &&
+ (!pmksa->opportunistic ||
+ !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
+ continue;
+
+ /*
+ * Give less priority to candidates found from normal
+ * scan results.
+ */
+ pmksa_candidate_add(sm, r->bssid,
+ PMKID_CANDIDATE_PRIO_SCAN,
+ ie.capabilities & WPA_CAPABILITY_PREAUTH);
+ }
+}
+
+
+/**
+ * rsn_preauth_get_status - Get pre-authentication status
+ * @sm: Pointer to WPA state machine data from wpa_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.
+ *
+ * Query WPA2 pre-authentication for status information. This function fills in
+ * a text area with current status information. If the buffer (buf) is not
+ * large enough, status information will be truncated to fit the buffer.
+ */
+int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+ int verbose)
+{
+ char *pos = buf, *end = buf + buflen;
+ int res;
+
+ if (sm->preauth_eapol) {
+ pos += snprintf(pos, end - pos, "Pre-authentication "
+ "EAPOL state machines:\n");
+ res = eapol_sm_get_status(sm->preauth_eapol,
+ pos, end - pos, verbose);
+ if (res >= 0)
+ pos += res;
+ }
+
+ return pos - buf;
+}
+
+
+/**
+ * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+int rsn_preauth_in_progress(struct wpa_sm *sm)
+{
+ return sm->preauth_eapol != NULL;
+}
+
+#endif /* IEEE8021X_EAPOL */
diff --git a/contrib/wpa_supplicant/preauth.h b/contrib/wpa_supplicant/preauth.h
new file mode 100644
index 0000000..9b528f0
--- /dev/null
+++ b/contrib/wpa_supplicant/preauth.h
@@ -0,0 +1,132 @@
+/*
+ * wpa_supplicant - WPA2/RSN pre-authentication functions
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 PREAUTH_H
+#define PREAUTH_H
+
+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)
+
+int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
+ struct wpa_ssid *config);
+void rsn_preauth_deinit(struct wpa_sm *sm);
+void rsn_preauth_scan_results(struct wpa_sm *sm,
+ struct wpa_scan_result *results, int count);
+void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
+ int prio, int preauth);
+void rsn_preauth_candidate_process(struct wpa_sm *sm);
+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 */
+
+static inline void rsn_preauth_candidate_process(struct wpa_sm *sm)
+{
+}
+
+static inline int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
+ struct wpa_ssid *config)
+{
+ return -1;
+}
+
+static inline void rsn_preauth_deinit(struct wpa_sm *sm)
+{
+}
+static inline void rsn_preauth_scan_results(struct wpa_sm *sm,
+ struct wpa_scan_result *results,
+ int count)
+{
+}
+
+static inline void pmksa_candidate_add(struct wpa_sm *sm,
+ const u8 *bssid,
+ int prio, int preauth)
+{
+}
+
+static inline int rsn_preauth_get_status(struct wpa_sm *sm, char *buf,
+ size_t buflen, int verbose)
+{
+ return 0;
+}
+
+static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
+{
+ return 0;
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA */
+
+#endif /* PREAUTH_H */
diff --git a/contrib/wpa_supplicant/preauth_test.c b/contrib/wpa_supplicant/preauth_test.c
index 13741bb..d89058d 100644
--- a/contrib/wpa_supplicant/preauth_test.c
+++ b/contrib/wpa_supplicant/preauth_test.c
@@ -1,6 +1,15 @@
/*
* WPA Supplicant - test code for pre-authentication
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.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.
*
* IEEE 802.1X Supplicant test code (to be used in place of wpa_supplicant.c.
* Not used in production version.
@@ -27,181 +36,175 @@
#include "l2_packet.h"
#include "ctrl_iface.h"
#include "pcsc_funcs.h"
+#include "preauth.h"
extern int wpa_debug_level;
extern int wpa_debug_show_keys;
-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);
-}
+struct wpa_driver_ops *wpa_supplicant_drivers[] = { };
-void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
- union wpa_event_data *data)
+struct preauth_test_data {
+ int auth_timed_out;
+};
+
+
+static void _wpa_supplicant_req_scan(void *wpa_s, int sec, int usec)
{
+ wpa_supplicant_req_scan(wpa_s, sec, usec);
}
-int rsn_preauth_init(struct wpa_supplicant *wpa_s, u8 *dst)
+static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
{
- return -1;
+ wpa_supplicant_disassociate(wpa_s, reason_code);
}
-void rsn_preauth_deinit(struct wpa_supplicant *wpa_s)
+static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
{
+ wpa_supplicant_deauthenticate(wpa_s, reason_code);
}
-int pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, size_t len)
+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)
{
- return 0;
+ struct ieee802_1x_hdr *hdr;
+
+ *msg_len = sizeof(*hdr) + data_len;
+ hdr = malloc(*msg_len);
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->version = wpa_s->conf->eapol_version;
+ hdr->type = type;
+ hdr->length = htons(data_len);
+
+ if (data)
+ memcpy(hdr + 1, data, data_len);
+ else
+ memset(hdr + 1, 0, data_len);
+
+ if (data_pos)
+ *data_pos = hdr + 1;
+
+ return (u8 *) hdr;
}
-int wpa_get_mib(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
+ const void *data, u16 data_len,
+ size_t *msg_len, void **data_pos)
{
- return 0;
+ return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
}
-void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
+static void _wpa_supplicant_set_state(void *ctx, wpa_states state)
{
+ struct wpa_supplicant *wpa_s = ctx;
+ wpa_s->wpa_state = state;
}
-const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
+static wpa_states _wpa_supplicant_get_state(void *ctx)
{
- return NULL;
+ struct wpa_supplicant *wpa_s = ctx;
+ return wpa_s->wpa_state;
}
-int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
+static int wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
+ const u8 *buf, size_t len)
{
+ printf("%s - not implemented\n", __func__);
return -1;
}
-static int eapol_test_eapol_send(void *ctx, int type, u8 *buf, size_t len)
+static struct wpa_ssid * _wpa_supplicant_get_ssid(void *wpa_s)
{
- struct wpa_supplicant *wpa_s = ctx;
- u8 *msg;
- size_t msglen;
- struct l2_ethhdr *ethhdr;
- struct ieee802_1x_hdr *hdr;
- int res;
-
- printf("WPA: wpa_eapol_send(type=%d len=%d)\n", type, len);
+ return wpa_supplicant_get_ssid(wpa_s);
+}
- if (wpa_s->l2_preauth == NULL)
- return -1;
- msglen = sizeof(*ethhdr) + sizeof(*hdr) + len;
- msg = malloc(msglen);
- if (msg == NULL)
- return -1;
+static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
+{
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+}
- ethhdr = (struct l2_ethhdr *) msg;
- memcpy(ethhdr->h_dest, wpa_s->preauth_bssid, ETH_ALEN);
- memcpy(ethhdr->h_source, wpa_s->own_addr, ETH_ALEN);
- ethhdr->h_proto = htons(ETH_P_RSN_PREAUTH);
- hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
- hdr->version = wpa_s->conf->eapol_version;
- hdr->type = type;
- hdr->length = htons(len);
+static int wpa_supplicant_get_beacon_ie(void *wpa_s)
+{
+ printf("%s - not implemented\n", __func__);
+ return -1;
+}
- memcpy((u8 *) (hdr + 1), buf, len);
- wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
- res = l2_packet_send(wpa_s->l2_preauth, msg, msglen);
- free(msg);
- return res;
+void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
+{
+ printf("%s - not implemented\n", __func__);
}
-static void eapol_test_eapol_done_cb(void *ctx)
+static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid)
{
- printf("WPA: EAPOL processing complete\n");
+ printf("%s - not implemented\n", __func__);
+ return -1;
}
-static void eapol_sm_cb(struct eapol_sm *eapol, int success, void *ctx)
+static int wpa_supplicant_set_key(void *wpa_s, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
{
- printf("eapol_sm_cb: success=%d\n", success);
- eloop_terminate();
+ printf("%s - not implemented\n", __func__);
+ return -1;
}
-static int test_eapol(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+static int wpa_supplicant_add_pmkid(void *wpa_s,
+ const u8 *bssid, const u8 *pmkid)
{
- struct eapol_config eapol_conf;
- struct eapol_ctx *ctx;
+ printf("%s - not implemented\n", __func__);
+ return -1;
+}
- ctx = malloc(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;
- ctx->cb = eapol_sm_cb;
- ctx->cb_ctx = wpa_s;
- ctx->preauth = 0;
- ctx->eapol_done_cb = eapol_test_eapol_done_cb;
- ctx->eapol_send = eapol_test_eapol_send;
-
- wpa_s->preauth_eapol = eapol_sm_init(ctx);
- if (wpa_s->preauth_eapol == NULL) {
- free(ctx);
- printf("Failed to initialize EAPOL state machines.\n");
- return -1;
- }
- wpa_s->current_ssid = ssid;
- memset(&eapol_conf, 0, sizeof(eapol_conf));
- eapol_conf.accept_802_1x_keys = 1;
- eapol_conf.required_keys = 0;
- eapol_conf.workaround = ssid->eap_workaround;
- eapol_sm_notify_config(wpa_s->preauth_eapol, ssid, &eapol_conf);
+static int wpa_supplicant_remove_pmkid(void *wpa_s,
+ const u8 *bssid, const u8 *pmkid)
+{
+ printf("%s - not implemented\n", __func__);
+ return -1;
+}
- eapol_sm_notify_portValid(wpa_s->preauth_eapol, FALSE);
- /* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(wpa_s->preauth_eapol, TRUE);
+static void wpa_supplicant_set_config_blob(void *ctx,
+ struct wpa_config_blob *blob)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ wpa_config_set_blob(wpa_s->conf, blob);
+}
- return 0;
+
+static const struct wpa_config_blob *
+wpa_supplicant_get_config_blob(void *ctx, const char *name)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ return wpa_config_get_blob(wpa_s->conf, name);
}
static void test_eapol_clean(struct wpa_supplicant *wpa_s)
{
- l2_packet_deinit(wpa_s->l2_preauth);
- eapol_sm_deinit(wpa_s->preauth_eapol);
- wpa_s->preauth_eapol = NULL;
+ 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);
wpa_config_free(wpa_s->conf);
@@ -210,117 +213,75 @@ static void test_eapol_clean(struct wpa_supplicant *wpa_s)
static void eapol_test_timeout(void *eloop_ctx, void *timeout_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct preauth_test_data *p = eloop_ctx;
printf("EAPOL test timed out\n");
- wpa_s->auth_timed_out = 1;
+ p->auth_timed_out = 1;
eloop_terminate();
}
-static void wpa_supplicant_imsi_identity(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+static void eapol_test_poll(void *eloop_ctx, void *timeout_ctx)
{
- if (ssid->identity == NULL && wpa_s->imsi) {
- ssid->identity = malloc(1 + wpa_s->imsi_len);
- if (ssid->identity) {
- ssid->identity[0] = '1';
- memcpy(ssid->identity + 1, wpa_s->imsi,
- wpa_s->imsi_len);
- ssid->identity_len = 1 + wpa_s->imsi_len;
- wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
- "IMSI", ssid->identity,
- ssid->identity_len);
- }
+ struct wpa_supplicant *wpa_s = eloop_ctx;
+ if (!rsn_preauth_in_progress(wpa_s->wpa))
+ eloop_terminate();
+ else {
+ eloop_register_timeout(0, 100000, eapol_test_poll, eloop_ctx,
+ timeout_ctx);
}
}
-static void wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- char buf[100];
- size_t len;
-
- if (ssid->pcsc == NULL)
- return;
- if (wpa_s->scard != NULL) {
- wpa_supplicant_imsi_identity(wpa_s, ssid);
- return;
- }
- wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM - "
- "initialize PCSC");
- wpa_s->scard = scard_init(SCARD_TRY_BOTH, ssid->pin);
- if (wpa_s->scard == NULL) {
- wpa_printf(MSG_WARNING, "Failed to initialize SIM "
- "(pcsc-lite)");
- /* TODO: what to do here? */
- return;
- }
- eapol_sm_register_scard_ctx(wpa_s->preauth_eapol, wpa_s->scard);
-
- len = sizeof(buf);
- if (scard_get_imsi(wpa_s->scard, buf, &len)) {
- wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
- /* TODO: what to do here? */
- return;
- }
-
- wpa_hexdump(MSG_DEBUG, "IMSI", (u8 *) buf, len);
- free(wpa_s->imsi);
- wpa_s->imsi = malloc(len);
- if (wpa_s->imsi) {
- memcpy(wpa_s->imsi, buf, len);
- wpa_s->imsi_len = len;
- wpa_supplicant_imsi_identity(wpa_s, ssid);
- }
-}
+static struct wpa_driver_ops dummy_driver;
-static void rsn_preauth_receive(void *ctx, unsigned char *src_addr,
- unsigned char *buf, size_t len)
+static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *ifname)
{
- struct wpa_supplicant *wpa_s = ctx;
+ struct l2_packet_data *l2;
+ struct wpa_sm_ctx *ctx;
- wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
- wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
-
- if (wpa_s->preauth_eapol == NULL ||
- memcmp(wpa_s->preauth_bssid, "\x00\x00\x00\x00\x00\x00",
- ETH_ALEN) == 0 ||
- memcmp(wpa_s->preauth_bssid, src_addr, ETH_ALEN) != 0) {
- wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
- "unexpected source " MACSTR " - dropped",
- MAC2STR(src_addr));
- return;
- }
+ memset(&dummy_driver, 0, sizeof(dummy_driver));
+ wpa_s->driver = &dummy_driver;
- eapol_sm_rx_eapol(wpa_s->preauth_eapol, src_addr, buf, len);
-}
+ ctx = malloc(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;
+ ctx->req_scan = _wpa_supplicant_req_scan;
+ ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+ ctx->disassociate = _wpa_supplicant_disassociate;
+ ctx->set_key = wpa_supplicant_set_key;
+ ctx->scan = wpa_supplicant_scan;
+ ctx->get_ssid = _wpa_supplicant_get_ssid;
+ ctx->get_bssid = wpa_supplicant_get_bssid;
+ ctx->ether_send = wpa_ether_send;
+ ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
+ ctx->alloc_eapol = _wpa_alloc_eapol;
+ ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
+ ctx->add_pmkid = wpa_supplicant_add_pmkid;
+ 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;
+
+ 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);
-static void wpa_init_conf(struct wpa_supplicant *wpa_s, const char *target,
- const char *ifname)
-{
strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+ wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname);
- if (hwaddr_aton(target, wpa_s->preauth_bssid)) {
- printf("Failed to parse target address '%s'.\n", target);
- exit(-1);
- }
-
- wpa_s->l2_preauth = l2_packet_init(wpa_s->ifname, NULL,
- ETH_P_RSN_PREAUTH,
- rsn_preauth_receive, wpa_s);
- if (wpa_s->l2_preauth == NULL) {
- wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
- "processing for pre-authentication");
- exit(-1);
- }
-
- if (l2_packet_get_own_addr(wpa_s->l2_preauth, wpa_s->own_addr)) {
+ l2 = l2_packet_init(wpa_s->ifname, NULL, ETH_P_RSN_PREAUTH, NULL,
+ NULL, 0);
+ assert(l2 != NULL);
+ if (l2_packet_get_own_addr(l2, wpa_s->own_addr)) {
wpa_printf(MSG_WARNING, "Failed to get own L2 address\n");
exit(-1);
}
+ l2_packet_deinit(l2);
+ wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
}
@@ -337,16 +298,25 @@ int main(int argc, char *argv[])
{
struct wpa_supplicant wpa_s;
int ret = 1;
+ u8 bssid[ETH_ALEN];
+ struct preauth_test_data preauth_test;
+
+ memset(&preauth_test, 0, sizeof(preauth_test));
wpa_debug_level = 0;
wpa_debug_show_keys = 1;
if (argc != 4) {
- printf("usage: eapol_test <conf> <target MAC address> "
+ printf("usage: preauth_test <conf> <target MAC address> "
"<ifname>\n");
return -1;
}
+ if (hwaddr_aton(argv[2], bssid)) {
+ printf("Failed to parse target address '%s'.\n", argv[2]);
+ return -1;
+ }
+
eloop_init(&wpa_s);
memset(&wpa_s, 0, sizeof(wpa_s));
@@ -360,33 +330,36 @@ int main(int argc, char *argv[])
return -1;
}
- wpa_init_conf(&wpa_s, argv[2], argv[3]);
+ wpa_init_conf(&wpa_s, argv[3]);
if (wpa_supplicant_ctrl_iface_init(&wpa_s)) {
printf("Failed to initialize control interface '%s'.\n"
- "You may have another eapol_test process already "
+ "You may have another preauth_test process already "
"running or the file was\n"
- "left by an unclean termination of eapol_test in "
+ "left by an unclean termination of preauth_test in "
"which case you will need\n"
"to manually remove this file before starting "
- "eapol_test again.\n",
+ "preauth_test again.\n",
wpa_s.conf->ctrl_interface);
return -1;
}
- wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid);
+ if (wpa_supplicant_scard_init(&wpa_s, wpa_s.conf->ssid))
+ return -1;
- if (test_eapol(&wpa_s, wpa_s.conf->ssid))
+ if (rsn_preauth_init(wpa_s.wpa, bssid, wpa_s.conf->ssid))
return -1;
- eloop_register_timeout(30, 0, eapol_test_timeout, &wpa_s, NULL);
+ 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_run();
- if (wpa_s.auth_timed_out)
+ if (preauth_test.auth_timed_out)
ret = -2;
- else
- ret = 0;
+ else {
+ ret = pmksa_cache_get(wpa_s.wpa, bssid, NULL) ? 0 : -3;
+ }
test_eapol_clean(&wpa_s);
diff --git a/contrib/wpa_supplicant/radius.c b/contrib/wpa_supplicant/radius.c
index 5fd323d..ce79a62 100644
--- a/contrib/wpa_supplicant/radius.c
+++ b/contrib/wpa_supplicant/radius.c
@@ -16,18 +16,20 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-#include <netinet/in.h>
#include <string.h>
-#include <sys/ioctl.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 "common.h"
#include "radius.h"
#include "md5.h"
+#include "crypto.h"
struct radius_msg *radius_msg_new(u8 code, u8 identifier)
@@ -124,8 +126,10 @@ static const char *radius_code_string(u8 code)
struct radius_attr_type {
u8 type;
char *name;
- enum { RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
- RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32 } data_type;
+ enum {
+ RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
+ RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
+ } data_type;
};
static struct radius_attr_type radius_attrs[] =
@@ -179,8 +183,8 @@ static struct radius_attr_type radius_attrs[] =
{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
RADIUS_ATTR_UNDIST },
{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
- RADIUS_ATTR_INT32 }
-
+ RADIUS_ATTR_INT32 },
+ { RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
};
#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
@@ -231,6 +235,19 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
printf(" Invalid IP address length %d\n", len);
break;
+#ifdef CONFIG_IPV6
+ case RADIUS_ATTR_IPV6:
+ if (len == 16) {
+ char buf[128];
+ const char *atxt;
+ struct in6_addr *addr = (struct in6_addr *) pos;
+ atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
+ printf(" Value: %s\n", atxt ? atxt : "?");
+ } else
+ printf(" Invalid IPv6 address length %d\n", len);
+ break;
+#endif /* CONFIG_IPV6 */
+
case RADIUS_ATTR_HEXDUMP:
case RADIUS_ATTR_UNDIST:
printf(" Value:");
@@ -242,7 +259,8 @@ static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
case RADIUS_ATTR_INT32:
if (len == 4) {
u32 *val = (u32 *) pos;
- printf(" Value: %d\n", ntohl(*val));
+ printf(" Value: %u\n",
+ (unsigned int) ntohl(*val));
} else
printf(" Invalid INT32 length %d\n", len);
break;
@@ -302,7 +320,8 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
{
u8 auth[MD5_MAC_LEN];
struct radius_attr_hdr *attr;
- MD5_CTX context;
+ const u8 *addr[4];
+ size_t len[4];
memset(auth, 0, MD5_MAC_LEN);
attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
@@ -318,13 +337,15 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
(u8 *) (attr + 1));
/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
- MD5Init(&context);
- MD5Update(&context, (u8 *) msg->hdr, 1 + 1 + 2);
- MD5Update(&context, req_authenticator, MD5_MAC_LEN);
- MD5Update(&context, (u8 *) (msg->hdr + 1),
- msg->buf_used - sizeof(*msg->hdr));
- MD5Update(&context, secret, secret_len);
- MD5Final(msg->hdr->authenticator, &context);
+ addr[0] = (u8 *) msg->hdr;
+ len[0] = 1 + 1 + 2;
+ addr[1] = req_authenticator;
+ len[1] = MD5_MAC_LEN;
+ addr[2] = (u8 *) (msg->hdr + 1);
+ len[2] = msg->buf_used - sizeof(*msg->hdr);
+ addr[3] = secret;
+ len[3] = secret_len;
+ md5_vector(4, addr, len, msg->hdr->authenticator);
if (msg->buf_used > 0xffff) {
printf("WARNING: too long RADIUS message (%lu)\n",
@@ -338,14 +359,16 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
size_t secret_len)
{
- MD5_CTX context;
+ const u8 *addr[2];
+ size_t len[2];
msg->hdr->length = htons(msg->buf_used);
memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
- MD5Init(&context);
- MD5Update(&context, msg->buf, msg->buf_used);
- MD5Update(&context, secret, secret_len);
- MD5Final(msg->hdr->authenticator, &context);
+ addr[0] = msg->buf;
+ len[0] = msg->buf_used;
+ addr[1] = secret;
+ len[1] = secret_len;
+ md5_vector(2, addr, len, msg->hdr->authenticator);
if (msg->buf_used > 0xffff) {
printf("WARNING: too long RADIUS messages (%lu)\n",
@@ -378,7 +401,7 @@ static int radius_msg_add_attr_to_array(struct radius_msg *msg,
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
- u8 *data, size_t data_len)
+ const u8 *data, size_t data_len)
{
size_t buf_needed;
struct radius_attr_hdr *attr;
@@ -493,9 +516,9 @@ struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
}
-int radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len)
+int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
{
- u8 *pos = data;
+ const u8 *pos = data;
size_t left = data_len;
while (left > 0) {
@@ -605,10 +628,11 @@ int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
}
-int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
- struct radius_msg *sent_msg)
+int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, struct radius_msg *sent_msg, int auth)
{
- MD5_CTX context;
+ const u8 *addr[4];
+ size_t len[4];
u8 hash[MD5_MAC_LEN];
if (sent_msg == NULL) {
@@ -616,19 +640,22 @@ int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
return 1;
}
- if (radius_msg_verify_msg_auth(msg, secret, secret_len,
+ if (auth &&
+ radius_msg_verify_msg_auth(msg, secret, secret_len,
sent_msg->hdr->authenticator)) {
return 1;
}
/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
- MD5Init(&context);
- MD5Update(&context, (u8 *) msg->hdr, 1 + 1 + 2);
- MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN);
- MD5Update(&context, (u8 *) (msg->hdr + 1),
- msg->buf_used - sizeof(*msg->hdr));
- MD5Update(&context, secret, secret_len);
- MD5Final(hash, &context);
+ addr[0] = (u8 *) msg->hdr;
+ len[0] = 1 + 1 + 2;
+ addr[1] = sent_msg->hdr->authenticator;
+ len[1] = MD5_MAC_LEN;
+ addr[2] = (u8 *) (msg->hdr + 1);
+ len[2] = msg->buf_used - sizeof(*msg->hdr);
+ addr[3] = secret;
+ len[3] = secret_len;
+ md5_vector(4, addr, len, hash);
if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
printf("Response Authenticator invalid!\n");
return 1;
@@ -639,29 +666,6 @@ int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
}
-int radius_msg_verify_acct(struct radius_msg *msg, u8 *secret,
- size_t secret_len, struct radius_msg *sent_msg)
-{
- MD5_CTX context;
- u8 hash[MD5_MAC_LEN];
-
- MD5Init(&context);
- MD5Update(&context, msg->buf, 4);
- MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN);
- if (msg->buf_used > sizeof(struct radius_hdr))
- MD5Update(&context, msg->buf + sizeof(struct radius_hdr),
- msg->buf_used - sizeof(struct radius_hdr));
- MD5Update(&context, secret, secret_len);
- MD5Final(hash, &context);
- if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
- printf("Response Authenticator invalid!\n");
- return 1;
- }
-
- return 0;
-}
-
-
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
u8 type)
{
@@ -694,16 +698,19 @@ void radius_msg_make_authenticator(struct radius_msg *msg,
u8 *data, size_t len)
{
struct timeval tv;
- MD5_CTX context;
long int l;
+ const u8 *addr[3];
+ size_t elen[3];
gettimeofday(&tv, NULL);
l = random();
- MD5Init(&context);
- MD5Update(&context, (u8 *) &tv, sizeof(tv));
- MD5Update(&context, data, len);
- MD5Update(&context, (u8 *) &l, sizeof(l));
- MD5Final(msg->hdr->authenticator, &context);
+ addr[0] = (u8 *) &tv;
+ elen[0] = sizeof(tv);
+ addr[1] = data;
+ elen[1] = len;
+ addr[2] = (u8 *) &l;
+ elen[2] = sizeof(l);
+ md5_vector(3, addr, elen, msg->hdr->authenticator);
}
@@ -780,8 +787,9 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
const u8 *pos;
size_t left, plen;
u8 hash[MD5_MAC_LEN];
- MD5_CTX context;
int i, first = 1;
+ const u8 *addr[3];
+ size_t elen[3];
/* key: 16-bit salt followed by encrypted key info */
@@ -804,15 +812,19 @@ static u8 * decrypt_ms_key(const u8 *key, size_t len,
/* b(1) = MD5(Secret + Request-Authenticator + Salt)
* b(i) = MD5(Secret + c(i - 1)) for i > 1 */
- MD5Init(&context);
- MD5Update(&context, secret, secret_len);
+ addr[0] = secret;
+ elen[0] = secret_len;
if (first) {
- MD5Update(&context, req_authenticator, MD5_MAC_LEN);
- MD5Update(&context, key, 2); /* Salt */
- first = 0;
- } else
- MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN);
- MD5Final(hash, &context);
+ addr[1] = req_authenticator;
+ elen[1] = MD5_MAC_LEN;
+ addr[2] = key;
+ elen[2] = 2; /* Salt */
+ } else {
+ addr[1] = pos - MD5_MAC_LEN;
+ elen[1] = MD5_MAC_LEN;
+ }
+ md5_vector(first ? 3 : 2, addr, elen, hash);
+ first = 0;
for (i = 0; i < MD5_MAC_LEN; i++)
*ppos++ = *pos++ ^ hash[i];
@@ -845,7 +857,8 @@ static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
{
int i, len, first = 1;
u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
- MD5_CTX context;
+ const u8 *addr[3];
+ size_t _len[3];
saltbuf[0] = salt >> 8;
saltbuf[1] = salt;
@@ -864,16 +877,19 @@ static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
while (len > 0) {
/* b(1) = MD5(Secret + Request-Authenticator + Salt)
* b(i) = MD5(Secret + c(i - 1)) for i > 1 */
- MD5Init(&context);
- MD5Update(&context, secret, secret_len);
+ addr[0] = secret;
+ _len[0] = secret_len;
if (first) {
- MD5Update(&context, req_authenticator, MD5_MAC_LEN);
- MD5Update(&context, saltbuf, sizeof(saltbuf));
- first = 0;
+ addr[1] = req_authenticator;
+ _len[1] = MD5_MAC_LEN;
+ addr[2] = saltbuf;
+ _len[2] = sizeof(saltbuf);
} else {
- MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN);
+ addr[1] = pos - MD5_MAC_LEN;
+ _len[1] = MD5_MAC_LEN;
}
- MD5Final(hash, &context);
+ md5_vector(first ? 3 : 2, addr, _len, hash);
+ first = 0;
for (i = 0; i < MD5_MAC_LEN; i++)
*pos++ ^= hash[i];
@@ -1037,8 +1053,9 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
{
u8 buf[128];
int padlen, i, pos;
- MD5_CTX context;
size_t buf_len;
+ const u8 *addr[2];
+ size_t len[2];
u8 hash[16];
if (data_len > 128)
@@ -1054,20 +1071,22 @@ radius_msg_add_attr_user_password(struct radius_msg *msg,
buf_len += padlen;
}
- MD5Init(&context);
- MD5Update(&context, secret, secret_len);
- MD5Update(&context, msg->hdr->authenticator, 16);
- MD5Final(hash, &context);
+ addr[0] = secret;
+ len[0] = secret_len;
+ addr[1] = msg->hdr->authenticator;
+ len[1] = 16;
+ md5_vector(2, addr, len, hash);
for (i = 0; i < 16; i++)
buf[i] ^= hash[i];
pos = 16;
while (pos < buf_len) {
- MD5Init(&context);
- MD5Update(&context, secret, secret_len);
- MD5Update(&context, &buf[pos - 16], 16);
- MD5Final(hash, &context);
+ addr[0] = secret;
+ len[0] = secret_len;
+ addr[1] = &buf[pos - 16];
+ len[1] = 16;
+ md5_vector(2, addr, len, hash);
for (i = 0; i < 16; i++)
buf[pos + i] ^= hash[i];
@@ -1104,13 +1123,14 @@ 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)
+ size_t *len, const u8 *start)
{
int i;
struct radius_attr_hdr *attr = NULL;
for (i = 0; i < msg->attr_used; i++) {
- if (msg->attrs[i]->type == type) {
+ if (msg->attrs[i]->type == type &&
+ (start == NULL || (u8 *) msg->attrs[i] > start)) {
attr = msg->attrs[i];
break;
}
@@ -1123,3 +1143,18 @@ int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
*len = attr->length - sizeof(*attr);
return 0;
}
+
+
+int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
+{
+ int i, count;
+
+ for (count = 0, i = 0; i < msg->attr_used; i++) {
+ if (msg->attrs[i]->type == type &&
+ msg->attrs[i]->length >=
+ sizeof(struct radius_attr_hdr) + min_len)
+ count++;
+ }
+
+ return count;
+}
diff --git a/contrib/wpa_supplicant/radius.h b/contrib/wpa_supplicant/radius.h
index 318e0ad..b9f8977 100644
--- a/contrib/wpa_supplicant/radius.h
+++ b/contrib/wpa_supplicant/radius.h
@@ -63,7 +63,8 @@ enum { RADIUS_ATTR_USER_NAME = 1,
RADIUS_ATTR_CONNECT_INFO = 77,
RADIUS_ATTR_EAP_MESSAGE = 79,
RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
- RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85
+ RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
+ RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
};
@@ -168,16 +169,16 @@ int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,
size_t secret_len);
struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
- u8 *data, size_t data_len);
+ const u8 *data, size_t data_len);
struct radius_msg *radius_msg_parse(const u8 *data, size_t len);
-int radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len);
+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 *len);
-int radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
- struct radius_msg *sent_msg);
+int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len, struct radius_msg *sent_msg,
+ int auth);
int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
size_t secret_len, const u8 *req_auth);
-int radius_msg_verify_acct(struct radius_msg *msg, u8 *secret,
- size_t secret_len, struct radius_msg *sent_msg);
int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
u8 type);
void radius_msg_make_authenticator(struct radius_msg *msg,
@@ -219,6 +220,7 @@ static inline int radius_msg_get_attr_int32(struct radius_msg *msg, u8 type,
return 0;
}
int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
- size_t *len);
+ size_t *len, const u8 *start);
+int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len);
#endif /* RADIUS_H */
diff --git a/contrib/wpa_supplicant/radius_client.c b/contrib/wpa_supplicant/radius_client.c
index 91ab3c7..abc28bd 100644
--- a/contrib/wpa_supplicant/radius_client.c
+++ b/contrib/wpa_supplicant/radius_client.c
@@ -1,41 +1,39 @@
/*
* Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / RADIUS client / modified for eapol_test
- * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Host AP kernel driver / RADIUS client
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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. See README and COPYING for
- * more details.
+ * 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 <stdlib.h>
#include <stdio.h>
#include <unistd.h>
-#include <netinet/in.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 "common.h"
-#include "wpa.h"
-#include "config_ssid.h"
-#include "wpa_supplicant.h"
-#include "wpa_supplicant_i.h"
+#include "hostapd.h"
#include "radius.h"
#include "radius_client.h"
#include "eloop.h"
-#include "l2_packet.h"
-
-#include "wpa_supplicant.h"
-#define hostapd_logger(h, a, m, l, t...) wpa_printf(MSG_DEBUG, t)
-#define HOSTAPD_DEBUG(l, a...) wpa_printf(MSG_DEBUG, a)
-#define HOSTAPD_DEBUG_COND(l) 1
/* Defaults for RADIUS retransmit values (exponential backoff) */
-#define RADIUS_CLIENT_FIRST_WAIT 1 /* seconds */
+#define RADIUS_CLIENT_FIRST_WAIT 3 /* seconds */
#define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */
#define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts
* before entry is removed from retransmit
@@ -47,11 +45,66 @@
* many failed retry attempts */
+struct radius_rx_handler {
+ RadiusRxResult (*handler)(struct radius_msg *msg,
+ struct radius_msg *req,
+ u8 *shared_secret, size_t shared_secret_len,
+ void *data);
+ void *data;
+};
+
+
+/* RADIUS message retransmit list */
+struct radius_msg_list {
+ u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages
+ * for the same STA. */
+ struct radius_msg *msg;
+ RadiusType msg_type;
+ time_t first_try;
+ time_t next_try;
+ int attempts;
+ int next_wait;
+ struct timeval last_attempt;
+
+ u8 *shared_secret;
+ size_t shared_secret_len;
+
+ /* TODO: server config with failover to backup server(s) */
+
+ struct radius_msg_list *next;
+};
+
+
+struct radius_client_data {
+ void *ctx;
+ struct hostapd_radius_servers *conf;
+
+ int auth_serv_sock; /* socket for authentication RADIUS messages */
+ int acct_serv_sock; /* socket for accounting RADIUS messages */
+ int auth_serv_sock6;
+ int acct_serv_sock6;
+ int auth_sock; /* currently used socket */
+ int acct_sock; /* currently used socket */
+
+ struct radius_rx_handler *auth_handlers;
+ size_t num_auth_handlers;
+ struct radius_rx_handler *acct_handlers;
+ size_t num_acct_handlers;
+
+ struct radius_msg_list *msgs;
+ size_t num_msgs;
+
+ u8 next_radius_identifier;
+};
+
static int
-radius_change_server(struct wpa_supplicant *wpa_s, struct hostapd_radius_server *nserv,
+radius_change_server(struct radius_client_data *radius,
+ struct hostapd_radius_server *nserv,
struct hostapd_radius_server *oserv,
- int sock, int auth);
+ int sock, int sock6, int auth);
+static int radius_client_init_acct(struct radius_client_data *radius);
+static int radius_client_init_auth(struct radius_client_data *radius);
static void radius_client_msg_free(struct radius_msg_list *req)
@@ -62,9 +115,9 @@ static void radius_client_msg_free(struct radius_msg_list *req)
}
-int radius_client_register(struct wpa_supplicant *wpa_s, RadiusType msg_type,
- RadiusRxResult (*handler)(struct wpa_supplicant *wpa_s,
- struct radius_msg *msg,
+int radius_client_register(struct radius_client_data *radius,
+ RadiusType msg_type,
+ RadiusRxResult (*handler)(struct radius_msg *msg,
struct radius_msg *req,
u8 *shared_secret,
size_t shared_secret_len,
@@ -75,11 +128,11 @@ int radius_client_register(struct wpa_supplicant *wpa_s, RadiusType msg_type,
size_t *num;
if (msg_type == RADIUS_ACCT) {
- handlers = &wpa_s->radius->acct_handlers;
- num = &wpa_s->radius->num_acct_handlers;
+ handlers = &radius->acct_handlers;
+ num = &radius->num_acct_handlers;
} else {
- handlers = &wpa_s->radius->auth_handlers;
- num = &wpa_s->radius->num_auth_handlers;
+ handlers = &radius->auth_handlers;
+ num = &radius->num_auth_handlers;
}
newh = (struct radius_rx_handler *)
@@ -97,24 +150,62 @@ int radius_client_register(struct wpa_supplicant *wpa_s, RadiusType msg_type,
}
-static int radius_client_retransmit(struct wpa_supplicant *wpa_s,
+static void radius_client_handle_send_error(struct radius_client_data *radius,
+ int s, RadiusType msg_type)
+{
+#ifndef CONFIG_NATIVE_WINDOWS
+ int _errno = errno;
+ perror("send[RADIUS]");
+ if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Send failed - maybe interface status changed -"
+ " try to connect again");
+ eloop_unregister_read_sock(s);
+ close(s);
+ if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
+ radius_client_init_acct(radius);
+ else
+ radius_client_init_auth(radius);
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+static int radius_client_retransmit(struct radius_client_data *radius,
struct radius_msg_list *entry, time_t now)
{
+ struct hostapd_radius_servers *conf = radius->conf;
int s;
if (entry->msg_type == RADIUS_ACCT ||
- entry->msg_type == RADIUS_ACCT_INTERIM)
- s = wpa_s->radius->acct_serv_sock;
- else
- s = wpa_s->radius->auth_serv_sock;
+ entry->msg_type == RADIUS_ACCT_INTERIM) {
+ s = radius->acct_sock;
+ if (entry->attempts == 0)
+ conf->acct_server->requests++;
+ else {
+ conf->acct_server->timeouts++;
+ conf->acct_server->retransmissions++;
+ }
+ } else {
+ s = radius->auth_sock;
+ if (entry->attempts == 0)
+ conf->auth_server->requests++;
+ else {
+ conf->auth_server->timeouts++;
+ conf->auth_server->retransmissions++;
+ }
+ }
/* retransmit; remove entry if too many attempts */
entry->attempts++;
- HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL, "Resending RADIUS message (id=%d)"
- "\n", entry->msg->hdr->identifier);
+ hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
+ entry->msg->hdr->identifier);
+ gettimeofday(&entry->last_attempt, NULL);
if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
- perror("send[RADIUS]");
+ radius_client_handle_send_error(radius, s, entry->msg_type);
entry->next_try = now + entry->next_wait;
entry->next_wait *= 2;
@@ -132,12 +223,14 @@ static int radius_client_retransmit(struct wpa_supplicant *wpa_s,
static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct radius_client_data *radius = eloop_ctx;
+ struct hostapd_radius_servers *conf = radius->conf;
time_t now, first;
struct radius_msg_list *entry, *prev, *tmp;
int auth_failover = 0, acct_failover = 0;
+ char abuf[50];
- entry = wpa_s->radius->msgs;
+ entry = radius->msgs;
if (!entry)
return;
@@ -147,16 +240,16 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
prev = NULL;
while (entry) {
if (now >= entry->next_try &&
- radius_client_retransmit(wpa_s, entry, now)) {
+ radius_client_retransmit(radius, entry, now)) {
if (prev)
prev->next = entry->next;
else
- wpa_s->radius->msgs = entry->next;
+ radius->msgs = entry->next;
tmp = entry;
entry = entry->next;
radius_client_msg_free(tmp);
- wpa_s->radius->num_msgs--;
+ radius->num_msgs--;
continue;
}
@@ -175,51 +268,98 @@ static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
entry = entry->next;
}
- if (wpa_s->radius->msgs) {
+ if (radius->msgs) {
if (first < now)
first = now;
eloop_register_timeout(first - now, 0,
- radius_client_timer, wpa_s, NULL);
+ 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));
}
- if (auth_failover && wpa_s->num_auth_servers > 1) {
+ if (auth_failover && conf->num_auth_servers > 1) {
struct hostapd_radius_server *next, *old;
- old = wpa_s->auth_server;
- hostapd_logger(wpa_s, NULL, HOSTAPD_MODULE_RADIUS,
+ old = conf->auth_server;
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_NOTICE,
"No response from Authentication server "
"%s:%d - failover",
- inet_ntoa(old->addr), old->port);
+ hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+ old->port);
+
+ for (entry = radius->msgs; entry; entry = entry->next) {
+ if (entry->msg_type == RADIUS_AUTH)
+ old->timeouts++;
+ }
next = old + 1;
- if (next > &(wpa_s->auth_servers
- [wpa_s->num_auth_servers - 1]))
- next = wpa_s->auth_servers;
- wpa_s->auth_server = next;
- radius_change_server(wpa_s, next, old,
- wpa_s->radius->auth_serv_sock, 1);
+ if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
+ next = conf->auth_servers;
+ conf->auth_server = next;
+ radius_change_server(radius, next, old,
+ radius->auth_serv_sock,
+ radius->auth_serv_sock6, 1);
}
- if (acct_failover && wpa_s->num_acct_servers > 1) {
+ if (acct_failover && conf->num_acct_servers > 1) {
struct hostapd_radius_server *next, *old;
- old = wpa_s->acct_server;
- hostapd_logger(wpa_s, NULL, HOSTAPD_MODULE_RADIUS,
+ old = conf->acct_server;
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_NOTICE,
"No response from Accounting server "
"%s:%d - failover",
- inet_ntoa(old->addr), old->port);
+ hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
+ old->port);
+
+ for (entry = radius->msgs; entry; entry = entry->next) {
+ if (entry->msg_type == RADIUS_ACCT ||
+ entry->msg_type == RADIUS_ACCT_INTERIM)
+ old->timeouts++;
+ }
+
next = old + 1;
- if (next > &wpa_s->acct_servers
- [wpa_s->num_acct_servers - 1])
- next = wpa_s->acct_servers;
- wpa_s->acct_server = next;
- radius_change_server(wpa_s, next, old,
- wpa_s->radius->acct_serv_sock, 0);
+ if (next > &conf->acct_servers[conf->num_acct_servers - 1])
+ next = conf->acct_servers;
+ conf->acct_server = next;
+ radius_change_server(radius, next, old,
+ radius->acct_serv_sock,
+ radius->acct_serv_sock6, 0);
}
}
-static void radius_client_list_add(struct wpa_supplicant *wpa_s, struct radius_msg *msg,
+static void radius_client_update_timeout(struct radius_client_data *radius)
+{
+ time_t now, first;
+ struct radius_msg_list *entry;
+
+ eloop_cancel_timeout(radius_client_timer, radius, NULL);
+
+ if (radius->msgs == NULL) {
+ return;
+ }
+
+ first = 0;
+ for (entry = radius->msgs; entry; entry = entry->next) {
+ if (first == 0 || entry->next_try < first)
+ first = entry->next_try;
+ }
+
+ time(&now);
+ if (first < now)
+ first = now;
+ eloop_register_timeout(first - now, 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));
+}
+
+
+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)
{
@@ -251,16 +391,13 @@ static void radius_client_list_add(struct wpa_supplicant *wpa_s, struct radius_m
time(&entry->first_try);
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;
+ radius_client_update_timeout(radius);
- if (!wpa_s->radius->msgs)
- eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
- radius_client_timer, wpa_s, NULL);
-
- entry->next = wpa_s->radius->msgs;
- wpa_s->radius->msgs = entry;
-
- if (wpa_s->radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
+ if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
printf("Removing the oldest un-ACKed RADIUS packet due to "
"retransmit list limits.\n");
prev = NULL;
@@ -273,11 +410,11 @@ static void radius_client_list_add(struct wpa_supplicant *wpa_s, struct radius_m
radius_client_msg_free(entry);
}
} else
- wpa_s->radius->num_msgs++;
+ radius->num_msgs++;
}
-static void radius_client_list_del(struct wpa_supplicant *wpa_s,
+static void radius_client_list_del(struct radius_client_data *radius,
RadiusType msg_type, u8 *addr)
{
struct radius_msg_list *entry, *prev, *tmp;
@@ -285,7 +422,7 @@ static void radius_client_list_del(struct wpa_supplicant *wpa_s,
if (addr == NULL)
return;
- entry = wpa_s->radius->msgs;
+ entry = radius->msgs;
prev = NULL;
while (entry) {
if (entry->msg_type == msg_type &&
@@ -293,14 +430,15 @@ static void radius_client_list_del(struct wpa_supplicant *wpa_s,
if (prev)
prev->next = entry->next;
else
- wpa_s->radius->msgs = entry->next;
+ radius->msgs = entry->next;
tmp = entry;
entry = entry->next;
- HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
- "Removing matching RADIUS message for "
- MACSTR "\n", MAC2STR(addr));
+ hostapd_logger(radius->ctx, addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG,
+ "Removing matching RADIUS message");
radius_client_msg_free(tmp);
- wpa_s->radius->num_msgs--;
+ radius->num_msgs--;
continue;
}
prev = entry;
@@ -309,9 +447,10 @@ static void radius_client_list_del(struct wpa_supplicant *wpa_s,
}
-int radius_client_send(struct wpa_supplicant *wpa_s, struct radius_msg *msg,
- RadiusType msg_type, u8 *addr)
+int radius_client_send(struct radius_client_data *radius,
+ struct radius_msg *msg, RadiusType msg_type, u8 *addr)
{
+ struct hostapd_radius_servers *conf = radius->conf;
u8 *shared_secret;
size_t shared_secret_len;
char *name;
@@ -319,33 +458,36 @@ int radius_client_send(struct wpa_supplicant *wpa_s, struct radius_msg *msg,
if (msg_type == RADIUS_ACCT_INTERIM) {
/* Remove any pending interim acct update for the same STA. */
- radius_client_list_del(wpa_s, msg_type, addr);
+ radius_client_list_del(radius, msg_type, addr);
}
if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
- shared_secret = wpa_s->acct_server->shared_secret;
- shared_secret_len = wpa_s->acct_server->shared_secret_len;
+ shared_secret = conf->acct_server->shared_secret;
+ shared_secret_len = conf->acct_server->shared_secret_len;
radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
name = "accounting";
- s = wpa_s->radius->acct_serv_sock;
+ s = radius->acct_sock;
+ conf->acct_server->requests++;
} else {
- shared_secret = wpa_s->auth_server->shared_secret;
- shared_secret_len = wpa_s->auth_server->shared_secret_len;
+ shared_secret = conf->auth_server->shared_secret;
+ shared_secret_len = conf->auth_server->shared_secret_len;
radius_msg_finish(msg, shared_secret, shared_secret_len);
name = "authentication";
- s = wpa_s->radius->auth_serv_sock;
+ s = radius->auth_sock;
+ conf->auth_server->requests++;
}
- HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
- "Sending RADIUS message to %s server\n", name);
- if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS))
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
+ "server", name);
+ if (conf->msg_dumps)
radius_msg_dump(msg);
res = send(s, msg->buf, msg->buf_used, 0);
if (res < 0)
- perror("send[RADIUS]");
+ radius_client_handle_send_error(radius, s, msg_type);
- radius_client_list_add(wpa_s, msg, msg_type, shared_secret,
+ radius_client_list_add(radius, msg, msg_type, shared_secret,
shared_secret_len, addr);
return res;
@@ -354,22 +496,37 @@ int radius_client_send(struct wpa_supplicant *wpa_s, struct radius_msg *msg,
static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
{
- struct wpa_supplicant *wpa_s = (struct wpa_supplicant *) eloop_ctx;
+ struct radius_client_data *radius = eloop_ctx;
+ struct hostapd_radius_servers *conf = radius->conf;
RadiusType msg_type = (RadiusType) sock_ctx;
- int len, i;
+ int len, i, roundtrip;
unsigned char buf[3000];
struct radius_msg *msg;
struct radius_rx_handler *handlers;
size_t num_handlers;
struct radius_msg_list *req, *prev_req;
+ struct timeval tv;
+ struct hostapd_radius_server *rconf;
+ int invalid_authenticator = 0;
- len = recv(sock, buf, sizeof(buf), 0);
+ if (msg_type == RADIUS_ACCT) {
+ handlers = radius->acct_handlers;
+ num_handlers = radius->num_acct_handlers;
+ rconf = conf->acct_server;
+ } else {
+ handlers = radius->auth_handlers;
+ num_handlers = radius->num_auth_handlers;
+ rconf = conf->auth_server;
+ }
+
+ len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
if (len < 0) {
perror("recv[RADIUS]");
return;
}
- HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
- "Received %d bytes from RADIUS server\n", len);
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
+ "server", len);
if (len == sizeof(buf)) {
printf("Possibly too long UDP frame for our buffer - "
"dropping it\n");
@@ -379,24 +536,32 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
msg = radius_msg_parse(buf, len);
if (msg == NULL) {
printf("Parsing incoming RADIUS frame failed\n");
+ rconf->malformed_responses++;
return;
}
- HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
- "Received RADIUS message\n");
- if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS))
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
+ if (conf->msg_dumps)
radius_msg_dump(msg);
- if (msg_type == RADIUS_ACCT) {
- handlers = wpa_s->radius->acct_handlers;
- num_handlers = wpa_s->radius->num_acct_handlers;
- } else {
- handlers = wpa_s->radius->auth_handlers;
- num_handlers = wpa_s->radius->num_auth_handlers;
+ switch (msg->hdr->code) {
+ case RADIUS_CODE_ACCESS_ACCEPT:
+ rconf->access_accepts++;
+ break;
+ case RADIUS_CODE_ACCESS_REJECT:
+ rconf->access_rejects++;
+ break;
+ case RADIUS_CODE_ACCESS_CHALLENGE:
+ rconf->access_challenges++;
+ break;
+ case RADIUS_CODE_ACCOUNTING_RESPONSE:
+ rconf->responses++;
+ break;
}
prev_req = NULL;
- req = wpa_s->radius->msgs;
+ req = radius->msgs;
while (req) {
/* TODO: also match by src addr:port of the packet when using
* alternative RADIUS servers (?) */
@@ -411,24 +576,34 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
}
if (req == NULL) {
- HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
- "No matching RADIUS request found (type=%d "
- "id=%d) - dropping packet\n",
- msg_type, msg->hdr->identifier);
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG,
+ "No matching RADIUS request found (type=%d "
+ "id=%d) - dropping packet",
+ msg_type, msg->hdr->identifier);
goto fail;
}
+ gettimeofday(&tv, NULL);
+ roundtrip = (tv.tv_sec - req->last_attempt.tv_sec) * 100 +
+ (tv.tv_usec - req->last_attempt.tv_usec) / 10000;
+ hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG,
+ "Received RADIUS packet matched with a pending "
+ "request, round trip time %d.%02d sec",
+ roundtrip / 100, roundtrip % 100);
+ rconf->round_trip_time = roundtrip;
+
/* Remove ACKed RADIUS packet from retransmit list */
if (prev_req)
prev_req->next = req->next;
else
- wpa_s->radius->msgs = req->next;
- wpa_s->radius->num_msgs--;
+ radius->msgs = req->next;
+ radius->num_msgs--;
for (i = 0; i < num_handlers; i++) {
RadiusRxResult res;
- res = handlers[i].handler(wpa_s, msg, req->msg,
- req->shared_secret,
+ res = handlers[i].handler(msg, req->msg, req->shared_secret,
req->shared_secret_len,
handlers[i].data);
switch (res) {
@@ -439,14 +614,25 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
case RADIUS_RX_QUEUED:
radius_client_msg_free(req);
return;
+ case RADIUS_RX_INVALID_AUTHENTICATOR:
+ invalid_authenticator++;
+ /* continue */
case RADIUS_RX_UNKNOWN:
/* continue with next handler */
break;
}
}
- printf("No RADIUS RX handler found (type=%d code=%d id=%d) - dropping "
- "packet\n", msg_type, msg->hdr->code, msg->hdr->identifier);
+ if (invalid_authenticator)
+ rconf->bad_authenticators++;
+ else
+ rconf->unknown_types++;
+ hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
+ "(type=%d code=%d id=%d)%s - dropping packet",
+ msg_type, msg->hdr->code, msg->hdr->identifier,
+ invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
+ "");
radius_client_msg_free(req);
fail:
@@ -455,24 +641,26 @@ static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
}
-u8 radius_client_get_id(struct wpa_supplicant *wpa_s)
+u8 radius_client_get_id(struct radius_client_data *radius)
{
struct radius_msg_list *entry, *prev, *remove;
- u8 id = wpa_s->radius->next_radius_identifier++;
+ u8 id = radius->next_radius_identifier++;
/* remove entries with matching id from retransmit list to avoid
* using new reply from the RADIUS server with an old request */
- entry = wpa_s->radius->msgs;
+ entry = radius->msgs;
prev = NULL;
while (entry) {
if (entry->msg->hdr->identifier == id) {
- HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
- "Removing pending RADIUS message, since "
- "its id (%d) is reused\n", id);
+ hostapd_logger(radius->ctx, entry->addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG,
+ "Removing pending RADIUS message, "
+ "since its id (%d) is reused", id);
if (prev)
prev->next = entry->next;
else
- wpa_s->radius->msgs = entry->next;
+ radius->msgs = entry->next;
remove = entry;
} else
remove = NULL;
@@ -487,18 +675,18 @@ u8 radius_client_get_id(struct wpa_supplicant *wpa_s)
}
-void radius_client_flush(struct wpa_supplicant *wpa_s)
+void radius_client_flush(struct radius_client_data *radius)
{
struct radius_msg_list *entry, *prev;
- if (!wpa_s->radius)
+ if (!radius)
return;
- eloop_cancel_timeout(radius_client_timer, wpa_s, NULL);
+ eloop_cancel_timeout(radius_client_timer, radius, NULL);
- entry = wpa_s->radius->msgs;
- wpa_s->radius->msgs = NULL;
- wpa_s->radius->num_msgs = 0;
+ entry = radius->msgs;
+ radius->msgs = NULL;
+ radius->num_msgs = 0;
while (entry) {
prev = entry;
entry = entry->next;
@@ -508,16 +696,26 @@ void radius_client_flush(struct wpa_supplicant *wpa_s)
static int
-radius_change_server(struct wpa_supplicant *wpa_s, struct hostapd_radius_server *nserv,
+radius_change_server(struct radius_client_data *radius,
+ struct hostapd_radius_server *nserv,
struct hostapd_radius_server *oserv,
- int sock, int auth)
+ int sock, int sock6, int auth)
{
struct sockaddr_in serv;
-
- hostapd_logger(wpa_s, NULL, HOSTAPD_MODULE_RADIUS, HOSTAPD_LEVEL_INFO,
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 serv6;
+#endif /* CONFIG_IPV6 */
+ struct sockaddr *addr;
+ socklen_t addrlen;
+ char abuf[50];
+ int sel_sock;
+
+ hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
"%s server %s:%d",
auth ? "Authentication" : "Accounting",
- inet_ntoa(nserv->addr), nserv->port);
+ hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
+ nserv->port);
if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
memcmp(nserv->shared_secret, oserv->shared_secret,
@@ -527,11 +725,11 @@ radius_change_server(struct wpa_supplicant *wpa_s, struct hostapd_radius_server
* update all message authenticators and
* User-Passwords, etc. and retry with new server. For
* now, just drop all pending packets. */
- radius_client_flush(wpa_s);
+ radius_client_flush(radius);
} else {
/* Reset retry counters for the new server */
struct radius_msg_list *entry;
- entry = wpa_s->radius->msgs;
+ entry = radius->msgs;
while (entry) {
entry->next_try = entry->first_try +
RADIUS_CLIENT_FIRST_WAIT;
@@ -539,136 +737,379 @@ radius_change_server(struct wpa_supplicant *wpa_s, struct hostapd_radius_server
entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
entry = entry->next;
}
- if (wpa_s->radius->msgs) {
- eloop_cancel_timeout(radius_client_timer, wpa_s, NULL);
+ if (radius->msgs) {
+ eloop_cancel_timeout(radius_client_timer, radius,
+ NULL);
eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
- radius_client_timer, wpa_s,
+ radius_client_timer, radius,
NULL);
}
}
- memset(&serv, 0, sizeof(serv));
- serv.sin_family = AF_INET;
- serv.sin_addr.s_addr = nserv->addr.s_addr;
- serv.sin_port = htons(nserv->port);
+ switch (nserv->addr.af) {
+ case AF_INET:
+ 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);
+ addr = (struct sockaddr *) &serv;
+ addrlen = sizeof(serv);
+ sel_sock = sock;
+ break;
+#ifdef CONFIG_IPV6
+ case AF_INET6:
+ memset(&serv6, 0, sizeof(serv6));
+ serv6.sin6_family = AF_INET6;
+ 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);
+ sel_sock = sock6;
+ break;
+#endif /* CONFIG_IPV6 */
+ default:
+ return -1;
+ }
- if (connect(sock, (struct sockaddr *) &serv, sizeof(serv)) < 0) {
+ if (connect(sel_sock, addr, addrlen) < 0) {
perror("connect[radius]");
return -1;
}
+ if (auth)
+ radius->auth_sock = sel_sock;
+ else
+ radius->acct_sock = sel_sock;
+
return 0;
}
static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct radius_client_data *radius = eloop_ctx;
+ struct hostapd_radius_servers *conf = radius->conf;
struct hostapd_radius_server *oserv;
- if (wpa_s->radius->auth_serv_sock >= 0 && wpa_s->auth_servers &&
- wpa_s->auth_server != wpa_s->auth_servers) {
- oserv = wpa_s->auth_server;
- wpa_s->auth_server = wpa_s->auth_servers;
- radius_change_server(wpa_s, wpa_s->auth_server, oserv,
- wpa_s->radius->auth_serv_sock, 1);
+ if (radius->auth_sock >= 0 && conf->auth_servers &&
+ conf->auth_server != conf->auth_servers) {
+ oserv = conf->auth_server;
+ conf->auth_server = conf->auth_servers;
+ radius_change_server(radius, conf->auth_server, oserv,
+ radius->auth_serv_sock,
+ radius->auth_serv_sock6, 1);
}
- if (wpa_s->radius->acct_serv_sock >= 0 && wpa_s->acct_servers &&
- wpa_s->acct_server != wpa_s->acct_servers) {
- oserv = wpa_s->acct_server;
- wpa_s->acct_server = wpa_s->acct_servers;
- radius_change_server(wpa_s, wpa_s->acct_server, oserv,
- wpa_s->radius->acct_serv_sock, 0);
+ if (radius->acct_sock >= 0 && conf->acct_servers &&
+ conf->acct_server != conf->acct_servers) {
+ oserv = conf->acct_server;
+ conf->acct_server = conf->acct_servers;
+ radius_change_server(radius, conf->acct_server, oserv,
+ radius->acct_serv_sock,
+ radius->acct_serv_sock6, 0);
}
- if (wpa_s->radius_retry_primary_interval)
- eloop_register_timeout(wpa_s->
- radius_retry_primary_interval, 0,
- radius_retry_primary_timer, wpa_s, NULL);
+ if (conf->retry_primary_interval)
+ eloop_register_timeout(conf->retry_primary_interval, 0,
+ radius_retry_primary_timer, radius,
+ NULL);
}
-static int radius_client_init_auth(struct wpa_supplicant *wpa_s)
+static int radius_client_init_auth(struct radius_client_data *radius)
{
- wpa_s->radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (wpa_s->radius->auth_serv_sock < 0) {
+ struct hostapd_radius_servers *conf = radius->conf;
+ int ok = 0;
+
+ radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (radius->auth_serv_sock < 0)
perror("socket[PF_INET,SOCK_DGRAM]");
+ else
+ ok++;
+
+#ifdef CONFIG_IPV6
+ radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
+ if (radius->auth_serv_sock6 < 0)
+ perror("socket[PF_INET6,SOCK_DGRAM]");
+ else
+ ok++;
+#endif /* CONFIG_IPV6 */
+
+ if (ok == 0)
return -1;
- }
- radius_change_server(wpa_s, wpa_s->auth_server, NULL,
- wpa_s->radius->auth_serv_sock, 1);
+ radius_change_server(radius, conf->auth_server, NULL,
+ radius->auth_serv_sock, radius->auth_serv_sock6,
+ 1);
+
+ if (radius->auth_serv_sock >= 0 &&
+ eloop_register_read_sock(radius->auth_serv_sock,
+ radius_client_receive, radius,
+ (void *) RADIUS_AUTH)) {
+ printf("Could not register read socket for authentication "
+ "server\n");
+ return -1;
+ }
- if (eloop_register_read_sock(wpa_s->radius->auth_serv_sock,
- radius_client_receive, wpa_s,
+#ifdef CONFIG_IPV6
+ if (radius->auth_serv_sock6 >= 0 &&
+ eloop_register_read_sock(radius->auth_serv_sock6,
+ radius_client_receive, radius,
(void *) RADIUS_AUTH)) {
printf("Could not register read socket for authentication "
"server\n");
return -1;
}
+#endif /* CONFIG_IPV6 */
return 0;
}
-static int radius_client_init_acct(struct wpa_supplicant *wpa_s)
+static int radius_client_init_acct(struct radius_client_data *radius)
{
- wpa_s->radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
- if (wpa_s->radius->acct_serv_sock < 0) {
+ struct hostapd_radius_servers *conf = radius->conf;
+ int ok = 0;
+
+ radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (radius->acct_serv_sock < 0)
perror("socket[PF_INET,SOCK_DGRAM]");
+ else
+ ok++;
+
+ radius_change_server(radius, conf->acct_server, NULL,
+ radius->acct_serv_sock, radius->acct_serv_sock6,
+ 0);
+
+ if (radius->acct_serv_sock >= 0 &&
+ eloop_register_read_sock(radius->acct_serv_sock,
+ radius_client_receive, radius,
+ (void *) RADIUS_ACCT)) {
+ printf("Could not register read socket for accounting "
+ "server\n");
return -1;
}
- radius_change_server(wpa_s, wpa_s->acct_server, NULL,
- wpa_s->radius->acct_serv_sock, 0);
-
- if (eloop_register_read_sock(wpa_s->radius->acct_serv_sock,
- radius_client_receive, wpa_s,
+#ifdef CONFIG_IPV6
+ if (radius->acct_serv_sock6 >= 0 &&
+ eloop_register_read_sock(radius->acct_serv_sock6,
+ radius_client_receive, radius,
(void *) RADIUS_ACCT)) {
printf("Could not register read socket for accounting "
"server\n");
return -1;
}
+#endif /* CONFIG_IPV6 */
return 0;
}
-int radius_client_init(struct wpa_supplicant *wpa_s)
+struct radius_client_data *
+radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
{
- wpa_s->radius = malloc(sizeof(struct radius_client_data));
- if (wpa_s->radius == NULL)
- return -1;
-
- memset(wpa_s->radius, 0, sizeof(struct radius_client_data));
- wpa_s->radius->auth_serv_sock = wpa_s->radius->acct_serv_sock = -1;
-
- if (wpa_s->auth_server && radius_client_init_auth(wpa_s))
- return -1;
+ struct radius_client_data *radius;
+
+ radius = malloc(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 =
+ radius->auth_serv_sock6 = radius->acct_serv_sock6 =
+ radius->auth_sock = radius->acct_sock = -1;
+
+ if (conf->auth_server && radius_client_init_auth(radius)) {
+ radius_client_deinit(radius);
+ return NULL;
+ }
- if (wpa_s->acct_server && radius_client_init_acct(wpa_s))
- return -1;
+ if (conf->acct_server && radius_client_init_acct(radius)) {
+ radius_client_deinit(radius);
+ return NULL;
+ }
- if (wpa_s->radius_retry_primary_interval)
- eloop_register_timeout(wpa_s->radius_retry_primary_interval, 0,
- radius_retry_primary_timer, wpa_s,
+ if (conf->retry_primary_interval)
+ eloop_register_timeout(conf->retry_primary_interval, 0,
+ radius_retry_primary_timer, radius,
NULL);
- return 0;
+ return radius;
}
-void radius_client_deinit(struct wpa_supplicant *wpa_s)
+void radius_client_deinit(struct radius_client_data *radius)
{
- if (!wpa_s->radius)
+ if (!radius)
return;
- eloop_cancel_timeout(radius_retry_primary_timer, wpa_s, NULL);
+ eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
+
+ radius_client_flush(radius);
+ free(radius->auth_handlers);
+ free(radius->acct_handlers);
+ free(radius);
+}
+
+
+void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
+{
+ struct radius_msg_list *entry, *prev, *tmp;
+
+ prev = NULL;
+ entry = radius->msgs;
+ while (entry) {
+ if (entry->msg_type == RADIUS_AUTH &&
+ memcmp(entry->addr, addr, ETH_ALEN) == 0) {
+ hostapd_logger(radius->ctx, addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_DEBUG,
+ "Removing pending RADIUS authentication"
+ " message for removed client");
+
+ if (prev)
+ prev->next = entry->next;
+ else
+ radius->msgs = entry->next;
+
+ tmp = entry;
+ entry = entry->next;
+ radius_client_msg_free(tmp);
+ radius->num_msgs--;
+ continue;
+ }
+
+ prev = entry;
+ entry = entry->next;
+ }
+}
+
+
+static int radius_client_dump_auth_server(char *buf, size_t buflen,
+ struct hostapd_radius_server *serv,
+ struct radius_client_data *cli)
+{
+ int pending = 0;
+ struct radius_msg_list *msg;
+ char abuf[50];
+
+ if (cli) {
+ for (msg = cli->msgs; msg; msg = msg->next) {
+ if (msg->msg_type == RADIUS_AUTH)
+ pending++;
+ }
+ }
+
+ 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);
+}
+
+
+static int radius_client_dump_acct_server(char *buf, size_t buflen,
+ struct hostapd_radius_server *serv,
+ struct radius_client_data *cli)
+{
+ int pending = 0;
+ struct radius_msg_list *msg;
+ char abuf[50];
+
+ if (cli) {
+ for (msg = cli->msgs; msg; msg = msg->next) {
+ if (msg->msg_type == RADIUS_ACCT ||
+ msg->msg_type == RADIUS_ACCT_INTERIM)
+ pending++;
+ }
+ }
+
+ 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);
+}
+
+
+int radius_client_get_mib(struct radius_client_data *radius, char *buf,
+ size_t buflen)
+{
+ struct hostapd_radius_servers *conf = radius->conf;
+ int i;
+ struct hostapd_radius_server *serv;
+ int count = 0;
+
+ if (conf->auth_servers) {
+ for (i = 0; i < conf->num_auth_servers; i++) {
+ serv = &conf->auth_servers[i];
+ count += radius_client_dump_auth_server(
+ buf + count, buflen - count, serv,
+ serv == conf->auth_server ?
+ radius : NULL);
+ }
+ }
+
+ if (conf->acct_servers) {
+ for (i = 0; i < conf->num_acct_servers; i++) {
+ serv = &conf->acct_servers[i];
+ count += radius_client_dump_acct_server(
+ buf + count, buflen - count, serv,
+ serv == conf->acct_server ?
+ radius : NULL);
+ }
+ }
- radius_client_flush(wpa_s);
- free(wpa_s->radius->auth_handlers);
- free(wpa_s->radius->acct_handlers);
- free(wpa_s->radius);
- wpa_s->radius = NULL;
+ return count;
}
diff --git a/contrib/wpa_supplicant/radius_client.h b/contrib/wpa_supplicant/radius_client.h
index 993f8d0..d21ca83 100644
--- a/contrib/wpa_supplicant/radius_client.h
+++ b/contrib/wpa_supplicant/radius_client.h
@@ -1,81 +1,87 @@
#ifndef RADIUS_CLIENT_H
#define RADIUS_CLIENT_H
-typedef enum {
- RADIUS_AUTH,
- RADIUS_ACCT,
- RADIUS_ACCT_INTERIM /* used only with radius_client_send(); just like
- * RADIUS_ACCT, but removes any pending interim
- * RADIUS Accounting packages for the same STA
- * before sending the new interim update */
-} RadiusType;
+#include "config_types.h"
-/* RADIUS message retransmit list */
-struct radius_msg_list {
- u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages
- * for the same STA. */
- struct radius_msg *msg;
- RadiusType msg_type;
- time_t first_try;
- time_t next_try;
- int attempts;
- int next_wait;
+struct radius_msg;
+struct hostapd_radius_server {
+ /* MIB prefix for shared variables:
+ * @ = radiusAuth or radiusAcc depending on the type of the server */
+ struct hostapd_ip_addr addr; /* @ServerAddress */
+ int port; /* @ClientServerPortNumber */
u8 *shared_secret;
size_t shared_secret_len;
- /* TODO: server config with failover to backup server(s) */
-
- struct radius_msg_list *next;
+ /* Dynamic (not from configuration file) MIB data */
+ int index; /* @ServerIndex */
+ int round_trip_time; /* @ClientRoundTripTime; in hundredths of a
+ * second */
+ u32 requests; /* @Client{Access,}Requests */
+ u32 retransmissions; /* @Client{Access,}Retransmissions */
+ u32 access_accepts; /* radiusAuthClientAccessAccepts */
+ u32 access_rejects; /* radiusAuthClientAccessRejects */
+ u32 access_challenges; /* radiusAuthClientAccessChallenges */
+ u32 responses; /* radiusAccClientResponses */
+ u32 malformed_responses; /* @ClientMalformed{Access,}Responses */
+ u32 bad_authenticators; /* @ClientBadAuthenticators */
+ u32 timeouts; /* @ClientTimeouts */
+ u32 unknown_types; /* @ClientUnknownTypes */
+ u32 packets_dropped; /* @ClientPacketsDropped */
+ /* @ClientPendingRequests: length of hapd->radius->msgs for matching
+ * msg_type */
};
+struct hostapd_radius_servers {
+ /* RADIUS Authentication and Accounting servers in priority order */
+ struct hostapd_radius_server *auth_servers, *auth_server;
+ int num_auth_servers;
+ struct hostapd_radius_server *acct_servers, *acct_server;
+ int num_acct_servers;
-typedef enum {
- RADIUS_RX_PROCESSED,
- RADIUS_RX_QUEUED,
- RADIUS_RX_UNKNOWN
-} RadiusRxResult;
+ int retry_primary_interval;
+ int acct_interim_interval;
-struct radius_rx_handler {
- RadiusRxResult (*handler)(struct wpa_supplicant *wpa_s,
- struct radius_msg *msg,
- struct radius_msg *req,
- u8 *shared_secret, size_t shared_secret_len,
- void *data);
- void *data;
+ int msg_dumps;
};
-struct radius_client_data {
- int auth_serv_sock; /* socket for authentication RADIUS messages */
- int acct_serv_sock; /* socket for accounting RADIUS messages */
-
- struct radius_rx_handler *auth_handlers;
- size_t num_auth_handlers;
- struct radius_rx_handler *acct_handlers;
- size_t num_acct_handlers;
- struct radius_msg_list *msgs;
- size_t num_msgs;
+typedef enum {
+ RADIUS_AUTH,
+ RADIUS_ACCT,
+ RADIUS_ACCT_INTERIM /* used only with radius_client_send(); just like
+ * RADIUS_ACCT, but removes any pending interim
+ * RADIUS Accounting packages for the same STA
+ * before sending the new interim update */
+} RadiusType;
- u8 next_radius_identifier;
- u32 acct_session_id_hi;
- u32 acct_session_id_lo;
-};
+typedef enum {
+ RADIUS_RX_PROCESSED,
+ RADIUS_RX_QUEUED,
+ RADIUS_RX_UNKNOWN,
+ RADIUS_RX_INVALID_AUTHENTICATOR
+} RadiusRxResult;
+struct radius_client_data;
-int radius_client_register(struct wpa_supplicant *wpa_s, RadiusType msg_type,
+int radius_client_register(struct radius_client_data *radius,
+ RadiusType msg_type,
RadiusRxResult (*handler)
- (struct wpa_supplicant *wpa_s,
- struct radius_msg *msg, struct radius_msg *req,
+ (struct radius_msg *msg, struct radius_msg *req,
u8 *shared_secret, size_t shared_secret_len,
void *data),
void *data);
-int radius_client_send(struct wpa_supplicant *wpa_s, struct radius_msg *msg,
+int radius_client_send(struct radius_client_data *radius,
+ struct radius_msg *msg,
RadiusType msg_type, u8 *addr);
-u8 radius_client_get_id(struct wpa_supplicant *wpa_s);
-
-void radius_client_flush(struct wpa_supplicant *wpa_s);
-int radius_client_init(struct wpa_supplicant *wpa_s);
-void radius_client_deinit(struct wpa_supplicant *wpa_s);
+u8 radius_client_get_id(struct radius_client_data *radius);
+
+void radius_client_flush(struct radius_client_data *radius);
+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);
#endif /* RADIUS_CLIENT_H */
diff --git a/contrib/wpa_supplicant/rc4.c b/contrib/wpa_supplicant/rc4.c
index 97ec1b0..4cf14d9 100644
--- a/contrib/wpa_supplicant/rc4.c
+++ b/contrib/wpa_supplicant/rc4.c
@@ -1,7 +1,6 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / RC4
- * Copyright (c) 2002-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * RC4 stream cipher
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 +18,20 @@
#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
-void rc4_skip(u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len)
+/**
+ * rc4 - XOR RC4 stream to given data with skip-stream-start
+ * @key: RC4 key
+ * @keylen: RC4 key length
+ * @skip: number of bytes to skip from the beginning of the RC4 stream
+ * @data: data to be XOR'ed with RC4 stream
+ * @data_len: buf length
+ *
+ * Generate RC4 pseudo random stream for the given key, skip beginning of the
+ * stream, and XOR the end result with the data buffer to perform RC4
+ * encryption/decryption.
+ */
+void rc4_skip(const u8 *key, size_t keylen, size_t skip,
+ u8 *data, size_t data_len)
{
u32 i, j, k;
u8 S[256], *pos;
@@ -57,7 +69,17 @@ void rc4_skip(u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len)
}
-void rc4(u8 *buf, size_t len, u8 *key, size_t key_len)
+/**
+ * rc4 - XOR RC4 stream to given data
+ * @buf: data to be XOR'ed with RC4 stream
+ * @len: buf length
+ * @key: RC4 key
+ * @key_len: RC4 key length
+ *
+ * Generate RC4 pseudo random stream for the given key and XOR this with the
+ * data buffer to perform RC4 encryption/decryption.
+ */
+void rc4(u8 *buf, size_t len, const u8 *key, size_t key_len)
{
rc4_skip(key, key_len, 0, buf, len);
}
diff --git a/contrib/wpa_supplicant/rc4.h b/contrib/wpa_supplicant/rc4.h
index 0e77b7e..3873240 100644
--- a/contrib/wpa_supplicant/rc4.h
+++ b/contrib/wpa_supplicant/rc4.h
@@ -1,7 +1,22 @@
+/*
+ * RC4 stream cipher
+ * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.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 RC4_H
#define RC4_H
-void rc4_skip(u8 *key, size_t keylen, size_t skip, u8 *data, size_t data_len);
-void rc4(u8 *buf, size_t len, u8 *key, size_t key_len);
+void rc4_skip(const u8 *key, size_t keylen, size_t skip,
+ u8 *data, size_t data_len);
+void rc4(u8 *buf, size_t len, const u8 *key, size_t key_len);
#endif /* RC4_H */
diff --git a/contrib/wpa_supplicant/sha1.c b/contrib/wpa_supplicant/sha1.c
index 04943b5..7e32e31 100644
--- a/contrib/wpa_supplicant/sha1.c
+++ b/contrib/wpa_supplicant/sha1.c
@@ -19,36 +19,38 @@
#include "common.h"
#include "sha1.h"
#include "md5.h"
+#include "crypto.h"
-void sha1_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
- u8 *mac)
-{
- SHA1_CTX context;
- SHA1Init(&context);
- SHA1Update(&context, key, key_len);
- SHA1Update(&context, data, data_len);
- SHA1Update(&context, key, key_len);
- SHA1Final(mac, &context);
-}
-
-
-/* HMAC code is based on RFC 2104 */
+/**
+ * hmac_sha1_vector - HMAC-SHA1 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 (20 bytes)
+ */
void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac)
{
- SHA1_CTX context;
- unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */
- unsigned char k_opad[65]; /* outer padding - key XORd with opad */
+ 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];
+
+ 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 = SHA1(key) */
if (key_len > 64) {
- SHA1Init(&context);
- SHA1Update(&context, key, key_len);
- SHA1Final(tk, &context);
-
+ sha1_vector(1, &key, &key_len, tk);
key = tk;
key_len = 20;
}
@@ -62,35 +64,45 @@ void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
* opad is the byte 0x5c repeated 64 times
* and text is the data being protected */
- /* start out by storing key in pads */
- memset(k_ipad, 0, sizeof(k_ipad));
- memset(k_opad, 0, sizeof(k_opad));
- memcpy(k_ipad, key, key_len);
- memcpy(k_opad, key, key_len);
-
- /* XOR key with ipad and opad values */
- for (i = 0; i < 64; i++) {
- k_ipad[i] ^= 0x36;
- k_opad[i] ^= 0x5c;
- }
+ /* 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 SHA1 */
- SHA1Init(&context); /* init context for 1st pass */
- SHA1Update(&context, k_ipad, 64); /* start with inner pad */
- /* then text of datagram; all fragments */
+ _addr[0] = k_pad;
+ _len[0] = 64;
for (i = 0; i < num_elem; i++) {
- SHA1Update(&context, addr[i], len[i]);
+ _addr[i + 1] = addr[i];
+ _len[i + 1] = len[i];
}
- SHA1Final(mac, &context); /* finish up 1st pass */
+ sha1_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 SHA1 */
- SHA1Init(&context); /* init context for 2nd pass */
- SHA1Update(&context, k_opad, 64); /* start with outer pad */
- SHA1Update(&context, mac, 20); /* then results of 1st hash */
- SHA1Final(mac, &context); /* finish up 2nd pass */
+ _addr[0] = k_pad;
+ _len[0] = 64;
+ _addr[1] = mac;
+ _len[1] = SHA1_MAC_LEN;
+ sha1_vector(2, _addr, _len, mac);
}
+/**
+ * hmac_sha1 - HMAC-SHA1 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_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac)
{
@@ -98,6 +110,19 @@ void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
}
+/**
+ * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
+ * @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 (e.g., PMK in IEEE 802.11i).
+ */
void sha1_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
@@ -135,7 +160,20 @@ void sha1_prf(const u8 *key, size_t key_len, const char *label,
}
-/* draft-cam-winget-eap-fast-00.txt */
+/**
+ * sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @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 for EAP-FAST. T-PRF is defined in
+ * draft-cam-winget-eap-fast-02.txt, Appendix B.
+ */
void sha1_t_prf(const u8 *key, size_t key_len, const char *label,
const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len)
{
@@ -177,7 +215,19 @@ void sha1_t_prf(const u8 *key, size_t key_len, const char *label,
}
-/* RFC 2246 */
+/**
+ * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+*
+ * 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)
{
@@ -285,6 +335,19 @@ static void pbkdf2_sha1_f(const char *passphrase, const char *ssid,
}
+/**
+ * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
+ * @passphrase: ASCII passphrase
+ * @ssid: SSID
+ * @ssid_len: SSID length in bytes
+ * @interations: Number of iterations to run
+ * @buf: Buffer for the generated key
+ * @buflen: Length of the buffer in bytes
+ *
+ * This function is used to derive PSK for WPA-PSK. For this protocol,
+ * iterations is set to 4096 and buflen to 32. This function is described in
+ * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0.
+ */
void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen)
{
@@ -305,20 +368,27 @@ void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
}
-void sha1_transform(u8 *state, u8 data[64])
-{
-#ifdef EAP_TLS_FUNCS
- SHA_CTX context;
- memset(&context, 0, sizeof(context));
- memcpy(&context.h0, state, 5 * 4);
- SHA1_Transform(&context, data);
- memcpy(state, &context.h0, 5 * 4);
-#else /* EAP_TLS_FUNCS */
- SHA1Transform((u32 *) state, data);
-#endif /* EAP_TLS_FUNCS */
-}
+#ifndef EAP_TLS_FUNCS
+
+typedef struct {
+ u32 state[5];
+ u32 count[2];
+ unsigned char buffer[64];
+} 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);
+static void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
+/**
+ * sha1_vector - SHA-1 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ */
void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac)
{
@@ -332,7 +402,21 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
}
-#ifndef EAP_TLS_FUNCS
+/**
+ * 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])
+{
+ SHA1Transform((u32 *) state, data);
+}
+
/* ===== start - public domain SHA1 implementation ===== */
@@ -462,7 +546,7 @@ void SHAPrintContext(SHA1_CTX *context, char *msg)
/* Hash a single 512-bit block. This is the core of the algorithm. */
-void SHA1Transform(u32 state[5], const unsigned char buffer[64])
+static void SHA1Transform(u32 state[5], const unsigned char buffer[64])
{
u32 a, b, c, d, e;
typedef union {
@@ -520,7 +604,7 @@ void SHA1Transform(u32 state[5], const unsigned char buffer[64])
/* SHA1Init - Initialize new context */
-void SHA1Init(SHA1_CTX* context)
+static void SHA1Init(SHA1_CTX* context)
{
/* SHA1 initialization constants */
context->state[0] = 0x67452301;
@@ -534,7 +618,7 @@ void SHA1Init(SHA1_CTX* context)
/* Run your data through this. */
-void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
+static void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
{
u32 i, j;
const unsigned char *data = _data;
@@ -564,7 +648,7 @@ void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
/* Add padding and return the message digest. */
-void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+static void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
{
u32 i;
unsigned char finalcount[8];
diff --git a/contrib/wpa_supplicant/sha1.h b/contrib/wpa_supplicant/sha1.h
index 186e3c1..3c6d915 100644
--- a/contrib/wpa_supplicant/sha1.h
+++ b/contrib/wpa_supplicant/sha1.h
@@ -1,36 +1,22 @@
+/*
+ * SHA1 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 SHA1_H
#define SHA1_H
-#ifdef EAP_TLS_FUNCS
-
-#include <openssl/sha.h>
-
-#define SHA1_CTX SHA_CTX
-#define SHA1Init SHA1_Init
-#define SHA1Update SHA1_Update
-#define SHA1Final SHA1_Final
-#define SHA1Transform SHA1_Transform
-#define SHA1_MAC_LEN SHA_DIGEST_LENGTH
-
-#else /* EAP_TLS_FUNCS */
-
#define SHA1_MAC_LEN 20
-typedef struct {
- u32 state[5];
- u32 count[2];
- unsigned char buffer[64];
-} SHA1_CTX;
-
-void SHA1Init(SHA1_CTX *context);
-void SHA1Update(SHA1_CTX *context, const void *data, u32 len);
-void SHA1Final(unsigned char digest[20], SHA1_CTX* context);
-void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
-
-#endif /* EAP_TLS_FUNCS */
-
-void sha1_mac(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
- u8 *mac);
void hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
const u8 *addr[], const size_t *len, u8 *mac);
void hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
@@ -43,8 +29,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);
void pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
int iterations, u8 *buf, size_t buflen);
-void sha1_transform(u8 *state, u8 data[64]);
-void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
- u8 *mac);
#endif /* SHA1_H */
diff --git a/contrib/wpa_supplicant/tls.h b/contrib/wpa_supplicant/tls.h
index 99c9b33..a6a8110 100644
--- a/contrib/wpa_supplicant/tls.h
+++ b/contrib/wpa_supplicant/tls.h
@@ -1,3 +1,17 @@
+/*
+ * WPA Supplicant / SSL/TLS interface definition
+ * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.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 TLS_H
#define TLS_H
@@ -10,28 +24,115 @@ struct tls_keys {
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;
+};
+
+struct tls_config {
+ const char *opensc_engine_path;
+ const char *pkcs11_engine_path;
+ const char *pkcs11_module_path;
};
/**
- * tls_init - initialize TLS library
- *
- * Returns: Context data to be used as @tls_ctx in calls to other functions,
+ * struct tls_connection_params - Parameters for TLS connection
+ * @ca_cert: File or reference name for CA X.509 certificate in PEM or DER
+ * format
+ * @ca_cert_blob: ca_cert as inlined data or %NULL if not used
+ * @ca_cert_blob_len: ca_cert_blob length
+ * @ca_path: Path to CA certificates (OpenSSL specific)
+ * @subject_match: String to match in the subject of the peer certificate or
+ * %NULL to allow all subjects
+ * @altsubject_match: String to match in the alternative subject of the peer
+ * certificate or %NULL to allow all alternative subjects
+ * @client_cert: File or reference name for client X.509 certificate in PEM or
+ * DER format
+ * @client_cert_blob: client_cert as inlined data or %NULL if not used
+ * @client_cert_blob_len: client_cert_blob length
+ * @private_key: File or reference name for client private key in PEM or DER
+ * format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY)
+ * @private_key_blob: private_key as inlined data or %NULL if not used
+ * @private_key_blob_len: private_key_blob length
+ * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
+ * passphrase is used.
+ * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
+ * @dh_blob: dh_file as inlined data or %NULL if not used
+ * @dh_blob_len: dh_blob length
+ * @engine: 1 = use engine (e.g., a smartcard) for private key operations
+ * (this is OpenSSL specific for now)
+ * @engine_id: engine id string (this is OpenSSL specific for now)
+ * @ppin: pointer to the pin variable in the configuration
+ * (this is OpenSSL specific for now)
+ * @key_id: the private key's key id (this is OpenSSL specific for now)
+ *
+ * TLS connection parameters to be configured with tls_connection_set_params().
+ *
+ * Certificates and private key can be configured either as a reference name
+ * (file path or reference to certificate store) or by providing the same data
+ * as a pointer to the data in memory. Only one option will be used for each
+ * field.
+ */
+struct tls_connection_params {
+ const char *ca_cert;
+ const u8 *ca_cert_blob;
+ size_t ca_cert_blob_len;
+ const char *ca_path;
+ const char *subject_match;
+ const char *altsubject_match;
+ const char *client_cert;
+ const u8 *client_cert_blob;
+ size_t client_cert_blob_len;
+ const char *private_key;
+ const u8 *private_key_blob;
+ size_t private_key_blob_len;
+ const char *private_key_passwd;
+ const char *dh_file;
+ const u8 *dh_blob;
+ size_t dh_blob_len;
+
+ /* OpenSSL specific variables */
+ int engine;
+ const char *engine_id;
+ const char *pin;
+ const char *key_id;
+};
+
+
+/**
+ * tls_init - Initialize TLS library
+ * @conf: Configuration data for TLS library
+ * Returns: Context data to be used as tls_ctx in calls to other functions,
* or %NULL on failure.
*
- * Called once during program startup.
+ * Called once during program startup and once for each RSN pre-authentication
+ * session. In other words, there can be two concurrent TLS contexts. If global
+ * library initialization is needed (i.e., one that is shared between both
+ * authentication types), the TLS library wrapper should maintain a reference
+ * counter and do global initialization only when moving from 0 to 1 reference.
*/
-void * tls_init(void);
+void * tls_init(const struct tls_config *conf);
/**
- * tls_deinit - deinitialize TLS library
+ * tls_deinit - Deinitialize TLS library
* @tls_ctx: TLS context data from tls_init()
*
- * Called once during program shutdown.
+ * Called once during program shutdown and once for each RSN pre-authentication
+ * session. If global library deinitialization is needed (i.e., one that is
+ * shared between both authentication types), the TLS library wrapper should
+ * maintain a reference counter and do global deinitialization only when moving
+ * from 1 to 0 references.
*/
void tls_deinit(void *tls_ctx);
/**
- * tls_get_errors - process pending errors
+ * tls_get_errors - Process pending errors
* @tls_ctx: TLS context data from tls_init()
*
* Returns: Number of found error, 0 if no errors detected.
@@ -41,15 +142,15 @@ void tls_deinit(void *tls_ctx);
int tls_get_errors(void *tls_ctx);
/**
- * tls_connection_init - initialize a new TLS connection
+ * 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
+ * Returns: Connection context data, conn for other function calls
*/
struct tls_connection * tls_connection_init(void *tls_ctx);
/**
- * tls_connection_deinit - free TLS connection data
+ * tls_connection_deinit - Free TLS connection data
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
*
@@ -58,7 +159,7 @@ struct tls_connection * tls_connection_init(void *tls_ctx);
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
/**
- * tls_connection_established - has the TLS connection been completed?
+ * 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()
*
@@ -67,34 +168,40 @@ void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
/**
- * tls_connection_shutdown - shutdown TLS connection data.
+ * tls_connection_shutdown - Shutdown TLS connection data.
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
*
* Returns: 0 on success, -1 on failure
*
* Shutdown current TLS connection without releasing all resources. New
- * connection can be started by using the same @conn without having to call
+ * connection can be started by using the same conn without having to call
* tls_connection_init() or setting certificates etc. again. The new
* connection should try to use session resumption.
*/
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
+enum {
+ TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
+ TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
+};
/**
- * tls_connection_ca_cert - set trusted CA certificate for TLS connection
+ * tls_connection_set_params - Set TLS connection parameters
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- * @ca_cert: File name for CA certificate in PEM or DER format
- * @subject_match: String to match in the subject of the peer certificate or
- * %NULL to allow all subjects
+ * @params: Connection parameters
*
- * Returns: 0 on success, -1 on failure
+ * 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_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
- const char *ca_cert, const char *subject_match);
+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_ca_cert - Set trusted CA certificate for all TLS connections
* @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
@@ -104,31 +211,28 @@ int tls_connection_ca_cert(void *tls_ctx, struct tls_connection *conn,
int tls_global_ca_cert(void *tls_ctx, const char *ca_cert);
/**
- * tls_connection_ca_cert - set trusted CA certificate for TLS connection
+ * tls_global_set_verify - Set global certificate verification options
* @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @verify_peer: 1 = verify peer certificate
- * @subject_match: String to match in the subject of the peer certificate or
- * %NULL to allow all subjects
+ * @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_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
- int verify_peer, const char *subject_match);
+int tls_global_set_verify(void *tls_ctx, int check_crl);
/**
- * tls_connection_client_cert - set client certificate for TLS connection
+ * tls_connection_set_verify - Set certificate verification options
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
- * @client_cert: File name for client certificate in PEM or DER format
+ * @verify_peer: 1 = verify peer certificate
*
* Returns: 0 on success, -1 on failure
*/
-int tls_connection_client_cert(void *tls_ctx, struct tls_connection *conn,
- const char *client_cert);
+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_global_client_cert - Set client certificate for all TLS connections
* @tls_ctx: TLS context data from tls_init()
* @client_cert: File name for client certificate in PEM or DER format
*
@@ -137,21 +241,7 @@ int tls_connection_client_cert(void *tls_ctx, struct tls_connection *conn,
int tls_global_client_cert(void *tls_ctx, const char *client_cert);
/**
- * tls_connection_private_key - set private key for TLS connection
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_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
- */
-int tls_connection_private_key(void *tls_ctx, struct tls_connection *conn,
- const char *private_key,
- const char *private_key_passwd);
-
-/**
- * tls_global_private_key - set private key for all TLS connections
+ * 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
@@ -163,18 +253,7 @@ int tls_global_private_key(void *tls_ctx, const char *private_key,
const char *private_key_passwd);
/**
- * tls_connection_dh - set DH/DSA parameters for TLS connection
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @dh_file: File name for DH/DSA data in PEM format.
- *
- * Returns: 0 on success, -1 on failure
- */
-int tls_connection_dh(void *tls_ctx, struct tls_connection *conn,
- const char *dh_file);
-
-/**
- * tls_connection_get_keys - get master key and random data from TLS connection
+ * 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)
@@ -185,23 +264,37 @@ int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
struct tls_keys *keys);
/**
- * tls_connection_handshake - process TLS handshake (client side)
+ * 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.
*
- * Returns: pointer to output data, %NULL on failure
+ * Returns: Pointer to output data, %NULL on failure
*
* Caller is responsible for freeing returned output data.
+ *
+ * This function is used during TLS handshake. The first call is done with
+ * in_data == %NULL and the library is expected to return ClientHello packet.
+ * This packet is then send to the server and a response from server is given
+ * to TLS library by calling this function again with in_data pointing to the
+ * TLS message from the server.
+ *
+ * If the TLS handshake fails, this function may return %NULL. However, if the
+ * TLS library has a TLS alert to send out, that should be returned as the
+ * output data. In this case, tls_connection_get_failed() must return failure
+ * (> 0).
+ *
+ * tls_connection_established() should return 1 once the TLS handshake has been
+ * completed successfully.
*/
u8 * tls_connection_handshake(void *tls_ctx, struct tls_connection *conn,
const u8 *in_data, size_t in_len,
size_t *out_len);
/**
- * tls_connection_servr_handshake - process TLS handshake (server side)
+ * tls_connection_server_handshake - Process TLS handshake (server side)
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @in_data: Input data from TLS peer
@@ -218,37 +311,43 @@ u8 * tls_connection_server_handshake(void *tls_ctx,
size_t *out_len);
/**
- * tls_connection_encrypt - encrypt data into TLS tunnel
+ * tls_connection_encrypt - Encrypt data into TLS tunnel
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @in_data: 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
+ * @out_len: Maximum out_data length
+ *
+ * Returns: Number of bytes written to out_data, -1 on failure
*
- * 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 tls_connection_encrypt(void *tls_ctx, struct tls_connection *conn,
- u8 *in_data, size_t in_len,
+ const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len);
/**
- * tls_connection_decrypt - decrypt data from TLS tunnel
+ * tls_connection_decrypt - Decrypt data from TLS tunnel
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @in_data: 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
+ * @out_len: Maximum out_data length
*
- * Returns: Number of bytes written to @out_data, -1 on failure
+ * 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 tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn,
- u8 *in_data, size_t in_len,
+ const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len);
/**
- * tls_connection_resumed - was session resumption used
+ * tls_connection_resumed - Was session resumption used
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
*
@@ -257,19 +356,19 @@ int tls_connection_decrypt(void *tls_ctx, struct tls_connection *conn,
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
/**
- * tls_connection_set_master_key - configure master secret for TLS connection
+ * tls_connection_set_master_key - Configure master secret for TLS connection
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
* @key: TLS pre-master-secret
- * @key_len: length of @key in bytes
+ * @key_len: length of key in bytes
*
* Returns: 0 on success, -1 on failure
*/
-int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
+int tls_connection_set_master_key(void *tls_ctx, struct tls_connection *conn,
const u8 *key, size_t key_len);
/**
- * tls_connection_set_anon_dh - configure TLS connection to use anonymous DH
+ * tls_connection_set_anon_dh - Configure TLS connection to use anonymous DH
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
*
@@ -278,22 +377,24 @@ int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
* TODO: consider changing this to more generic routine for configuring allowed
* ciphers
*/
-int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn);
+int tls_connection_set_anon_dh(void *tls_ctx, struct tls_connection *conn);
/**
- * tls_get_cipher - get current cipher name
+ * tls_get_cipher - Get current cipher name
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
+ * @buf: Buffer for the cipher name
+ * @buflen: buf size
*
* Returns: 0 on success, -1 on failure
*
* Get the name of the currently used cipher.
*/
-int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
char *buf, size_t buflen);
/**
- * tls_connection_enable_workaround - enable TLS workaround options
+ * tls_connection_enable_workaround - Enable TLS workaround options
* @tls_ctx: TLS context data from tls_init()
* @conn: Connection context data from tls_connection_init()
*
@@ -302,11 +403,61 @@ int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
* This function is used to enable connection-specific workaround options for
* buffer SSL/TLS implementations.
*/
-int tls_connection_enable_workaround(void *ssl_ctx,
+int tls_connection_enable_workaround(void *tls_ctx,
struct tls_connection *conn);
-int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+/**
+ * tls_connection_client_hello_ext - Set TLS extension for ClientHello
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @ext_type: Extension type
+ * @data: Extension payload (NULL to remove extension)
+ * @data_len: Extension payload length
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len);
+/**
+ * tls_connection_get_failed - Get connection failure status
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ *
+ * Returns >0 if connection has failed, 0 if not.
+ */
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_get_read_alerts - Get connection read alert status
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ *
+ * Returns: Number of times a fatal read (remote end reported error) has
+ * happened during this connection.
+ */
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_get_write_alerts - Get connection write alert status
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ *
+ * Returns: Number of times a fatal write (locally detected error) has happened
+ * during this connection.
+ */
+int tls_connection_get_write_alerts(void *tls_ctx,
+ struct tls_connection *conn);
+
+/**
+ * tls_connection_get_keyblock_size - Get TLS key_block size
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on
+ * failure
+ */
+int tls_connection_get_keyblock_size(void *tls_ctx,
+ struct tls_connection *conn);
+
#endif /* TLS_H */
diff --git a/contrib/wpa_supplicant/tls_gnutls.c b/contrib/wpa_supplicant/tls_gnutls.c
new file mode 100644
index 0000000..2bc9ed8
--- /dev/null
+++ b/contrib/wpa_supplicant/tls_gnutls.c
@@ -0,0 +1,792 @@
+/*
+ * WPA Supplicant / SSL/TLS interface functions for openssl
+ * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include "common.h"
+#include "tls.h"
+
+
+/*
+ * 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
+ * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
+ * hack that copies the gnutls_session_int definition from gnutls_int.h so that
+ * we can get the needed information.
+ */
+
+typedef u8 uint8;
+#define TLS_RANDOM_SIZE 32
+#define TLS_MASTER_SIZE 48
+typedef unsigned char opaque;
+typedef struct {
+ uint8 suite[2];
+} cipher_suite_st;
+
+typedef struct {
+ gnutls_connection_end_t entity;
+ gnutls_kx_algorithm_t kx_algorithm;
+ gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
+ gnutls_mac_algorithm_t read_mac_algorithm;
+ gnutls_compression_method_t read_compression_algorithm;
+ gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
+ gnutls_mac_algorithm_t write_mac_algorithm;
+ gnutls_compression_method_t write_compression_algorithm;
+ cipher_suite_st current_cipher_suite;
+ opaque master_secret[TLS_MASTER_SIZE];
+ opaque client_random[TLS_RANDOM_SIZE];
+ opaque server_random[TLS_RANDOM_SIZE];
+ /* followed by stuff we are not interested in */
+} security_parameters_st;
+
+struct gnutls_session_int {
+ security_parameters_st security_parameters;
+ /* followed by things we are not interested in */
+};
+
+static int tls_gnutls_ref_count = 0;
+
+struct tls_connection {
+ gnutls_session session;
+ char *subject_match, *altsubject_match;
+ int read_alerts, write_alerts, failed;
+
+ u8 *pre_shared_secret;
+ size_t pre_shared_secret_len;
+ int established;
+ int verify_peer;
+
+ u8 *push_buf, *pull_buf, *pull_buf_offset;
+ size_t push_buf_len, pull_buf_len;
+
+ gnutls_certificate_credentials_t xcred;
+};
+
+
+static void tls_log_func(int level, const char *msg)
+{
+ char *s, *pos;
+ if (level == 6 || level == 7) {
+ /* These levels seem to be mostly I/O debug and msg dumps */
+ return;
+ }
+
+ s = strdup(msg);
+ if (s == NULL)
+ return;
+
+ pos = s;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
+ "gnutls<%d> %s", level, s);
+ free(s);
+}
+
+
+extern int wpa_debug_show_keys;
+
+void * tls_init(const struct tls_config *conf)
+{
+ /* 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 };
+ int i;
+
+ if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0)
+ return NULL;
+ tls_gnutls_ref_count++;
+
+ ver = gnutls_check_version(NULL);
+ if (ver == NULL)
+ 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)
+ break;
+ }
+ 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);
+ return NULL;
+ }
+
+ gnutls_global_set_log_function(tls_log_func);
+ if (wpa_debug_show_keys)
+ gnutls_global_set_log_level(11);
+ return (void *) 1;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+ tls_gnutls_ref_count--;
+ if (tls_gnutls_ref_count == 0)
+ gnutls_global_deinit();
+}
+
+
+int tls_get_errors(void *ssl_ctx)
+{
+ return 0;
+}
+
+
+static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
+ size_t len)
+{
+ struct tls_connection *conn = (struct tls_connection *) ptr;
+ u8 *end;
+ if (conn->pull_buf == NULL) {
+ errno = EWOULDBLOCK;
+ return -1;
+ }
+
+ end = conn->pull_buf + conn->pull_buf_len;
+ if (end - conn->pull_buf_offset < len)
+ len = end - conn->pull_buf_offset;
+ 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);
+ conn->pull_buf = conn->pull_buf_offset = NULL;
+ conn->pull_buf_len = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in pull_buf",
+ __func__, end - conn->pull_buf_offset);
+ }
+ return len;
+}
+
+
+static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
+ size_t len)
+{
+ struct tls_connection *conn = (struct tls_connection *) ptr;
+ u8 *nbuf;
+
+ nbuf = realloc(conn->push_buf, conn->push_buf_len + len);
+ if (nbuf == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+ memcpy(nbuf + conn->push_buf_len, buf, len);
+ conn->push_buf = nbuf;
+ conn->push_buf_len += len;
+
+ return len;
+}
+
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+ struct tls_connection *conn;
+ const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
+ const int protos[2] = { GNUTLS_TLS1, 0 };
+
+
+ conn = malloc(sizeof(*conn));
+ if (conn == NULL)
+ return NULL;
+ memset(conn, 0, sizeof(*conn));
+ if (gnutls_init(&conn->session, GNUTLS_CLIENT) < 0) {
+ wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
+ "connection");
+ free(conn);
+ return NULL;
+ }
+
+ gnutls_set_default_priority(conn->session);
+ gnutls_certificate_type_set_priority(conn->session, cert_types);
+ gnutls_protocol_set_priority(conn->session, protos);
+
+ 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 conn;
+}
+
+
+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return;
+ 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);
+}
+
+
+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
+{
+ return conn ? conn->established : 0;
+}
+
+
+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+
+ /* Shutdown previous TLS connection without notifying the peer
+ * because the connection was already terminated in practice
+ * and "close notify" shutdown alert would confuse AS. */
+ gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
+ 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? */
+ return 0;
+}
+
+
+#if 0
+static int tls_match_altsubject(X509 *cert, const char *match)
+{
+ 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)
+ continue;
+ snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
+ if (strstr(tmp, match))
+ found++;
+ free(tmp);
+ }
+
+ return found;
+}
+#endif
+
+
+#if 0
+static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+ char buf[256];
+ X509 *err_cert;
+ int err, depth;
+ SSL *ssl;
+ struct tls_connection *conn;
+ char *match, *altmatch;
+
+ err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+ err = X509_STORE_CTX_get_error(x509_ctx);
+ depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+ ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
+
+ conn = SSL_get_app_data(ssl);
+ match = conn ? conn->subject_match : NULL;
+ altmatch = conn ? conn->altsubject_match : NULL;
+
+ if (!preverify_ok) {
+ wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
+ " error %d (%s) depth %d for '%s'", err,
+ X509_verify_cert_error_string(err), depth, buf);
+ } else {
+ wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
+ "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) {
+ wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
+ "match with '%s'", buf, match);
+ preverify_ok = 0;
+ } else if (depth == 0 && altmatch &&
+ !tls_match_altsubject(err_cert, altmatch)) {
+ wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+ "'%s' not found", altmatch);
+ preverify_ok = 0;
+ }
+ }
+
+ return preverify_ok;
+}
+#endif
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+ const struct tls_connection_params *params)
+{
+ int ret;
+
+ if (conn == NULL || params == NULL)
+ return -1;
+
+ free(conn->subject_match);
+ conn->subject_match = NULL;
+ if (params->subject_match) {
+ conn->subject_match = strdup(params->subject_match);
+ if (conn->subject_match == NULL)
+ return -1;
+ }
+
+ free(conn->altsubject_match);
+ conn->altsubject_match = NULL;
+ if (params->altsubject_match) {
+ conn->altsubject_match = strdup(params->altsubject_match);
+ if (conn->altsubject_match == NULL)
+ return -1;
+ }
+
+ /* TODO: gnutls_certificate_set_verify_flags(xcred, flags);
+ * to force peer validation(?) */
+
+ if (params->ca_cert) {
+ conn->verify_peer = 1;
+ ret = gnutls_certificate_set_x509_trust_file(
+ conn->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(
+ conn->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));
+ }
+ }
+ }
+
+ if (params->client_cert && params->private_key) {
+ /* TODO: private_key_passwd? */
+ ret = gnutls_certificate_set_x509_key_file(
+ conn->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(
+ conn->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));
+ return ret;
+ }
+ }
+ }
+
+ ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
+ conn->xcred);
+ if (ret < 0) {
+ wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
+ gnutls_strerror(ret));
+ }
+
+ return ret;
+}
+
+
+int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
+{
+ /* TODO */
+ return -1;
+}
+
+
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
+{
+ /* TODO */
+ return -1;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+ int verify_peer)
+{
+ if (conn == NULL)
+ return -1;
+
+ /* TODO */
+
+ return 1;
+}
+
+
+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;
+}
+
+
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_keys *keys)
+{
+ security_parameters_st *sec;
+
+ if (conn == NULL || conn->session == NULL || keys == NULL)
+ return -1;
+
+ memset(keys, 0, sizeof(*keys));
+ 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;
+ keys->server_random_len = TLS_RANDOM_SIZE;
+
+ return 0;
+}
+
+
+static int tls_connection_verify_peer(struct tls_connection *conn)
+{
+ unsigned int status, num_certs, i;
+ time_t now;
+ const gnutls_datum_t *certs;
+ gnutls_x509_crt_t cert;
+
+ if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
+ wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
+ "certificate chain");
+ return -1;
+ }
+
+ if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
+ wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
+ return -1;
+ }
+
+ if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
+ wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
+ "known issuer");
+ return -1;
+ }
+
+ if (status & GNUTLS_CERT_REVOKED) {
+ wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
+ return -1;
+ }
+
+ now = time(NULL);
+
+ certs = gnutls_certificate_get_peers(conn->session, &num_certs);
+ if (certs == NULL) {
+ wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
+ "received");
+ return -1;
+ }
+
+ for (i = 0; i < num_certs; i++) {
+ char *buf;
+ size_t len;
+ if (gnutls_x509_crt_init(&cert) < 0) {
+ wpa_printf(MSG_INFO, "TLS: Certificate initialization "
+ "failed");
+ return -1;
+ }
+
+ if (gnutls_x509_crt_import(cert, &certs[i],
+ GNUTLS_X509_FMT_DER) < 0) {
+ wpa_printf(MSG_INFO, "TLS: Could not parse peer "
+ "certificate %d/%d", i + 1, num_certs);
+ gnutls_x509_crt_deinit(cert);
+ return -1;
+ }
+
+ gnutls_x509_crt_get_dn(cert, NULL, &len);
+ len++;
+ buf = malloc(len + 1);
+ if (buf) {
+ buf[0] = buf[len] = '\0';
+ gnutls_x509_crt_get_dn(cert, buf, &len);
+ }
+ wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
+ i + 1, num_certs, buf);
+
+ if (i == 0) {
+ /* TODO: validate subject_match and altsubject_match */
+ }
+
+ free(buf);
+
+ if (gnutls_x509_crt_get_expiration_time(cert) < now ||
+ gnutls_x509_crt_get_activation_time(cert) > now) {
+ wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
+ "not valid at this time",
+ i + 1, num_certs);
+ gnutls_x509_crt_deinit(cert);
+ return -1;
+ }
+
+ gnutls_x509_crt_deinit(cert);
+ }
+
+ 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)
+{
+ u8 *out_data;
+ int ret;
+
+ 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);
+ }
+ conn->pull_buf = malloc(in_len);
+ if (conn->pull_buf == NULL)
+ return NULL;
+ memcpy(conn->pull_buf, in_data, in_len);
+ conn->pull_buf_offset = conn->pull_buf;
+ conn->pull_buf_len = in_len;
+ }
+
+ ret = gnutls_handshake(conn->session);
+ if (ret < 0) {
+ switch (ret) {
+ case GNUTLS_E_AGAIN:
+ break;
+ case GNUTLS_E_FATAL_ALERT_RECEIVED:
+ wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
+ __func__, gnutls_alert_get_name(
+ gnutls_alert_get(conn->session)));
+ conn->read_alerts++;
+ /* continue */
+ default:
+ wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
+ "-> %s", __func__, gnutls_strerror(ret));
+ conn->failed++;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
+ if (conn->verify_peer && tls_connection_verify_peer(conn)) {
+ wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
+ "failed validation");
+ conn->failed++;
+ return NULL;
+ }
+ conn->established = 1;
+ if (conn->push_buf == NULL) {
+ /* Need to return something to get final TLS ACK. */
+ conn->push_buf = malloc(1);
+ }
+ }
+
+ out_data = conn->push_buf;
+ *out_len = conn->push_buf_len;
+ conn->push_buf = NULL;
+ conn->push_buf_len = 0;
+ return out_data;
+}
+
+
+u8 * tls_connection_server_handshake(void *ssl_ctx,
+ struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len)
+{
+ /* TODO */
+ return NULL;
+}
+
+
+int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ ssize_t res;
+ res = gnutls_record_send(conn->session, in_data, in_len);
+ 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);
+ conn->push_buf = NULL;
+ conn->push_buf_len = 0;
+ return out_len;
+}
+
+
+int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ ssize_t res;
+
+ if (conn->pull_buf) {
+ wpa_printf(MSG_DEBUG, "%s - %d bytes remaining in "
+ "pull_buf", __func__, conn->pull_buf_len);
+ free(conn->pull_buf);
+ }
+ conn->pull_buf = malloc(in_len);
+ if (conn->pull_buf == NULL)
+ return -1;
+ memcpy(conn->pull_buf, in_data, in_len);
+ conn->pull_buf_offset = conn->pull_buf;
+ conn->pull_buf_len = in_len;
+
+ res = gnutls_record_recv(conn->session, out_data, out_len);
+ if (res < 0) {
+ wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
+ "(%s)", __func__, res, gnutls_strerror(res));
+ }
+
+ return res;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return 0;
+ return gnutls_session_is_resumed(conn->session);
+}
+
+
+#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)
+{
+ /* TODO: set ADH-AES128-SHA cipher */
+ return -1;
+}
+
+
+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ /* TODO */
+ buf[0] = '\0';
+ return 0;
+}
+
+
+int tls_connection_enable_workaround(void *ssl_ctx,
+ struct tls_connection *conn)
+{
+ /* TODO: set SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS */
+ return 0;
+}
+
+
+#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)
+{
+ /* TODO */
+ return -1;
+}
+#endif /* EAP_FAST */
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->write_alerts;
+}
diff --git a/contrib/wpa_supplicant/tls_none.c b/contrib/wpa_supplicant/tls_none.c
index 2b3cafc..07fd879 100644
--- a/contrib/wpa_supplicant/tls_none.c
+++ b/contrib/wpa_supplicant/tls_none.c
@@ -12,7 +12,13 @@
* See README and COPYING for more details.
*/
-void * tls_init(void)
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "common.h"
+#include "tls.h"
+
+void * tls_init(const struct tls_config *conf)
{
return (void *) 1;
}
diff --git a/contrib/wpa_supplicant/tls_openssl.c b/contrib/wpa_supplicant/tls_openssl.c
index 4e6ea53..08d5a80 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-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2004-2006, Jouni Malinen <jkmaline@cc.hut.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,21 +15,504 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+
+#ifndef CONFIG_SMARTCARD
+#ifndef OPENSSL_NO_ENGINE
+#define OPENSSL_NO_ENGINE
+#endif
+#endif
+
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif /* OPENSSL_NO_ENGINE */
#include "common.h"
#include "tls.h"
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#define OPENSSL_d2i_TYPE const unsigned char **
+#else
+#define OPENSSL_d2i_TYPE unsigned char **
+#endif
+
+static int tls_openssl_ref_count = 0;
struct tls_connection {
SSL *ssl;
BIO *ssl_in, *ssl_out;
- char *subject_match;
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE *engine; /* functional reference to the engine */
+ EVP_PKEY *private_key; /* the private key if using engine */
+#endif /* OPENSSL_NO_ENGINE */
+ char *subject_match, *altsubject_match;
+ int read_alerts, write_alerts, failed;
+
+ u8 *pre_shared_secret;
+ size_t pre_shared_secret_len;
};
+#ifdef CONFIG_NO_STDOUT_DEBUG
+
+static void _tls_show_errors(void)
+{
+ unsigned long err;
+
+ while ((err = ERR_get_error())) {
+ /* Just ignore the errors, since stdout is disabled */
+ }
+}
+#define tls_show_errors(l, f, t) _tls_show_errors()
+
+#else /* CONFIG_NO_STDOUT_DEBUG */
+
+static void tls_show_errors(int level, const char *func, const char *txt)
+{
+ unsigned long err;
+
+ wpa_printf(level, "OpenSSL: %s - %s %s",
+ func, txt, ERR_error_string(ERR_get_error(), NULL));
+
+ while ((err = ERR_get_error())) {
+ wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
+ ERR_error_string(err, NULL));
+ }
+}
+
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+
+/* Windows CryptoAPI and access to certificate stores */
+#include <wincrypt.h>
+
+#ifdef __MINGW32_VERSION
+/*
+ * MinGW does not yet include all the needed definitions for CryptoAPI, so
+ * define here whatever extra is needed.
+ */
+#define CALG_SSL3_SHAMD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5)
+#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
+#define CERT_STORE_READONLY_FLAG 0x00008000
+#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
+#define CRYPT_ACQUIRE_COMPARE_KEY_FLAG 0x00000004
+
+static BOOL WINAPI
+(*CryptAcquireCertificatePrivateKey)(PCCERT_CONTEXT pCert, DWORD dwFlags,
+ void *pvReserved, HCRYPTPROV *phCryptProv,
+ DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
+= NULL; /* to be loaded from crypt32.dll */
+
+static PCCERT_CONTEXT WINAPI
+(*CertEnumCertificatesInStore)(HCERTSTORE hCertStore,
+ PCCERT_CONTEXT pPrevCertContext)
+= 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 (CryptAcquireCertificatePrivateKey)
+ return 0;
+
+ dll = LoadLibrary("crypt32");
+ if (dll == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
+ "library");
+ return -1;
+ }
+
+ CryptAcquireCertificatePrivateKey = GetProcAddress(
+ dll, "CryptAcquireCertificatePrivateKey");
+ if (CryptAcquireCertificatePrivateKey == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+ "CryptAcquireCertificatePrivateKey() address from "
+ "crypt32 library");
+ return -1;
+ }
+
+ CertEnumCertificatesInStore = (void *) GetProcAddress(
+ dll, "CertEnumCertificatesInStore");
+ if (CertEnumCertificatesInStore == NULL) {
+ wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+ "CertEnumCertificatesInStore() address from "
+ "crypt32 library");
+ return -1;
+ }
+
+ return 0;
+}
+
+#else /* __MINGW32_VERSION */
+
+static int mingw_load_crypto_func(void)
+{
+ return 0;
+}
+
+#endif /* __MINGW32_VERSION */
+
+
+struct cryptoapi_rsa_data {
+ const CERT_CONTEXT *cert;
+ HCRYPTPROV crypt_prov;
+ DWORD key_spec;
+ BOOL free_crypt_prov;
+};
+
+
+static void cryptoapi_error(const char *msg)
+{
+ wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
+ msg, (unsigned int) GetLastError());
+}
+
+
+static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+ return 0;
+}
+
+
+static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+ return 0;
+}
+
+
+static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ struct cryptoapi_rsa_data *priv =
+ (struct cryptoapi_rsa_data *) rsa->meth->app_data;
+ HCRYPTHASH hash;
+ DWORD hash_size, len, i;
+ unsigned char *buf = NULL;
+ int ret = 0;
+
+ if (priv == NULL) {
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+ ERR_R_PASSED_NULL_PARAMETER);
+ return 0;
+ }
+
+ if (padding != RSA_PKCS1_PADDING) {
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+ RSA_R_UNKNOWN_PADDING_TYPE);
+ return 0;
+ }
+
+ if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
+ wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
+ __func__);
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+ RSA_R_INVALID_MESSAGE_LENGTH);
+ return 0;
+ }
+
+ if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
+ {
+ cryptoapi_error("CryptCreateHash failed");
+ return 0;
+ }
+
+ len = sizeof(hash_size);
+ if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
+ 0)) {
+ cryptoapi_error("CryptGetHashParam failed");
+ goto err;
+ }
+
+ if (hash_size != flen) {
+ wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
+ (unsigned) hash_size, flen);
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+ RSA_R_INVALID_MESSAGE_LENGTH);
+ goto err;
+ }
+ if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
+ cryptoapi_error("CryptSetHashParam failed");
+ goto err;
+ }
+
+ len = RSA_size(rsa);
+ buf = malloc(len);
+ if (buf == NULL) {
+ RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
+ cryptoapi_error("CryptSignHash failed");
+ goto err;
+ }
+
+ for (i = 0; i < len; i++)
+ to[i] = buf[len - i - 1];
+ ret = len;
+
+err:
+ free(buf);
+ CryptDestroyHash(hash);
+
+ return ret;
+}
+
+
+static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
+ unsigned char *to, RSA *rsa, int padding)
+{
+ wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+ return 0;
+}
+
+
+static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
+{
+ if (priv == NULL)
+ return;
+ if (priv->crypt_prov && priv->free_crypt_prov)
+ CryptReleaseContext(priv->crypt_prov, 0);
+ if (priv->cert)
+ CertFreeCertificateContext(priv->cert);
+ free(priv);
+}
+
+
+static int cryptoapi_finish(RSA *rsa)
+{
+ cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
+ free((void *) rsa->meth);
+ rsa->meth = NULL;
+ return 1;
+}
+
+
+static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
+{
+ HCERTSTORE cs;
+ const CERT_CONTEXT *ret = NULL;
+
+ cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
+ store | CERT_STORE_OPEN_EXISTING_FLAG |
+ CERT_STORE_READONLY_FLAG, L"MY");
+ if (cs == NULL) {
+ cryptoapi_error("Failed to open 'My system store'");
+ return NULL;
+ }
+
+ if (strncmp(name, "cert://", 7) == 0) {
+ unsigned short wbuf[255];
+ MultiByteToWideChar(CP_ACP, 0, name + 7, -1,
+ wbuf, sizeof(wbuf));
+ ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING,
+ 0, CERT_FIND_SUBJECT_STR,
+ wbuf, NULL);
+ } else if (strncmp(name, "hash://", 7) == 0) {
+ CRYPT_HASH_BLOB blob;
+ int len;
+ const char *hash = name + 7;
+ unsigned char *buf;
+
+ len = strlen(hash) / 2;
+ buf = malloc(len);
+ if (buf && hexstr2bin(hash, buf, len) == 0) {
+ blob.cbData = len;
+ blob.pbData = buf;
+ ret = CertFindCertificateInStore(cs,
+ X509_ASN_ENCODING |
+ PKCS_7_ASN_ENCODING,
+ 0, CERT_FIND_HASH,
+ &blob, NULL);
+ }
+ free(buf);
+ }
+
+ CertCloseStore(cs, 0);
+
+ return ret;
+}
+
+
+static int tls_cryptoapi_cert(SSL *ssl, const char *name)
+{
+ X509 *cert = NULL;
+ RSA *rsa = NULL, *pub_rsa;
+ struct cryptoapi_rsa_data *priv;
+ RSA_METHOD *rsa_meth;
+
+ if (name == NULL ||
+ (strncmp(name, "cert://", 7) != 0 &&
+ strncmp(name, "hash://", 7) != 0))
+ return -1;
+
+ priv = malloc(sizeof(*priv));
+ rsa_meth = malloc(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);
+ 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) {
+ priv->cert = cryptoapi_find_cert(
+ name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
+ }
+ if (priv->cert == NULL) {
+ wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
+ "'%s'", name);
+ goto err;
+ }
+
+ cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded,
+ priv->cert->cbCertEncoded);
+ if (cert == NULL) {
+ wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
+ "encoding");
+ goto err;
+ }
+
+ if (mingw_load_crypto_func())
+ goto err;
+
+ if (!CryptAcquireCertificatePrivateKey(priv->cert,
+ CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
+ NULL, &priv->crypt_prov,
+ &priv->key_spec,
+ &priv->free_crypt_prov)) {
+ cryptoapi_error("Failed to acquire a private key for the "
+ "certificate");
+ goto err;
+ }
+
+ rsa_meth->name = "Microsoft CryptoAPI RSA Method";
+ rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
+ rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
+ rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
+ rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
+ rsa_meth->finish = cryptoapi_finish;
+ rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
+ rsa_meth->app_data = (char *) priv;
+
+ rsa = RSA_new();
+ if (rsa == NULL) {
+ SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
+ ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ if (!SSL_use_certificate(ssl, cert))
+ goto err;
+ pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
+ X509_free(cert);
+ cert = NULL;
+
+ rsa->n = BN_dup(pub_rsa->n);
+ rsa->e = BN_dup(pub_rsa->e);
+ if (!RSA_set_method(rsa, rsa_meth))
+ goto err;
+
+ if (!SSL_use_RSAPrivateKey(ssl, rsa))
+ goto err;
+ RSA_free(rsa);
+
+ return 0;
+
+err:
+ if (cert)
+ X509_free(cert);
+ if (rsa)
+ RSA_free(rsa);
+ else {
+ free(rsa_meth);
+ cryptoapi_free_data(priv);
+ }
+ return -1;
+}
+
+
+static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
+{
+ HCERTSTORE cs;
+ PCCERT_CONTEXT ctx = NULL;
+ X509 *cert;
+ char buf[128];
+
+ if (mingw_load_crypto_func())
+ return -1;
+
+ if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
+ return -1;
+
+ cs = CertOpenSystemStore(0, name + 13);
+ if (cs == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
+ "'%s': error=%d", __func__, name + 13,
+ (int) GetLastError());
+ return -1;
+ }
+
+ while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
+ cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded,
+ ctx->cbCertEncoded);
+ if (cert == NULL) {
+ wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
+ "X509 DER encoding for CA cert");
+ continue;
+ }
+
+ X509_NAME_oneline(X509_get_subject_name(cert), buf,
+ sizeof(buf));
+ wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
+ "system certificate store: subject='%s'", buf);
+
+ if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to add ca_cert to OpenSSL "
+ "certificate store");
+ }
+
+ X509_free(cert);
+ }
+
+ if (!CertCloseStore(cs, 0)) {
+ wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
+ "'%s': error=%d", __func__, name + 13,
+ (int) GetLastError());
+ }
+
+ return 0;
+}
+
+
+#else /* CONFIG_NATIVE_WINDOWS */
+
+static int tls_cryptoapi_cert(SSL *ssl, const char *name)
+{
+ return -1;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
static void ssl_info_cb(const SSL *ssl, int where, int ret)
{
const char *str;
@@ -50,10 +533,18 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
} else if (where & SSL_CB_ALERT) {
wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
where & SSL_CB_READ ?
- "read (authentication server reported an error)" :
+ "read (remote end reported an error)" :
"write (local SSL3 detected an error)",
SSL_alert_type_string_long(ret),
SSL_alert_desc_string_long(ret));
+ if ((ret >> 8) == SSL3_AL_FATAL) {
+ struct tls_connection *conn =
+ SSL_get_app_data((SSL *) ssl);
+ if (where & SSL_CB_READ)
+ conn->read_alerts++;
+ else
+ conn->write_alerts++;
+ }
} else if (where & SSL_CB_EXIT && ret <= 0) {
wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
str, ret == 0 ? "failed" : "error",
@@ -62,18 +553,160 @@ static void ssl_info_cb(const SSL *ssl, int where, int ret)
}
-void * tls_init(void)
+#ifndef OPENSSL_NO_ENGINE
+/**
+ * tls_engine_load_dynamic_generic - load any openssl engine
+ * @pre: an array of commands and values that load an engine initialized
+ * in the engine specific function
+ * @post: an array of commands and values that initialize an already loaded
+ * engine (or %NULL if not required)
+ * @id: the engine id of the engine to load (only required if post is not %NULL
+ *
+ * This function is a generic function that loads any openssl engine.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int tls_engine_load_dynamic_generic(const char *pre[],
+ const char *post[], const char *id)
+{
+ ENGINE *engine;
+ const char *dynamic_id = "dynamic";
+
+ engine = ENGINE_by_id(id);
+ if (engine) {
+ ENGINE_free(engine);
+ wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
+ "available", id);
+ return 0;
+ }
+ ERR_clear_error();
+
+ engine = ENGINE_by_id(dynamic_id);
+ if (engine == NULL) {
+ wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
+ dynamic_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ /* Perform the pre commands. This will load the engine. */
+ while (pre && pre[0]) {
+ wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
+ if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
+ wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
+ "%s %s [%s]", pre[0], pre[1],
+ ERR_error_string(ERR_get_error(), NULL));
+ ENGINE_free(engine);
+ return -1;
+ }
+ pre += 2;
+ }
+
+ /*
+ * Free the reference to the "dynamic" engine. The loaded engine can
+ * now be looked up using ENGINE_by_id().
+ */
+ ENGINE_free(engine);
+
+ engine = ENGINE_by_id(id);
+ if (engine == NULL) {
+ wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
+ id, ERR_error_string(ERR_get_error(), NULL));
+ return -1;
+ }
+
+ while (post && post[0]) {
+ wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
+ if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
+ wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
+ " %s %s [%s]", post[0], post[1],
+ ERR_error_string(ERR_get_error(), NULL));
+ ENGINE_remove(engine);
+ ENGINE_free(engine);
+ return -1;
+ }
+ post += 2;
+ }
+ ENGINE_free(engine);
+
+ return 0;
+}
+
+
+/**
+ * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
+ * @pkcs11_so_path: pksc11_so_path from the configuration
+ * @pcks11_module_path: pkcs11_module_path from the configuration
+ */
+static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
+ const char *pkcs11_module_path)
+{
+ char *engine_id = "pkcs11";
+ const char *pre_cmd[] = {
+ "SO_PATH", pkcs11_so_path,
+ "ID", engine_id,
+ "LIST_ADD", "1",
+ /* "NO_VCHECK", "1", */
+ "LOAD", NULL,
+ NULL, NULL
+ };
+ const char *post_cmd[] = {
+ "MODULE_PATH", pkcs11_module_path,
+ NULL, NULL
+ };
+
+ if (!pkcs11_so_path || !pkcs11_module_path)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
+ pkcs11_so_path);
+
+ return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
+}
+
+
+/**
+ * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
+ * @opensc_so_path: opensc_so_path from the configuration
+ */
+static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
+{
+ char *engine_id = "opensc";
+ const char *pre_cmd[] = {
+ "SO_PATH", opensc_so_path,
+ "ID", engine_id,
+ "LIST_ADD", "1",
+ "LOAD", NULL,
+ NULL, NULL
+ };
+
+ if (!opensc_so_path)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
+ opensc_so_path);
+
+ return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+
+void * tls_init(const struct tls_config *conf)
{
SSL_CTX *ssl;
- SSL_load_error_strings();
- SSL_library_init();
- /* TODO: if /dev/urandom is available, PRNG is seeded automatically.
- * If this is not the case, random data should be added here. */
+ if (tls_openssl_ref_count == 0) {
+ SSL_load_error_strings();
+ SSL_library_init();
+ /* TODO: if /dev/urandom is available, PRNG is seeded
+ * automatically. If this is not the case, random data should
+ * be added here. */
#ifdef PKCS12_FUNCS
- PKCS12_PBE_add();
+ PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
+ }
+ tls_openssl_ref_count++;
ssl = SSL_CTX_new(TLSv1_method());
if (ssl == NULL)
@@ -81,6 +714,23 @@ void * tls_init(void)
SSL_CTX_set_info_callback(ssl, ssl_info_cb);
+#ifndef OPENSSL_NO_ENGINE
+ if (conf &&
+ (conf->opensc_engine_path || conf->pkcs11_engine_path ||
+ conf->pkcs11_module_path)) {
+ wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+ ERR_load_ENGINE_strings();
+ ENGINE_load_dynamic();
+
+ if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
+ tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
+ conf->pkcs11_module_path)) {
+ tls_deinit(ssl);
+ return NULL;
+ }
+ }
+#endif /* OPENSSL_NO_ENGINE */
+
return ssl;
}
@@ -89,8 +739,98 @@ void tls_deinit(void *ssl_ctx)
{
SSL_CTX *ssl = ssl_ctx;
SSL_CTX_free(ssl);
- ERR_free_strings();
- EVP_cleanup();
+
+ tls_openssl_ref_count--;
+ if (tls_openssl_ref_count == 0) {
+#ifndef OPENSSL_NO_ENGINE
+ ENGINE_cleanup();
+#endif /* OPENSSL_NO_ENGINE */
+ ERR_free_strings();
+ EVP_cleanup();
+ }
+}
+
+
+static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
+ const char *pin, const char *key_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+ int ret = -1;
+ if (engine_id == NULL) {
+ wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
+ return -1;
+ }
+ if (pin == NULL) {
+ wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
+ return -1;
+ }
+ if (key_id == NULL) {
+ wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
+ return -1;
+ }
+
+ ERR_clear_error();
+ conn->engine = ENGINE_by_id(engine_id);
+ if (!conn->engine) {
+ wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
+ engine_id, ERR_error_string(ERR_get_error(), NULL));
+ goto err;
+ }
+ if (ENGINE_init(conn->engine) != 1) {
+ wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
+ "(engine: %s) [%s]", engine_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ goto err;
+ }
+ wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
+
+ if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
+ wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
+ ERR_error_string(ERR_get_error(), NULL));
+ goto err;
+ }
+ conn->private_key = ENGINE_load_private_key(conn->engine,
+ key_id, NULL, NULL);
+ if (!conn->private_key) {
+ wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
+ " '%s' [%s]", key_id,
+ ERR_error_string(ERR_get_error(), NULL));
+ ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+ goto err;
+ }
+ return 0;
+
+err:
+ if (conn->engine) {
+ ENGINE_free(conn->engine);
+ conn->engine = NULL;
+ }
+
+ if (conn->private_key) {
+ EVP_PKEY_free(conn->private_key);
+ conn->private_key = NULL;
+ }
+
+ return ret;
+#else /* OPENSSL_NO_ENGINE */
+ return 0;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static void tls_engine_deinit(struct tls_connection *conn)
+{
+#ifndef OPENSSL_NO_ENGINE
+ wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
+ if (conn->private_key) {
+ EVP_PKEY_free(conn->private_key);
+ conn->private_key = NULL;
+ }
+ if (conn->engine) {
+ ENGINE_finish(conn->engine);
+ conn->engine = NULL;
+ }
+#endif /* OPENSSL_NO_ENGINE */
}
@@ -119,22 +859,21 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
memset(conn, 0, sizeof(*conn));
conn->ssl = SSL_new(ssl);
if (conn->ssl == NULL) {
- wpa_printf(MSG_INFO, "TLS: Failed to initialize new SSL "
- "connection: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to initialize new SSL connection");
free(conn);
return NULL;
}
+ SSL_set_app_data(conn->ssl, conn);
SSL_set_options(conn->ssl,
SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
SSL_OP_SINGLE_DH_USE);
conn->ssl_in = BIO_new(BIO_s_mem());
if (!conn->ssl_in) {
- wpa_printf(MSG_INFO, "SSL: Failed to create a new BIO for "
- "ssl_in: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to create a new BIO for ssl_in");
SSL_free(conn->ssl);
free(conn);
return NULL;
@@ -142,9 +881,8 @@ struct tls_connection * tls_connection_init(void *ssl_ctx)
conn->ssl_out = BIO_new(BIO_s_mem());
if (!conn->ssl_out) {
- wpa_printf(MSG_INFO, "SSL: Failed to create a new BIO for "
- "ssl_out: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to create a new BIO for ssl_out");
SSL_free(conn->ssl);
BIO_free(conn->ssl_in);
free(conn);
@@ -161,8 +899,11 @@ void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
{
if (conn == NULL)
return;
+ free(conn->pre_shared_secret);
SSL_free(conn->ssl);
+ tls_engine_deinit(conn);
free(conn->subject_match);
+ free(conn->altsubject_match);
free(conn);
}
@@ -187,6 +928,55 @@ int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
}
+static int tls_match_altsubject(X509 *cert, const char *match)
+{
+ 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)
+ continue;
+ snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
+ if (strstr(tmp, match))
+ found++;
+ free(tmp);
+ }
+
+ return found;
+}
+
+
static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
char buf[256];
@@ -194,17 +984,18 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
int err, depth;
SSL *ssl;
struct tls_connection *conn;
- char *match;
+ char *match, *altmatch;
err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
err = X509_STORE_CTX_get_error(x509_ctx);
depth = X509_STORE_CTX_get_error_depth(x509_ctx);
ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
SSL_get_ex_data_X509_STORE_CTX_idx());
- X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256);
+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
conn = SSL_get_app_data(ssl);
match = conn ? conn->subject_match : NULL;
+ altmatch = conn ? conn->altsubject_match : NULL;
if (!preverify_ok) {
wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
@@ -219,6 +1010,11 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
"match with '%s'", buf, match);
preverify_ok = 0;
+ } else if (depth == 0 && altmatch &&
+ !tls_match_altsubject(err_cert, altmatch)) {
+ wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+ "'%s' not found", altmatch);
+ preverify_ok = 0;
}
}
@@ -226,34 +1022,102 @@ static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
}
-int tls_connection_ca_cert(void *ssl_ctx, struct tls_connection *conn,
- const char *ca_cert, const char *subject_match)
+#ifndef OPENSSL_NO_STDIO
+static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
{
- if (conn == NULL)
+ SSL_CTX *ssl_ctx = _ssl_ctx;
+ X509_LOOKUP *lookup;
+ int ret = 0;
+
+ lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
+ X509_LOOKUP_file());
+ if (lookup == NULL) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed add lookup for X509 store");
return -1;
+ }
- free(conn->subject_match);
- conn->subject_match = NULL;
- if (subject_match) {
- conn->subject_match = strdup(subject_match);
- if (conn->subject_match == NULL)
- return -1;
+ if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
+ unsigned long err = ERR_peek_error();
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed load CA in DER format");
+ if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+ ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
+ "cert already in hash table error",
+ __func__);
+ } else
+ ret = -1;
}
- if (ca_cert) {
- if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
- {
- wpa_printf(MSG_WARNING, "TLS: Failed to load root "
- "certificates: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ return ret;
+}
+#endif /* OPENSSL_NO_STDIO */
+
+
+static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
+ const char *ca_cert, const u8 *ca_cert_blob,
+ size_t ca_cert_blob_len, const char *ca_path)
+{
+ SSL_CTX *ssl_ctx = _ssl_ctx;
+
+ if (ca_cert_blob) {
+ X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob,
+ ca_cert_blob_len);
+ if (cert == NULL) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to parse ca_cert_blob");
+ return -1;
+ }
+
+ if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to add ca_cert_blob to "
+ "certificate store");
+ X509_free(cert);
return -1;
+ }
+ X509_free(cert);
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
+ "to certificate store", __func__);
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ return 0;
+ }
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
+ 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
+ "system certificate store");
+ SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+ return 0;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ if (ca_cert || ca_path) {
+#ifndef OPENSSL_NO_STDIO
+ if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
+ 1) {
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to load root certificates");
+ if (ca_cert &&
+ tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
+ "DER format CA certificate",
+ __func__);
+ } else
+ return -1;
} else {
wpa_printf(MSG_DEBUG, "TLS: Trusted root "
"certificate(s) loaded");
tls_get_errors(ssl_ctx);
}
- SSL_set_app_data(conn->ssl, conn);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+#else /* OPENSSL_NO_STDIO */
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
+ __func__);
+ return -1;
+#endif /* OPENSSL_NO_STDIO */
} else {
/* No ca_cert configured - do not try to verify server
* certificate */
@@ -270,26 +1134,51 @@ int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
if (ca_cert) {
if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
{
- wpa_printf(MSG_WARNING, "TLS: Failed to load root "
- "certificates: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_WARNING, __func__,
+ "Failed to load root certificates");
return -1;
- } else {
- wpa_printf(MSG_DEBUG, "TLS: Trusted root "
- "certificate(s) loaded");
}
+
+ wpa_printf(MSG_DEBUG, "TLS: Trusted root "
+ "certificate(s) loaded");
+
+#ifndef OPENSSL_NO_STDIO
+ /* Add the same CAs to the client certificate requests */
+ SSL_CTX_set_client_CA_list(ssl_ctx,
+ SSL_load_client_CA_file(ca_cert));
+#endif /* OPENSSL_NO_STDIO */
}
return 0;
}
-int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
- int verify_peer, const char *subject_match)
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
{
- if (conn == NULL)
- return -1;
+ int flags;
+
+ if (check_crl) {
+ X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
+ if (cs == NULL) {
+ tls_show_errors(MSG_INFO, __func__, "Failed to get "
+ "certificate store when enabling "
+ "check_crl");
+ return -1;
+ }
+ flags = X509_V_FLAG_CRL_CHECK;
+ if (check_crl == 2)
+ flags |= X509_V_FLAG_CRL_CHECK_ALL;
+ X509_STORE_set_flags(cs, flags);
+ }
+ return 0;
+}
+
+static int tls_connection_set_subject_match(void *ssl_ctx,
+ struct tls_connection *conn,
+ const char *subject_match,
+ const char *altsubject_match)
+{
free(conn->subject_match);
conn->subject_match = NULL;
if (subject_match) {
@@ -298,8 +1187,25 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
return -1;
}
+ free(conn->altsubject_match);
+ conn->altsubject_match = NULL;
+ if (altsubject_match) {
+ conn->altsubject_match = strdup(altsubject_match);
+ if (conn->altsubject_match == NULL)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+ int verify_peer)
+{
+ if (conn == NULL)
+ return -1;
+
if (verify_peer) {
- SSL_set_app_data(conn->ssl, conn);
SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
@@ -313,29 +1219,60 @@ int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
}
-int tls_connection_client_cert(void *ssl_ctx, struct tls_connection *conn,
- const char *client_cert)
+static int tls_connection_client_cert(void *ssl_ctx,
+ struct tls_connection *conn,
+ const char *client_cert,
+ const u8 *client_cert_blob,
+ size_t client_cert_blob_len)
{
- if (client_cert == NULL)
+ if (client_cert == NULL && client_cert_blob == NULL)
return 0;
- if (conn == NULL)
+
+ if (client_cert_blob &&
+ SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
+ client_cert_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
+ "OK");
+ return 0;
+ } else if (client_cert_blob) {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_certificate_ASN1 failed");
+ }
+
+ if (client_cert == NULL)
return -1;
+#ifndef OPENSSL_NO_STDIO
if (SSL_use_certificate_file(conn->ssl, client_cert,
- SSL_FILETYPE_ASN1) != 1 &&
- SSL_use_certificate_file(conn->ssl, client_cert,
- SSL_FILETYPE_PEM) != 1) {
- wpa_printf(MSG_INFO, "TLS: Failed to load client "
- "certificate: %s",
- ERR_error_string(ERR_get_error(), NULL));
- return -1;
+ SSL_FILETYPE_ASN1) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
+ " --> OK");
+ return 0;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_certificate_file (DER) failed");
}
- return 0;
+
+ if (SSL_use_certificate_file(conn->ssl, client_cert,
+ SSL_FILETYPE_PEM) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
+ " --> OK");
+ return 0;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_certificate_file (PEM) failed");
+ }
+#else /* OPENSSL_NO_STDIO */
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+#endif /* OPENSSL_NO_STDIO */
+
+ return -1;
}
int tls_global_client_cert(void *_ssl_ctx, const char *client_cert)
{
+#ifndef OPENSSL_NO_STDIO
SSL_CTX *ssl_ctx = _ssl_ctx;
if (client_cert == NULL)
return 0;
@@ -344,12 +1281,17 @@ int tls_global_client_cert(void *_ssl_ctx, const char *client_cert)
SSL_FILETYPE_ASN1) != 1 &&
SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
SSL_FILETYPE_PEM) != 1) {
- wpa_printf(MSG_INFO, "TLS: Failed to load client "
- "certificate: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to load client certificate");
return -1;
}
return 0;
+#else /* OPENSSL_NO_STDIO */
+ if (client_cert == NULL)
+ return 0;
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+ return -1;
+#endif /* OPENSSL_NO_STDIO */
}
@@ -364,42 +1306,31 @@ static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
}
-static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
- const char *passwd)
-{
#ifdef PKCS12_FUNCS
- FILE *f;
- PKCS12 *p12;
+static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
+ const char *passwd)
+{
EVP_PKEY *pkey;
X509 *cert;
+ STACK_OF(X509) *certs;
int res = 0;
-
- f = fopen(private_key, "r");
- if (f == NULL)
- return -1;
-
- p12 = d2i_PKCS12_fp(f, NULL);
- if (p12 == NULL) {
- wpa_printf(MSG_DEBUG, "TLS: Failed to read PKCS12 file '%s'",
- private_key);
- fclose(f);
- return -1;
- }
- fclose(f);
+ char buf[256];
pkey = NULL;
cert = NULL;
- if (!PKCS12_parse(p12, passwd, &pkey, &cert, NULL)) {
- wpa_printf(MSG_DEBUG, "TLS: Failed to parse PKCS12 file '%s': "
- "%s", private_key,
- ERR_error_string(ERR_get_error(), NULL));
+ certs = NULL;
+ if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "Failed to parse PKCS12 file");
return -1;
}
- wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 file '%s'",
- private_key);
+ wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
if (cert) {
- wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12");
+ X509_NAME_oneline(X509_get_subject_name(cert), buf,
+ sizeof(buf));
+ wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
+ "subject='%s'", buf);
if (ssl) {
if (SSL_use_certificate(ssl, cert) != 1)
res = -1;
@@ -422,9 +1353,56 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
EVP_PKEY_free(pkey);
}
+ if (certs) {
+ while ((cert = sk_X509_pop(certs)) != NULL) {
+ X509_NAME_oneline(X509_get_subject_name(cert), buf,
+ sizeof(buf));
+ wpa_printf(MSG_DEBUG, "TLS: additional certificate"
+ " from PKCS12: subject='%s'", buf);
+ /*
+ * There is no SSL equivalent for the chain cert - so
+ * always add it to the context...
+ */
+ if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
+ res = -1;
+ break;
+ }
+ }
+ sk_X509_free(certs);
+ }
+
PKCS12_free(p12);
+ if (res < 0)
+ tls_get_errors(ssl_ctx);
+
return res;
+}
+#endif /* PKCS12_FUNCS */
+
+
+static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
+ const char *passwd)
+{
+#ifdef PKCS12_FUNCS
+ FILE *f;
+ PKCS12 *p12;
+
+ f = fopen(private_key, "r");
+ if (f == NULL)
+ return -1;
+
+ p12 = d2i_PKCS12_fp(f, NULL);
+ fclose(f);
+
+ if (p12 == NULL) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to use PKCS#12 file");
+ return -1;
+ }
+
+ return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+
#else /* PKCS12_FUNCS */
wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
"p12/pfx files");
@@ -433,17 +1411,65 @@ static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
}
-int tls_connection_private_key(void *_ssl_ctx, struct tls_connection *conn,
- const char *private_key,
- const char *private_key_passwd)
+static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
+ const u8 *blob, size_t len, const char *passwd)
+{
+#ifdef PKCS12_FUNCS
+ PKCS12 *p12;
+
+ p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
+ if (p12 == NULL) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to use PKCS#12 blob");
+ return -1;
+ }
+
+ return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+
+#else /* PKCS12_FUNCS */
+ wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
+ "p12/pfx blobs");
+ return -1;
+#endif /* PKCS12_FUNCS */
+}
+
+
+static int tls_connection_engine_private_key(void *_ssl_ctx,
+ struct tls_connection *conn)
+{
+#ifndef OPENSSL_NO_ENGINE
+ if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
+ tls_show_errors(MSG_ERROR, __func__,
+ "ENGINE: cannot use private key for TLS");
+ return -1;
+ }
+ if (!SSL_check_private_key(conn->ssl)) {
+ tls_show_errors(MSG_INFO, __func__,
+ "Private key failed verification");
+ return -1;
+ }
+ return 0;
+#else /* OPENSSL_NO_ENGINE */
+ wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
+ "engine support was not compiled in");
+ return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_private_key(void *_ssl_ctx,
+ struct tls_connection *conn,
+ const char *private_key,
+ const char *private_key_passwd,
+ const u8 *private_key_blob,
+ size_t private_key_blob_len)
{
SSL_CTX *ssl_ctx = _ssl_ctx;
char *passwd;
+ int ok;
- if (private_key == NULL)
+ if (private_key == NULL && private_key_blob == NULL)
return 0;
- if (conn == NULL)
- return -1;
if (private_key_passwd) {
passwd = strdup(private_key_passwd);
@@ -454,28 +1480,123 @@ int tls_connection_private_key(void *_ssl_ctx, struct tls_connection *conn,
SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
- if (SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_ASN1) != 1 &&
- SSL_use_PrivateKey_file(conn->ssl, private_key,
- SSL_FILETYPE_PEM) != 1 &&
- tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)) {
- wpa_printf(MSG_INFO, "SSL: Failed to load private key: %s",
- ERR_error_string(ERR_get_error(), NULL));
+
+ ok = 0;
+ while (private_key_blob) {
+ if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
+ (u8 *) private_key_blob,
+ private_key_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
+ "ASN1(EVP_PKEY_RSA) --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA)"
+ " failed");
+ }
+
+ if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
+ (u8 *) private_key_blob,
+ private_key_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
+ "ASN1(EVP_PKEY_DSA) --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA)"
+ " failed");
+ }
+
+ if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
+ (u8 *) private_key_blob,
+ private_key_blob_len) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: "
+ "SSL_use_RSAPrivateKey_ASN1 --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_RSAPrivateKey_ASN1 failed");
+ }
+
+ if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
+ private_key_blob_len, passwd) == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
+ "OK");
+ ok = 1;
+ break;
+ }
+
+ break;
+ }
+
+ while (!ok && private_key) {
+#ifndef OPENSSL_NO_STDIO
+ if (SSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_ASN1) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: "
+ "SSL_use_PrivateKey_File (DER) --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_PrivateKey_File (DER) "
+ "failed");
+ }
+
+ if (SSL_use_PrivateKey_file(conn->ssl, private_key,
+ SSL_FILETYPE_PEM) == 1) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: "
+ "SSL_use_PrivateKey_File (PEM) --> OK");
+ ok = 1;
+ break;
+ } else {
+ tls_show_errors(MSG_DEBUG, __func__,
+ "SSL_use_PrivateKey_File (PEM) "
+ "failed");
+ }
+#else /* OPENSSL_NO_STDIO */
+ wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
+ __func__);
+#endif /* OPENSSL_NO_STDIO */
+
+ if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
+ == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
+ "--> OK");
+ ok = 1;
+ break;
+ }
+
+ if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
+ wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
+ "access certificate store --> OK");
+ ok = 1;
+ break;
+ }
+
+ break;
+ }
+
+ if (!ok) {
+ wpa_printf(MSG_INFO, "OpenSSL: Failed to load private key");
free(passwd);
ERR_clear_error();
return -1;
}
ERR_clear_error();
- free(passwd);
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
+ free(passwd);
if (!SSL_check_private_key(conn->ssl)) {
- wpa_printf(MSG_INFO, "SSL: Private key failed "
- "verification: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__, "Private key failed "
+ "verification");
return -1;
}
+ wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
return 0;
}
@@ -498,13 +1619,16 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
- if (SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
+ if (
+#ifndef OPENSSL_NO_STDIO
+ SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
SSL_FILETYPE_ASN1) != 1 &&
SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
SSL_FILETYPE_PEM) != 1 &&
+#endif /* OPENSSL_NO_STDIO */
tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
- wpa_printf(MSG_INFO, "SSL: Failed to load private key: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Failed to load private key");
free(passwd);
ERR_clear_error();
return -1;
@@ -514,9 +1638,8 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
if (!SSL_CTX_check_private_key(ssl_ctx)) {
- wpa_printf(MSG_INFO, "SSL: Private key failed "
- "verification: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Private key failed verification");
return -1;
}
@@ -524,7 +1647,7 @@ int tls_global_private_key(void *_ssl_ctx, const char *private_key,
}
-int tls_connection_dh(void *ssl_ctx, struct tls_connection *conn,
+static int tls_connection_dh(void *ssl_ctx, struct tls_connection *conn,
const char *dh_file)
{
#ifdef OPENSSL_NO_DH
@@ -537,6 +1660,7 @@ int tls_connection_dh(void *ssl_ctx, struct tls_connection *conn,
DH *dh;
BIO *bio;
+ /* TODO: add support for dh_blob */
if (dh_file == NULL)
return 0;
if (conn == NULL)
@@ -609,6 +1733,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));
keys->master_key = ssl->session->master_key;
keys->master_key_len = ssl->session->master_key_length;
keys->client_random = ssl->s3->client_random;
@@ -627,13 +1752,18 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
int res;
u8 *out_data;
+ /*
+ * Give TLS handshake data from the server (if available) to OpenSSL
+ * for processing.
+ */
if (in_data &&
BIO_write(conn->ssl_in, in_data, in_len) < 0) {
- wpa_printf(MSG_INFO, "TLS: Handshake failed - BIO_write: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Handshake failed - BIO_write");
return NULL;
}
+ /* Initiate TLS handshake or continue the existing handshake */
res = SSL_connect(conn->ssl);
if (res != 1) {
int err = SSL_get_error(conn->ssl, res);
@@ -644,27 +1774,33 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
"write");
else {
- wpa_printf(MSG_INFO, "SSL: SSL_connect: %s",
- ERR_error_string(ERR_get_error(), NULL));
- return NULL;
+ tls_show_errors(MSG_INFO, __func__, "SSL_connect");
+ conn->failed++;
}
}
+ /* Get the TLS handshake data to be sent to the server */
res = BIO_ctrl_pending(conn->ssl_out);
wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
out_data = malloc(res == 0 ? 1 : res);
if (out_data == NULL) {
wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
"handshake output (%d bytes)", res);
- BIO_reset(conn->ssl_out);
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "BIO_reset failed");
+ }
*out_len = 0;
return NULL;
}
res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Handshake failed - BIO_read: %s",
- ERR_error_string(ERR_get_error(), NULL));
- BIO_reset(conn->ssl_out);
+ tls_show_errors(MSG_INFO, __func__,
+ "Handshake failed - BIO_read");
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "BIO_reset failed");
+ }
*out_len = 0;
return NULL;
}
@@ -684,8 +1820,8 @@ u8 * tls_connection_server_handshake(void *ssl_ctx,
if (in_data &&
BIO_write(conn->ssl_in, in_data, in_len) < 0) {
- wpa_printf(MSG_INFO, "TLS: Handshake failed - BIO_write: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Handshake failed - BIO_write");
return NULL;
}
@@ -701,15 +1837,21 @@ u8 * tls_connection_server_handshake(void *ssl_ctx,
if (out_data == NULL) {
wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
"handshake output (%d bytes)", res);
- BIO_reset(conn->ssl_out);
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "BIO_reset failed");
+ }
*out_len = 0;
return NULL;
}
res = res == 0 ? 0 : BIO_read(conn->ssl_out, out_data, res);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Handshake failed - BIO_read: %s",
- ERR_error_string(ERR_get_error(), NULL));
- BIO_reset(conn->ssl_out);
+ tls_show_errors(MSG_INFO, __func__,
+ "Handshake failed - BIO_read");
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__,
+ "BIO_reset failed");
+ }
*out_len = 0;
return NULL;
}
@@ -719,7 +1861,7 @@ u8 * tls_connection_server_handshake(void *ssl_ctx,
int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
- u8 *in_data, size_t in_len,
+ const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len)
{
int res;
@@ -727,19 +1869,24 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
if (conn == NULL)
return -1;
- BIO_reset(conn->ssl_in);
- BIO_reset(conn->ssl_out);
+ /* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
+ if ((res = BIO_reset(conn->ssl_in)) < 0 ||
+ (res = BIO_reset(conn->ssl_out)) < 0) {
+ tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
+ return res;
+ }
res = SSL_write(conn->ssl, in_data, in_len);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Encryption failed - SSL_write: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Encryption failed - SSL_write");
return res;
}
+ /* Read encrypted data to be sent to the server */
res = BIO_read(conn->ssl_out, out_data, out_len);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Encryption failed - BIO_read: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Encryption failed - BIO_read");
return res;
}
@@ -748,23 +1895,28 @@ int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
- u8 *in_data, size_t in_len,
+ const u8 *in_data, size_t in_len,
u8 *out_data, size_t out_len)
{
int res;
+ /* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
res = BIO_write(conn->ssl_in, in_data, in_len);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Decryption failed - BIO_write: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Decryption failed - BIO_write");
+ return res;
+ }
+ if (BIO_reset(conn->ssl_out) < 0) {
+ tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
return res;
}
- BIO_reset(conn->ssl_out);
+ /* Read decrypted data for further processing */
res = SSL_read(conn->ssl, out_data, out_len);
if (res < 0) {
- wpa_printf(MSG_INFO, "TLS: Decryption failed - SSL_read: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Decryption failed - SSL_read");
return res;
}
@@ -778,22 +1930,54 @@ int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
}
+#ifdef EAP_FAST
+/* Pre-shared secred requires a patch to openssl, so this function is
+ * commented out unless explicitly needed for EAP-FAST in order to be able to
+ * build this file with unmodified openssl. */
+
+static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
+ STACK_OF(SSL_CIPHER) *peer_ciphers,
+ SSL_CIPHER **cipher, void *arg)
+{
+ struct tls_connection *conn = arg;
+
+ if (conn == NULL || conn->pre_shared_secret == 0)
+ return 0;
+
+ memcpy(secret, conn->pre_shared_secret, conn->pre_shared_secret_len);
+ *secret_len = conn->pre_shared_secret_len;
+
+ return 1;
+}
+
+
int tls_connection_set_master_key(void *ssl_ctx, struct tls_connection *conn,
const u8 *key, size_t key_len)
{
- SSL *ssl;
-
- if (conn == NULL || key == NULL || key_len > SSL_MAX_MASTER_KEY_LENGTH)
- return -1;
- ssl = conn->ssl;
- if (ssl == NULL || ssl->session == NULL)
+ if (conn == NULL || key_len > SSL_MAX_MASTER_KEY_LENGTH)
return -1;
- memcpy(ssl->session->master_key, key, key_len);
- ssl->session->master_key_length = key_len;
+ 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);
+ if (conn->pre_shared_secret) {
+ 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,
+ conn) != 1)
+ return -1;
+ } else {
+ if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+ return -1;
+ }
return 0;
}
+#endif /* EAP_FAST */
int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn)
@@ -802,8 +1986,8 @@ int tls_connection_set_anon_dh(void *ssl_ctx, struct tls_connection *conn)
return -1;
if (SSL_set_cipher_list(conn->ssl, "ADH-AES128-SHA") != 1) {
- wpa_printf(MSG_INFO, "TLS: Anon DH configuration failed - %s",
- ERR_error_string(ERR_get_error(), NULL));
+ tls_show_errors(MSG_INFO, __func__,
+ "Anon DH configuration failed");
return -1;
}
@@ -844,36 +2028,116 @@ int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
int ext_type, const u8 *data,
size_t data_len)
{
- struct tls_ext_hdr {
- u16 extensions_len;
- u16 extension_type;
- u16 extension_len;
- } *hdr;
-
if (conn == NULL || conn->ssl == NULL)
return -1;
- OPENSSL_free(conn->ssl->hello_extension);
- if (data == NULL) {
- conn->ssl->hello_extension = NULL;
- conn->ssl->hello_extension_len = 0;
- return 0;
+
+ if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
+ data_len) != 1)
+ return -1;
+
+ return 0;
+}
+#endif /* EAP_FAST */
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->write_alerts;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+ const struct tls_connection_params *params)
+{
+ int ret;
+ unsigned long err;
+
+ if (conn == NULL)
+ return -1;
+
+ while ((err = ERR_get_error())) {
+ wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
+ __func__, ERR_error_string(err, NULL));
}
- if (data_len == 0) {
- conn->ssl->hello_extension = OPENSSL_malloc(1);
- conn->ssl->hello_extension_len = 0;
- return 0;
+
+ if (tls_connection_set_subject_match(tls_ctx, conn,
+ params->subject_match,
+ params->altsubject_match))
+ return -1;
+ if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+ params->ca_cert_blob,
+ params->ca_cert_blob_len,
+ params->ca_path))
+ return -1;
+ if (tls_connection_client_cert(tls_ctx, conn, params->client_cert,
+ params->client_cert_blob,
+ params->client_cert_blob_len))
+ return -1;
+
+ if (params->engine) {
+ wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+ ret = tls_engine_init(conn, params->engine_id, params->pin,
+ params->key_id);
+ if (ret)
+ return ret;
+ if (tls_connection_engine_private_key(tls_ctx, conn))
+ return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+ } else if (tls_connection_private_key(tls_ctx, conn,
+ params->private_key,
+ params->private_key_passwd,
+ params->private_key_blob,
+ params->private_key_blob_len)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
+ params->private_key);
+ return -1;
}
- conn->ssl->hello_extension = OPENSSL_malloc(sizeof(*hdr) + data_len);
- if (conn->ssl->hello_extension == NULL)
+
+ if (tls_connection_dh(tls_ctx, conn, params->dh_file)) {
+ wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+ params->dh_file);
return -1;
+ }
- hdr = (struct tls_ext_hdr *) conn->ssl->hello_extension;
- hdr->extensions_len = host_to_be16(sizeof(*hdr) - 2 + data_len);
- hdr->extension_type = host_to_be16(ext_type);
- hdr->extension_len = host_to_be16(data_len);
- memcpy(hdr + 1, data, data_len);
- conn->ssl->hello_extension_len = sizeof(*hdr) + data_len;
+ tls_get_errors(tls_ctx);
return 0;
}
-#endif /* EAP_FAST */
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+ struct tls_connection *conn)
+{
+ const EVP_CIPHER *c;
+ const EVP_MD *h;
+
+ if (conn == NULL || conn->ssl == NULL ||
+ conn->ssl->enc_read_ctx == NULL ||
+ conn->ssl->enc_read_ctx->cipher == NULL ||
+ conn->ssl->read_hash == NULL)
+ return -1;
+
+ c = conn->ssl->enc_read_ctx->cipher;
+ h = conn->ssl->read_hash;
+
+ return 2 * (EVP_CIPHER_key_length(c) +
+ EVP_MD_size(h) +
+ EVP_CIPHER_iv_length(c));
+}
diff --git a/contrib/wpa_supplicant/tls_schannel.c b/contrib/wpa_supplicant/tls_schannel.c
new file mode 100644
index 0000000..d06a1c3
--- /dev/null
+++ b/contrib/wpa_supplicant/tls_schannel.c
@@ -0,0 +1,738 @@
+/*
+ * WPA Supplicant / SSL/TLS interface functions for Microsoft Schannel
+ * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.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.
+ */
+
+/*
+ * FIX: Go through all SSPI functions and verify what needs to be freed
+ * FIX: session resumption
+ * TODO: add support for server cert chain validation
+ * TODO: add support for CA cert validation
+ * TODO: add support for EAP-TLS (client cert/key conf)
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <windows.h>
+#include <wincrypt.h>
+#include <schannel.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <sspi.h>
+
+#include "common.h"
+#include "tls.h"
+
+
+struct tls_global {
+ HMODULE hsecurity;
+ PSecurityFunctionTable sspi;
+ HCERTSTORE my_cert_store;
+};
+
+struct tls_connection {
+ int established, start;
+ int failed, read_alerts, write_alerts;
+
+ SCHANNEL_CRED schannel_cred;
+ CredHandle creds;
+ CtxtHandle context;
+
+ u8 eap_tls_prf[128];
+ int eap_tls_prf_set;
+};
+
+
+static int schannel_load_lib(struct tls_global *global)
+{
+ INIT_SECURITY_INTERFACE pInitSecurityInterface;
+
+ global->hsecurity = LoadLibrary("Secur32.dll");
+ if (global->hsecurity == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
+ __func__, (unsigned int) GetLastError());
+ return -1;
+ }
+
+ pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
+ global->hsecurity, "InitSecurityInterfaceA");
+ if (pInitSecurityInterface == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Could not find "
+ "InitSecurityInterfaceA from Secur32.dll",
+ __func__);
+ FreeLibrary(global->hsecurity);
+ global->hsecurity = NULL;
+ return -1;
+ }
+
+ global->sspi = pInitSecurityInterface();
+ if (global->sspi == NULL) {
+ wpa_printf(MSG_ERROR, "%s: Could not read security "
+ "interface - 0x%x",
+ __func__, (unsigned int) GetLastError());
+ FreeLibrary(global->hsecurity);
+ global->hsecurity = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+ struct tls_global *global;
+
+ global = malloc(sizeof(*global));
+ if (global == NULL)
+ return NULL;
+ memset(global, 0, sizeof(*global));
+ if (schannel_load_lib(global)) {
+ free(global);
+ return NULL;
+ }
+ return global;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+ struct tls_global *global = ssl_ctx;
+
+ if (global->my_cert_store)
+ CertCloseStore(global->my_cert_store, 0);
+ FreeLibrary(global->hsecurity);
+ free(global);
+}
+
+
+int tls_get_errors(void *ssl_ctx)
+{
+ return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+ struct tls_connection *conn;
+
+ conn = malloc(sizeof(*conn));
+ if (conn == NULL)
+ return NULL;
+ memset(conn, 0, sizeof(*conn));
+ conn->start = 1;
+
+ return conn;
+}
+
+
+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return;
+
+ free(conn);
+}
+
+
+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
+{
+ return conn ? conn->established : 0;
+}
+
+
+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
+{
+ struct tls_global *global = ssl_ctx;
+ if (conn == NULL)
+ return -1;
+
+ conn->eap_tls_prf_set = 0;
+ conn->established = conn->failed = 0;
+ conn->read_alerts = conn->write_alerts = 0;
+ global->sspi->DeleteSecurityContext(&conn->context);
+ /* FIX: what else needs to be reseted? */
+
+ return 0;
+}
+
+
+int tls_global_ca_cert(void *_ssl_ctx, const char *ca_cert)
+{
+ return -1;
+}
+
+
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
+{
+ return -1;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+ int verify_peer)
+{
+ return -1;
+}
+
+
+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)
+{
+ return -1;
+}
+
+
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+ struct tls_keys *keys)
+{
+ 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
+ * EAP-TTLS cannot use this, though, since they are using different
+ * labels. The only option could be to implement TLSv1 completely here
+ * 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);
+
+ return 0;
+}
+
+
+static u8 * tls_conn_hs_clienthello(struct tls_global *global,
+ struct tls_connection *conn,
+ size_t *out_len)
+{
+ DWORD sspi_flags, sspi_flags_out;
+ SecBufferDesc outbuf;
+ SecBuffer outbufs[1];
+ SECURITY_STATUS status;
+ TimeStamp ts_expiry;
+
+ sspi_flags = ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_RET_EXTENDED_ERROR |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_MANUAL_CRED_VALIDATION;
+
+ wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
+
+ outbufs[0].pvBuffer = NULL;
+ outbufs[0].BufferType = SECBUFFER_TOKEN;
+ outbufs[0].cbBuffer = 0;
+
+ outbuf.cBuffers = 1;
+ outbuf.pBuffers = outbufs;
+ outbuf.ulVersion = SECBUFFER_VERSION;
+
+ 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);
+ if (status != SEC_I_CONTINUE_NEEDED) {
+ wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
+ "failed - 0x%x",
+ __func__, (unsigned int) status);
+ return NULL;
+ }
+
+ if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
+ u8 *buf;
+ wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
+ outbufs[0].pvBuffer, outbufs[0].cbBuffer);
+ conn->start = 0;
+ *out_len = outbufs[0].cbBuffer;
+ buf = malloc(*out_len);
+ if (buf == NULL)
+ return NULL;
+ memcpy(buf, outbufs[0].pvBuffer, *out_len);
+ global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
+ return buf;
+ }
+
+ wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
+
+ return NULL;
+}
+
+
+#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
+#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
+
+typedef struct _SecPkgContext_EapKeyBlock {
+ BYTE rgbKeys[128];
+ BYTE rgbIVs[64];
+} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
+#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
+
+static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
+{
+ SECURITY_STATUS status;
+ SecPkgContext_EapKeyBlock kb;
+
+ /* Note: Windows NT and Windows Me/98/95 do not support getting
+ * EapKeyBlock */
+
+ status = global->sspi->QueryContextAttributes(
+ &conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
+ if (status != SEC_E_OK) {
+ wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
+ "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
+ __func__, (int) status);
+ return -1;
+ }
+
+ wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
+ kb.rgbKeys, sizeof(kb.rgbKeys));
+ wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
+ kb.rgbIVs, sizeof(kb.rgbIVs));
+
+ memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
+ conn->eap_tls_prf_set = 1;
+}
+
+
+u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len)
+{
+ struct tls_global *global = ssl_ctx;
+ DWORD sspi_flags, sspi_flags_out;
+ SecBufferDesc inbuf, outbuf;
+ SecBuffer inbufs[2], outbufs[1];
+ SECURITY_STATUS status;
+ TimeStamp ts_expiry;
+ u8 *out_buf = NULL;
+
+ if (conn->start) {
+ return tls_conn_hs_clienthello(global, conn, out_len);
+ }
+
+ wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
+ in_len);
+
+ sspi_flags = ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_RET_EXTENDED_ERROR |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_MANUAL_CRED_VALIDATION;
+
+ /* Input buffer for Schannel */
+ inbufs[0].pvBuffer = (u8 *) in_data;
+ inbufs[0].cbBuffer = in_len;
+ inbufs[0].BufferType = SECBUFFER_TOKEN;
+
+ /* Place for leftover data from Schannel */
+ inbufs[1].pvBuffer = NULL;
+ inbufs[1].cbBuffer = 0;
+ inbufs[1].BufferType = SECBUFFER_EMPTY;
+
+ inbuf.cBuffers = 2;
+ inbuf.pBuffers = inbufs;
+ inbuf.ulVersion = SECBUFFER_VERSION;
+
+ /* Output buffer for Schannel */
+ outbufs[0].pvBuffer = NULL;
+ outbufs[0].cbBuffer = 0;
+ outbufs[0].BufferType = SECBUFFER_TOKEN;
+
+ outbuf.cBuffers = 1;
+ outbuf.pBuffers = outbufs;
+ outbuf.ulVersion = SECBUFFER_VERSION;
+
+ status = global->sspi->InitializeSecurityContextA(
+ &conn->creds, &conn->context, NULL, sspi_flags, 0,
+ SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
+ &outbuf, &sspi_flags_out, &ts_expiry);
+
+ wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContextA -> "
+ "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
+ "intype[1]=%d outlen[0]=%d",
+ (int) status, (int) inbufs[0].cbBuffer,
+ (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
+ (int) inbufs[1].BufferType,
+ (int) outbufs[0].cbBuffer);
+ if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
+ (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
+ if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
+ 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);
+ global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
+ outbufs[0].pvBuffer = NULL;
+ }
+ }
+
+ switch (status) {
+ case SEC_E_INCOMPLETE_MESSAGE:
+ wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
+ break;
+ case SEC_I_CONTINUE_NEEDED:
+ wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
+ break;
+ case SEC_E_OK:
+ /* TODO: verify server certificate chain */
+ wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
+ "completed successfully");
+ conn->established = 1;
+ tls_get_eap(global, conn);
+
+ /* Need to return something to get final TLS ACK. */
+ if (out_buf == NULL)
+ out_buf = 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 */
+ global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
+ inbufs[1].pvBuffer = NULL;
+ }
+ break;
+ case SEC_I_INCOMPLETE_CREDENTIALS:
+ wpa_printf(MSG_DEBUG,
+ "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
+ break;
+ case SEC_E_WRONG_PRINCIPAL:
+ wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
+ break;
+ case SEC_E_INTERNAL_ERROR:
+ wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
+ break;
+ }
+
+ if (FAILED(status)) {
+ wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
+ "(out_buf=%p)", out_buf);
+ conn->failed++;
+ global->sspi->DeleteSecurityContext(&conn->context);
+ return out_buf;
+ }
+
+ if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
+ /* TODO: Can this happen? What to do with this data? */
+ wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
+ inbufs[1].pvBuffer, inbufs[1].cbBuffer);
+ global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
+ inbufs[1].pvBuffer = NULL;
+ }
+
+ return out_buf;
+}
+
+
+u8 * tls_connection_server_handshake(void *ssl_ctx,
+ struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ size_t *out_len)
+{
+ return NULL;
+}
+
+
+int tls_connection_encrypt(void *ssl_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ struct tls_global *global = ssl_ctx;
+ SECURITY_STATUS status;
+ SecBufferDesc buf;
+ SecBuffer bufs[4];
+ SecPkgContext_StreamSizes sizes;
+ int i;
+ size_t total_len;
+
+ status = global->sspi->QueryContextAttributes(&conn->context,
+ SECPKG_ATTR_STREAM_SIZES,
+ &sizes);
+ if (status != SEC_E_OK) {
+ wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
+ __func__);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
+ __func__,
+ (unsigned int) sizes.cbHeader,
+ (unsigned int) sizes.cbTrailer);
+
+ total_len = sizes.cbHeader + in_len + sizes.cbTrailer;
+
+ if (out_len < total_len) {
+ wpa_printf(MSG_DEBUG, "%s: too short out_data (out_len=%lu "
+ "in_len=%lu total_len=%lu)", __func__,
+ (unsigned long) out_len, (unsigned long) in_len,
+ (unsigned long) total_len);
+ return -1;
+ }
+
+ 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);
+ bufs[1].pvBuffer = out_data + sizes.cbHeader;
+ bufs[1].cbBuffer = in_len;
+ bufs[1].BufferType = SECBUFFER_DATA;
+
+ bufs[2].pvBuffer = out_data + sizes.cbHeader + in_len;
+ bufs[2].cbBuffer = sizes.cbTrailer;
+ bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
+
+ buf.ulVersion = SECBUFFER_VERSION;
+ buf.cBuffers = 3;
+ buf.pBuffers = bufs;
+
+ status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
+
+ wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
+ "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
+ "len[2]=%d type[2]=%d",
+ (int) status,
+ (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
+ (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
+ (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
+ wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
+ "out_data=%p bufs %p %p %p",
+ out_data, bufs[0].pvBuffer, bufs[1].pvBuffer,
+ bufs[2].pvBuffer);
+
+ for (i = 0; i < 3; i++) {
+ if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
+ {
+ wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
+ bufs[i].pvBuffer, bufs[i].cbBuffer);
+ }
+ }
+
+ if (status == SEC_E_OK) {
+ wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
+ wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Encrypted data from "
+ "EncryptMessage", out_data, total_len);
+ return total_len;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
+ __func__, (int) status);
+ return -1;
+}
+
+
+int tls_connection_decrypt(void *ssl_ctx, struct tls_connection *conn,
+ const u8 *in_data, size_t in_len,
+ u8 *out_data, size_t out_len)
+{
+ struct tls_global *global = ssl_ctx;
+ SECURITY_STATUS status;
+ SecBufferDesc buf;
+ SecBuffer bufs[4];
+ int i;
+
+ if (out_len < in_len) {
+ wpa_printf(MSG_DEBUG, "%s: out_len=%lu < in_len=%lu", __func__,
+ (unsigned long) out_len, (unsigned long) in_len);
+ return -1;
+ }
+
+ 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);
+ bufs[0].pvBuffer = out_data;
+ bufs[0].cbBuffer = in_len;
+ bufs[0].BufferType = SECBUFFER_DATA;
+
+ bufs[1].BufferType = SECBUFFER_EMPTY;
+ bufs[2].BufferType = SECBUFFER_EMPTY;
+ bufs[3].BufferType = SECBUFFER_EMPTY;
+
+ buf.ulVersion = SECBUFFER_VERSION;
+ buf.cBuffers = 4;
+ buf.pBuffers = bufs;
+
+ status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
+ NULL);
+ wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
+ "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
+ "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
+ (int) status,
+ (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
+ (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
+ (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
+ (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
+ wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
+ "out_data=%p bufs %p %p %p %p",
+ out_data, bufs[0].pvBuffer, bufs[1].pvBuffer,
+ bufs[2].pvBuffer, bufs[3].pvBuffer);
+
+ switch (status) {
+ case SEC_E_INCOMPLETE_MESSAGE:
+ wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
+ __func__);
+ break;
+ case SEC_E_OK:
+ wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
+ for (i = 0; i < 4; i++) {
+ if (bufs[i].BufferType == SECBUFFER_DATA)
+ break;
+ }
+ if (i == 4) {
+ wpa_printf(MSG_DEBUG, "%s: No output data from "
+ "DecryptMessage", __func__);
+ return -1;
+ }
+ wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
+ "DecryptMessage",
+ bufs[i].pvBuffer, bufs[i].cbBuffer);
+ if (bufs[i].cbBuffer > out_len) {
+ wpa_printf(MSG_DEBUG, "%s: Too long output data",
+ __func__);
+ return -1;
+ }
+ memmove(out_data, bufs[i].pvBuffer, bufs[i].cbBuffer);
+ return bufs[i].cbBuffer;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
+ __func__, (int) status);
+ return -1;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+ return 0;
+}
+
+
+#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)
+{
+ return -1;
+}
+
+
+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+ char *buf, size_t buflen)
+{
+ return -1;
+}
+
+
+int tls_connection_enable_workaround(void *ssl_ctx,
+ struct tls_connection *conn)
+{
+ return 0;
+}
+
+
+#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)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+ if (conn == NULL)
+ return -1;
+ return conn->write_alerts;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+ const struct tls_connection_params *params)
+{
+ struct tls_global *global = tls_ctx;
+ ALG_ID algs[1];
+ SECURITY_STATUS status;
+ TimeStamp ts_expiry;
+
+ if (conn == NULL)
+ return -1;
+
+ if (global->my_cert_store == NULL &&
+ (global->my_cert_store = CertOpenSystemStore(0, "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));
+ 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;
+ status = global->sspi->AcquireCredentialsHandleA(
+ NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
+ &conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
+ if (status != SEC_E_OK) {
+ wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
+ "0x%x", __func__, (unsigned int) status);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/todo.txt b/contrib/wpa_supplicant/todo.txt
index 52f3349..5ecda1d 100644
--- a/contrib/wpa_supplicant/todo.txt
+++ b/contrib/wpa_supplicant/todo.txt
@@ -1,21 +1,9 @@
To do:
-- add WPA support to Linux Wireless Extensions
-- add support for other drivers
-- implement GUI for WPA Supplicant/Xsupplicant/iwconfig/iwlist
- (easy to use configuration and network stats, etc.)
-- add support for opportunistic PMKSA caching
- hostap: try other roaming modes
NOTE: current mode (manual roaming) does not really roam at all..
Firmware did not notice the current AP disappearing..
-- EAP-MSCHAPv2: add support for password changing
- add support for WPA with ap_scan=0 (update selected cipher etc. based on
AssocInfo; make sure these match with configuration)
-- add driver interface for using wpa_supplicant with wired interface
- (or a separate program using EAPOL library)
-- wpa_supplicant.conf g+rw so that frontend can change wpa_supplicant.conf
- and RECONFIG wpa_supplicant (?)
- (or wpa_supplicant changes .conf and ctrl interface gets support for
- changing config?)
- optional security separation (build time option): run EAPOL state machines
as non-root (need to add something like socketpair between privileged root
process and non-root handler; send EAPOL packets between processes
@@ -29,9 +17,6 @@ To do:
auth)
- EAP-AKA: AT_CHECKCODE
- EAP-SIM/AKA: AT_RESULT_IND
-- abort auth if EAP method initialization fails and there no other
- accepted methods (i.e., do not send NAK for the same method that just
- failed)
- 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
@@ -40,15 +25,31 @@ To do:
- 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
-- read CA certs from PFX file
- 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)
+ 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..
-- update developer.txt to match with current implementation
- (driver API updates, EAP methods)
-- driver_wext.c and driver that does not support WPA -> fix plaintext, WEP, and
- IEEE 802.1X operation (e.g., use capabilities to report no support for WPA)
+- -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)
+ * 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?)
+- 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
+ web pages including the same information.. i.e., have this information only
+ 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
diff --git a/contrib/wpa_supplicant/version.h b/contrib/wpa_supplicant/version.h
index b030f34..8f8eff8 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.3.9"
+#define VERSION_STR "0.4.8"
#endif /* VERSION_H */
diff --git a/contrib/wpa_supplicant/wpa.c b/contrib/wpa_supplicant/wpa.c
index c70f556..91e1f2a 100644
--- a/contrib/wpa_supplicant/wpa.c
+++ b/contrib/wpa_supplicant/wpa.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant
+ * WPA Supplicant - WPA state machine and EAPOL-Key processing
* Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -14,12 +14,10 @@
#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 "common.h"
#include "md5.h"
@@ -27,23 +25,14 @@
#include "rc4.h"
#include "aes_wrap.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 "wpa_supplicant_i.h"
+#include "preauth.h"
+#include "wpa_i.h"
-static void rsn_preauth_candidate_process(struct wpa_supplicant *wpa_s);
-
-#define PMKID_CANDIDATE_PRIO_SCAN 1000
-
-/* TODO: make these configurable */
-static const int dot11RSNAConfigPMKLifetime = 43200;
-static const int dot11RSNAConfigPMKReauthThreshold = 70;
-static const int dot11RSNAConfigSATimeout = 60;
-static const int pmksa_cache_max_entries = 32;
static const int WPA_SELECTOR_LEN = 4;
static const u8 WPA_OUI_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
@@ -68,7 +57,7 @@ static const u8 WPA_CIPHER_SUITE_WEP104[] = { 0x00, 0x50, 0xf2, 5 };
* Authenticated Key Management Suite Count (2 octets, little endian)
* (default: 1)
* Authenticated Key Management Suite List (4 * n octets)
- * (default: unspec 802.1x)
+ * (default: unspec 802.1X)
* WPA Capabilities (2 octets, little endian) (default: 0)
*/
@@ -77,7 +66,7 @@ struct wpa_ie_hdr {
u8 len;
u8 oui[3];
u8 oui_type;
- u16 version;
+ u8 version[2];
} __attribute__ ((packed));
@@ -117,7 +106,7 @@ static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 };
* Authenticated Key Management Suite Count (2 octets, little endian)
* (default: 1)
* Authenticated Key Management Suite List (4 * n octets)
- * (default: unspec 802.1x)
+ * (default: unspec 802.1X)
* RSN Capabilities (2 octets, little endian) (default: 0)
* PMKID Count (2 octets) (default: 0)
* PMKID List (16 * n octets)
@@ -126,11 +115,93 @@ static const u8 RSN_KEY_DATA_PMKID[] = { 0x00, 0x0f, 0xac, 4 };
struct rsn_ie_hdr {
u8 elem_id; /* WLAN_EID_RSN */
u8 len;
- u16 version;
+ u8 version[2];
+} __attribute__ ((packed));
+
+
+struct wpa_eapol_key {
+ u8 type;
+ /* Note: key_info, key_length, and key_data_length are unaligned */
+ u8 key_info[2];
+ u8 key_length[2];
+ u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+ u8 key_nonce[WPA_NONCE_LEN];
+ u8 key_iv[16];
+ u8 key_rsc[8];
+ u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
+ u8 key_mic[16];
+ u8 key_data_length[2];
+ /* followed by key_data_length bytes of key_data */
} __attribute__ ((packed));
+#define WPA_KEY_INFO_TYPE_MASK (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 */
+/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
+#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
+#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
+#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
+#define WPA_KEY_INFO_TXRX BIT(6) /* group */
+#define WPA_KEY_INFO_ACK BIT(7)
+#define WPA_KEY_INFO_MIC BIT(8)
+#define WPA_KEY_INFO_SECURE BIT(9)
+#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 */
+
+
+
+/**
+ * wpa_cipher_txt - Convert cipher suite to a text string
+ * @cipher: Cipher suite (WPA_CIPHER_* enum)
+ * Returns: Pointer to a text string of the cipher suite name
+ */
+static const char * wpa_cipher_txt(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_NONE:
+ return "NONE";
+ case WPA_CIPHER_WEP40:
+ return "WEP-40";
+ case WPA_CIPHER_WEP104:
+ return "WEP-104";
+ case WPA_CIPHER_TKIP:
+ return "TKIP";
+ case WPA_CIPHER_CCMP:
+ return "CCMP";
+ default:
+ return "UNKNOWN";
+ }
+}
+
-static int wpa_selector_to_bitfield(u8 *s)
+/**
+ * wpa_key_mgmt_txt - Convert key management suite to a text string
+ * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
+ * @proto: WPA/WPA2 version (WPA_PROTO_*)
+ * Returns: Pointer to a text string of the key management suite name
+ */
+static const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
+{
+ switch (key_mgmt) {
+ case WPA_KEY_MGMT_IEEE8021X:
+ return proto == WPA_PROTO_RSN ?
+ "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
+ case WPA_KEY_MGMT_PSK:
+ return proto == WPA_PROTO_RSN ?
+ "WPA2-PSK" : "WPA-PSK";
+ case WPA_KEY_MGMT_NONE:
+ return "NONE";
+ case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
+ return "IEEE 802.1X (no WPA)";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+static int wpa_selector_to_bitfield(const u8 *s)
{
if (memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == 0)
return WPA_CIPHER_NONE;
@@ -146,7 +217,7 @@ static int wpa_selector_to_bitfield(u8 *s)
}
-static int wpa_key_mgmt_to_bitfield(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;
@@ -159,7 +230,7 @@ static int wpa_key_mgmt_to_bitfield(u8 *s)
}
-static int rsn_selector_to_bitfield(u8 *s)
+static int rsn_selector_to_bitfield(const u8 *s)
{
if (memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == 0)
return WPA_CIPHER_NONE;
@@ -175,7 +246,7 @@ static int rsn_selector_to_bitfield(u8 *s)
}
-static int rsn_key_mgmt_to_bitfield(u8 *s)
+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;
@@ -186,217 +257,11 @@ static int rsn_key_mgmt_to_bitfield(u8 *s)
}
-static void rsn_pmkid(u8 *pmk, u8 *aa, 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_supplicant *wpa_s);
-
-
-static void pmksa_cache_free_entry(struct wpa_supplicant *wpa_s,
- struct rsn_pmksa_cache *entry)
-{
- free(entry);
- wpa_s->pmksa_count--;
- if (wpa_s->cur_pmksa == entry) {
- wpa_printf(MSG_DEBUG, "RSN: removed current PMKSA entry");
- /* TODO: should drop PMK and PTK and trigger new key
- * negotiation */
- wpa_s->cur_pmksa = NULL;
- }
-}
-
-
-static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+ struct wpa_ie_data *data)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- time_t now;
-
- time(&now);
- while (wpa_s->pmksa && wpa_s->pmksa->expiration <= now) {
- struct rsn_pmksa_cache *entry = wpa_s->pmksa;
- wpa_s->pmksa = entry->next;
- wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
- MACSTR, MAC2STR(entry->aa));
- pmksa_cache_free_entry(wpa_s, entry);
- }
-
- pmksa_cache_set_expiration(wpa_s);
-}
-
-
-static void pmksa_cache_set_expiration(struct wpa_supplicant *wpa_s)
-{
- int sec;
- eloop_cancel_timeout(pmksa_cache_expire, wpa_s, NULL);
- if (wpa_s->pmksa == NULL)
- return;
- sec = wpa_s->pmksa->expiration - time(NULL);
- if (sec < 0)
- sec = 0;
- eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, wpa_s, NULL);
-}
-
-
-static void pmksa_cache_add(struct wpa_supplicant *wpa_s, u8 *pmk,
- size_t pmk_len, u8 *aa, u8 *spa)
-{
- struct rsn_pmksa_cache *entry, *pos, *prev;
-
- if (wpa_s->proto != WPA_PROTO_RSN || pmk_len > PMK_LEN)
- return;
-
- entry = malloc(sizeof(*entry));
- if (entry == NULL)
- return;
- memset(entry, 0, sizeof(*entry));
- memcpy(entry->pmk, pmk, pmk_len);
- entry->pmk_len = pmk_len;
- rsn_pmkid(pmk, aa, spa, entry->pmkid);
- entry->expiration = time(NULL) + dot11RSNAConfigPMKLifetime;
- entry->akmp = WPA_KEY_MGMT_IEEE8021X;
- memcpy(entry->aa, aa, ETH_ALEN);
-
- /* Replace an old entry for the same Authenticator (if found) with the
- * new entry */
- pos = wpa_s->pmksa;
- prev = NULL;
- while (pos) {
- if (memcmp(aa, pos->aa, ETH_ALEN) == 0) {
- if (prev == NULL)
- wpa_s->pmksa = pos->next;
- else
- prev->next = pos->next;
- pmksa_cache_free_entry(wpa_s, pos);
- break;
- }
- prev = pos;
- pos = pos->next;
- }
-
- if (wpa_s->pmksa_count >= pmksa_cache_max_entries && wpa_s->pmksa) {
- /* Remove the oldest entry to make room for the new entry */
- pos = wpa_s->pmksa;
- wpa_s->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_drv_remove_pmkid(wpa_s, pos->aa, pos->pmkid);
- pmksa_cache_free_entry(wpa_s, pos);
- }
-
- /* Add the new entry; order by expiration time */
- pos = wpa_s->pmksa;
- prev = NULL;
- while (pos) {
- if (pos->expiration > entry->expiration)
- break;
- prev = pos;
- pos = pos->next;
- }
- if (prev == NULL) {
- entry->next = wpa_s->pmksa;
- wpa_s->pmksa = entry;
- } else {
- entry->next = prev->next;
- prev->next = entry;
- }
- wpa_s->pmksa_count++;
- wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
- MAC2STR(entry->aa));
- wpa_drv_add_pmkid(wpa_s, entry->aa, entry->pmkid);
-}
-
-
-void pmksa_cache_free(struct wpa_supplicant *wpa_s)
-{
- struct rsn_pmksa_cache *entry, *prev;
-
- entry = wpa_s->pmksa;
- wpa_s->pmksa = NULL;
- while (entry) {
- prev = entry;
- entry = entry->next;
- free(prev);
- }
- pmksa_cache_set_expiration(wpa_s);
- wpa_s->cur_pmksa = NULL;
-}
-
-
-struct rsn_pmksa_cache * pmksa_cache_get(struct wpa_supplicant *wpa_s,
- u8 *aa, u8 *pmkid)
-{
- struct rsn_pmksa_cache *entry = wpa_s->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;
-}
-
-
-int pmksa_cache_list(struct wpa_supplicant *wpa_s, 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)\n");
- i = 0;
- entry = wpa_s->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\n",
- (int) (entry->expiration - now));
- entry = entry->next;
- }
- return pos - buf;
-}
-
-
-void pmksa_candidate_free(struct wpa_supplicant *wpa_s)
-{
- struct rsn_pmksa_candidate *entry, *prev;
-
- entry = wpa_s->pmksa_candidates;
- wpa_s->pmksa_candidates = NULL;
- while (entry) {
- prev = entry;
- entry = entry->next;
- free(prev);
- }
-}
-
-
-static int wpa_parse_wpa_ie_wpa(struct wpa_supplicant *wpa_s, u8 *wpa_ie,
- size_t wpa_ie_len, struct wpa_ie_data *data)
-{
- struct wpa_ie_hdr *hdr;
- u8 *pos;
+ const struct wpa_ie_hdr *hdr;
+ const u8 *pos;
int left;
int i, count;
@@ -419,18 +284,18 @@ static int wpa_parse_wpa_ie_wpa(struct wpa_supplicant *wpa_s, u8 *wpa_ie,
return -1;
}
- hdr = (struct wpa_ie_hdr *) wpa_ie;
+ hdr = (const struct wpa_ie_hdr *) wpa_ie;
if (hdr->elem_id != GENERIC_INFO_ELEM ||
hdr->len != wpa_ie_len - 2 ||
memcmp(&hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN) != 0 ||
- le_to_host16(hdr->version) != WPA_VERSION) {
+ WPA_GET_LE16(hdr->version) != WPA_VERSION) {
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
__func__);
return -1;
}
- pos = (u8 *) (hdr + 1);
+ pos = (const u8 *) (hdr + 1);
left = wpa_ie_len - sizeof(*hdr);
if (left >= WPA_SELECTOR_LEN) {
@@ -445,7 +310,7 @@ static int wpa_parse_wpa_ie_wpa(struct wpa_supplicant *wpa_s, u8 *wpa_ie,
if (left >= 2) {
data->pairwise_cipher = 0;
- count = pos[0] | (pos[1] << 8);
+ count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * WPA_SELECTOR_LEN) {
@@ -466,7 +331,7 @@ static int wpa_parse_wpa_ie_wpa(struct wpa_supplicant *wpa_s, u8 *wpa_ie,
if (left >= 2) {
data->key_mgmt = 0;
- count = pos[0] | (pos[1] << 8);
+ count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * WPA_SELECTOR_LEN) {
@@ -486,7 +351,7 @@ static int wpa_parse_wpa_ie_wpa(struct wpa_supplicant *wpa_s, u8 *wpa_ie,
}
if (left >= 2) {
- data->capabilities = pos[0] | (pos[1] << 8);
+ data->capabilities = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
}
@@ -501,11 +366,11 @@ static int wpa_parse_wpa_ie_wpa(struct wpa_supplicant *wpa_s, u8 *wpa_ie,
}
-static int wpa_parse_wpa_ie_rsn(struct wpa_supplicant *wpa_s, u8 *rsn_ie,
- size_t rsn_ie_len, struct wpa_ie_data *data)
+static int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
+ struct wpa_ie_data *data)
{
- struct rsn_ie_hdr *hdr;
- u8 *pos;
+ const struct rsn_ie_hdr *hdr;
+ const u8 *pos;
int left;
int i, count;
@@ -528,17 +393,17 @@ static int wpa_parse_wpa_ie_rsn(struct wpa_supplicant *wpa_s, u8 *rsn_ie,
return -1;
}
- hdr = (struct rsn_ie_hdr *) rsn_ie;
+ hdr = (const struct rsn_ie_hdr *) rsn_ie;
if (hdr->elem_id != RSN_INFO_ELEM ||
hdr->len != rsn_ie_len - 2 ||
- le_to_host16(hdr->version) != RSN_VERSION) {
+ WPA_GET_LE16(hdr->version) != RSN_VERSION) {
wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
__func__);
return -1;
}
- pos = (u8 *) (hdr + 1);
+ pos = (const u8 *) (hdr + 1);
left = rsn_ie_len - sizeof(*hdr);
if (left >= RSN_SELECTOR_LEN) {
@@ -553,7 +418,7 @@ static int wpa_parse_wpa_ie_rsn(struct wpa_supplicant *wpa_s, u8 *rsn_ie,
if (left >= 2) {
data->pairwise_cipher = 0;
- count = pos[0] | (pos[1] << 8);
+ count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
@@ -574,7 +439,7 @@ static int wpa_parse_wpa_ie_rsn(struct wpa_supplicant *wpa_s, u8 *rsn_ie,
if (left >= 2) {
data->key_mgmt = 0;
- count = pos[0] | (pos[1] << 8);
+ count = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (count == 0 || left < count * RSN_SELECTOR_LEN) {
@@ -594,13 +459,13 @@ static int wpa_parse_wpa_ie_rsn(struct wpa_supplicant *wpa_s, u8 *rsn_ie,
}
if (left >= 2) {
- data->capabilities = pos[0] | (pos[1] << 8);
+ data->capabilities = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
}
if (left >= 2) {
- data->num_pmkid = pos[0] | (pos[1] << 8);
+ data->num_pmkid = WPA_GET_LE16(pos);
pos += 2;
left -= 2;
if (left < data->num_pmkid * PMKID_LEN) {
@@ -624,69 +489,84 @@ static int wpa_parse_wpa_ie_rsn(struct wpa_supplicant *wpa_s, u8 *rsn_ie,
}
-int wpa_parse_wpa_ie(struct wpa_supplicant *wpa_s, u8 *wpa_ie,
- size_t wpa_ie_len, struct wpa_ie_data *data)
+/**
+ * wpa_parse_wpa_ie - Parse WPA/RSN IE
+ * @wpa_ie: Pointer to WPA or RSN IE
+ * @wpa_ie_len: Length of the WPA/RSN IE
+ * @data: Pointer to data area for parsing results
+ * Returns: 0 on success, -1 on failure
+ *
+ * Parse the contents of WPA or RSN IE and write the parsed data into data.
+ */
+int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
+ struct wpa_ie_data *data)
{
if (wpa_ie_len >= 1 && wpa_ie[0] == RSN_INFO_ELEM)
- return wpa_parse_wpa_ie_rsn(wpa_s, wpa_ie, wpa_ie_len, data);
+ return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
else
- return wpa_parse_wpa_ie_wpa(wpa_s, wpa_ie, wpa_ie_len, data);
+ return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
}
-static int wpa_gen_wpa_ie_wpa(struct wpa_supplicant *wpa_s, u8 *wpa_ie)
+static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
+ int pairwise_cipher, int group_cipher,
+ int key_mgmt)
{
u8 *pos;
struct wpa_ie_hdr *hdr;
+ if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
+ 2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
+ return -1;
+
hdr = (struct wpa_ie_hdr *) wpa_ie;
hdr->elem_id = GENERIC_INFO_ELEM;
memcpy(&hdr->oui, WPA_OUI_TYPE, WPA_SELECTOR_LEN);
- hdr->version = host_to_le16(WPA_VERSION);
+ WPA_PUT_LE16(hdr->version, WPA_VERSION);
pos = (u8 *) (hdr + 1);
- if (wpa_s->group_cipher == WPA_CIPHER_CCMP) {
+ if (group_cipher == WPA_CIPHER_CCMP) {
memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
- } else if (wpa_s->group_cipher == WPA_CIPHER_TKIP) {
+ } else if (group_cipher == WPA_CIPHER_TKIP) {
memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
- } else if (wpa_s->group_cipher == WPA_CIPHER_WEP104) {
+ } else if (group_cipher == WPA_CIPHER_WEP104) {
memcpy(pos, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN);
- } else if (wpa_s->group_cipher == WPA_CIPHER_WEP40) {
+ } else if (group_cipher == WPA_CIPHER_WEP40) {
memcpy(pos, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
- wpa_s->group_cipher);
+ group_cipher);
return -1;
}
pos += WPA_SELECTOR_LEN;
*pos++ = 1;
*pos++ = 0;
- if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) {
+ if (pairwise_cipher == WPA_CIPHER_CCMP) {
memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
- } else if (wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
+ } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
- } else if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) {
+ } else if (pairwise_cipher == WPA_CIPHER_NONE) {
memcpy(pos, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
- wpa_s->pairwise_cipher);
+ pairwise_cipher);
return -1;
}
pos += WPA_SELECTOR_LEN;
*pos++ = 1;
*pos++ = 0;
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
+ if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
memcpy(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN);
- } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK) {
+ } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
memcpy(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X,
WPA_SELECTOR_LEN);
- } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+ } else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
memcpy(pos, WPA_AUTH_KEY_MGMT_NONE, WPA_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
- wpa_s->key_mgmt);
+ key_mgmt);
return -1;
}
pos += WPA_SELECTOR_LEN;
@@ -695,60 +575,69 @@ static int wpa_gen_wpa_ie_wpa(struct wpa_supplicant *wpa_s, u8 *wpa_ie)
hdr->len = (pos - wpa_ie) - 2;
+ WPA_ASSERT(pos - wpa_ie <= wpa_ie_len);
+
return pos - wpa_ie;
}
-static int wpa_gen_wpa_ie_rsn(struct wpa_supplicant *wpa_s, u8 *rsn_ie)
+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)
{
u8 *pos;
struct rsn_ie_hdr *hdr;
+ if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
+ 2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
+ (sm->cur_pmksa ? 2 + PMKID_LEN : 0))
+ return -1;
+
hdr = (struct rsn_ie_hdr *) rsn_ie;
hdr->elem_id = RSN_INFO_ELEM;
- hdr->version = host_to_le16(RSN_VERSION);
+ WPA_PUT_LE16(hdr->version, RSN_VERSION);
pos = (u8 *) (hdr + 1);
- if (wpa_s->group_cipher == WPA_CIPHER_CCMP) {
+ if (group_cipher == WPA_CIPHER_CCMP) {
memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
- } else if (wpa_s->group_cipher == WPA_CIPHER_TKIP) {
+ } else if (group_cipher == WPA_CIPHER_TKIP) {
memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
- } else if (wpa_s->group_cipher == WPA_CIPHER_WEP104) {
+ } else if (group_cipher == WPA_CIPHER_WEP104) {
memcpy(pos, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN);
- } else if (wpa_s->group_cipher == WPA_CIPHER_WEP40) {
+ } else if (group_cipher == WPA_CIPHER_WEP40) {
memcpy(pos, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
- wpa_s->group_cipher);
+ group_cipher);
return -1;
}
pos += RSN_SELECTOR_LEN;
*pos++ = 1;
*pos++ = 0;
- if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) {
+ if (pairwise_cipher == WPA_CIPHER_CCMP) {
memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
- } else if (wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
+ } else if (pairwise_cipher == WPA_CIPHER_TKIP) {
memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
- } else if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) {
+ } else if (pairwise_cipher == WPA_CIPHER_NONE) {
memcpy(pos, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
- wpa_s->pairwise_cipher);
+ pairwise_cipher);
return -1;
}
pos += RSN_SELECTOR_LEN;
*pos++ = 1;
*pos++ = 0;
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
+ if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
memcpy(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN);
- } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK) {
+ } else if (key_mgmt == WPA_KEY_MGMT_PSK) {
memcpy(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X,
RSN_SELECTOR_LEN);
} else {
wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
- wpa_s->key_mgmt);
+ key_mgmt);
return -1;
}
pos += RSN_SELECTOR_LEN;
@@ -757,39 +646,67 @@ static int wpa_gen_wpa_ie_rsn(struct wpa_supplicant *wpa_s, u8 *rsn_ie)
*pos++ = 0;
*pos++ = 0;
- if (wpa_s->cur_pmksa) {
+ if (sm->cur_pmksa) {
/* PMKID Count (2 octets, little endian) */
*pos++ = 1;
*pos++ = 0;
/* PMKID */
- memcpy(pos, wpa_s->cur_pmksa->pmkid, PMKID_LEN);
+ memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
pos += PMKID_LEN;
}
hdr->len = (pos - rsn_ie) - 2;
+ WPA_ASSERT(pos - rsn_ie <= rsn_ie_len);
+
return pos - rsn_ie;
}
-int wpa_gen_wpa_ie(struct wpa_supplicant *wpa_s, u8 *wpa_ie)
+/**
+ * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
+ * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
+ * Returns: Length of the generated WPA/RSN IE or -1 on failure
+ */
+static int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
{
- if (wpa_s->proto == WPA_PROTO_RSN)
- return wpa_gen_wpa_ie_rsn(wpa_s, wpa_ie);
+ if (sm->proto == WPA_PROTO_RSN)
+ return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
+ sm->pairwise_cipher,
+ sm->group_cipher,
+ sm->key_mgmt, sm);
else
- return wpa_gen_wpa_ie_wpa(wpa_s, wpa_ie);
+ return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
+ sm->pairwise_cipher,
+ sm->group_cipher,
+ sm->key_mgmt);
}
-static void wpa_pmk_to_ptk(u8 *pmk, size_t pmk_len, u8 *addr1, u8 *addr2,
- u8 *nonce1, u8 *nonce2, u8 *ptk, size_t ptk_len)
+/**
+ * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
+ * @pmk: Pairwise master key
+ * @addr1: AA or SA
+ * @addr2: SA or AA
+ * @nonce1: ANonce or SNonce
+ * @nonce2: SNonce or ANonce
+ * @ptk: Buffer for pairwise transient key
+ * @ptk_len: Length of PTK
+ *
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ * PTK = PRF-X(PMK, "Pairwise key expansion",
+ * Min(AA, SA) || Max(AA, SA) ||
+ * Min(ANonce, SNonce) || Max(ANonce, SNonce))
+ */
+static void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len,
+ 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];
- /* PTK = PRF-X(PMK, "Pairwise key expansion",
- * Min(AA, SA) || Max(AA, SA) ||
- * Min(ANonce, SNonce) || Max(ANonce, SNonce)) */
-
if (memcmp(addr1, addr2, ETH_ALEN) < 0) {
memcpy(data, addr1, ETH_ALEN);
memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
@@ -814,39 +731,25 @@ static void wpa_pmk_to_ptk(u8 *pmk, size_t pmk_len, u8 *addr1, u8 *addr2,
}
-struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
-{
- struct wpa_ssid *entry;
- u8 ssid[MAX_SSID_LEN];
- int ssid_len;
- u8 bssid[ETH_ALEN];
-
- 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_drv_get_bssid(wpa_s, bssid) < 0) {
- wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
- return NULL;
- }
-
- entry = wpa_s->conf->ssid;
- while (entry) {
- if (ssid_len == entry->ssid_len &&
- memcmp(ssid, entry->ssid, ssid_len) == 0 &&
- (!entry->bssid_set ||
- memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
- return entry;
- entry = entry->next;
- }
-
- return NULL;
-}
-
-
-static void wpa_eapol_key_mic(u8 *key, int ver, u8 *buf, size_t len, u8 *mic)
+/**
+ * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
+ * @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
+ * @buf: Pointer to the beginning of the EAPOL header (version field)
+ * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
+ * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
+ *
+ * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
+ * to be cleared (all zeroes) when calling this function.
+ *
+ * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
+ * description of the Key MIC calculation. It includes packet data from the
+ * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
+ * happened during final editing of the standard and the correct behavior is
+ * defined in the last draft (IEEE 802.11i/D10).
+ */
+static void wpa_eapol_key_mic(const u8 *key, int ver,
+ const u8 *buf, size_t len, u8 *mic)
{
if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
hmac_md5(key, 16, buf, len, mic);
@@ -858,200 +761,185 @@ static void wpa_eapol_key_mic(u8 *key, int ver, u8 *buf, size_t len, u8 *mic)
}
-void wpa_supplicant_key_request(struct wpa_supplicant *wpa_s,
- int error, int pairwise)
+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)
{
- int rlen;
- struct ieee802_1x_hdr *hdr;
+ 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);
+}
+
+
+/**
+ * wpa_sm_key_request - Send EAPOL-Key Request
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @error: Indicate whether this is an Michael MIC error report
+ * @pairwise: 1 = error report for pairwise packet, 0 = for group packet
+ * Returns: Pointer to the current network structure or %NULL on failure
+ *
+ * Send an EAPOL-Key Request to the current authenticator. This function is
+ * used to request rekeying and it is usually called when a local Michael MIC
+ * failure is detected.
+ */
+void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
+{
+ size_t rlen;
struct wpa_eapol_key *reply;
- unsigned char *rbuf;
- struct l2_ethhdr *ethhdr;
int key_info, ver;
- u8 bssid[ETH_ALEN];
+ u8 bssid[ETH_ALEN], *rbuf;
- if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP)
+ 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_drv_get_bssid(wpa_s, bssid) < 0) {
+ if (wpa_sm_get_bssid(sm, bssid) < 0) {
wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
"request");
return;
}
- rlen = sizeof(*ethhdr) + sizeof(*hdr) + sizeof(*reply);
- rbuf = malloc(rlen);
+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+ sizeof(*reply), &rlen, (void *) &reply);
if (rbuf == NULL)
return;
- memset(rbuf, 0, rlen);
- ethhdr = (struct l2_ethhdr *) rbuf;
- memcpy(ethhdr->h_dest, bssid, ETH_ALEN);
- memcpy(ethhdr->h_source, wpa_s->own_addr, ETH_ALEN);
- ethhdr->h_proto = htons(ETH_P_EAPOL);
-
- hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
- hdr->version = wpa_s->conf->eapol_version;
- hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
- hdr->length = htons(sizeof(*reply));
-
- reply = (struct wpa_eapol_key *) (hdr + 1);
- reply->type = wpa_s->proto == WPA_PROTO_RSN ?
+ reply->type = sm->proto == WPA_PROTO_RSN ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
key_info = WPA_KEY_INFO_REQUEST | ver;
- if (wpa_s->ptk_set)
+ if (sm->ptk_set)
key_info |= WPA_KEY_INFO_MIC;
if (error)
key_info |= WPA_KEY_INFO_ERROR;
if (pairwise)
key_info |= WPA_KEY_INFO_KEY_TYPE;
- reply->key_info = host_to_be16(key_info);
- reply->key_length = 0;
- memcpy(reply->replay_counter, wpa_s->request_counter,
+ 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);
- inc_byte_array(wpa_s->request_counter, WPA_REPLAY_COUNTER_LEN);
+ inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
- reply->key_data_length = host_to_be16(0);
-
- if (key_info & WPA_KEY_INFO_MIC) {
- wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, (u8 *) hdr,
- rlen - sizeof(*ethhdr), reply->key_mic);
- }
+ WPA_PUT_BE16(reply->key_data_length, 0);
wpa_printf(MSG_INFO, "WPA: Sending EAPOL-Key Request (error=%d "
- "pairwise=%d ptk_set=%d len=%d)",
- error, pairwise, wpa_s->ptk_set, rlen);
- wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key Request", rbuf, rlen);
- l2_packet_send(wpa_s->l2, rbuf, rlen);
- eapol_sm_notify_tx_eapol_key(wpa_s->eapol);
- free(rbuf);
+ "pairwise=%d ptk_set=%d len=%lu)",
+ error, pairwise, sm->ptk_set, (unsigned long) rlen);
+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
+ rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
+ reply->key_mic : NULL);
}
-static void wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
- unsigned char *src_addr,
- struct wpa_eapol_key *key, int ver)
-{
- int rlen;
- struct ieee802_1x_hdr *hdr;
- struct wpa_eapol_key *reply;
- unsigned char *rbuf;
- struct l2_ethhdr *ethhdr;
- struct wpa_ssid *ssid;
- struct wpa_ptk *ptk;
- u8 buf[8], wpa_ie_buf[80], *wpa_ie, *pmkid = NULL;
- int wpa_ie_len;
- int abort_cached = 0;
+struct wpa_eapol_ie_parse {
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+ const u8 *rsn_ie;
+ size_t rsn_ie_len;
+ const u8 *pmkid;
+ const u8 *gtk;
+ size_t gtk_len;
+};
- wpa_s->wpa_state = WPA_4WAY_HANDSHAKE;
- wpa_printf(MSG_DEBUG, "WPA: RX message 1 of 4-Way Handshake from "
- MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
- ssid = wpa_supplicant_get_ssid(wpa_s);
- if (ssid == NULL) {
- wpa_printf(MSG_WARNING, "WPA: No SSID info found (msg 1 of "
- "4).");
- return;
+/**
+ * wpa_supplicant_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_supplicant_parse_generic(const u8 *pos, const u8 *end,
+ struct wpa_eapol_ie_parse *ie)
+{
+ if (pos[1] == 0)
+ return 1;
+
+ if (pos[1] >= 6 &&
+ 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;
+ ie->wpa_ie_len = pos[1] + 2;
+ return 0;
}
- if (wpa_s->proto == WPA_PROTO_RSN) {
- /* RSN: msg 1/4 should contain PMKID for the selected PMK */
- u8 *pos = (u8 *) (key + 1);
- u8 *end = pos + be_to_host16(key->key_data_length);
- wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data",
- pos, be_to_host16(key->key_data_length));
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end) {
- wpa_printf(MSG_DEBUG, "RSN: key data "
- "underflow (ie=%d len=%d)",
- pos[0], pos[1]);
- break;
- }
- if (pos[0] == GENERIC_INFO_ELEM &&
- pos + 1 + RSN_SELECTOR_LEN < end &&
- pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
- memcmp(pos + 2, RSN_KEY_DATA_PMKID,
- RSN_SELECTOR_LEN) == 0) {
- pmkid = pos + 2 + RSN_SELECTOR_LEN;
- wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
- "Authenticator", pmkid, PMKID_LEN);
- break;
- } else if (pos[0] == GENERIC_INFO_ELEM &&
- pos[1] == 0)
- break;
- pos += 2 + pos[1];
- }
+ 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) {
+ ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+ return 0;
}
- if (wpa_s->assoc_wpa_ie) {
- /* The driver reported a WPA IE that may be different from the
- * one that the Supplicant would use. Message 2/4 has to use
- * the exact copy of the WPA IE from the Association Request,
- * so use the value reported by the driver. */
- wpa_ie = wpa_s->assoc_wpa_ie;
- wpa_ie_len = wpa_s->assoc_wpa_ie_len;
- } else {
- wpa_ie = wpa_ie_buf;
- wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie);
- if (wpa_ie_len < 0) {
- wpa_printf(MSG_WARNING, "WPA: Failed to generate "
- "WPA IE (for msg 2 of 4).");
- return;
- }
- wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4",
- wpa_ie, wpa_ie_len);
+ if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+ 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;
}
- rlen = sizeof(*ethhdr) + sizeof(*hdr) + sizeof(*reply) + wpa_ie_len;
- rbuf = malloc(rlen);
- if (rbuf == NULL)
- return;
-
- memset(rbuf, 0, rlen);
- ethhdr = (struct l2_ethhdr *) rbuf;
- memcpy(ethhdr->h_dest, src_addr, ETH_ALEN);
- memcpy(ethhdr->h_source, wpa_s->own_addr, ETH_ALEN);
- ethhdr->h_proto = htons(ETH_P_EAPOL);
-
- hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
- hdr->version = wpa_s->conf->eapol_version;
- hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
- hdr->length = htons(sizeof(*reply) + wpa_ie_len);
+ return 0;
+}
- reply = (struct wpa_eapol_key *) (hdr + 1);
- reply->type = wpa_s->proto == WPA_PROTO_RSN ?
- EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
- reply->key_info = host_to_be16(ver | WPA_KEY_INFO_KEY_TYPE |
- WPA_KEY_INFO_MIC);
- reply->key_length = key->key_length;
- memcpy(reply->replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
- reply->key_data_length = host_to_be16(wpa_ie_len);
- memcpy(reply + 1, wpa_ie, wpa_ie_len);
+/**
+ * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+ struct wpa_eapol_ie_parse *ie)
+{
+ const u8 *pos, *end;
+ int ret = 0;
- if (wpa_s->renew_snonce) {
- if (hostapd_get_rand(wpa_s->snonce, WPA_NONCE_LEN)) {
- wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to get "
- "random data for SNonce");
- free(rbuf);
- return;
+ memset(ie, 0, sizeof(*ie));
+ for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+ if (pos + 2 + pos[1] > end) {
+ wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
+ "underflow (ie=%d len=%d)", pos[0], pos[1]);
+ ret = -1;
+ break;
+ }
+ if (*pos == RSN_INFO_ELEM) {
+ ie->rsn_ie = pos;
+ ie->rsn_ie_len = pos[1] + 2;
+ } else if (*pos == GENERIC_INFO_ELEM) {
+ ret = wpa_supplicant_parse_generic(pos, end, ie);
+ if (ret < 0)
+ break;
+ if (ret > 0) {
+ ret = 0;
+ break;
+ }
+ } else {
+ wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
+ "Key Data IE", pos, 2 + pos[1]);
}
- wpa_s->renew_snonce = 0;
- wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
- wpa_s->snonce, WPA_NONCE_LEN);
}
- memcpy(reply->key_nonce, wpa_s->snonce, WPA_NONCE_LEN);
- ptk = &wpa_s->tptk;
- memcpy(wpa_s->anonce, key->key_nonce, WPA_NONCE_LEN);
- if (pmkid && !wpa_s->cur_pmksa) {
+
+ return ret;
+}
+
+
+static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
+ const unsigned char *src_addr,
+ const u8 *pmkid)
+{
+ int abort_cached = 0;
+
+ if (pmkid && !sm->cur_pmksa) {
/* When using drivers that generate RSN IE, wpa_supplicant may
* 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. */
- wpa_s->cur_pmksa = pmksa_cache_get(wpa_s, src_addr, pmkid);
- if (wpa_s->cur_pmksa) {
+ sm->cur_pmksa = pmksa_cache_get(sm, src_addr, pmkid);
+ if (sm->cur_pmksa) {
wpa_printf(MSG_DEBUG, "RSN: found matching PMKID from "
"PMKSA cache");
} else {
@@ -1060,125 +948,241 @@ static void wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
}
}
- if (pmkid && wpa_s->cur_pmksa &&
- memcmp(pmkid, wpa_s->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+ if (pmkid && sm->cur_pmksa &&
+ memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
- memcpy(wpa_s->pmk, wpa_s->cur_pmksa->pmk, PMK_LEN);
+ wpa_sm_set_pmk_from_pmksa(sm);
wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
- wpa_s->pmk, PMK_LEN);
- eapol_sm_notify_cached(wpa_s->eapol);
- } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X && wpa_s->eapol) {
+ sm->pmk, sm->pmk_len);
+ eapol_sm_notify_cached(sm->eapol);
+ } else if (sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X && sm->eapol) {
int res, pmk_len;
pmk_len = PMK_LEN;
- res = eapol_sm_get_key(wpa_s->eapol, wpa_s->pmk, PMK_LEN);
+ res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
#ifdef EAP_LEAP
if (res) {
- res = eapol_sm_get_key(wpa_s->eapol, wpa_s->pmk, 16);
+ 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", wpa_s->pmk, pmk_len);
- wpa_s->pmk_len = pmk_len;
- pmksa_cache_add(wpa_s, wpa_s->pmk, pmk_len, src_addr,
- wpa_s->own_addr);
- if (!wpa_s->cur_pmksa && pmkid &&
- pmksa_cache_get(wpa_s, src_addr, pmkid)) {
+ "machines", sm->pmk, pmk_len);
+ sm->pmk_len = pmk_len;
+ pmksa_cache_add(sm, sm->pmk, pmk_len, src_addr,
+ sm->own_addr, sm->cur_ssid);
+ if (!sm->cur_pmksa && pmkid &&
+ pmksa_cache_get(sm, src_addr, pmkid)) {
wpa_printf(MSG_DEBUG, "RSN: the new PMK "
"matches with the PMKID");
abort_cached = 0;
}
} else {
- wpa_msg(wpa_s, MSG_WARNING,
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
"WPA: Failed to get master session key from "
"EAPOL state machines");
- wpa_msg(wpa_s, MSG_WARNING,
+ wpa_msg(sm->ctx->ctx, MSG_WARNING,
"WPA: Key handshake aborted");
- if (wpa_s->cur_pmksa) {
+ if (sm->cur_pmksa) {
wpa_printf(MSG_DEBUG, "RSN: Cancelled PMKSA "
"caching attempt");
- wpa_s->cur_pmksa = NULL;
+ sm->cur_pmksa = NULL;
abort_cached = 1;
} else {
- free(rbuf);
- return;
+ return -1;
}
}
-#ifdef CONFIG_XSUPPLICANT_IFACE
- } else if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X &&
- !wpa_s->ext_pmk_received) {
- wpa_printf(MSG_INFO, "WPA: Master session has not yet "
- "been received from the external IEEE "
- "802.1X Supplicant - ignoring WPA "
- "EAPOL-Key frame");
- free(rbuf);
- return;
-#endif /* CONFIG_XSUPPLICANT_IFACE */
}
- if (abort_cached && wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
+ if (abort_cached && sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
/* Send EAPOL-Start to trigger full EAP authentication. */
+ u8 *buf;
+ size_t buflen;
+
wpa_printf(MSG_DEBUG, "RSN: no PMKSA entry found - trigger "
- "full EAP authenication");
- wpa_eapol_send(wpa_s, IEEE802_1X_TYPE_EAPOL_START,
- (u8 *) "", 0);
- free(rbuf);
- return;
+ "full EAP authentication");
+ buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START,
+ NULL, 0, &buflen, NULL);
+ if (buf) {
+ wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL,
+ buf, buflen);
+ free(buf);
+ }
+
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_send_2_of_4(struct wpa_sm *sm,
+ const unsigned char *src_addr,
+ const struct wpa_eapol_key *key,
+ int ver)
+{
+ size_t rlen;
+ struct wpa_eapol_key *reply;
+ struct wpa_ptk *ptk;
+ u8 buf[8], *rbuf, *wpa_ie;
+ int wpa_ie_len;
+
+ if (sm->assoc_wpa_ie == NULL) {
+ wpa_printf(MSG_WARNING, "WPA: No assoc_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,
+ NULL, sizeof(*reply) + wpa_ie_len,
+ &rlen, (void *) &reply);
+ if (rbuf == NULL)
+ return -1;
+
+ reply->type = sm->proto == WPA_PROTO_RSN ?
+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+ WPA_PUT_BE16(reply->key_info,
+ ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
+ 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);
+
+ WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
+ 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);
- wpa_pmk_to_ptk(wpa_s->pmk, wpa_s->pmk_len, wpa_s->own_addr, src_addr,
- wpa_s->snonce, key->key_nonce,
+ /* 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);
- wpa_s->tptk_set = 1;
- wpa_eapol_key_mic(wpa_s->tptk.mic_key, ver, (u8 *) hdr,
- rlen - sizeof(*ethhdr), reply->key_mic);
- wpa_hexdump(MSG_DEBUG, "WPA: EAPOL-Key MIC", reply->key_mic, 16);
+ sm->tptk_set = 1;
wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
- wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key 2/4", rbuf, rlen);
- l2_packet_send(wpa_s->l2, rbuf, rlen);
- eapol_sm_notify_tx_eapol_key(wpa_s->eapol);
- free(rbuf);
+ wpa_eapol_key_send(sm, ptk->kck, ver, src_addr, ETH_P_EAPOL,
+ rbuf, rlen, reply->key_mic);
+
+ return 0;
+}
+
+
+static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
+ const unsigned char *src_addr,
+ const struct wpa_eapol_key *key,
+ u16 ver)
+{
+ struct wpa_eapol_ie_parse ie;
+
+ if (wpa_sm_get_ssid(sm) == NULL) {
+ wpa_printf(MSG_WARNING, "WPA: No SSID info found (msg 1 of "
+ "4).");
+ return;
+ }
+
+ wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
+ 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));
+
+ if (sm->proto == WPA_PROTO_RSN) {
+ /* RSN: msg 1/4 should contain PMKID for the selected PMK */
+ 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);
+ if (ie.pmkid) {
+ wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
+ "Authenticator", ie.pmkid, PMKID_LEN);
+ }
+ }
+
+ if (wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid))
+ return;
+
+ if (wpa_supplicant_send_2_of_4(sm, src_addr, key, ver))
+ return;
+
+ memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
}
-static void wpa_supplicant_key_neg_complete(struct wpa_supplicant *wpa_s,
- u8 *addr, int secure)
+static void wpa_sm_start_preauth(void *eloop_ctx, void *timeout_ctx)
{
- wpa_msg(wpa_s, MSG_INFO, "WPA: Key negotiation completed with "
+ struct wpa_sm *sm = eloop_ctx;
+ rsn_preauth_candidate_process(sm);
+}
+
+
+static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
+ const u8 *addr, int secure)
+{
+ wpa_msg(sm->ctx->ctx, MSG_INFO, "WPA: Key negotiation completed with "
MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr),
- wpa_cipher_txt(wpa_s->pairwise_cipher),
- wpa_cipher_txt(wpa_s->group_cipher));
- eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
- wpa_supplicant_cancel_auth_timeout(wpa_s);
- wpa_s->wpa_state = WPA_COMPLETED;
+ wpa_cipher_txt(sm->pairwise_cipher),
+ wpa_cipher_txt(sm->group_cipher));
+ eloop_cancel_timeout(sm->ctx->scan, sm->ctx->ctx, NULL);
+ wpa_sm_cancel_auth_timeout(sm);
+ wpa_sm_set_state(sm, WPA_COMPLETED);
if (secure) {
/* MLME.SETPROTECTION.request(TA, Tx_Rx) */
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK)
- eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
- rsn_preauth_candidate_process(wpa_s);
+ eapol_sm_notify_portValid(sm->eapol, TRUE);
+ if (sm->key_mgmt == WPA_KEY_MGMT_PSK)
+ eapol_sm_notify_eap_success(sm->eapol, TRUE);
+ /*
+ * Start preauthentication after a short wait to avoid a
+ * possible race condition between the data receive and key
+ * configuration after the 4-Way Handshake. This increases the
+ * likelyhood of the first preauth EAPOL-Start frame getting to
+ * the target AP.
+ */
+ eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
+ }
+
+ if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
+ wpa_printf(MSG_DEBUG, "RSN: Authenticator accepted "
+ "opportunistic PMKSA entry - marking it valid");
+ sm->cur_pmksa->opportunistic = 0;
}
}
-static int wpa_supplicant_install_ptk(struct wpa_supplicant *wpa_s,
- unsigned char *src_addr,
- struct wpa_eapol_key *key)
+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;
- u8 *key_rsc;
+ const u8 *key_rsc;
u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.");
- switch (wpa_s->pairwise_cipher) {
+ switch (sm->pairwise_cipher) {
case WPA_CIPHER_CCMP:
alg = WPA_ALG_CCMP;
keylen = 16;
@@ -1195,20 +1199,19 @@ static int wpa_supplicant_install_ptk(struct wpa_supplicant *wpa_s,
return 0;
default:
wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise cipher %d",
- wpa_s->pairwise_cipher);
+ sm->pairwise_cipher);
return -1;
}
- if (wpa_s->proto == WPA_PROTO_RSN) {
+ if (sm->proto == WPA_PROTO_RSN) {
key_rsc = null_rsc;
} else {
key_rsc = key->key_rsc;
wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
}
- wpa_s->keys_cleared = 0;
- if (wpa_drv_set_key(wpa_s, alg, src_addr, 0, 1, key_rsc, rsclen,
- (u8 *) &wpa_s->ptk.tk1, keylen) < 0) {
+ if (wpa_sm_set_key(sm, alg, src_addr, 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;
@@ -1217,91 +1220,99 @@ static int wpa_supplicant_install_ptk(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_check_group_cipher(struct wpa_supplicant *wpa_s,
+static int wpa_supplicant_check_group_cipher(int group_cipher,
int keylen, int maxkeylen,
int *key_rsc_len, int *alg)
{
- switch (wpa_s->group_cipher) {
+ int ret = 0;
+
+ switch (group_cipher) {
case WPA_CIPHER_CCMP:
if (keylen != 16 || maxkeylen < 16) {
- wpa_printf(MSG_WARNING, "WPA: Unsupported CCMP Group "
- "Cipher key length %d (%d).",
- keylen, maxkeylen);
- return -1;
+ ret = -1;
+ break;
}
*key_rsc_len = 6;
*alg = WPA_ALG_CCMP;
break;
case WPA_CIPHER_TKIP:
if (keylen != 32 || maxkeylen < 32) {
- wpa_printf(MSG_WARNING, "WPA: Unsupported TKIP Group "
- "Cipher key length %d (%d).",
- keylen, maxkeylen);
- return -1;
+ ret = -1;
+ break;
}
*key_rsc_len = 6;
*alg = WPA_ALG_TKIP;
break;
case WPA_CIPHER_WEP104:
if (keylen != 13 || maxkeylen < 13) {
- wpa_printf(MSG_WARNING, "WPA: Unsupported WEP104 Group"
- " Cipher key length %d (%d).",
- keylen, maxkeylen);
- return -1;
+ ret = -1;
+ break;
}
*key_rsc_len = 0;
*alg = WPA_ALG_WEP;
break;
case WPA_CIPHER_WEP40:
if (keylen != 5 || maxkeylen < 5) {
- wpa_printf(MSG_WARNING, "WPA: Unsupported WEP40 Group "
- "Cipher key length %d (%d).",
- keylen, maxkeylen);
- return -1;
+ ret = -1;
+ break;
}
*key_rsc_len = 0;
*alg = WPA_ALG_WEP;
break;
default:
- wpa_printf(MSG_WARNING, "WPA: Unsupport Group Cipher %d",
- wpa_s->group_cipher);
+ wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d",
+ group_cipher);
return -1;
}
- return 0;
+ if (ret < 0 ) {
+ wpa_printf(MSG_WARNING, "WPA: Unsupported %s Group Cipher key "
+ "length %d (%d).",
+ wpa_cipher_txt(group_cipher), keylen, maxkeylen);
+ }
+
+ return ret;
}
-static int wpa_supplicant_install_gtk(struct wpa_supplicant *wpa_s,
- struct wpa_eapol_key *key, int alg,
- u8 *gtk, int gtk_len, int keyidx,
- int key_rsc_len, int tx)
+struct wpa_gtk_data {
+ int alg, tx, key_rsc_len, keyidx;
+ u8 gtk[32];
+ int gtk_len;
+};
+
+
+static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
+ const struct wpa_gtk_data *gd,
+ const u8 *key_rsc)
{
- wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gtk, gtk_len);
+ const u8 *_gtk = gd->gtk;
+ u8 gtk_buf[32];
+
+ wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver "
- "(keyidx=%d tx=%d).", keyidx, tx);
- wpa_hexdump(MSG_DEBUG, "WPA: RSC", key->key_rsc, key_rsc_len);
- if (wpa_s->group_cipher == WPA_CIPHER_TKIP) {
+ "(keyidx=%d tx=%d).", gd->keyidx, gd->tx);
+ 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 */
- u8 tmpbuf[8];
- memcpy(tmpbuf, gtk + 16, 8);
- memcpy(gtk + 16, gtk + 24, 8);
- memcpy(gtk + 24, tmpbuf, 8);
- }
- wpa_s->keys_cleared = 0;
- if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) {
- if (wpa_drv_set_key(wpa_s, alg,
- (u8 *) "\xff\xff\xff\xff\xff\xff",
- keyidx, 1, key->key_rsc, key_rsc_len,
- gtk, gtk_len) < 0) {
+ memcpy(gtk_buf, gd->gtk, 16);
+ memcpy(gtk_buf + 16, gd->gtk + 24, 8);
+ memcpy(gtk_buf + 24, gd->gtk + 16, 8);
+ _gtk = gtk_buf;
+ }
+ if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
+ if (wpa_sm_set_key(sm, gd->alg,
+ (u8 *) "\xff\xff\xff\xff\xff\xff",
+ gd->keyidx, 1, key_rsc, gd->key_rsc_len,
+ _gtk, gd->gtk_len) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set "
"GTK to the driver (Group only).");
return -1;
}
- } else if (wpa_drv_set_key(wpa_s, alg,
- (u8 *) "\xff\xff\xff\xff\xff\xff",
- keyidx, tx, key->key_rsc, key_rsc_len,
- gtk, gtk_len) < 0) {
+ } else if (wpa_sm_set_key(sm, gd->alg,
+ (u8 *) "\xff\xff\xff\xff\xff\xff",
+ gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
+ _gtk, gd->gtk_len) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to "
"the driver.");
return -1;
@@ -1311,61 +1322,83 @@ static int wpa_supplicant_install_gtk(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_pairwise_gtk(struct wpa_supplicant *wpa_s,
- unsigned char *src_addr,
- struct wpa_eapol_key *key,
- u8 *gtk, int gtk_len, int key_info)
+static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
+ int tx)
{
- int keyidx, tx, key_rsc_len = 0, alg;
-
- wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake",
- gtk, gtk_len);
-
- keyidx = gtk[0] & 0x3;
- tx = !!(gtk[0] & BIT(2));
- if (tx && wpa_s->pairwise_cipher != WPA_CIPHER_NONE) {
- /* Ignore Tx bit in GTK IE if a pairwise key is used. One AP
+ if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) {
+ /* Ignore Tx bit for GTK if a pairwise key is used. One AP
* seemed to set this bit (incorrectly, since Tx is only when
* doing Group Key only APs) and without this workaround, the
* data connection does not work because wpa_supplicant
* configured non-zero keyidx to be used for unicast. */
- wpa_printf(MSG_INFO, "RSN: Tx bit set for GTK IE, but "
- "pairwise keys are used - ignore Tx bit");
- tx = 0;
+ wpa_printf(MSG_INFO, "WPA: Tx bit set for GTK, but pairwise "
+ "keys are used - ignore Tx bit");
+ return 0;
}
+ return tx;
+}
+
+
+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,
+ int key_info)
+{
+ struct wpa_gtk_data gd;
+
+ /*
+ * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x
+ * GTK KDE format:
+ * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7]
+ * Reserved [bits 0-7]
+ * GTK
+ */
+
+ memset(&gd, 0, sizeof(gd));
+ wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake",
+ gtk, gtk_len);
+
+ if (gtk_len < 2 || gtk_len - 2 > sizeof(gd.gtk))
+ return -1;
+
+ gd.keyidx = gtk[0] & 0x3;
+ gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
+ !!(gtk[0] & BIT(2)));
gtk += 2;
gtk_len -= 2;
- if (wpa_supplicant_check_group_cipher(wpa_s, gtk_len, gtk_len,
- &key_rsc_len, &alg)) {
- return -1;
- }
+ memcpy(gd.gtk, gtk, gtk_len);
+ gd.gtk_len = gtk_len;
- if (wpa_supplicant_install_gtk(wpa_s, key, alg, gtk, gtk_len, keyidx,
- key_rsc_len, tx)) {
+ if (wpa_supplicant_check_group_cipher(sm->group_cipher,
+ gtk_len, gtk_len,
+ &gd.key_rsc_len, &gd.alg) ||
+ wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) {
+ wpa_printf(MSG_DEBUG, "RSN: Failed to install GTK");
return -1;
}
- wpa_supplicant_key_neg_complete(wpa_s, src_addr,
+ wpa_supplicant_key_neg_complete(sm, src_addr,
key_info & WPA_KEY_INFO_SECURE);
return 0;
}
-static void wpa_report_ie_mismatch(struct wpa_supplicant *wpa_s,
+static void wpa_report_ie_mismatch(struct wpa_sm *sm,
const char *reason, const u8 *src_addr,
const u8 *wpa_ie, size_t wpa_ie_len,
const u8 *rsn_ie, size_t rsn_ie_len)
{
- wpa_msg(wpa_s, MSG_WARNING, "WPA: %s (src=" MACSTR ")",
+ wpa_msg(sm->ctx->ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")",
reason, MAC2STR(src_addr));
- if (wpa_s->ap_wpa_ie) {
+ if (sm->ap_wpa_ie) {
wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp",
- wpa_s->ap_wpa_ie, wpa_s->ap_wpa_ie_len);
+ sm->ap_wpa_ie, sm->ap_wpa_ie_len);
}
if (wpa_ie) {
- if (!wpa_s->ap_wpa_ie) {
+ if (!sm->ap_wpa_ie) {
wpa_printf(MSG_INFO, "WPA: No WPA IE in "
"Beacon/ProbeResp");
}
@@ -1373,12 +1406,12 @@ static void wpa_report_ie_mismatch(struct wpa_supplicant *wpa_s,
wpa_ie, wpa_ie_len);
}
- if (wpa_s->ap_rsn_ie) {
+ if (sm->ap_rsn_ie) {
wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp",
- wpa_s->ap_rsn_ie, wpa_s->ap_rsn_ie_len);
+ sm->ap_rsn_ie, sm->ap_rsn_ie_len);
}
if (rsn_ie) {
- if (!wpa_s->ap_rsn_ie) {
+ if (!sm->ap_rsn_ie) {
wpa_printf(MSG_INFO, "WPA: No RSN IE in "
"Beacon/ProbeResp");
}
@@ -1386,73 +1419,21 @@ static void wpa_report_ie_mismatch(struct wpa_supplicant *wpa_s,
rsn_ie, rsn_ie_len);
}
- wpa_supplicant_disassociate(wpa_s, REASON_IE_IN_4WAY_DIFFERS);
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ wpa_sm_disassociate(sm, REASON_IE_IN_4WAY_DIFFERS);
+ wpa_sm_req_scan(sm, 0, 0);
}
-static void wpa_supplicant_process_3_of_4(struct wpa_supplicant *wpa_s,
- unsigned char *src_addr,
- struct wpa_eapol_key *key,
- int extra_len, int ver)
+static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
+ const unsigned char *src_addr,
+ struct wpa_eapol_ie_parse *ie)
{
- int rlen;
- struct ieee802_1x_hdr *hdr;
- struct wpa_eapol_key *reply;
- unsigned char *rbuf;
- struct l2_ethhdr *ethhdr;
- int key_info, wpa_ie_len = 0, rsn_ie_len = 0, keylen, gtk_len = 0;
- u8 *wpa_ie = NULL, *rsn_ie = NULL, *gtk = NULL;
- u8 *pos, *end;
- u16 len;
- struct wpa_ssid *ssid = wpa_s->current_ssid;
-
- wpa_s->wpa_state = WPA_4WAY_HANDSHAKE;
- wpa_printf(MSG_DEBUG, "WPA: RX message 3 of 4-Way Handshake from "
- MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
-
- key_info = be_to_host16(key->key_info);
+ struct wpa_ssid *ssid = sm->cur_ssid;
- pos = (u8 *) (key + 1);
- len = be_to_host16(key->key_data_length);
- end = pos + len;
- wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end) {
- wpa_printf(MSG_DEBUG, "WPA: key data underflow (ie=%d "
- "len=%d)", pos[0], pos[1]);
- break;
- }
- if (*pos == RSN_INFO_ELEM) {
- rsn_ie = pos;
- rsn_ie_len = pos[1] + 2;
- } else if (*pos == GENERIC_INFO_ELEM && pos[1] >= 6 &&
- memcmp(pos + 2, WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0
- && pos[2 + WPA_SELECTOR_LEN] == 1 &&
- pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
- wpa_ie = pos;
- wpa_ie_len = pos[1] + 2;
- } else if (pos[0] == GENERIC_INFO_ELEM &&
- pos[1] > RSN_SELECTOR_LEN + 2 &&
- memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY,
- RSN_SELECTOR_LEN) == 0) {
- if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
- wpa_printf(MSG_WARNING, "WPA: GTK IE in "
- "unencrypted key data");
- return;
- }
- gtk = pos + 2 + RSN_SELECTOR_LEN;
- gtk_len = pos[1] - RSN_SELECTOR_LEN;
- } else if (pos[0] == GENERIC_INFO_ELEM && pos[1] == 0)
- break;
-
- pos += 2 + pos[1];
- }
-
- if (wpa_s->ap_wpa_ie == NULL && wpa_s->ap_rsn_ie == NULL) {
+ if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) {
wpa_printf(MSG_DEBUG, "WPA: No WPA/RSN IE for this AP known. "
"Trying to get from scan results");
- if (wpa_supplicant_get_beacon_ie(wpa_s) < 0) {
+ if (wpa_sm_get_beacon_ie(sm) < 0) {
wpa_printf(MSG_WARNING, "WPA: Could not find AP from "
"the scan results");
} else {
@@ -1461,40 +1442,107 @@ static void wpa_supplicant_process_3_of_4(struct wpa_supplicant *wpa_s,
}
}
- if ((wpa_ie && wpa_s->ap_wpa_ie &&
- (wpa_ie_len != wpa_s->ap_wpa_ie_len ||
- memcmp(wpa_ie, wpa_s->ap_wpa_ie, wpa_ie_len) != 0)) ||
- (rsn_ie && wpa_s->ap_rsn_ie &&
- (rsn_ie_len != wpa_s->ap_rsn_ie_len ||
- memcmp(rsn_ie, wpa_s->ap_rsn_ie, rsn_ie_len) != 0))) {
- wpa_report_ie_mismatch(wpa_s, "IE in 3/4 msg does not match "
+ 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)) ||
+ (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))) {
+ wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
"with IE in Beacon/ProbeResp",
- src_addr, wpa_ie, wpa_ie_len,
- rsn_ie, rsn_ie_len);
- return;
+ src_addr, ie->wpa_ie, ie->wpa_ie_len,
+ ie->rsn_ie, ie->rsn_ie_len);
+ return -1;
}
- if (wpa_s->proto == WPA_PROTO_WPA &&
- rsn_ie && wpa_s->ap_rsn_ie == NULL &&
+ if (sm->proto == WPA_PROTO_WPA &&
+ ie->rsn_ie && sm->ap_rsn_ie == NULL &&
ssid && (ssid->proto & WPA_PROTO_RSN)) {
- wpa_report_ie_mismatch(wpa_s, "Possible downgrade attack "
+ wpa_report_ie_mismatch(sm, "Possible downgrade attack "
"detected - RSN was enabled and RSN IE "
"was in msg 3/4, but not in "
"Beacon/ProbeResp",
- src_addr, wpa_ie, wpa_ie_len,
- rsn_ie, rsn_ie_len);
+ src_addr, ie->wpa_ie, ie->wpa_ie_len,
+ ie->rsn_ie, ie->rsn_ie_len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_send_4_of_4(struct wpa_sm *sm,
+ const unsigned char *src_addr,
+ const struct wpa_eapol_key *key,
+ u16 ver, u16 key_info)
+{
+ size_t rlen;
+ struct wpa_eapol_key *reply;
+ u8 *rbuf;
+
+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+ sizeof(*reply), &rlen, (void *) &reply);
+ if (rbuf == NULL)
+ return -1;
+
+ reply->type = sm->proto == WPA_PROTO_RSN ?
+ EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+ key_info &= WPA_KEY_INFO_SECURE;
+ key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
+ WPA_PUT_BE16(reply->key_info, key_info);
+ 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);
+
+ WPA_PUT_BE16(reply->key_data_length, 0);
+
+ wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
+ rbuf, rlen, reply->key_mic);
+
+ return 0;
+}
+
+
+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 key_info, keylen, len;
+ const u8 *pos;
+ struct wpa_eapol_ie_parse ie;
+
+ 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);
+
+ key_info = WPA_GET_BE16(key->key_info);
+
+ pos = (const u8 *) (key + 1);
+ len = WPA_GET_BE16(key->key_data_length);
+ wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
+ wpa_supplicant_parse_ies(pos, len, &ie);
+ if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+ wpa_printf(MSG_WARNING, "WPA: GTK IE in unencrypted key data");
return;
}
- if (memcmp(wpa_s->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
+ if (wpa_supplicant_validate_ie(sm, src_addr, &ie) < 0)
+ return;
+
+ if (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));
return;
}
- keylen = be_to_host16(key->key_length);
- switch (wpa_s->pairwise_cipher) {
+ keylen = WPA_GET_BE16(key->key_length);
+ switch (sm->pairwise_cipher) {
case WPA_CIPHER_CCMP:
if (keylen != 16) {
wpa_printf(MSG_WARNING, "WPA: Invalid CCMP key length "
@@ -1513,273 +1561,250 @@ static void wpa_supplicant_process_3_of_4(struct wpa_supplicant *wpa_s,
break;
}
- rlen = sizeof(*ethhdr) + sizeof(*hdr) + sizeof(*reply);
- rbuf = malloc(rlen);
- if (rbuf == NULL)
+ if (wpa_supplicant_send_4_of_4(sm, src_addr, key, ver, key_info))
return;
- memset(rbuf, 0, rlen);
- ethhdr = (struct l2_ethhdr *) rbuf;
- memcpy(ethhdr->h_dest, src_addr, ETH_ALEN);
- memcpy(ethhdr->h_source, wpa_s->own_addr, ETH_ALEN);
- ethhdr->h_proto = htons(ETH_P_EAPOL);
-
- hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
- hdr->version = wpa_s->conf->eapol_version;
- hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
- hdr->length = htons(sizeof(*reply));
-
- reply = (struct wpa_eapol_key *) (hdr + 1);
- reply->type = wpa_s->proto == WPA_PROTO_RSN ?
- EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
- reply->key_info = host_to_be16(ver | WPA_KEY_INFO_KEY_TYPE |
- WPA_KEY_INFO_MIC |
- (key_info & WPA_KEY_INFO_SECURE));
- reply->key_length = key->key_length;
- memcpy(reply->replay_counter, key->replay_counter,
- WPA_REPLAY_COUNTER_LEN);
-
- reply->key_data_length = host_to_be16(0);
-
- memcpy(reply->key_nonce, wpa_s->snonce, WPA_NONCE_LEN);
- wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, (u8 *) hdr,
- rlen - sizeof(*ethhdr), reply->key_mic);
-
- wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
- wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key 4/4", rbuf, rlen);
- l2_packet_send(wpa_s->l2, rbuf, rlen);
- eapol_sm_notify_tx_eapol_key(wpa_s->eapol);
- free(rbuf);
-
/* SNonce was successfully used in msg 3/4, so mark it to be renewed
* for the next 4-Way Handshake. If msg 3 is received again, the old
* SNonce will still be used to avoid changing PTK. */
- wpa_s->renew_snonce = 1;
+ sm->renew_snonce = 1;
if (key_info & WPA_KEY_INFO_INSTALL) {
- wpa_supplicant_install_ptk(wpa_s, src_addr, key);
+ wpa_supplicant_install_ptk(sm, src_addr, key);
}
if (key_info & WPA_KEY_INFO_SECURE) {
/* MLME.SETPROTECTION.request(TA, Tx_Rx) */
- eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+ eapol_sm_notify_portValid(sm->eapol, TRUE);
}
- wpa_s->wpa_state = WPA_GROUP_HANDSHAKE;
+ wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
- if (gtk) {
- wpa_supplicant_pairwise_gtk(wpa_s, src_addr, key,
- gtk, gtk_len, key_info);
+ if (ie.gtk &&
+ wpa_supplicant_pairwise_gtk(sm, src_addr, key,
+ ie.gtk, ie.gtk_len, key_info) < 0) {
+ wpa_printf(MSG_INFO, "RSN: Failed to configure GTK");
}
}
-static void wpa_supplicant_process_1_of_2(struct wpa_supplicant *wpa_s,
- unsigned char *src_addr,
- struct wpa_eapol_key *key,
- int extra_len, int ver)
+static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
+ const u8 *keydata,
+ size_t keydatalen,
+ int key_info,
+ struct wpa_gtk_data *gd)
{
- int rlen;
- struct ieee802_1x_hdr *hdr;
- struct wpa_eapol_key *reply;
- unsigned char *rbuf;
- struct l2_ethhdr *ethhdr;
- int key_info, keylen, keydatalen, maxkeylen, keyidx, key_rsc_len = 0;
- int alg, tx, rekey;
- u8 ek[32], gtk[32];
- u8 *gtk_ie = NULL;
- size_t gtk_ie_len = 0;
-
- rekey = wpa_s->wpa_state == WPA_COMPLETED;
- wpa_s->wpa_state = WPA_GROUP_HANDSHAKE;
- wpa_printf(MSG_DEBUG, "WPA: RX message 1 of Group Key Handshake from "
- MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
+ int maxkeylen;
+ struct wpa_eapol_ie_parse ie;
- key_info = be_to_host16(key->key_info);
- keydatalen = be_to_host16(key->key_data_length);
-
- if (wpa_s->proto == WPA_PROTO_RSN) {
- u8 *pos = (u8 *) (key + 1);
- u8 *end = pos + keydatalen;
- while (pos + 1 < end) {
- if (pos + 2 + pos[1] > end) {
- wpa_printf(MSG_DEBUG, "RSN: key data "
- "underflow (ie=%d len=%d)",
- pos[0], pos[1]);
- break;
- }
- if (pos[0] == GENERIC_INFO_ELEM &&
- pos + 1 + RSN_SELECTOR_LEN < end &&
- pos[1] > RSN_SELECTOR_LEN + 2 &&
- memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY,
- RSN_SELECTOR_LEN) == 0) {
- if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
- wpa_printf(MSG_WARNING, "WPA: GTK IE "
- "in unencrypted key data");
- return;
- }
- gtk_ie = pos + 2 + RSN_SELECTOR_LEN;
- gtk_ie_len = pos[1] - RSN_SELECTOR_LEN;
- break;
- } else if (pos[0] == GENERIC_INFO_ELEM &&
- pos[1] == 0)
- break;
+ wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
+ wpa_supplicant_parse_ies(keydata, keydatalen, &ie);
+ if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+ wpa_printf(MSG_WARNING, "WPA: GTK IE in unencrypted key data");
+ return -1;
+ }
+ if (ie.gtk == NULL) {
+ wpa_printf(MSG_INFO, "WPA: No GTK IE in Group Key msg 1/2");
+ return -1;
+ }
+ maxkeylen = gd->gtk_len = ie.gtk_len - 2;
- pos += 2 + pos[1];
- }
+ if (wpa_supplicant_check_group_cipher(sm->group_cipher,
+ gd->gtk_len, maxkeylen,
+ &gd->key_rsc_len, &gd->alg))
+ return -1;
- if (gtk_ie == NULL) {
- wpa_printf(MSG_INFO, "WPA: No GTK IE in Group Key "
- "message 1/2");
- return;
- }
- maxkeylen = keylen = gtk_ie_len - 2;
- } else {
- keylen = be_to_host16(key->key_length);
- maxkeylen = keydatalen;
- if (keydatalen > extra_len) {
- wpa_printf(MSG_INFO, "WPA: Truncated EAPOL-Key packet:"
- " key_data_length=%d > extra_len=%d",
- keydatalen, extra_len);
- return;
- }
- if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES)
- maxkeylen -= 8;
+ wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake",
+ ie.gtk, ie.gtk_len);
+ gd->keyidx = ie.gtk[0] & 0x3;
+ gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
+ !!(ie.gtk[0] & BIT(2)));
+ if (ie.gtk_len - 2 > sizeof(gd->gtk)) {
+ wpa_printf(MSG_INFO, "RSN: Too long GTK in GTK IE "
+ "(len=%lu)", (unsigned long) ie.gtk_len - 2);
+ return -1;
}
+ memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
- if (wpa_supplicant_check_group_cipher(wpa_s, keylen, maxkeylen,
- &key_rsc_len, &alg)) {
- return;
+ return 0;
+}
+
+
+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,
+ struct wpa_gtk_data *gd)
+{
+ int 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);
+ return -1;
}
+ if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES)
+ maxkeylen -= 8;
- if (wpa_s->proto == WPA_PROTO_RSN) {
- wpa_hexdump(MSG_DEBUG,
- "RSN: received GTK in group key handshake",
- gtk_ie, gtk_ie_len);
- keyidx = gtk_ie[0] & 0x3;
- tx = !!(gtk_ie[0] & BIT(2));
- if (gtk_ie_len - 2 > sizeof(gtk)) {
- wpa_printf(MSG_INFO, "RSN: Too long GTK in GTK IE "
- "(len=%lu)",
- (unsigned long) gtk_ie_len - 2);
- return;
+ if (wpa_supplicant_check_group_cipher(sm->group_cipher,
+ gd->gtk_len, maxkeylen,
+ &gd->key_rsc_len, &gd->alg))
+ return -1;
+
+ 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);
+ if (keydatalen > sizeof(gd->gtk)) {
+ wpa_printf(MSG_WARNING, "WPA: RC4 key data "
+ "too long (%lu)",
+ (unsigned long) keydatalen);
+ return -1;
}
- memcpy(gtk, gtk_ie + 2, gtk_ie_len - 2);
- } else {
- 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, wpa_s->ptk.encr_key, 16);
- rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen);
- memcpy(gtk, key + 1, keylen);
- } else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
- if (keydatalen % 8) {
- wpa_printf(MSG_WARNING, "WPA: Unsupported "
- "AES-WRAP len %d", keydatalen);
- return;
- }
- if (aes_unwrap(wpa_s->ptk.encr_key, maxkeylen / 8,
- (u8 *) (key + 1), gtk)) {
- wpa_printf(MSG_WARNING, "WPA: AES unwrap "
- "failed - could not decrypt GTK");
- return;
- }
+ 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) {
+ wpa_printf(MSG_WARNING, "WPA: Unsupported AES-WRAP "
+ "len %lu", (unsigned long) keydatalen);
+ return -1;
+ }
+ if (maxkeylen > sizeof(gd->gtk)) {
+ wpa_printf(MSG_WARNING, "WPA: AES-WRAP key data "
+ "too long (keydatalen=%lu maxkeylen=%lu)",
+ (unsigned long) keydatalen,
+ (unsigned long) maxkeylen);
+ return -1;
+ }
+ if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
+ (const u8 *) (key + 1), gd->gtk)) {
+ wpa_printf(MSG_WARNING, "WPA: AES unwrap "
+ "failed - could not decrypt GTK");
+ return -1;
}
- tx = !!(key_info & WPA_KEY_INFO_TXRX);
}
+ gd->tx = wpa_supplicant_gtk_tx_bit_workaround(
+ sm, !!(key_info & WPA_KEY_INFO_TXRX));
+ return 0;
+}
- if (tx && wpa_s->pairwise_cipher != WPA_CIPHER_NONE) {
- /* Ignore Tx bit in Group Key message if a pairwise key
- * is used. Some APs seem to setting this bit
- * (incorrectly, since Tx is only when doing Group Key
- * only APs) and without this workaround, the data
- * connection does not work because wpa_supplicant
- * configured non-zero keyidx to be used for unicast.
- */
- wpa_printf(MSG_INFO, "WPA: Tx bit set for GTK, but "
- "pairwise keys are used - ignore Tx bit");
- tx = 0;
- }
- wpa_supplicant_install_gtk(wpa_s, key, alg, gtk, keylen, keyidx,
- key_rsc_len, tx);
+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)
+{
+ size_t rlen;
+ struct wpa_eapol_key *reply;
+ u8 *rbuf;
- rlen = sizeof(*ethhdr) + sizeof(*hdr) + sizeof(*reply);
- rbuf = malloc(rlen);
+ rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+ sizeof(*reply), &rlen, (void *) &reply);
if (rbuf == NULL)
- return;
-
- memset(rbuf, 0, rlen);
- ethhdr = (struct l2_ethhdr *) rbuf;
- memcpy(ethhdr->h_dest, src_addr, ETH_ALEN);
- memcpy(ethhdr->h_source, wpa_s->own_addr, ETH_ALEN);
- ethhdr->h_proto = htons(ETH_P_EAPOL);
-
- hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
- hdr->version = wpa_s->conf->eapol_version;
- hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
- hdr->length = htons(sizeof(*reply));
+ return -1;
- reply = (struct wpa_eapol_key *) (hdr + 1);
- reply->type = wpa_s->proto == WPA_PROTO_RSN ?
+ reply->type = sm->proto == WPA_PROTO_RSN ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
- reply->key_info =
- host_to_be16(ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE |
- (key_info & WPA_KEY_INFO_KEY_INDEX_MASK));
- reply->key_length = key->key_length;
+ key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
+ key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
+ WPA_PUT_BE16(reply->key_info, key_info);
+ 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);
-
- reply->key_data_length = host_to_be16(0);
+ WPA_REPLAY_COUNTER_LEN);
- wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, (u8 *) hdr,
- rlen - sizeof(*ethhdr), reply->key_mic);
+ WPA_PUT_BE16(reply->key_data_length, 0);
wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
- wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key 2/2", rbuf, rlen);
- l2_packet_send(wpa_s->l2, rbuf, rlen);
- eapol_sm_notify_tx_eapol_key(wpa_s->eapol);
- free(rbuf);
+ wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
+ rbuf, rlen, reply->key_mic);
+
+ return 0;
+}
+
+
+static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
+ const unsigned char *src_addr,
+ const struct wpa_eapol_key *key,
+ int extra_len, u16 ver)
+{
+ u16 key_info, keydatalen;
+ int rekey;
+ struct wpa_gtk_data gd;
+
+ 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);
+
+ key_info = WPA_GET_BE16(key->key_info);
+ 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;
+ } else {
+ if (wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
+ key_info, extra_len,
+ ver, &gd))
+ return;
+ }
+
+ if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
+ wpa_supplicant_send_2_of_2(sm, src_addr, key, ver, key_info))
+ return;
if (rekey) {
- wpa_msg(wpa_s, MSG_INFO, "WPA: Group rekeying completed with "
- MACSTR " [GTK=%s]", MAC2STR(src_addr),
- wpa_cipher_txt(wpa_s->group_cipher));
- wpa_s->wpa_state = WPA_COMPLETED;
+ wpa_msg(sm->ctx->ctx, MSG_INFO, "WPA: Group rekeying "
+ "completed with " MACSTR " [GTK=%s]",
+ MAC2STR(src_addr), wpa_cipher_txt(sm->group_cipher));
+ wpa_sm_set_state(sm, WPA_COMPLETED);
} else {
- wpa_supplicant_key_neg_complete(wpa_s, src_addr,
+ wpa_supplicant_key_neg_complete(sm, src_addr,
key_info &
WPA_KEY_INFO_SECURE);
}
}
-static int wpa_supplicant_verify_eapol_key_mic(struct wpa_supplicant *wpa_s,
+static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
struct wpa_eapol_key *key,
- int ver, u8 *buf, size_t len)
+ u16 ver,
+ const u8 *buf, size_t len)
{
u8 mic[16];
int ok = 0;
memcpy(mic, key->key_mic, 16);
- if (wpa_s->tptk_set) {
+ if (sm->tptk_set) {
memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(wpa_s->tptk.mic_key, ver, buf, len,
+ wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
key->key_mic);
if (memcmp(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
"when using TPTK - ignoring TPTK");
} else {
ok = 1;
- wpa_s->tptk_set = 0;
- wpa_s->ptk_set = 1;
- memcpy(&wpa_s->ptk, &wpa_s->tptk, sizeof(wpa_s->ptk));
+ sm->tptk_set = 0;
+ sm->ptk_set = 1;
+ memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
}
}
- if (!ok && wpa_s->ptk_set) {
+ if (!ok && sm->ptk_set) {
memset(key->key_mic, 0, 16);
- wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, buf, len,
+ wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
key->key_mic);
if (memcmp(mic, key->key_mic, 16) != 0) {
wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
@@ -1795,22 +1820,22 @@ static int wpa_supplicant_verify_eapol_key_mic(struct wpa_supplicant *wpa_s,
return -1;
}
- memcpy(wpa_s->rx_replay_counter, key->replay_counter,
+ memcpy(sm->rx_replay_counter, key->replay_counter,
WPA_REPLAY_COUNTER_LEN);
- wpa_s->rx_replay_counter_set = 1;
+ sm->rx_replay_counter_set = 1;
return 0;
}
/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
-static int wpa_supplicant_decrypt_key_data(struct wpa_supplicant *wpa_s,
- struct wpa_eapol_key *key, int ver)
+static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
+ struct wpa_eapol_key *key, u16 ver)
{
- int keydatalen = be_to_host16(key->key_data_length);
+ u16 keydatalen = WPA_GET_BE16(key->key_data_length);
wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
(u8 *) (key + 1), keydatalen);
- if (!wpa_s->ptk_set) {
+ if (!sm->ptk_set) {
wpa_printf(MSG_WARNING, "WPA: PTK not available, "
"cannot decrypt EAPOL-Key key data.");
return -1;
@@ -1821,7 +1846,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_supplicant *wpa_s,
if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
u8 ek[32];
memcpy(ek, key->key_iv, 16);
- memcpy(ek + 16, wpa_s->ptk.encr_key, 16);
+ 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;
@@ -1837,7 +1862,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_supplicant *wpa_s,
"AES-UNWRAP buffer");
return -1;
}
- if (aes_unwrap(wpa_s->ptk.encr_key, keydatalen / 8,
+ if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
(u8 *) (key + 1), buf)) {
free(buf);
wpa_printf(MSG_WARNING, "WPA: AES unwrap failed - "
@@ -1846,7 +1871,7 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_supplicant *wpa_s,
}
memcpy(key + 1, buf, keydatalen);
free(buf);
- key->key_data_length = host_to_be16(keydatalen);
+ WPA_PUT_BE16(key->key_data_length, keydatalen);
}
wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
(u8 *) (key + 1), keydatalen);
@@ -1854,50 +1879,73 @@ static int wpa_supplicant_decrypt_key_data(struct wpa_supplicant *wpa_s,
}
-static void wpa_sm_rx_eapol(struct wpa_supplicant *wpa_s,
- unsigned char *src_addr, unsigned char *buf,
- size_t len)
+/**
+ * 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
+ * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
+ * @len: Length of the EAPOL frame
+ * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure
+ *
+ * This function is called for each received EAPOL frame. Other than EAPOL-Key
+ * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is
+ * only processing WPA and WPA2 EAPOL-Key frames.
+ *
+ * The received EAPOL-Key packets are validated and valid packets are replied
+ * to. In addition, key material (PTK, GTK) is configured at the end of a
+ * successful key handshake.
+ */
+int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
+ const u8 *buf, size_t len)
{
size_t plen, data_len, extra_len;
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- int key_info, ver;
+ u16 key_info, ver;
+ u8 *tmp;
+ int ret = -1;
- hdr = (struct ieee802_1x_hdr *) buf;
- key = (struct wpa_eapol_key *) (hdr + 1);
if (len < sizeof(*hdr) + sizeof(*key)) {
- wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short, len %lu, "
- "expecting at least %lu",
+ wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short to be a WPA "
+ "EAPOL-Key (len %lu, expecting at least %lu)",
(unsigned long) len,
(unsigned long) sizeof(*hdr) + sizeof(*key));
- return;
+ return 0;
}
+
+ tmp = malloc(len);
+ if (tmp == NULL)
+ return -1;
+ memcpy(tmp, buf, len);
+
+ hdr = (struct ieee802_1x_hdr *) tmp;
+ key = (struct wpa_eapol_key *) (hdr + 1);
plen = ntohs(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);
- wpa_drv_poll(wpa_s);
-
if (hdr->version < EAPOL_VERSION) {
/* TODO: backwards compatibility */
}
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 (wpa_s->cur_pmksa) {
+ if (sm->cur_pmksa) {
wpa_printf(MSG_DEBUG, "WPA: Cancelling PMKSA caching "
"attempt - attempt full EAP "
"authentication");
- eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 0);
+ eapol_sm_notify_pmkid_attempt(sm->eapol, 0);
}
- return;
+ ret = 0;
+ goto out;
}
if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
wpa_printf(MSG_DEBUG, "WPA: EAPOL frame payload size %lu "
"invalid (frame size %lu)",
(unsigned long) plen, (unsigned long) len);
- return;
+ ret = 0;
+ goto out;
}
wpa_printf(MSG_DEBUG, " EAPOL-Key type=%d", key->type);
@@ -1905,28 +1953,30 @@ static void wpa_sm_rx_eapol(struct wpa_supplicant *wpa_s,
{
wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key type (%d) unknown, "
"discarded", key->type);
- return;
+ ret = 0;
+ goto out;
}
- wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
+ eapol_sm_notify_lower_layer_success(sm->eapol);
+ wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
if (data_len < len) {
wpa_printf(MSG_DEBUG, "WPA: ignoring %lu bytes after the IEEE "
"802.1X data", (unsigned long) len - data_len);
}
- key_info = be_to_host16(key->key_info);
+ key_info = WPA_GET_BE16(key->key_info);
ver = key_info & WPA_KEY_INFO_TYPE_MASK;
if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_printf(MSG_INFO, "WPA: Unsupported EAPOL-Key descriptor "
"version %d.", ver);
- return;
+ goto out;
}
- if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP &&
+ if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_printf(MSG_INFO, "WPA: CCMP is used, but EAPOL-Key "
"descriptor version (%d) is not 2.", ver);
- if (wpa_s->group_cipher != WPA_CIPHER_CCMP &&
+ if (sm->group_cipher != WPA_CIPHER_CCMP &&
!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
/* Earlier versions of IEEE 802.11i did not explicitly
* require version 2 descriptor for all EAPOL-Key
@@ -1936,115 +1986,78 @@ static void wpa_sm_rx_eapol(struct wpa_supplicant *wpa_s,
"allow invalid version for non-CCMP group "
"keys");
} else
- return;
+ goto out;
}
- if (wpa_s->rx_replay_counter_set &&
- memcmp(key->replay_counter, wpa_s->rx_replay_counter,
+ if (sm->rx_replay_counter_set &&
+ 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");
- return;
+ goto out;
}
if (!(key_info & WPA_KEY_INFO_ACK)) {
wpa_printf(MSG_INFO, "WPA: No Ack bit in key_info");
- return;
+ goto out;
}
if (key_info & WPA_KEY_INFO_REQUEST) {
wpa_printf(MSG_INFO, "WPA: EAPOL-Key with Request bit - "
"dropped");
- return;
+ goto out;
}
if ((key_info & WPA_KEY_INFO_MIC) &&
- wpa_supplicant_verify_eapol_key_mic(wpa_s, key, ver, buf,
- data_len))
- return;
+ wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
+ goto out;
extra_len = data_len - sizeof(*hdr) - sizeof(*key);
- if (be_to_host16(key->key_data_length) > extra_len) {
- wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
- "key_data overflow (%d > %lu)",
- be_to_host16(key->key_data_length),
+ if (WPA_GET_BE16(key->key_data_length) > extra_len) {
+ wpa_msg(sm->ctx->ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
+ "frame - key_data overflow (%d > %lu)",
+ WPA_GET_BE16(key->key_data_length),
(unsigned long) extra_len);
- return;
+ goto out;
}
- if (wpa_s->proto == WPA_PROTO_RSN &&
+ if (sm->proto == WPA_PROTO_RSN &&
(key_info & WPA_KEY_INFO_ENCR_KEY_DATA) &&
- wpa_supplicant_decrypt_key_data(wpa_s, key, ver))
- return;
+ wpa_supplicant_decrypt_key_data(sm, key, ver))
+ goto out;
if (key_info & WPA_KEY_INFO_KEY_TYPE) {
if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
wpa_printf(MSG_WARNING, "WPA: Ignored EAPOL-Key "
"(Pairwise) with non-zero key index");
- return;
+ goto out;
}
if (key_info & WPA_KEY_INFO_MIC) {
/* 3/4 4-Way Handshake */
- wpa_supplicant_process_3_of_4(wpa_s, src_addr, key,
+ wpa_supplicant_process_3_of_4(sm, src_addr, key,
extra_len, ver);
} else {
/* 1/4 4-Way Handshake */
- wpa_supplicant_process_1_of_4(wpa_s, src_addr, key,
+ wpa_supplicant_process_1_of_4(sm, src_addr, key,
ver);
}
} else {
if (key_info & WPA_KEY_INFO_MIC) {
/* 1/2 Group Key Handshake */
- wpa_supplicant_process_1_of_2(wpa_s, src_addr, key,
+ wpa_supplicant_process_1_of_2(sm, src_addr, key,
extra_len, ver);
} else {
wpa_printf(MSG_WARNING, "WPA: EAPOL-Key (Group) "
"without Mic bit - dropped");
}
}
-}
+ ret = 1;
-void wpa_supplicant_rx_eapol(void *ctx, unsigned char *src_addr,
- unsigned char *buf, size_t len)
-{
- struct wpa_supplicant *wpa_s = ctx;
-
- wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
- wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
-
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
- wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
- "no key management is configured");
- return;
- }
-
- if (wpa_s->eapol_received == 0) {
- /* Timeout for completing IEEE 802.1X and WPA authentication */
- wpa_supplicant_req_auth_timeout(
- wpa_s,
- (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) ?
- 70 : 10, 0);
- }
- wpa_s->eapol_received++;
-
- if (wpa_s->countermeasures) {
- wpa_printf(MSG_INFO, "WPA: Countermeasures - dropped EAPOL "
- "packet");
- return;
- }
-
- /* Source address of the incoming EAPOL frame could be compared to the
- * current BSSID. However, it is possible that a centralized
- * Authenticator could be using another MAC address than the BSSID of
- * 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);
- eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len);
- wpa_sm_rx_eapol(wpa_s, src_addr, buf, len);
+out:
+ free(tmp);
+ return ret;
}
@@ -2065,16 +2078,16 @@ static int wpa_cipher_bits(int cipher)
}
-static const u8 * wpa_key_mgmt_suite(struct wpa_supplicant *wpa_s)
+static const u8 * wpa_key_mgmt_suite(struct wpa_sm *sm)
{
static const u8 *dummy = (u8 *) "\x00\x00\x00\x00";
- switch (wpa_s->key_mgmt) {
+ switch (sm->key_mgmt) {
case WPA_KEY_MGMT_IEEE8021X:
- return (wpa_s->proto == WPA_PROTO_RSN ?
+ return (sm->proto == WPA_PROTO_RSN ?
RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
case WPA_KEY_MGMT_PSK:
- return (wpa_s->proto == WPA_PROTO_RSN ?
+ return (sm->proto == WPA_PROTO_RSN ?
RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X :
WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
case WPA_KEY_MGMT_WPA_NONE:
@@ -2085,24 +2098,24 @@ static const u8 * wpa_key_mgmt_suite(struct wpa_supplicant *wpa_s)
}
-static const u8 * wpa_cipher_suite(struct wpa_supplicant *wpa_s, int cipher)
+static const u8 * wpa_cipher_suite(struct wpa_sm *sm, int cipher)
{
static const u8 *dummy = (u8 *) "\x00\x00\x00\x00";
switch (cipher) {
case WPA_CIPHER_CCMP:
- return (wpa_s->proto == WPA_PROTO_RSN ?
+ return (sm->proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
case WPA_CIPHER_TKIP:
- return (wpa_s->proto == WPA_PROTO_RSN ?
+ return (sm->proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
case WPA_CIPHER_WEP104:
- return (wpa_s->proto == WPA_PROTO_RSN ?
+ return (sm->proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
case WPA_CIPHER_WEP40:
- return (wpa_s->proto == WPA_PROTO_RSN ?
+ return (sm->proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
case WPA_CIPHER_NONE:
- return (wpa_s->proto == WPA_PROTO_RSN ?
+ return (sm->proto == WPA_PROTO_RSN ?
RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
default:
return dummy;
@@ -2113,21 +2126,41 @@ static const u8 * wpa_cipher_suite(struct wpa_supplicant *wpa_s, int cipher)
#define RSN_SUITE "%02x-%02x-%02x-%d"
#define RSN_SUITE_ARG(s) (s)[0], (s)[1], (s)[2], (s)[3]
-int wpa_get_mib(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+/**
+ * wpa_sm_get_mib - Dump text list of MIB entries
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @buf: Buffer for the list
+ * @buflen: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used fetch dot11 MIB variables.
+ */
+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;
- if (wpa_s->cur_pmksa) {
+ if (sm->cur_pmksa) {
char *pos = pmkid_txt;
for (i = 0; i < PMKID_LEN; i++) {
- pos += sprintf(pos, "%02x",
- wpa_s->cur_pmksa->pmkid[i]);
+ pos += sprintf(pos, "%02x", sm->cur_pmksa->pmkid[i]);
}
} else
pmkid_txt[0] = '\0';
+ if ((sm->key_mgmt == WPA_KEY_MGMT_PSK ||
+ sm->key_mgmt == WPA_KEY_MGMT_IEEE8021X) &&
+ sm->proto == WPA_PROTO_RSN)
+ rsna = 1;
+ 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"
@@ -2142,316 +2175,504 @@ int wpa_get_mib(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
- "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
+ "dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n"
+ "dot11RSNA4WayHandshakeFailures=%u\n",
+ rsna ? "TRUE" : "FALSE",
+ rsna ? "TRUE" : "FALSE",
RSN_VERSION,
- wpa_cipher_bits(wpa_s->group_cipher),
- dot11RSNAConfigPMKLifetime,
- dot11RSNAConfigPMKReauthThreshold,
- dot11RSNAConfigSATimeout,
- RSN_SUITE_ARG(wpa_key_mgmt_suite(wpa_s)),
- RSN_SUITE_ARG(wpa_cipher_suite(wpa_s,
- wpa_s->pairwise_cipher)),
- RSN_SUITE_ARG(wpa_cipher_suite(wpa_s,
- wpa_s->group_cipher)),
+ 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(wpa_s)),
- RSN_SUITE_ARG(wpa_cipher_suite(wpa_s,
- wpa_s->pairwise_cipher)),
- RSN_SUITE_ARG(wpa_cipher_suite(wpa_s,
- wpa_s->group_cipher)));
+ 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;
}
-#ifdef IEEE8021X_EAPOL
+/**
+ * wpa_sm_init - Initialize WPA state machine
+ * @ctx: Context pointer for callbacks
+ * Returns: Pointer to the allocated WPA state machine data
+ *
+ * This function is used to allocate a new WPA state machine and the returned
+ * value is passed to all WPA state machine calls.
+ */
+struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
+{
+ struct wpa_sm *sm;
+
+ sm = malloc(sizeof(*sm));
+ if (sm == NULL)
+ return NULL;
+ memset(sm, 0, sizeof(*sm));
+ sm->renew_snonce = 1;
+ sm->ctx = ctx;
+
+ sm->dot11RSNAConfigPMKLifetime = 43200;
+ sm->dot11RSNAConfigPMKReauthThreshold = 70;
+ sm->dot11RSNAConfigSATimeout = 60;
+
+ return sm;
+}
+
-static void rsn_preauth_receive(void *ctx, unsigned char *src_addr,
- unsigned char *buf, size_t len)
+/**
+ * wpa_sm_deinit - Deinitialize WPA state machine
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void wpa_sm_deinit(struct wpa_sm *sm)
{
- struct wpa_supplicant *wpa_s = ctx;
-
- wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
- wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
-
- if (wpa_s->preauth_eapol == NULL ||
- memcmp(wpa_s->preauth_bssid, "\x00\x00\x00\x00\x00\x00",
- ETH_ALEN) == 0 ||
- memcmp(wpa_s->preauth_bssid, src_addr, ETH_ALEN) != 0) {
- wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
- "unexpected source " MACSTR " - dropped",
- MAC2STR(src_addr));
+ 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);
+}
- eapol_sm_rx_eapol(wpa_s->preauth_eapol, src_addr, buf, len);
+
+/**
+ * wpa_sm_notify_assoc - Notify WPA state machine about association
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @bssid: The BSSID of the new association
+ *
+ * This function is called to let WPA state machine know that the connection
+ * was established.
+ */
+void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
+{
+ if (sm == NULL)
+ 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);
+ sm->rx_replay_counter_set = 0;
+ sm->renew_snonce = 1;
+ if (memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0)
+ rsn_preauth_deinit(sm);
}
-static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
- void *ctx)
+/**
+ * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * This function is called to let WPA state machine know that the connection
+ * was lost. This will abort any existing pre-authentication session.
+ */
+void wpa_sm_notify_disassoc(struct wpa_sm *sm)
{
- struct wpa_supplicant *wpa_s = ctx;
- u8 pmk[PMK_LEN];
+ rsn_preauth_deinit(sm);
+ if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
+ sm->dot11RSNA4WayHandshakeFailures++;
+}
- wpa_msg(wpa_s, MSG_INFO, "RSN: pre-authentication with " MACSTR
- " %s", MAC2STR(wpa_s->preauth_bssid),
- success ? "completed successfully" : "failed");
- if (success) {
- int res, pmk_len;
- pmk_len = PMK_LEN;
- res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
-#ifdef EAP_LEAP
- if (res) {
- 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);
- wpa_s->pmk_len = pmk_len;
- pmksa_cache_add(wpa_s, pmk, pmk_len,
- wpa_s->preauth_bssid, wpa_s->own_addr);
- } else {
- wpa_msg(wpa_s, MSG_INFO, "RSN: failed to get master "
- "session key from pre-auth EAPOL state "
- "machines");
- }
+/**
+ * wpa_sm_set_pmk - Set PMK
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @pmk: The new PMK
+ * @pmk_len: The length of the new PMK in bytes
+ *
+ * Configure the PMK for WPA state machine.
+ */
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
+{
+ if (sm == NULL)
+ return;
+
+ sm->pmk_len = pmk_len;
+ memcpy(sm->pmk, pmk, pmk_len);
+}
+
+
+/**
+ * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK
+ * will be cleared.
+ */
+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
+{
+ if (sm == NULL)
+ return;
+
+ if (sm->cur_pmksa) {
+ sm->pmk_len = sm->cur_pmksa->pmk_len;
+ memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
+ } else {
+ sm->pmk_len = PMK_LEN;
+ memset(sm->pmk, 0, PMK_LEN);
}
+}
- rsn_preauth_deinit(wpa_s);
- rsn_preauth_candidate_process(wpa_s);
+
+/**
+ * wpa_sm_set_fast_reauth - Set fast reauthentication (EAP) enabled/disabled
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @fast_reauth: Whether fast reauthentication (EAP) is allowed
+ */
+void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth)
+{
+ if (sm)
+ sm->fast_reauth = fast_reauth;
}
-static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
+/**
+ * wpa_sm_set_scard_ctx - Set context pointer for smartcard callbacks
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @scard_ctx: Context pointer for smartcard related callback functions
+ */
+void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- wpa_msg(wpa_s, MSG_INFO, "RSN: pre-authentication with " MACSTR
- " timed out", MAC2STR(wpa_s->preauth_bssid));
- rsn_preauth_deinit(wpa_s);
- rsn_preauth_candidate_process(wpa_s);
+ if (sm == NULL)
+ return;
+ sm->scard_ctx = scard_ctx;
+ if (sm->preauth_eapol)
+ eapol_sm_register_scard_ctx(sm->preauth_eapol, scard_ctx);
}
-int rsn_preauth_init(struct wpa_supplicant *wpa_s, u8 *dst)
+/**
+ * wpa_sm_set_config - Notification of current configration change
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @config: Pointer to current network configuration
+ *
+ * Notify WPA state machine that configuration has changed. config will be
+ * stored as a backpointer to network configuration. This can be %NULL to clear
+ * the stored pointed.
+ */
+void wpa_sm_set_config(struct wpa_sm *sm, struct wpa_ssid *config)
{
- struct eapol_config eapol_conf;
- struct eapol_ctx *ctx;
+ if (sm)
+ sm->cur_ssid = config;
+}
- if (wpa_s->preauth_eapol)
- return -1;
- wpa_msg(wpa_s, MSG_DEBUG, "RSN: starting pre-authentication with "
- MACSTR, MAC2STR(dst));
+/**
+ * wpa_sm_set_own_addr - Set own MAC address
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @addr: Own MAC address
+ */
+void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
+{
+ if (sm)
+ memcpy(sm->own_addr, addr, ETH_ALEN);
+}
- wpa_s->l2_preauth = l2_packet_init(wpa_s->ifname,
- wpa_drv_get_mac_addr(wpa_s),
- ETH_P_RSN_PREAUTH,
- rsn_preauth_receive, wpa_s);
- if (wpa_s->l2_preauth == NULL) {
- wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
- "processing for pre-authentication");
- return -2;
- }
- ctx = malloc(sizeof(*ctx));
- if (ctx == NULL) {
- wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
- return -4;
- }
- memset(ctx, 0, sizeof(*ctx));
- ctx->ctx = wpa_s;
- ctx->msg_ctx = wpa_s;
- ctx->preauth = 1;
- ctx->cb = rsn_preauth_eapol_cb;
- ctx->cb_ctx = wpa_s;
- ctx->scard_ctx = wpa_s->scard;
- ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
- ctx->eapol_send = wpa_eapol_send_preauth;
-
- wpa_s->preauth_eapol = eapol_sm_init(ctx);
- if (wpa_s->preauth_eapol == NULL) {
- 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));
- eapol_conf.accept_802_1x_keys = 0;
- eapol_conf.required_keys = 0;
- eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
- if (wpa_s->current_ssid)
- eapol_conf.workaround = wpa_s->current_ssid->eap_workaround;
- eapol_sm_notify_config(wpa_s->preauth_eapol, wpa_s->current_ssid,
- &eapol_conf);
- memcpy(wpa_s->preauth_bssid, dst, ETH_ALEN);
-
- eapol_sm_notify_portValid(wpa_s->preauth_eapol, TRUE);
- /* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(wpa_s->preauth_eapol, TRUE);
-
- eloop_register_timeout(60, 0, rsn_preauth_timeout, wpa_s, NULL);
+/**
+ * wpa_sm_set_ifname - Set network interface name
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ifname: Interface name
+ */
+void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname)
+{
+ if (sm)
+ sm->ifname = ifname;
+}
- return 0;
+
+/**
+ * wpa_sm_set_eapol - Set EAPOL state machine pointer
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @eapol: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ */
+void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol)
+{
+ if (sm)
+ sm->eapol = eapol;
}
-void rsn_preauth_deinit(struct wpa_supplicant *wpa_s)
+/**
+ * wpa_sm_set_param - Set WPA state machine parameters
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @param: Parameter field
+ * @value: Parameter value
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
+ unsigned int value)
{
- if (!wpa_s->preauth_eapol)
- return;
+ int ret = 0;
+
+ if (sm == NULL)
+ return -1;
- eloop_cancel_timeout(rsn_preauth_timeout, wpa_s, NULL);
- eapol_sm_deinit(wpa_s->preauth_eapol);
- wpa_s->preauth_eapol = NULL;
- memset(wpa_s->preauth_bssid, 0, ETH_ALEN);
+ switch (param) {
+ case RSNA_PMK_LIFETIME:
+ if (value > 0)
+ sm->dot11RSNAConfigPMKLifetime = value;
+ else
+ ret = -1;
+ break;
+ case RSNA_PMK_REAUTH_THRESHOLD:
+ if (value > 0 && value <= 100)
+ sm->dot11RSNAConfigPMKReauthThreshold = value;
+ else
+ ret = -1;
+ break;
+ case RSNA_SA_TIMEOUT:
+ if (value > 0)
+ sm->dot11RSNAConfigSATimeout = value;
+ else
+ ret = -1;
+ break;
+ case WPA_PARAM_PROTO:
+ sm->proto = value;
+ break;
+ case WPA_PARAM_PAIRWISE:
+ sm->pairwise_cipher = value;
+ break;
+ case WPA_PARAM_GROUP:
+ sm->group_cipher = value;
+ break;
+ case WPA_PARAM_KEY_MGMT:
+ sm->key_mgmt = value;
+ break;
+ }
- l2_packet_deinit(wpa_s->l2_preauth);
- wpa_s->l2_preauth = NULL;
+ return ret;
}
-static void rsn_preauth_candidate_process(struct wpa_supplicant *wpa_s)
+/**
+ * wpa_sm_get_param - Get WPA state machine parameters
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @param: Parameter field
+ * Returns: Parameter value
+ */
+unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param)
{
- struct rsn_pmksa_candidate *candidate;
+ if (sm == NULL)
+ return 0;
- if (wpa_s->pmksa_candidates == NULL)
- return;
+ switch (param) {
+ case RSNA_PMK_LIFETIME:
+ return sm->dot11RSNAConfigPMKLifetime;
+ case RSNA_PMK_REAUTH_THRESHOLD:
+ return sm->dot11RSNAConfigPMKReauthThreshold;
+ case RSNA_SA_TIMEOUT:
+ return sm->dot11RSNAConfigSATimeout;
+ case WPA_PARAM_PROTO:
+ return sm->proto;
+ case WPA_PARAM_PAIRWISE:
+ return sm->pairwise_cipher;
+ case WPA_PARAM_GROUP:
+ return sm->group_cipher;
+ case WPA_PARAM_KEY_MGMT:
+ return sm->key_mgmt;
+ default:
+ return 0;
+ }
+}
- /* TODO: drop priority for old candidate entries */
-
- wpa_msg(wpa_s, MSG_DEBUG, "RSN: processing PMKSA candidate list");
- if (wpa_s->preauth_eapol ||
- wpa_s->proto != WPA_PROTO_RSN ||
- wpa_s->wpa_state != WPA_COMPLETED ||
- wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X) {
- wpa_msg(wpa_s, MSG_DEBUG, "RSN: not in suitable state for new "
- "pre-authentication");
- return; /* invalid state for new pre-auth */
- }
-
- while (wpa_s->pmksa_candidates) {
- struct rsn_pmksa_cache *p = NULL;
- candidate = wpa_s->pmksa_candidates;
- p = pmksa_cache_get(wpa_s, candidate->bssid, NULL);
- if (memcmp(wpa_s->bssid, candidate->bssid, ETH_ALEN) != 0 &&
- p == NULL) {
- wpa_msg(wpa_s, MSG_DEBUG, "RSN: PMKSA candidate "
- MACSTR " selected for pre-authentication",
- MAC2STR(candidate->bssid));
- wpa_s->pmksa_candidates = candidate->next;
- rsn_preauth_init(wpa_s, candidate->bssid);
- free(candidate);
- return;
- }
- wpa_msg(wpa_s, MSG_DEBUG, "RSN: PMKSA candidate " MACSTR
- " does not need pre-authentication anymore",
- MAC2STR(candidate->bssid));
- /* Some drivers (e.g., NDIS) expect to get notified about the
- * PMKIDs again, so report the existing data now. */
- if (p)
- wpa_drv_add_pmkid(wpa_s, candidate->bssid, p->pmkid);
-
- wpa_s->pmksa_candidates = candidate->next;
- free(candidate);
- }
- wpa_msg(wpa_s, MSG_DEBUG, "RSN: no more pending PMKSA candidates");
+
+/**
+ * wpa_sm_get_status - Get WPA state machine
+ * @sm: Pointer to WPA state machine data from wpa_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.
+ *
+ * Query WPA state machine for status information. This function fills in
+ * a text area with current status information. If the buffer (buf) is not
+ * large enough, status information will be truncated to fit the buffer.
+ */
+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));
+ return pos - buf;
}
-void pmksa_candidate_add(struct wpa_supplicant *wpa_s, const u8 *bssid,
- int prio)
+/**
+ * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @wpa_ie: Pointer to buffer for WPA/RSN IE
+ * @wpa_ie_len: Pointer to the length of the wpa_ie buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the WPA/RSN IE used in (Re)Association
+ * Request frame. The IE will be used to override the default value generated
+ * with wpa_sm_set_assoc_wpa_ie_default().
+ */
+int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
+ size_t *wpa_ie_len)
{
- struct rsn_pmksa_candidate *cand, *prev, *pos;
-
- /* If BSSID already on candidate list, update the priority of the old
- * entry. Do not override priority based on normal scan results. */
- prev = NULL;
- cand = wpa_s->pmksa_candidates;
- while (cand) {
- if (memcmp(cand->bssid, bssid, ETH_ALEN) == 0) {
- if (prev)
- prev->next = cand->next;
- else
- wpa_s->pmksa_candidates = cand->next;
- break;
- }
- prev = cand;
- cand = cand->next;
+ if (sm == NULL)
+ return -1;
+
+ *wpa_ie_len = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
+ if (*wpa_ie_len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "WPA: Set own WPA IE default",
+ wpa_ie, *wpa_ie_len);
+
+ if (sm->assoc_wpa_ie == NULL) {
+ /*
+ * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets
+ * 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);
+ if (sm->assoc_wpa_ie == NULL)
+ return -1;
+
+ memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
+ sm->assoc_wpa_ie_len = *wpa_ie_len;
}
- if (cand) {
- if (prio < PMKID_CANDIDATE_PRIO_SCAN)
- cand->priority = prio;
+ return 0;
+}
+
+
+/**
+ * wpa_sm_set_assoc_wpa_ie - Set own WPA/RSN IE from (Re)AssocReq
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the WPA/RSN IE used in (Re)Association
+ * Request frame. The IE will be used to override the default value generated
+ * with wpa_sm_set_assoc_wpa_ie_default().
+ */
+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);
+ 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 {
- cand = malloc(sizeof(*cand));
- if (cand == NULL)
- return;
- memset(cand, 0, sizeof(*cand));
- memcpy(cand->bssid, bssid, ETH_ALEN);
- cand->priority = prio;
- }
+ wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len);
+ sm->assoc_wpa_ie = malloc(len);
+ if (sm->assoc_wpa_ie == NULL)
+ return -1;
- /* Add candidate to the list; order by increasing priority value. i.e.,
- * highest priority (smallest value) first. */
- prev = NULL;
- pos = wpa_s->pmksa_candidates;
- while (pos) {
- if (cand->priority <= pos->priority)
- break;
- prev = pos;
- pos = pos->next;
+ memcpy(sm->assoc_wpa_ie, ie, len);
+ sm->assoc_wpa_ie_len = len;
}
- cand->next = pos;
- if (prev)
- prev->next = cand;
- else
- wpa_s->pmksa_candidates = cand;
- wpa_msg(wpa_s, MSG_DEBUG, "RSN: added PMKSA cache "
- "candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
- rsn_preauth_candidate_process(wpa_s);
+ return 0;
}
-/* TODO: schedule periodic scans if current AP supports preauth */
-void rsn_preauth_scan_results(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *results, int count)
+/**
+ * wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the WPA IE used in Beacon / Probe Response
+ * frame.
+ */
+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
{
- struct wpa_scan_result *r;
- struct wpa_ie_data ie;
- int i;
+ if (sm == NULL)
+ return -1;
- if (wpa_s->current_ssid == NULL)
- return;
+ 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);
+ if (sm->ap_wpa_ie == NULL)
+ return -1;
- pmksa_candidate_free(wpa_s);
-
- for (i = count - 1; i >= 0; i--) {
- r = &results[i];
- if (r->ssid_len == wpa_s->current_ssid->ssid_len &&
- memcmp(r->ssid, wpa_s->current_ssid->ssid, r->ssid_len) ==
- 0 &&
- memcmp(r->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
- r->rsn_ie_len > 0 &&
- wpa_parse_wpa_ie(wpa_s, r->rsn_ie, r->rsn_ie_len, &ie) ==
- 0 &&
- (ie.capabilities & WPA_CAPABILITY_PREAUTH) &&
- pmksa_cache_get(wpa_s, r->bssid, NULL) == NULL) {
- /* Give less priority to candidates found from normal
- * scan results. */
- pmksa_candidate_add(wpa_s, r->bssid,
- PMKID_CANDIDATE_PRIO_SCAN);
- }
+ memcpy(sm->ap_wpa_ie, ie, len);
+ sm->ap_wpa_ie_len = len;
}
+
+ return 0;
}
-#else /* IEEE8021X_EAPOL */
-static void rsn_preauth_candidate_process(struct wpa_supplicant *wpa_s)
+/**
+ * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSN IE used in Beacon / Probe Response
+ * frame.
+ */
+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);
+ 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);
+ if (sm->ap_rsn_ie == NULL)
+ return -1;
+
+ memcpy(sm->ap_rsn_ie, ie, len);
+ sm->ap_rsn_ie_len = len;
+ }
+
+ return 0;
}
-#endif /* IEEE8021X_EAPOL */
+
+/**
+ * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @data: Pointer to data area for parsing results
+ * Returns: 0 on success, -1 if IE is not known, or -2 on parsing failure
+ *
+ * Parse the contents of the own WPA or RSN IE from (Re)AssocReq and write the
+ * parsed data into data.
+ */
+int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data)
+{
+ if (sm == NULL || sm->assoc_wpa_ie == NULL) {
+ wpa_printf(MSG_DEBUG, "WPA: No WPA/RSN IE available from "
+ "association info");
+ return -1;
+ }
+ if (wpa_parse_wpa_ie(sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, data))
+ return -2;
+ return 0;
+}
diff --git a/contrib/wpa_supplicant/wpa.h b/contrib/wpa_supplicant/wpa.h
index a4f3f55..6b59d43 100644
--- a/contrib/wpa_supplicant/wpa.h
+++ b/contrib/wpa_supplicant/wpa.h
@@ -1,6 +1,22 @@
+/*
+ * wpa_supplicant - WPA definitions
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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_H
#define WPA_H
+#include "defs.h"
+
#define BIT(n) (1 << (n))
struct ieee802_1x_hdr {
@@ -23,70 +39,6 @@ enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
EAPOL_KEY_TYPE_WPA = 254 };
-#define IEEE8021X_REPLAY_COUNTER_LEN 8
-#define IEEE8021X_KEY_SIGN_LEN 16
-#define IEEE8021X_KEY_IV_LEN 16
-
-#define IEEE8021X_KEY_INDEX_FLAG 0x80
-#define IEEE8021X_KEY_INDEX_MASK 0x03
-
-struct ieee802_1x_eapol_key {
- u8 type;
- u16 key_length;
- /* does not repeat within the life of the keying material used to
- * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
- u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
- u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
- u8 key_index; /* key flag in the most significant bit:
- * 0 = broadcast (default key),
- * 1 = unicast (key mapping key); key index is in the
- * 7 least significant bits */
- /* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
- * the key */
- u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
-
- /* followed by key: if packet body length = 44 + key length, then the
- * key field (of key_length bytes) contains the key in encrypted form;
- * if packet body length = 44, key field is absent and key_length
- * 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));
-
-
-#define WPA_NONCE_LEN 32
-#define WPA_REPLAY_COUNTER_LEN 8
-
-struct wpa_eapol_key {
- u8 type;
- u16 key_info;
- u16 key_length;
- u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
- u8 key_nonce[WPA_NONCE_LEN];
- u8 key_iv[16];
- u8 key_rsc[8];
- u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
- u8 key_mic[16];
- u16 key_data_length;
- /* followed by key_data_length bytes of key_data */
-} __attribute__ ((packed));
-
-#define WPA_KEY_INFO_TYPE_MASK (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 */
-/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
-#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
-#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
-#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
-#define WPA_KEY_INFO_TXRX BIT(6) /* group */
-#define WPA_KEY_INFO_ACK BIT(7)
-#define WPA_KEY_INFO_MIC BIT(8)
-#define WPA_KEY_INFO_SECURE BIT(9)
-#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_CAPABILITY_PREAUTH BIT(0)
#define GENERIC_INFO_ELEM 0xdd
@@ -109,4 +61,226 @@ enum {
REASON_CIPHER_SUITE_REJECTED = 24
};
+#define PMKID_LEN 16
+
+
+struct wpa_sm;
+struct wpa_ssid;
+struct eapol_sm;
+struct wpa_config_blob;
+
+struct wpa_sm_ctx {
+ void *ctx; /* pointer to arbitrary upper level context */
+
+ void (*set_state)(void *ctx, wpa_states state);
+ wpa_states (*get_state)(void *ctx);
+ void (*req_scan)(void *ctx, int sec, int usec);
+ void (*deauthenticate)(void * ctx, int reason_code);
+ void (*disassociate)(void *ctx, int reason_code);
+ int (*set_key)(void *ctx, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len);
+ void (*scan)(void *eloop_ctx, void *timeout_ctx);
+ struct wpa_ssid * (*get_ssid)(void *ctx);
+ int (*get_bssid)(void *ctx, u8 *bssid);
+ int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
+ size_t len);
+ int (*get_beacon_ie)(void *ctx);
+ void (*cancel_auth_timeout)(void *ctx);
+ u8 * (*alloc_eapol)(void *ctx, u8 type, const void *data, u16 data_len,
+ size_t *msg_len, void **data_pos);
+ int (*add_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
+ int (*remove_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
+ void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
+ const struct wpa_config_blob * (*get_config_blob)(void *ctx,
+ const char *name);
+};
+
+
+enum wpa_sm_conf_params {
+ RSNA_PMK_LIFETIME /* dot11RSNAConfigPMKLifetime */,
+ RSNA_PMK_REAUTH_THRESHOLD /* dot11RSNAConfigPMKReauthThreshold */,
+ RSNA_SA_TIMEOUT /* dot11RSNAConfigSATimeout */,
+ WPA_PARAM_PROTO,
+ WPA_PARAM_PAIRWISE,
+ WPA_PARAM_GROUP,
+ WPA_PARAM_KEY_MGMT
+};
+
+struct wpa_ie_data {
+ int proto;
+ int pairwise_cipher;
+ int group_cipher;
+ int key_mgmt;
+ int capabilities;
+ int num_pmkid;
+ const u8 *pmkid;
+};
+
+#ifndef CONFIG_NO_WPA
+
+struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx);
+void wpa_sm_deinit(struct wpa_sm *sm);
+void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
+void wpa_sm_notify_disassoc(struct wpa_sm *sm);
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len);
+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
+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_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,
+ size_t *wpa_ie_len);
+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
+
+int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
+ unsigned int value);
+unsigned int wpa_sm_get_param(struct wpa_sm *sm,
+ enum wpa_sm_conf_params param);
+
+int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+ int verbose);
+
+void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
+
+int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
+ struct wpa_ie_data *data);
+
+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);
+
+#else /* CONFIG_NO_WPA */
+
+static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
+{
+ return (struct wpa_sm *) 1;
+}
+
+static inline void wpa_sm_deinit(struct wpa_sm *sm)
+{
+}
+
+static inline void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
+{
+}
+
+static inline void wpa_sm_notify_disassoc(struct wpa_sm *sm)
+{
+}
+
+static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk,
+ size_t pmk_len)
+{
+}
+
+static inline void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
+{
+}
+
+static inline void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth)
+{
+}
+
+static inline void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
+{
+}
+
+static inline void wpa_sm_set_config(struct wpa_sm *sm,
+ struct wpa_ssid *config)
+{
+}
+
+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_eapol(struct wpa_sm *sm, struct eapol_sm *eapol)
+{
+}
+
+static inline int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
+static inline int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm,
+ u8 *wpa_ie,
+ size_t *wpa_ie_len)
+{
+ return -1;
+}
+
+static inline int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
+static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie,
+ size_t len)
+{
+ return -1;
+}
+
+static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
+{
+ return 0;
+}
+
+static inline int wpa_sm_set_param(struct wpa_sm *sm,
+ enum wpa_sm_conf_params param,
+ unsigned int value)
+{
+ return -1;
+}
+
+static inline unsigned int wpa_sm_get_param(struct wpa_sm *sm,
+ enum wpa_sm_conf_params param)
+{
+ return 0;
+}
+
+static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
+ size_t buflen, int verbose)
+{
+ return 0;
+}
+
+static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
+ int pairwise)
+{
+}
+
+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 int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ return -1;
+}
+
+static inline int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm,
+ struct wpa_ie_data *data)
+{
+ return -1;
+}
+
+#endif /* CONFIG_NO_WPA */
+
#endif /* WPA_H */
diff --git a/contrib/wpa_supplicant/wpa_cli.c b/contrib/wpa_supplicant/wpa_cli.c
index 8582fae..c274723 100644
--- a/contrib/wpa_supplicant/wpa_cli.c
+++ b/contrib/wpa_supplicant/wpa_cli.c
@@ -18,6 +18,8 @@
#include <signal.h>
#include <unistd.h>
#include <dirent.h>
+#include <errno.h>
+#include <sys/time.h>
#ifdef CONFIG_READLINE
#include <readline/readline.h>
#include <readline/history.h>
@@ -104,7 +106,29 @@ static const char *commands_help =
" preauthenticate <BSSID> = force preauthentication\n"
" identity <network id> <identity> = configure identity for an SSID\n"
" password <network id> <password> = configure password for an SSID\n"
+" new_password <network id> <password> = change password for an SSID\n"
+" pin <network id> <pin> = configure pin for an SSID\n"
" otp <network id> <password> = configure one-time-password for an SSID\n"
+" passphrase <network id> <passphrase> = configure private key passphrase\n"
+" for an SSID\n"
+" bssid <network id> <BSSID> = set preferred BSSID for an SSID\n"
+" list_networks = list configured networks\n"
+" select_network <network id> = select a network (disable others)\n"
+" enable_network <network id> = enable a network\n"
+" disable_network <network id> = disable a network\n"
+" add_network = add a network\n"
+" remove_network <network id> = remove a network\n"
+" set_network <network id> <variable> <value> = set network variables "
+"(shows\n"
+" list of variables when run without arguments)\n"
+" get_network <network id> <variable> = get network variables\n"
+" save_config = save the current configuration\n"
+" disconnect = disconnect and wait for reassociate command before "
+"connecting\n"
+" scan = request new BSS scan\n"
+" scan_results = get latest scan results\n"
+" get_capability <eap/pairwise/group/key_mgmt/proto/auth_alg> = "
+"get capabilies\n"
" terminate = terminate wpa_supplicant\n"
" quit = exit wpa_cli\n";
@@ -113,14 +137,21 @@ static int wpa_cli_quit = 0;
static int wpa_cli_attached = 0;
static const char *ctrl_iface_dir = "/var/run/wpa_supplicant";
static char *ctrl_ifname = NULL;
+static const char *pid_file = NULL;
+static const char *action_file = NULL;
static void usage(void)
{
- printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hv] "
- "[command..]\n"
+ printf("wpa_cli [-p<path to ctrl sockets>] [-i<ifname>] [-hvB] "
+ "[-a<action file>] \\\n"
+ " [-P<pid file>] [-g<global ctrl>] [command..]\n"
" -h = help (show this usage text)\n"
" -v = shown version information\n"
+ " -a = run in daemon mode executing the action file based on "
+ "events from\n"
+ " wpa_supplicant\n"
+ " -B = run a daemon in the background\n"
" default path: /var/run/wpa_supplicant\n"
" default interface: first interface found in socket path\n"
"%s",
@@ -264,6 +295,12 @@ static void wpa_cli_show_variables(void)
"seconds)\n"
" EAPOL::maxStart (EAPOL state machine maximum start "
"attempts)\n");
+ printf(" dot11RSNAConfigPMKLifetime (WPA/WPA2 PMK lifetime in "
+ "seconds)\n"
+ " dot11RSNAConfigPMKReauthThreshold (WPA/WPA2 reauthentication"
+ " threshold\n\tpercentage)\n"
+ " dot11RSNAConfigSATimeout (WPA/WPA2 timeout for completing "
+ "security\n\tassociation in seconds)\n");
}
@@ -356,7 +393,7 @@ 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, "CTRL-RSP-IDENTITY-%s:%s",
+ 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]);
@@ -378,7 +415,7 @@ 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, "CTRL-RSP-PASSWORD-%s:%s",
+ 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]);
@@ -387,6 +424,51 @@ static int wpa_cli_cmd_password(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_new_password(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256], *pos, *end;
+ int i;
+
+ if (argc < 2) {
+ printf("Invalid NEW_PASSWORD command: needs two arguments "
+ "(network id and password)\n");
+ return 0;
+ }
+
+ 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]);
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_pin(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256], *pos, *end;
+ int i;
+
+ if (argc < 2) {
+ printf("Invalid PIN command: needs two arguments "
+ "(network id and pin)\n");
+ return 0;
+ }
+
+ 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]);
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
{
char cmd[256], *pos, *end;
@@ -400,7 +482,7 @@ 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, "CTRL-RSP-OTP-%s:%s",
+ 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]);
@@ -409,6 +491,246 @@ static int wpa_cli_cmd_otp(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
+static int wpa_cli_cmd_passphrase(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256], *pos, *end;
+ int i;
+
+ if (argc < 2) {
+ printf("Invalid PASSPHRASE command: needs two arguments "
+ "(network id and passphrase)\n");
+ return 0;
+ }
+
+ 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]);
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_bssid(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ char cmd[256], *pos, *end;
+ int i;
+
+ if (argc < 2) {
+ printf("Invalid BSSID command: needs two arguments (network "
+ "id and BSSID)\n");
+ return 0;
+ }
+
+ 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]);
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_list_networks(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "LIST_NETWORKS");
+}
+
+
+static int wpa_cli_cmd_select_network(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[32];
+
+ if (argc < 1) {
+ printf("Invalid SELECT_NETWORK command: needs one argument "
+ "(network id)\n");
+ return 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "SELECT_NETWORK %s", argv[0]);
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_enable_network(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[32];
+
+ if (argc < 1) {
+ printf("Invalid ENABLE_NETWORK command: needs one argument "
+ "(network id)\n");
+ return 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %s", argv[0]);
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_disable_network(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[32];
+
+ if (argc < 1) {
+ printf("Invalid DISABLE_NETWORK command: needs one argument "
+ "(network id)\n");
+ return 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "DISABLE_NETWORK %s", argv[0]);
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_add_network(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "ADD_NETWORK");
+}
+
+
+static int wpa_cli_cmd_remove_network(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[32];
+
+ if (argc < 1) {
+ printf("Invalid REMOVE_NETWORK command: needs one argument "
+ "(network id)\n");
+ return 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %s", argv[0]);
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static void wpa_cli_show_network_variables(void)
+{
+ printf("set_network variables:\n"
+ " ssid (network name, SSID)\n"
+ " psk (WPA passphrase or pre-shared key)\n"
+ " key_mgmt (key management protocol)\n"
+ " identity (EAP identity)\n"
+ " password (EAP password)\n"
+ " ...\n"
+ "\n"
+ "Note: Values are entered in the same format as the "
+ "configuration file is using,\n"
+ "i.e., strings values need to be inside double quotation "
+ "marks.\n"
+ "For example: set_network 1 ssid \"network name\"\n"
+ "\n"
+ "Please see wpa_supplicant.conf documentation for full list "
+ "of\navailable variables.\n");
+}
+
+
+static int wpa_cli_cmd_set_network(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+
+ if (argc == 0) {
+ wpa_cli_show_network_variables();
+ return 0;
+ }
+
+ if (argc != 3) {
+ printf("Invalid SET_NETWORK command: needs three arguments\n"
+ "(network id, variable name, and value)\n");
+ return 0;
+ }
+
+ if (snprintf(cmd, sizeof(cmd), "SET_NETWORK %s %s %s",
+ argv[0], argv[1], argv[2]) >= sizeof(cmd) - 1) {
+ printf("Too long SET_NETWORK command.\n");
+ return 0;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_get_network(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+
+ if (argc == 0) {
+ wpa_cli_show_network_variables();
+ return 0;
+ }
+
+ if (argc != 2) {
+ printf("Invalid GET_NETWORK command: needs two arguments\n"
+ "(network id and variable name)\n");
+ return 0;
+ }
+
+ if (snprintf(cmd, sizeof(cmd), "GET_NETWORK %s %s",
+ argv[0], argv[1]) >= sizeof(cmd) - 1) {
+ printf("Too long GET_NETWORK command.\n");
+ return 0;
+ }
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_disconnect(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "DISCONNECT");
+}
+
+
+static int wpa_cli_cmd_save_config(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "SAVE_CONFIG");
+}
+
+
+static int wpa_cli_cmd_scan(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "SCAN");
+}
+
+
+static int wpa_cli_cmd_scan_results(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ return wpa_ctrl_command(ctrl, "SCAN_RESULTS");
+}
+
+
+static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[64];
+
+ if (argc != 1) {
+ printf("Invalid GET_CAPABILITY command: needs one argument\n");
+ return 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_CAPABILITY %s", argv[0]);
+
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
static void wpa_cli_list_interfaces(struct wpa_ctrl *ctrl)
{
struct dirent *dent;
@@ -473,6 +795,46 @@ static int wpa_cli_cmd_terminate(struct wpa_ctrl *ctrl, int argc,
}
+static int wpa_cli_cmd_interface_add(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[256];
+
+ if (argc < 1) {
+ printf("Invalid INTERFACE_ADD command: needs at least one "
+ "argument (interface name)\n"
+ "All arguments: ifname confname driver ctrl_interface "
+ "driver_param\n");
+ return 0;
+ }
+
+ /*
+ * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
+ * <driver_param>
+ */
+ 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] : "");
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_interface_remove(struct wpa_ctrl *ctrl, int argc,
+ char *argv[])
+{
+ char cmd[128];
+
+ if (argc != 1) {
+ printf("Invalid INTERFACE_REMOVE command: needs one argument "
+ "(interface name)\n");
+ return 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "INTERFACE_REMOVE %s", argv[0]);
+ return wpa_ctrl_command(ctrl, cmd);
+}
+
+
struct wpa_cli_cmd {
const char *cmd;
int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -495,9 +857,28 @@ static struct wpa_cli_cmd wpa_cli_commands[] = {
{ "preauthenticate", wpa_cli_cmd_preauthenticate },
{ "identity", wpa_cli_cmd_identity },
{ "password", wpa_cli_cmd_password },
+ { "new_password", wpa_cli_cmd_new_password },
+ { "pin", wpa_cli_cmd_pin },
{ "otp", wpa_cli_cmd_otp },
+ { "passphrase", wpa_cli_cmd_passphrase },
+ { "bssid", wpa_cli_cmd_bssid },
+ { "list_networks", wpa_cli_cmd_list_networks },
+ { "select_network", wpa_cli_cmd_select_network },
+ { "enable_network", wpa_cli_cmd_enable_network },
+ { "disable_network", wpa_cli_cmd_disable_network },
+ { "add_network", wpa_cli_cmd_add_network },
+ { "remove_network", wpa_cli_cmd_remove_network },
+ { "set_network", wpa_cli_cmd_set_network },
+ { "get_network", wpa_cli_cmd_get_network },
+ { "save_config", wpa_cli_cmd_save_config },
+ { "disconnect", wpa_cli_cmd_disconnect },
+ { "scan", wpa_cli_cmd_scan },
+ { "scan_results", wpa_cli_cmd_scan_results },
+ { "get_capability", wpa_cli_cmd_get_capability },
{ "reconfigure", wpa_cli_cmd_reconfigure },
{ "terminate", wpa_cli_cmd_terminate },
+ { "interface_add", wpa_cli_cmd_interface_add },
+ { "interface_remove", wpa_cli_cmd_interface_remove },
{ NULL, NULL }
};
@@ -512,6 +893,11 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
while (cmd->cmd) {
if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
match = cmd;
+ if (strcasecmp(cmd->cmd, argv[0]) == 0) {
+ /* we have an exact match */
+ count = 1;
+ break;
+ }
count++;
}
cmd++;
@@ -536,7 +922,63 @@ static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
}
-static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
+static int str_match(const char *a, const char *b)
+{
+ return strncmp(a, b, strlen(b)) == 0;
+}
+
+
+static int wpa_cli_exec(const char *program, const char *arg1,
+ const char *arg2)
+{
+ char *cmd;
+ size_t len;
+
+ len = strlen(program) + strlen(arg1) + strlen(arg2) + 3;
+ cmd = malloc(len);
+ if (cmd == NULL)
+ return -1;
+ snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
+ system(cmd);
+ free(cmd);
+
+ return 0;
+}
+
+
+static void wpa_cli_action_process(const char *msg)
+{
+ const char *pos;
+
+ pos = msg;
+ if (*pos == '<') {
+ /* skip priority */
+ pos = strchr(pos, '>');
+ if (pos)
+ pos++;
+ else
+ pos = msg;
+ }
+
+ if (str_match(pos, WPA_EVENT_CONNECTED)) {
+ wpa_cli_exec(action_file, ctrl_ifname, "CONNECTED");
+ } else if (str_match(pos, WPA_EVENT_DISCONNECTED)) {
+ 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;
+ }
+}
+
+
+static void wpa_cli_action_cb(char *msg, size_t len)
+{
+ wpa_cli_action_process(msg);
+}
+
+
+static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
+ int action_monitor)
{
int first = 1;
if (ctrl_conn == NULL)
@@ -546,10 +988,14 @@ static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read)
size_t len = sizeof(buf) - 1;
if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
buf[len] = '\0';
- if (in_read && first)
- printf("\n");
- first = 0;
- printf("%s\n", buf);
+ if (action_monitor)
+ wpa_cli_action_process(buf);
+ else {
+ if (in_read && first)
+ printf("\n");
+ first = 0;
+ printf("%s\n", buf);
+ }
} else {
printf("Could not read pending message.\n");
break;
@@ -620,7 +1066,7 @@ static void wpa_cli_interactive(void)
#endif /* CONFIG_READLINE */
do {
- wpa_cli_recv_pending(ctrl_conn, 0);
+ wpa_cli_recv_pending(ctrl_conn, 0, 0);
#ifndef CONFIG_NATIVE_WINDOWS
alarm(1);
#endif /* CONFIG_NATIVE_WINDOWS */
@@ -663,6 +1109,11 @@ static void wpa_cli_interactive(void)
argc++;
if (argc == max_args)
break;
+ if (*pos == '"') {
+ char *pos2 = strrchr(pos, '"');
+ if (pos2)
+ pos = pos2 + 1;
+ }
while (*pos != '\0' && *pos != ' ')
pos++;
if (*pos == ' ')
@@ -687,7 +1138,8 @@ static void wpa_cli_interactive(void)
while (*p == ' ' || *p == '\t')
p++;
if (strncasecmp(p, "pa", 2) == 0 ||
- strncasecmp(p, "o", 1) == 0) {
+ strncasecmp(p, "o", 1) == 0 ||
+ strncasecmp(p, "n", 1)) {
h = remove_history(where_history());
if (h) {
free(h->line);
@@ -706,9 +1158,58 @@ static void wpa_cli_interactive(void)
}
-static void wpa_cli_terminate(int sig)
+static void wpa_cli_action(struct wpa_ctrl *ctrl)
+{
+ fd_set rfds;
+ int fd, res;
+ struct timeval tv;
+ char buf[16];
+ size_t len;
+
+ fd = wpa_ctrl_get_fd(ctrl);
+
+ while (!wpa_cli_quit) {
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+ tv.tv_sec = 2;
+ tv.tv_usec = 0;
+ res = select(fd + 1, &rfds, NULL, NULL, &tv);
+ if (res < 0 && errno != EINTR) {
+ perror("select");
+ break;
+ }
+
+ if (FD_ISSET(fd, &rfds))
+ wpa_cli_recv_pending(ctrl, 0, 1);
+ else {
+ /* verify that connection is still working */
+ 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) {
+ printf("wpa_supplicant did not reply to PING "
+ "command - exiting\n");
+ break;
+ }
+ }
+ }
+}
+
+
+static void wpa_cli_cleanup(void)
{
wpa_cli_close_connection();
+ if (pid_file)
+ unlink(pid_file);
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+static void wpa_cli_terminate(int sig)
+{
+ wpa_cli_cleanup();
exit(0);
}
@@ -735,7 +1236,7 @@ static void wpa_cli_alarm(int sig)
}
}
if (ctrl_conn)
- wpa_cli_recv_pending(ctrl_conn, 1);
+ wpa_cli_recv_pending(ctrl_conn, 1, 0);
alarm(1);
}
#endif /* CONFIG_NATIVE_WINDOWS */
@@ -746,6 +1247,9 @@ 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;
@@ -756,10 +1260,19 @@ int main(int argc, char *argv[])
#endif /* CONFIG_NATIVE_WINDOWS */
for (;;) {
- c = getopt(argc, argv, "hi:p:v");
+ c = getopt(argc, argv, "a:Bg:hi:p:P:v");
if (c < 0)
break;
switch (c) {
+ case 'a':
+ action_file = optarg;
+ break;
+ case 'B':
+ daemonize = 1;
+ break;
+ case 'g':
+ global = optarg;
+ break;
case 'h':
usage();
return 0;
@@ -772,18 +1285,30 @@ int main(int argc, char *argv[])
case 'p':
ctrl_iface_dir = optarg;
break;
+ case 'P':
+ pid_file = optarg;
+ break;
default:
usage();
return -1;
}
}
- interactive = argc == optind;
+ interactive = (argc == optind) && (action_file == NULL);
if (interactive)
printf("%s\n\n%s\n\n", wpa_cli_version, wpa_cli_license);
- for (;;) {
+ if (global) {
+ ctrl_conn = wpa_ctrl_open(global);
+ if (ctrl_conn == NULL) {
+ perror("Failed to connect to wpa_supplicant - "
+ "wpa_ctrl_open");
+ return -1;
+ }
+ }
+
+ for (; !global;) {
if (ctrl_ifname == NULL) {
struct dirent *dent;
DIR *dir = opendir(ctrl_iface_dir);
@@ -828,23 +1353,39 @@ int main(int argc, char *argv[])
signal(SIGALRM, wpa_cli_alarm);
#endif /* CONFIG_NATIVE_WINDOWS */
- if (interactive) {
+ if (interactive || action_file) {
if (wpa_ctrl_attach(ctrl_conn) == 0) {
wpa_cli_attached = 1;
} else {
printf("Warning: Failed to attach to "
"wpa_supplicant.\n");
+ if (!interactive)
+ return -1;
+ }
+ }
+
+ if (daemonize && daemon(0, 0)) {
+ perror("daemon");
+ return -1;
+ }
+
+ if (pid_file) {
+ f = fopen(pid_file, "w");
+ if (f) {
+ fprintf(f, "%u\n", getpid());
+ fclose(f);
}
+ }
+
+ if (interactive)
wpa_cli_interactive();
- } else
+ else if (action_file)
+ wpa_cli_action(ctrl_conn);
+ else
wpa_request(ctrl_conn, argc - optind, &argv[optind]);
free(ctrl_ifname);
- wpa_cli_close_connection();
-
-#ifdef CONFIG_NATIVE_WINDOWS
- WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
+ wpa_cli_cleanup();
return 0;
}
diff --git a/contrib/wpa_supplicant/wpa_ctrl.c b/contrib/wpa_supplicant/wpa_ctrl.c
index 631c628..98e0669 100644
--- a/contrib/wpa_supplicant/wpa_ctrl.c
+++ b/contrib/wpa_supplicant/wpa_ctrl.c
@@ -1,5 +1,5 @@
/*
- * WPA Supplicant - wpa_supplicant control interface library
+ * wpa_supplicant/hostapd control interface library
* Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,7 @@
#include <sys/time.h>
#ifndef CONFIG_NATIVE_WINDOWS
#include <sys/socket.h>
+#include <netinet/in.h>
#include <sys/un.h>
#endif /* CONFIG_NATIVE_WINDOWS */
@@ -29,6 +30,15 @@
#endif /* CONFIG_NATIVE_WINDOWS */
+/**
+ * struct wpa_ctrl - Internal structure for control interface library
+ *
+ * This structure is used by the wpa_supplicant/hostapd control interface
+ * library to store internal data. Programs using the library should not touch
+ * this data directly. They can only use the pointer to the data structure as
+ * an identifier for the control interface connection and use this as one of
+ * the arguments for most of the control interface library functions.
+ */
struct wpa_ctrl {
int s;
#ifdef CONFIG_CTRL_IFACE_UDP
@@ -72,7 +82,7 @@ struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
ctrl->dest.sin_family = AF_INET;
ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
- ctrl->dest.sin_port = htons(9877);
+ ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
sizeof(ctrl->dest)) < 0) {
perror("connect");
@@ -123,7 +133,7 @@ void wpa_ctrl_close(struct wpa_ctrl *ctrl)
}
-int wpa_ctrl_request(struct wpa_ctrl *ctrl, char *cmd, size_t cmd_len,
+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))
{
@@ -152,7 +162,7 @@ int wpa_ctrl_request(struct wpa_ctrl *ctrl, char *cmd, size_t cmd_len,
if (msg_cb) {
/* Make sure the message is nul
* terminated. */
- if (res == *reply_len)
+ if ((size_t) res == *reply_len)
res = (*reply_len) - 1;
reply[res] = '\0';
msg_cb(reply, res);
diff --git a/contrib/wpa_supplicant/wpa_ctrl.h b/contrib/wpa_supplicant/wpa_ctrl.h
index 48b088a..c8fa48d 100644
--- a/contrib/wpa_supplicant/wpa_ctrl.h
+++ b/contrib/wpa_supplicant/wpa_ctrl.h
@@ -1,15 +1,185 @@
+/*
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_CTRL_H
#define WPA_CTRL_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* wpa_supplicant control interface - fixed message prefixes */
+
+/** Interactive request for identity/password/pin */
+#define WPA_CTRL_REQ "CTRL-REQ-"
+
+/** Response to identity/password/pin request */
+#define WPA_CTRL_RSP "CTRL-RSP-"
+
+/* Event messages with fixed prefix */
+/** Authentication completed successfully and data connection enabled */
+#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
+/** Disconnected, data connection is not available */
+#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
+/** wpa_supplicant is exiting */
+#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
+/** Password change was completed successfully */
+#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
+/** EAP-Request/Notification received */
+#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
+/** EAP authentication started (EAP-Request/Identity received) */
+#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
+/** EAP method selected */
+#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
+/** EAP authentication completed successfully */
+#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
+/** EAP authentication failed (EAP-Failure received) */
+#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+
+
+/* wpa_supplicant/hostapd control interface access */
+
+/**
+ * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
+ * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
+ * Returns: Pointer to abstract control interface data or %NULL on failure
+ *
+ * This function is used to open a control interface to wpa_supplicant/hostapd.
+ * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
+ * is configured in wpa_supplicant/hostapd and other programs using the control
+ * interface need to use matching path configuration.
+ */
struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
+
+
+/**
+ * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ *
+ * This function is used to close a control interface.
+ */
void wpa_ctrl_close(struct wpa_ctrl *ctrl);
-int wpa_ctrl_request(struct wpa_ctrl *ctrl, char *cmd, size_t cmd_len,
+
+
+/**
+ * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @cmd: Command; usually, ASCII text, e.g., "PING"
+ * @cmd_len: Length of the cmd in bytes
+ * @reply: Buffer for the response
+ * @reply_len: Reply buffer length
+ * @msg_cb: Callback function for unsolicited messages or %NULL if not used
+ * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
+ *
+ * This function is used to send commands to wpa_supplicant/hostapd. Received
+ * response will be written to reply and reply_len is set to the actual length
+ * of the reply. This function will block for up to two seconds while waiting
+ * for the reply. If unsolicited messages are received, the blocking time may
+ * be longer.
+ *
+ * msg_cb can be used to register a callback function that will be called for
+ * unsolicited messages received while waiting for the command response. These
+ * messages may be received if wpa_ctrl_request() is called at the same time as
+ * wpa_supplicant/hostapd is sending such a message. This can happen only if
+ * the program has used wpa_ctrl_attach() to register itself as a monitor for
+ * event messages. Alternatively to msg_cb, programs can register two control
+ * interface connections and use one of them for commands and the other one for
+ * receiving event messages, in other words, call wpa_ctrl_attach() only for
+ * the control interface connection that will be used for event messages.
+ */
+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));
+
+
+/**
+ * wpa_ctrl_attach - Register as an event monitor for the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function registers the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
+ * control interface connection starts receiving event messages that can be
+ * read with wpa_ctrl_recv().
+ */
int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_detach - Unregister event monitor from the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function unregisters the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events, i.e., cancels the registration done with
+ * wpa_ctrl_attach().
+ */
int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_recv - Receive a pending control interface message
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @reply: Buffer for the message data
+ * @reply_len: Length of the reply buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function will receive a pending control interface message. This
+ * function will block if no messages are available. The received response will
+ * be written to reply and reply_len is set to the actual length of the reply.
+ * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
+ * must have been used to register the control interface as an event monitor.
+ */
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
+ *
+ * This function will check whether there are any pending control interface
+ * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
+ * only used for event messages, i.e., wpa_ctrl_attach() must have been used to
+ * register the control interface as an event monitor.
+ */
int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_get_fd - Get file descriptor used by the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: File descriptor used for the connection
+ *
+ * This function can be used to get the file descriptor that is used for the
+ * control interface connection. The returned value can be used, e.g., with
+ * select() while waiting for multiple events.
+ *
+ * The returned file descriptor must not be used directly for sending or
+ * receiving packets; instead, the library functions wpa_ctrl_request() and
+ * wpa_ctrl_recv() must be used for this.
+ */
int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
+#ifdef CONFIG_CTRL_IFACE_UDP
+#define WPA_CTRL_IFACE_PORT 9877
+#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* WPA_CTRL_H */
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui
new file mode 100644
index 0000000..3735fb7
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui
@@ -0,0 +1,125 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>EventHistory</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>EventHistory</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>533</width>
+ <height>285</height>
+ </rect>
+ </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>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="resizePolicy">
+ <enum>Manual</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>NoSelection</enum>
+ </property>
+ <property name="resizeMode">
+ <enum>LastColumn</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout30</cstring>
+ </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>
+ </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>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui.h b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui.h
new file mode 100644
index 0000000..cb2caab
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+void EventHistory::init()
+{
+}
+
+
+void EventHistory::destroy()
+{
+}
+
+
+void EventHistory::addEvents(WpaMsgList msgs)
+{
+ WpaMsgList::iterator it;
+ for (it = msgs.begin(); it != msgs.end(); it++) {
+ addEvent(*it);
+ }
+}
+
+
+void EventHistory::addEvent(WpaMsg msg)
+{
+ Q3ListViewItem *item;
+ item = new Q3ListViewItem(eventListView,
+ msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"),
+ msg.getMsg());
+ if (item == NULL)
+ return;
+ eventListView->setSelected(item, false);
+}
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/main.cpp b/contrib/wpa_supplicant/wpa_gui-qt4/main.cpp
new file mode 100644
index 0000000..a78473a
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/main.cpp
@@ -0,0 +1,30 @@
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+#include <qapplication.h>
+#include "wpagui.h"
+
+int main( int argc, char ** argv )
+{
+ QApplication a( 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;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ w.show();
+ a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
+ ret = a.exec();
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui
new file mode 100644
index 0000000..1f98372
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui
@@ -0,0 +1,455 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>NetworkConfig</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>NetworkConfig</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>413</height>
+ </rect>
+ </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>
+ </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>
+ </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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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>
+ </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>
+ </spacer>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>addButton</cstring>
+ </property>
+ <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>
+ </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>
+ <tabstop>ssidEdit</tabstop>
+ <tabstop>authSelect</tabstop>
+ <tabstop>encrSelect</tabstop>
+ <tabstop>pskEdit</tabstop>
+ <tabstop>eapSelect</tabstop>
+ <tabstop>identityEdit</tabstop>
+ <tabstop>passwordEdit</tabstop>
+ <tabstop>cacertEdit</tabstop>
+ <tabstop>wep0Radio</tabstop>
+ <tabstop>wep1Radio</tabstop>
+ <tabstop>wep2Radio</tabstop>
+ <tabstop>wep3Radio</tabstop>
+ <tabstop>wep0Edit</tabstop>
+ <tabstop>wep1Edit</tabstop>
+ <tabstop>wep2Edit</tabstop>
+ <tabstop>wep3Edit</tabstop>
+ <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>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui.h b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui.h
new file mode 100644
index 0000000..5e87462
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui.h
@@ -0,0 +1,513 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+
+enum {
+ AUTH_NONE = 0,
+ AUTH_IEEE8021X = 1,
+ AUTH_WPA_PSK = 2,
+ AUTH_WPA_EAP = 3,
+ AUTH_WPA2_PSK = 4,
+ AUTH_WPA2_EAP = 5
+};
+
+void NetworkConfig::init()
+{
+ wpagui = NULL;
+ new_network = false;
+}
+
+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())
+ 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())
+ 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();
+ 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);
+}
+
+
+void NetworkConfig::paramsFromConfig( int network_id )
+{
+ int i;
+
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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';
+ pskEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
+ reply_len = sizeof(reply);
+ 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);
+ 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';
+ passwordEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
+ reply_len = sizeof(reply);
+ 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);
+ 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++) {
+ 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[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ 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;
+ }
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
+ reply_len = sizeof(reply);
+ 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/scanresults.ui b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui
new file mode 100644
index 0000000..66c8b4b
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui
@@ -0,0 +1,179 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ScanResults</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ScanResults</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>452</width>
+ <height>225</height>
+ </rect>
+ </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>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout24</cstring>
+ </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>
+ </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>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui.h b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui.h
new file mode 100644
index 0000000..530d2e6
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+void ScanResults::init()
+{
+ wpagui = NULL;
+}
+
+
+void ScanResults::destroy()
+{
+ delete timer;
+}
+
+
+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/setup-mingw-cross-compiling b/contrib/wpa_supplicant/wpa_gui-qt4/setup-mingw-cross-compiling
new file mode 100755
index 0000000..e173b00
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/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-qt4/userdatarequest.ui b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui
new file mode 100644
index 0000000..c3d545f
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui
@@ -0,0 +1,163 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>UserDataRequest</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>UserDataRequest</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>216</width>
+ <height>103</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Authentication credentials required</string>
+ </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>
+ </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>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui.h b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui.h
new file mode 100644
index 0000000..4b47ccd
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+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/wpa_gui.pro b/contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
new file mode 100644
index 0000000..a1ad0ee
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
@@ -0,0 +1,41 @@
+TEMPLATE = app
+LANGUAGE = C++
+
+CONFIG += qt warn_on release
+
+win32 {
+ LIBS += -lws2_32 -static
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_UDP
+} else:win32-g++ {
+ # cross compilation to win32
+ LIBS += -lws2_32 -static
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_UDP
+}
+
+INCLUDEPATH += . ..
+
+HEADERS += wpamsg.h
+
+SOURCES += main.cpp \
+ ../wpa_ctrl.c
+
+FORMS = wpagui.ui \
+ eventhistory.ui \
+ scanresults.ui \
+ userdatarequest.ui \
+ networkconfig.ui
+
+
+unix {
+ UI_DIR = .ui
+ MOC_DIR = .moc
+ OBJECTS_DIR = .obj
+}
+
+
+
+#The following line was inserted by qt3to4
+QT += qt3support
+#The following line was inserted by qt3to4
+CONFIG += uic3
+
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui
new file mode 100644
index 0000000..7097bfa
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui
@@ -0,0 +1,464 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>WpaGui</class>
+<widget class="QMainWindow">
+ <property name="name">
+ <cstring>WpaGui</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>279</width>
+ <height>308</height>
+ </rect>
+ </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>
+ </property>
+ <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>
+ </property>
+ </widget>
+ <widget class="QFrame" row="2" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </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>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <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>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <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>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <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>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textStatus</cstring>
+ </property>
+ <property name="text">
+ <string></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>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>textAuthentication</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>textEncryption</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>textSsid</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1">
+ <property name="name">
+ <cstring>textBssid</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="1">
+ <property name="name">
+ <cstring>textIpAddress</cstring>
+ </property>
+ <property name="text">
+ <string></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>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>connectButton</cstring>
+ </property>
+ <property name="text">
+ <string>Connect</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="2">
+ <property name="name">
+ <cstring>disconnectButton</cstring>
+ </property>
+ <property name="text">
+ <string>Disconnect</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="3">
+ <property name="name">
+ <cstring>scanButton</cstring>
+ </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>
+ </property>
+ <property name="menuText">
+ <string>E&amp;xit</string>
+ </property>
+ <property name="accel">
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+</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>
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui.h b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui.h
new file mode 100644
index 0000000..58760e7
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui.h
@@ -0,0 +1,651 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+
+#ifdef __MINGW32__
+/* Need to get getopt() */
+#include <unistd.h>
+#endif
+
+
+void WpaGui::init()
+{
+ 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();
+}
+
+
+void WpaGui::destroy()
+{
+ 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::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;
+
+ 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");
+#else /* CONFIG_CTRL_IFACE_UDP */
+ struct dirent *dent;
+ DIR *dir = opendir(ctrl_iface_dir);
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+ 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_iface = strdup(dent->d_name);
+ break;
+ }
+ closedir(dir);
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+ }
+
+ if (ctrl_iface == NULL)
+ return -1;
+
+ 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);
+
+ 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;
+ }
+
+ msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
+ QSocketNotifier::Read, this);
+ connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
+
+ adapterSelect->clear();
+ adapterSelect->insertItem(ctrl_iface);
+ adapterSelect->setCurrentItem(0);
+
+ 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-2005,\n"
+ "Jouni Malinen <jkmaline@cc.hut.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;
+
+ 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 (wpa_ctrl_pending(monitor_conn)) {
+ 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();
+}
diff --git a/contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h b/contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h
new file mode 100644
index 0000000..0808e1f
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h
@@ -0,0 +1,28 @@
+#ifndef WPAMSG_H
+#define WPAMSG_H
+
+#include <QDateTime>
+#include <QLinkedList>
+
+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; }
+
+private:
+ QString msg;
+ int priority;
+ QDateTime timestamp;
+};
+
+typedef QLinkedList<WpaMsg> WpaMsgList;
+
+#endif /* WPAMSG_H */
diff --git a/contrib/wpa_supplicant/wpa_gui/eventhistory.ui b/contrib/wpa_supplicant/wpa_gui/eventhistory.ui
new file mode 100644
index 0000000..3735fb7
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/eventhistory.ui
@@ -0,0 +1,125 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>EventHistory</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>EventHistory</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>533</width>
+ <height>285</height>
+ </rect>
+ </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>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="resizePolicy">
+ <enum>Manual</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>NoSelection</enum>
+ </property>
+ <property name="resizeMode">
+ <enum>LastColumn</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout30</cstring>
+ </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>
+ </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>
diff --git a/contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h b/contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h
new file mode 100644
index 0000000..8d8fa48
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+void EventHistory::init()
+{
+}
+
+
+void EventHistory::destroy()
+{
+}
+
+
+void EventHistory::addEvents(WpaMsgList msgs)
+{
+ WpaMsgList::iterator it;
+ for (it = msgs.begin(); it != msgs.end(); it++) {
+ addEvent(*it);
+ }
+}
+
+
+void EventHistory::addEvent(WpaMsg msg)
+{
+ QListViewItem *item;
+ item = new QListViewItem(eventListView,
+ msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"),
+ msg.getMsg());
+ if (item == NULL)
+ return;
+ eventListView->setSelected(item, false);
+}
diff --git a/contrib/wpa_supplicant/wpa_gui/main.cpp b/contrib/wpa_supplicant/wpa_gui/main.cpp
new file mode 100644
index 0000000..a78473a
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/main.cpp
@@ -0,0 +1,30 @@
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+#include <qapplication.h>
+#include "wpagui.h"
+
+int main( int argc, char ** argv )
+{
+ QApplication a( 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;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ w.show();
+ a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
+ ret = a.exec();
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ return ret;
+}
diff --git a/contrib/wpa_supplicant/wpa_gui/networkconfig.ui b/contrib/wpa_supplicant/wpa_gui/networkconfig.ui
new file mode 100644
index 0000000..1f98372
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/networkconfig.ui
@@ -0,0 +1,455 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>NetworkConfig</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>NetworkConfig</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>413</height>
+ </rect>
+ </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>
+ </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>
+ </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">
+ <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">
+ <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">
+ <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">
+ <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">
+ <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>
+ </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>
+ </spacer>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>addButton</cstring>
+ </property>
+ <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>
+ </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>
+ <tabstop>ssidEdit</tabstop>
+ <tabstop>authSelect</tabstop>
+ <tabstop>encrSelect</tabstop>
+ <tabstop>pskEdit</tabstop>
+ <tabstop>eapSelect</tabstop>
+ <tabstop>identityEdit</tabstop>
+ <tabstop>passwordEdit</tabstop>
+ <tabstop>cacertEdit</tabstop>
+ <tabstop>wep0Radio</tabstop>
+ <tabstop>wep1Radio</tabstop>
+ <tabstop>wep2Radio</tabstop>
+ <tabstop>wep3Radio</tabstop>
+ <tabstop>wep0Edit</tabstop>
+ <tabstop>wep1Edit</tabstop>
+ <tabstop>wep2Edit</tabstop>
+ <tabstop>wep3Edit</tabstop>
+ <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>
diff --git a/contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h b/contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h
new file mode 100644
index 0000000..c03260b
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h
@@ -0,0 +1,513 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+
+enum {
+ AUTH_NONE = 0,
+ AUTH_IEEE8021X = 1,
+ AUTH_WPA_PSK = 2,
+ AUTH_WPA_EAP = 3,
+ AUTH_WPA2_PSK = 4,
+ AUTH_WPA2_EAP = 5
+};
+
+void NetworkConfig::init()
+{
+ wpagui = NULL;
+ new_network = false;
+}
+
+void NetworkConfig::paramsFromScanResults(QListViewItem *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())
+ 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())
+ 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();
+ 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);
+}
+
+
+void NetworkConfig::paramsFromConfig( int network_id )
+{
+ int i;
+
+ 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);
+ 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);
+ 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);
+ 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);
+ 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);
+ 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';
+ pskEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
+ reply_len = sizeof(reply);
+ 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);
+ 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';
+ passwordEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
+ reply_len = sizeof(reply);
+ 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);
+ 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++) {
+ 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[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ 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;
+ }
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
+ reply_len = sizeof(reply);
+ 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/scanresults.ui b/contrib/wpa_supplicant/wpa_gui/scanresults.ui
new file mode 100644
index 0000000..66c8b4b
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/scanresults.ui
@@ -0,0 +1,179 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ScanResults</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ScanResults</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>452</width>
+ <height>225</height>
+ </rect>
+ </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>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout24</cstring>
+ </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>
+ </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>
diff --git a/contrib/wpa_supplicant/wpa_gui/scanresults.ui.h b/contrib/wpa_supplicant/wpa_gui/scanresults.ui.h
new file mode 100644
index 0000000..61555b5
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/scanresults.ui.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+void ScanResults::init()
+{
+ wpagui = NULL;
+}
+
+
+void ScanResults::destroy()
+{
+ delete timer;
+}
+
+
+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 QListViewItem(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( QListViewItem * 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/userdatarequest.ui b/contrib/wpa_supplicant/wpa_gui/userdatarequest.ui
new file mode 100644
index 0000000..c3d545f
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/userdatarequest.ui
@@ -0,0 +1,163 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>UserDataRequest</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>UserDataRequest</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>216</width>
+ <height>103</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Authentication credentials required</string>
+ </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>
+ </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>
diff --git a/contrib/wpa_supplicant/wpa_gui/userdatarequest.ui.h b/contrib/wpa_supplicant/wpa_gui/userdatarequest.ui.h
new file mode 100644
index 0000000..4b47ccd
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/userdatarequest.ui.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+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/wpa_gui.pro b/contrib/wpa_supplicant/wpa_gui/wpa_gui.pro
new file mode 100644
index 0000000..7134c7d
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/wpa_gui.pro
@@ -0,0 +1,31 @@
+TEMPLATE = app
+LANGUAGE = C++
+
+CONFIG += qt warn_on release
+
+# For Windows build:
+#LIBS += -lws2_32 -static
+#DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_UDP
+
+INCLUDEPATH += ..
+
+HEADERS += wpamsg.h
+
+SOURCES += main.cpp \
+ ../wpa_ctrl.c
+
+FORMS = wpagui.ui \
+ eventhistory.ui \
+ scanresults.ui \
+ userdatarequest.ui \
+ networkconfig.ui
+
+
+unix {
+ UI_DIR = .ui
+ MOC_DIR = .moc
+ OBJECTS_DIR = .obj
+}
+
+
+
diff --git a/contrib/wpa_supplicant/wpa_gui/wpagui.ui b/contrib/wpa_supplicant/wpa_gui/wpagui.ui
new file mode 100644
index 0000000..7097bfa
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/wpagui.ui
@@ -0,0 +1,464 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>WpaGui</class>
+<widget class="QMainWindow">
+ <property name="name">
+ <cstring>WpaGui</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>279</width>
+ <height>308</height>
+ </rect>
+ </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>
+ </property>
+ <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>
+ </property>
+ </widget>
+ <widget class="QFrame" row="2" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </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>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <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>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <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>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <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>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textStatus</cstring>
+ </property>
+ <property name="text">
+ <string></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>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>textAuthentication</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>textEncryption</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>textSsid</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1">
+ <property name="name">
+ <cstring>textBssid</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="1">
+ <property name="name">
+ <cstring>textIpAddress</cstring>
+ </property>
+ <property name="text">
+ <string></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>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>connectButton</cstring>
+ </property>
+ <property name="text">
+ <string>Connect</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="2">
+ <property name="name">
+ <cstring>disconnectButton</cstring>
+ </property>
+ <property name="text">
+ <string>Disconnect</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="3">
+ <property name="name">
+ <cstring>scanButton</cstring>
+ </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>
+ </property>
+ <property name="menuText">
+ <string>E&amp;xit</string>
+ </property>
+ <property name="accel">
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+ <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>
+</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>
diff --git a/contrib/wpa_supplicant/wpa_gui/wpagui.ui.h b/contrib/wpa_supplicant/wpa_gui/wpagui.ui.h
new file mode 100644
index 0000000..58760e7
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/wpagui.ui.h
@@ -0,0 +1,651 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+
+#ifdef __MINGW32__
+/* Need to get getopt() */
+#include <unistd.h>
+#endif
+
+
+void WpaGui::init()
+{
+ 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();
+}
+
+
+void WpaGui::destroy()
+{
+ 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::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;
+
+ 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");
+#else /* CONFIG_CTRL_IFACE_UDP */
+ struct dirent *dent;
+ DIR *dir = opendir(ctrl_iface_dir);
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+ 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_iface = strdup(dent->d_name);
+ break;
+ }
+ closedir(dir);
+ }
+#endif /* CONFIG_CTRL_IFACE_UDP */
+ }
+
+ if (ctrl_iface == NULL)
+ return -1;
+
+ 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);
+
+ 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;
+ }
+
+ msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
+ QSocketNotifier::Read, this);
+ connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
+
+ adapterSelect->clear();
+ adapterSelect->insertItem(ctrl_iface);
+ adapterSelect->setCurrentItem(0);
+
+ 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-2005,\n"
+ "Jouni Malinen <jkmaline@cc.hut.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;
+
+ 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 (wpa_ctrl_pending(monitor_conn)) {
+ 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();
+}
diff --git a/contrib/wpa_supplicant/wpa_gui/wpamsg.h b/contrib/wpa_supplicant/wpa_gui/wpamsg.h
new file mode 100644
index 0000000..2984017
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_gui/wpamsg.h
@@ -0,0 +1,27 @@
+#ifndef WPAMSG_H
+#define WPAMSG_H
+
+#include <qdatetime.h>
+
+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; }
+
+private:
+ QString msg;
+ int priority;
+ 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
new file mode 100644
index 0000000..4442832
--- /dev/null
+++ b/contrib/wpa_supplicant/wpa_i.h
@@ -0,0 +1,197 @@
+/*
+ * wpa_supplicant - Internal WPA state machine definitions
+ * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.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_I_H
+#define WPA_I_H
+
+#define WPA_NONCE_LEN 32
+#define WPA_REPLAY_COUNTER_LEN 8
+
+
+struct rsn_pmksa_candidate;
+
+/**
+ * struct wpa_ptk - WPA Pairwise Transient Key
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ */
+struct wpa_ptk {
+ u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
+ u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
+ u8 tk1[16]; /* Temporal Key 1 (TK1) */
+ union {
+ u8 tk2[16]; /* Temporal Key 2 (TK2) */
+ struct {
+ u8 tx_mic_key[8];
+ 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 wpa_sm - Internal WPA state machine data
+ */
+struct wpa_sm {
+ u8 pmk[PMK_LEN];
+ size_t pmk_len;
+ struct wpa_ptk ptk, tptk;
+ int ptk_set, tptk_set;
+ u8 snonce[WPA_NONCE_LEN];
+ u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
+ int renew_snonce;
+ u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
+ int rx_replay_counter_set;
+ u8 request_counter[WPA_REPLAY_COUNTER_LEN];
+
+ 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_candidate *pmksa_candidates;
+
+ struct l2_packet_data *l2_preauth;
+ u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or
+ * 00:00:00:00:00:00 if no pre-auth is
+ * in progress */
+ struct eapol_sm *preauth_eapol;
+
+ struct wpa_sm_ctx *ctx;
+
+ void *scard_ctx; /* context for smartcard callbacks */
+ int fast_reauth; /* whether EAP fast re-authentication is enabled */
+
+ struct wpa_ssid *cur_ssid;
+
+ u8 own_addr[ETH_ALEN];
+ const char *ifname;
+ u8 bssid[ETH_ALEN];
+
+ unsigned int dot11RSNAConfigPMKLifetime;
+ unsigned int dot11RSNAConfigPMKReauthThreshold;
+ unsigned int dot11RSNAConfigSATimeout;
+
+ unsigned int dot11RSNA4WayHandshakeFailures;
+
+ /* Selected configuration (based on Beacon/ProbeResp WPA IE) */
+ unsigned int proto;
+ unsigned int pairwise_cipher;
+ unsigned int group_cipher;
+ unsigned int key_mgmt;
+
+ 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;
+};
+
+
+static inline void wpa_sm_set_state(struct wpa_sm *sm, wpa_states state)
+{
+ sm->ctx->set_state(sm->ctx->ctx, state);
+}
+
+static inline wpa_states wpa_sm_get_state(struct wpa_sm *sm)
+{
+ return sm->ctx->get_state(sm->ctx->ctx);
+}
+
+static inline void wpa_sm_req_scan(struct wpa_sm *sm, int sec, int usec)
+{
+ sm->ctx->req_scan(sm->ctx->ctx, sec, usec);
+}
+
+static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code)
+{
+ sm->ctx->deauthenticate(sm->ctx->ctx, reason_code);
+}
+
+static inline void wpa_sm_disassociate(struct wpa_sm *sm, int reason_code)
+{
+ sm->ctx->disassociate(sm->ctx->ctx, reason_code);
+}
+
+static inline int wpa_sm_set_key(struct wpa_sm *sm, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
+ seq, seq_len, key, key_len);
+}
+
+static inline struct wpa_ssid * wpa_sm_get_ssid(struct wpa_sm *sm)
+{
+ return sm->ctx->get_ssid(sm->ctx->ctx);
+}
+
+static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid)
+{
+ return sm->ctx->get_bssid(sm->ctx->ctx, bssid);
+}
+
+static inline int wpa_sm_ether_send(struct wpa_sm *sm, const u8 *dest,
+ u16 proto, const u8 *buf, size_t len)
+{
+ return sm->ctx->ether_send(sm->ctx->ctx, dest, proto, buf, len);
+}
+
+static inline int wpa_sm_get_beacon_ie(struct wpa_sm *sm)
+{
+ return sm->ctx->get_beacon_ie(sm->ctx->ctx);
+}
+
+static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm)
+{
+ sm->ctx->cancel_auth_timeout(sm->ctx->ctx);
+}
+
+static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
+ const void *data, u16 data_len,
+ size_t *msg_len, void **data_pos)
+{
+ return sm->ctx->alloc_eapol(sm->ctx->ctx, type, data, data_len,
+ msg_len, data_pos);
+}
+
+static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, const u8 *bssid,
+ const u8 *pmkid)
+{
+ return sm->ctx->add_pmkid(sm->ctx->ctx, bssid, pmkid);
+}
+
+static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid,
+ const u8 *pmkid)
+{
+ return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid);
+}
+
+#endif /* WPA_I_H */
diff --git a/contrib/wpa_supplicant/wpa_passphrase.c b/contrib/wpa_supplicant/wpa_passphrase.c
index 5a8203b..2a68cb5 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-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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,15 +23,36 @@ int main(int argc, char *argv[])
{
unsigned char psk[32];
int i;
- char *ssid, *passphrase;
+ char *ssid, *passphrase, buf[64], *pos;
- if (argc != 3) {
- printf("usage: wpa_passphrase <ssid> <passphrase>\n");
+ if (argc < 2) {
+ printf("usage: wpa_passphrase <ssid> [passphrase]\n"
+ "\nIf passphrase is left out, it will be read from "
+ "stdin\n");
return 1;
}
ssid = argv[1];
- passphrase = argv[2];
+
+ if (argc > 2) {
+ passphrase = argv[2];
+ } else {
+ printf("# reading passphrase from stdin\n");
+ if (fgets(buf, sizeof(buf), stdin) == NULL) {
+ printf("Failed to read passphrase\n");
+ return 1;
+ }
+ buf[sizeof(buf) - 1] = '\0';
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\r' || *pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ passphrase = buf;
+ }
if (strlen(passphrase) < 8 || strlen(passphrase) > 63) {
printf("Passphrase must be 8..63 characters\n");
diff --git a/contrib/wpa_supplicant/wpa_supplicant.c b/contrib/wpa_supplicant/wpa_supplicant.c
index 0c57143..8e5ea44 100644
--- a/contrib/wpa_supplicant/wpa_supplicant.c
+++ b/contrib/wpa_supplicant/wpa_supplicant.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.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,27 +17,16 @@
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
-#include <sys/time.h>
#include <time.h>
#include <signal.h>
-#include <sys/types.h>
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/socket.h>
-#include <sys/un.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-#include <unistd.h>
-#include <ctype.h>
#ifndef CONFIG_NATIVE_WINDOWS
#include <netinet/in.h>
#endif /* CONFIG_NATIVE_WINDOWS */
-#include <fcntl.h>
-#define OPENSSL_DISABLE_OLD_DES_SUPPORT
#include "common.h"
#include "eapol_sm.h"
#include "eap.h"
#include "wpa.h"
-#include "driver.h"
#include "eloop.h"
#include "wpa_supplicant.h"
#include "config.h"
@@ -46,12 +35,14 @@
#include "ctrl_iface.h"
#include "pcsc_funcs.h"
#include "version.h"
+#include "preauth.h"
+#include "wpa_ctrl.h"
-static const char *wpa_supplicant_version =
+const char *wpa_supplicant_version =
"wpa_supplicant v" VERSION_STR "\n"
-"Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
+"Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi> and contributors";
-static const char *wpa_supplicant_license =
+const char *wpa_supplicant_license =
"This program is free software. You can distribute it and/or modify it\n"
"under the terms of the GNU General Public License version 2.\n"
"\n"
@@ -63,7 +54,8 @@ static const char *wpa_supplicant_license =
#endif /* EAP_TLS_FUNCS */
;
-static const char *wpa_supplicant_full_license =
+#ifndef CONFIG_NO_STDOUT_DEBUG
+const char *wpa_supplicant_full_license =
"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"
@@ -107,25 +99,15 @@ static const char *wpa_supplicant_full_license =
"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
"\n";
+#endif /* CONFIG_NO_STDOUT_DEBUG */
extern struct wpa_driver_ops *wpa_supplicant_drivers[];
-static void wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s);
-static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
- int wait_for_interface);
-static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *bss,
- struct wpa_ssid *ssid);
-static int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *bss,
- struct wpa_ssid *ssid,
- u8 *wpa_ie, int *wpa_ie_len);
-
-
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, ...)
{
@@ -152,13 +134,69 @@ void wpa_msg(struct wpa_supplicant *wpa_s, int level, char *fmt, ...)
}
-int wpa_eapol_send(void *ctx, int type, u8 *buf, size_t len)
+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)
+{
+ struct ieee802_1x_hdr *hdr;
+
+ *msg_len = sizeof(*hdr) + data_len;
+ hdr = malloc(*msg_len);
+ if (hdr == NULL)
+ return NULL;
+
+ hdr->version = wpa_s->conf->eapol_version;
+ hdr->type = type;
+ hdr->length = htons(data_len);
+
+ if (data)
+ memcpy(hdr + 1, data, data_len);
+ else
+ memset(hdr + 1, 0, data_len);
+
+ if (data_pos)
+ *data_pos = hdr + 1;
+
+ return (u8 *) hdr;
+}
+
+
+/**
+ * wpa_ether_send - Send Ethernet frame
+ * @wpa_s: pointer to wpa_supplicant data
+ * @dest: Destination MAC address
+ * @proto: Ethertype
+ * @buf: Frame payload starting from IEEE 802.1X header
+ * @len: Frame payload length
+ */
+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);
+ }
+
+ return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+}
+
+
+#ifdef IEEE8021X_EAPOL
+/**
+ * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator
+ * @ctx: pointer to wpa_supplicant data
+ * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*)
+ * @buf: EAPOL payload (after IEEE 802.1X header)
+ * @len: EAPOL payload length
+ *
+ * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame
+ * to the current Authenticator.
+ */
+static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
+ size_t len)
{
struct wpa_supplicant *wpa_s = ctx;
u8 *msg, *dst, bssid[ETH_ALEN];
size_t msglen;
- struct l2_ethhdr *ethhdr;
- struct ieee802_1x_hdr *hdr;
int res;
/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
@@ -175,7 +213,8 @@ int wpa_eapol_send(void *ctx, int type, u8 *buf, size_t len)
return -1;
}
- if (wpa_s->cur_pmksa && type == IEEE802_1X_TYPE_EAPOL_START) {
+ if (pmksa_cache_get_current(wpa_s->wpa) &&
+ type == IEEE802_1X_TYPE_EAPOL_START) {
/* Trying to use PMKSA caching - do not send EAPOL-Start frames
* since they will trigger full EAPOL authentication. */
wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
@@ -205,64 +244,12 @@ int wpa_eapol_send(void *ctx, int type, u8 *buf, size_t len)
dst = wpa_s->bssid;
}
- msglen = sizeof(*ethhdr) + sizeof(*hdr) + len;
- msg = malloc(msglen);
+ msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL);
if (msg == NULL)
return -1;
- ethhdr = (struct l2_ethhdr *) msg;
- memcpy(ethhdr->h_dest, dst, ETH_ALEN);
- memcpy(ethhdr->h_source, wpa_s->own_addr, ETH_ALEN);
- ethhdr->h_proto = htons(ETH_P_EAPOL);
-
- hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
- hdr->version = wpa_s->conf->eapol_version;
- hdr->type = type;
- hdr->length = htons(len);
-
- memcpy((u8 *) (hdr + 1), buf, len);
-
wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen);
- res = l2_packet_send(wpa_s->l2, msg, msglen);
- free(msg);
- return res;
-}
-
-
-int wpa_eapol_send_preauth(void *ctx, int type, u8 *buf, size_t len)
-{
- struct wpa_supplicant *wpa_s = ctx;
- u8 *msg;
- size_t msglen;
- struct l2_ethhdr *ethhdr;
- struct ieee802_1x_hdr *hdr;
- int res;
-
- /* TODO: could add l2_packet_sendmsg that allows fragments to avoid
- * extra copy here */
-
- if (wpa_s->l2_preauth == NULL)
- return -1;
-
- msglen = sizeof(*ethhdr) + sizeof(*hdr) + len;
- msg = malloc(msglen);
- if (msg == NULL)
- return -1;
-
- ethhdr = (struct l2_ethhdr *) msg;
- memcpy(ethhdr->h_dest, wpa_s->preauth_bssid, ETH_ALEN);
- memcpy(ethhdr->h_source, wpa_s->own_addr, ETH_ALEN);
- ethhdr->h_proto = htons(ETH_P_RSN_PREAUTH);
-
- hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
- hdr->version = wpa_s->conf->eapol_version;
- hdr->type = type;
- hdr->length = htons(len);
-
- memcpy((u8 *) (hdr + 1), buf, len);
-
- wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
- res = l2_packet_send(wpa_s->l2_preauth, msg, msglen);
+ res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
free(msg);
return res;
}
@@ -279,15 +266,33 @@ int wpa_eapol_send_preauth(void *ctx, int type, u8 *buf, size_t len)
* Returns 0 on success or < 0 on error.
*/
static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
- u8 *key, size_t keylen)
+ const u8 *key, size_t keylen)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_s->keys_cleared = 0;
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);
}
+#endif /* IEEE8021X_EAPOL */
+
+
+#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
+static void wpa_supplicant_set_config_blob(void *ctx,
+ struct wpa_config_blob *blob)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ wpa_config_set_blob(wpa_s->conf, blob);
+}
+
+
+static const struct wpa_config_blob *
+wpa_supplicant_get_config_blob(void *ctx, const char *name)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ return wpa_config_get_blob(wpa_s->conf, name);
+}
+#endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */
/* Configure default/group WEP key for static WEP */
@@ -295,7 +300,6 @@ static int wpa_set_wep_key(void *ctx, int set_tx, int keyidx, const u8 *key,
size_t keylen)
{
struct wpa_supplicant *wpa_s = ctx;
- wpa_s->keys_cleared = 0;
return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
(u8 *) "\xff\xff\xff\xff\xff\xff",
keyidx, set_tx, (u8 *) "", 0, key, keylen);
@@ -351,17 +355,24 @@ static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
}
-void wpa_supplicant_notify_eapol_done(void *ctx)
+#ifdef IEEE8021X_EAPOL
+static void wpa_supplicant_notify_eapol_done(void *ctx)
{
struct wpa_supplicant *wpa_s = ctx;
wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
- eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
- wpa_supplicant_cancel_auth_timeout(wpa_s);
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
+ wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
+ } else {
+ eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+ }
}
+#endif /* IEEE8021X_EAPOL */
-static struct wpa_blacklist *
-wpa_blacklist_get(struct wpa_supplicant *wpa_s, const u8 *bssid)
+struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
+ const u8 *bssid)
{
struct wpa_blacklist *e;
@@ -376,7 +387,7 @@ wpa_blacklist_get(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
-static int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e;
@@ -404,7 +415,7 @@ static int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
-static int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
+int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
{
struct wpa_blacklist *e, *prev = NULL;
@@ -428,7 +439,7 @@ static int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
}
-static void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
+void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
{
struct wpa_blacklist *e, *prev;
@@ -483,6 +494,7 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
MAC2STR(wpa_s->bssid));
wpa_blacklist_add(wpa_s, wpa_s->bssid);
+ wpa_sm_notify_disassoc(wpa_s->wpa);
wpa_supplicant_disassociate(wpa_s, REASON_DEAUTH_LEAVING);
wpa_s->reassociate = 1;
wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -492,6 +504,10 @@ static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
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)
+ return;
+
wpa_msg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
"%d usec", sec, usec);
eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
@@ -507,7 +523,7 @@ void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
}
-static void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
+void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
{
struct eapol_config eapol_conf;
struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -533,15 +549,22 @@ static void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
eapol_conf.required_keys |=
EAPOL_REQUIRE_KEY_BROADCAST;
}
+
+ if (wpa_s->conf && wpa_s->driver &&
+ strcmp(wpa_s->driver->name, "wired") == 0) {
+ eapol_conf.required_keys = 0;
+ }
}
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);
}
-static void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
+void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid)
{
int i;
@@ -549,15 +572,9 @@ static void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
else
wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie = NULL;
- wpa_s->ap_wpa_ie_len = 0;
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie = NULL;
- wpa_s->ap_rsn_ie_len = 0;
- free(wpa_s->assoc_wpa_ie);
- wpa_s->assoc_wpa_ie = NULL;
- wpa_s->assoc_wpa_ie_len = 0;
+ wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
+ wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+ 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;
@@ -573,40 +590,12 @@ static void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
}
}
- wpa_s->cur_pmksa = NULL;
-}
-
-
-static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
-{
- struct wpa_ssid *ssid;
-
- if (wpa_s->conf->ap_scan == 1)
- return 0;
-
- ssid = wpa_supplicant_get_ssid(wpa_s);
- if (ssid == NULL) {
- wpa_printf(MSG_INFO, "No network configuration found for the "
- "current AP");
- return -1;
- }
-
- wpa_printf(MSG_DEBUG, "Network configuration found for the current "
- "AP");
- if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
- WPA_KEY_MGMT_WPA_NONE)) {
- u8 wpa_ie[80];
- int wpa_ie_len;
- wpa_supplicant_set_suites(wpa_s, NULL, ssid,
- wpa_ie, &wpa_ie_len);
- } else {
- wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
- }
-
- wpa_s->current_ssid = ssid;
- wpa_supplicant_initiate_eapol(wpa_s);
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
+ 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);
- return 0;
+ pmksa_cache_clear_current(wpa_s->wpa);
}
@@ -614,50 +603,41 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
{
scard_deinit(wpa_s->scard);
wpa_s->scard = NULL;
+ wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
l2_packet_deinit(wpa_s->l2);
wpa_s->l2 = NULL;
-#ifdef CONFIG_XSUPPLICANT_IFACE
- if (wpa_s->dot1x_s > -1) {
- close(wpa_s->dot1x_s);
- wpa_s->dot1x_s = -1;
- }
-#endif /* CONFIG_XSUPPLICANT_IFACE */
-
wpa_supplicant_ctrl_iface_deinit(wpa_s);
if (wpa_s->conf != NULL) {
wpa_config_free(wpa_s->conf);
wpa_s->conf = NULL;
}
- free(wpa_s->assoc_wpa_ie);
- wpa_s->assoc_wpa_ie = NULL;
-
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie = NULL;
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie = NULL;
-
free(wpa_s->confname);
wpa_s->confname = NULL;
+ wpa_sm_set_eapol(wpa_s->wpa, NULL);
eapol_sm_deinit(wpa_s->eapol);
wpa_s->eapol = NULL;
- rsn_preauth_deinit(wpa_s);
+ rsn_preauth_deinit(wpa_s->wpa);
- pmksa_candidate_free(wpa_s);
- pmksa_cache_free(wpa_s);
+ 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);
wpa_s->scan_results = NULL;
wpa_s->num_scan_results = 0;
+
+ wpa_supplicant_cancel_scan(wpa_s);
}
-static void wpa_clear_keys(struct wpa_supplicant *wpa_s, u8 *addr)
+void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
{
u8 *bcast = (u8 *) "\xff\xff\xff\xff\xff\xff";
@@ -686,341 +666,65 @@ static void wpa_clear_keys(struct wpa_supplicant *wpa_s, u8 *addr)
}
-static void wpa_supplicant_stop_countermeasures(void *eloop_ctx,
- void *sock_ctx)
-{
- struct wpa_supplicant *wpa_s = eloop_ctx;
-
- if (wpa_s->countermeasures) {
- wpa_s->countermeasures = 0;
- wpa_drv_set_countermeasures(wpa_s, 0);
- wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped");
- wpa_supplicant_req_scan(wpa_s, 0, 0);
- }
-}
-
-
-static void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
-{
- wpa_s->wpa_state = WPA_DISCONNECTED;
- memset(wpa_s->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)
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
-}
-
-
-static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
-{
- struct wpa_ie_data ie;
- int i;
-
- if (wpa_parse_wpa_ie(wpa_s, wpa_s->assoc_wpa_ie,
- wpa_s->assoc_wpa_ie_len, &ie) < 0 ||
- ie.pmkid == NULL)
- return;
-
- for (i = 0; i < ie.num_pmkid; i++) {
- wpa_s->cur_pmksa = pmksa_cache_get(wpa_s, NULL,
- ie.pmkid + i * PMKID_LEN);
- if (wpa_s->cur_pmksa) {
- eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
- break;
- }
- }
-
- wpa_printf(MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from PMKSA "
- "cache", wpa_s->cur_pmksa ? "" : "not ");
-}
-
-
-static void wpa_supplicant_add_pmkid_candidate(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+const char * wpa_supplicant_state_txt(int state)
{
- if (data == NULL) {
- wpa_printf(MSG_DEBUG, "RSN: No data in PMKID candidate event");
- return;
- }
- wpa_printf(MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR
- " index=%d preauth=%d",
- MAC2STR(data->pmkid_candidate.bssid),
- data->pmkid_candidate.index,
- data->pmkid_candidate.preauth);
-
- if (!data->pmkid_candidate.preauth) {
- wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
- "preauth flag");
- return;
- }
-
- pmksa_candidate_add(wpa_s, data->pmkid_candidate.bssid,
- data->pmkid_candidate.index);
-}
-
-
-static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
-{
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
- return 0;
-
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
- wpa_s->current_ssid &&
- !(wpa_s->current_ssid->eapol_flags &
- (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
- EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
- /* IEEE 802.1X, but not using dynamic WEP keys (i.e., either
- * plaintext or static WEP keys). */
- return 0;
+ switch (state) {
+ case WPA_DISCONNECTED:
+ return "DISCONNECTED";
+ case WPA_INACTIVE:
+ return "INACTIVE";
+ case WPA_SCANNING:
+ return "SCANNING";
+ case WPA_ASSOCIATING:
+ return "ASSOCIATING";
+ case WPA_ASSOCIATED:
+ return "ASSOCIATED";
+ case WPA_4WAY_HANDSHAKE:
+ return "4WAY_HANDSHAKE";
+ case WPA_GROUP_HANDSHAKE:
+ return "GROUP_HANDSHAKE";
+ case WPA_COMPLETED:
+ return "COMPLETED";
+ default:
+ return "UNKNOWN";
}
-
- return 1;
}
-static void wpa_supplicant_associnfo(struct wpa_supplicant *wpa_s,
- union wpa_event_data *data)
+void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_states state)
{
- int l, len;
- u8 *p;
-
- wpa_printf(MSG_DEBUG, "Association info event");
- wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
- data->assoc_info.req_ies_len);
- wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies,
- data->assoc_info.resp_ies_len);
- if (wpa_s->assoc_wpa_ie) {
- free(wpa_s->assoc_wpa_ie);
- wpa_s->assoc_wpa_ie = NULL;
- wpa_s->assoc_wpa_ie_len = 0;
- }
-
- p = data->assoc_info.req_ies;
- l = data->assoc_info.req_ies_len;
-
- /* Go through the IEs and make a copy of the WPA/RSN IE, if present. */
- while (l >= 2) {
- len = p[1] + 2;
- if (len > l) {
- wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
- p, l);
- break;
- }
- if ((p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
- (memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
- (p[0] == RSN_INFO_ELEM && p[1] >= 2)) {
- wpa_s->assoc_wpa_ie = malloc(len);
- if (wpa_s->assoc_wpa_ie == NULL)
- break;
- wpa_s->assoc_wpa_ie_len = len;
- memcpy(wpa_s->assoc_wpa_ie, p, len);
- wpa_hexdump(MSG_DEBUG, "assoc_wpa_ie",
- wpa_s->assoc_wpa_ie,
- wpa_s->assoc_wpa_ie_len);
- wpa_find_assoc_pmkid(wpa_s);
- break;
- }
- l -= len;
- p += len;
- }
-
- /* WPA/RSN IE from Beacon/ProbeResp */
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie = NULL;
- wpa_s->ap_wpa_ie_len = 0;
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie = NULL;
- wpa_s->ap_rsn_ie_len = 0;
-
- p = data->assoc_info.beacon_ies;
- l = data->assoc_info.beacon_ies_len;
-
- /* Go through the IEs and make a copy of the WPA/RSN IEs, if present.
- */
- while (l >= 2) {
- len = p[1] + 2;
- if (len > l) {
- wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies",
- p, l);
- break;
- }
- if (wpa_s->ap_wpa_ie == NULL &&
- p[0] == GENERIC_INFO_ELEM && p[1] >= 6 &&
- memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
- wpa_s->ap_wpa_ie = malloc(len);
- if (wpa_s->ap_wpa_ie) {
- memcpy(wpa_s->ap_wpa_ie, p, len);
- wpa_s->ap_wpa_ie_len = len;
- }
- }
-
- if (wpa_s->ap_rsn_ie == NULL &&
- p[0] == RSN_INFO_ELEM && p[1] >= 2) {
- wpa_s->ap_rsn_ie = malloc(len);
- if (wpa_s->ap_rsn_ie) {
- memcpy(wpa_s->ap_rsn_ie, p, len);
- wpa_s->ap_rsn_ie_len = len;
- }
-
- }
-
- l -= len;
- p += len;
- }
-
+ wpa_printf(MSG_DEBUG, "State: %s -> %s",
+ wpa_supplicant_state_txt(wpa_s->wpa_state),
+ wpa_supplicant_state_txt(state));
+ if (state == WPA_COMPLETED && wpa_s->new_connection) {
+ wpa_s->new_connection = 0;
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
+ MACSTR " completed %s",
+ MAC2STR(wpa_s->bssid), wpa_s->reassociated_connection ?
+ "(reauth)" : "(auth)");
+ wpa_s->reassociated_connection = 1;
+ } else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
+ state == WPA_ASSOCIATED) {
+ wpa_s->new_connection = 1;
+ }
+ wpa_s->wpa_state = state;
}
-void wpa_supplicant_event(struct wpa_supplicant *wpa_s, wpa_event_type event,
- union wpa_event_data *data)
+wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s)
{
- int pairwise;
- time_t now;
- u8 bssid[ETH_ALEN];
-
- switch (event) {
- case EVENT_ASSOC:
- wpa_s->wpa_state = WPA_ASSOCIATED;
- wpa_printf(MSG_DEBUG, "Association event - clear replay "
- "counter");
- memset(wpa_s->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
- wpa_s->rx_replay_counter_set = 0;
- wpa_s->renew_snonce = 1;
- if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
- 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);
- if (wpa_supplicant_dynamic_keys(wpa_s)) {
- wpa_clear_keys(wpa_s, bssid);
- }
- wpa_supplicant_select_config(wpa_s);
- }
- wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR,
- MAC2STR(bssid));
- /* Set portEnabled first to FALSE in order to get EAP state
- * machine out of the SUCCESS state and eapSuccess cleared.
- * Without this, EAPOL PAE state machine may transit to
- * AUTHENTICATING state based on obsolete eapSuccess and then
- * trigger BE_AUTH to SUCCESS and PAE to AUTHENTICATED without
- * ever giving chance to EAP state machine to reset the state.
- */
- 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)
- eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
- /* 802.1X::portControl = Auto */
- eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
- wpa_s->eapol_received = 0;
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
- wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
- wpa_supplicant_cancel_auth_timeout(wpa_s);
- } else {
- /* Timeout for receiving the first EAPOL packet */
- wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
- }
- break;
- case EVENT_DISASSOC:
- if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
- /* At least Host AP driver and a Prism3 card seemed to
- * be generating streams of disconnected events when
- * configuring IBSS for WPA-None. Ignore them for now.
- */
- wpa_printf(MSG_DEBUG, "Disconnect event - ignore in "
- "IBSS/WPA-None mode");
- break;
- }
- if (wpa_s->wpa_state >= WPA_ASSOCIATED)
- wpa_supplicant_req_scan(wpa_s, 0, 100000);
- wpa_blacklist_add(wpa_s, wpa_s->bssid);
- wpa_supplicant_mark_disassoc(wpa_s);
- wpa_msg(wpa_s, MSG_INFO, "Disconnect event - remove keys");
- if (wpa_supplicant_dynamic_keys(wpa_s)) {
- wpa_s->keys_cleared = 0;
- wpa_clear_keys(wpa_s, wpa_s->bssid);
- }
- break;
- case EVENT_MICHAEL_MIC_FAILURE:
- wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
- pairwise = (data && data->michael_mic_failure.unicast);
- wpa_supplicant_key_request(wpa_s, 1, pairwise);
- time(&now);
- if (wpa_s->last_michael_mic_error &&
- now - wpa_s->last_michael_mic_error <= 60) {
- /* initialize countermeasures */
- wpa_s->countermeasures = 1;
- wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures "
- "started");
-
- /* 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);
-
- wpa_drv_set_countermeasures(wpa_s, 1);
- wpa_supplicant_deauthenticate(
- wpa_s, REASON_MICHAEL_MIC_FAILURE);
- eloop_cancel_timeout(
- wpa_supplicant_stop_countermeasures, wpa_s,
- NULL);
- eloop_register_timeout(
- 60, 0, wpa_supplicant_stop_countermeasures,
- wpa_s, NULL);
- /* TODO: mark the AP rejected for 60 second. STA is
- * allowed to associate with another AP.. */
- }
- wpa_s->last_michael_mic_error = now;
- break;
- case EVENT_SCAN_RESULTS:
- wpa_supplicant_scan_results(wpa_s);
- break;
- case EVENT_ASSOCINFO:
- wpa_supplicant_associnfo(wpa_s, data);
- break;
- case EVENT_INTERFACE_STATUS:
- if (strcmp(wpa_s->ifname, data->interface_status.ifname) != 0)
- break;
- switch (data->interface_status.ievent) {
- case EVENT_INTERFACE_ADDED:
- if (!wpa_s->interface_removed)
- break;
- wpa_s->interface_removed = 0;
- wpa_printf(MSG_DEBUG, "Configured interface was "
- "added.");
- if (wpa_supplicant_driver_init(wpa_s, 1) < 0) {
- wpa_printf(MSG_INFO, "Failed to initialize "
- "the driver after interface was "
- "added.");
- }
- break;
- case EVENT_INTERFACE_REMOVED:
- wpa_printf(MSG_DEBUG, "Configured interface was "
- "removed.");
- wpa_s->interface_removed = 1;
- wpa_supplicant_mark_disassoc(wpa_s);
- l2_packet_deinit(wpa_s->l2);
- wpa_s->l2 = NULL;
- break;
- }
- break;
- case EVENT_PMKID_CANDIDATE:
- wpa_supplicant_add_pmkid_candidate(wpa_s, data);
- break;
- default:
- wpa_printf(MSG_INFO, "Unknown event %d", event);
- break;
- }
+ return wpa_s->wpa_state;
}
static void wpa_supplicant_terminate(int sig, void *eloop_ctx,
void *signal_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- for (wpa_s = wpa_s->head; wpa_s; wpa_s = wpa_s->next) {
- wpa_msg(wpa_s, MSG_INFO, "Signal %d received - terminating",
- sig);
+ struct wpa_global *global = eloop_ctx;
+ struct wpa_supplicant *wpa_s;
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING "- signal %d "
+ "received", sig);
}
eloop_terminate();
}
@@ -1048,8 +752,15 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
wpa_supplicant_ctrl_iface_deinit(wpa_s);
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);
- rsn_preauth_deinit(wpa_s);
+ 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)
@@ -1065,9 +776,10 @@ int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
static void wpa_supplicant_reconfig(int sig, void *eloop_ctx,
void *signal_ctx)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
+ struct wpa_global *global = eloop_ctx;
+ struct wpa_supplicant *wpa_s;
wpa_printf(MSG_DEBUG, "Signal %d received - reconfiguring", sig);
- for (wpa_s = wpa_s->head; wpa_s; wpa_s = wpa_s->next) {
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
eloop_terminate();
}
@@ -1085,6 +797,9 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
if (ssid == NULL)
return;
+ if (wpa_s->current_ssid == NULL)
+ wpa_s->current_ssid = ssid;
+ wpa_supplicant_initiate_eapol(wpa_s);
wpa_printf(MSG_DEBUG, "Already associated with a configured network - "
"generating associated event");
memset(&data, 0, sizeof(data));
@@ -1092,26 +807,40 @@ static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
}
-void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
+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;
- if (wpa_s->conf->ap_scan == 0) {
- wpa_supplicant_gen_assoc_event(wpa_s);
+ if (wpa_s->disconnected)
+ return;
+
+ enabled = 0;
+ ssid = wpa_s->conf->ssid;
+ while (ssid) {
+ if (!ssid->disabled) {
+ enabled++;
+ break;
+ }
+ ssid = ssid->next;
+ }
+ if (!enabled && !wpa_s->scan_req) {
+ wpa_printf(MSG_DEBUG, "No enabled networks - do not scan");
+ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
return;
}
+ scan_req = wpa_s->scan_req;
+ wpa_s->scan_req = 0;
- if (wpa_s->conf->ap_scan == 2) {
- ssid = wpa_s->conf->ssid;
- if (ssid == NULL)
- return;
- wpa_supplicant_associate(wpa_s, NULL, ssid);
+ if (wpa_s->conf->ap_scan == 0) {
+ wpa_supplicant_gen_assoc_event(wpa_s);
return;
}
- if (wpa_s->wpa_state == WPA_DISCONNECTED)
- wpa_s->wpa_state = WPA_SCANNING;
+ if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+ wpa_s->wpa_state == WPA_INACTIVE)
+ wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
ssid = wpa_s->conf->ssid;
if (wpa_s->prev_scan_ssid != BROADCAST_SSID_SCAN) {
@@ -1124,11 +853,30 @@ void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
}
while (ssid) {
- if (ssid->scan_ssid)
+ if (!ssid->disabled &&
+ (ssid->scan_ssid || wpa_s->conf->ap_scan == 2))
break;
ssid = ssid->next;
}
+ if (scan_req != 2 && wpa_s->conf->ap_scan == 2) {
+ /*
+ * ap_scan=2 mode - try to associate with each SSID instead of
+ * scanning for each scan_ssid=1 network.
+ */
+ if (ssid == NULL)
+ return;
+ if (ssid->next) {
+ /* Continue from the next SSID on the next attempt. */
+ wpa_s->prev_scan_ssid = ssid;
+ } else {
+ /* Start from the beginning of the SSID list. */
+ wpa_s->prev_scan_ssid = BROADCAST_SSID_SCAN;
+ }
+ wpa_supplicant_associate(wpa_s, NULL, ssid);
+ return;
+ }
+
wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)",
ssid ? "specific": "broadcast");
if (ssid) {
@@ -1184,14 +932,14 @@ static wpa_key_mgmt key_mgmt2driver(int key_mgmt)
static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid,
- struct wpa_ie_data *ie) {
- if (wpa_s->assoc_wpa_ie == NULL)
- return -1;
-
- if (wpa_parse_wpa_ie(wpa_s, wpa_s->assoc_wpa_ie,
- wpa_s->assoc_wpa_ie_len, ie)) {
- wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE from "
- "association info");
+ struct wpa_ie_data *ie)
+{
+ int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
+ if (ret) {
+ if (ret == -2) {
+ wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
+ "from association info");
+ }
return -1;
}
@@ -1220,33 +968,36 @@ static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
}
-static int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *bss,
- struct wpa_ssid *ssid,
- u8 *wpa_ie, int *wpa_ie_len)
+int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *bss,
+ struct wpa_ssid *ssid,
+ u8 *wpa_ie, size_t *wpa_ie_len)
{
struct wpa_ie_data ie;
int sel, proto;
- u8 *ap_ie;
- size_t ap_ie_len;
- if (bss && bss->rsn_ie_len && (ssid->proto & WPA_PROTO_RSN)) {
+ if (bss && bss->rsn_ie_len && (ssid->proto & WPA_PROTO_RSN) &&
+ wpa_parse_wpa_ie(bss->rsn_ie, bss->rsn_ie_len, &ie) == 0 &&
+ (ie.group_cipher & ssid->group_cipher) &&
+ (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ (ie.key_mgmt & ssid->key_mgmt)) {
wpa_msg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
proto = WPA_PROTO_RSN;
- ap_ie = bss->rsn_ie;
- ap_ie_len = bss->rsn_ie_len;
- } else if (bss) {
+ } else if (bss && bss->wpa_ie_len && (ssid->proto & WPA_PROTO_WPA) &&
+ wpa_parse_wpa_ie(bss->wpa_ie, bss->wpa_ie_len, &ie) == 0 &&
+ (ie.group_cipher & ssid->group_cipher) &&
+ (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+ (ie.key_mgmt & ssid->key_mgmt)) {
wpa_msg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
proto = WPA_PROTO_WPA;
- ap_ie = bss->wpa_ie;
- ap_ie_len = bss->wpa_ie_len;
+ } else if (bss) {
+ wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
+ return -1;
} else {
if (ssid->proto & WPA_PROTO_RSN)
proto = WPA_PROTO_RSN;
else
proto = WPA_PROTO_WPA;
- ap_ie = NULL;
- ap_ie_len = 0;
if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
memset(&ie, 0, sizeof(ie));
ie.group_cipher = ssid->group_cipher;
@@ -1257,42 +1008,17 @@ static int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
}
}
- if (ap_ie && wpa_parse_wpa_ie(wpa_s, ap_ie, ap_ie_len, &ie)) {
- wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to parse WPA IE for "
- "the selected BSS.");
- return -1;
- }
wpa_printf(MSG_DEBUG, "WPA: Selected cipher suites: group %d "
"pairwise %d key_mgmt %d",
ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt);
- wpa_s->proto = proto;
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie = NULL;
- wpa_s->ap_wpa_ie_len = 0;
- if (bss && bss->wpa_ie_len) {
- wpa_s->ap_wpa_ie = malloc(bss->wpa_ie_len);
- if (wpa_s->ap_wpa_ie == NULL) {
- wpa_printf(MSG_INFO, "WPA: malloc failed");
- return -1;
- }
- memcpy(wpa_s->ap_wpa_ie, bss->wpa_ie, bss->wpa_ie_len);
- wpa_s->ap_wpa_ie_len = bss->wpa_ie_len;
- }
-
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie = NULL;
- wpa_s->ap_rsn_ie_len = 0;
- if (bss && bss->rsn_ie_len) {
- wpa_s->ap_rsn_ie = malloc(bss->rsn_ie_len);
- if (wpa_s->ap_rsn_ie == NULL) {
- wpa_printf(MSG_INFO, "WPA: malloc failed");
- return -1;
- }
- memcpy(wpa_s->ap_rsn_ie, bss->rsn_ie, bss->rsn_ie_len);
- wpa_s->ap_rsn_ie_len = bss->rsn_ie_len;
- }
+ if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss ? bss->wpa_ie : NULL,
+ bss ? bss->wpa_ie_len : 0) ||
+ wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss ? bss->rsn_ie : NULL,
+ bss ? bss->rsn_ie_len : 0))
+ return -1;
sel = ie.group_cipher & ssid->group_cipher;
if (sel & WPA_CIPHER_CCMP) {
@@ -1344,61 +1070,44 @@ static int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
return -1;
}
- *wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie);
- if (*wpa_ie_len < 0) {
+ wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
+ 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);
+
+ 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;
}
- wpa_hexdump(MSG_DEBUG, "WPA: Own WPA IE", wpa_ie, *wpa_ie_len);
- if (wpa_s->assoc_wpa_ie == NULL) {
- /*
- * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets
- * the correct version of the IE even if PMKSA caching is
- * aborted (which would remove PMKID from IE generation).
- */
- wpa_s->assoc_wpa_ie = malloc(*wpa_ie_len);
- if (wpa_s->assoc_wpa_ie) {
- memcpy(wpa_s->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
- wpa_s->assoc_wpa_ie_len = *wpa_ie_len;
- }
- }
- if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
- wpa_s->pmk_len = PMK_LEN;
- memcpy(wpa_s->pmk, ssid->psk, PMK_LEN);
- } else if (wpa_s->cur_pmksa) {
- wpa_s->pmk_len = wpa_s->cur_pmksa->pmk_len;
- memcpy(wpa_s->pmk, wpa_s->cur_pmksa->pmk, wpa_s->pmk_len);
- } else {
- wpa_s->pmk_len = PMK_LEN;
- memset(wpa_s->pmk, 0, PMK_LEN);
-#ifdef CONFIG_XSUPPLICANT_IFACE
- wpa_s->ext_pmk_received = 0;
-#endif /* CONFIG_XSUPPLICANT_IFACE */
- }
+ if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
+ wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
+ else
+ wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
return 0;
}
-static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *bss,
- struct wpa_ssid *ssid)
+void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *bss,
+ struct wpa_ssid *ssid)
{
u8 wpa_ie[80];
- int wpa_ie_len;
+ size_t wpa_ie_len;
int use_crypt;
int algs = AUTH_ALG_OPEN_SYSTEM;
int cipher_pairwise, cipher_group;
struct wpa_driver_associate_params params;
int wep_keys_set = 0;
struct wpa_driver_capa capa;
+ int assoc_failed = 0;
wpa_s->reassociate = 0;
if (bss) {
wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
" (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
- wpa_ssid_txt(ssid->ssid, ssid->ssid_len), bss->freq);
+ wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
memset(wpa_s->bssid, 0, ETH_ALEN);
} else {
wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
@@ -1408,9 +1117,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
/* Starting new association, so clear the possibly used WPA IE from the
* previous association. */
- free(wpa_s->assoc_wpa_ie);
- wpa_s->assoc_wpa_ie = NULL;
- wpa_s->assoc_wpa_ie_len = 0;
+ wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
if (ssid->leap) {
@@ -1436,12 +1143,14 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
if (bss && (bss->wpa_ie_len || bss->rsn_ie_len) &&
(ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK))) {
- wpa_s->cur_pmksa = pmksa_cache_get(wpa_s, bss->bssid, NULL);
- if (wpa_s->cur_pmksa) {
- wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
- wpa_s->cur_pmksa->pmkid, PMKID_LEN);
+ int try_opportunistic;
+ try_opportunistic = ssid->proactive_key_caching &&
+ (ssid->proto & WPA_PROTO_RSN);
+ if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+ wpa_s->current_ssid,
+ try_opportunistic) == 0)
eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
- }
+ wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
wpa_ie, &wpa_ie_len)) {
wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
@@ -1451,6 +1160,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
} else if (ssid->key_mgmt &
(WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
WPA_KEY_MGMT_WPA_NONE)) {
+ wpa_ie_len = sizeof(wpa_ie);
if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
wpa_ie, &wpa_ie_len)) {
wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
@@ -1504,7 +1214,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
}
wpa_drv_set_drop_unencrypted(wpa_s, use_crypt);
- wpa_s->wpa_state = WPA_ASSOCIATING;
+ wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
memset(&params, 0, sizeof(params));
if (bss) {
params.bssid = bss->bssid;
@@ -1527,6 +1237,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
"failed");
/* try to continue anyway; new association will be tried again
* after timeout */
+ assoc_failed = 1;
}
if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
@@ -1536,9 +1247,17 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
/* No need to timeout authentication since there is no key
* management. */
wpa_supplicant_cancel_auth_timeout(wpa_s);
+ wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
} else {
/* Timeout for IEEE 802.11 authentication and association */
- wpa_supplicant_req_auth_timeout(wpa_s, 5, 0);
+ int timeout;
+ if (assoc_failed)
+ timeout = 5;
+ else if (wpa_s->conf->ap_scan == 1)
+ timeout = 10;
+ else
+ timeout = 60;
+ wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
}
if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
@@ -1556,6 +1275,7 @@ static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
}
wpa_s->current_ssid = ssid;
+ wpa_sm_set_config(wpa_s->wpa, wpa_s->current_ssid);
wpa_supplicant_initiate_eapol(wpa_s);
}
@@ -1564,13 +1284,14 @@ void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
int reason_code)
{
u8 *addr = NULL;
- wpa_s->wpa_state = WPA_DISCONNECTED;
+ 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);
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
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);
@@ -1581,211 +1302,21 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code)
{
u8 *addr = NULL;
- wpa_s->wpa_state = WPA_DISCONNECTED;
+ 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);
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
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);
}
-static void wpa_supplicant_imsi_identity(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- int aka = 0;
- u8 *pos = ssid->eap_methods;
-
- while (pos && *pos != EAP_TYPE_NONE) {
- if (*pos == EAP_TYPE_AKA) {
- aka = 1;
- break;
- }
- pos++;
- }
-
- if (ssid->identity == NULL && wpa_s->imsi) {
- ssid->identity = malloc(1 + wpa_s->imsi_len);
- if (ssid->identity) {
- ssid->identity[0] = aka ? '0' : '1';
- memcpy(ssid->identity + 1, wpa_s->imsi,
- wpa_s->imsi_len);
- ssid->identity_len = 1 + wpa_s->imsi_len;
- wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
- "IMSI", ssid->identity,
- ssid->identity_len);
- }
- }
-}
-
-
-static void wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
- struct wpa_ssid *ssid)
-{
- char buf[100];
- size_t len;
-
- if (ssid->pcsc == NULL)
- return;
- if (wpa_s->scard != NULL) {
- wpa_supplicant_imsi_identity(wpa_s, ssid);
- return;
- }
- wpa_printf(MSG_DEBUG, "Selected network is configured to use SIM - "
- "initialize PCSC");
- wpa_s->scard = scard_init(SCARD_TRY_BOTH, ssid->pin);
- if (wpa_s->scard == NULL) {
- wpa_printf(MSG_WARNING, "Failed to initialize SIM "
- "(pcsc-lite)");
- /* TODO: what to do here? */
- return;
- }
- eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
-
- len = sizeof(buf);
- if (scard_get_imsi(wpa_s->scard, buf, &len)) {
- wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
- /* TODO: what to do here? */
- return;
- }
-
- wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) buf, len);
- free(wpa_s->imsi);
- wpa_s->imsi = malloc(len);
- if (wpa_s->imsi) {
- memcpy(wpa_s->imsi, buf, len);
- wpa_s->imsi_len = len;
- wpa_supplicant_imsi_identity(wpa_s, ssid);
- }
-}
-
-
-static struct wpa_scan_result *
-wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
- struct wpa_scan_result *results, int num,
- struct wpa_ssid **selected_ssid)
-{
- struct wpa_ssid *ssid;
- struct wpa_scan_result *bss, *selected = NULL;
- int i;
- struct wpa_blacklist *e;
-
- wpa_printf(MSG_DEBUG, "Selecting BSS from priority group %d",
- group->priority);
-
- bss = NULL;
- ssid = NULL;
- /* First, try to find WPA-enabled AP */
- for (i = 0; i < num && !selected; i++) {
- bss = &results[i];
- wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
- "wpa_ie_len=%lu rsn_ie_len=%lu",
- i, MAC2STR(bss->bssid),
- wpa_ssid_txt(bss->ssid, bss->ssid_len),
- (unsigned long) bss->wpa_ie_len,
- (unsigned long) bss->rsn_ie_len);
- if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
- e->count > 1) {
- wpa_printf(MSG_DEBUG, " skip - blacklisted");
- continue;
- }
-
- if (bss->wpa_ie_len == 0 && bss->rsn_ie_len == 0) {
- wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE");
- continue;
- }
-
- for (ssid = group; ssid; ssid = ssid->pnext) {
- struct wpa_ie_data ie;
- if (bss->ssid_len != ssid->ssid_len ||
- 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) {
- wpa_printf(MSG_DEBUG, " skip - "
- "BSSID mismatch");
- continue;
- }
- if (!(((ssid->proto & WPA_PROTO_RSN) &&
- wpa_parse_wpa_ie(wpa_s, bss->rsn_ie,
- bss->rsn_ie_len, &ie) == 0) ||
- ((ssid->proto & WPA_PROTO_WPA) &&
- wpa_parse_wpa_ie(wpa_s, bss->wpa_ie,
- bss->wpa_ie_len, &ie) == 0))) {
- wpa_printf(MSG_DEBUG, " skip - "
- "could not parse WPA/RSN IE");
- continue;
- }
- if (!(ie.proto & ssid->proto)) {
- wpa_printf(MSG_DEBUG, " skip - "
- "proto mismatch");
- continue;
- }
- if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
- wpa_printf(MSG_DEBUG, " skip - "
- "PTK cipher mismatch");
- continue;
- }
- if (!(ie.group_cipher & ssid->group_cipher)) {
- wpa_printf(MSG_DEBUG, " skip - "
- "GTK cipher mismatch");
- continue;
- }
- if (!(ie.key_mgmt & ssid->key_mgmt)) {
- wpa_printf(MSG_DEBUG, " skip - "
- "key mgmt mismatch");
- continue;
- }
-
- selected = bss;
- *selected_ssid = ssid;
- wpa_printf(MSG_DEBUG, " selected");
- break;
- }
- }
-
- /* If no WPA-enabled AP found, try to find non-WPA AP, if configuration
- * allows this. */
- for (i = 0; i < num && !selected; i++) {
- bss = &results[i];
- if ((e = wpa_blacklist_get(wpa_s, bss->bssid)) &&
- e->count > 1) {
- continue;
- }
- for (ssid = group; ssid; ssid = ssid->pnext) {
- if (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)))
- {
- 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;
- }
- }
- }
-
- return selected;
-}
-
-
-static int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
{
#define SCAN_AP_LIMIT 128
struct wpa_scan_result *results, *tmp;
@@ -1825,57 +1356,7 @@ static int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s)
}
-static void wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s)
-{
- int num, prio;
- struct wpa_scan_result *selected = NULL;
- struct wpa_ssid *ssid;
- struct wpa_scan_result *results;
-
- if (wpa_supplicant_get_scan_results(wpa_s) < 0) {
- wpa_printf(MSG_DEBUG, "Failed to get scan results - try "
- "scanning again");
- wpa_supplicant_req_scan(wpa_s, 1, 0);
- return;
- }
- results = wpa_s->scan_results;
- num = wpa_s->num_scan_results;
-
- while (selected == NULL) {
- for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
- selected = wpa_supplicant_select_bss(
- wpa_s, wpa_s->conf->pssid[prio], results, num,
- &ssid);
- if (selected)
- break;
- }
-
- if (selected == NULL && wpa_s->blacklist) {
- wpa_printf(MSG_DEBUG, "No APs found - clear blacklist "
- "and try again");
- wpa_blacklist_clear(wpa_s);
- } else if (selected == NULL) {
- break;
- }
- }
-
- if (selected) {
- if (wpa_s->reassociate ||
- memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0) {
- wpa_supplicant_scard_init(wpa_s, ssid);
- wpa_supplicant_associate(wpa_s, selected, ssid);
- } else {
- wpa_printf(MSG_DEBUG, "Already associated with the "
- "selected AP.");
- }
- rsn_preauth_scan_results(wpa_s, results, num);
- } else {
- wpa_printf(MSG_DEBUG, "No suitable AP found.");
- wpa_supplicant_req_scan(wpa_s, 5, 0);
- }
-}
-
-
+#ifndef CONFIG_NO_WPA
static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
{
int i, ret = 0;
@@ -1894,33 +1375,11 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
}
if (curr) {
- free(wpa_s->ap_wpa_ie);
- wpa_s->ap_wpa_ie_len = curr->wpa_ie_len;
- if (curr->wpa_ie_len) {
- wpa_s->ap_wpa_ie = malloc(wpa_s->ap_wpa_ie_len);
- if (wpa_s->ap_wpa_ie) {
- memcpy(wpa_s->ap_wpa_ie, curr->wpa_ie,
- curr->wpa_ie_len);
- } else {
- ret = -1;
- }
- } else {
- wpa_s->ap_wpa_ie = NULL;
- }
-
- free(wpa_s->ap_rsn_ie);
- wpa_s->ap_rsn_ie_len = curr->rsn_ie_len;
- if (curr->rsn_ie_len) {
- wpa_s->ap_rsn_ie = malloc(wpa_s->ap_rsn_ie_len);
- if (wpa_s->ap_rsn_ie) {
- memcpy(wpa_s->ap_rsn_ie, curr->rsn_ie,
- curr->rsn_ie_len);
- } else {
- ret = -1;
- }
- } else {
- wpa_s->ap_rsn_ie = NULL;
- }
+ if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, curr->wpa_ie,
+ curr->wpa_ie_len) ||
+ wpa_sm_set_ap_rsn_ie(wpa_s->wpa, curr->rsn_ie,
+ curr->rsn_ie_len))
+ ret = -1;
} else {
ret = -1;
}
@@ -1929,8 +1388,9 @@ static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
}
-int wpa_supplicant_get_beacon_ie(struct wpa_supplicant *wpa_s)
+static int wpa_supplicant_get_beacon_ie(void *ctx)
{
+ struct wpa_supplicant *wpa_s = ctx;
if (wpa_get_beacon_ie(wpa_s) == 0) {
return 0;
}
@@ -1943,69 +1403,135 @@ int wpa_supplicant_get_beacon_ie(struct wpa_supplicant *wpa_s)
return wpa_get_beacon_ie(wpa_s);
}
+#endif /* CONFIG_NO_WPA */
-#ifdef CONFIG_XSUPPLICANT_IFACE
-static void wpa_supplicant_dot1x_receive(int sock, void *eloop_ctx,
- void *sock_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
+ */
+struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
{
- struct wpa_supplicant *wpa_s = eloop_ctx;
- u8 buf[128];
- int res;
+ struct wpa_ssid *entry;
+ u8 ssid[MAX_SSID_LEN];
+ int ssid_len;
+ u8 bssid[ETH_ALEN];
- res = recv(sock, buf, sizeof(buf), 0);
- wpa_printf(MSG_DEBUG, "WPA: Receive from dot1x (Xsupplicant) socket "
- "==> %d", res);
- if (res < 0) {
- perror("recv");
- return;
+ 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 (res != PMK_LEN) {
- wpa_printf(MSG_WARNING, "WPA: Invalid master key length (%d) "
- "from dot1x", res);
- return;
+ if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+ wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
+ return NULL;
}
- wpa_hexdump(MSG_DEBUG, "WPA: Master key (dot1x)", buf, PMK_LEN);
- if (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
- memcpy(wpa_s->pmk, buf, PMK_LEN);
- wpa_s->ext_pmk_received = 1;
- } else {
- wpa_printf(MSG_INFO, "WPA: Not in IEEE 802.1X mode - dropping "
- "dot1x PMK update (%d)", wpa_s->key_mgmt);
+ entry = wpa_s->conf->ssid;
+ while (entry) {
+ if (!entry->disabled &&
+ ssid_len == entry->ssid_len &&
+ memcmp(ssid, entry->ssid, ssid_len) == 0 &&
+ (!entry->bssid_set ||
+ memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+ return entry;
+ entry = entry->next;
}
+
+ return NULL;
}
-static int wpa_supplicant_802_1x_init(struct wpa_supplicant *wpa_s)
+#ifndef CONFIG_NO_WPA
+static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
+ const void *data, u16 data_len,
+ size_t *msg_len, void **data_pos)
{
- int s;
- struct sockaddr_un addr;
+ return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
+}
- s = socket(AF_LOCAL, SOCK_DGRAM, 0);
- if (s < 0) {
- perror("socket");
- return -1;
- }
- memset(&addr, 0, sizeof(addr));
- addr.sun_family = AF_LOCAL;
- addr.sun_path[0] = '\0';
- snprintf(addr.sun_path + 1, sizeof(addr.sun_path) - 1,
- "wpa_supplicant");
- if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind");
- close(s);
- return -1;
- }
+static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
+ const u8 *buf, size_t len)
+{
+ return wpa_ether_send(wpa_s, dest, proto, buf, len);
+}
- wpa_s->dot1x_s = s;
- eloop_register_read_sock(s, wpa_supplicant_dot1x_receive, wpa_s,
- NULL);
- return 0;
+
+static void _wpa_supplicant_req_scan(void *wpa_s, int sec, int usec)
+{
+ wpa_supplicant_req_scan(wpa_s, sec, usec);
+}
+
+
+static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
+{
+ wpa_supplicant_cancel_auth_timeout(wpa_s);
+}
+
+
+static void _wpa_supplicant_set_state(void *wpa_s, wpa_states state)
+{
+ wpa_supplicant_set_state(wpa_s, state);
+}
+
+
+static wpa_states _wpa_supplicant_get_state(void *wpa_s)
+{
+ return wpa_supplicant_get_state(wpa_s);
+}
+
+
+static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
+{
+ wpa_supplicant_disassociate(wpa_s, reason_code);
+}
+
+
+static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
+{
+ wpa_supplicant_deauthenticate(wpa_s, reason_code);
+}
+
+
+static struct wpa_ssid * _wpa_supplicant_get_ssid(void *wpa_s)
+{
+ return wpa_supplicant_get_ssid(wpa_s);
+}
+
+
+static int wpa_supplicant_get_bssid(void *wpa_s, u8 *bssid)
+{
+ return wpa_drv_get_bssid(wpa_s, bssid);
+}
+
+
+static int wpa_supplicant_set_key(void *wpa_s, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
+ key, key_len);
+}
+
+
+static int wpa_supplicant_add_pmkid(void *wpa_s,
+ const u8 *bssid, const u8 *pmkid)
+{
+ return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
+}
+
+
+static int wpa_supplicant_remove_pmkid(void *wpa_s,
+ const u8 *bssid, const u8 *pmkid)
+{
+ return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
}
-#endif /* CONFIG_XSUPPLICANT_IFACE */
+#endif /* CONFIG_NO_WPA */
static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
@@ -2040,34 +1566,67 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
}
-static void wpa_supplicant_fd_workaround(void)
+void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len)
{
- 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
- * places in wpa_supplicant are still printing out to stdout. As a
- * workaround, make sure that fd's 0, 1, and 2 are not used for other
- * sockets. */
- for (i = 0; i < 3; i++) {
- s = open("/dev/null", O_RDWR);
- if (s > 2) {
- close(s);
- break;
- }
+ struct wpa_supplicant *wpa_s = ctx;
+
+ wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
+ wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+
+ if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
+ wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
+ "no key management is configured");
+ return;
+ }
+
+ if (wpa_s->eapol_received == 0) {
+ /* Timeout for completing IEEE 802.1X and WPA authentication */
+ wpa_supplicant_req_auth_timeout(
+ wpa_s,
+ (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ||
+ wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) ?
+ 70 : 10, 0);
+ }
+ wpa_s->eapol_received++;
+
+ if (wpa_s->countermeasures) {
+ wpa_printf(MSG_INFO, "WPA: Countermeasures - dropped EAPOL "
+ "packet");
+ return;
}
+
+ /* Source address of the incoming EAPOL frame could be compared to the
+ * current BSSID. However, it is possible that a centralized
+ * Authenticator could be using another MAC address than the BSSID of
+ * 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);
+ if (wpa_s->key_mgmt != WPA_KEY_MGMT_PSK &&
+ eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
+ return;
+ wpa_drv_poll(wpa_s);
+ wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
}
-static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
- int wait_for_interface)
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
+ int wait_for_interface)
{
static int interface_count = 0;
for (;;) {
+ 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);
+ break;
+ }
wpa_s->l2 = l2_packet_init(wpa_s->ifname,
wpa_drv_get_mac_addr(wpa_s),
ETH_P_EAPOL,
- wpa_supplicant_rx_eapol, wpa_s);
+ wpa_supplicant_rx_eapol, wpa_s, 0);
if (wpa_s->l2)
break;
else if (!wait_for_interface)
@@ -2076,7 +1635,7 @@ static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
sleep(5);
}
- if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
+ 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");
return -1;
}
@@ -2084,9 +1643,21 @@ static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "Own MAC address: " MACSTR,
MAC2STR(wpa_s->own_addr));
+ /* 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. */
if (wpa_drv_set_wpa(wpa_s, 1) < 0) {
- fprintf(stderr, "Failed to enable WPA in the driver.\n");
- return -1;
+ struct wpa_driver_capa capa;
+ if (wpa_drv_get_capa(wpa_s, &capa) < 0 ||
+ !(capa.flags & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2))) {
+ 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");
+ return -1;
+ }
}
wpa_clear_keys(wpa_s, NULL);
@@ -2105,50 +1676,23 @@ static int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
}
-static void usage(void)
+static int wpa_supplicant_daemon(const char *pid_file)
{
- int i;
- printf("%s\n\n%s\n"
- "usage:\n"
- " wpa_supplicant [-BddehLqqvw] -i<ifname> -c<config file> "
- "[-D<driver>] \\\n"
- " [-P<pid file>] "
- "[-N -i<ifname> -c<conf> [-D<driver>] ...]\n"
- "\n"
- "drivers:\n",
- wpa_supplicant_version, wpa_supplicant_license);
-
- for (i = 0; wpa_supplicant_drivers[i]; i++) {
- printf(" %s = %s\n",
- wpa_supplicant_drivers[i]->name,
- wpa_supplicant_drivers[i]->desc);
+ wpa_printf(MSG_DEBUG, "Daemonize..");
+ if (daemon(0, 0)) {
+ perror("daemon");
+ return -1;
}
- printf("options:\n"
- " -B = run daemon in the background\n"
- " -d = increase debugging verbosity (-dd even more)\n"
- " -K = include keys (passwords, etc.) in debug output\n"
- " -t = include timestamp in debug messages\n"
-#ifdef CONFIG_XSUPPLICANT_IFACE
-#ifdef IEEE8021X_EAPOL
- " -e = use external IEEE 802.1X Supplicant (e.g., "
- "xsupplicant)\n"
- " (this disables the internal Supplicant)\n"
-#endif /* IEEE8021X_EAPOL */
-#endif /* CONFIG_XSUPPLICANT_IFACE */
- " -h = show this help text\n"
- " -L = show license (GPL and BSD)\n"
- " -q = decrease debugging verbosity (-qq even less)\n"
- " -v = show version\n"
- " -w = wait for interface to be added, if needed\n"
- " -N = start describing new interface\n");
-}
-
+ if (pid_file) {
+ FILE *f = fopen(pid_file, "w");
+ if (f) {
+ fprintf(f, "%u\n", getpid());
+ fclose(f);
+ }
+ }
-static void license(void)
-{
- printf("%s\n\n%s\n",
- wpa_supplicant_version, wpa_supplicant_full_license);
+ return 0;
}
@@ -2161,92 +1705,170 @@ static struct wpa_supplicant * wpa_supplicant_alloc(void)
return NULL;
memset(wpa_s, 0, sizeof(*wpa_s));
wpa_s->ctrl_sock = -1;
-#ifdef CONFIG_XSUPPLICANT_IFACE
- wpa_s->dot1x_s = -1;
-#endif /* CONFIG_XSUPPLICANT_IFACE */
+ wpa_s->scan_req = 1;
return wpa_s;
}
-static int wpa_supplicant_init(struct wpa_supplicant *wpa_s,
- const char *confname, const char *driver,
- const char *ifname)
+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'", ifname, confname, driver ? driver : "default");
+ "'%s' ctrl_interface '%s'", iface->ifname,
+ iface->confname ? iface->confname : "N/A",
+ iface->driver ? iface->driver : "default",
+ iface->ctrl_interface ? iface->ctrl_interface : "N/A");
- if (wpa_supplicant_set_driver(wpa_s, driver) < 0) {
+ if (wpa_supplicant_set_driver(wpa_s, iface->driver) < 0) {
return -1;
}
- if (confname) {
- wpa_s->confname = rel2abs_path(confname);
+ if (iface->confname) {
+#ifdef CONFIG_BACKEND_FILE
+ wpa_s->confname = rel2abs_path(iface->confname);
if (wpa_s->confname == NULL) {
wpa_printf(MSG_ERROR, "Failed to get absolute path "
- "for configuration file '%s'.", confname);
+ "for configuration file '%s'.",
+ iface->confname);
return -1;
}
wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
- confname, wpa_s->confname);
+ iface->confname, wpa_s->confname);
+#else /* CONFIG_BACKEND_FILE */
+ wpa_s->confname = 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 configuration file '%s'.\n",
- wpa_s->confname);
+ printf("Failed to read read or parse configuration "
+ "'%s'.\n", wpa_s->confname);
return -1;
}
- }
- if (wpa_s->conf == NULL || wpa_s->conf->ssid == NULL) {
- usage();
- printf("\nNo networks (SSID) configured.\n");
+ /*
+ * Override ctrl_interface and driver_param if set on command
+ * line.
+ */
+ if (iface->ctrl_interface) {
+ free(wpa_s->conf->ctrl_interface);
+ wpa_s->conf->ctrl_interface =
+ strdup(iface->ctrl_interface);
+ }
+
+ if (iface->driver_param) {
+ free(wpa_s->conf->driver_param);
+ wpa_s->conf->driver_param =
+ 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");
return -1;
}
- if (ifname == NULL) {
- usage();
+ if (iface->ifname == NULL) {
printf("\nInterface name is required.\n");
return -1;
}
- if (strlen(ifname) >= sizeof(wpa_s->ifname)) {
- printf("Too long interface name '%s'.\n", ifname);
+ if (strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
+ printf("Too long interface name '%s'.\n", iface->ifname);
+ return -1;
+ }
+ strncpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+
+ return 0;
+}
+
+
+static int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+ struct eapol_ctx *ctx;
+ ctx = malloc(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->eapol_send_ctx = wpa_s;
+ ctx->preauth = 0;
+ ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
+ ctx->eapol_send = wpa_supplicant_eapol_send;
+ 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->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");
+ return -1;
+ }
+#endif /* IEEE8021X_EAPOL */
+
+ return 0;
+}
+
+
+static int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
+{
+#ifndef CONFIG_NO_WPA
+ struct wpa_sm_ctx *ctx;
+ ctx = malloc(sizeof(*ctx));
+ if (ctx == NULL) {
+ printf("Failed to allocate WPA context.\n");
+ 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;
+ ctx->req_scan = _wpa_supplicant_req_scan;
+ ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+ ctx->disassociate = _wpa_supplicant_disassociate;
+ ctx->set_key = wpa_supplicant_set_key;
+ ctx->scan = wpa_supplicant_scan;
+ ctx->get_ssid = _wpa_supplicant_get_ssid;
+ ctx->get_bssid = wpa_supplicant_get_bssid;
+ ctx->ether_send = _wpa_ether_send;
+ ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
+ ctx->alloc_eapol = _wpa_alloc_eapol;
+ ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
+ ctx->add_pmkid = wpa_supplicant_add_pmkid;
+ 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;
+
+ wpa_s->wpa = wpa_sm_init(ctx);
+ if (wpa_s->wpa == NULL) {
+ fprintf(stderr, "Failed to initialize WPA state machine\n");
return -1;
}
- strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+#endif /* CONFIG_NO_WPA */
return 0;
}
-static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s,
- int disable_eapol, int wait_for_interface)
+static int wpa_supplicant_init_iface2(struct wpa_supplicant *wpa_s,
+ int wait_for_interface)
{
const char *ifname;
wpa_printf(MSG_DEBUG, "Initializing interface (2) '%s'",
wpa_s->ifname);
- if (!disable_eapol) {
- struct eapol_ctx *ctx;
- ctx = malloc(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->preauth = 0;
- ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
- ctx->eapol_send = wpa_eapol_send;
- ctx->set_wep_key = wpa_eapol_set_wep_key;
- wpa_s->eapol = eapol_sm_init(ctx);
- if (wpa_s->eapol == NULL) {
- free(ctx);
- printf("Failed to initialize EAPOL state machines.\n");
- return -1;
- }
- }
+ if (wpa_supplicant_init_eapol(wpa_s) < 0)
+ return -1;
/* RSNA Supplicant Key Management - INITIALIZE */
eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
@@ -2261,6 +1883,11 @@ static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s,
fprintf(stderr, "Failed to initialize driver interface\n");
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);
+ return -1;
+ }
ifname = wpa_drv_get_ifname(wpa_s);
if (ifname && strcmp(ifname, wpa_s->ifname) != 0) {
@@ -2269,10 +1896,41 @@ static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s,
strncpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
}
- wpa_s->renew_snonce = 1;
+ if (wpa_supplicant_init_wpa(wpa_s) < 0)
+ return -1;
+
+ wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname);
+ 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");
+ 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");
+ 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");
+ return -1;
+ }
+
if (wpa_supplicant_driver_init(wpa_s, wait_for_interface) < 0) {
return -1;
}
+ 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"
@@ -2286,18 +1944,18 @@ static int wpa_supplicant_init2(struct wpa_supplicant *wpa_s,
return -1;
}
-#ifdef CONFIG_XSUPPLICANT_IFACE
- if (disable_eapol)
- wpa_supplicant_802_1x_init(wpa_s);
-#endif /* CONFIG_XSUPPLICANT_IFACE */
-
return 0;
}
-static void wpa_supplicant_deinit(struct wpa_supplicant *wpa_s)
+static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s)
{
if (wpa_s->drv_priv) {
+ wpa_supplicant_deauthenticate(wpa_s, REASON_DEAUTH_LEAVING);
+
+ /* 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. */
if (wpa_drv_set_wpa(wpa_s, 0) < 0) {
fprintf(stderr, "Failed to disable WPA in the "
"driver.\n");
@@ -2313,137 +1971,176 @@ static void wpa_supplicant_deinit(struct wpa_supplicant *wpa_s)
}
-int main(int argc, char *argv[])
+/**
+ * wpa_supplicant_add_iface - Add a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @iface: Interface configuration options
+ * Returns: Pointer to the created interface or %NULL on failure
+ *
+ * This function is used to add new network interfaces for %wpa_supplicant.
+ * This can be called before wpa_supplicant_run() to add interfaces before the
+ * main event loop has been started. In addition, new interfaces can be added
+ * dynamically while %wpa_supplicant is already running. This could happen,
+ * e.g., when a hotplug network adapter is inserted.
+ */
+struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
+ struct wpa_interface *iface)
{
- struct wpa_supplicant *head, *wpa_s;
- int c;
- const char *confname, *driver, *ifname;
- char *pid_file = NULL;
- int daemonize = 0, wait_for_interface = 0, disable_eapol = 0, exitcode;
+ struct wpa_supplicant *wpa_s;
-#ifdef CONFIG_NATIVE_WINDOWS
- WSADATA wsaData;
- if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
- printf("Could not find a usable WinSock.dll\n");
- return -1;
- }
-#endif /* CONFIG_NATIVE_WINDOWS */
+ if (global == NULL || iface == NULL)
+ return NULL;
- head = wpa_s = wpa_supplicant_alloc();
+ wpa_s = wpa_supplicant_alloc();
if (wpa_s == NULL)
- return -1;
- wpa_s->head = head;
+ return NULL;
- wpa_supplicant_fd_workaround();
- eloop_init(head);
+ if (wpa_supplicant_init_iface(wpa_s, iface) ||
+ wpa_supplicant_init_iface2(wpa_s,
+ global->params.wait_for_interface)) {
+ wpa_printf(MSG_DEBUG, "Failed to add interface %s",
+ iface->ifname);
+ wpa_supplicant_deinit_iface(wpa_s);
+ free(wpa_s);
+ return NULL;
+ }
- ifname = confname = driver = NULL;
+ wpa_s->global = global;
+ wpa_s->next = global->ifaces;
+ global->ifaces = wpa_s;
- for (;;) {
- c = getopt(argc, argv, "Bc:D:dehi:KLNP:qtvw");
- if (c < 0)
- break;
- switch (c) {
- case 'B':
- daemonize++;
- break;
- case 'c':
- confname = optarg;
- break;
- case 'D':
- driver = optarg;
- break;
- case 'd':
- wpa_debug_level--;
- break;
-#ifdef CONFIG_XSUPPLICANT_IFACE
-#ifdef IEEE8021X_EAPOL
- case 'e':
- disable_eapol++;
- break;
-#endif /* IEEE8021X_EAPOL */
-#endif /* CONFIG_XSUPPLICANT_IFACE */
- case 'h':
- usage();
- return -1;
- case 'i':
- ifname = optarg;
- break;
- case 'K':
- wpa_debug_show_keys++;
- break;
- case 'L':
- license();
- return -1;
- case 'P':
- pid_file = rel2abs_path(optarg);
- break;
- case 'q':
- wpa_debug_level++;
- break;
- case 't':
- wpa_debug_timestamp++;
- break;
- case 'v':
- printf("%s\n", wpa_supplicant_version);
- return -1;
- case 'w':
- wait_for_interface++;
- break;
- case 'N':
- if (wpa_supplicant_init(wpa_s, confname, driver,
- ifname))
- return -1;
- wpa_s->next = wpa_supplicant_alloc();
- wpa_s = wpa_s->next;
- if (wpa_s == NULL)
- return -1;
- wpa_s->head = head;
- ifname = confname = driver = NULL;
- break;
- default:
- usage();
+ wpa_printf(MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+
+ return wpa_s;
+}
+
+
+/**
+ * wpa_supplicant_remove_iface - Remove a network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @wpa_s: Pointer to the network interface to be removed
+ * Returns: 0 if interface was removed, -1 if interface was not found
+ *
+ * This function can be used to dynamically remove network interfaces from
+ * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
+ * addition, this function is used to remove all remaining interdaces when
+ * %wpa_supplicant is terminated.
+ */
+int wpa_supplicant_remove_iface(struct wpa_global *global,
+ struct wpa_supplicant *wpa_s)
+{
+ struct wpa_supplicant *prev;
+
+ /* Remove interface from the global list of interfaces */
+ prev = global->ifaces;
+ if (prev == wpa_s) {
+ global->ifaces = wpa_s->next;
+ } else {
+ while (prev && prev->next != wpa_s)
+ prev = prev->next;
+ if (prev == NULL)
return -1;
- }
+ prev->next = wpa_s->next;
}
- if (wpa_supplicant_init(wpa_s, confname, driver, ifname))
- return -1;
+ wpa_printf(MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
- exitcode = 0;
+ wpa_supplicant_deinit_iface(wpa_s);
+ free(wpa_s);
- if (wait_for_interface && daemonize) {
- wpa_printf(MSG_DEBUG, "Daemonize..");
- if (daemon(0, 0)) {
- perror("daemon");
- exitcode = -1;
- goto cleanup;
- }
+ return 0;
+}
+
+
+/**
+ * wpa_supplicant_get_iface - Get a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Interface name
+ * Returns: Pointer to the interface or %NULL if not found
+ */
+struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
+ const char *ifname)
+{
+ struct wpa_supplicant *wpa_s;
+
+ for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+ if (strcmp(wpa_s->ifname, ifname) == 0)
+ return wpa_s;
}
+ return NULL;
+}
- for (wpa_s = head; wpa_s; wpa_s = wpa_s->next) {
- if (wpa_supplicant_init2(wpa_s, disable_eapol,
- wait_for_interface)) {
- exitcode = -1;
- goto cleanup;
- }
+
+/**
+ * wpa_supplicant_init - Initialize %wpa_supplicant
+ * @params: Parameters for %wpa_supplicant
+ * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
+ *
+ * This function is used to initialize %wpa_supplicant. After successful
+ * initialization, the returned data pointer can be used to add and remove
+ * network interfaces, and eventually, to deinitialize %wpa_supplicant.
+ */
+struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
+{
+ struct wpa_global *global;
+
+ if (params == NULL)
+ return NULL;
+ global = malloc(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;
+ if (params->pid_file)
+ global->params.pid_file = strdup(params->pid_file);
+ if (params->ctrl_interface)
+ global->params.ctrl_interface = 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;
+
+ eloop_init(global);
+
+ if (wpa_supplicant_global_ctrl_iface_init(global)) {
+ eloop_destroy();
+ return NULL;
}
- if (!wait_for_interface && daemonize) {
- wpa_printf(MSG_DEBUG, "Daemonize..");
- if (daemon(0, 0)) {
- perror("daemon");
- exitcode = -1;
- goto cleanup;
- }
+ if (global->params.wait_for_interface && global->params.daemonize &&
+ wpa_supplicant_daemon(global->params.pid_file)) {
+ eloop_destroy();
+ return NULL;
}
- if (pid_file) {
- FILE *f = fopen(pid_file, "w");
- if (f) {
- fprintf(f, "%u\n", getpid());
- fclose(f);
- }
+ return global;
+}
+
+
+/**
+ * wpa_supplicant_run - Run the %wpa_supplicant main event loop
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 after successful event loop run, -1 on failure
+ *
+ * This function starts the main event loop and continues running as long as
+ * there are any remaining events. In most cases, this function is running as
+ * long as the %wpa_supplicant process in still in use.
+ */
+int wpa_supplicant_run(struct wpa_global *global)
+{
+ struct wpa_supplicant *wpa_s;
+
+ if (!global->params.wait_for_interface && global->params.daemonize &&
+ wpa_supplicant_daemon(global->params.pid_file))
+ return -1;
+
+ 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);
}
eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
@@ -2454,30 +2151,34 @@ int main(int argc, char *argv[])
eloop_run();
- for (wpa_s = head; wpa_s; wpa_s = wpa_s->next) {
- wpa_supplicant_deauthenticate(wpa_s, REASON_DEAUTH_LEAVING);
- }
+ return 0;
+}
-cleanup:
- wpa_s = head;
- while (wpa_s) {
- struct wpa_supplicant *prev;
- wpa_supplicant_deinit(wpa_s);
- prev = wpa_s;
- wpa_s = wpa_s->next;
- free(prev);
- }
+
+/**
+ * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
+ * @global: Pointer to global data from wpa_supplicant_init()
+ *
+ * This function is called to deinitialize %wpa_supplicant and to free all
+ * allocated resources. Remaining network interfaces will also be removed.
+ */
+void wpa_supplicant_deinit(struct wpa_global *global)
+{
+ if (global == NULL)
+ return;
+
+ while (global->ifaces)
+ wpa_supplicant_remove_iface(global, global->ifaces);
+
+ wpa_supplicant_global_ctrl_iface_deinit(global);
eloop_destroy();
- if (pid_file) {
- unlink(pid_file);
- free(pid_file);
+ if (global->params.pid_file) {
+ unlink(global->params.pid_file);
+ free(global->params.pid_file);
}
+ free(global->params.ctrl_interface);
-#ifdef CONFIG_NATIVE_WINDOWS
- WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
-
- return exitcode;
+ free(global);
}
diff --git a/contrib/wpa_supplicant/wpa_supplicant.conf b/contrib/wpa_supplicant/wpa_supplicant.conf
index e8be91a..92e9ec1 100644
--- a/contrib/wpa_supplicant/wpa_supplicant.conf
+++ b/contrib/wpa_supplicant/wpa_supplicant.conf
@@ -1,9 +1,28 @@
##### Example wpa_supplicant configuration file ###############################
+#
+# This file describes configuration file format and lists all available option.
+# Please also take a look at simpler configuration examples in 'examples'
+# subdirectory.
+#
# Empty lines and lines starting with # are ignored
# NOTE! This file may contain password information and should probably be made
# readable only by root user on multiuser systems.
+# Note: All file paths in this configuration file should use full (absolute,
+# not relative to working directory) path in order to allow working directory
+# to be changed. This can happen if wpa_supplicant is run in the background.
+
+# Whether to allow wpa_supplicant to update (overwrite) configuration
+#
+# This option can be used to allow wpa_supplicant to overwrite configuration
+# file whenever configuration is changed (e.g., new network block is added with
+# wpa_cli or wpa_gui, or a password is changed). This is required for
+# wpa_cli/wpa_gui to be able to store the configuration changes permanently.
+# Please note that overwriting configuration file will remove the comments from
+# it.
+#update_config=1
+
# global configuration (shared by all network blocks)
#
# Interface for separate control program. If this is specified, wpa_supplicant
@@ -52,13 +71,15 @@ eapol_version=1
# 0: driver takes care of scanning, AP selection, and IEEE 802.11 association
# parameters (e.g., WPA IE generation); this mode can also be used with
# non-WPA drivers when using IEEE 802.1X mode; do not try to associate with
-# APs (i.e., external program needs to control association)
+# APs (i.e., external program needs to control association). This mode must
+# also be used when using wired Ethernet drivers.
# 2: like 0, but associate with APs using security policy and SSID (but not
-# BSSID); this can be used, e.g., with ndiswrapper and NDIS driver to
+# BSSID); this can be used, e.g., with ndiswrapper and NDIS drivers to
# enable operation with hidden SSIDs and optimized roaming; in this mode,
-# only the first network block in the configuration file is used and this
-# configuration should have explicit security policy (i.e., only one option
-# in the lists) for key_mgmt, pairwise, group, proto variables
+# the network blocks in the configuration file are tried one by one until
+# the driver reports successful association; each network block should have
+# explicit security policy (i.e., only one option in the lists) for
+# key_mgmt, pairwise, group, proto variables
ap_scan=1
# EAP fast re-authentication
@@ -67,6 +88,31 @@ ap_scan=1
# Normally, there is no need to disable this.
fast_reauth=1
+# OpenSSL Engine support
+# These options can be used to load OpenSSL engines.
+# The two engines that are supported currently are shown below:
+# 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
+# make the pkcs11 engine available
+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
+
+# Driver interface parameters
+# This field can be used to configure arbitrary driver interace parameters. The
+# format is specific to the selected driver interface. This field is not used
+# in most cases.
+#driver_param="field=value"
+
+# Maximum lifetime for PMKSA in seconds; default 43200
+#dot11RSNAConfigPMKLifetime=43200
+# Threshold for reauthentication (percentage of PMK lifetime); default 70
+#dot11RSNAConfigPMKReauthThreshold=70
+# Timeout for security association negotiation in seconds; default 60
+#dot11RSNAConfigSATimeout=60
+
# network block
#
# Each network (usually AP's sharing the same SSID) is configured as a separate
@@ -75,6 +121,11 @@ fast_reauth=1
#
# network block fields:
#
+# disabled:
+# 0 = this network can be used (default)
+# 1 = this network block is disabled (can be enabled through ctrl_iface,
+# e.g., with wpa_cli or wpa_gui)
+#
# ssid: SSID (mandatory); either as an ASCII string with double quotation or
# as hex string; network name
#
@@ -95,9 +146,9 @@ fast_reauth=1
# priority value, the sooner the network is matched against the scan results).
# Within each priority group, networks will be selected based on security
# policy, signal strength, etc.
-# Please note that AP scanning with scan_ssid=1 is not using this priority to
-# select the order for scanning. Instead, it uses the order the networks are in
-# the configuration file.
+# Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are not
+# using this priority to select the order for scanning. Instead, they try the
+# networks in the order that used in the configuration file.
#
# mode: IEEE 802.11 operation mode
# 0 = infrastructure (Managed) mode, i.e., associate with an AP (default)
@@ -155,10 +206,21 @@ fast_reauth=1
# only when the passphrase or SSID has actually changed.
#
# eapol_flags: IEEE 802.1X/EAPOL options (bit field)
-# Dynamic WEP key require for non-WPA mode
+# Dynamic WEP key required for non-WPA mode
# bit0 (1): require dynamically generated unicast WEP key
# bit1 (2): require dynamically generated broadcast WEP key
# (3 = require both keys; default)
+# Note: When using wired authentication, eapol_flags must be set to 0 for the
+# authentication to be completed successfully.
+#
+# proactive_key_caching:
+# Enable/disable opportunistic PMKSA caching for WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#
+# wep_key0..3: Static WEP key (ASCII in double quotation, e.g. "abcde" or
+# hex without quotation, e.g., 0102030405)
+# wep_tx_keyidx: Default WEP key index (TX) (0..3)
#
# Following fields are only used with internal EAP implementation.
# eap: space-separated list of accepted EAP methods
@@ -182,16 +244,40 @@ fast_reauth=1
# unencrypted identity with EAP types that support different tunnelled
# identity, e.g., EAP-TTLS)
# password: Password string for EAP
-# ca_cert: File path to CA certificate file. This file can have one or more
-# trusted CA certificates. If ca_cert is not included, server certificate
-# will not be verified. This is insecure and the CA file should always be
-# configured.
+# ca_cert: File path to CA certificate file (PEM/DER). This file can have one
+# or more trusted CA certificates. If ca_cert and ca_path are not
+# included, server certificate will not be verified. This is insecure and
+# a trusted CA certificate should always be configured when using
+# EAP-TLS/TTLS/PEAP. Full path should be used since working directory may
+# change when wpa_supplicant is run in the background.
+# 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".
+# ca_path: Directory path for CA certificate files (PEM). This path may
+# contain multiple CA certificates in OpenSSL format. Common use for this
+# is to point to system trusted CA list which is often installed into
+# directory like /etc/ssl/certs. If configured, these certificates are
+# added to the list of trusted CAs. ca_cert may also be included in that
+# case, but it is not required.
# client_cert: File path to client certificate file (PEM/DER)
+# Full path should be used since working directory may change when
+# wpa_supplicant is run in the background.
+# Alternatively, a named configuration blob can be used by setting this
+# to blob://<blob name>.
# private_key: File path to client private key file (PEM/DER/PFX)
# When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
# commented out. Both the private key and certificate will be read from
-# the PKCS#12 file in this case.
-# private_key_passwd: Password for private key file
+# the PKCS#12 file in this case. Full path should be used since working
+# directory may change when wpa_supplicant is run in the background.
+# Windows certificate store can be used by leaving client_cert out and
+# configuring private_key in one of the following formats:
+# cert://substring_to_match
+# hash://certificate_thumbprint_in_hex
+# for example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+# 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
+# asked through control interface)
# dh_file: File path to DH/DSA parameters file (in PEM format)
# This is an optional configuration file for setting parameters for an
# ephemeral DH key exchange. In most cases, the default RSA
@@ -205,6 +291,13 @@ fast_reauth=1
# 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.
+# altSubjectName string is in following format: TYPE:VALUE
+# Example: DNS:server.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
# "peapver=1 peaplabel=1")
@@ -230,25 +323,30 @@ fast_reauth=1
# Following certificate/private key fields are used in inner Phase2
# authentication when using EAP-TTLS or EAP-PEAP.
# ca_cert2: File path to CA certificate file. This file can have one or more
-# trusted CA certificates. If ca_cert2 is not included, server
-# certificate will not be verified. This is insecure and the CA file
-# should always be configured.
+# trusted CA certificates. If ca_cert2 and ca_path2 are not included,
+# server certificate will not be verified. This is insecure and a trusted
+# CA certificate should always be configured.
+# ca_path2: Directory path for CA certificate files (PEM)
# client_cert2: File path to client certificate file
# private_key2: File path to client private key file
# private_key2_passwd: Password for private key file
# dh_file2: File path to DH/DSA parameters file (in PEM format)
# subject_match2: Substring to be matched against the subject of the
# authentication server certificate.
+# altsubject_match2: Substring to be matched against the alternative subject
+# name of the authentication server certificate.
#
# EAP-PSK variables:
# eappsk: 16-byte (128-bit, 32 hex digits) pre-shared key in hex format
# nai: user NAI
-# server_nai: authentication server NAI
#
# 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
-# provisioned or refreshed.
+# provisioned or refreshed. Full path to the file should be used since
+# working directory may change when wpa_supplicant is run in the
+# background. Alternatively, a named configuration blob can be used by
+# setting this to blob://<blob name>
# phase1: fast_provisioning=1 option enables in-line provisioning of EAP-FAST
# credentials (PAC)
#
@@ -400,7 +498,6 @@ network={
identity="eap_psk_user"
eappsk=06b4be19da289f475aa46a33cb793029
nai="eap_psk_user@example.com"
- server_nai="as@example.com"
}
@@ -441,6 +538,17 @@ network={
pac_file="/etc/wpa_supplicant.eap-fast-pac"
}
+network={
+ ssid="eap-fast-test"
+ key_mgmt=WPA-EAP
+ eap=FAST
+ anonymous_identity="FAST-000102030405"
+ identity="username"
+ password="password"
+ phase1="fast_provisioning=1"
+ pac_file="blob://eap-fast-pac"
+}
+
# Plaintext connection (no WPA, no IEEE 802.1X)
network={
ssid="plaintext-test"
@@ -503,3 +611,52 @@ network={
private_key_passwd="password"
phase1="peaplabel=0"
}
+
+# Example of EAP-TLS with smartcard (openssl engine)
+network={
+ ssid="example"
+ key_mgmt=WPA-EAP
+ eap=TLS
+ proto=RSN
+ pairwise=CCMP TKIP
+ group=CCMP TKIP
+ identity="user@example.com"
+ ca_cert="/etc/cert/ca.pem"
+ client_cert="/etc/cert/user.pem"
+
+ engine=1
+
+ # The engine configured here must be available. Look at
+ # OpenSSL engine support in the global section.
+ # The key available through the engine must be the private key
+ # matching the client certificate configured above.
+
+ # use the opensc engine
+ #engine_id="opensc"
+ #key_id="45"
+
+ # use the pkcs11 engine
+ engine_id="pkcs11"
+ key_id="id_45"
+
+ # Optional PIN configuration; this can be left out and PIN will be
+ # asked through the control interface
+ pin="1234"
+}
+
+# Example configuration showing how to use an inlined blob as a CA certificate
+# data instead of using external file
+network={
+ ssid="example"
+ key_mgmt=WPA-EAP
+ eap=TTLS
+ identity="user@example.com"
+ anonymous_identity="anonymous@example.com"
+ password="foobar"
+ ca_cert="blob://exampleblob"
+ priority=20
+}
+
+blob-base64-exampleblob={
+SGVsbG8gV29ybGQhCg==
+}
diff --git a/contrib/wpa_supplicant/wpa_supplicant.h b/contrib/wpa_supplicant/wpa_supplicant.h
index e5ad182..e7e6f0d 100644
--- a/contrib/wpa_supplicant/wpa_supplicant.h
+++ b/contrib/wpa_supplicant/wpa_supplicant.h
@@ -1,3 +1,17 @@
+/*
+ * wpa_supplicant - Exported functions for wpa_supplicant modules
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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_SUPPLICANT_H
#define WPA_SUPPLICANT_H
@@ -6,21 +20,164 @@
*/
struct wpa_supplicant;
-typedef enum {
- EVENT_ASSOC, EVENT_DISASSOC, EVENT_MICHAEL_MIC_FAILURE,
- EVENT_SCAN_RESULTS, EVENT_ASSOCINFO, EVENT_INTERFACE_STATUS,
+/**
+ * enum wpa_event_type - Event type for wpa_supplicant_event() calls
+ */
+typedef enum wpa_event_type {
+ /**
+ * EVENT_ASSOC - Association completed
+ *
+ * This event needs to be delivered when the driver completes IEEE
+ * 802.11 association or reassociation successfully.
+ * wpa_driver_ops::get_bssid() is expected to provide the current BSSID
+ * after this even has been generated. In addition, optional
+ * EVENT_ASSOCINFO may be generated just before EVENT_ASSOC to provide
+ * more information about the association. If the driver interface gets
+ * both of these events at the same time, it can also include the
+ * assoc_info data in EVENT_ASSOC call.
+ */
+ EVENT_ASSOC,
+
+ /**
+ * EVENT_DISASSOC - Association lost
+ *
+ * This event should be called when association is lost either due to
+ * receiving deauthenticate or disassociate frame from the AP or when
+ * sending either of these frames to the current AP.
+ */
+ EVENT_DISASSOC,
+
+ /**
+ * EVENT_MICHAEL_MIC_FAILURE - Michael MIC (TKIP) detected
+ *
+ * This event must be delivered when a Michael MIC error is detected by
+ * the local driver. Additional data is for event processing is
+ * provided with union wpa_event_data::michael_mic_failure. This
+ * information is used to request new encyption key and to initiate
+ * TKIP countermeasures if needed.
+ */
+ EVENT_MICHAEL_MIC_FAILURE,
+
+ /**
+ * EVENT_SCAN_RESULTS - Scan results available
+ *
+ * This event must be called whenever scan results are available to be
+ * fetched with struct wpa_driver_ops::get_scan_results(). This event
+ * is expected to be used some time after struct wpa_driver_ops::scan()
+ * is called. If the driver provides an unsolicited event when the scan
+ * has been completed, this event can be used to trigger
+ * EVENT_SCAN_RESULTS call. If such event is not available from the
+ * driver, the driver wrapper code is expected to use a registered
+ * timeout to generate EVENT_SCAN_RESULTS call after the time that the
+ * scan is expected to be completed.
+ */
+ EVENT_SCAN_RESULTS,
+
+ /**
+ * EVENT_ASSOCINFO - Report optional extra information for association
+ *
+ * This event can be used to report extra association information for
+ * EVENT_ASSOC processing. This extra information includes IEs from
+ * association frames and Beacon/Probe Response frames in union
+ * wpa_event_data::assoc_info. EVENT_ASSOCINFO must be send just before
+ * EVENT_ASSOC. Alternatively, the driver interface can include
+ * assoc_info data in the EVENT_ASSOC call if it has all the
+ * information available at the same point.
+ */
+ EVENT_ASSOCINFO,
+
+ /**
+ * EVENT_INTERFACE_STATUS - Report interface status changes
+ *
+ * This optional event can be used to report changes in interface
+ * status (interface added/removed) using union
+ * wpa_event_data::interface_status. This can be used to trigger
+ * wpa_supplicant to stop and re-start processing for the interface,
+ * e.g., when a cardbus card is ejected/inserted.
+ */
+ EVENT_INTERFACE_STATUS,
+
+ /**
+ * EVENT_PMKID_CANDIDATE - Report a candidate AP for pre-authentication
+ *
+ * This event can be used to inform wpa_supplicant about candidates for
+ * RSN (WPA2) pre-authentication. If wpa_supplicant is not responsible
+ * for scan request (ap_scan=2 mode), this event is required for
+ * pre-authentication. If wpa_supplicant is performing scan request
+ * (ap_scan=1), this event is optional since scan results can be used
+ * to add pre-authentication candidates. union
+ * wpa_event_data::pmkid_candidate is used to report the BSSID of the
+ * candidate and priority of the candidate, e.g., based on the signal
+ * strength, in order to try to pre-authenticate first with candidates
+ * that are most likely targets for re-association.
+ *
+ * EVENT_PMKID_CANDIDATE can be called whenever the driver has updates
+ * on the candidate list. In addition, it can be called for the current
+ * AP and APs that have existing PMKSA cache entries. wpa_supplicant
+ * will automatically skip pre-authentication in cases where a valid
+ * PMKSA exists. When more than one candidate exists, this event should
+ * be generated once for each candidate.
+ *
+ * Driver will be notified about successful pre-authentication with
+ * struct wpa_driver_ops::add_pmkid() calls.
+ */
EVENT_PMKID_CANDIDATE
} wpa_event_type;
+
+/**
+ * union wpa_event_data - Additional data for wpa_supplicant_event() calls
+ */
union wpa_event_data {
- struct {
- /* Optional request information data: IEs included in AssocReq
- * and AssocResp. If these are not returned by the driver,
- * WPA Supplicant will generate the WPA/RSN IE. */
- u8 *req_ies, *resp_ies;
- size_t req_ies_len, resp_ies_len;
-
- /* Optional Beacon/ProbeResp data: IEs included in Beacon or
+ /**
+ * struct assoc_info - Data for EVENT_ASSOC and EVENT_ASSOCINFO events
+ *
+ * This structure is optional for EVENT_ASSOC calls and required for
+ * EVENT_ASSOCINFO calls. By using EVENT_ASSOC with this data, the
+ * driver interface does not need to generate separate EVENT_ASSOCINFO
+ * calls.
+ */
+ struct assoc_info {
+ /**
+ * req_ies - (Re)Association Request IEs
+ *
+ * If the driver generates WPA/RSN IE, this event data must be
+ * returned for WPA handshake to have needed information. If
+ * wpa_supplicant-generated WPA/RSN IE is used, this
+ * information event is optional.
+ *
+ * This should start with the first IE (fixed fields before IEs
+ * are not included).
+ */
+ u8 *req_ies;
+
+ /**
+ * req_ies_len - Length of req_ies in bytes
+ */
+ size_t req_ies_len;
+
+ /**
+ * resp_ies - (Re)Association Response IEs
+ *
+ * Optional association data from the driver. This data is not
+ * required WPA, but may be useful for some protocols and as
+ * such, should be reported if this is available to the driver
+ * interface.
+ *
+ * This should start with the first IE (fixed fields before IEs
+ * are not included).
+ */
+ u8 *resp_ies;
+
+ /**
+ * resp_ies_len - Length of resp_ies in bytes
+ */
+ size_t resp_ies_len;
+
+ /**
+ * beacon_ies - Beacon or Probe Response IEs
+ *
+ * Optional Beacon/ProbeResp data: IEs included in Beacon or
* Probe Response frames from the current AP (i.e., the one
* that the client just associated with). This information is
* used to update WPA/RSN IE for the AP. If this field is not
@@ -28,30 +185,52 @@ union wpa_event_data {
* data for the new AP is found, scan results will be requested
* again (without scan request). At this point, the driver is
* expected to provide WPA/RSN IE for the AP (if WPA/WPA2 is
- * used). */
- u8 *beacon_ies; /* beacon or probe resp IEs */
+ * used).
+ *
+ * This should start with the first IE (fixed fields before IEs
+ * are not included).
+ */
+ u8 *beacon_ies;
+
+ /**
+ * beacon_ies_len - Length of beacon_ies */
size_t beacon_ies_len;
} assoc_info;
- struct {
+
+ /**
+ * struct michael_mic_failure - Data for EVENT_MICHAEL_MIC_FAILURE
+ */
+ struct michael_mic_failure {
int unicast;
} michael_mic_failure;
- struct {
+
+ /**
+ * struct interface_status - Data for EVENT_INTERFACE_STATUS
+ */
+ struct interface_status {
char ifname[20];
enum {
EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
} ievent;
} interface_status;
- struct {
+
+ /**
+ * struct pmkid_candidate - Data for EVENT_PMKID_CANDIDATE
+ */
+ struct pmkid_candidate {
+ /** BSSID of the PMKID candidate */
u8 bssid[ETH_ALEN];
- int index; /* smaller the index, higher the priority */
+ /** Smaller the index, higher the priority */
+ int index;
+ /** Whether RSN IE includes pre-authenticate flag */
int preauth;
} pmkid_candidate;
};
/**
- * wpa_supplicant_event - report a driver event for wpa_supplicant
- * @wpa_s: pointer to wpa_supplicant data; this is the @ctx variable registered
- * with wpa_driver_events_init()
+ * wpa_supplicant_event - Report a driver event for wpa_supplicant
+ * @wpa_s: pointer to wpa_supplicant data; this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
* @event: event type (defined above)
* @data: possible extra data for the event
*
@@ -62,7 +241,9 @@ 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_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
*
@@ -78,4 +259,16 @@ __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
+ * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
+ * @len: Length of the EAPOL data
+ *
+ * This function is called for each received EAPOL frame.
+ */
+void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+
#endif /* WPA_SUPPLICANT_H */
diff --git a/contrib/wpa_supplicant/wpa_supplicant_i.h b/contrib/wpa_supplicant/wpa_supplicant_i.h
index 508fe09..a22bc6f 100644
--- a/contrib/wpa_supplicant/wpa_supplicant_i.h
+++ b/contrib/wpa_supplicant/wpa_supplicant_i.h
@@ -1,93 +1,177 @@
+/*
+ * wpa_supplicant - Internal definitions
+ * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.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_SUPPLICANT_I_H
#define WPA_SUPPLICANT_I_H
#include "driver.h"
-#ifdef EAPOL_TEST
-#include <netinet/in.h>
-
-struct hostapd_radius_server {
- struct in_addr addr;
- int port;
- u8 *shared_secret;
- size_t shared_secret_len;
-};
-#endif /* EAPOL_TEST */
-
-#define PMKID_LEN 16
-struct rsn_pmksa_cache {
- struct rsn_pmksa_cache *next;
- u8 pmkid[PMKID_LEN];
- u8 pmk[PMK_LEN];
- size_t pmk_len;
- time_t expiration;
- int akmp; /* WPA_KEY_MGMT_* */
- u8 aa[ETH_ALEN];
-};
-
-struct rsn_pmksa_candidate {
- struct rsn_pmksa_candidate *next;
+struct wpa_blacklist {
+ struct wpa_blacklist *next;
u8 bssid[ETH_ALEN];
- int priority;
+ int count;
};
-struct wpa_ptk {
- u8 mic_key[16]; /* EAPOL-Key MIC Key (MK) */
- u8 encr_key[16]; /* EAPOL-Key Encryption Key (EK) */
- u8 tk1[16]; /* Temporal Key 1 (TK1) */
- union {
- u8 tk2[16]; /* Temporal Key 2 (TK2) */
- struct {
- u8 tx_mic_key[8];
- u8 rx_mic_key[8];
- } auth;
- } u;
-} __attribute__ ((packed));
+struct wpa_scan_result;
+struct wpa_sm;
+struct wpa_supplicant;
+/**
+ * struct wpa_interface - Parameters for wpa_supplicant_add_iface()
+ */
+struct wpa_interface {
+ /**
+ * confname - Configuration name (file or profile) name
+ *
+ * This can also be %NULL when a configuration file is not used. In
+ * that case, ctrl_interface must be set to allow the interface to be
+ * configured.
+ */
+ const char *confname;
+
+ /**
+ * ctrl_interface - Control interface parameter
+ *
+ * If a configuration file is not used, this variable can be used to
+ * set the ctrl_interface parameter that would have otherwise been read
+ * from the configuration file. If both confname and ctrl_interface are
+ * set, ctrl_interface is used to override the value from configuration
+ * file.
+ */
+ const char *ctrl_interface;
+
+ /**
+ * driver - Driver interface name, or %NULL to use the default driver
+ */
+ const char *driver;
+
+ /**
+ * driver_param - Driver interface parameters
+ *
+ * If a configuration file is not used, this variable can be used to
+ * set the driver_param parameters that would have otherwise been read
+ * from the configuration file. If both confname and driver_param are
+ * set, driver_param is used to override the value from configuration
+ * file.
+ */
+ const char *driver_param;
+
+ /**
+ * ifname - Interface name
+ */
+ const char *ifname;
+};
-struct wpa_blacklist {
- struct wpa_blacklist *next;
- u8 bssid[ETH_ALEN];
- int count;
+/**
+ * struct wpa_params - Parameters for wpa_supplicant_init()
+ */
+struct wpa_params {
+ /**
+ * daemonize - Run %wpa_supplicant in the background
+ */
+ int daemonize;
+
+ /**
+ * wait_for_interface - Wait for the network interface to appear
+ *
+ * If set, %wpa_supplicant will wait until all the configured network
+ * interfaces are available before starting processing. Please note
+ * that in many cases, a better alternative would be to start
+ * %wpa_supplicant without network interfaces and add the interfaces
+ * dynamically whenever they become available.
+ */
+ int wait_for_interface;
+
+ /**
+ * wait_for_monitor - Wait for a monitor program before starting
+ */
+ int wait_for_monitor;
+
+ /**
+ * pid_file - Path to a PID (process ID) file
+ *
+ * If this and daemonize are set, process ID of the background process
+ * will be written to the specified file.
+ */
+ char *pid_file;
+
+ /**
+ * wpa_debug_level - Debugging verbosity level (e.g., MSG_INFO)
+ */
+ int wpa_debug_level;
+
+ /**
+ * wpa_debug_show_keys - Whether keying material is included in debug
+ *
+ * This parameter can be used to allow keying material to be included
+ * in debug messages. This is a security risk and this option should
+ * not be enabled in normal configuration. If needed during
+ * development or while troubleshooting, this option can provide more
+ * details for figuring out what is happening.
+ */
+ int wpa_debug_show_keys;
+
+ /**
+ * wpa_debug_timestamp - Whether to include timestamp in debug messages
+ */
+ int wpa_debug_timestamp;
+
+ /**
+ * ctrl_interface - Global ctrl_iface path/parameter
+ */
+ char *ctrl_interface;
};
+/**
+ * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
+ *
+ * This structure is initialized by calling wpa_supplicant_init() when starting
+ * %wpa_supplicant.
+ */
+struct wpa_global {
+ struct wpa_supplicant *ifaces;
+ struct wpa_params params;
+ int ctrl_sock;
+};
+/**
+ * struct wpa_supplicant - Internal data for wpa_supplicant interface
+ *
+ * This structure contains the internal data for core wpa_supplicant code. This
+ * should be only used directly from the core code. However, a pointer to this
+ * data is used from other files as an arbitrary context pointer in calls to
+ * core functions.
+ */
struct wpa_supplicant {
- struct wpa_supplicant *head;
+ struct wpa_global *global;
struct wpa_supplicant *next;
struct l2_packet_data *l2;
unsigned char own_addr[ETH_ALEN];
char ifname[100];
-#ifdef CONFIG_XSUPPLICANT_IFACE
- int dot1x_s; /* socket for connection to Xsupplicant */
- int ext_pmk_received; /* 1 = PMK was received from Xsupplicant */
-#endif /* CONFIG_XSUPPLICANT_IFACE */
-
- u8 pmk[PMK_LEN];
- size_t pmk_len;
- u8 snonce[WPA_NONCE_LEN];
- u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
- struct wpa_ptk ptk, tptk;
- int ptk_set, tptk_set;
- int renew_snonce;
+
char *confname;
struct wpa_config *conf;
- u8 request_counter[WPA_REPLAY_COUNTER_LEN];
int countermeasures;
time_t last_michael_mic_error;
- u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
- int rx_replay_counter_set;
u8 bssid[ETH_ALEN];
int reassociate; /* reassociation requested */
+ int disconnected; /* all connections disabled; i.e., do no reassociate
+ * before this has been cleared */
struct wpa_ssid *current_ssid;
- u8 *ap_wpa_ie, *ap_rsn_ie;
- size_t ap_wpa_ie_len, ap_rsn_ie_len;
- u8 *assoc_wpa_ie;
- size_t assoc_wpa_ie_len;
/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
- int proto;
int pairwise_cipher;
int group_cipher;
int key_mgmt;
@@ -108,34 +192,20 @@ struct wpa_supplicant {
struct wpa_driver_ops *driver;
int interface_removed; /* whether the network interface has been
* removed */
+ 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;
- enum {
- WPA_DISCONNECTED, WPA_SCANNING, WPA_ASSOCIATING,
- WPA_ASSOCIATED, WPA_4WAY_HANDSHAKE, WPA_GROUP_HANDSHAKE,
- WPA_COMPLETED
- } wpa_state;
-
- struct rsn_pmksa_cache *pmksa; /* PMKSA cache */
- int pmksa_count; /* number of entries in PMKSA cache */
- struct rsn_pmksa_cache *cur_pmksa; /* current PMKSA entry */
- struct rsn_pmksa_candidate *pmksa_candidates;
-
- struct l2_packet_data *l2_preauth;
- u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or
- * 00:00:00:00:00:00 if no pre-auth is
- * in progress */
- struct eapol_sm *preauth_eapol;
+ wpa_states wpa_state;
+ int new_connection;
+ int reassociated_connection;
int eapol_received; /* number of EAPOL packets received after the
* previous association event */
- u8 *imsi;
- size_t imsi_len;
struct scard_data *scard;
unsigned char last_eapol_src[ETH_ALEN];
@@ -144,136 +214,61 @@ struct wpa_supplicant {
struct wpa_blacklist *blacklist;
-#ifdef EAPOL_TEST
- u8 radius_identifier;
- struct radius_msg *last_recv_radius;
- struct in_addr own_ip_addr;
- struct radius_client_data *radius;
-
- /* RADIUS Authentication and Accounting servers in priority order */
- struct hostapd_radius_server *auth_servers, *auth_server;
- int num_auth_servers;
- struct hostapd_radius_server *acct_servers, *acct_server;
- int num_acct_servers;
-
- int radius_retry_primary_interval;
- int radius_acct_interim_interval;
-
- u8 *last_eap_radius; /* last received EAP Response from Authentication
- * Server */
- size_t last_eap_radius_len;
-
- u8 authenticator_pmk[PMK_LEN];
- size_t authenticator_pmk_len;
- int radius_access_accept_received;
- int radius_access_reject_received;
- int auth_timed_out;
-
- u8 *eap_identity;
- size_t eap_identity_len;
-#endif /* EAPOL_TEST */
+ int scan_req; /* manual scan request; this forces a scan even if there
+ * are no enabled networks in the configuration */
};
/* wpa_supplicant.c */
-void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx);
-
-void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
-
void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
-void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
- int reason_code);
-void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
- int reason_code);
+int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
+const char * wpa_supplicant_state_txt(int state);
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s,
+ int wait_for_interface);
+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,
+ struct wpa_ssid *ssid,
+ u8 *wpa_ie, size_t *wpa_ie_len);
+void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
+ struct wpa_scan_result *bss,
+ struct wpa_ssid *ssid);
+void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
+void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s);
+void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
int sec, int usec);
-
-void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
-
-int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
-
-int wpa_supplicant_get_beacon_ie(struct wpa_supplicant *wpa_s);
-
-
-/* wpa.c */
-void wpa_supplicant_key_request(struct wpa_supplicant *wpa_s,
- int error, int pairwise);
-
-struct wpa_ie_data {
- int proto;
- int pairwise_cipher;
- int group_cipher;
- int key_mgmt;
- int capabilities;
- int num_pmkid;
- u8 *pmkid;
-};
-
-int wpa_parse_wpa_ie(struct wpa_supplicant *wpa_s, u8 *wpa_ie,
- size_t wpa_ie_len, struct wpa_ie_data *data);
-
-int wpa_gen_wpa_ie(struct wpa_supplicant *wpa_s, u8 *wpa_ie);
-
-void wpa_supplicant_rx_eapol(void *ctx, unsigned char *src_addr,
- unsigned char *buf, size_t len);
-
+void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_states state);
struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
+ int reason_code);
+void wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s,
+ int reason_code);
+void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
-void pmksa_cache_free(struct wpa_supplicant *wpa_s);
-struct rsn_pmksa_cache * pmksa_cache_get(struct wpa_supplicant *wpa_s,
- u8 *aa, u8 *pmkid);
-int pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, size_t len);
-void pmksa_candidate_free(struct wpa_supplicant *wpa_s);
-
-int wpa_get_mib(struct wpa_supplicant *wpa_s, char *buf, size_t buflen);
-
-struct wpa_scan_result;
-#ifdef IEEE8021X_EAPOL
-int rsn_preauth_init(struct wpa_supplicant *wpa_s, u8 *dst);
-void rsn_preauth_deinit(struct wpa_supplicant *wpa_s);
-void rsn_preauth_scan_results(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *results, int count);
-void pmksa_candidate_add(struct wpa_supplicant *wpa_s, const u8 *bssid,
- int prio);
-#else /* IEEE8021X_EAPOL */
-static inline int rsn_preauth_init(struct wpa_supplicant *wpa_s, u8 *dst)
-{
- return -1;
-}
-
-static inline void rsn_preauth_deinit(struct wpa_supplicant *wpa_s)
-{
-}
-static inline void rsn_preauth_scan_results(struct wpa_supplicant *wpa_s,
- struct wpa_scan_result *results,
- int count)
-{
-}
-
-static inline void pmksa_candidate_add(struct wpa_supplicant *wpa_s,
- const u8 *bssid,
- int prio)
-{
-}
-#endif /* IEEE8021X_EAPOL */
+void wpa_show_license(void);
-void wpa_supplicant_notify_eapol_done(void *ctx);
+struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
+ struct wpa_interface *iface);
+int wpa_supplicant_remove_iface(struct wpa_global *global,
+ struct wpa_supplicant *wpa_s);
+struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
+ const char *ifname);
+struct wpa_global * wpa_supplicant_init(struct wpa_params *params);
+int wpa_supplicant_run(struct wpa_global *global);
+void wpa_supplicant_deinit(struct wpa_global *global);
-/**
- * wpa_eapol_send - send IEEE 802.1X EAPOL packet to the Authenticator
- * @ctx: pointer to wpa_supplicant data
- * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*)
- * @buf: EAPOL payload (after IEEE 802.1X header)
- * @len: EAPOL payload length
- *
- * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame
- * to the current Authenticator or in case of pre-authentication, to the peer
- * of the authentication.
- */
-int wpa_eapol_send(void *ctx, int type, u8 *buf, size_t len);
-int wpa_eapol_send_preauth(void *ctx, int type, u8 *buf, size_t len);
+int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid);
/* driver_ops */
@@ -292,6 +287,14 @@ static inline void wpa_drv_deinit(struct wpa_supplicant *wpa_s)
wpa_s->driver->deinit(wpa_s->drv_priv);
}
+static inline int wpa_drv_set_param(struct wpa_supplicant *wpa_s,
+ const char *param)
+{
+ if (wpa_s->driver->set_param)
+ return wpa_s->driver->set_param(wpa_s->drv_priv, param);
+ return 0;
+}
+
static inline int wpa_drv_set_drop_unencrypted(struct wpa_supplicant *wpa_s,
int enabled)
{
@@ -381,6 +384,7 @@ static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s, wpa_alg alg,
const u8 *key, size_t key_len)
{
if (wpa_s->driver->set_key) {
+ wpa_s->keys_cleared = 0;
return wpa_s->driver->set_key(wpa_s->drv_priv, alg, addr,
key_idx, set_tx, seq, seq_len,
key, key_len);
@@ -467,4 +471,14 @@ static inline const u8 * wpa_drv_get_mac_addr(struct wpa_supplicant *wpa_s)
return NULL;
}
+static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s,
+ const u8 *dst, u16 proto,
+ const u8 *data, size_t data_len)
+{
+ if (wpa_s->driver->send_eapol)
+ return wpa_s->driver->send_eapol(wpa_s->drv_priv, dst, proto,
+ data, data_len);
+ return -1;
+}
+
#endif /* WPA_SUPPLICANT_I_H */
OpenPOWER on IntegriCloud