From 840099f34d8de1ca769f02fae379c4d8e5d6688a Mon Sep 17 00:00:00 2001 From: sam Date: Tue, 7 Mar 2006 05:26:33 +0000 Subject: Import of WPA supplicant 0.4.8 --- contrib/wpa_supplicant/ChangeLog | 294 ++- contrib/wpa_supplicant/Makefile | 196 +- contrib/wpa_supplicant/README | 209 +- contrib/wpa_supplicant/aes.c | 555 ++-- contrib/wpa_supplicant/aes_wrap.c | 231 +- contrib/wpa_supplicant/aes_wrap.h | 41 +- contrib/wpa_supplicant/base64.c | 198 ++ contrib/wpa_supplicant/base64.h | 23 + contrib/wpa_supplicant/common.c | 73 +- contrib/wpa_supplicant/common.h | 88 +- contrib/wpa_supplicant/config.c | 1272 ++++++--- contrib/wpa_supplicant/config.h | 296 ++- contrib/wpa_supplicant/config_file.c | 695 +++++ contrib/wpa_supplicant/config_ssid.h | 703 ++++- contrib/wpa_supplicant/config_types.h | 14 + contrib/wpa_supplicant/crypto.c | 109 +- contrib/wpa_supplicant/crypto.h | 117 +- contrib/wpa_supplicant/crypto_gnutls.c | 163 ++ contrib/wpa_supplicant/ctrl_iface.c | 1105 +++++++- contrib/wpa_supplicant/ctrl_iface.h | 33 + contrib/wpa_supplicant/defconfig | 32 +- contrib/wpa_supplicant/defs.h | 121 +- contrib/wpa_supplicant/doc/code_structure.doxygen | 264 ++ contrib/wpa_supplicant/doc/ctrl_iface.doxygen | 409 +++ contrib/wpa_supplicant/doc/docbook/Makefile | 25 + .../wpa_supplicant/doc/docbook/wpa_background.8 | 84 + .../wpa_supplicant/doc/docbook/wpa_background.sgml | 101 + contrib/wpa_supplicant/doc/docbook/wpa_cli.8 | 202 ++ contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml | 330 +++ .../wpa_supplicant/doc/docbook/wpa_passphrase.8 | 39 + .../wpa_supplicant/doc/docbook/wpa_passphrase.sgml | 72 + .../wpa_supplicant/doc/docbook/wpa_supplicant.8 | 544 ++++ .../doc/docbook/wpa_supplicant.conf.5 | 230 ++ .../doc/docbook/wpa_supplicant.conf.sgml | 244 ++ .../wpa_supplicant/doc/docbook/wpa_supplicant.sgml | 761 ++++++ contrib/wpa_supplicant/doc/doxygen.fast | 243 ++ contrib/wpa_supplicant/doc/doxygen.full | 230 ++ contrib/wpa_supplicant/doc/driver_wrapper.doxygen | 180 ++ contrib/wpa_supplicant/doc/eap.doxygen | 38 + contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl | 129 + contrib/wpa_supplicant/doc/mainpage.doxygen | 56 + contrib/wpa_supplicant/doc/porting.doxygen | 121 + contrib/wpa_supplicant/doc/testing_tools.doxygen | 288 ++ contrib/wpa_supplicant/doc/wpa_supplicant.fig | 42 +- contrib/wpa_supplicant/driver.h | 281 +- contrib/wpa_supplicant/driver_hostap.h | 153 ++ contrib/wpa_supplicant/driver_ndis.c | 137 +- contrib/wpa_supplicant/driver_ndis.h | 15 + contrib/wpa_supplicant/driver_wired.c | 271 ++ contrib/wpa_supplicant/drivers.c | 8 +- contrib/wpa_supplicant/eap.c | 705 ++++- contrib/wpa_supplicant/eap.h | 222 +- contrib/wpa_supplicant/eap_aka.c | 93 +- contrib/wpa_supplicant/eap_defs.h | 31 +- contrib/wpa_supplicant/eap_fast.c | 343 ++- contrib/wpa_supplicant/eap_gtc.c | 51 +- contrib/wpa_supplicant/eap_i.h | 182 +- contrib/wpa_supplicant/eap_leap.c | 82 +- contrib/wpa_supplicant/eap_md5.c | 45 +- contrib/wpa_supplicant/eap_mschapv2.c | 251 +- contrib/wpa_supplicant/eap_otp.c | 28 +- contrib/wpa_supplicant/eap_pax.c | 510 ++++ contrib/wpa_supplicant/eap_pax_common.c | 152 ++ contrib/wpa_supplicant/eap_pax_common.h | 84 + contrib/wpa_supplicant/eap_peap.c | 99 +- contrib/wpa_supplicant/eap_psk.c | 262 +- contrib/wpa_supplicant/eap_psk_common.c | 57 + contrib/wpa_supplicant/eap_psk_common.h | 92 + contrib/wpa_supplicant/eap_sim.c | 88 +- contrib/wpa_supplicant/eap_sim_common.c | 78 +- contrib/wpa_supplicant/eap_sim_common.h | 35 +- contrib/wpa_supplicant/eap_testing.txt | 90 +- contrib/wpa_supplicant/eap_tls.c | 91 +- contrib/wpa_supplicant/eap_tls_common.c | 315 ++- contrib/wpa_supplicant/eap_tls_common.h | 25 +- contrib/wpa_supplicant/eap_tlv.c | 28 +- contrib/wpa_supplicant/eap_tlv.h | 20 +- contrib/wpa_supplicant/eap_ttls.c | 115 +- contrib/wpa_supplicant/eap_ttls.h | 14 + contrib/wpa_supplicant/eapol_sm.c | 520 +++- contrib/wpa_supplicant/eapol_sm.h | 202 +- contrib/wpa_supplicant/eapol_test.c | 529 ++-- contrib/wpa_supplicant/eloop.c | 21 +- contrib/wpa_supplicant/eloop.h | 137 +- contrib/wpa_supplicant/events.c | 759 ++++++ contrib/wpa_supplicant/examples/ieee8021x.conf | 13 + contrib/wpa_supplicant/examples/plaintext.conf | 8 + contrib/wpa_supplicant/examples/wep.conf | 11 + contrib/wpa_supplicant/examples/wpa-psk-tkip.conf | 12 + contrib/wpa_supplicant/examples/wpa2-eap-ccmp.conf | 15 + contrib/wpa_supplicant/hostapd.h | 38 + contrib/wpa_supplicant/l2_packet.h | 109 +- contrib/wpa_supplicant/main.c | 250 ++ contrib/wpa_supplicant/md5.c | 146 +- contrib/wpa_supplicant/md5.h | 46 +- contrib/wpa_supplicant/ms_funcs.c | 200 +- contrib/wpa_supplicant/ms_funcs.h | 51 +- .../wpa_supplicant/openssl-tls-extensions.patch | 513 +++- contrib/wpa_supplicant/pcsc_funcs.c | 47 +- contrib/wpa_supplicant/pcsc_funcs.h | 20 +- contrib/wpa_supplicant/preauth.c | 934 +++++++ contrib/wpa_supplicant/preauth.h | 132 + contrib/wpa_supplicant/preauth_test.c | 387 ++- contrib/wpa_supplicant/radius.c | 219 +- contrib/wpa_supplicant/radius.h | 18 +- contrib/wpa_supplicant/radius_client.c | 845 ++++-- contrib/wpa_supplicant/radius_client.h | 118 +- contrib/wpa_supplicant/rc4.c | 32 +- contrib/wpa_supplicant/rc4.h | 19 +- contrib/wpa_supplicant/sha1.c | 202 +- contrib/wpa_supplicant/sha1.h | 45 +- contrib/wpa_supplicant/tls.h | 317 ++- contrib/wpa_supplicant/tls_gnutls.c | 792 ++++++ contrib/wpa_supplicant/tls_none.c | 8 +- contrib/wpa_supplicant/tls_openssl.c | 1618 ++++++++++-- contrib/wpa_supplicant/tls_schannel.c | 738 ++++++ contrib/wpa_supplicant/todo.txt | 43 +- contrib/wpa_supplicant/version.h | 2 +- contrib/wpa_supplicant/wpa.c | 2743 +++++++++++--------- contrib/wpa_supplicant/wpa.h | 302 ++- contrib/wpa_supplicant/wpa_cli.c | 589 ++++- contrib/wpa_supplicant/wpa_ctrl.c | 18 +- contrib/wpa_supplicant/wpa_ctrl.h | 172 +- contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui | 125 + .../wpa_supplicant/wpa_gui-qt4/eventhistory.ui.h | 41 + contrib/wpa_supplicant/wpa_gui-qt4/main.cpp | 30 + .../wpa_supplicant/wpa_gui-qt4/networkconfig.ui | 455 ++++ .../wpa_supplicant/wpa_gui-qt4/networkconfig.ui.h | 513 ++++ contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui | 179 ++ .../wpa_supplicant/wpa_gui-qt4/scanresults.ui.h | 101 + .../wpa_gui-qt4/setup-mingw-cross-compiling | 11 + .../wpa_supplicant/wpa_gui-qt4/userdatarequest.ui | 163 ++ .../wpa_gui-qt4/userdatarequest.ui.h | 70 + contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro | 41 + contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui | 464 ++++ contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui.h | 651 +++++ contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h | 28 + contrib/wpa_supplicant/wpa_gui/eventhistory.ui | 125 + contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h | 41 + contrib/wpa_supplicant/wpa_gui/main.cpp | 30 + contrib/wpa_supplicant/wpa_gui/networkconfig.ui | 455 ++++ contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h | 513 ++++ contrib/wpa_supplicant/wpa_gui/scanresults.ui | 179 ++ contrib/wpa_supplicant/wpa_gui/scanresults.ui.h | 101 + contrib/wpa_supplicant/wpa_gui/userdatarequest.ui | 163 ++ .../wpa_supplicant/wpa_gui/userdatarequest.ui.h | 70 + contrib/wpa_supplicant/wpa_gui/wpa_gui.pro | 31 + contrib/wpa_supplicant/wpa_gui/wpagui.ui | 464 ++++ contrib/wpa_supplicant/wpa_gui/wpagui.ui.h | 651 +++++ contrib/wpa_supplicant/wpa_gui/wpamsg.h | 27 + contrib/wpa_supplicant/wpa_i.h | 197 ++ contrib/wpa_supplicant/wpa_passphrase.c | 31 +- contrib/wpa_supplicant/wpa_supplicant.c | 2009 ++++++-------- contrib/wpa_supplicant/wpa_supplicant.conf | 199 +- contrib/wpa_supplicant/wpa_supplicant.h | 235 +- contrib/wpa_supplicant/wpa_supplicant_i.h | 408 +-- 156 files changed, 32492 insertions(+), 6502 deletions(-) create mode 100644 contrib/wpa_supplicant/base64.c create mode 100644 contrib/wpa_supplicant/base64.h create mode 100644 contrib/wpa_supplicant/config_file.c create mode 100644 contrib/wpa_supplicant/config_types.h create mode 100644 contrib/wpa_supplicant/crypto_gnutls.c create mode 100644 contrib/wpa_supplicant/doc/code_structure.doxygen create mode 100644 contrib/wpa_supplicant/doc/ctrl_iface.doxygen create mode 100644 contrib/wpa_supplicant/doc/docbook/Makefile create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_background.8 create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_background.sgml create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_cli.8 create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_cli.sgml create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_passphrase.8 create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_passphrase.sgml create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_supplicant.8 create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_supplicant.conf.sgml create mode 100644 contrib/wpa_supplicant/doc/docbook/wpa_supplicant.sgml create mode 100644 contrib/wpa_supplicant/doc/doxygen.fast create mode 100644 contrib/wpa_supplicant/doc/doxygen.full create mode 100644 contrib/wpa_supplicant/doc/driver_wrapper.doxygen create mode 100644 contrib/wpa_supplicant/doc/eap.doxygen create mode 100755 contrib/wpa_supplicant/doc/kerneldoc2doxygen.pl create mode 100644 contrib/wpa_supplicant/doc/mainpage.doxygen create mode 100644 contrib/wpa_supplicant/doc/porting.doxygen create mode 100644 contrib/wpa_supplicant/doc/testing_tools.doxygen create mode 100644 contrib/wpa_supplicant/driver_hostap.h create mode 100644 contrib/wpa_supplicant/driver_wired.c create mode 100644 contrib/wpa_supplicant/eap_pax.c create mode 100644 contrib/wpa_supplicant/eap_pax_common.c create mode 100644 contrib/wpa_supplicant/eap_pax_common.h create mode 100644 contrib/wpa_supplicant/eap_psk_common.c create mode 100644 contrib/wpa_supplicant/eap_psk_common.h create mode 100644 contrib/wpa_supplicant/events.c create mode 100644 contrib/wpa_supplicant/examples/ieee8021x.conf create mode 100644 contrib/wpa_supplicant/examples/plaintext.conf create mode 100644 contrib/wpa_supplicant/examples/wep.conf create mode 100644 contrib/wpa_supplicant/examples/wpa-psk-tkip.conf create mode 100644 contrib/wpa_supplicant/examples/wpa2-eap-ccmp.conf create mode 100644 contrib/wpa_supplicant/hostapd.h create mode 100644 contrib/wpa_supplicant/main.c create mode 100644 contrib/wpa_supplicant/preauth.c create mode 100644 contrib/wpa_supplicant/preauth.h create mode 100644 contrib/wpa_supplicant/tls_gnutls.c create mode 100644 contrib/wpa_supplicant/tls_schannel.c create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/eventhistory.ui.h create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/main.cpp create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/networkconfig.ui.h create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/scanresults.ui.h create mode 100755 contrib/wpa_supplicant/wpa_gui-qt4/setup-mingw-cross-compiling create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui.h create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/wpagui.ui.h create mode 100644 contrib/wpa_supplicant/wpa_gui-qt4/wpamsg.h create mode 100644 contrib/wpa_supplicant/wpa_gui/eventhistory.ui create mode 100644 contrib/wpa_supplicant/wpa_gui/eventhistory.ui.h create mode 100644 contrib/wpa_supplicant/wpa_gui/main.cpp create mode 100644 contrib/wpa_supplicant/wpa_gui/networkconfig.ui create mode 100644 contrib/wpa_supplicant/wpa_gui/networkconfig.ui.h create mode 100644 contrib/wpa_supplicant/wpa_gui/scanresults.ui create mode 100644 contrib/wpa_supplicant/wpa_gui/scanresults.ui.h create mode 100644 contrib/wpa_supplicant/wpa_gui/userdatarequest.ui create mode 100644 contrib/wpa_supplicant/wpa_gui/userdatarequest.ui.h create mode 100644 contrib/wpa_supplicant/wpa_gui/wpa_gui.pro create mode 100644 contrib/wpa_supplicant/wpa_gui/wpagui.ui create mode 100644 contrib/wpa_supplicant/wpa_gui/wpagui.ui.h create mode 100644 contrib/wpa_supplicant/wpa_gui/wpamsg.h create mode 100644 contrib/wpa_supplicant/wpa_i.h (limited to 'contrib') 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 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://", where 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://" 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 ' and + 'wpa_cli disable_network ') + * added support for adding and removing network from the current + configuration ('wpa_cli add_network' and 'wpa_cli remove_network + '); 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 '; 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) 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 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 and +Copyright (c) 2003-2006, Jouni Malinen 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 = force preauthentication identity = configure identity for an SSID password = configure password for an SSID + pin = configure pin for an SSID otp = configure one-time-password for an SSID + passphrase = configure private key passphrase + for an SSID + bssid = set preferred BSSID for an SSID + list_networks = list configured networks + select_network = select a network (disable others) + enable_network = enable a network + disable_network = disable a network + add_network = add a network + remove_network = remove a network + set_network = set network variables (shows + list of variables when run without arguments) + get_network = 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 = get capabilies terminate = terminate wpa_supplicant quit = exit wpa_cli +wpa_cli command line options + +wpa_cli [-p] [-i] [-hvB] [-a] \ + [-P] [-g] [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 = jkm - eap-peap { - random_file = /dev/urandom - root_cert = /home/jkm/CA.pem - chunk_size = 1398 - allow_types = eap_mschapv2 - eap-mschapv2 { - username = jkm - password = jkm - } - } -} +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 + * - 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 * * This 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 + * 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 * * This 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 #include "common.h" #include "aes_wrap.h" +#include "crypto.h" -#ifdef EAP_TLS_FUNCS - -#include - -#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 + * + * This 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 + * + * This 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 +#include + +#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 + +int main(int argc, char *argv[]) +{ + FILE *f; + size_t len, elen; + unsigned char *buf, *e; + + if (argc != 4) { + printf("Usage: base64 \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 + * + * This 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 * * This program is free software; you can redistribute it and/or modify @@ -22,6 +21,10 @@ #include #include #include +#ifdef CONFIG_NATIVE_WINDOWS +#include +#include +#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 + * + * This 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 #include -#endif -#ifdef __FreeBSD__ +#endif /* __linux__ */ + +#if defined(__FreeBSD__) || defined(__NetBSD__) #include #include #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 #include 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 . + * 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 * * 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 + * + * This 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 + * + * This 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 +#include +#include + +#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 + * + * This 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://. + * + * On Windows, trusted CA certificates can be loaded from the system + * certificate store by setting this to cert_store://, 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://. + */ 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://. + */ 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://. + */ 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://. + */ 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://. + */ 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://. + */ 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://. + */ 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://. + */ 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 +#include + #include +#include +#include #include +#include #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 + * + * This 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 + * + * This 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 +#include +#include + +#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 * * This program is free software; you can redistribute it and/or modify @@ -21,6 +21,8 @@ #include #ifndef CONFIG_NATIVE_WINDOWS #include +#include +#include #include #include #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: " " */ + 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: "" 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: "" */ + 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: "" */ + 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: "" */ + 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: " " */ + 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: " " */ + 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; + + /* + * TABTABTABTAB + */ + 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 + * + * This 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 + * + * This 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 + +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 + +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 + +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 + +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 + +Select a network (disable others). Network id can be received from the +\c LIST_NETWORKS command output. + + +\subsection ctrl_iface_ENABLE_NETWORK ENABLE_NETWORK + +Enable a network. Network id can be received from the +\c LIST_NETWORKS command output. + + +\subsection ctrl_iface_DISABLE_NETWORK DISABLE_NETWORK + +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 + +Remove a network. Network id can be received from the +\c LIST_NETWORKS command output. + + +\subsection ctrl_iface_SET_NETWORK SET_NETWORK + +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 + +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--- +CTRL-RSP--- +\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